@haposoft/cafekit 0.16.7 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (193) hide show
  1. package/README.md +14 -22
  2. package/bin/__tests__/codex-hooks-ownership.test.js +2 -2
  3. package/bin/__tests__/codex-hooks.test.js +0 -36
  4. package/bin/__tests__/codex-native.test.js +46 -88
  5. package/bin/__tests__/develop-contract.test.js +26 -57
  6. package/bin/__tests__/docs-sync-on-demand.test.js +93 -0
  7. package/bin/__tests__/grok-envelope.test.js +0 -56
  8. package/bin/__tests__/hook-payload.test.js +4 -6
  9. package/bin/__tests__/legacy-authority-decoupled.test.js +159 -0
  10. package/bin/__tests__/legacy-hooks-retired.test.js +221 -0
  11. package/bin/__tests__/omp-bridge.test.js +20 -17
  12. package/bin/__tests__/omp-hooks.test.js +0 -19
  13. package/bin/__tests__/optional-skill-inventory.test.js +112 -4
  14. package/bin/__tests__/orca-session.test.js +0 -2
  15. package/bin/__tests__/package-inventory.test.js +100 -541
  16. package/bin/__tests__/runtime-dir.test.js +0 -3
  17. package/bin/__tests__/runtime-schema.test.js +3 -2
  18. package/bin/__tests__/skill-routing-source.test.js +27 -15
  19. package/bin/__tests__/spec-narrowing.test.js +0 -27
  20. package/bin/__tests__/specs-v2-execution-closeout.test.js +4 -69
  21. package/bin/__tests__/ui-ux-skill.test.js +101 -0
  22. package/bin/__tests__/usage-hook-retired.test.js +114 -0
  23. package/bin/__tests__/validator-grounding.test.js +9 -28
  24. package/bin/phases/codex-runtime.js +24 -0
  25. package/bin/phases/omp-runtime.js +22 -0
  26. package/package.json +1 -1
  27. package/src/claude/CLAUDE.md +3 -10
  28. package/src/claude/agents/brainstormer.md +7 -3
  29. package/src/claude/agents/code-auditor.md +35 -50
  30. package/src/claude/agents/debugger.md +5 -79
  31. package/src/claude/agents/deployer.md +3 -5
  32. package/src/claude/agents/docs-keeper.md +2 -7
  33. package/src/claude/agents/implementer.md +6 -9
  34. package/src/claude/agents/inspector.md +2 -3
  35. package/src/claude/agents/project-manager.md +7 -15
  36. package/src/claude/agents/researcher.md +9 -3
  37. package/src/claude/agents/spec-maker.md +11 -11
  38. package/src/claude/hooks/__tests__/fixtures/statusline-default.golden +1 -1
  39. package/src/claude/hooks/__tests__/spec-gate.test.js +74 -3
  40. package/src/claude/hooks/__tests__/spec-state-touched.test.js +134 -0
  41. package/src/claude/hooks/__tests__/state.test.js +68 -0
  42. package/src/claude/hooks/__tests__/statusline.test.js +140 -11
  43. package/src/claude/hooks/agent.cjs +2 -1
  44. package/src/claude/hooks/lib/context.cjs +0 -89
  45. package/src/claude/hooks/lib/hook-payload.cjs +2 -2
  46. package/src/claude/hooks/rules.cjs +2 -1
  47. package/src/claude/hooks/session.cjs +0 -1
  48. package/src/claude/hooks/spec-gate.cjs +17 -28
  49. package/src/claude/hooks/spec-state.cjs +95 -1
  50. package/src/claude/hooks/state.cjs +21 -2
  51. package/src/claude/migration-manifest.json +30 -15
  52. package/src/claude/rules/ai-dev-rules.md +1 -1
  53. package/src/claude/rules/hook-protocols.md +8 -15
  54. package/src/claude/rules/manage-docs.md +9 -23
  55. package/src/claude/rules/orchestrator.md +3 -4
  56. package/src/claude/rules/review-audit-self-decision.md +3 -3
  57. package/src/claude/rules/skill-domain-routing.md +1 -3
  58. package/src/claude/rules/skill-workflow-routing.md +4 -5
  59. package/src/claude/rules/state-sync.md +3 -12
  60. package/src/claude/rules/workflow.md +10 -18
  61. package/src/claude/runtime.schema.json +5 -3
  62. package/src/claude/scripts/generate-skill-catalog.cjs +7 -6
  63. package/src/claude/scripts/provenance.cjs +23 -5
  64. package/src/claude/scripts/spec-receipt.cjs +24 -7
  65. package/src/claude/scripts/spec-resolver.cjs +1 -2
  66. package/src/claude/scripts/validate-spec-output.cjs +5 -32
  67. package/src/claude/settings/settings.json +1 -32
  68. package/src/claude/skills/{question → ask}/SKILL.md +9 -75
  69. package/src/claude/skills/brainstorm/SKILL.md +43 -131
  70. package/src/claude/skills/code-review/SKILL.md +48 -17
  71. package/src/claude/skills/code-review/references/spec-compliance-review.md +2 -3
  72. package/src/claude/skills/code-review/references/verification-gate.md +22 -27
  73. package/src/claude/skills/debug/SKILL.md +29 -149
  74. package/src/claude/skills/develop/SKILL.md +27 -36
  75. package/src/claude/skills/develop/references/parallel-waves.md +0 -8
  76. package/src/claude/skills/develop/references/quality-gate.md +15 -13
  77. package/src/claude/skills/docs/SKILL.md +2 -2
  78. package/src/claude/skills/docs/references/update-workflow.md +1 -1
  79. package/src/claude/skills/fix/SKILL.md +153 -0
  80. package/src/claude/skills/{hotfix → fix}/references/diagnosis-protocol.md +2 -2
  81. package/src/claude/skills/{hotfix → fix}/references/parallel-patterns.md +2 -2
  82. package/src/claude/skills/{hotfix → fix}/references/prevention-gate.md +3 -3
  83. package/src/claude/skills/{hotfix → fix}/references/review-cycle.md +1 -1
  84. package/src/claude/skills/git/SKILL.md +48 -9
  85. package/src/claude/skills/git/references/commit-protocols.md +35 -16
  86. package/src/claude/skills/git/references/worktree-blueprint.md +42 -6
  87. package/src/claude/skills/orca/SKILL.md +9 -8
  88. package/src/claude/skills/research/SKILL.md +2 -0
  89. package/src/claude/skills/scout/SKILL.md +61 -0
  90. package/src/claude/skills/{inspect → scout}/references/internal-inspection.md +26 -10
  91. package/src/claude/skills/specs/SKILL.md +22 -29
  92. package/src/claude/skills/specs/references/review.md +8 -6
  93. package/src/claude/skills/specs/references/templates.md +34 -41
  94. package/src/claude/skills/sync/SKILL.md +8 -15
  95. package/src/claude/skills/sync/references/rebind-and-audit.md +59 -0
  96. package/src/claude/skills/sync/references/sync-protocols.md +4 -13
  97. package/src/claude/skills/test/SKILL.md +22 -3
  98. package/src/claude/skills/test/references/execution-strategy.md +83 -0
  99. package/src/claude/skills/test/references/failure-triage.md +1 -1
  100. package/src/claude/skills/ui-ux/LICENSE +21 -0
  101. package/src/claude/skills/ui-ux/SKILL.md +497 -0
  102. package/src/claude/skills/ui-ux/references/brand-tokens.md +90 -0
  103. package/src/claude/skills/ui-ux/references/budgets.md +113 -0
  104. package/src/claude/skills/ui-ux/references/checklist.md +271 -0
  105. package/src/claude/skills/ui-ux/references/components/accordion.md +246 -0
  106. package/src/claude/skills/ui-ux/references/components/avatar.md +153 -0
  107. package/src/claude/skills/ui-ux/references/components/banner.md +43 -0
  108. package/src/claude/skills/ui-ux/references/components/breadcrumb.md +201 -0
  109. package/src/claude/skills/ui-ux/references/components/button.md +142 -0
  110. package/src/claude/skills/ui-ux/references/components/card.md +113 -0
  111. package/src/claude/skills/ui-ux/references/components/charts.md +376 -0
  112. package/src/claude/skills/ui-ux/references/components/chat.md +132 -0
  113. package/src/claude/skills/ui-ux/references/components/choice-controls.md +369 -0
  114. package/src/claude/skills/ui-ux/references/components/comment-thread.md +17 -0
  115. package/src/claude/skills/ui-ux/references/components/description-list.md +116 -0
  116. package/src/claude/skills/ui-ux/references/components/empty-state.md +98 -0
  117. package/src/claude/skills/ui-ux/references/components/file-upload.md +107 -0
  118. package/src/claude/skills/ui-ux/references/components/inline-edit.md +128 -0
  119. package/src/claude/skills/ui-ux/references/components/input.md +161 -0
  120. package/src/claude/skills/ui-ux/references/components/list-row.md +56 -0
  121. package/src/claude/skills/ui-ux/references/components/loading.md +198 -0
  122. package/src/claude/skills/ui-ux/references/components/logo.md +147 -0
  123. package/src/claude/skills/ui-ux/references/components/otp-input.md +43 -0
  124. package/src/claude/skills/ui-ux/references/components/quantity-input.md +100 -0
  125. package/src/claude/skills/ui-ux/references/components/range-slider.md +16 -0
  126. package/src/claude/skills/ui-ux/references/components/small-controls.md +340 -0
  127. package/src/claude/skills/ui-ux/references/components/sortable-header.md +86 -0
  128. package/src/claude/skills/ui-ux/references/components/tag-input.md +14 -0
  129. package/src/claude/skills/ui-ux/references/components/timeline.md +38 -0
  130. package/src/claude/skills/ui-ux/references/components/tree.md +30 -0
  131. package/src/claude/skills/ui-ux/references/design-process.md +650 -0
  132. package/src/claude/skills/ui-ux/references/layouts/app-kanban.html +303 -0
  133. package/src/claude/skills/ui-ux/references/layouts/app.md +1369 -0
  134. package/src/claude/skills/ui-ux/references/layouts/form.md +430 -0
  135. package/src/claude/skills/ui-ux/references/layouts/overlay.md +552 -0
  136. package/src/claude/skills/ui-ux/references/layouts/pricing.md +204 -0
  137. package/src/claude/skills/ui-ux/references/locked-rules.md +35 -0
  138. package/src/claude/skills/ui-ux/references/principles.md +408 -0
  139. package/src/claude/skills/ui-ux/references/refactor.md +245 -0
  140. package/src/claude/skills/ui-ux/references/responsive.md +195 -0
  141. package/src/claude/skills/ui-ux/references/review.md +528 -0
  142. package/src/claude/skills/ui-ux/references/rules-color.md +623 -0
  143. package/src/claude/skills/ui-ux/references/rules-form.md +235 -0
  144. package/src/claude/skills/ui-ux/references/rules-state.md +680 -0
  145. package/src/claude/skills/ui-ux/references/rules-type.md +369 -0
  146. package/src/claude/skills/ui-ux/references/styles.md +311 -0
  147. package/src/claude/skills/ui-ux/references/system.md +219 -0
  148. package/src/claude/skills/ui-ux/references/tailwind-v4-traps.md +237 -0
  149. package/src/claude/skills/ui-ux/references/tokens.css +362 -0
  150. package/src/claude/skills/ui-ux/scripts/lint-skill.mjs +216 -0
  151. package/src/claude/skills/ui-ux/scripts/package.json +9 -0
  152. package/src/claude/skills/ui-ux/scripts/probe.mjs +4447 -0
  153. package/src/claude/skills/ui-ux-pro-max/SKILL.md +1 -1
  154. package/src/claude/status.cjs +149 -144
  155. package/src/codex/AGENTS.md +8 -13
  156. package/src/codex/hooks/agent.cjs +2 -1
  157. package/src/codex/hooks/lib/spec-receipt.cjs +2 -2
  158. package/src/codex/hooks/lib/spec-utils.cjs +0 -7
  159. package/src/codex/hooks/rules.cjs +2 -1
  160. package/src/codex/hooks/session.cjs +0 -2
  161. package/src/codex/hooks/spec-gate.cjs +7 -18
  162. package/src/codex/hooks.json +0 -20
  163. package/src/codex/rules/state-sync.md +3 -12
  164. package/src/common/AGENTS.md +2 -2
  165. package/src/omp/extensions/cafekit-bridge.mjs +6 -6
  166. package/src/claude/hooks/__tests__/completion-authority.test.js +0 -990
  167. package/src/claude/hooks/__tests__/semantic-review-authority.test.js +0 -259
  168. package/src/claude/hooks/completion-authority-check.cjs +0 -56
  169. package/src/claude/hooks/completion-authority-state.cjs +0 -527
  170. package/src/claude/hooks/completion-authority.cjs +0 -163
  171. package/src/claude/hooks/semantic-review-authority.cjs +0 -154
  172. package/src/claude/hooks/task-scaffold-guard.cjs +0 -114
  173. package/src/claude/hooks/usage.cjs +0 -197
  174. package/src/claude/skills/delegate/SKILL.md +0 -124
  175. package/src/claude/skills/delegate/references/codex-delegation.md +0 -71
  176. package/src/claude/skills/delegate/references/grok-delegation.md +0 -84
  177. package/src/claude/skills/hotfix/SKILL.md +0 -289
  178. package/src/claude/skills/inspect/SKILL.md +0 -142
  179. package/src/claude/skills/loop/SKILL.md +0 -114
  180. package/src/claude/skills/loop/references/bounded-loop-protocol.md +0 -104
  181. package/src/claude/skills/loop/references/metric-and-guard-contract.md +0 -76
  182. package/src/claude/skills/route/SKILL.md +0 -94
  183. package/src/claude/skills/route/references/agent-timing.md +0 -46
  184. package/src/claude/skills/route/references/chaining-patterns.md +0 -53
  185. package/src/claude/skills/route/references/task-taxonomy.md +0 -48
  186. package/src/codex/hooks/completion-authority-check.cjs +0 -67
  187. package/src/codex/hooks/completion-authority-state.cjs +0 -527
  188. package/src/codex/hooks/completion-authority.cjs +0 -109
  189. package/src/codex/hooks/semantic-review-authority.cjs +0 -130
  190. package/src/codex/hooks/task-scaffold-guard.cjs +0 -63
  191. /package/src/claude/skills/{question → ask}/templates/question.md +0 -0
  192. /package/src/claude/skills/{hotfix → fix}/references/escalation-tactics.md +0 -0
  193. /package/src/claude/skills/{hotfix → fix}/references/workflow-specialized.md +0 -0
@@ -70,6 +70,7 @@ try {
70
70
  const baseDir = cwd;
71
71
  const plansPath = path.join(baseDir, runtime.paths?.plans || 'plans');
72
72
  const docsPath = path.join(baseDir, runtime.paths?.docs || 'docs');
73
+ const specsPath = path.join(baseDir, runtime.paths?.specs || 'specs');
73
74
  const maxLoc = runtime.docs?.maxLoc || 800;
74
75
 
75
76
  const lines = [];
@@ -84,7 +85,7 @@ try {
84
85
 
85
86
  lines.push(
86
87
  '## Rules',
87
- `- Markdown files: Plans → "${plansPath}/" | Docs → "${docsPath}/"`,
88
+ `- Markdown files: Specs → "${specsPath}/" | Plans → "${plansPath}/" | Docs → "${docsPath}/"`,
88
89
  '- **DO NOT** create markdown files outside of those directories unless explicitly asked.',
89
90
  `- docs.maxLoc: ${maxLoc} lines max per doc file`
90
91
  );
@@ -202,7 +202,6 @@ try {
202
202
  const envFile = process.env.CLAUDE_ENV_FILE;
203
203
  const cwd = projectRoot();
204
204
  const runtime = readRuntime(cwd);
205
- try { require('./completion-authority-state.cjs').clearState(cwd, payload.session_id); } catch { /* old installs remain fail-open */ }
206
205
 
207
206
  // Check CafeKit update in parallel with project detection (async, fail-open).
208
207
  const updateCheckPromise = checkCafeKitUpdate(cwd);
@@ -90,17 +90,17 @@ try {
90
90
  let POLICY;
91
91
  let RESOLVER;
92
92
  let RECEIPT;
93
- let FINAL_STATE;
94
93
  try {
95
94
  POLICY = require(policyPath);
95
+ // One gate run checks every done receipt against the same checkout; capture it once.
96
+ require(path.join(__dirname, '..', 'scripts', 'provenance.cjs')).enableSnapshotMemo();
96
97
  RESOLVER = require(path.join(__dirname, '..', 'scripts', 'spec-resolver.cjs'));
97
98
  RECEIPT = require(path.join(__dirname, '..', 'scripts', 'spec-receipt.cjs'));
98
- FINAL_STATE = require('./completion-authority-check.cjs');
99
99
  if (typeof POLICY.validateCanonicalReceipt !== 'function'
100
100
  || typeof POLICY.completionDecisionForSpec !== 'function'
101
101
  || typeof RECEIPT.checkTaskReceipt !== 'function'
102
102
  || typeof RECEIPT.checkWorkflowReceiptSet !== 'function'
103
- || typeof FINAL_STATE.evaluateCloseout !== 'function') {
103
+ || typeof RESOLVER.resolveWorkflowCandidate !== 'function') {
104
104
  throw new Error('shared workflow policy lacks completion authority functions');
105
105
  }
106
106
  } catch (error) {
@@ -127,9 +127,7 @@ try {
127
127
  || (typeof RESOLVER.readActiveFeatureTarget === 'function'
128
128
  ? RESOLVER.readActiveFeatureTarget({ projectRoot: baseDir, runtime })
129
129
  : null);
130
- let resolved = typeof RESOLVER.resolveWorkflowCandidate === 'function'
131
- ? RESOLVER.resolveWorkflowCandidate({ projectRoot: baseDir, runtime, target, includeCompleted: true })
132
- : FINAL_STATE.resolveCandidate({ resolver: RESOLVER, projectRoot: baseDir, runtime, payload });
130
+ let resolved = RESOLVER.resolveWorkflowCandidate({ projectRoot: baseDir, runtime, target, includeCompleted: true });
133
131
  if (typeof RESOLVER.refineWorkflowGateResolution === 'function') {
134
132
  resolved = RESOLVER.refineWorkflowGateResolution(resolved);
135
133
  }
@@ -150,7 +148,7 @@ try {
150
148
  const lines = [`⚠️ Completion gate: ${checked.failures.length} done task(s) lack a verification receipt.`];
151
149
  for (const failure of checked.failures) {
152
150
  lines.push(`- \`${failure.featureName}/${failure.taskPath}\`: failed check(s) ${failure.failures.join(', ')}`);
153
- const hint = typeof RECEIPT.receiptFixHint === 'function' ? RECEIPT.receiptFixHint(failure.failures) : null;
151
+ const hint = typeof RECEIPT.receiptFixHint === 'function' ? RECEIPT.receiptFixHint(failure.failures, failure.body) : null;
154
152
  lines.push(` Fix in \`specs/${failure.featureName}/${failure.taskPath}\`: ${hint || 'write a runtime-bound `## Receipt` with the planned command'}.`);
155
153
  }
156
154
  emitBlock(lines.slice(0, 8).join('\n'));
@@ -186,19 +184,10 @@ try {
186
184
  const lifecyclePhase = activeSpec.current_phase || activeSpec.phase;
187
185
  const explicitCloseout = ['done', 'completed', 'complete'].includes(activeSpec.status)
188
186
  || ['closeout', 'completion', 'completed', 'complete'].includes(lifecyclePhase);
189
- if (!processWorkflow && activeSpec.schema_version === '2.1') {
190
- const finalState = FINAL_STATE.evaluateCloseout({
191
- resolver: RESOLVER,
192
- policy: POLICY,
193
- projectRoot: baseDir,
194
- runtime,
195
- payload: { ...payload, session_id: sessionIdentity(payload) },
196
- });
197
- if (!finalState.ok) {
198
- emitBlock(`Completion gate: ${finalState.reason}`);
199
- process.exit(0);
200
- }
201
- if (finalState.active) process.exit(0);
187
+ // Legacy 2.1 closeout is retired; a 2.1 packet mid-execution keeps the ordinary receipt checks.
188
+ if (!processWorkflow && activeSpec.schema_version === '2.1' && explicitCloseout) {
189
+ emitBlock('Completion gate: Legacy spec.json closeout is no longer supported; move the packet to plan.md with flat task files');
190
+ process.exit(0);
202
191
  }
203
192
  const runtimeContext = POLICY.deriveRuntimeContext({
204
193
  projectRoot: baseDir,
@@ -251,12 +240,12 @@ try {
251
240
  );
252
241
  const featureDir = path.join(specsPath, featureName);
253
242
  const failures = allDoneTasks
254
- .map((taskPath) => ({
255
- taskPath,
256
- fails: processWorkflow
257
- ? RECEIPT.checkWorkflowTaskReceipt(featureDir, taskPath, runtimeContext, POLICY).failures
258
- : RECEIPT.checkTaskReceipt(featureDir, taskPath, taskRegistry[taskPath], runtimeContext, POLICY).failures,
259
- }))
243
+ .map((taskPath) => {
244
+ const proof = processWorkflow
245
+ ? RECEIPT.checkWorkflowTaskReceipt(featureDir, taskPath, runtimeContext, POLICY)
246
+ : RECEIPT.checkTaskReceipt(featureDir, taskPath, taskRegistry[taskPath], runtimeContext, POLICY);
247
+ return { taskPath, fails: proof.failures, body: proof.body };
248
+ })
260
249
  .filter((f) => f.fails.length > 0);
261
250
 
262
251
  const featureCloseoutRequired = !processWorkflow && explicitCloseout && allDoneTasks.length > 0;
@@ -298,12 +287,12 @@ try {
298
287
  ? `⚠️ Completion gate: ${failures.length} done task(s) lack a verification receipt.`
299
288
  : '⚠️ Completion gate: workflow completion proof is incomplete.',
300
289
  ];
301
- for (const { taskPath, fails } of failures) {
290
+ for (const { taskPath, fails, body } of failures) {
302
291
  lines.push(`- \`${taskPath}\`: failed check(s) ${fails.join(', ')}`);
303
292
  lines.push(taskPath === 'feature-receipt.md'
304
293
  ? ` Fix: run final integration proof, then write \`specs/${featureName}/feature-receipt.md\`.`
305
294
  : processWorkflow
306
- ? ` Fix in \`specs/${featureName}/${path.posix.basename(taskPath)}\`: ${(typeof RECEIPT.receiptFixHint === 'function' && RECEIPT.receiptFixHint(fails)) || 'write a runtime-bound `## Receipt` with command output'}.`
295
+ ? ` Fix in \`specs/${featureName}/${path.posix.basename(taskPath)}\`: ${(typeof RECEIPT.receiptFixHint === 'function' && RECEIPT.receiptFixHint(fails, body)) || 'write a runtime-bound `## Receipt` with command output'}.`
307
296
  : ` Fix: write canonical proof to \`specs/${featureName}/receipts/${path.posix.basename(taskPath)}\`; legacy \`## Evidence\` remains read-compatible.`);
308
297
  }
309
298
  if (completionBlocked) {
@@ -44,6 +44,40 @@ function canonicalPath(value) {
44
44
  try { return fs.realpathSync(value); } catch { return null; }
45
45
  }
46
46
 
47
+ /** Real path of `value`, resolving its deepest existing ancestor (the file may not exist yet). */
48
+ function canonicalTarget(value) {
49
+ if (typeof value !== 'string' || !value) return null;
50
+ let current = path.resolve(value);
51
+ const rest = [];
52
+ while (!fs.existsSync(current)) {
53
+ const parent = path.dirname(current);
54
+ if (parent === current) return null;
55
+ rest.unshift(path.basename(current));
56
+ current = parent;
57
+ }
58
+ const real = canonicalPath(current);
59
+ return real ? path.join(real, ...rest) : null;
60
+ }
61
+
62
+ function escapeRegExp(text) {
63
+ return text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
64
+ }
65
+
66
+ /**
67
+ * Packets the prompt names: `specs/<name>`, a `/cf:<command> <name>` token, or the bare
68
+ * name when it carries `-`, `_` or a digit. A plain word such as `docs` must use `specs/`,
69
+ * so an ordinary sentence does not touch a packet.
70
+ */
71
+ function packetsNamedIn(text, names) {
72
+ if (typeof text !== 'string' || !text) return [];
73
+ return names.filter((name) => {
74
+ const n = escapeRegExp(name);
75
+ if (new RegExp(`(^|[^\\w-])specs/${n}(?![\\w-])`).test(text)) return true;
76
+ if (new RegExp(`/cf:[\\w-]+\\s+(?:specs/)?${n}(?![\\w-])`).test(text)) return true;
77
+ return /[-_0-9]/.test(name) && new RegExp(`(^|[^\\w/-])${n}(?![\\w-])`).test(text);
78
+ });
79
+ }
80
+
47
81
  try {
48
82
  // ── Main ──────────────────────────────────────────────────────────────────
49
83
 
@@ -51,7 +85,8 @@ try {
51
85
  if (!stdin) process.exit(0);
52
86
 
53
87
  const { normalizeHookPayload } = require('./lib/hook-payload.cjs');
54
- const payload = normalizeHookPayload(JSON.parse(stdin));
88
+ const rawPayload = JSON.parse(stdin);
89
+ const payload = normalizeHookPayload(rawPayload);
55
90
  const cwd = payload.cwd || process.cwd();
56
91
 
57
92
  let POLICY;
@@ -84,6 +119,64 @@ try {
84
119
  const baseDir = installedRoot || process.env.PROJECT_ROOT || cwd;
85
120
  const explicitFeature = payload.featureName || payload.feature || payload.explicitFeature || null;
86
121
  const explicitPath = payload.specPath || payload.spec_path || payload.featurePath || null;
122
+
123
+ // ── Per-session touch set (Claude only) ───────────────────────────────────
124
+ // Several sessions can share one checkout. On Claude the tollgate speaks only about a
125
+ // packet this session touched. omp and Codex run their own copies, and grok sends
126
+ // `sessionId` before normalization, so all three keep the old behaviour.
127
+ const claudeSession = rawPayload && typeof rawPayload.session_id === 'string' && rawPayload.session_id
128
+ ? rawPayload.session_id
129
+ : null;
130
+ const touchFilter = runtimeDirName() === '.claude' && claudeSession !== null;
131
+ const touchFile = touchFilter
132
+ ? path.join(
133
+ require('./lib/hook-state-dir.cjs').hookStateDir(),
134
+ `spec-touched-${require('crypto').createHash('sha256').update(claudeSession).digest('hex')}.json`,
135
+ )
136
+ : null;
137
+ const readTouched = () => {
138
+ try {
139
+ const list = JSON.parse(fs.readFileSync(touchFile, 'utf8'));
140
+ return new Set(Array.isArray(list) ? list : []);
141
+ } catch { return new Set(); }
142
+ };
143
+ const addTouched = (names) => {
144
+ const touched = readTouched();
145
+ const before = touched.size;
146
+ for (const name of names) touched.add(name);
147
+ if (touched.size === before) return;
148
+ try {
149
+ fs.mkdirSync(path.dirname(touchFile), { recursive: true });
150
+ fs.writeFileSync(touchFile, JSON.stringify([...touched].sort()));
151
+ } catch { /* an unwritable state dir only loses the touch */ }
152
+ };
153
+ let specsRoot = null;
154
+ try { specsRoot = RESOLVER.specsDirectory(baseDir, runtime); } catch { /* resolver reports it below */ }
155
+
156
+ if (payload.hook_event_name === 'PostToolUse') {
157
+ // Record only; no resolve, no git, no tollgate cache.
158
+ if (touchFilter && specsRoot && /^(Edit|Write|MultiEdit)$/.test(payload.tool_name || '')) {
159
+ const realRoot = canonicalPath(specsRoot);
160
+ const realTarget = canonicalTarget(payload.tool_input && payload.tool_input.file_path);
161
+ if (realRoot && realTarget) {
162
+ const rel = path.relative(realRoot, realTarget);
163
+ const parts = rel.split(path.sep);
164
+ if (rel && parts[0] !== '..' && !path.isAbsolute(rel) && parts.length > 1) addTouched([parts[0]]);
165
+ }
166
+ }
167
+ process.exit(0);
168
+ }
169
+
170
+ if (touchFilter) {
171
+ let packets = [];
172
+ try {
173
+ packets = fs.readdirSync(specsRoot, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
174
+ } catch { /* no specs root */ }
175
+ const named = packetsNamedIn(payload.prompt, packets);
176
+ if (typeof explicitFeature === 'string' && explicitFeature) named.push(explicitFeature);
177
+ if (named.length) addTouched(named);
178
+ }
179
+
87
180
  const resolveWorkflow = typeof RESOLVER.resolveWorkflowCandidate === 'function'
88
181
  ? RESOLVER.resolveWorkflowCandidate
89
182
  : RESOLVER.resolveActiveSpec;
@@ -118,6 +211,7 @@ try {
118
211
  const activeSpec = resolved.spec || {};
119
212
  const processWorkflow = resolved.layoutKind === 'process-v3';
120
213
  const featureName = resolved.featureName;
214
+ if (touchFilter && !readTouched().has(featureName)) process.exit(0);
121
215
  const specsPath = resolved.specsDir;
122
216
  const runtimeContext = POLICY.deriveRuntimeContext({
123
217
  projectRoot: baseDir,
@@ -148,6 +148,21 @@ try {
148
148
  return data;
149
149
  }
150
150
 
151
+ /**
152
+ * True when latest.md holds something beyond the filler this hook writes itself:
153
+ * headings, HTML comments, the three placeholder bullets and timestamp-only agent results.
154
+ */
155
+ function hasPriorContent(text) {
156
+ const filler = [
157
+ /^#{1,6}\s/,
158
+ /^<!--.*-->$/,
159
+ /^- \((No completed tasks recorded|All tasks completed|No file changes detected)\)$/,
160
+ /^- Completed at \d{2}:\d{2}:\d{2}$/,
161
+ ];
162
+ return text.split('\n').map((line) => line.trim())
163
+ .some((line) => line && !filler.some((pattern) => pattern.test(line)));
164
+ }
165
+
151
166
  function buildStateContent(data) {
152
167
  const done = data.todos.filter((todo) => todo.status === 'completed' || todo.status === 'done');
153
168
  const pending = data.todos.filter((todo) => !['completed', 'done'].includes(todo.status));
@@ -226,14 +241,18 @@ try {
226
241
  if (!stdin) process.exit(0);
227
242
 
228
243
  const { normalizeHookPayload } = require('./lib/hook-payload.cjs');
229
- const data = normalizeHookPayload(JSON.parse(stdin));
244
+ const rawPayload = JSON.parse(stdin);
245
+ const data = normalizeHookPayload(rawPayload);
230
246
  const event = data.hook_event_name || '';
231
247
  const cwd = data.cwd || process.cwd();
232
248
  const dir = stateDir(cwd);
233
249
 
234
250
  if (event === 'SessionStart') {
235
251
  const previous = loadLatest(cwd);
236
- if (previous) {
252
+ // Claude only: grok (camelCase sessionId), omp and Codex keep printing the block.
253
+ const claudeSession = runtimeDirName() === '.claude'
254
+ && typeof rawPayload.session_id === 'string' && rawPayload.session_id.length > 0;
255
+ if (previous && (!claudeSession || hasPriorContent(previous))) {
237
256
  console.log('\n=== Prior Execution Context ===');
238
257
  console.log(previous.trim());
239
258
  console.log('=== End of Prior Context ===\n');
@@ -7,23 +7,21 @@
7
7
  "skills": {
8
8
  "required": [
9
9
  "agent-browser",
10
+ "ask",
10
11
  "brainstorm",
11
12
  "chrome-devtools",
12
13
  "code-review",
13
14
  "debug",
14
- "delegate",
15
15
  "develop",
16
+ "fix",
16
17
  "git",
17
- "hotfix",
18
- "inspect",
19
- "loop",
20
18
  "orca",
21
- "question",
22
19
  "research",
23
- "route",
20
+ "scout",
24
21
  "specs",
25
22
  "sync",
26
23
  "test",
24
+ "ui-ux",
27
25
  "ui-ux-pro-max",
28
26
  "web-testing"
29
27
  ],
@@ -86,7 +84,13 @@
86
84
  "frontend-design",
87
85
  "mobile-development",
88
86
  "devops",
89
- "react-best-practices"
87
+ "react-best-practices",
88
+ "inspect",
89
+ "hotfix",
90
+ "question",
91
+ "loop",
92
+ "route",
93
+ "delegate"
90
94
  ],
91
95
  "agents": {
92
96
  "claude": ["agents/god-developer.md"],
@@ -112,10 +116,27 @@
112
116
  "skills/specs/rules/ears-format.md",
113
117
  "skills/specs/rules/phase-decision-matrix.md",
114
118
  "skills/specs/rules/task-scoring-rubric.md",
115
- "skills/specs/rules/tasks-generation.md"
119
+ "skills/specs/rules/tasks-generation.md",
120
+ "hooks/usage.cjs",
121
+ "hooks/completion-authority.cjs",
122
+ "hooks/completion-authority-check.cjs",
123
+ "hooks/completion-authority-state.cjs",
124
+ "hooks/semantic-review-authority.cjs",
125
+ "hooks/task-scaffold-guard.cjs"
116
126
  ],
117
127
  "settingsHookCommandSubstrings": [
118
- "hooks/skill-router.cjs"
128
+ "hooks/skill-router.cjs",
129
+ ".claude/hooks/usage.cjs",
130
+ ".claude/hooks/docs-sync.cjs",
131
+ ".claude/hooks/completion-authority.cjs",
132
+ ".codex/hooks/completion-authority.cjs",
133
+ ".codex\\hooks\\completion-authority.cjs",
134
+ ".claude/hooks/semantic-review-authority.cjs",
135
+ ".codex/hooks/semantic-review-authority.cjs",
136
+ ".codex\\hooks\\semantic-review-authority.cjs",
137
+ ".claude/hooks/task-scaffold-guard.cjs",
138
+ ".codex/hooks/task-scaffold-guard.cjs",
139
+ ".codex\\hooks\\task-scaffold-guard.cjs"
119
140
  ]
120
141
  },
121
142
  "runtime": {
@@ -128,18 +149,12 @@
128
149
  "hooks/precompact.cjs",
129
150
  "hooks/docs-sync.cjs",
130
151
  "hooks/agent.cjs",
131
- "hooks/usage.cjs",
132
152
  "hooks/privacy-block.cjs",
133
153
  "hooks/secret-output-guardrail.cjs",
134
154
  "hooks/inspect-block.cjs",
135
- "hooks/task-scaffold-guard.cjs",
136
155
  "hooks/rules.cjs",
137
156
  "hooks/spec-state.cjs",
138
157
  "hooks/spec-gate.cjs",
139
- "hooks/completion-authority.cjs",
140
- "hooks/completion-authority-check.cjs",
141
- "hooks/completion-authority-state.cjs",
142
- "hooks/semantic-review-authority.cjs",
143
158
  "hooks/state.cjs",
144
159
  "hooks/lib/color.cjs",
145
160
  "hooks/lib/parser.cjs",
@@ -42,7 +42,7 @@ Keep implementation simple, scoped, and verifiable.
42
42
 
43
43
  ## Git Hygiene
44
44
 
45
- - Lint before commit.
45
+ - Lint before commit when the project has a linter.
46
46
  - Run required tests before push.
47
47
  - Keep commits focused.
48
48
  - Use conventional commits.
@@ -4,28 +4,21 @@ Hooks are instruction boundaries. Do not bypass or work around them.
4
4
 
5
5
  ## Privacy Block Hook
6
6
 
7
- When a tool call is blocked by the privacy hook, the output contains a JSON marker between:
7
+ When a tool call touches a sensitive file, or the hook cannot classify it safely,
8
+ the privacy hook returns a permission decision of `ask` with the reason, and the
9
+ host asks the user to approve or deny that one call. Do not ask again yourself.
10
+ On a host whose hook can only deny, the call is blocked; ask the user instead of
11
+ retrying it another way.
8
12
 
9
- ```text
10
- @@PRIVACY_PROMPT_START@@
11
- ...
12
- @@PRIVACY_PROMPT_END@@
13
- ```
14
-
15
- Required flow:
16
-
17
- 1. Parse the JSON payload from the marker.
18
- 2. Ask the user for approval using the available user-question tool and the prompt/options from the payload.
19
- 3. If approved, retry only the blocked action.
20
- 4. If denied, continue without reading that file or performing that blocked action.
13
+ - If approved, the call runs; do not widen it to other files.
14
+ - If denied, continue without reading that file or performing that blocked action.
21
15
 
22
16
  Never use another command, path, encoding, or side channel to access a privacy-blocked file without explicit approval.
23
17
 
24
18
  ## State And Spec Hooks
25
19
 
26
20
  - If a hook reports state drift, run the appropriate sync/audit flow before continuing.
27
- - If a hook rejects task completion, keep the task `in_progress` or `blocked` until proof exists.
28
- - Do not mark a task `done` unless the matching task file contains a valid verification receipt.
21
+ - If a hook rejects task completion, keep the task `in_progress` or `blocked` until proof exists; the receipt contract lives in `state-sync.md`.
29
22
 
30
23
  ## Hook Failure Handling
31
24
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## Living Documents
4
4
 
5
- The project maintains these core documents in `./docs`:
5
+ When the project keeps these core documents in `./docs`, keep them current (a project may have only some of them):
6
6
 
7
7
  | Document | Purpose |
8
8
  |----------|---------|
@@ -14,8 +14,6 @@ The project maintains these core documents in `./docs`:
14
14
  ### Freshness Rule
15
15
 
16
16
  - Before updating any doc, check its last modified date
17
- - If a doc hasn't been updated in >2 weeks while development is active, flag it for review
18
- - The `docs-keeper` agent should proactively scan for stale docs during weekly reviews
19
17
 
20
18
  ## When to Update
21
19
 
@@ -26,7 +24,6 @@ The `docs-keeper` agent is responsible for keeping these documents current. Trig
26
24
  - A significant feature ships or a critical bug is resolved
27
25
  - Security patches are applied or dependencies change
28
26
  - Project scope or timeline shifts
29
- - Weekly progress reviews are due
30
27
 
31
28
  ### Update Discipline
32
29
 
@@ -43,7 +40,7 @@ Use [Keep a Changelog](https://keepachangelog.com/) convention:
43
40
  ## [version] - YYYY-MM-DD
44
41
 
45
42
  ### Added
46
- - Feature description (#PR-number)
43
+ - Feature description (#PR-number when there is one)
47
44
 
48
45
  ### Fixed
49
46
  - Bug fix description (#issue-number)
@@ -74,38 +71,27 @@ specs/
74
71
 
75
72
  Task files are direct children beside `plan.md`; do not place them in a task
76
73
  subdirectory.
77
- The plan records the C1 scope decision, explicit exclusions, acceptance
74
+ The plan records the GATE-SCOPE scope decision, explicit exclusions, acceptance
78
75
  criteria, and task mapping. Each task owns one usable outcome, bounded paths,
79
76
  dependencies, acceptance, and a runnable Verification Plan.
80
77
 
81
78
  ### Gates and execution handoff
82
79
 
83
- - C1: the user chooses EXPAND, KEEP, or CUT before the plan is written.
84
- - C2: the user accepts, rejects, or revises deduplicated adversarial findings.
80
+ - GATE-SCOPE: the user chooses EXPAND, KEEP, or CUT before the plan is written.
81
+ - GATE-REVIEW: the user accepts, rejects, or revises deduplicated adversarial findings.
85
82
  - Specs stops after planning; implementation begins only through a new explicit
86
83
  Develop invocation.
87
- - C3: after execution, current receipts and limitations are shown and the user
84
+ - GATE-DONE: after execution, current receipts and limitations are shown and the user
88
85
  decides whether the feature is complete.
89
86
 
90
87
  ### Task state and proof
91
88
 
92
- Each task contains exactly one `Status:` field. The final inline `## Receipt`
93
- is canonical proof and must contain the exact command, `Exit: 0`,
94
- `Verification: PASS`, runtime-derived Base and Head values, and non-empty
95
- fenced current output before the task becomes done.
89
+ Task status, the inline `## Receipt` and its proof contract are defined in
90
+ `state-sync.md`.
96
91
 
97
92
  Sync only observed state with surgical edits. Re-read the changed task after
98
93
  every update; never infer missing proof, approval, or readiness. When a done
99
94
  task changes user-facing behavior, architecture, API contracts, operations, or
100
95
  project status, classify docs impact and update only affected existing docs.
101
96
 
102
- Comply with the overarching rules in `./rules/ai-dev-rules.md`.
103
-
104
- ## Legacy specification layout
105
-
106
- Existing features containing `spec.json`, nested `tasks/task-R*.md`, or other
107
- legacy kernel artifacts keep their installed adapters and original layout.
108
- Preserve `task_registry`, `semantic_model`, `planning_depth`, lane,
109
- `execution_tier`, machine authority, typed topology, separate receipts, and
110
- feature closeout files. Do not migrate them as part of unrelated documentation
111
- work.
97
+ Comply with the overarching rules in `ai-dev-rules.md`.
@@ -22,10 +22,9 @@ Example prompt:
22
22
 
23
23
  ## Resource Constraints
24
24
 
25
- - Each subagent has a **200K token context window** — scope tasks to fit comfortably within it
26
- - Spawning many parallel agents degrades system performance — check available CPU/memory before scaling out. For parallel implementation waves the cap is 3 concurrent agents by default, never more than 5 (each agent carries the 200K budget above)
25
+ - Each subagent has its own context window — scope tasks to fit comfortably within it
26
+ - Spawning many parallel agents degrades system performance — check available CPU/memory before scaling out. For parallel implementation waves the cap is 3 concurrent agents by default, never more than 5 (each agent carries its own context window)
27
27
  - Prefer fewer, well-scoped agents over many overlapping ones
28
- - Include system resource info (from hook injection) when delegating tasks so subagents can self-regulate
29
28
 
30
29
  ---
31
30
 
@@ -132,7 +131,7 @@ Docs: [docs path]
132
131
 
133
132
  | ❌ Vague | ✅ Precise |
134
133
  |----------|-----------|
135
- | "Pick up where we left off" | "Add the `/users` POST endpoint per `phase-02.md`" |
134
+ | "Pick up where we left off" | "Add the `/users` POST endpoint per `task-02-api.md`" |
136
135
  | "Fix the issues we talked about" | "Add null-check in `auth.ts:45` — root cause: missing input validation" |
137
136
  | "Explore the codebase" | "Read `src/api/routes.ts`, then add the missing handler" |
138
137
  | Dumping 50+ lines of chat history | A 5-line summary with file paths |
@@ -12,10 +12,10 @@ When rejecting an audit concern, name the verification source briefly.
12
12
 
13
13
  ## User Decisions
14
14
 
15
- Do not silently undo an explicit user decision. This covers the C1 scope choice,
16
- C2 finding dispositions, and C3 completion judgement, along with thresholds,
15
+ Do not silently undo an explicit user decision. This covers the GATE-SCOPE scope choice,
16
+ GATE-REVIEW finding dispositions, and GATE-DONE completion judgement, along with thresholds,
17
17
  selected libraries, feature scope, schema shape, pricing, timelines, compliance
18
- choices, and UX trade-offs. Those gates are defined in `workflow.md`; this rule
18
+ choices, and UX trade-offs. Those gates are defined in `state-sync.md`; this rule
19
19
  governs only how a later review may treat them.
20
20
 
21
21
  If an audit suggests reversing a user decision, present:
@@ -27,6 +27,4 @@ an entry condition for the primary. If zero valid capabilities match, continue
27
27
  inline when safe or name the gap. If multiple catalog entries expose the same
28
28
  public identity, do not auto-route; require explicit user disambiguation.
29
29
 
30
- Never infer an optional document capability from this rule. Never select the
31
- explicit-only numeric optimization capability unless the user invokes it with
32
- its required bounded metric/guard contract.
30
+ Never infer an optional document capability from this rule.
@@ -9,9 +9,9 @@ workflow.
9
9
  1. If the user names a valid installed skill, use it directly.
10
10
  2. If one obvious low-risk installed skill covers the intent, use it directly.
11
11
  3. For direct factual conversation, answer directly or use the installed
12
- evidence-answer capability; do not invoke Route or agents for ceremony.
13
- 4. For ambiguous, multi-step, multi-domain, or elevated/high-risk work, use the
14
- installed Route capability to classify and compose the shortest valid chain.
12
+ evidence-answer capability; do not spawn agents for ceremony.
13
+ 4. For ambiguous, multi-step, multi-domain, or elevated/high-risk work, classify
14
+ it yourself and compose the shortest valid chain below.
15
15
 
16
16
  Resolve every abstract link against the current runtime catalog. An absent,
17
17
  invalid, folder-mismatched, duplicate, or retired entry is not routable. Continue
@@ -28,5 +28,4 @@ owner, entry condition, and observable exit per retained link. Diagnosis does
28
28
  not authorize repair; implementation does not authorize commit, push, deploy,
29
29
  publish, or release; no route expands the user's existing authority.
30
30
 
31
- Use `skill-domain-routing.md` to resolve domain capability slots. The numeric
32
- optimization capability remains explicit-only and must never be auto-routed.
31
+ Use `skill-domain-routing.md` to resolve domain capability slots.
@@ -51,19 +51,10 @@ proves only the boundary it executed.
51
51
 
52
52
  ## Human gates and workflow ownership
53
53
 
54
- - C1 records the user's scope decision before the plan is written.
55
- - C2 records the user's disposition of deduplicated adversarial findings.
54
+ - GATE-SCOPE records the user's scope decision before the plan is written.
55
+ - GATE-REVIEW records the user's disposition of deduplicated adversarial findings.
56
56
  - Develop starts only after a new explicit user invocation and executes one
57
57
  unblocked task at a time.
58
58
  - Sync changes only observed file state and never starts implementation.
59
- - C3 occurs after current receipts and limitations are shown; the user decides
59
+ - GATE-DONE occurs after current receipts and limitations are shown; the user decides
60
60
  whether the requested feature is complete.
61
-
62
- ## Legacy compatibility
63
-
64
- Existing packets containing `spec.json`, nested `tasks/task-R*.md`, or other
65
- legacy kernel artifacts stay on their installed adapters. Preserve their
66
- `task_registry`, `semantic_model`, `planning_depth`, lane,
67
- `execution_tier`, typed topology, separate receipts, and feature closeout
68
- contract. Do not migrate that machine authority or storage shape while syncing
69
- an unrelated process-first packet.