From fc13f79a52fe53ea5230e90fa8e3e7440f20164d Mon Sep 17 00:00:00 2001 From: Snider Date: Sun, 15 Mar 2026 10:19:53 +0000 Subject: [PATCH] fix(agentic): fresh clone with feature branch in sandboxed workspace Dispatch now clones the full repo (not shallow) into workspace/src/, creates an agent/{task-slug} feature branch, and sets the push remote to forge. Agent never touches the main checkout. Co-Authored-By: Virgil --- pkg/mcp/agentic/prep.go | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/pkg/mcp/agentic/prep.go b/pkg/mcp/agentic/prep.go index a7e90dd..73c44a8 100644 --- a/pkg/mcp/agentic/prep.go +++ b/pkg/mcp/agentic/prep.go @@ -135,9 +135,36 @@ func (s *PrepSubsystem) prepWorkspace(ctx context.Context, _ *mcp.CallToolReques // Source repo path repoPath := filepath.Join(s.codePath, "core", input.Repo) - // 1. Clone repo into src/ - cmd := exec.CommandContext(ctx, "git", "clone", "--depth", "1", repoPath, filepath.Join(wsDir, "src")) - cmd.Run() + // 1. Clone repo into src/ and create feature branch + srcDir := filepath.Join(wsDir, "src") + cloneCmd := exec.CommandContext(ctx, "git", "clone", repoPath, srcDir) + cloneCmd.Run() + + // Create feature branch + taskSlug := strings.Map(func(r rune) rune { + if r >= 'a' && r <= 'z' || r >= '0' && r <= '9' || r == '-' { + return r + } + if r >= 'A' && r <= 'Z' { + return r + 32 // lowercase + } + return '-' + }, input.Task) + if len(taskSlug) > 40 { + taskSlug = taskSlug[:40] + } + taskSlug = strings.Trim(taskSlug, "-") + branchName := fmt.Sprintf("agent/%s", taskSlug) + + branchCmd := exec.CommandContext(ctx, "git", "checkout", "-b", branchName) + branchCmd.Dir = srcDir + branchCmd.Run() + + // Set push remote to forge + remoteCmd := exec.CommandContext(ctx, "git", "remote", "set-url", "origin", + fmt.Sprintf("ssh://git@forge.lthn.ai:2223/%s/%s.git", input.Org, input.Repo)) + remoteCmd.Dir = srcDir + remoteCmd.Run() // 2. Copy CLAUDE.md to workspace root claudeMdPath := filepath.Join(repoPath, "CLAUDE.md")