summaryrefslogtreecommitdiff
path: root/internal/task
diff options
context:
space:
mode:
authorPeter Stone <thepeterstone@gmail.com>2026-03-08 20:16:00 +0000
committerPeter Stone <thepeterstone@gmail.com>2026-03-08 20:16:00 +0000
commit1f36e2312d316969db65a601ac7d9793fbc3bc4c (patch)
tree1d91358beaf910df23a5bd18b9dabbc3f59d448a /internal/task
parent9955a2f10c034dac60bc17cde6b80b432e21d9d3 (diff)
feat: rename working_dir→project_dir; git sandbox execution
- ClaudeConfig.WorkingDir → ProjectDir (json: project_dir) - UnmarshalJSON fallback reads legacy working_dir from DB records - New executions with project_dir clone into a temp sandbox via git clone --local - Non-git project_dirs get git init + initial commit before clone - After success: verify clean working tree, merge --ff-only back to project_dir, remove sandbox - On failure/BLOCKED: sandbox preserved, path included in error message - Resume executions run directly in project_dir (no re-clone) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Diffstat (limited to 'internal/task')
-rw-r--r--internal/task/task.go26
-rw-r--r--internal/task/validator_test.go2
2 files changed, 25 insertions, 3 deletions
diff --git a/internal/task/task.go b/internal/task/task.go
index f6635cc..498c364 100644
--- a/internal/task/task.go
+++ b/internal/task/task.go
@@ -1,6 +1,9 @@
package task
-import "time"
+import (
+ "encoding/json"
+ "time"
+)
type State string
@@ -29,7 +32,7 @@ type ClaudeConfig struct {
Model string `yaml:"model" json:"model"`
ContextFiles []string `yaml:"context_files" json:"context_files"`
Instructions string `yaml:"instructions" json:"instructions"`
- WorkingDir string `yaml:"working_dir" json:"working_dir"`
+ ProjectDir string `yaml:"project_dir" json:"project_dir"`
MaxBudgetUSD float64 `yaml:"max_budget_usd" json:"max_budget_usd"`
PermissionMode string `yaml:"permission_mode" json:"permission_mode"`
AllowedTools []string `yaml:"allowed_tools" json:"allowed_tools"`
@@ -39,6 +42,25 @@ type ClaudeConfig struct {
SkipPlanning bool `yaml:"skip_planning" json:"skip_planning"`
}
+// UnmarshalJSON reads project_dir with fallback to legacy working_dir.
+func (c *ClaudeConfig) UnmarshalJSON(data []byte) error {
+ type Alias ClaudeConfig
+ aux := &struct {
+ ProjectDir string `json:"project_dir"`
+ WorkingDir string `json:"working_dir"` // legacy
+ *Alias
+ }{Alias: (*Alias)(c)}
+ if err := json.Unmarshal(data, aux); err != nil {
+ return err
+ }
+ if aux.ProjectDir != "" {
+ c.ProjectDir = aux.ProjectDir
+ } else {
+ c.ProjectDir = aux.WorkingDir
+ }
+ return nil
+}
+
type RetryConfig struct {
MaxAttempts int `yaml:"max_attempts" json:"max_attempts"`
Backoff string `yaml:"backoff" json:"backoff"` // "linear", "exponential"
diff --git a/internal/task/validator_test.go b/internal/task/validator_test.go
index 967eed3..02bde45 100644
--- a/internal/task/validator_test.go
+++ b/internal/task/validator_test.go
@@ -11,7 +11,7 @@ func validTask() *Task {
Name: "Valid Task",
Claude: ClaudeConfig{
Instructions: "do something",
- WorkingDir: "/tmp",
+ ProjectDir: "/tmp",
},
Priority: PriorityNormal,
Retry: RetryConfig{MaxAttempts: 1, Backoff: "exponential"},