diff --git a/packages/hooks/hooks-claude/src/index.ts b/packages/hooks/hooks-claude/src/index.ts index 7e21f7ea82..6816201e60 100644 --- a/packages/hooks/hooks-claude/src/index.ts +++ b/packages/hooks/hooks-claude/src/index.ts @@ -290,8 +290,9 @@ export function apply(ctx: Context, config: Config): void { // Look up the child (still recoverable: `subagent/end` fires from the // service's detached `.then` BEFORE the tool caller's `await run.result` // disposes it) so the hook runs in the child's cwd, not the server default. - // No `.then`/inject (SubagentStop only observes) and no session is passed, so - // runPoint cannot reject — no `.catch` is needed. Fire-and-forget. + // No `.then`/inject follows (SubagentStop only observes), and no `turn` is + // passed (so no `hook/*` log records), so runPoint has nothing that can + // reject — no `.catch` is needed. Fire-and-forget. const child = ctx.get('agents')?.get(info.id) void runPoint('SubagentStop', SUBAGENT_TYPE, subagentPayload('SubagentStop', info, child), { ...child ? { agent: child } : {} }) }) diff --git a/packages/hooks/hooks-claude/tests/coverage.spec.ts b/packages/hooks/hooks-claude/tests/coverage.spec.ts index 097e026d1a..c1c6d1581d 100644 --- a/packages/hooks/hooks-claude/tests/coverage.spec.ts +++ b/packages/hooks/hooks-claude/tests/coverage.spec.ts @@ -493,13 +493,11 @@ describe('hooks-claude coverage — hook runs in the session cwd, not the server }) it('runs a SubagentStop hook in the CHILD session workspace, not the server cwd', async () => { - // The bug: SubagentStop ran runPoint(..., {}) with no agent, so the hook fell - // back to the executor default (server cwd). SubagentStop must look the child - // up (still recoverable at subagent/end) and run in the CHILD's session cwd. - // Here the executor default and the child session cwd are DIFFERENT dirs; a - // SubagentStop hook writes `pwd` to a marker and we assert it ran in the CHILD - // dir. (Proven to regress: neuter the child lookup and the marker lands in the - // server dir instead.) + // SubagentStop looks the child up (recoverable at subagent/end) and runs the + // hook in the CHILD's session cwd, not the executor default. Here the executor + // default and the child session cwd are DIFFERENT dirs; a SubagentStop hook + // writes `pwd` to a relative marker and we assert it landed in the CHILD dir — + // which only holds if the listener threaded the child agent into runPoint. const serverDir = dir() const childDir = dir() const marker = join(childDir, 'stopwhere')