@paths.design/caws-cli 10.2.0 → 11.0.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 (421) hide show
  1. package/README.md +125 -374
  2. package/dist/index.js +43 -785
  3. package/dist/shell/binding/resolve-binding.d.ts +4 -0
  4. package/dist/shell/binding/resolve-binding.d.ts.map +1 -0
  5. package/dist/shell/binding/resolve-binding.js +228 -0
  6. package/dist/shell/binding/resolve-binding.js.map +1 -0
  7. package/dist/shell/binding/types.d.ts +42 -0
  8. package/dist/shell/binding/types.d.ts.map +1 -0
  9. package/dist/shell/binding/types.js +21 -0
  10. package/dist/shell/binding/types.js.map +1 -0
  11. package/dist/shell/commands/claim.d.ts +14 -0
  12. package/dist/shell/commands/claim.d.ts.map +1 -0
  13. package/dist/shell/commands/claim.js +197 -0
  14. package/dist/shell/commands/claim.js.map +1 -0
  15. package/dist/shell/commands/doctor.d.ts +13 -0
  16. package/dist/shell/commands/doctor.d.ts.map +1 -0
  17. package/dist/shell/commands/doctor.js +97 -0
  18. package/dist/shell/commands/doctor.js.map +1 -0
  19. package/dist/shell/commands/evidence.d.ts +28 -0
  20. package/dist/shell/commands/evidence.d.ts.map +1 -0
  21. package/dist/shell/commands/evidence.js +166 -0
  22. package/dist/shell/commands/evidence.js.map +1 -0
  23. package/dist/shell/commands/gates.d.ts +19 -0
  24. package/dist/shell/commands/gates.d.ts.map +1 -0
  25. package/dist/shell/commands/gates.js +181 -0
  26. package/dist/shell/commands/gates.js.map +1 -0
  27. package/dist/shell/commands/init.d.ts +8 -0
  28. package/dist/shell/commands/init.d.ts.map +1 -0
  29. package/dist/shell/commands/init.js +64 -0
  30. package/dist/shell/commands/init.js.map +1 -0
  31. package/dist/shell/commands/scope.d.ts +11 -0
  32. package/dist/shell/commands/scope.d.ts.map +1 -0
  33. package/dist/shell/commands/scope.js +92 -0
  34. package/dist/shell/commands/scope.js.map +1 -0
  35. package/dist/shell/commands/status.d.ts +15 -0
  36. package/dist/shell/commands/status.d.ts.map +1 -0
  37. package/dist/shell/commands/status.js +106 -0
  38. package/dist/shell/commands/status.js.map +1 -0
  39. package/dist/shell/commands/waiver.d.ts +38 -0
  40. package/dist/shell/commands/waiver.d.ts.map +1 -0
  41. package/dist/shell/commands/waiver.js +240 -0
  42. package/dist/shell/commands/waiver.js.map +1 -0
  43. package/dist/shell/gates/disposition.d.ts +23 -0
  44. package/dist/shell/gates/disposition.d.ts.map +1 -0
  45. package/dist/shell/gates/disposition.js +87 -0
  46. package/dist/shell/gates/disposition.js.map +1 -0
  47. package/dist/shell/gates/gate-result-contract.d.ts +39 -0
  48. package/dist/shell/gates/gate-result-contract.d.ts.map +1 -0
  49. package/dist/shell/gates/gate-result-contract.js +150 -0
  50. package/dist/shell/gates/gate-result-contract.js.map +1 -0
  51. package/dist/shell/gates/quality-gates-adapter.d.ts +55 -0
  52. package/dist/shell/gates/quality-gates-adapter.d.ts.map +1 -0
  53. package/dist/shell/gates/quality-gates-adapter.js +161 -0
  54. package/dist/shell/gates/quality-gates-adapter.js.map +1 -0
  55. package/dist/shell/gates/waiver-filter.d.ts +58 -0
  56. package/dist/shell/gates/waiver-filter.d.ts.map +1 -0
  57. package/dist/shell/gates/waiver-filter.js +119 -0
  58. package/dist/shell/gates/waiver-filter.js.map +1 -0
  59. package/dist/shell/index.d.ts +50 -0
  60. package/dist/shell/index.d.ts.map +1 -0
  61. package/dist/shell/index.js +73 -0
  62. package/dist/shell/index.js.map +1 -0
  63. package/dist/shell/register.d.ts +11 -0
  64. package/dist/shell/register.d.ts.map +1 -0
  65. package/dist/shell/register.js +274 -0
  66. package/dist/shell/register.js.map +1 -0
  67. package/dist/shell/render/claim.d.ts +22 -0
  68. package/dist/shell/render/claim.d.ts.map +1 -0
  69. package/dist/shell/render/claim.js +75 -0
  70. package/dist/shell/render/claim.js.map +1 -0
  71. package/dist/shell/render/decision.d.ts +15 -0
  72. package/dist/shell/render/decision.d.ts.map +1 -0
  73. package/dist/shell/render/decision.js +66 -0
  74. package/dist/shell/render/decision.js.map +1 -0
  75. package/dist/shell/render/diagnostic.d.ts +19 -0
  76. package/dist/shell/render/diagnostic.d.ts.map +1 -0
  77. package/dist/shell/render/diagnostic.js +76 -0
  78. package/dist/shell/render/diagnostic.js.map +1 -0
  79. package/dist/shell/render/finding.d.ts +15 -0
  80. package/dist/shell/render/finding.d.ts.map +1 -0
  81. package/dist/shell/render/finding.js +57 -0
  82. package/dist/shell/render/finding.js.map +1 -0
  83. package/dist/shell/render/gates.d.ts +3 -0
  84. package/dist/shell/render/gates.d.ts.map +1 -0
  85. package/dist/shell/render/gates.js +56 -0
  86. package/dist/shell/render/gates.js.map +1 -0
  87. package/dist/shell/render/init.d.ts +11 -0
  88. package/dist/shell/render/init.d.ts.map +1 -0
  89. package/dist/shell/render/init.js +32 -0
  90. package/dist/shell/render/init.js.map +1 -0
  91. package/dist/shell/render/status.d.ts +26 -0
  92. package/dist/shell/render/status.d.ts.map +1 -0
  93. package/dist/shell/render/status.js +143 -0
  94. package/dist/shell/render/status.js.map +1 -0
  95. package/dist/shell/render/waiver.d.ts +21 -0
  96. package/dist/shell/render/waiver.d.ts.map +1 -0
  97. package/dist/shell/render/waiver.js +94 -0
  98. package/dist/shell/render/waiver.js.map +1 -0
  99. package/dist/shell/rules.d.ts +37 -0
  100. package/dist/shell/rules.d.ts.map +1 -0
  101. package/dist/shell/rules.js +51 -0
  102. package/dist/shell/rules.js.map +1 -0
  103. package/dist/shell/session/actor.d.ts +14 -0
  104. package/dist/shell/session/actor.d.ts.map +1 -0
  105. package/dist/shell/session/actor.js +34 -0
  106. package/dist/shell/session/actor.js.map +1 -0
  107. package/dist/shell/session/resolve-session.d.ts +5 -0
  108. package/dist/shell/session/resolve-session.d.ts.map +1 -0
  109. package/dist/shell/session/resolve-session.js +239 -0
  110. package/dist/shell/session/resolve-session.js.map +1 -0
  111. package/dist/shell/session/types.d.ts +56 -0
  112. package/dist/shell/session/types.d.ts.map +1 -0
  113. package/dist/shell/session/types.js +15 -0
  114. package/dist/shell/session/types.js.map +1 -0
  115. package/dist/store/agents-store.d.ts +3 -0
  116. package/dist/store/agents-store.d.ts.map +1 -0
  117. package/dist/store/agents-store.js +63 -0
  118. package/dist/store/agents-store.js.map +1 -0
  119. package/dist/store/apply-patch.d.ts +16 -0
  120. package/dist/store/apply-patch.d.ts.map +1 -0
  121. package/dist/store/apply-patch.js +191 -0
  122. package/dist/store/apply-patch.js.map +1 -0
  123. package/dist/store/atomic-write.d.ts +16 -0
  124. package/dist/store/atomic-write.d.ts.map +1 -0
  125. package/dist/store/atomic-write.js +132 -0
  126. package/dist/store/atomic-write.js.map +1 -0
  127. package/dist/store/doctor-snapshot.d.ts +20 -0
  128. package/dist/store/doctor-snapshot.d.ts.map +1 -0
  129. package/dist/store/doctor-snapshot.js +176 -0
  130. package/dist/store/doctor-snapshot.js.map +1 -0
  131. package/dist/store/events-store.d.ts +33 -0
  132. package/dist/store/events-store.d.ts.map +1 -0
  133. package/dist/store/events-store.js +297 -0
  134. package/dist/store/events-store.js.map +1 -0
  135. package/dist/store/index.d.ts +21 -0
  136. package/dist/store/index.d.ts.map +1 -0
  137. package/dist/store/index.js +47 -0
  138. package/dist/store/index.js.map +1 -0
  139. package/dist/store/init-store.d.ts +21 -0
  140. package/dist/store/init-store.d.ts.map +1 -0
  141. package/dist/store/init-store.js +295 -0
  142. package/dist/store/init-store.js.map +1 -0
  143. package/dist/store/json-store.d.ts +3 -0
  144. package/dist/store/json-store.d.ts.map +1 -0
  145. package/dist/store/json-store.js +65 -0
  146. package/dist/store/json-store.js.map +1 -0
  147. package/dist/store/policy-store.d.ts +3 -0
  148. package/dist/store/policy-store.d.ts.map +1 -0
  149. package/dist/store/policy-store.js +65 -0
  150. package/dist/store/policy-store.js.map +1 -0
  151. package/dist/store/repo-root.d.ts +46 -0
  152. package/dist/store/repo-root.d.ts.map +1 -0
  153. package/dist/store/repo-root.js +145 -0
  154. package/dist/store/repo-root.js.map +1 -0
  155. package/dist/store/rules.d.ts +53 -0
  156. package/dist/store/rules.d.ts.map +1 -0
  157. package/dist/store/rules.js +78 -0
  158. package/dist/store/rules.js.map +1 -0
  159. package/dist/store/specs-store.d.ts +3 -0
  160. package/dist/store/specs-store.d.ts.map +1 -0
  161. package/dist/store/specs-store.js +131 -0
  162. package/dist/store/specs-store.js.map +1 -0
  163. package/dist/store/types.d.ts +84 -0
  164. package/dist/store/types.d.ts.map +1 -0
  165. package/dist/store/types.js +14 -0
  166. package/dist/store/types.js.map +1 -0
  167. package/dist/store/waivers-store.d.ts +25 -0
  168. package/dist/store/waivers-store.d.ts.map +1 -0
  169. package/dist/store/waivers-store.js +232 -0
  170. package/dist/store/waivers-store.js.map +1 -0
  171. package/dist/store/worktrees-store.d.ts +3 -0
  172. package/dist/store/worktrees-store.d.ts.map +1 -0
  173. package/dist/store/worktrees-store.js +62 -0
  174. package/dist/store/worktrees-store.js.map +1 -0
  175. package/dist/store/yaml-store.d.ts +9 -0
  176. package/dist/store/yaml-store.d.ts.map +1 -0
  177. package/dist/store/yaml-store.js +121 -0
  178. package/dist/store/yaml-store.js.map +1 -0
  179. package/package.json +15 -13
  180. package/dist/budget-derivation.js +0 -751
  181. package/dist/cicd-optimizer.js +0 -504
  182. package/dist/commands/agents.js +0 -124
  183. package/dist/commands/archive.js +0 -500
  184. package/dist/commands/burnup.js +0 -198
  185. package/dist/commands/diagnose.js +0 -525
  186. package/dist/commands/evaluate.js +0 -314
  187. package/dist/commands/gates.js +0 -149
  188. package/dist/commands/init.js +0 -857
  189. package/dist/commands/iterate.js +0 -417
  190. package/dist/commands/mode.js +0 -269
  191. package/dist/commands/parallel.js +0 -242
  192. package/dist/commands/plan.js +0 -438
  193. package/dist/commands/provenance.js +0 -1143
  194. package/dist/commands/quality-monitor.js +0 -284
  195. package/dist/commands/scope.js +0 -264
  196. package/dist/commands/session.js +0 -312
  197. package/dist/commands/sidecar.js +0 -74
  198. package/dist/commands/specs.js +0 -1656
  199. package/dist/commands/status.js +0 -1172
  200. package/dist/commands/templates.js +0 -237
  201. package/dist/commands/tool.js +0 -136
  202. package/dist/commands/tutorial.js +0 -480
  203. package/dist/commands/validate.js +0 -357
  204. package/dist/commands/verify-acs.js +0 -443
  205. package/dist/commands/waivers.js +0 -599
  206. package/dist/commands/workflow.js +0 -243
  207. package/dist/commands/worktree.js +0 -502
  208. package/dist/config/lite-scope.js +0 -158
  209. package/dist/config/modes.js +0 -347
  210. package/dist/constants/spec-types.js +0 -65
  211. package/dist/gates/budget-limit.js +0 -121
  212. package/dist/gates/feedback.js +0 -260
  213. package/dist/gates/format.js +0 -179
  214. package/dist/gates/god-object.js +0 -117
  215. package/dist/gates/pipeline.js +0 -167
  216. package/dist/gates/scope-boundary.js +0 -112
  217. package/dist/gates/spec-completeness.js +0 -109
  218. package/dist/gates/todo-detection.js +0 -205
  219. package/dist/generators/jest-config-generator.js +0 -242
  220. package/dist/generators/working-spec.js +0 -237
  221. package/dist/minimal-cli.js +0 -88
  222. package/dist/parallel/parallel-manager.js +0 -433
  223. package/dist/policy/PolicyManager.js +0 -470
  224. package/dist/scaffold/claude-hooks.js +0 -443
  225. package/dist/scaffold/cursor-hooks.js +0 -177
  226. package/dist/scaffold/git-hooks.js +0 -928
  227. package/dist/scaffold/index.js +0 -794
  228. package/dist/session/session-manager.js +0 -653
  229. package/dist/sidecars/index.js +0 -33
  230. package/dist/sidecars/listeners.js +0 -40
  231. package/dist/sidecars/provenance-summary.js +0 -238
  232. package/dist/sidecars/quality-gaps.js +0 -258
  233. package/dist/sidecars/schema.js +0 -149
  234. package/dist/sidecars/spec-drift.js +0 -151
  235. package/dist/sidecars/waiver-draft.js +0 -176
  236. package/dist/spec/SpecFileManager.js +0 -419
  237. package/dist/templates/.caws/schemas/policy.schema.json +0 -117
  238. package/dist/templates/.caws/schemas/scope.schema.json +0 -52
  239. package/dist/templates/.caws/schemas/waivers.schema.json +0 -106
  240. package/dist/templates/.caws/schemas/working-spec.schema.json +0 -340
  241. package/dist/templates/.caws/schemas/worktrees.schema.json +0 -38
  242. package/dist/templates/.caws/templates/working-spec.template.yml +0 -80
  243. package/dist/templates/.caws/tools/README.md +0 -18
  244. package/dist/templates/.caws/tools/scope-guard.js +0 -203
  245. package/dist/templates/.caws/tools-allow.json +0 -331
  246. package/dist/templates/.caws/waivers.yml +0 -19
  247. package/dist/templates/.claude/README.md +0 -190
  248. package/dist/templates/.claude/hooks/audit.sh +0 -121
  249. package/dist/templates/.claude/hooks/block-dangerous.sh +0 -203
  250. package/dist/templates/.claude/hooks/classify_command.py +0 -592
  251. package/dist/templates/.claude/hooks/doc-frontmatter-check.sh +0 -173
  252. package/dist/templates/.claude/hooks/lite-sprawl-check.sh +0 -145
  253. package/dist/templates/.claude/hooks/naming-check.sh +0 -100
  254. package/dist/templates/.claude/hooks/protected-paths.sh +0 -39
  255. package/dist/templates/.claude/hooks/quality-check.sh +0 -81
  256. package/dist/templates/.claude/hooks/scan-secrets.sh +0 -85
  257. package/dist/templates/.claude/hooks/scope-guard.sh +0 -381
  258. package/dist/templates/.claude/hooks/session-caws-status.sh +0 -117
  259. package/dist/templates/.claude/hooks/session-log.sh +0 -634
  260. package/dist/templates/.claude/hooks/simplification-guard.sh +0 -92
  261. package/dist/templates/.claude/hooks/stop-worktree-check.sh +0 -46
  262. package/dist/templates/.claude/hooks/test_classify_command.py +0 -370
  263. package/dist/templates/.claude/hooks/test_wrapper_smoke.sh +0 -96
  264. package/dist/templates/.claude/hooks/validate-spec.sh +0 -76
  265. package/dist/templates/.claude/hooks/worktree-guard.sh +0 -220
  266. package/dist/templates/.claude/hooks/worktree-write-guard.sh +0 -190
  267. package/dist/templates/.claude/rules/git-safety.md +0 -26
  268. package/dist/templates/.claude/rules/worktree-isolation.md +0 -101
  269. package/dist/templates/.claude/settings.json +0 -141
  270. package/dist/templates/.cursor/README.md +0 -299
  271. package/dist/templates/.cursor/hooks/audit.sh +0 -55
  272. package/dist/templates/.cursor/hooks/block-dangerous.sh +0 -84
  273. package/dist/templates/.cursor/hooks/caws-quality-check.sh +0 -52
  274. package/dist/templates/.cursor/hooks/caws-scope-guard.sh +0 -130
  275. package/dist/templates/.cursor/hooks/format.sh +0 -38
  276. package/dist/templates/.cursor/hooks/naming-check.sh +0 -64
  277. package/dist/templates/.cursor/hooks/scan-secrets.sh +0 -51
  278. package/dist/templates/.cursor/hooks/scope-guard.sh +0 -52
  279. package/dist/templates/.cursor/hooks/session-log.sh +0 -924
  280. package/dist/templates/.cursor/hooks/validate-spec.sh +0 -83
  281. package/dist/templates/.cursor/hooks.json +0 -76
  282. package/dist/templates/.cursor/rules/00-claims-verification.mdc +0 -144
  283. package/dist/templates/.cursor/rules/01-working-style.mdc +0 -50
  284. package/dist/templates/.cursor/rules/02-quality-gates.mdc +0 -368
  285. package/dist/templates/.cursor/rules/03-naming-and-refactor.mdc +0 -33
  286. package/dist/templates/.cursor/rules/04-logging-language-style.mdc +0 -23
  287. package/dist/templates/.cursor/rules/05-safe-defaults-guards.mdc +0 -23
  288. package/dist/templates/.cursor/rules/06-typescript-conventions.mdc +0 -36
  289. package/dist/templates/.cursor/rules/07-process-ops.mdc +0 -20
  290. package/dist/templates/.cursor/rules/08-solid-and-architecture.mdc +0 -16
  291. package/dist/templates/.cursor/rules/09-docstrings.mdc +0 -89
  292. package/dist/templates/.cursor/rules/10-documentation-quality-standards.mdc +0 -385
  293. package/dist/templates/.cursor/rules/11-scope-management-waivers.mdc +0 -381
  294. package/dist/templates/.cursor/rules/12-implementation-completeness.mdc +0 -516
  295. package/dist/templates/.cursor/rules/13-language-agnostic-standards.mdc +0 -578
  296. package/dist/templates/.cursor/rules/README.md +0 -148
  297. package/dist/templates/.github/copilot-instructions.md +0 -82
  298. package/dist/templates/.idea/runConfigurations/CAWS_Evaluate.xml +0 -5
  299. package/dist/templates/.idea/runConfigurations/CAWS_Validate.xml +0 -5
  300. package/dist/templates/.junie/guidelines.md +0 -73
  301. package/dist/templates/.vscode/launch.json +0 -17
  302. package/dist/templates/.vscode/settings.json +0 -95
  303. package/dist/templates/.windsurf/rules/caws-quality-standards.md +0 -54
  304. package/dist/templates/.windsurf/workflows/caws-guided-development.md +0 -92
  305. package/dist/templates/CLAUDE.md +0 -196
  306. package/dist/templates/COMMIT_CONVENTIONS.md +0 -86
  307. package/dist/templates/OIDC_SETUP.md +0 -300
  308. package/dist/templates/agents.md +0 -171
  309. package/dist/templates/codemod/README.md +0 -1
  310. package/dist/templates/codemod/test.js +0 -93
  311. package/dist/templates/docs/README.md +0 -151
  312. package/dist/templates/scripts/new_feature.sh +0 -80
  313. package/dist/templates/scripts/quality-gates/check-god-objects.js +0 -146
  314. package/dist/templates/scripts/quality-gates/run-quality-gates.js +0 -50
  315. package/dist/templates/scripts/v3/analysis/todo_analyzer.py +0 -1997
  316. package/dist/test-analysis.js +0 -786
  317. package/dist/tool-interface.js +0 -314
  318. package/dist/tool-loader.js +0 -303
  319. package/dist/tool-validator.js +0 -393
  320. package/dist/utils/agent-display.js +0 -210
  321. package/dist/utils/agent-session.js +0 -344
  322. package/dist/utils/async-utils.js +0 -188
  323. package/dist/utils/command-wrapper.js +0 -200
  324. package/dist/utils/event-log.js +0 -584
  325. package/dist/utils/event-renderer.js +0 -521
  326. package/dist/utils/finalization.js +0 -230
  327. package/dist/utils/git-lock.js +0 -119
  328. package/dist/utils/gitignore-updater.js +0 -158
  329. package/dist/utils/ide-detection.js +0 -133
  330. package/dist/utils/lifecycle-events.js +0 -94
  331. package/dist/utils/project-analysis.js +0 -367
  332. package/dist/utils/promise-utils.js +0 -72
  333. package/dist/utils/quality-gates-errors.js +0 -520
  334. package/dist/utils/quality-gates-utils.js +0 -387
  335. package/dist/utils/schema-validator.js +0 -50
  336. package/dist/utils/spec-resolver.js +0 -711
  337. package/dist/utils/typescript-detector.js +0 -369
  338. package/dist/utils/working-state.js +0 -530
  339. package/dist/utils/yaml-validation.js +0 -156
  340. package/dist/validation/spec-validation.js +0 -924
  341. package/dist/waivers-manager.js +0 -732
  342. package/dist/worktree/worktree-manager.js +0 -1735
  343. package/templates/.caws/schemas/policy.schema.json +0 -117
  344. package/templates/.caws/schemas/scope.schema.json +0 -52
  345. package/templates/.caws/schemas/waivers.schema.json +0 -106
  346. package/templates/.caws/schemas/working-spec.schema.json +0 -340
  347. package/templates/.caws/schemas/worktrees.schema.json +0 -38
  348. package/templates/.caws/templates/working-spec.template.yml +0 -80
  349. package/templates/.caws/tools/README.md +0 -18
  350. package/templates/.caws/tools/scope-guard.js +0 -203
  351. package/templates/.caws/tools-allow.json +0 -331
  352. package/templates/.caws/waivers.yml +0 -19
  353. package/templates/.claude/README.md +0 -190
  354. package/templates/.claude/hooks/audit.sh +0 -121
  355. package/templates/.claude/hooks/block-dangerous.sh +0 -203
  356. package/templates/.claude/hooks/classify_command.py +0 -592
  357. package/templates/.claude/hooks/doc-frontmatter-check.sh +0 -173
  358. package/templates/.claude/hooks/lite-sprawl-check.sh +0 -145
  359. package/templates/.claude/hooks/naming-check.sh +0 -100
  360. package/templates/.claude/hooks/protected-paths.sh +0 -39
  361. package/templates/.claude/hooks/quality-check.sh +0 -81
  362. package/templates/.claude/hooks/scan-secrets.sh +0 -85
  363. package/templates/.claude/hooks/scope-guard.sh +0 -381
  364. package/templates/.claude/hooks/session-caws-status.sh +0 -117
  365. package/templates/.claude/hooks/session-log.sh +0 -634
  366. package/templates/.claude/hooks/simplification-guard.sh +0 -92
  367. package/templates/.claude/hooks/stop-worktree-check.sh +0 -46
  368. package/templates/.claude/hooks/test_classify_command.py +0 -370
  369. package/templates/.claude/hooks/test_wrapper_smoke.sh +0 -96
  370. package/templates/.claude/hooks/validate-spec.sh +0 -76
  371. package/templates/.claude/hooks/worktree-guard.sh +0 -220
  372. package/templates/.claude/hooks/worktree-write-guard.sh +0 -190
  373. package/templates/.claude/rules/git-safety.md +0 -26
  374. package/templates/.claude/rules/worktree-isolation.md +0 -101
  375. package/templates/.claude/settings.json +0 -141
  376. package/templates/.cursor/README.md +0 -299
  377. package/templates/.cursor/hooks/audit.sh +0 -55
  378. package/templates/.cursor/hooks/block-dangerous.sh +0 -84
  379. package/templates/.cursor/hooks/caws-quality-check.sh +0 -52
  380. package/templates/.cursor/hooks/caws-scope-guard.sh +0 -130
  381. package/templates/.cursor/hooks/format.sh +0 -38
  382. package/templates/.cursor/hooks/naming-check.sh +0 -64
  383. package/templates/.cursor/hooks/scan-secrets.sh +0 -51
  384. package/templates/.cursor/hooks/scope-guard.sh +0 -52
  385. package/templates/.cursor/hooks/session-log.sh +0 -924
  386. package/templates/.cursor/hooks/validate-spec.sh +0 -83
  387. package/templates/.cursor/hooks.json +0 -76
  388. package/templates/.cursor/rules/00-claims-verification.mdc +0 -144
  389. package/templates/.cursor/rules/01-working-style.mdc +0 -50
  390. package/templates/.cursor/rules/02-quality-gates.mdc +0 -368
  391. package/templates/.cursor/rules/03-naming-and-refactor.mdc +0 -33
  392. package/templates/.cursor/rules/04-logging-language-style.mdc +0 -23
  393. package/templates/.cursor/rules/05-safe-defaults-guards.mdc +0 -23
  394. package/templates/.cursor/rules/06-typescript-conventions.mdc +0 -36
  395. package/templates/.cursor/rules/07-process-ops.mdc +0 -20
  396. package/templates/.cursor/rules/08-solid-and-architecture.mdc +0 -16
  397. package/templates/.cursor/rules/09-docstrings.mdc +0 -89
  398. package/templates/.cursor/rules/10-documentation-quality-standards.mdc +0 -385
  399. package/templates/.cursor/rules/11-scope-management-waivers.mdc +0 -381
  400. package/templates/.cursor/rules/12-implementation-completeness.mdc +0 -516
  401. package/templates/.cursor/rules/13-language-agnostic-standards.mdc +0 -578
  402. package/templates/.cursor/rules/README.md +0 -148
  403. package/templates/.github/copilot-instructions.md +0 -82
  404. package/templates/.idea/runConfigurations/CAWS_Evaluate.xml +0 -5
  405. package/templates/.idea/runConfigurations/CAWS_Validate.xml +0 -5
  406. package/templates/.junie/guidelines.md +0 -73
  407. package/templates/.vscode/launch.json +0 -17
  408. package/templates/.vscode/settings.json +0 -95
  409. package/templates/.windsurf/rules/caws-quality-standards.md +0 -54
  410. package/templates/.windsurf/workflows/caws-guided-development.md +0 -92
  411. package/templates/CLAUDE.md +0 -196
  412. package/templates/COMMIT_CONVENTIONS.md +0 -86
  413. package/templates/OIDC_SETUP.md +0 -300
  414. package/templates/agents.md +0 -171
  415. package/templates/codemod/README.md +0 -1
  416. package/templates/codemod/test.js +0 -93
  417. package/templates/docs/README.md +0 -151
  418. package/templates/scripts/new_feature.sh +0 -80
  419. package/templates/scripts/quality-gates/check-god-objects.js +0 -146
  420. package/templates/scripts/quality-gates/run-quality-gates.js +0 -50
  421. package/templates/scripts/v3/analysis/todo_analyzer.py +0 -1997
@@ -1,584 +0,0 @@
1
- /**
2
- * @fileoverview Event Log — append-only provenance surface
3
- *
4
- * CAWS events are written once to `.caws/events.jsonl` and never rewritten.
5
- * Every other view (per-spec state, session registry, provenance chain) is
6
- * a pure function of this log. See docs/internal/EVENTS_LOG_MIGRATION.md
7
- * for the full design.
8
- *
9
- * Contract highlights:
10
- * - Append-only. Readers tolerate partial last lines.
11
- * - Hash-chained. Each event carries prev_hash and event_hash (sha256).
12
- * - Fail-loud. Events missing a required spec_id throw; no silent writes.
13
- * - Cross-platform file lock via `fs.openSync(lockPath, 'wx')` sentinel.
14
- *
15
- * This file ships as Phase 1 (dual-write). State-layer writes in
16
- * working-state.js continue unchanged; this log is additive.
17
- *
18
- * @author @darianrosebrook
19
- */
20
-
21
- const fs = require('fs');
22
- const path = require('path');
23
- const crypto = require('crypto');
24
-
25
- // ---------------------------------------------------------------------------
26
- // Constants
27
- // ---------------------------------------------------------------------------
28
-
29
- const EVENTS_FILE = '.caws/events.jsonl';
30
- const LOCK_SUFFIX = '.lock';
31
- const HASH_DOMAIN = 'caws.events.v1';
32
- const LOCK_RETRY_MS = 20;
33
- const LOCK_RETRY_MAX = 50; // ~1s total
34
-
35
- /**
36
- * Events that require a spec_id in their payload. appendEvent throws if
37
- * spec_id is missing for any event listed here. This is the fence that
38
- * prevents the `.caws/state/undefined.json` bug class.
39
- */
40
- const REQUIRES_SPEC_ID = new Set([
41
- 'validation_completed',
42
- 'evaluation_completed',
43
- 'verify_acs_completed',
44
- 'gates_evaluated',
45
- 'spec_created',
46
- 'spec_updated',
47
- 'spec_closed',
48
- 'spec_archived',
49
- 'spec_deleted',
50
- 'spec_drift_detected',
51
- 'waiver_applied',
52
- ]);
53
-
54
- /**
55
- * Events that optionally carry a spec_id. These are allowed to omit it.
56
- * Any event not in REQUIRES_SPEC_ID and not in OPTIONAL_SPEC_ID is
57
- * treated as an unknown event type — appendEvent will still write it,
58
- * but it's recorded as-is without spec_id validation.
59
- */
60
- const OPTIONAL_SPEC_ID = new Set([
61
- 'session_started',
62
- 'session_ended',
63
- 'commit_made',
64
- 'branch_switched',
65
- 'worktree_created',
66
- 'worktree_merged',
67
- 'worktree_destroyed',
68
- ]);
69
-
70
- // ---------------------------------------------------------------------------
71
- // Helpers
72
- // ---------------------------------------------------------------------------
73
-
74
- /**
75
- * Resolve the absolute path to `.caws/events.jsonl` for a project root.
76
- * @param {string} projectRoot
77
- * @returns {string}
78
- */
79
- function getEventsPath(projectRoot) {
80
- return path.join(projectRoot, EVENTS_FILE);
81
- }
82
-
83
- /**
84
- * Canonicalize an event object for hashing. Keys are sorted alphabetically
85
- * and serialized with no whitespace, so two structurally-equivalent events
86
- * always produce the same hash regardless of key insertion order.
87
- *
88
- * This is a deliberate subset of RFC 8785 (JCS) — sufficient for our flat
89
- * event shape but not a full implementation.
90
- *
91
- * @param {object} obj
92
- * @returns {string}
93
- */
94
- function canonicalJson(obj) {
95
- if (obj === null) return 'null';
96
- if (typeof obj === 'number') {
97
- if (!Number.isFinite(obj)) {
98
- throw new Error(`canonicalJson: non-finite number ${obj}`);
99
- }
100
- return JSON.stringify(obj);
101
- }
102
- if (typeof obj === 'string') return JSON.stringify(obj);
103
- if (typeof obj === 'boolean') return obj ? 'true' : 'false';
104
- if (Array.isArray(obj)) {
105
- return '[' + obj.map(canonicalJson).join(',') + ']';
106
- }
107
- if (typeof obj === 'object') {
108
- const keys = Object.keys(obj).sort();
109
- const parts = keys.map((k) => JSON.stringify(k) + ':' + canonicalJson(obj[k]));
110
- return '{' + parts.join(',') + '}';
111
- }
112
- throw new Error(`canonicalJson: unsupported type ${typeof obj}`);
113
- }
114
-
115
- /**
116
- * Compute sha256 of the domain-separated canonical JSON of an event.
117
- * The `event_hash` field, if present on the input, is stripped before
118
- * hashing so the hash can be stored back on the event itself.
119
- *
120
- * @param {object} event
121
- * @returns {string} "sha256:<hex>"
122
- */
123
- function computeEventHash(event) {
124
- const withoutHash = { ...event };
125
- delete withoutHash.event_hash;
126
- const canonical = canonicalJson(withoutHash);
127
- const hash = crypto
128
- .createHash('sha256')
129
- .update(HASH_DOMAIN)
130
- .update('\x00')
131
- .update(canonical)
132
- .digest('hex');
133
- return `sha256:${hash}`;
134
- }
135
-
136
- /**
137
- * Sleep for a number of milliseconds. Used by the async lock retry loop.
138
- * @param {number} ms
139
- * @returns {Promise<void>}
140
- */
141
- function sleep(ms) {
142
- return new Promise((resolve) => { globalThis.setTimeout(resolve, ms); });
143
- }
144
-
145
- /**
146
- * Synchronously sleep for a number of milliseconds. Node has no built-in
147
- * sync sleep; `Atomics.wait` on a dummy Int32Array blocks the thread
148
- * without CPU burn and is the least-ugly cross-platform option.
149
- * Used by the sync lock retry loop for call sites that cannot await.
150
- * @param {number} ms
151
- */
152
- function sleepSync(ms) {
153
- const buf = new Int32Array(new SharedArrayBuffer(4));
154
- Atomics.wait(buf, 0, 0, ms);
155
- }
156
-
157
- /**
158
- * Acquire an exclusive lock on the events file by creating a sentinel
159
- * lockfile with the `wx` flag (fails atomically if the file already
160
- * exists). Retries with a short backoff.
161
- *
162
- * Returns an opaque handle that must be passed to releaseLock.
163
- *
164
- * @param {string} eventsPath
165
- * @returns {Promise<{lockPath: string, fd: number}>}
166
- */
167
- async function acquireLock(eventsPath) {
168
- const lockPath = eventsPath + LOCK_SUFFIX;
169
- const dir = path.dirname(eventsPath);
170
- if (!fs.existsSync(dir)) {
171
- fs.mkdirSync(dir, { recursive: true });
172
- }
173
-
174
- for (let attempt = 0; attempt < LOCK_RETRY_MAX; attempt++) {
175
- try {
176
- const fd = fs.openSync(lockPath, 'wx');
177
- // Write pid to the lock so stale locks are diagnosable.
178
- fs.writeSync(fd, String(process.pid));
179
- return { lockPath, fd };
180
- } catch (err) {
181
- if (err.code !== 'EEXIST') throw err;
182
- // Check for stale lock (>30s old) — clean it up so one crashed
183
- // writer doesn't block forever. This is still race-prone against
184
- // another writer that just grabbed it; we accept that risk because
185
- // the worst case is a rejected append, not corruption.
186
- try {
187
- const stat = fs.statSync(lockPath);
188
- if (Date.now() - stat.mtimeMs > 30_000) {
189
- fs.unlinkSync(lockPath);
190
- continue; // retry immediately without backoff
191
- }
192
- } catch {
193
- /* stat failed — file may have been released; retry */
194
- }
195
- await sleep(LOCK_RETRY_MS);
196
- }
197
- }
198
- throw new Error(
199
- `event-log: could not acquire lock on ${lockPath} after ${LOCK_RETRY_MAX * LOCK_RETRY_MS}ms — another writer may be stuck`
200
- );
201
- }
202
-
203
- /**
204
- * Synchronous lock acquirer. Same behavior as `acquireLock` but blocks
205
- * the thread via `sleepSync`. Intended for call sites that cannot await
206
- * (e.g. session-manager.startSession/endSession which are synchronous
207
- * for historical reasons).
208
- *
209
- * @param {string} eventsPath
210
- * @returns {{lockPath: string, fd: number}}
211
- */
212
- function acquireLockSync(eventsPath) {
213
- const lockPath = eventsPath + LOCK_SUFFIX;
214
- const dir = path.dirname(eventsPath);
215
- if (!fs.existsSync(dir)) {
216
- fs.mkdirSync(dir, { recursive: true });
217
- }
218
-
219
- for (let attempt = 0; attempt < LOCK_RETRY_MAX; attempt++) {
220
- try {
221
- const fd = fs.openSync(lockPath, 'wx');
222
- fs.writeSync(fd, String(process.pid));
223
- return { lockPath, fd };
224
- } catch (err) {
225
- if (err.code !== 'EEXIST') throw err;
226
- try {
227
- const stat = fs.statSync(lockPath);
228
- if (Date.now() - stat.mtimeMs > 30_000) {
229
- fs.unlinkSync(lockPath);
230
- continue;
231
- }
232
- } catch {
233
- /* stat failed — retry */
234
- }
235
- sleepSync(LOCK_RETRY_MS);
236
- }
237
- }
238
- throw new Error(
239
- `event-log: could not acquire lock on ${lockPath} after ${LOCK_RETRY_MAX * LOCK_RETRY_MS}ms — another writer may be stuck`
240
- );
241
- }
242
-
243
- /**
244
- * Release a lock acquired via acquireLock. Never throws; a failed release
245
- * is logged but not propagated, because the caller has already written.
246
- *
247
- * @param {{lockPath: string, fd: number}} handle
248
- */
249
- function releaseLock(handle) {
250
- try {
251
- fs.closeSync(handle.fd);
252
- } catch {
253
- /* close failure is non-fatal; the unlink below is the real release */
254
- }
255
- try {
256
- fs.unlinkSync(handle.lockPath);
257
- } catch (err) {
258
- if (err.code !== 'ENOENT') {
259
- // Surface unexpected release failures on stderr so they're diagnosable.
260
-
261
- console.error(`event-log: failed to release lock ${handle.lockPath}: ${err.message}`);
262
- }
263
- }
264
- }
265
-
266
- /**
267
- * Read the last non-empty line of a file without loading the whole file
268
- * into memory. Used to find the tail of the event log for seq/prev_hash
269
- * continuity.
270
- *
271
- * Returns `null` if the file does not exist or contains only whitespace.
272
- *
273
- * @param {string} filePath
274
- * @returns {string|null}
275
- */
276
- function readLastLine(filePath) {
277
- if (!fs.existsSync(filePath)) return null;
278
- const stat = fs.statSync(filePath);
279
- if (stat.size === 0) return null;
280
-
281
- // Read from the end in chunks until we have at least one complete line.
282
- const fd = fs.openSync(filePath, 'r');
283
- try {
284
- const chunkSize = 4096;
285
- let buffer = Buffer.alloc(0);
286
- let pos = stat.size;
287
- while (pos > 0) {
288
- const readSize = Math.min(chunkSize, pos);
289
- pos -= readSize;
290
- const chunk = Buffer.alloc(readSize);
291
- fs.readSync(fd, chunk, 0, readSize, pos);
292
- buffer = Buffer.concat([chunk, buffer]);
293
- const text = buffer.toString('utf8');
294
- const lines = text.split('\n').filter((l) => l.length > 0);
295
- if (lines.length >= 2 || pos === 0) {
296
- return lines[lines.length - 1] || null;
297
- }
298
- }
299
- return null;
300
- } finally {
301
- fs.closeSync(fd);
302
- }
303
- }
304
-
305
- // ---------------------------------------------------------------------------
306
- // Public API
307
- // ---------------------------------------------------------------------------
308
-
309
- /**
310
- * Append a single event to the project's event log.
311
- *
312
- * The event is stamped with a monotonic `seq`, an ISO-8601 `ts`, a
313
- * `prev_hash` linking it to the previous event, and an `event_hash`
314
- * computed over its canonical JSON (excluding the hash field itself).
315
- *
316
- * This function is **intentionally non-tolerant**:
317
- * - If `event` is an event type that requires `spec_id` and one is
318
- * missing, it throws. Do NOT wrap calls in `try { ... } catch {}`.
319
- * - If the lock cannot be acquired, it throws.
320
- * - If the last line of the file is malformed, it throws.
321
- *
322
- * Silent loss of provenance is the current failure mode of `.caws/state/`
323
- * and the whole point of this module is to reverse that default.
324
- *
325
- * @param {object} params
326
- * @param {string} params.actor — who emitted the event (cli, hook, session, agent, subagent-name)
327
- * @param {string} params.event — event type from the v0 vocabulary
328
- * @param {string} [params.spec_id] — required for spec-scoped events, optional otherwise
329
- * @param {object} [params.data] — event-type-specific payload
330
- * @param {object} [options]
331
- * @param {string} [options.projectRoot] — defaults to cwd
332
- * @param {string} [options.session_id] — session correlator; defaults to env CAWS_SESSION_ID or "standalone"
333
- * @returns {Promise<{seq: number, event_hash: string, prev_hash: string}>}
334
- */
335
- /**
336
- * Shared contract validation for both the async and sync append paths.
337
- * Throws on any violation. Returns a normalized descriptor the
338
- * file-writing helper consumes.
339
- *
340
- * @param {object} params
341
- * @param {object} options
342
- * @returns {{actor: string, event: string, spec_id: (string|undefined), data: (object|undefined), sessionId: string, eventsPath: string}}
343
- */
344
- function validateAppendParams(params, options) {
345
- const { actor, event, spec_id, data } = params || {};
346
- const projectRoot = options.projectRoot || process.cwd();
347
- const sessionId = options.session_id || process.env.CAWS_SESSION_ID || 'standalone';
348
-
349
- if (!actor || typeof actor !== 'string') {
350
- throw new Error('event-log.appendEvent: `actor` is required (non-empty string)');
351
- }
352
- if (!event || typeof event !== 'string') {
353
- throw new Error('event-log.appendEvent: `event` is required (non-empty string)');
354
- }
355
- if (REQUIRES_SPEC_ID.has(event)) {
356
- if (!spec_id || typeof spec_id !== 'string' || spec_id.trim() === '') {
357
- throw new Error(
358
- `event-log.appendEvent: event "${event}" requires a non-empty spec_id ` +
359
- `(got ${JSON.stringify(spec_id)}). This is the fence that prevents the ` +
360
- `.caws/state/undefined.json bug class — do not catch this error and continue.`
361
- );
362
- }
363
- }
364
-
365
- return {
366
- actor,
367
- event,
368
- spec_id,
369
- data,
370
- sessionId,
371
- eventsPath: getEventsPath(projectRoot),
372
- };
373
- }
374
-
375
- /**
376
- * Shared critical section: read tail, build event, write. Assumes the
377
- * caller already holds the lock. Returns the new event (with seq, hashes).
378
- *
379
- * @param {object} ctx — output of validateAppendParams
380
- * @returns {{seq: number, event_hash: string, prev_hash: string}}
381
- */
382
- function writeEventUnderLock(ctx) {
383
- const { actor, event, spec_id, data, sessionId, eventsPath } = ctx;
384
-
385
- const lastLine = readLastLine(eventsPath);
386
- let seq = 1;
387
- let prevHash = '';
388
- if (lastLine !== null) {
389
- let lastEvent;
390
- try {
391
- lastEvent = JSON.parse(lastLine);
392
- } catch (parseErr) {
393
- throw new Error(
394
- `event-log.appendEvent: last line of ${eventsPath} is malformed: ${parseErr.message}. ` +
395
- `The log is corrupt; manual inspection required before continuing.`
396
- );
397
- }
398
- if (typeof lastEvent.seq !== 'number' || !Number.isInteger(lastEvent.seq)) {
399
- throw new Error(
400
- `event-log.appendEvent: last event missing integer seq (got ${JSON.stringify(lastEvent.seq)})`
401
- );
402
- }
403
- seq = lastEvent.seq + 1;
404
- prevHash = typeof lastEvent.event_hash === 'string' ? lastEvent.event_hash : '';
405
- }
406
-
407
- const newEvent = {
408
- seq,
409
- ts: new Date().toISOString(),
410
- session_id: sessionId,
411
- actor,
412
- event,
413
- };
414
- if (spec_id !== undefined && spec_id !== null && spec_id !== '') {
415
- newEvent.spec_id = spec_id;
416
- }
417
- if (data !== undefined) {
418
- newEvent.data = data;
419
- }
420
- newEvent.prev_hash = prevHash;
421
- newEvent.event_hash = computeEventHash(newEvent);
422
-
423
- fs.appendFileSync(eventsPath, JSON.stringify(newEvent) + '\n', { encoding: 'utf8' });
424
-
425
- return {
426
- seq: newEvent.seq,
427
- event_hash: newEvent.event_hash,
428
- prev_hash: newEvent.prev_hash,
429
- };
430
- }
431
-
432
- async function appendEvent(params, options = {}) {
433
- const ctx = validateAppendParams(params, options);
434
- const handle = await acquireLock(ctx.eventsPath);
435
- try {
436
- return writeEventUnderLock(ctx);
437
- } finally {
438
- releaseLock(handle);
439
- }
440
- }
441
-
442
- /**
443
- * Synchronous variant of `appendEvent`. Same contract, same fail-loud
444
- * behavior. Intended for call sites that cannot await (synchronous
445
- * session manager functions, hooks, etc.). Blocks the thread during
446
- * lock contention via `Atomics.wait`.
447
- *
448
- * Prefer `appendEvent` in async contexts — it cooperates with the event
449
- * loop instead of blocking it.
450
- *
451
- * @param {object} params — same as appendEvent
452
- * @param {object} [options] — same as appendEvent
453
- * @returns {{seq: number, event_hash: string, prev_hash: string}}
454
- */
455
- function appendEventSync(params, options = {}) {
456
- const ctx = validateAppendParams(params, options);
457
- const handle = acquireLockSync(ctx.eventsPath);
458
- try {
459
- return writeEventUnderLock(ctx);
460
- } finally {
461
- releaseLock(handle);
462
- }
463
- }
464
-
465
- /**
466
- * Read all events from the project's event log, in seq order.
467
- *
468
- * Tolerates a partial trailing line (from a crashed writer) by discarding
469
- * it. Returns an array of parsed events. The caller is responsible for
470
- * filtering by spec_id or event type.
471
- *
472
- * This is intentionally eager (not a stream) in Phase 1 — the expected
473
- * event log size for CLI-scale projects is under 10k lines, well within
474
- * memory. A streaming reader is a future addition when compaction lands.
475
- *
476
- * @param {object} [options]
477
- * @param {string} [options.projectRoot] — defaults to cwd
478
- * @param {boolean} [options.strict] — if true, throw on any malformed line (default false: discard trailing partial)
479
- * @returns {object[]}
480
- */
481
- function readEvents(options = {}) {
482
- const projectRoot = options.projectRoot || process.cwd();
483
- const strict = options.strict === true;
484
- const eventsPath = getEventsPath(projectRoot);
485
-
486
- if (!fs.existsSync(eventsPath)) return [];
487
- const content = fs.readFileSync(eventsPath, 'utf8');
488
- if (content.length === 0) return [];
489
-
490
- const lines = content.split('\n');
491
- // The file ends in \n, so the split yields a trailing empty element.
492
- // Any other empty element is a malformed blank line.
493
- const events = [];
494
- for (let i = 0; i < lines.length; i++) {
495
- const line = lines[i];
496
- const isLast = i === lines.length - 1;
497
- if (line.length === 0) {
498
- if (isLast) continue; // normal trailing newline
499
- if (strict) {
500
- throw new Error(`event-log.readEvents: empty line at index ${i} (strict mode)`);
501
- }
502
- continue;
503
- }
504
- try {
505
- events.push(JSON.parse(line));
506
- } catch (err) {
507
- if (isLast) {
508
- // Partial trailing line from a crashed writer — tolerate unless strict.
509
- if (strict) {
510
- throw new Error(
511
- `event-log.readEvents: partial trailing line (strict mode): ${err.message}`
512
- );
513
- }
514
- // Drop it silently; the next append will overwrite it.
515
- continue;
516
- }
517
- throw new Error(
518
- `event-log.readEvents: malformed line at index ${i}: ${err.message}. ` +
519
- `The log is corrupt; manual inspection required.`
520
- );
521
- }
522
- }
523
- return events;
524
- }
525
-
526
- /**
527
- * Verify the hash chain of the event log end-to-end. Walks every event,
528
- * recomputes its event_hash, and asserts prev_hash matches the previous
529
- * event's event_hash.
530
- *
531
- * Intended for a future `caws events verify` command; exported here so
532
- * tests can use it to prove chain continuity.
533
- *
534
- * @param {object} [options]
535
- * @param {string} [options.projectRoot]
536
- * @returns {{ok: boolean, count: number, firstBadSeq?: number, reason?: string}}
537
- */
538
- function verifyChain(options = {}) {
539
- const events = readEvents({ ...options, strict: true });
540
- let prevHash = '';
541
- for (const event of events) {
542
- if (event.prev_hash !== prevHash) {
543
- return {
544
- ok: false,
545
- count: events.length,
546
- firstBadSeq: event.seq,
547
- reason: `prev_hash mismatch at seq ${event.seq}: expected ${JSON.stringify(prevHash)}, got ${JSON.stringify(event.prev_hash)}`,
548
- };
549
- }
550
- const recomputed = computeEventHash(event);
551
- if (recomputed !== event.event_hash) {
552
- return {
553
- ok: false,
554
- count: events.length,
555
- firstBadSeq: event.seq,
556
- reason: `event_hash mismatch at seq ${event.seq}: stored ${event.event_hash}, recomputed ${recomputed}`,
557
- };
558
- }
559
- prevHash = event.event_hash;
560
- }
561
- return { ok: true, count: events.length };
562
- }
563
-
564
- // ---------------------------------------------------------------------------
565
- // Exports
566
- // ---------------------------------------------------------------------------
567
-
568
- module.exports = {
569
- appendEvent,
570
- appendEventSync,
571
- readEvents,
572
- verifyChain,
573
-
574
- // Exposed for tests and the renderer; not part of the stable public API.
575
- _internal: {
576
- canonicalJson,
577
- computeEventHash,
578
- readLastLine,
579
- REQUIRES_SPEC_ID,
580
- OPTIONAL_SPEC_ID,
581
- HASH_DOMAIN,
582
- EVENTS_FILE,
583
- },
584
- };