feat(daemon): add per-task isolated execution environments
Introduce the `execenv` package that creates isolated working directories for each agent task. Supports git worktree mode (code tasks) and plain directory mode (non-code tasks), with `.agent_context/issue_context.md` injected into the workdir for Claude Code to discover. Key changes: - New `server/internal/daemon/execenv/` package (Prepare/Cleanup) - `runTask()` now creates isolated env instead of using shared reposRoot - Prompt updated to reference `.agent_context/` files - Add `WorkspacesRoot` config (default ~/multica_workspaces) - Add `KeepEnvAfterTask` config for debugging - Default agent timeout increased from 20min to 2h - `CompleteTask` now forwards branch name to server Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
0ce25597d6
commit
678266ec87
10 changed files with 841 additions and 66 deletions
69
server/internal/daemon/execenv/context.go
Normal file
69
server/internal/daemon/execenv/context.go
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
package execenv
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// writeContextFiles renders and writes .agent_context/issue_context.md into workDir.
|
||||
func writeContextFiles(workDir string, ctx TaskContextForEnv) error {
|
||||
contextDir := filepath.Join(workDir, ".agent_context")
|
||||
if err := os.MkdirAll(contextDir, 0o755); err != nil {
|
||||
return fmt.Errorf("create .agent_context dir: %w", err)
|
||||
}
|
||||
|
||||
content := renderIssueContext(ctx)
|
||||
path := filepath.Join(contextDir, "issue_context.md")
|
||||
if err := os.WriteFile(path, []byte(content), 0o644); err != nil {
|
||||
return fmt.Errorf("write issue_context.md: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// renderIssueContext builds the markdown content for issue_context.md.
|
||||
// Sections with empty content are omitted.
|
||||
func renderIssueContext(ctx TaskContextForEnv) string {
|
||||
var b strings.Builder
|
||||
|
||||
if ctx.IssueTitle != "" {
|
||||
fmt.Fprintf(&b, "# Issue: %s\n\n", ctx.IssueTitle)
|
||||
}
|
||||
|
||||
if ctx.IssueDescription != "" {
|
||||
b.WriteString("## Description\n\n")
|
||||
b.WriteString(ctx.IssueDescription)
|
||||
b.WriteString("\n\n")
|
||||
}
|
||||
|
||||
if len(ctx.AcceptanceCriteria) > 0 {
|
||||
b.WriteString("## Acceptance Criteria\n\n")
|
||||
for _, item := range ctx.AcceptanceCriteria {
|
||||
fmt.Fprintf(&b, "- %s\n", item)
|
||||
}
|
||||
b.WriteString("\n")
|
||||
}
|
||||
|
||||
if len(ctx.ContextRefs) > 0 {
|
||||
b.WriteString("## Context References\n\n")
|
||||
for _, ref := range ctx.ContextRefs {
|
||||
fmt.Fprintf(&b, "- %s\n", ref)
|
||||
}
|
||||
b.WriteString("\n")
|
||||
}
|
||||
|
||||
if ctx.WorkspaceContext != "" {
|
||||
b.WriteString("## Workspace Context\n\n")
|
||||
b.WriteString(ctx.WorkspaceContext)
|
||||
b.WriteString("\n\n")
|
||||
}
|
||||
|
||||
if ctx.AgentSkills != "" {
|
||||
b.WriteString("## Agent Instructions\n\n")
|
||||
b.WriteString(ctx.AgentSkills)
|
||||
b.WriteString("\n")
|
||||
}
|
||||
|
||||
return b.String()
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue