fix(start-work): remove worktree setup prompt when unspecified, add strong worktree active instructions

When no worktree is specified in boulder, stop injecting 'Worktree Setup Required'
instructions. When worktree IS present, inject emphatic instructions ensuring the
agent and all subagents operate exclusively within the worktree directory.
This commit is contained in:
YeonGyu-Kim
2026-03-06 14:20:32 +09:00
parent 8cc3d4b99a
commit 97b2208aaa
2 changed files with 24 additions and 18 deletions
+12 -8
View File
@@ -417,7 +417,7 @@ describe("start-work hook", () => {
detectSpy.mockRestore() detectSpy.mockRestore()
}) })
test("should inject model-decides instructions when no --worktree flag", async () => { test("should NOT inject worktree instructions when no --worktree flag", async () => {
// given - single plan, no worktree flag // given - single plan, no worktree flag
const plansDir = join(testDir, ".sisyphus", "plans") const plansDir = join(testDir, ".sisyphus", "plans")
mkdirSync(plansDir, { recursive: true }) mkdirSync(plansDir, { recursive: true })
@@ -431,10 +431,10 @@ describe("start-work hook", () => {
// when // when
await hook["chat.message"]({ sessionID: "session-123" }, output) await hook["chat.message"]({ sessionID: "session-123" }, output)
// then - model-decides instructions should appear // then - no worktree instructions should appear
expect(output.parts[0].text).toContain("Worktree Setup Required") expect(output.parts[0].text).not.toContain("Worktree Setup Required")
expect(output.parts[0].text).toContain("git worktree list --porcelain") expect(output.parts[0].text).not.toContain("Worktree Active")
expect(output.parts[0].text).toContain("git worktree add") expect(output.parts[0].text).not.toContain("git worktree list --porcelain")
}) })
test("should inject worktree path when --worktree flag is valid", async () => { test("should inject worktree path when --worktree flag is valid", async () => {
@@ -452,8 +452,10 @@ describe("start-work hook", () => {
// when // when
await hook["chat.message"]({ sessionID: "session-123" }, output) await hook["chat.message"]({ sessionID: "session-123" }, output)
// then - validated path shown, no model-decides instructions // then - strong worktree active instructions shown
expect(output.parts[0].text).toContain("**Worktree**: /validated/worktree") expect(output.parts[0].text).toContain("Worktree Active")
expect(output.parts[0].text).toContain("/validated/worktree")
expect(output.parts[0].text).toContain("subagent")
expect(output.parts[0].text).not.toContain("Worktree Setup Required") expect(output.parts[0].text).not.toContain("Worktree Setup Required")
}) })
@@ -548,8 +550,10 @@ describe("start-work hook", () => {
// when // when
await hook["chat.message"]({ sessionID: "session-789" }, output) await hook["chat.message"]({ sessionID: "session-789" }, output)
// then - shows existing worktree, no model-decides instructions // then - shows strong worktree active instructions
expect(output.parts[0].text).toContain("Worktree Active")
expect(output.parts[0].text).toContain("/existing/wt") expect(output.parts[0].text).toContain("/existing/wt")
expect(output.parts[0].text).toContain("subagent")
expect(output.parts[0].text).not.toContain("Worktree Setup Required") expect(output.parts[0].text).not.toContain("Worktree Setup Required")
}) })
}) })
+12 -10
View File
@@ -34,26 +34,28 @@ function findPlanByName(plans: string[], requestedName: string): string | null {
return partialMatch || null return partialMatch || null
} }
const MODEL_DECIDES_WORKTREE_BLOCK = ` function createWorktreeActiveBlock(worktreePath: string): string {
## Worktree Setup Required return `
## Worktree Active
No worktree specified. Before starting work, you MUST choose or create one: **Worktree**: \`${worktreePath}\`
1. \`git worktree list --porcelain\` — list existing worktrees **CRITICAL — DO NOT FORGET**: You are working inside a git worktree. ALL operations MUST be performed exclusively within this worktree directory.
2. Create if needed: \`git worktree add <absolute-path> <branch-or-HEAD>\` - Every file read, write, edit, and git operation MUST target paths under: \`${worktreePath}\`
3. Update \`.sisyphus/boulder.json\` — add \`"worktree_path": "<absolute-path>"\` - When delegating tasks to subagents, you MUST include the worktree path in your delegation prompt so they also operate exclusively within the worktree
4. Work exclusively inside that worktree directory` - NEVER operate on the main repository directory — always use the worktree path above`
}
function resolveWorktreeContext( function resolveWorktreeContext(
explicitWorktreePath: string | null, explicitWorktreePath: string | null,
): { worktreePath: string | undefined; block: string } { ): { worktreePath: string | undefined; block: string } {
if (explicitWorktreePath === null) { if (explicitWorktreePath === null) {
return { worktreePath: undefined, block: MODEL_DECIDES_WORKTREE_BLOCK } return { worktreePath: undefined, block: "" }
} }
const validatedPath = detectWorktreePath(explicitWorktreePath) const validatedPath = detectWorktreePath(explicitWorktreePath)
if (validatedPath) { if (validatedPath) {
return { worktreePath: validatedPath, block: `\n**Worktree**: ${validatedPath}` } return { worktreePath: validatedPath, block: createWorktreeActiveBlock(validatedPath) }
} }
return { return {
@@ -165,7 +167,7 @@ No incomplete plans available. Create a new plan with: /plan "your task"`
appendSessionId(ctx.directory, sessionId) appendSessionId(ctx.directory, sessionId)
} }
const worktreeDisplay = effectiveWorktree ? `\n**Worktree**: ${effectiveWorktree}` : worktreeBlock const worktreeDisplay = effectiveWorktree ? createWorktreeActiveBlock(effectiveWorktree) : worktreeBlock
contextInfo = ` contextInfo = `
## Active Work Session Found ## Active Work Session Found