diff --git a/agents/gsd-debugger.md b/agents/gsd-debugger.md index 8c7109032..3ed354166 100644 --- a/agents/gsd-debugger.md +++ b/agents/gsd-debugger.md @@ -2,6 +2,7 @@ name: gsd-debugger description: Investigates bugs using scientific method, manages debug sessions, handles checkpoints. Spawned by /gsd:debug orchestrator. tools: Read, Write, Edit, Bash, Grep, Glob, WebSearch +permissionMode: acceptEdits color: orange # hooks: # PostToolUse: diff --git a/agents/gsd-executor.md b/agents/gsd-executor.md index a7673e6f0..03cbf9b3e 100644 --- a/agents/gsd-executor.md +++ b/agents/gsd-executor.md @@ -2,6 +2,7 @@ name: gsd-executor description: Executes GSD plans with atomic commits, deviation handling, checkpoint protocols, and state management. Spawned by execute-phase orchestrator or execute-plan command. tools: Read, Write, Edit, Bash, Grep, Glob +permissionMode: acceptEdits color: yellow # hooks: # PostToolUse: diff --git a/get-shit-done/workflows/map-codebase.md b/get-shit-done/workflows/map-codebase.md index 7c0e44bf2..ed061f504 100644 --- a/get-shit-done/workflows/map-codebase.md +++ b/get-shit-done/workflows/map-codebase.md @@ -85,10 +85,7 @@ Continue to spawn_agents. Before spawning agents, detect whether the current runtime supports the `Task` tool for subagent delegation. -**Runtimes with Task tool:** Claude Code, Cursor, OpenCode (native subagent support via `Task` or `task`) -**Runtimes WITHOUT Task tool:** Antigravity, Gemini CLI, Codex, and others - -**How to detect:** Check if you have access to a `Task` or `task` tool (either casing counts). If you do NOT have a Task/task tool (or only have tools like `browser_subagent` which is for web browsing, NOT code analysis): +**How to detect:** Check if you have access to a `Task` tool (may be capitalized as `Task` or lowercase as `task` depending on runtime). If you do NOT have a `Task`/`task` tool (or only have tools like `browser_subagent` which is for web browsing, NOT code analysis): → **Skip `spawn_agents` and `collect_confirmations`** — go directly to `sequential_mapping` instead. @@ -218,7 +215,7 @@ If any agent failed, note the failure and continue with successful documents. Continue to verify_output. - + When the `Task` tool is unavailable, perform codebase mapping sequentially in the current context. This replaces `spawn_agents` and `collect_confirmations`. **IMPORTANT:** Do NOT use `browser_subagent`, `Explore`, or any browser-based tool. Use only file system tools (Read, Bash, Write, Grep, Glob, list_dir, view_file, grep_search, or equivalent tools available in your runtime). diff --git a/tests/agent-frontmatter.test.cjs b/tests/agent-frontmatter.test.cjs index f9977c338..19b5a956f 100644 --- a/tests/agent-frontmatter.test.cjs +++ b/tests/agent-frontmatter.test.cjs @@ -339,3 +339,56 @@ describe('DISCUSS: discussion log generation', () => { ); }); }); + +// ─── Worktree Permission Mode (#1334) ─────────────────────────────────────── + +describe('PERM: worktree agents have permissionMode: acceptEdits', () => { + // Agents spawned with isolation="worktree" need permissionMode: acceptEdits + // to avoid per-directory edit permission prompts in the worktree path. + // See: anthropics/claude-code#29110, anthropics/claude-code#28041 + const WORKTREE_AGENTS = ['gsd-executor', 'gsd-debugger']; + + for (const agent of WORKTREE_AGENTS) { + test(`${agent} has permissionMode: acceptEdits`, () => { + const content = fs.readFileSync(path.join(AGENTS_DIR, agent + '.md'), 'utf-8'); + const frontmatter = content.split('---')[1] || ''; + assert.ok( + frontmatter.includes('permissionMode: acceptEdits'), + `${agent} must have permissionMode: acceptEdits — worktree agents need this to avoid ` + + `per-directory edit permission prompts (see #1334)` + ); + }); + } + + test('worktree-spawned agents are covered', () => { + // Verify that agents referenced with isolation="worktree" in workflows + // are included in the WORKTREE_AGENTS list above + const dirs = [WORKFLOWS_DIR, COMMANDS_DIR]; + const worktreeAgentTypes = new Set(); + + for (const dir of dirs) { + if (!fs.existsSync(dir)) continue; + const files = fs.readdirSync(dir).filter(f => f.endsWith('.md')); + for (const file of files) { + const content = fs.readFileSync(path.join(dir, file), 'utf-8'); + // Find patterns like: subagent_type="gsd-executor" ... isolation="worktree" + // These can span multiple lines in Task() calls + const taskBlocks = content.match(/Task\([^)]*isolation="worktree"[^)]*\)/gs) || []; + for (const block of taskBlocks) { + const typeMatch = block.match(/subagent_type="([^"]+)"/); + if (typeMatch) { + worktreeAgentTypes.add(typeMatch[1]); + } + } + } + } + + for (const agentType of worktreeAgentTypes) { + assert.ok( + WORKTREE_AGENTS.includes(agentType), + `${agentType} is spawned with isolation="worktree" but not in WORKTREE_AGENTS list — ` + + `add permissionMode: acceptEdits to its frontmatter and update this test` + ); + } + }); +});