summaryrefslogtreecommitdiff
path: root/internal/cli/serve.go
diff options
context:
space:
mode:
authorClaudomator Agent <agent@claudomator.local>2026-03-21 23:18:50 +0000
committerClaudomator Agent <agent@claudomator.local>2026-03-21 23:18:50 +0000
commit8dca9bbb0baee59ffe0d3127180ef0958dda8b91 (patch)
treee887036f4cce0f10694c5b9a29f4b4dc251769ba /internal/cli/serve.go
parent9e35f7e4087cfa6017cb65ec6a7036f394f5eb22 (diff)
feat: executor reliability — per-agent limit, drain gate, pre-flight creds, auth recovery
- maxPerAgent=1: only 1 in-flight execution per agent type at a time; excess tasks are requeued after 30s - Drain gate: after 2 consecutive failures the agent is drained and a question is set on the task; reset on first success; POST /api/pool/agents/{agent}/undrain to acknowledge - Pre-flight credential check: verify .credentials.json and .claude.json exist in agentHome before spinning up a container - Auth error auto-recovery: detect auth errors (Not logged in, OAuth token has expired, etc.) and retry once after running sync-credentials and re-copying fresh credentials - Extracted runContainer() helper from ContainerRunner.Run() to support the retry flow - Wire CredentialSyncCmd in serve.go for all three ContainerRunner instances - Tests: TestPool_MaxPerAgent_*, TestPool_ConsecutiveFailures_*, TestPool_Undrain_*, TestContainerRunner_Missing{Credentials,Settings}_FailsFast, TestIsAuthError_*, TestContainerRunner_AuthError_SyncsAndRetries Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Diffstat (limited to 'internal/cli/serve.go')
-rw-r--r--internal/cli/serve.go46
1 files changed, 25 insertions, 21 deletions
diff --git a/internal/cli/serve.go b/internal/cli/serve.go
index 1d0de21..e7b6b71 100644
--- a/internal/cli/serve.go
+++ b/internal/cli/serve.go
@@ -78,35 +78,39 @@ func serve(addr string) error {
// Use configured credentials dir; sync-credentials keeps this populated.
claudeConfigDir := cfg.ClaudeConfigDir
+ repoDir, _ := os.Getwd()
runners := map[string]executor.Runner{
// ContainerRunner: binaries are resolved via PATH inside the container image,
// so ClaudeBinary/GeminiBinary are left empty (host paths would not exist inside).
"claude": &executor.ContainerRunner{
- Image: cfg.ClaudeImage,
- Logger: logger,
- LogDir: cfg.LogDir,
- APIURL: apiURL,
- DropsDir: cfg.DropsDir,
- SSHAuthSock: cfg.SSHAuthSock,
- ClaudeConfigDir: claudeConfigDir,
+ Image: cfg.ClaudeImage,
+ Logger: logger,
+ LogDir: cfg.LogDir,
+ APIURL: apiURL,
+ DropsDir: cfg.DropsDir,
+ SSHAuthSock: cfg.SSHAuthSock,
+ ClaudeConfigDir: claudeConfigDir,
+ CredentialSyncCmd: filepath.Join(repoDir, "scripts", "sync-credentials"),
},
"gemini": &executor.ContainerRunner{
- Image: cfg.GeminiImage,
- Logger: logger,
- LogDir: cfg.LogDir,
- APIURL: apiURL,
- DropsDir: cfg.DropsDir,
- SSHAuthSock: cfg.SSHAuthSock,
- ClaudeConfigDir: claudeConfigDir,
+ Image: cfg.GeminiImage,
+ Logger: logger,
+ LogDir: cfg.LogDir,
+ APIURL: apiURL,
+ DropsDir: cfg.DropsDir,
+ SSHAuthSock: cfg.SSHAuthSock,
+ ClaudeConfigDir: claudeConfigDir,
+ CredentialSyncCmd: filepath.Join(repoDir, "scripts", "sync-credentials"),
},
"container": &executor.ContainerRunner{
- Image: "claudomator-agent:latest",
- Logger: logger,
- LogDir: cfg.LogDir,
- APIURL: apiURL,
- DropsDir: cfg.DropsDir,
- SSHAuthSock: cfg.SSHAuthSock,
- ClaudeConfigDir: claudeConfigDir,
+ Image: "claudomator-agent:latest",
+ Logger: logger,
+ LogDir: cfg.LogDir,
+ APIURL: apiURL,
+ DropsDir: cfg.DropsDir,
+ SSHAuthSock: cfg.SSHAuthSock,
+ ClaudeConfigDir: claudeConfigDir,
+ CredentialSyncCmd: filepath.Join(repoDir, "scripts", "sync-credentials"),
},
}