Add PRs to agent

Change-Id: If623cf29d160a0ff4dcbbb2923f681a2d9f17c1b
diff --git a/server/.env b/server/.env
index 4d4d76d..562c49a 100644
--- a/server/.env
+++ b/server/.env
@@ -1,3 +1,9 @@
 REMOTE_REPO_URL=https://github.com/iomodo/staff.git
 WORKING_DIR=../ 
-OPENAI_API_KEY=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
\ No newline at end of file
+OPENAI_API_KEY=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
+
+GERRIT_ENABLED=true
+GERRIT_USERNAME=staff-agent
+GERRIT_PASSWORD=your-gerrit-api-token-or-password
+GERRIT_BASE_URL=https://gerrit.company.com
+GERRIT_PROJECT=my-project
\ No newline at end of file
diff --git a/server/agent/agent.go b/server/agent/agent.go
index d1c64a4..42a7024 100644
--- a/server/agent/agent.go
+++ b/server/agent/agent.go
@@ -37,6 +37,18 @@
 	GitRepoPath string
 	GitRemote   string
 	GitBranch   string
+
+	// Gerrit Configuration
+	GerritEnabled bool
+	GerritConfig  GerritConfig
+}
+
+// GerritConfig holds configuration for Gerrit operations
+type GerritConfig struct {
+	Username string
+	Password string // Can be HTTP password or API token
+	BaseURL  string
+	Project  string
 }
 
 // Agent represents an AI agent that can process tasks
@@ -62,7 +74,26 @@
 	}
 
 	// Create git interface
-	gitInterface := git.DefaultGit(config.GitRepoPath)
+	var gitInterface git.GitInterface
+	if config.GerritEnabled {
+		// Create Gerrit pull request provider
+		gerritPRProvider := git.NewGerritPullRequestProvider(config.GerritConfig.Project, git.GerritConfig{
+			Username:   config.GerritConfig.Username,
+			Password:   config.GerritConfig.Password,
+			BaseURL:    config.GerritConfig.BaseURL,
+			HTTPClient: nil, // Will use default client
+		})
+
+		// Create git interface with Gerrit pull request provider
+		gitConfig := git.GitConfig{
+			Timeout:             30 * time.Second,
+			PullRequestProvider: gerritPRProvider,
+		}
+		gitInterface = git.NewGitWithPullRequests(config.GitRepoPath, gitConfig, gerritPRProvider)
+	} else {
+		// Use default git interface (GitHub)
+		gitInterface = git.DefaultGit(config.GitRepoPath)
+	}
 
 	// Create context with cancellation
 	ctx, cancel := context.WithCancel(context.Background())
@@ -152,6 +183,52 @@
 		}
 	}
 
+	// Set up git user configuration
+	userConfig := git.UserConfig{
+		Name:  a.Config.GitUsername,
+		Email: a.Config.GitEmail,
+	}
+	if err := a.gitInterface.SetUserConfig(ctx, userConfig); err != nil {
+		return fmt.Errorf("failed to set git user config: %w", err)
+	}
+
+	// Check if remote origin exists, if not add it
+	remotes, err := a.gitInterface.ListRemotes(ctx)
+	if err != nil {
+		return fmt.Errorf("failed to list remotes: %w", err)
+	}
+
+	originExists := false
+	for _, remote := range remotes {
+		if remote.Name == "origin" {
+			originExists = true
+			break
+		}
+	}
+
+	if !originExists {
+		// Add remote origin - use Gerrit URL if enabled, otherwise use the configured remote
+		remoteURL := a.Config.GitRemote
+		if a.Config.GerritEnabled {
+			// For Gerrit, the remote URL should be the Gerrit SSH or HTTP URL
+			// Format: ssh://username@gerrit-host:29418/project-name.git
+			// or: https://gerrit-host/project-name.git
+			if strings.HasPrefix(a.Config.GerritConfig.BaseURL, "https://") {
+				remoteURL = fmt.Sprintf("%s/%s.git", a.Config.GerritConfig.BaseURL, a.Config.GerritConfig.Project)
+			} else {
+				// Assume SSH format
+				remoteURL = fmt.Sprintf("ssh://%s@%s:29418/%s.git",
+					a.Config.GerritConfig.Username,
+					strings.TrimPrefix(a.Config.GerritConfig.BaseURL, "https://"),
+					a.Config.GerritConfig.Project)
+			}
+		}
+
+		if err := a.gitInterface.AddRemote(ctx, "origin", remoteURL); err != nil {
+			return fmt.Errorf("failed to add remote origin: %w", err)
+		}
+	}
+
 	// Checkout to the specified branch
 	if a.Config.GitBranch != "" {
 		if err := a.gitInterface.Checkout(ctx, a.Config.GitBranch); err != nil {
@@ -309,7 +386,7 @@
 		return fmt.Errorf("failed to add solution file: %w", err)
 	}
 
-	commitMessage := fmt.Sprintf("feat: Complete task %s - %s", task.ID, task.Title)
+	commitMessage := fmt.Sprintf("feat: Complete task %s - %s\n\n%s", task.ID, task.Title, a.formatPullRequestDescription(task, solution))
 	if err := a.gitInterface.Commit(ctx, commitMessage, git.CommitOptions{
 		Author: &git.Author{
 			Name:  a.Config.GitUsername,
@@ -320,12 +397,37 @@
 		return fmt.Errorf("failed to commit solution: %w", err)
 	}
 
-	// Push the branch
-	if err := a.gitInterface.Push(ctx, "origin", branchName, git.PushOptions{SetUpstream: true}); err != nil {
-		return fmt.Errorf("failed to push branch: %w", err)
+	if a.Config.GerritEnabled {
+		// For Gerrit: Push to refs/for/BRANCH to create a change
+		gerritRef := fmt.Sprintf("refs/for/%s", a.Config.GitBranch)
+		if err := a.gitInterface.Push(ctx, "origin", gerritRef, git.PushOptions{}); err != nil {
+			return fmt.Errorf("failed to push to Gerrit: %w", err)
+		}
+		log.Printf("Created Gerrit change for task %s by pushing to %s", task.ID, gerritRef)
+	} else {
+		// For GitHub: Push branch and create PR
+		if err := a.gitInterface.Push(ctx, "origin", branchName, git.PushOptions{SetUpstream: true}); err != nil {
+			return fmt.Errorf("failed to push branch: %w", err)
+		}
+
+		// Create pull request using the git interface
+		prOptions := git.PullRequestOptions{
+			Title:       fmt.Sprintf("Complete task %s: %s", task.ID, task.Title),
+			Description: a.formatPullRequestDescription(task, solution),
+			BaseBranch:  a.Config.GitBranch,
+			HeadBranch:  branchName,
+			BaseRepo:    a.Config.GerritConfig.Project,
+			HeadRepo:    a.Config.GerritConfig.Project,
+		}
+
+		pr, err := a.gitInterface.CreatePullRequest(ctx, prOptions)
+		if err != nil {
+			return fmt.Errorf("failed to create pull request: %w", err)
+		}
+
+		log.Printf("Created pull request for task %s: %s (ID: %s)", task.ID, pr.Title, pr.ID)
 	}
 
-	log.Printf("Created pull request for task %s on branch %s", task.ID, branchName)
 	return nil
 }
 
@@ -386,6 +488,28 @@
 	return content.String()
 }
 
+// formatPullRequestDescription formats the description for the pull request
+func (a *Agent) formatPullRequestDescription(task *tm.Task, solution string) string {
+	var content strings.Builder
+
+	content.WriteString(fmt.Sprintf("**Task ID:** %s\n", task.ID))
+	content.WriteString(fmt.Sprintf("**Title:** %s\n", task.Title))
+	content.WriteString(fmt.Sprintf("**Priority:** %s\n", task.Priority))
+
+	if task.Description != "" {
+		content.WriteString(fmt.Sprintf("**Description:** %s\n", task.Description))
+	}
+
+	if task.DueDate != nil {
+		content.WriteString(fmt.Sprintf("**Due Date:** %s\n", task.DueDate.Format("2006-01-02")))
+	}
+
+	content.WriteString("\n**Solution:**\n\n")
+	content.WriteString(solution)
+
+	return content.String()
+}
+
 // ptr helpers for cleaner code
 func intPtr(i int) *int {
 	return &i
diff --git a/server/server/server.go b/server/server/server.go
index 41d1366..fc0d230 100644
--- a/server/server/server.go
+++ b/server/server/server.go
@@ -55,9 +55,36 @@
 		return fmt.Errorf("WORKING_DIR environment variable is required")
 	}
 
+	// Get Gerrit configuration (optional)
+	gerritEnabled := os.Getenv("GERRIT_ENABLED") == "true"
+	var gerritConfig agent.GerritConfig
+	if gerritEnabled {
+		gerritConfig = agent.GerritConfig{
+			Username: os.Getenv("GERRIT_USERNAME"),
+			Password: os.Getenv("GERRIT_PASSWORD"),
+			BaseURL:  os.Getenv("GERRIT_BASE_URL"),
+			Project:  os.Getenv("GERRIT_PROJECT"),
+		}
+
+		// Validate Gerrit configuration
+		if gerritConfig.Username == "" {
+			return fmt.Errorf("GERRIT_USERNAME environment variable is required when GERRIT_ENABLED=true")
+		}
+		if gerritConfig.Password == "" {
+			return fmt.Errorf("GERRIT_PASSWORD environment variable is required when GERRIT_ENABLED=true")
+		}
+		if gerritConfig.BaseURL == "" {
+			return fmt.Errorf("GERRIT_BASE_URL environment variable is required when GERRIT_ENABLED=true")
+		}
+		if gerritConfig.Project == "" {
+			return fmt.Errorf("GERRIT_PROJECT environment variable is required when GERRIT_ENABLED=true")
+		}
+	}
+
 	a.logger.Info("Environment variables loaded",
 		slog.String("remoteRepoURL", remoteRepoURL),
-		slog.String("workingDir", workingDir))
+		slog.String("workingDir", workingDir),
+		slog.Bool("gerritEnabled", gerritEnabled))
 
 	// Check if working directory is empty
 	isEmpty, err := a.isDirectoryEmpty(workingDir)
@@ -106,19 +133,21 @@
 		}
 
 		config := agent.AgentConfig{
-			Name:         agentName,
-			Role:         cases.Title(language.English).String(agentName),
-			GitUsername:  fmt.Sprintf("Staff %s", cases.Title(language.English).String(agentName)),
-			GitEmail:     fmt.Sprintf("%s@staff.com", strings.ToLower(agentName)),
-			WorkingDir:   workingDir,
-			LLMProvider:  llm.ProviderOpenAI,
-			LLMModel:     "gpt-4o-mini",
-			LLMConfig:    llmConfig,
-			SystemPrompt: systemPrompt,
-			TaskManager:  taskManager,
-			GitRepoPath:  workingDir,
-			GitRemote:    "origin",
-			GitBranch:    "main",
+			Name:          agentName,
+			Role:          cases.Title(language.English).String(agentName),
+			GitUsername:   fmt.Sprintf("Staff %s", cases.Title(language.English).String(agentName)),
+			GitEmail:      fmt.Sprintf("%s@staff.com", strings.ToLower(agentName)),
+			WorkingDir:    workingDir,
+			LLMProvider:   llm.ProviderOpenAI,
+			LLMModel:      "gpt-4o-mini",
+			LLMConfig:     llmConfig,
+			SystemPrompt:  systemPrompt,
+			TaskManager:   taskManager,
+			GitRepoPath:   workingDir,
+			GitRemote:     "origin",
+			GitBranch:     "main",
+			GerritEnabled: gerritEnabled,
+			GerritConfig:  gerritConfig,
 		}
 
 		ag, err := agent.NewAgent(config)
@@ -198,6 +227,27 @@
 		return fmt.Errorf("failed to set git user config: %w", err)
 	}
 
+	// Check if Gerrit is enabled and adjust remote URL accordingly
+	gerritEnabled := os.Getenv("GERRIT_ENABLED") == "true"
+	if gerritEnabled {
+		gerritBaseURL := os.Getenv("GERRIT_BASE_URL")
+		gerritProject := os.Getenv("GERRIT_PROJECT")
+
+		// For Gerrit, construct the appropriate remote URL
+		if strings.HasPrefix(gerritBaseURL, "https://") {
+			remoteRepoURL = fmt.Sprintf("%s/%s.git", gerritBaseURL, gerritProject)
+		} else {
+			// Assume SSH format
+			gerritUsername := os.Getenv("GERRIT_USERNAME")
+			remoteRepoURL = fmt.Sprintf("ssh://%s@%s:29418/%s.git",
+				gerritUsername,
+				strings.TrimPrefix(gerritBaseURL, "https://"),
+				gerritProject)
+		}
+
+		a.logger.Info("Using Gerrit remote URL", slog.String("url", remoteRepoURL))
+	}
+
 	// Add remote origin
 	if err := gitRepo.AddRemote(ctx, "origin", remoteRepoURL); err != nil {
 		return fmt.Errorf("failed to add remote origin: %w", err)