@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,592 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- Command safety classifier for Claude Code PreToolUse hooks.
4
-
5
- Segments shell commands, parses them individually, and classifies each
6
- as allow / confirm / deny based on tiered policy.
7
-
8
- Output: JSON object with keys:
9
- decision: "allow" | "ask" | "deny"
10
- reason: human-readable explanation (empty string for allow)
11
-
12
- Usage:
13
- echo "$COMMAND" | python3 classify_command.py [--repo-root DIR] [--home DIR]
14
- """
15
-
16
- from __future__ import annotations
17
-
18
- import json
19
- import os
20
- import re
21
- import shlex
22
- import sys
23
- from pathlib import Path
24
-
25
-
26
- # ---------------------------------------------------------------------------
27
- # Configuration
28
- # ---------------------------------------------------------------------------
29
-
30
- # Paths that are safe targets for recursive deletion (relative to repo root).
31
- # After normalization, if the resolved path starts with one of these, allow.
32
- SAFE_DELETE_PREFIXES: list[str] = [
33
- "target/",
34
- "tmp/",
35
- ".pytest_cache/",
36
- "node_modules/",
37
- "__pycache__/",
38
- ]
39
-
40
- # Pipeline-aware deny patterns: matched against the FULL raw command string
41
- # BEFORE segmentation. These detect cross-pipeline dangers like curl|sh and
42
- # fork bombs whose syntax spans segment boundaries.
43
- DENY_PIPELINE_PATTERNS: list[tuple[str, str]] = [
44
- # Pipe-to-shell (network exfiltration) — must match across | boundary
45
- (r"\b(curl|wget)\b.*\|\s*(ba)?sh\b", "pipe-to-shell execution"),
46
- # Fork bombs — special syntax that segmentation mangles
47
- (r":\(\)\s*\{.*:\|:.*\}\s*;\s*:", "fork bomb"),
48
- (r"\bwhile\s+true\b.*\bfork\b", "fork loop"),
49
- ]
50
-
51
- # Segment-level regex patterns that are always hard-blocked.
52
- # These are matched against individual parsed command segments, NOT the raw
53
- # command string. Quoted literals in other segments will not trigger them.
54
- DENY_SEGMENT_PATTERNS: list[tuple[str, str]] = [
55
- # System destruction
56
- (r"\bdd\b.*\bif=/dev/(zero|random)\b", "dd with destructive input"),
57
- (r"\bmkfs\.", "filesystem format"),
58
- (r"\bfdisk\b", "disk partitioning"),
59
- (r">\s*/dev/sd", "raw device write"),
60
- # Permission escalation
61
- (r"\bchmod\b.*\+s\b", "setuid/setgid bit"),
62
- # System control
63
- (r"\b(shutdown|reboot)\b", "system shutdown/reboot"),
64
- (r"\binit\s+[06]\b", "system runlevel change"),
65
- ]
66
-
67
- # Segment-level regex patterns that require user confirmation.
68
- CONFIRM_SEGMENT_PATTERNS: list[tuple[str, str]] = [
69
- # Git destructive operations
70
- (r"\bgit\s+reset\s+--hard\b", "git reset --hard"),
71
- (r"\bgit\s+push\s+(-f\b|--force\b|--force-with-lease\b)", "git force push"),
72
- (r"\bgit\s+clean\s+-[a-zA-Z]*f", "git clean with force"),
73
- (r"\bgit\s+checkout\s+\.\s*$", "git checkout . (discard all changes)"),
74
- (r"\bgit\s+restore\s+\.\s*$", "git restore . (discard all changes)"),
75
- (r"\bgit\s+rebase\b", "git rebase (rewrites branch history)"),
76
- (r"\bgit\s+cherry-pick\b", "git cherry-pick (replays commits across branches)"),
77
- # chmod 777
78
- (r"\bchmod\b.*\b777\b", "chmod 777"),
79
- # History manipulation
80
- (r"\bhistory\s+-c\b", "history clear"),
81
- # sudo (not in allowed list)
82
- (r"^sudo\s+(?!npm|yarn|pnpm|brew|apt-get|apt|dnf|yum)", "sudo command"),
83
- # venv creation (sprawl prevention)
84
- (r"\bpython3?\s+-m\s+venv\b", "virtual environment creation"),
85
- (r"\bvirtualenv\s", "virtual environment creation"),
86
- (r"\bconda\s+create\b", "conda environment creation"),
87
- # git init (unless CAWS worktree context)
88
- (r"\bgit\s+init\b", "git init"),
89
- # Credential file reads
90
- (r"\bcat\b.*\.(env|ssh/|aws/)", "credential file read"),
91
- (r"\bcat\b.*/etc/(passwd|shadow)\b", "system credential read"),
92
- (r"\bcat\b.*(id_rsa|credentials)\b", "credential file read"),
93
- ]
94
-
95
-
96
- # ---------------------------------------------------------------------------
97
- # Command segmentation
98
- # ---------------------------------------------------------------------------
99
-
100
- def segment_command(raw: str) -> list[str]:
101
- """Split a shell command string on &&, ||, ;, | operators.
102
-
103
- Respects quoted strings so that e.g. git commit -m "rm -rf /" does not
104
- split inside the quotes. Returns individual command segments with
105
- leading/trailing whitespace stripped.
106
-
107
- This is intentionally conservative: if we cannot parse, we return
108
- the entire string as one segment so it still gets classified.
109
- """
110
- segments: list[str] = []
111
- current: list[str] = []
112
- i = 0
113
- in_single = False
114
- in_double = False
115
- in_heredoc: str | None = None
116
- heredoc_marker: str = ""
117
-
118
- while i < len(raw):
119
- ch = raw[i]
120
-
121
- # ---- heredoc detection ----
122
- # Look for <<EOF or <<'EOF' or <<"EOF" at segment level
123
- if not in_single and not in_double and in_heredoc is None:
124
- if raw[i:i+2] == "<<":
125
- # Extract the delimiter
126
- j = i + 2
127
- while j < len(raw) and raw[j] in (' ', '\t'):
128
- j += 1
129
- # Strip optional quotes around delimiter
130
- quote_char = None
131
- if j < len(raw) and raw[j] in ("'", '"'):
132
- quote_char = raw[j]
133
- j += 1
134
- k = j
135
- while k < len(raw) and raw[k] not in (' ', '\t', '\n', "'", '"', ')'):
136
- k += 1
137
- if k > j:
138
- heredoc_marker = raw[j:k]
139
- in_heredoc = heredoc_marker
140
- # Skip to end of this line
141
- nl = raw.find('\n', i)
142
- if nl >= 0:
143
- current.append(raw[i:nl+1])
144
- i = nl + 1
145
- else:
146
- current.append(raw[i:])
147
- i = len(raw)
148
- continue
149
-
150
- # ---- inside heredoc: scan for closing marker ----
151
- if in_heredoc is not None:
152
- nl = raw.find('\n', i)
153
- if nl < 0:
154
- # No newline found, rest is heredoc content
155
- current.append(raw[i:])
156
- i = len(raw)
157
- continue
158
- line = raw[i:nl]
159
- current.append(raw[i:nl+1])
160
- i = nl + 1
161
- if line.strip() == in_heredoc:
162
- in_heredoc = None
163
- continue
164
-
165
- # ---- quoting ----
166
- if ch == '\\' and not in_single:
167
- current.append(raw[i:i+2])
168
- i += 2
169
- continue
170
- if ch == "'" and not in_double:
171
- in_single = not in_single
172
- current.append(ch)
173
- i += 1
174
- continue
175
- if ch == '"' and not in_single:
176
- in_double = not in_double
177
- current.append(ch)
178
- i += 1
179
- continue
180
-
181
- # ---- segment separators (only outside quotes) ----
182
- if not in_single and not in_double:
183
- # && or ||
184
- if raw[i:i+2] in ('&&', '||'):
185
- seg = ''.join(current).strip()
186
- if seg:
187
- segments.append(seg)
188
- current = []
189
- i += 2
190
- continue
191
- # ; (but not ;;)
192
- if ch == ';' and (i + 1 >= len(raw) or raw[i+1] != ';'):
193
- seg = ''.join(current).strip()
194
- if seg:
195
- segments.append(seg)
196
- current = []
197
- i += 1
198
- continue
199
- # | (but not ||, already handled above)
200
- if ch == '|':
201
- seg = ''.join(current).strip()
202
- if seg:
203
- segments.append(seg)
204
- current = []
205
- i += 1
206
- continue
207
-
208
- current.append(ch)
209
- i += 1
210
-
211
- seg = ''.join(current).strip()
212
- if seg:
213
- segments.append(seg)
214
-
215
- return segments if segments else [raw.strip()]
216
-
217
-
218
- def strip_quotes(s: str) -> str:
219
- """Remove surrounding quotes from a shell token."""
220
- if len(s) >= 2:
221
- if (s[0] == '"' and s[-1] == '"') or (s[0] == "'" and s[-1] == "'"):
222
- return s[1:-1]
223
- return s
224
-
225
-
226
- def extract_command_word(segment: str) -> str:
227
- """Extract the first command word from a segment.
228
-
229
- Strips leading variable assignments (FOO=bar), env prefixes,
230
- and common wrappers like 'time'.
231
- """
232
- try:
233
- tokens = shlex.split(segment)
234
- except ValueError:
235
- # Malformed quoting — return raw first word
236
- return segment.split()[0] if segment.split() else ""
237
-
238
- for tok in tokens:
239
- # Skip variable assignments
240
- if '=' in tok and not tok.startswith('-'):
241
- continue
242
- # Skip common prefixes
243
- if tok in ('env', 'time', 'nice', 'nohup', 'command', 'builtin'):
244
- continue
245
- return tok
246
- return ""
247
-
248
-
249
- # ---------------------------------------------------------------------------
250
- # rm classifier
251
- # ---------------------------------------------------------------------------
252
-
253
- def is_recursive_rm(segment: str) -> tuple[bool, list[str]]:
254
- """Check if a segment is an rm command with recursive flags.
255
-
256
- Returns (is_recursive, [target_paths]).
257
- """
258
- try:
259
- tokens = shlex.split(segment)
260
- except ValueError:
261
- # Cannot parse — be conservative
262
- if re.search(r'\brm\b', segment) and re.search(r'-[a-zA-Z]*r', segment):
263
- return True, []
264
- return False, []
265
-
266
- if not tokens:
267
- return False, []
268
-
269
- # Find the rm command (skip env/time prefixes)
270
- rm_idx = -1
271
- for idx, tok in enumerate(tokens):
272
- if tok in ('env', 'time', 'nice', 'nohup', 'command', 'builtin'):
273
- continue
274
- if '=' in tok and not tok.startswith('-'):
275
- continue
276
- if tok == 'rm':
277
- rm_idx = idx
278
- break
279
-
280
- if rm_idx < 0:
281
- return False, []
282
-
283
- # Check for recursive flag
284
- is_recursive = False
285
- targets: list[str] = []
286
- i = rm_idx + 1
287
- while i < len(tokens):
288
- tok = tokens[i]
289
- if tok == '--':
290
- # Everything after -- is targets
291
- targets.extend(tokens[i+1:])
292
- break
293
- if tok.startswith('-') and not tok.startswith('--'):
294
- if 'r' in tok or 'R' in tok:
295
- is_recursive = True
296
- elif tok.startswith('--'):
297
- if tok == '--recursive':
298
- is_recursive = True
299
- # Other long options: skip
300
- else:
301
- targets.append(tok)
302
- i += 1
303
-
304
- return is_recursive, targets
305
-
306
-
307
- def classify_rm_target(
308
- target: str,
309
- repo_root: Path,
310
- home: Path,
311
- cwd: Path,
312
- ) -> tuple[str, str]:
313
- """Classify a single rm target path.
314
-
315
- Returns ("deny"|"ask"|"allow", reason).
316
- """
317
- # Resolve the target to an absolute path
318
- raw = target.strip()
319
- if not raw:
320
- return "deny", "empty target on recursive delete"
321
-
322
- # Handle glob-like patterns conservatively
323
- if any(c in raw for c in ('*', '?', '[', ']')):
324
- # Check if it is /* or ~/* which are catastrophic
325
- stripped = raw.rstrip('/')
326
- if stripped in ('/*', '~/*', './*'):
327
- return "deny", f"glob expansion at dangerous root: {raw}"
328
- # Other globs: confirm
329
- return "ask", f"recursive delete with glob pattern: {raw}"
330
-
331
- # Resolve path
332
- try:
333
- if raw.startswith('~'):
334
- resolved = (home / raw[2:]).resolve(strict=False) if len(raw) > 1 else home
335
- elif raw.startswith('/'):
336
- resolved = Path(raw).resolve(strict=False)
337
- else:
338
- resolved = (cwd / raw).resolve(strict=False)
339
- except (ValueError, OSError):
340
- return "ask", f"cannot resolve path: {raw}"
341
-
342
- resolved_str = str(resolved)
343
- repo_str = str(repo_root)
344
- home_str = str(home)
345
-
346
- # Hard-block: root, home, repo root
347
- if resolved_str == '/':
348
- return "deny", f"recursive delete targets filesystem root"
349
- if resolved_str == home_str:
350
- return "deny", f"recursive delete targets home directory"
351
- if resolved_str == repo_str:
352
- return "deny", f"recursive delete targets repository root"
353
-
354
- # Check if resolved path is a parent of repo or home (even worse)
355
- if repo_str.startswith(resolved_str + '/'):
356
- return "deny", f"recursive delete targets ancestor of repository: {raw}"
357
- if home_str.startswith(resolved_str + '/'):
358
- return "deny", f"recursive delete targets ancestor of home directory: {raw}"
359
-
360
- # Allow: known safe prefixes (relative to repo root)
361
- try:
362
- rel = resolved.relative_to(repo_root)
363
- rel_str = str(rel) + '/'
364
- for prefix in SAFE_DELETE_PREFIXES:
365
- if rel_str.startswith(prefix):
366
- return "allow", ""
367
- except ValueError:
368
- pass # Not inside repo root
369
-
370
- # Default: confirm
371
- return "ask", f"recursive delete: {raw}"
372
-
373
-
374
- def classify_find_delete(segment: str) -> tuple[str, str] | None:
375
- """Check if segment is a find command with -delete or -exec rm.
376
-
377
- Returns classification tuple or None if not a find-delete.
378
- """
379
- try:
380
- tokens = shlex.split(segment)
381
- except ValueError:
382
- return None
383
-
384
- cmd = extract_command_word(segment)
385
- if cmd != 'find':
386
- return None
387
-
388
- has_delete = '-delete' in tokens
389
- has_exec_rm = False
390
- for i, tok in enumerate(tokens):
391
- if tok == '-exec' and i + 1 < len(tokens) and 'rm' in tokens[i + 1]:
392
- has_exec_rm = True
393
- break
394
-
395
- if not has_delete and not has_exec_rm:
396
- return None
397
-
398
- return "ask", f"find with delete action"
399
-
400
-
401
- def strip_quoted_regions(raw: str) -> str:
402
- """Remove content inside single/double quotes and heredocs.
403
-
404
- Returns only the executable shell surface — quoted literals, heredoc
405
- bodies, and $(...) subshell content embedded in quotes are replaced
406
- with whitespace so that regex patterns only match actual commands.
407
- """
408
- result: list[str] = []
409
- i = 0
410
- in_single = False
411
- in_double = False
412
- in_heredoc: str | None = None
413
-
414
- while i < len(raw):
415
- ch = raw[i]
416
-
417
- # Heredoc detection (outside quotes)
418
- if not in_single and not in_double and in_heredoc is None:
419
- if raw[i:i+2] == "<<":
420
- j = i + 2
421
- while j < len(raw) and raw[j] in (' ', '\t'):
422
- j += 1
423
- if j < len(raw) and raw[j] in ("'", '"'):
424
- j += 1
425
- k = j
426
- while k < len(raw) and raw[k] not in (' ', '\t', '\n', "'", '"', ')'):
427
- k += 1
428
- if k > j:
429
- in_heredoc = raw[j:k]
430
- # Keep the << marker but skip to end of line
431
- result.append(raw[i:i+2])
432
- nl = raw.find('\n', i)
433
- if nl >= 0:
434
- i = nl + 1
435
- else:
436
- i = len(raw)
437
- continue
438
-
439
- # Inside heredoc: skip until closing marker
440
- if in_heredoc is not None:
441
- nl = raw.find('\n', i)
442
- if nl < 0:
443
- i = len(raw)
444
- continue
445
- line = raw[i:nl]
446
- i = nl + 1
447
- if line.strip() == in_heredoc:
448
- in_heredoc = None
449
- else:
450
- result.append(' ') # placeholder
451
- continue
452
-
453
- # Escape handling
454
- if ch == '\\' and not in_single:
455
- result.append(' ')
456
- i += 2
457
- continue
458
-
459
- # Quote tracking
460
- if ch == "'" and not in_double:
461
- if in_single:
462
- in_single = False
463
- else:
464
- in_single = True
465
- i += 1
466
- continue
467
- if ch == '"' and not in_single:
468
- if in_double:
469
- in_double = False
470
- else:
471
- in_double = True
472
- i += 1
473
- continue
474
-
475
- # Inside quotes: replace with space
476
- if in_single or in_double:
477
- result.append(' ')
478
- i += 1
479
- continue
480
-
481
- result.append(ch)
482
- i += 1
483
-
484
- return ''.join(result)
485
-
486
-
487
- # ---------------------------------------------------------------------------
488
- # Main classifier
489
- # ---------------------------------------------------------------------------
490
-
491
- def classify_command(
492
- raw_command: str,
493
- repo_root: Path,
494
- home: Path,
495
- cwd: Path,
496
- caws_worktree: bool = False,
497
- ) -> tuple[str, str]:
498
- """Classify a full command string.
499
-
500
- Returns the most restrictive (decision, reason) across all segments.
501
- Priority: deny > ask > allow.
502
- """
503
- worst_decision = "allow"
504
- worst_reason = ""
505
-
506
- def escalate(decision: str, reason: str) -> None:
507
- nonlocal worst_decision, worst_reason
508
- priority = {"allow": 0, "ask": 1, "deny": 2}
509
- if priority.get(decision, 0) > priority.get(worst_decision, 0):
510
- worst_decision = decision
511
- worst_reason = reason
512
-
513
- # --- Pipeline-aware deny patterns ---
514
- # Strip quoted regions so patterns only match executable shell surface.
515
- # This prevents commit messages, echo arguments, etc. from triggering.
516
- executable_surface = strip_quoted_regions(raw_command)
517
- for pattern, desc in DENY_PIPELINE_PATTERNS:
518
- if re.search(pattern, executable_surface, re.IGNORECASE):
519
- escalate("deny", desc)
520
-
521
- segments = segment_command(raw_command)
522
-
523
- for segment in segments:
524
- # Strip quoted regions for pattern matching so that e.g.
525
- # echo "git reset --hard" does not trigger the git pattern.
526
- # The original segment is still used for rm/find parsing
527
- # (shlex.split handles quotes correctly for argument extraction).
528
- segment_surface = strip_quoted_regions(segment)
529
-
530
- # --- Hard-block patterns (segment-level) ---
531
- for pattern, desc in DENY_SEGMENT_PATTERNS:
532
- if re.search(pattern, segment_surface, re.IGNORECASE):
533
- escalate("deny", desc)
534
-
535
- # --- Confirm patterns (segment-level) ---
536
- for pattern, desc in CONFIRM_SEGMENT_PATTERNS:
537
- if re.search(pattern, segment_surface, re.IGNORECASE):
538
- # Special case: git init in worktree context is allowed
539
- if "git init" in desc and caws_worktree:
540
- continue
541
- escalate("ask", desc)
542
-
543
- # --- rm classifier ---
544
- is_recursive, targets = is_recursive_rm(segment)
545
- if is_recursive:
546
- if not targets:
547
- # Cannot determine targets — be conservative
548
- escalate("ask", "recursive delete with unparseable targets")
549
- else:
550
- for target in targets:
551
- decision, reason = classify_rm_target(
552
- target, repo_root, home, cwd,
553
- )
554
- escalate(decision, reason)
555
-
556
- # --- find -delete classifier ---
557
- find_result = classify_find_delete(segment)
558
- if find_result:
559
- escalate(*find_result)
560
-
561
- return worst_decision, worst_reason
562
-
563
-
564
- # ---------------------------------------------------------------------------
565
- # Entry point
566
- # ---------------------------------------------------------------------------
567
-
568
- def main() -> None:
569
- import argparse
570
-
571
- parser = argparse.ArgumentParser(description="Classify shell command safety")
572
- parser.add_argument("--repo-root", default=os.environ.get("CLAUDE_PROJECT_DIR", "."))
573
- parser.add_argument("--home", default=str(Path.home()))
574
- parser.add_argument("--cwd", default=os.getcwd())
575
- args = parser.parse_args()
576
-
577
- raw_command = sys.stdin.read()
578
-
579
- repo_root = Path(args.repo_root).resolve(strict=False)
580
- home = Path(args.home).resolve(strict=False)
581
- cwd = Path(args.cwd).resolve(strict=False)
582
- caws_worktree = os.environ.get("CAWS_WORKTREE_CONTEXT", "0") == "1"
583
-
584
- decision, reason = classify_command(
585
- raw_command, repo_root, home, cwd, caws_worktree,
586
- )
587
-
588
- json.dump({"decision": decision, "reason": reason}, sys.stdout)
589
-
590
-
591
- if __name__ == "__main__":
592
- main()