diff --git a/hooks/hooks.json b/hooks/hooks.json index 80886bc..9087627 100644 --- a/hooks/hooks.json +++ b/hooks/hooks.json @@ -5,7 +5,7 @@ "hooks": [ { "type": "command", - "command": "node ./hooks/session-start.mjs" + "command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/session-start.mjs" } ] } @@ -14,9 +14,8 @@ { "hooks": [ { - "type": "prompt", - "prompt": "Check if Specwright has active work. Read .specwright/state/workflow.json. If currentWork exists and currentWork.status is NOT 'shipped', 'abandoned', or null, respond: {\"ok\": false, \"reason\": \"Specwright has active work: [work-id] (status: [status], [completed]/[total] tasks done). Consider running /sw-status before ending this session, or /sw-status --reset to abandon.\"}. If no active work or file does not exist, respond: {\"ok\": true}. IMPORTANT: Check $ARGUMENTS — if stop_hook_active is true, always respond {\"ok\": true} to prevent loops.", - "timeout": 10 + "type": "command", + "command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/session-stop.mjs" } ] } diff --git a/hooks/session-stop.mjs b/hooks/session-stop.mjs new file mode 100644 index 0000000..2d84e8d --- /dev/null +++ b/hooks/session-stop.mjs @@ -0,0 +1,38 @@ +/** + * Specwright session-stop hook. + * Checks if there's active work and warns the user before ending the session. + * Deterministic — no LLM involved. + */ + +import { readFileSync, existsSync } from 'fs'; +import { join } from 'path'; + +const cwd = process.cwd(); +const statePath = join(cwd, '.specwright', 'state', 'workflow.json'); + +if (!existsSync(statePath)) { + // No Specwright state — nothing to warn about + console.log(JSON.stringify({ ok: true })); + process.exit(0); +} + +try { + const state = JSON.parse(readFileSync(statePath, 'utf-8')); + const work = state.currentWork; + + if (work && !['shipped', 'abandoned', null].includes(work.status)) { + const completed = work.tasksCompleted?.length ?? 0; + const total = work.tasksTotal ?? '?'; + console.log(JSON.stringify({ + ok: false, + reason: `Specwright has active work: ${work.id} (status: ${work.status}, ${completed}/${total} tasks done). Consider running /sw-status before ending this session, or /sw-status --reset to abandon.` + })); + } else { + console.log(JSON.stringify({ ok: true })); + } +} catch { + // Don't block session end on read errors + console.log(JSON.stringify({ ok: true })); +} + +process.exit(0);