@haposoft/cafekit 0.16.0-rc.7 → 0.16.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 (299) hide show
  1. package/README.md +116 -27
  2. package/bin/__tests__/codex-hooks-ownership.test.js +239 -0
  3. package/bin/__tests__/codex-hooks.test.js +295 -0
  4. package/bin/__tests__/codex-native.test.js +2289 -34
  5. package/bin/__tests__/develop-contract.test.js +400 -23
  6. package/bin/__tests__/installer-safety.test.js +3 -3
  7. package/bin/__tests__/optional-skill-inventory.test.js +249 -0
  8. package/bin/__tests__/output-styles.test.js +214 -0
  9. package/bin/__tests__/package-inventory.test.js +2131 -16
  10. package/bin/__tests__/runtime-schema.test.js +111 -0
  11. package/bin/__tests__/secret-output-guardrail.test.js +122 -0
  12. package/bin/__tests__/skill-routing-source.test.js +172 -0
  13. package/bin/__tests__/specs-v2-execution-closeout.test.js +1 -1
  14. package/bin/install.js +10 -0
  15. package/bin/lib/codex-install.js +170 -5
  16. package/bin/lib/context.js +14 -0
  17. package/bin/lib/i18n.js +12 -6
  18. package/bin/lib/skill-deps.js +5 -5
  19. package/bin/phases/claude-runtime.js +23 -0
  20. package/bin/phases/claude-settings.js +8 -0
  21. package/bin/phases/codex-hooks.js +156 -0
  22. package/bin/phases/codex-runtime.js +29 -38
  23. package/bin/phases/copy-payload.js +8 -2
  24. package/bin/phases/select-skill-bundles.js +96 -0
  25. package/bin/phases/skill-inventory.js +71 -0
  26. package/bin/phases/skills-setup.js +9 -2
  27. package/bin/phases/write-metadata.js +8 -5
  28. package/package.json +8 -2
  29. package/src/claude/CLAUDE.md +3 -3
  30. package/src/claude/agents/brainstormer.md +52 -69
  31. package/src/claude/agents/code-auditor.md +32 -14
  32. package/src/claude/agents/debugger.md +35 -20
  33. package/src/claude/agents/deployer.md +12 -5
  34. package/src/claude/agents/docs-keeper.md +11 -1
  35. package/src/claude/agents/implementer.md +25 -13
  36. package/src/claude/agents/inspector.md +6 -3
  37. package/src/claude/agents/project-manager.md +1 -1
  38. package/src/claude/agents/researcher.md +26 -55
  39. package/src/claude/agents/spec-maker.md +24 -13
  40. package/src/claude/agents/strategist.md +52 -0
  41. package/src/claude/agents/test-runner.md +117 -132
  42. package/src/claude/agents/ui-ux-designer.md +1 -1
  43. package/src/claude/hooks/__tests__/fixtures/statusline-default.golden +1 -0
  44. package/src/claude/hooks/__tests__/precompact.test.js +158 -0
  45. package/src/claude/hooks/__tests__/spec-gate.test.js +87 -4
  46. package/src/claude/hooks/__tests__/state.test.js +254 -3
  47. package/src/claude/hooks/__tests__/statusline.test.js +196 -0
  48. package/src/claude/hooks/agent.cjs +1 -1
  49. package/src/claude/hooks/docs-sync.cjs +12 -10
  50. package/src/claude/hooks/inspect-block.cjs +1 -1
  51. package/src/claude/hooks/lib/config.cjs +3 -0
  52. package/src/claude/hooks/lib/hook-state-dir.cjs +39 -0
  53. package/src/claude/hooks/lib/secret-keywords.cjs +42 -0
  54. package/src/claude/hooks/precompact.cjs +105 -0
  55. package/src/claude/hooks/rules.cjs +1 -1
  56. package/src/claude/hooks/secret-output-guardrail.cjs +43 -0
  57. package/src/claude/hooks/session.cjs +27 -1
  58. package/src/claude/hooks/spec-gate.cjs +3 -3
  59. package/src/claude/hooks/spec-state.cjs +32 -5
  60. package/src/claude/hooks/state.cjs +1 -1
  61. package/src/claude/hooks/task-scaffold-guard.cjs +1 -1
  62. package/src/claude/hooks/usage.cjs +1 -1
  63. package/src/claude/migration-manifest.json +29 -15
  64. package/src/claude/output-styles/coding-level-0-eli5.md +103 -0
  65. package/src/claude/output-styles/coding-level-1-junior.md +124 -0
  66. package/src/claude/output-styles/coding-level-2-mid.md +146 -0
  67. package/src/claude/output-styles/coding-level-3-senior.md +148 -0
  68. package/src/claude/output-styles/coding-level-4-lead.md +159 -0
  69. package/src/claude/output-styles/coding-level-5-god.md +91 -0
  70. package/src/claude/references/debugger/core-philosophy.md +5 -3
  71. package/src/claude/references/debugger/frontend-verification.md +2 -2
  72. package/src/claude/references/debugger/log-ci-analysis.md +13 -1
  73. package/src/claude/references/debugger/parallel-agent-hydration.md +19 -34
  74. package/src/claude/references/debugger/performance-diagnostics.md +2 -2
  75. package/src/claude/references/debugger/root-cause-tracing.md +37 -6
  76. package/src/claude/references/debugger/side-effect-gate.md +3 -1
  77. package/src/claude/references/debugger/verification-protocol.md +13 -12
  78. package/src/claude/rules/orchestrator.md +7 -1
  79. package/src/claude/rules/process-management.md +39 -0
  80. package/src/claude/rules/review-audit-self-decision.md +48 -0
  81. package/src/claude/rules/skill-domain-routing.md +26 -24
  82. package/src/claude/rules/skill-workflow-routing.md +22 -14
  83. package/src/claude/rules/workflow.md +3 -3
  84. package/src/claude/runtime.json +1 -0
  85. package/src/claude/runtime.schema.json +205 -0
  86. package/src/claude/scripts/generate-skill-catalog.cjs +156 -122
  87. package/src/claude/scripts/provenance.cjs +18 -5
  88. package/src/claude/scripts/spec-receipt.cjs +76 -21
  89. package/src/claude/scripts/spec-resolver.cjs +144 -4
  90. package/src/claude/scripts/workflow-policy.cjs +1 -1
  91. package/src/claude/settings/settings.json +16 -0
  92. package/src/claude/skills/agent-browser/SKILL.md +1 -1
  93. package/src/claude/skills/ai-multimodal/SKILL.md +1 -1
  94. package/src/claude/skills/brainstorm/SKILL.md +193 -172
  95. package/src/claude/skills/brainstorm/references/question-framework.md +105 -167
  96. package/src/claude/skills/chrome-devtools/SKILL.md +1 -1
  97. package/src/claude/skills/code-review/SKILL.md +43 -25
  98. package/src/claude/skills/code-review/references/spec-compliance-review.md +3 -4
  99. package/src/claude/skills/code-review/references/verification-gate.md +1 -1
  100. package/src/claude/skills/debug/SKILL.md +48 -19
  101. package/src/claude/skills/delegate/SKILL.md +1 -1
  102. package/src/claude/skills/develop/SKILL.md +92 -65
  103. package/src/claude/skills/develop/references/parallel-waves.md +36 -63
  104. package/src/claude/skills/develop/references/quality-gate.md +31 -4
  105. package/src/claude/skills/develop/references/subagent-patterns.md +21 -7
  106. package/src/claude/skills/docs/SKILL.md +42 -23
  107. package/src/claude/skills/docs/references/init-workflow.md +4 -4
  108. package/src/claude/skills/docs/references/reconstruct-workflow.md +6 -6
  109. package/src/claude/skills/docs/references/standard-docs-workflow.md +6 -2
  110. package/src/claude/skills/docs/references/summarize-workflow.md +2 -2
  111. package/src/claude/skills/docs/references/update-workflow.md +9 -7
  112. package/src/claude/skills/docs/templates/requirements-as-is.md +1 -1
  113. package/src/claude/skills/docx/SKILL.md +1 -1
  114. package/src/claude/skills/git/SKILL.md +1 -1
  115. package/src/claude/skills/git/references/commit-protocols.md +1 -1
  116. package/src/claude/skills/git/references/finish-branch.md +1 -1
  117. package/src/claude/skills/hotfix/SKILL.md +159 -170
  118. package/src/claude/skills/hotfix/references/diagnosis-protocol.md +14 -9
  119. package/src/claude/skills/hotfix/references/parallel-patterns.md +27 -13
  120. package/src/claude/skills/hotfix/references/prevention-gate.md +5 -0
  121. package/src/claude/skills/hotfix/references/review-cycle.md +21 -15
  122. package/src/claude/skills/hotfix/references/workflow-specialized.md +53 -21
  123. package/src/claude/skills/inspect/SKILL.md +55 -46
  124. package/src/claude/skills/inspect/references/internal-inspection.md +21 -5
  125. package/src/claude/skills/loop/SKILL.md +114 -0
  126. package/src/claude/skills/loop/references/bounded-loop-protocol.md +104 -0
  127. package/src/claude/skills/loop/references/metric-and-guard-contract.md +76 -0
  128. package/src/claude/skills/pdf/SKILL.md +1 -1
  129. package/src/claude/skills/pptx/SKILL.md +1 -1
  130. package/src/claude/skills/question/SKILL.md +16 -13
  131. package/src/claude/skills/research/SKILL.md +70 -43
  132. package/src/claude/skills/route/SKILL.md +94 -0
  133. package/src/claude/skills/route/references/agent-timing.md +46 -0
  134. package/src/claude/skills/route/references/chaining-patterns.md +53 -0
  135. package/src/claude/skills/route/references/task-taxonomy.md +48 -0
  136. package/src/claude/skills/specs/SKILL.md +48 -57
  137. package/src/claude/skills/specs/references/review.md +26 -8
  138. package/src/claude/skills/specs/references/templates.md +76 -31
  139. package/src/claude/skills/specs/templates/requirements-init.md +1 -1
  140. package/src/claude/skills/specs/templates/research.md +2 -2
  141. package/src/claude/skills/sync/SKILL.md +6 -6
  142. package/src/claude/skills/sync/references/sync-protocols.md +1 -1
  143. package/src/claude/skills/test/SKILL.md +120 -120
  144. package/src/claude/skills/test/references/execution-strategy.md +208 -361
  145. package/src/claude/skills/test/references/failure-triage.md +55 -121
  146. package/src/claude/skills/test/references/test-memory.md +20 -34
  147. package/src/claude/skills/ui-ux-pro-max/SKILL.md +1 -1
  148. package/src/claude/skills/web-testing/SKILL.md +1 -1
  149. package/src/claude/skills/xlsx/SKILL.md +1 -1
  150. package/src/claude/status.cjs +135 -33
  151. package/src/codex/AGENTS.md +14 -4
  152. package/src/codex/hooks/docs-sync.cjs +8 -3
  153. package/src/codex/hooks/lib/hook-context.cjs +18 -4
  154. package/src/codex/hooks/rules.cjs +29 -1
  155. package/src/codex/hooks/secret-output-guardrail.cjs +30 -0
  156. package/src/codex/hooks/spec-gate.cjs +3 -8
  157. package/src/codex/hooks/spec-state.cjs +34 -5
  158. package/src/codex/hooks.json +5 -0
  159. package/src/codex/runtime.json +2 -0
  160. package/src/common/.env.example +1 -1
  161. package/src/claude/skills/backend-development/SKILL.md +0 -101
  162. package/src/claude/skills/backend-development/references/backend-api-design.md +0 -495
  163. package/src/claude/skills/backend-development/references/backend-architecture.md +0 -454
  164. package/src/claude/skills/backend-development/references/backend-authentication.md +0 -338
  165. package/src/claude/skills/backend-development/references/backend-code-quality.md +0 -659
  166. package/src/claude/skills/backend-development/references/backend-debugging.md +0 -904
  167. package/src/claude/skills/backend-development/references/backend-devops.md +0 -491
  168. package/src/claude/skills/backend-development/references/backend-mindset.md +0 -387
  169. package/src/claude/skills/backend-development/references/backend-performance.md +0 -397
  170. package/src/claude/skills/backend-development/references/backend-security.md +0 -342
  171. package/src/claude/skills/backend-development/references/backend-technologies.md +0 -256
  172. package/src/claude/skills/backend-development/references/backend-testing.md +0 -429
  173. package/src/claude/skills/devops/.env.example +0 -76
  174. package/src/claude/skills/devops/SKILL.md +0 -102
  175. package/src/claude/skills/devops/references/browser-rendering.md +0 -305
  176. package/src/claude/skills/devops/references/cloudflare-d1-kv.md +0 -123
  177. package/src/claude/skills/devops/references/cloudflare-platform.md +0 -271
  178. package/src/claude/skills/devops/references/cloudflare-r2-storage.md +0 -280
  179. package/src/claude/skills/devops/references/cloudflare-workers-advanced.md +0 -312
  180. package/src/claude/skills/devops/references/cloudflare-workers-apis.md +0 -309
  181. package/src/claude/skills/devops/references/cloudflare-workers-basics.md +0 -418
  182. package/src/claude/skills/devops/references/docker-basics.md +0 -297
  183. package/src/claude/skills/devops/references/docker-compose.md +0 -292
  184. package/src/claude/skills/devops/references/gcloud-platform.md +0 -297
  185. package/src/claude/skills/devops/references/gcloud-services.md +0 -304
  186. package/src/claude/skills/devops/references/kubernetes-basics.md +0 -95
  187. package/src/claude/skills/devops/references/kubernetes-helm-advanced.md +0 -70
  188. package/src/claude/skills/devops/references/kubernetes-helm.md +0 -81
  189. package/src/claude/skills/devops/references/kubernetes-kubectl.md +0 -74
  190. package/src/claude/skills/devops/references/kubernetes-security-advanced.md +0 -94
  191. package/src/claude/skills/devops/references/kubernetes-security.md +0 -89
  192. package/src/claude/skills/devops/references/kubernetes-troubleshooting-advanced.md +0 -74
  193. package/src/claude/skills/devops/references/kubernetes-troubleshooting.md +0 -49
  194. package/src/claude/skills/devops/references/kubernetes-workflows-advanced.md +0 -75
  195. package/src/claude/skills/devops/references/kubernetes-workflows.md +0 -76
  196. package/src/claude/skills/devops/scripts/cloudflare_deploy.py +0 -269
  197. package/src/claude/skills/devops/scripts/docker_optimize.py +0 -332
  198. package/src/claude/skills/devops/scripts/requirements.txt +0 -20
  199. package/src/claude/skills/devops/scripts/tests/requirements.txt +0 -3
  200. package/src/claude/skills/devops/scripts/tests/test_cloudflare_deploy.py +0 -285
  201. package/src/claude/skills/devops/scripts/tests/test_docker_optimize.py +0 -436
  202. package/src/claude/skills/frontend-design/SKILL.md +0 -135
  203. package/src/claude/skills/frontend-design/references/ai-multimodal-overview.md +0 -165
  204. package/src/claude/skills/frontend-design/references/analysis-best-practices.md +0 -80
  205. package/src/claude/skills/frontend-design/references/analysis-prompts.md +0 -141
  206. package/src/claude/skills/frontend-design/references/analysis-techniques.md +0 -118
  207. package/src/claude/skills/frontend-design/references/animejs.md +0 -396
  208. package/src/claude/skills/frontend-design/references/anti-slop-rules.md +0 -103
  209. package/src/claude/skills/frontend-design/references/asset-generation.md +0 -337
  210. package/src/claude/skills/frontend-design/references/bento-motion-engine.md +0 -142
  211. package/src/claude/skills/frontend-design/references/design-extraction-overview.md +0 -71
  212. package/src/claude/skills/frontend-design/references/extraction-best-practices.md +0 -141
  213. package/src/claude/skills/frontend-design/references/extraction-output-templates.md +0 -162
  214. package/src/claude/skills/frontend-design/references/extraction-prompts.md +0 -127
  215. package/src/claude/skills/frontend-design/references/magicui-components.md +0 -129
  216. package/src/claude/skills/frontend-design/references/performance-guardrails.md +0 -169
  217. package/src/claude/skills/frontend-design/references/premium-design-patterns.md +0 -93
  218. package/src/claude/skills/frontend-design/references/redesign-audit-checklist.md +0 -114
  219. package/src/claude/skills/frontend-design/references/technical-accessibility.md +0 -119
  220. package/src/claude/skills/frontend-design/references/technical-best-practices.md +0 -97
  221. package/src/claude/skills/frontend-design/references/technical-optimization.md +0 -44
  222. package/src/claude/skills/frontend-design/references/technical-overview.md +0 -90
  223. package/src/claude/skills/frontend-design/references/technical-workflows.md +0 -150
  224. package/src/claude/skills/frontend-design/references/visual-analysis-overview.md +0 -95
  225. package/src/claude/skills/frontend-design/references/workflow-3d.md +0 -102
  226. package/src/claude/skills/frontend-design/references/workflow-describe.md +0 -87
  227. package/src/claude/skills/frontend-design/references/workflow-immersive.md +0 -87
  228. package/src/claude/skills/frontend-design/references/workflow-quick.md +0 -57
  229. package/src/claude/skills/frontend-design/references/workflow-screenshot.md +0 -63
  230. package/src/claude/skills/frontend-design/references/workflow-video.md +0 -74
  231. package/src/claude/skills/frontend-development/SKILL.md +0 -406
  232. package/src/claude/skills/frontend-development/resources/common-patterns.md +0 -331
  233. package/src/claude/skills/frontend-development/resources/complete-examples.md +0 -872
  234. package/src/claude/skills/frontend-development/resources/component-patterns.md +0 -502
  235. package/src/claude/skills/frontend-development/resources/data-fetching.md +0 -767
  236. package/src/claude/skills/frontend-development/resources/file-organization.md +0 -502
  237. package/src/claude/skills/frontend-development/resources/loading-and-error-states.md +0 -501
  238. package/src/claude/skills/frontend-development/resources/performance.md +0 -406
  239. package/src/claude/skills/frontend-development/resources/routing-guide.md +0 -364
  240. package/src/claude/skills/frontend-development/resources/styling-guide.md +0 -428
  241. package/src/claude/skills/frontend-development/resources/typescript-standards.md +0 -418
  242. package/src/claude/skills/mobile-development/SKILL.md +0 -218
  243. package/src/claude/skills/mobile-development/references/mobile-android.md +0 -604
  244. package/src/claude/skills/mobile-development/references/mobile-best-practices.md +0 -544
  245. package/src/claude/skills/mobile-development/references/mobile-debugging.md +0 -1089
  246. package/src/claude/skills/mobile-development/references/mobile-frameworks.md +0 -465
  247. package/src/claude/skills/mobile-development/references/mobile-ios.md +0 -496
  248. package/src/claude/skills/mobile-development/references/mobile-mindset.md +0 -542
  249. package/src/claude/skills/react-best-practices/AGENTS.md +0 -2249
  250. package/src/claude/skills/react-best-practices/README.md +0 -123
  251. package/src/claude/skills/react-best-practices/SKILL.md +0 -128
  252. package/src/claude/skills/react-best-practices/metadata.json +0 -15
  253. package/src/claude/skills/react-best-practices/rules/_sections.md +0 -46
  254. package/src/claude/skills/react-best-practices/rules/_template.md +0 -28
  255. package/src/claude/skills/react-best-practices/rules/advanced-event-handler-refs.md +0 -55
  256. package/src/claude/skills/react-best-practices/rules/advanced-use-latest.md +0 -49
  257. package/src/claude/skills/react-best-practices/rules/async-api-routes.md +0 -38
  258. package/src/claude/skills/react-best-practices/rules/async-defer-await.md +0 -80
  259. package/src/claude/skills/react-best-practices/rules/async-dependencies.md +0 -36
  260. package/src/claude/skills/react-best-practices/rules/async-parallel.md +0 -28
  261. package/src/claude/skills/react-best-practices/rules/async-suspense-boundaries.md +0 -99
  262. package/src/claude/skills/react-best-practices/rules/bundle-barrel-imports.md +0 -59
  263. package/src/claude/skills/react-best-practices/rules/bundle-conditional.md +0 -31
  264. package/src/claude/skills/react-best-practices/rules/bundle-defer-third-party.md +0 -49
  265. package/src/claude/skills/react-best-practices/rules/bundle-dynamic-imports.md +0 -35
  266. package/src/claude/skills/react-best-practices/rules/bundle-preload.md +0 -50
  267. package/src/claude/skills/react-best-practices/rules/client-event-listeners.md +0 -74
  268. package/src/claude/skills/react-best-practices/rules/client-swr-dedup.md +0 -56
  269. package/src/claude/skills/react-best-practices/rules/js-batch-dom-css.md +0 -82
  270. package/src/claude/skills/react-best-practices/rules/js-cache-function-results.md +0 -80
  271. package/src/claude/skills/react-best-practices/rules/js-cache-property-access.md +0 -28
  272. package/src/claude/skills/react-best-practices/rules/js-cache-storage.md +0 -70
  273. package/src/claude/skills/react-best-practices/rules/js-combine-iterations.md +0 -32
  274. package/src/claude/skills/react-best-practices/rules/js-early-exit.md +0 -50
  275. package/src/claude/skills/react-best-practices/rules/js-hoist-regexp.md +0 -45
  276. package/src/claude/skills/react-best-practices/rules/js-index-maps.md +0 -37
  277. package/src/claude/skills/react-best-practices/rules/js-length-check-first.md +0 -49
  278. package/src/claude/skills/react-best-practices/rules/js-min-max-loop.md +0 -82
  279. package/src/claude/skills/react-best-practices/rules/js-set-map-lookups.md +0 -24
  280. package/src/claude/skills/react-best-practices/rules/js-tosorted-immutable.md +0 -57
  281. package/src/claude/skills/react-best-practices/rules/rendering-activity.md +0 -26
  282. package/src/claude/skills/react-best-practices/rules/rendering-animate-svg-wrapper.md +0 -47
  283. package/src/claude/skills/react-best-practices/rules/rendering-conditional-render.md +0 -40
  284. package/src/claude/skills/react-best-practices/rules/rendering-content-visibility.md +0 -38
  285. package/src/claude/skills/react-best-practices/rules/rendering-hoist-jsx.md +0 -46
  286. package/src/claude/skills/react-best-practices/rules/rendering-hydration-no-flicker.md +0 -82
  287. package/src/claude/skills/react-best-practices/rules/rendering-svg-precision.md +0 -28
  288. package/src/claude/skills/react-best-practices/rules/rerender-defer-reads.md +0 -39
  289. package/src/claude/skills/react-best-practices/rules/rerender-dependencies.md +0 -45
  290. package/src/claude/skills/react-best-practices/rules/rerender-derived-state.md +0 -29
  291. package/src/claude/skills/react-best-practices/rules/rerender-functional-setstate.md +0 -74
  292. package/src/claude/skills/react-best-practices/rules/rerender-lazy-state-init.md +0 -58
  293. package/src/claude/skills/react-best-practices/rules/rerender-memo.md +0 -44
  294. package/src/claude/skills/react-best-practices/rules/rerender-transitions.md +0 -40
  295. package/src/claude/skills/react-best-practices/rules/server-after-nonblocking.md +0 -73
  296. package/src/claude/skills/react-best-practices/rules/server-cache-lru.md +0 -41
  297. package/src/claude/skills/react-best-practices/rules/server-cache-react.md +0 -26
  298. package/src/claude/skills/react-best-practices/rules/server-parallel-fetching.md +0 -79
  299. package/src/claude/skills/react-best-practices/rules/server-serialization.md +0 -38
@@ -138,6 +138,269 @@ function inHookFixture(run, options = {}) {
138
138
  }
139
139
  }
140
140
 
141
+ function processTaskContent(title, status, dependency = 'none') {
142
+ return [
143
+ `# ${title}`, '', `Status: ${status}`, '',
144
+ '## Dependencies', '', `- ${dependency}`, '',
145
+ '## Verification Plan', '', '- Command: node --test', '',
146
+ ].join('\n');
147
+ }
148
+
149
+ function canonicalProcessTask(root, title, dependency = 'none') {
150
+ const context = workflowRuntimeContext(root, 'auth', 'session-auth-state');
151
+ return [
152
+ processTaskContent(title, 'done', dependency),
153
+ '## Receipt', '', 'Verification: PASS', 'Command: node --test', 'Exit: 0',
154
+ `Base: ${context.base}`, `Head: ${context.head}`,
155
+ '```text', 'node --test', '1 test passed', '```', '',
156
+ ].join('\n');
157
+ }
158
+
159
+ test('Claude and Codex docs sync ignore committed Specs state but report source changes', () => {
160
+ inHookFixture((root, hooks) => {
161
+ const docsDir = path.join(root, 'docs');
162
+ fs.mkdirSync(docsDir, { recursive: true });
163
+ fs.writeFileSync(path.join(root, 'package.json'), '{"name":"docs-sync-fixture"}\n');
164
+ fs.writeFileSync(path.join(docsDir, 'project-overview-pdr.md'), '# Fixture\n');
165
+ let result = spawnSync('git', ['-C', root, 'add', 'package.json', 'docs/project-overview-pdr.md'], { encoding: 'utf8' });
166
+ assert.equal(result.status, 0, result.stderr);
167
+ result = spawnSync('git', ['-C', root, 'commit', '-qm', 'source baseline'], { encoding: 'utf8' });
168
+ assert.equal(result.status, 0, result.stderr);
169
+ const sourceBase = spawnSync('git', ['-C', root, 'rev-parse', 'HEAD'], { encoding: 'utf8' }).stdout.trim();
170
+ fs.writeFileSync(path.join(docsDir, '.sync_hash'), `${sourceBase}\n`);
171
+ result = spawnSync('git', ['-C', root, 'add', 'docs/.sync_hash'], { encoding: 'utf8' });
172
+ assert.equal(result.status, 0, result.stderr);
173
+ result = spawnSync('git', ['-C', root, 'commit', '-qm', 'sync docs'], { encoding: 'utf8' });
174
+ assert.equal(result.status, 0, result.stderr);
175
+
176
+ const featureDir = path.join(root, 'specs', 'demo');
177
+ fs.mkdirSync(featureDir, { recursive: true });
178
+ fs.writeFileSync(path.join(featureDir, 'plan.md'), '# Completed packet\n');
179
+ result = spawnSync('git', ['-C', root, 'add', 'specs/demo/plan.md'], { encoding: 'utf8' });
180
+ assert.equal(result.status, 0, result.stderr);
181
+ result = spawnSync('git', ['-C', root, 'commit', '-qm', 'refresh receipt state'], { encoding: 'utf8' });
182
+ assert.equal(result.status, 0, result.stderr);
183
+
184
+ const payload = { cwd: root, session_id: 'docs-sync-session', hook_event_name: 'SessionStart' };
185
+ const docsSyncHooks = [
186
+ path.join(hooks, 'docs-sync.cjs'),
187
+ path.join(PACKAGE_ROOT, 'src/claude/hooks/docs-sync.cjs'),
188
+ ];
189
+ for (const hook of docsSyncHooks) {
190
+ const afterSpecCommit = runHook(hook, root, payload);
191
+ assert.equal(afterSpecCommit.status, 0, afterSpecCommit.stderr);
192
+ assert.equal(afterSpecCommit.stdout, '', `${hook}: spec-only commits must not stale docs sync`);
193
+ }
194
+
195
+ fs.mkdirSync(path.join(root, 'src'), { recursive: true });
196
+ fs.writeFileSync(path.join(root, 'src', 'app.js'), 'module.exports = true;\n');
197
+ result = spawnSync('git', ['-C', root, 'add', 'src/app.js'], { encoding: 'utf8' });
198
+ assert.equal(result.status, 0, result.stderr);
199
+ result = spawnSync('git', ['-C', root, 'commit', '-qm', 'change source'], { encoding: 'utf8' });
200
+ assert.equal(result.status, 0, result.stderr);
201
+ for (const hook of docsSyncHooks) {
202
+ const afterSourceCommit = runHook(hook, root, payload);
203
+ assert.equal(afterSourceCommit.status, 0, afterSourceCommit.stderr);
204
+ assert.match(afterSourceCommit.stdout, /Docs sync needed/);
205
+ }
206
+ });
207
+ });
208
+
209
+ function inInstalledProcessSpecStateFixture(run) {
210
+ return inHookFixture((root, hooks) => {
211
+ const feature = path.join(root, 'specs', 'auth');
212
+ fs.mkdirSync(feature, { recursive: true });
213
+ fs.writeFileSync(path.join(feature, 'plan.md'), '# Auth plan\nSpecs-Contract: process-first-ready-v1\n');
214
+
215
+ const writeTask = (basename, title, status, dependency = 'none') => {
216
+ fs.writeFileSync(
217
+ path.join(feature, basename),
218
+ processTaskContent(title, status, dependency),
219
+ );
220
+ };
221
+ const runState = () => runHook(path.join(hooks, 'spec-state.cjs'), root, {
222
+ cwd: root,
223
+ featureName: 'auth',
224
+ session_id: 'session-auth-state',
225
+ hook_event_name: 'UserPromptSubmit',
226
+ prompt: 'Continue',
227
+ });
228
+ const findCacheFile = () => {
229
+ const cacheDir = path.join(hooks, '.logs');
230
+ const cacheNames = fs.existsSync(cacheDir)
231
+ ? fs.readdirSync(cacheDir).filter((file) => file.startsWith('tollgate-'))
232
+ : [];
233
+ assert.equal(cacheNames.length, 1, 'one installed session cache must exist');
234
+ return path.join(cacheDir, cacheNames[0]);
235
+ };
236
+ return run({
237
+ feature,
238
+ findCacheFile,
239
+ hooks,
240
+ root,
241
+ runState,
242
+ writePlan: (content) => fs.writeFileSync(path.join(feature, 'plan.md'), content),
243
+ writeTask,
244
+ });
245
+ });
246
+ }
247
+
248
+ test('Codex installed spec-state re-evaluates a standalone task when blocked becomes pending', () => {
249
+ inInstalledProcessSpecStateFixture(({ findCacheFile, hooks, runState, writeTask }) => {
250
+ writeTask('task-01-auth.md', 'Task 01: auth', 'blocked');
251
+
252
+ const blocked = runState();
253
+ assert.equal(blocked.status, 0, blocked.stderr);
254
+ assert.match(blocked.stdout, /Spec state changed: `auth`/);
255
+ assert.doesNotMatch(blocked.stdout, /Next unblocked/);
256
+ const cacheFile = findCacheFile();
257
+ assert.ok(cacheFile.startsWith(`${hooks}${path.sep}`), 'cache must stay inside temporary installed hooks');
258
+ const blockedCache = fs.readFileSync(cacheFile, 'utf8');
259
+
260
+ writeTask('task-01-auth.md', 'Task 01: auth', 'pending');
261
+ const pending = runState();
262
+ assert.equal(pending.status, 0, pending.stderr);
263
+ assert.match(pending.stdout, /Spec state changed: `auth`/);
264
+ assert.match(pending.stdout, /Next unblocked: `task-01-auth\.md`/);
265
+ assert.notEqual(fs.readFileSync(cacheFile, 'utf8'), blockedCache, 'state cache must change');
266
+ });
267
+ });
268
+
269
+ test('Codex installed spec-state requires current canonical dependency proof and keys receipt mutations', () => {
270
+ inInstalledProcessSpecStateFixture(({ feature, findCacheFile, hooks, root, runState, writeTask }) => {
271
+ const predecessor = 'task-01-semantic-review.md';
272
+ const dependent = 'task-02-implementation.md';
273
+ writeTask(predecessor, 'Task 01: semantic review', 'blocked');
274
+ writeTask(dependent, 'Task 02: implementation', 'pending', predecessor);
275
+ const dependentPath = path.join(feature, dependent);
276
+ const unchangedDependent = fs.readFileSync(dependentPath, 'utf8');
277
+
278
+ const blocked = runState();
279
+ assert.equal(blocked.status, 0, blocked.stderr);
280
+ assert.match(blocked.stdout, /Tasks: 0 done \/ 2 total/);
281
+ assert.doesNotMatch(blocked.stdout, /Next unblocked/);
282
+ const cacheFile = findCacheFile();
283
+ assert.ok(cacheFile.startsWith(`${hooks}${path.sep}`), 'cache must stay inside temporary installed hooks');
284
+ const blockedCache = fs.readFileSync(cacheFile, 'utf8');
285
+
286
+ writeTask(predecessor, 'Task 01: semantic review', 'done');
287
+ const missing = runState();
288
+ assert.equal(missing.status, 0, missing.stderr);
289
+ assert.doesNotMatch(missing.stdout, /Next unblocked/);
290
+ const missingCache = fs.readFileSync(cacheFile, 'utf8');
291
+ assert.notEqual(missingCache, blockedCache, 'done without proof must change cached proof state');
292
+
293
+ fs.appendFileSync(path.join(feature, predecessor), '\n## Receipt\n\nVerification: PASS\n');
294
+ const malformed = runState();
295
+ assert.equal(malformed.status, 0, malformed.stderr);
296
+ assert.doesNotMatch(malformed.stdout, /Next unblocked/);
297
+
298
+ fs.writeFileSync(path.join(feature, predecessor), canonicalProcessTask(root, 'Task 01: semantic review'));
299
+ const ready = runState();
300
+ assert.equal(ready.status, 0, ready.stderr);
301
+ assert.match(ready.stdout, /Next unblocked: `task-02-implementation\.md`/);
302
+ const readyCache = fs.readFileSync(cacheFile, 'utf8');
303
+ assert.notEqual(readyCache, missingCache, 'canonical proof must change cached proof state');
304
+
305
+ fs.writeFileSync(
306
+ path.join(feature, predecessor),
307
+ fs.readFileSync(path.join(feature, predecessor), 'utf8').replace('Verification: PASS', 'Verification: FAIL'),
308
+ );
309
+ const mutated = runState();
310
+ assert.equal(mutated.status, 0, mutated.stderr);
311
+ assert.doesNotMatch(mutated.stdout, /Next unblocked/);
312
+ assert.notEqual(fs.readFileSync(cacheFile, 'utf8'), readyCache, 'receipt-only mutation must change cache');
313
+ assert.equal(fs.readFileSync(dependentPath, 'utf8'), unchangedDependent, 'dependent must remain pending');
314
+ });
315
+ });
316
+
317
+ test('Codex installed spec-state keeps unversioned pending packets out of Next with migration guidance', () => {
318
+ inInstalledProcessSpecStateFixture(({ feature, runState, writePlan, writeTask }) => {
319
+ const fencedMarkerPlan = '# Auth plan\n\n```markdown\nSpecs-Contract: process-first-ready-v1\n```\n';
320
+ writePlan(fencedMarkerPlan);
321
+ writeTask('task-01-auth.md', 'Task 01: auth', 'pending');
322
+ const taskBytes = fs.readFileSync(path.join(feature, 'task-01-auth.md'));
323
+ const result = runState();
324
+ assert.equal(result.status, 0, result.stderr);
325
+ assert.doesNotMatch(result.stdout, /Next unblocked/);
326
+ assert.match(result.stdout, /Migration required: add `Specs-Contract: process-first-ready-v1`/);
327
+ const cached = runState();
328
+ assert.equal(cached.status, 0, cached.stderr);
329
+ assert.doesNotMatch(cached.stdout, /Next unblocked/);
330
+ assert.match(cached.stdout, /Add `Specs-Contract: process-first-ready-v1`/);
331
+
332
+ writePlan(fencedMarkerPlan.replace('# Auth plan\n', '# Auth plan\nSpecs-Contract: process-first-ready-v1\n'));
333
+ const marked = runState();
334
+ assert.equal(marked.status, 0, marked.stderr);
335
+ assert.match(marked.stdout, /Spec state changed: `auth`/);
336
+ assert.match(marked.stdout, /Next unblocked: `task-01-auth\.md`/);
337
+ assert.deepEqual(fs.readFileSync(path.join(feature, 'task-01-auth.md')), taskBytes, 'marker-only transition must not change task bytes');
338
+ });
339
+ });
340
+
341
+ test('Codex resolver ignores fenced workflow annotations and rejects fenced-only Status', () => {
342
+ inInstalledProcessSpecStateFixture(({ feature, root, runState, writePlan, writeTask }) => {
343
+ const resolver = require(path.join(root, '.codex', 'scripts', 'spec-resolver.cjs'));
344
+ const trailingFence = resolver.annotatedMarkdownLines([
345
+ '```markdown', '``` trailing', 'Specs-Contract: process-first-ready-v1',
346
+ 'Status: done', '## Receipt', '```',
347
+ ].join('\n'));
348
+ assert.deepEqual(trailingFence.slice(2, 5).map(({ outsideFence }) => outsideFence), [false, false, false]);
349
+ const fourSpaceFence = resolver.annotatedMarkdownLines(' ```markdown\nStatus: pending');
350
+ assert.equal(fourSpaceFence[1].outsideFence, true);
351
+ writePlan('# Auth plan\nSpecs-Contract: process-first-ready-v1\n');
352
+ fs.writeFileSync(path.join(feature, 'task-01-fenced-only.md'), [
353
+ '# Task 01', '', '```markdown', 'Status: done', '```', '',
354
+ '## Dependencies', '', '- none', '', '## Verification Plan', '', '- Command: node --test', '',
355
+ ].join('\n'));
356
+ const malformed = resolver.resolveWorkflowCandidate({ projectRoot: root, runtime: {}, explicitFeature: 'auth' });
357
+ assert.equal(malformed.error, 'explicit_malformed');
358
+ assert.match(malformed.reason, /must contain exactly one supported Status field/);
359
+
360
+ fs.rmSync(path.join(feature, 'task-01-fenced-only.md'));
361
+ writeTask('task-01-dependent.md', 'Task 01: dependent', 'pending', 'task-02-predecessor.md');
362
+ fs.writeFileSync(path.join(feature, 'task-02-predecessor.md'), [
363
+ '# Task 02', '', 'Status: pending', '', '## Dependencies', '', '- none', '',
364
+ '## Verification Plan', '', '- Command: node --test', '',
365
+ '~~~~markdown', 'Status: done', '## Dependencies', '- task-01-dependent.md', '## Receipt',
366
+ 'Verification: PASS', 'Command: node --test', 'Exit: 0', '```text', 'fake pass', '```', '~~~~', '',
367
+ ].join('\n'));
368
+ const result = runState();
369
+ assert.equal(result.status, 0, result.stderr);
370
+ assert.match(result.stdout, /Next unblocked: `task-02-predecessor\.md`/);
371
+ assert.doesNotMatch(result.stdout, /Next unblocked: `task-01-dependent\.md`/);
372
+ });
373
+ });
374
+
375
+ test('Codex resolver accepts unique legacy task numbers, rejects ambiguity, and rejects exact cycles', () => {
376
+ inInstalledProcessSpecStateFixture(({ feature, root, writePlan, writeTask }) => {
377
+ const resolver = require(path.join(root, '.codex', 'scripts', 'spec-resolver.cjs'));
378
+ writePlan('# Auth plan\n');
379
+ writeTask('task-01-a.md', 'Task 01: a', 'pending');
380
+ writeTask('task-02-b.md', 'Task 02: b', 'pending', '01');
381
+ fs.writeFileSync(path.join(feature, 'task-03-c.md'), '# Task 03: c\n\nStatus: pending\n');
382
+ const unique = resolver.resolveWorkflowCandidate({ projectRoot: root, runtime: {}, explicitFeature: 'auth' });
383
+ assert.deepEqual(unique.taskRegistry['task-02-b.md'].dependencies, ['task-01-a.md']);
384
+ assert.deepEqual(unique.taskRegistry['task-03-c.md'].dependencies, []);
385
+ assert.equal(unique.workflowContract, null);
386
+ assert.equal(unique.queueReady, false);
387
+
388
+ writeTask('task-01-second.md', 'Task 01: second', 'pending');
389
+ const ambiguous = resolver.resolveWorkflowCandidate({ projectRoot: root, runtime: {}, explicitFeature: 'auth' });
390
+ assert.equal(ambiguous.error, 'explicit_malformed');
391
+ assert.match(ambiguous.reason, /legacy dependency 01 maps to 2 task basenames/);
392
+
393
+ fs.rmSync(path.join(feature, 'task-01-second.md'));
394
+ fs.rmSync(path.join(feature, 'task-03-c.md'));
395
+ writePlan('# Auth plan\nSpecs-Contract: process-first-ready-v1\n');
396
+ writeTask('task-01-a.md', 'Task 01: a', 'pending', 'task-02-b.md');
397
+ writeTask('task-02-b.md', 'Task 02: b', 'pending', 'task-01-a.md');
398
+ const cycle = resolver.resolveWorkflowCandidate({ projectRoot: root, runtime: {}, explicitFeature: 'auth' });
399
+ assert.equal(cycle.error, 'explicit_malformed');
400
+ assert.match(cycle.reason, /dependency cycle detected: task-01-a\.md -> task-02-b\.md -> task-01-a\.md/);
401
+ });
402
+ });
403
+
141
404
  test('Codex privacy approval is exact, session-bound, and reusable within its window', () => {
142
405
  inHookFixture((root, hooks) => {
143
406
  const nested = path.join(root, 'packages', 'app');
@@ -434,6 +697,7 @@ test('Codex completion gate validates explicit process-v3 inline Receipt', () =>
434
697
  fs.writeFileSync(path.join(feature, 'plan.md'), '# Auth plan\n');
435
698
  fs.writeFileSync(taskFile, [
436
699
  '# Task 01: auth', '', 'Status: done', '',
700
+ '## Dependencies', '', '- none', '',
437
701
  '## Verification Plan', '', '- Command: node --test', '',
438
702
  ].join('\n'));
439
703
 
@@ -452,6 +716,33 @@ test('Codex completion gate validates explicit process-v3 inline Receipt', () =>
452
716
  const context = workflowRuntimeContext(root);
453
717
  fs.writeFileSync(taskFile, [
454
718
  '# Task 01: auth', '', 'Status: done', '',
719
+ '## Dependencies', '', '- none', '',
720
+ '## Verification Plan', '', '- Command: node --test', '',
721
+ '## Receipt', '', '```text', 'Verification: PASS', 'Command: node --test', 'Exit: 0',
722
+ `Base: ${context.base}`, `Head: ${context.head}`, 'pass: 1', '```', '',
723
+ ].join('\n'));
724
+ const fencedFields = runHook(gate, nested, payload);
725
+ assert.equal(fencedFields.status, 0, fencedFields.stderr);
726
+ assert.match(JSON.parse(fencedFields.stdout).reason, /verification_state/);
727
+ assert.match(JSON.parse(fencedFields.stdout).reason, /command/);
728
+ assert.match(JSON.parse(fencedFields.stdout).reason, /provenance/);
729
+
730
+ fs.writeFileSync(taskFile, [
731
+ '# Task 01: auth', '', 'Status: done', '',
732
+ '## Dependencies', '', '- none', '',
733
+ '## Verification Plan', '', '- Command: node --test', '',
734
+ '## Receipt', '',
735
+ 'Verification: PASS', 'Command: node --test', 'Exit: 0',
736
+ `Base: ${context.base}`, `Head: ${context.head}`,
737
+ '````text', '$ node --test', 'pass: 1', '```', '',
738
+ ].join('\n'));
739
+ const malformedOutputFence = runHook(gate, nested, payload);
740
+ assert.equal(malformedOutputFence.status, 0, malformedOutputFence.stderr);
741
+ assert.match(JSON.parse(malformedOutputFence.stdout).reason, /command_output/);
742
+
743
+ fs.writeFileSync(taskFile, [
744
+ '# Task 01: auth', '', 'Status: done', '',
745
+ '## Dependencies', '', '- none', '',
455
746
  '## Verification Plan', '', '- Command: node --test', '',
456
747
  '## Receipt', '',
457
748
  'Verification: PASS', 'Command: node --test', 'Exit: 0',
@@ -472,6 +763,7 @@ test('Codex process-v3 Receipt command must match the exact Verification Plan co
472
763
  const context = workflowRuntimeContext(root);
473
764
  fs.writeFileSync(path.join(feature, 'task-01-auth.md'), [
474
765
  '# Task 01: auth', '', 'Status: done', '',
766
+ '## Dependencies', '', '- none', '',
475
767
  '## Verification Plan', '', '- Command: pnpm test', '',
476
768
  '## Receipt', '', 'Verification: PASS', 'Command: true', 'Exit: 0',
477
769
  `Base: ${context.base}`, `Head: ${context.head}`,
@@ -501,6 +793,7 @@ test('Codex process-v3 Stop ignores a completed packet when one packet remains a
501
793
  const context = workflowRuntimeContext(root);
502
794
  fs.writeFileSync(path.join(completed, 'task-01-auth.md'), [
503
795
  '# Task 01: auth', '', 'Status: done', '',
796
+ '## Dependencies', '', '- none', '',
504
797
  '## Verification Plan', '', '- Command: node --test', '',
505
798
  '## Receipt', '',
506
799
  'Verification: PASS', 'Command: node --test', 'Exit: 0',
@@ -509,6 +802,7 @@ test('Codex process-v3 Stop ignores a completed packet when one packet remains a
509
802
  ].join('\n'));
510
803
  fs.writeFileSync(path.join(active, 'task-01-active.md'), [
511
804
  '# Task 01: active', '', 'Status: pending', '',
805
+ '## Dependencies', '', '- none', '',
512
806
  '## Verification Plan', '', '- Command: node --test', '',
513
807
  ].join('\n'));
514
808
 
@@ -532,6 +826,7 @@ test('Codex process-v3 Stop accepts two completed packets with valid Receipts',
532
826
  const context = workflowRuntimeContext(root, featureName);
533
827
  fs.writeFileSync(path.join(feature, `task-01-${featureName}.md`), [
534
828
  `# Task 01: ${featureName}`, '', 'Status: done', '',
829
+ '## Dependencies', '', '- none', '',
535
830
  '## Verification Plan', '', '- Command: node --test', '',
536
831
  '## Receipt', '',
537
832
  'Verification: PASS', 'Command: node --test', 'Exit: 0',