@paths.design/caws-cli 10.1.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 (419) hide show
  1. package/README.md +125 -374
  2. package/dist/index.js +43 -756
  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/archive.js +0 -500
  183. package/dist/commands/burnup.js +0 -198
  184. package/dist/commands/diagnose.js +0 -525
  185. package/dist/commands/evaluate.js +0 -314
  186. package/dist/commands/gates.js +0 -149
  187. package/dist/commands/init.js +0 -857
  188. package/dist/commands/iterate.js +0 -417
  189. package/dist/commands/mode.js +0 -269
  190. package/dist/commands/parallel.js +0 -242
  191. package/dist/commands/plan.js +0 -438
  192. package/dist/commands/provenance.js +0 -1143
  193. package/dist/commands/quality-monitor.js +0 -284
  194. package/dist/commands/scope.js +0 -264
  195. package/dist/commands/session.js +0 -312
  196. package/dist/commands/sidecar.js +0 -74
  197. package/dist/commands/specs.js +0 -1448
  198. package/dist/commands/status.js +0 -1151
  199. package/dist/commands/templates.js +0 -237
  200. package/dist/commands/tool.js +0 -136
  201. package/dist/commands/tutorial.js +0 -480
  202. package/dist/commands/validate.js +0 -357
  203. package/dist/commands/verify-acs.js +0 -443
  204. package/dist/commands/waivers.js +0 -599
  205. package/dist/commands/workflow.js +0 -243
  206. package/dist/commands/worktree.js +0 -386
  207. package/dist/config/lite-scope.js +0 -158
  208. package/dist/config/modes.js +0 -347
  209. package/dist/constants/spec-types.js +0 -65
  210. package/dist/gates/budget-limit.js +0 -121
  211. package/dist/gates/feedback.js +0 -260
  212. package/dist/gates/format.js +0 -179
  213. package/dist/gates/god-object.js +0 -117
  214. package/dist/gates/pipeline.js +0 -167
  215. package/dist/gates/scope-boundary.js +0 -93
  216. package/dist/gates/spec-completeness.js +0 -109
  217. package/dist/gates/todo-detection.js +0 -205
  218. package/dist/generators/jest-config-generator.js +0 -242
  219. package/dist/generators/working-spec.js +0 -237
  220. package/dist/minimal-cli.js +0 -88
  221. package/dist/parallel/parallel-manager.js +0 -433
  222. package/dist/policy/PolicyManager.js +0 -465
  223. package/dist/scaffold/claude-hooks.js +0 -443
  224. package/dist/scaffold/cursor-hooks.js +0 -177
  225. package/dist/scaffold/git-hooks.js +0 -928
  226. package/dist/scaffold/index.js +0 -794
  227. package/dist/session/session-manager.js +0 -653
  228. package/dist/sidecars/index.js +0 -33
  229. package/dist/sidecars/listeners.js +0 -40
  230. package/dist/sidecars/provenance-summary.js +0 -238
  231. package/dist/sidecars/quality-gaps.js +0 -258
  232. package/dist/sidecars/schema.js +0 -149
  233. package/dist/sidecars/spec-drift.js +0 -151
  234. package/dist/sidecars/waiver-draft.js +0 -176
  235. package/dist/spec/SpecFileManager.js +0 -419
  236. package/dist/templates/.caws/schemas/policy.schema.json +0 -112
  237. package/dist/templates/.caws/schemas/scope.schema.json +0 -52
  238. package/dist/templates/.caws/schemas/waivers.schema.json +0 -106
  239. package/dist/templates/.caws/schemas/working-spec.schema.json +0 -340
  240. package/dist/templates/.caws/schemas/worktrees.schema.json +0 -38
  241. package/dist/templates/.caws/templates/working-spec.template.yml +0 -80
  242. package/dist/templates/.caws/tools/README.md +0 -18
  243. package/dist/templates/.caws/tools/scope-guard.js +0 -203
  244. package/dist/templates/.caws/tools-allow.json +0 -331
  245. package/dist/templates/.caws/waivers.yml +0 -19
  246. package/dist/templates/.claude/README.md +0 -190
  247. package/dist/templates/.claude/hooks/audit.sh +0 -121
  248. package/dist/templates/.claude/hooks/block-dangerous.sh +0 -203
  249. package/dist/templates/.claude/hooks/classify_command.py +0 -592
  250. package/dist/templates/.claude/hooks/doc-frontmatter-check.sh +0 -173
  251. package/dist/templates/.claude/hooks/lite-sprawl-check.sh +0 -145
  252. package/dist/templates/.claude/hooks/naming-check.sh +0 -100
  253. package/dist/templates/.claude/hooks/protected-paths.sh +0 -39
  254. package/dist/templates/.claude/hooks/quality-check.sh +0 -81
  255. package/dist/templates/.claude/hooks/scan-secrets.sh +0 -85
  256. package/dist/templates/.claude/hooks/scope-guard.sh +0 -381
  257. package/dist/templates/.claude/hooks/session-caws-status.sh +0 -117
  258. package/dist/templates/.claude/hooks/session-log.sh +0 -634
  259. package/dist/templates/.claude/hooks/simplification-guard.sh +0 -92
  260. package/dist/templates/.claude/hooks/stop-worktree-check.sh +0 -46
  261. package/dist/templates/.claude/hooks/test_classify_command.py +0 -370
  262. package/dist/templates/.claude/hooks/test_wrapper_smoke.sh +0 -96
  263. package/dist/templates/.claude/hooks/validate-spec.sh +0 -76
  264. package/dist/templates/.claude/hooks/worktree-guard.sh +0 -220
  265. package/dist/templates/.claude/hooks/worktree-write-guard.sh +0 -190
  266. package/dist/templates/.claude/rules/git-safety.md +0 -26
  267. package/dist/templates/.claude/rules/worktree-isolation.md +0 -83
  268. package/dist/templates/.claude/settings.json +0 -141
  269. package/dist/templates/.cursor/README.md +0 -299
  270. package/dist/templates/.cursor/hooks/audit.sh +0 -55
  271. package/dist/templates/.cursor/hooks/block-dangerous.sh +0 -84
  272. package/dist/templates/.cursor/hooks/caws-quality-check.sh +0 -52
  273. package/dist/templates/.cursor/hooks/caws-scope-guard.sh +0 -130
  274. package/dist/templates/.cursor/hooks/format.sh +0 -38
  275. package/dist/templates/.cursor/hooks/naming-check.sh +0 -64
  276. package/dist/templates/.cursor/hooks/scan-secrets.sh +0 -51
  277. package/dist/templates/.cursor/hooks/scope-guard.sh +0 -52
  278. package/dist/templates/.cursor/hooks/session-log.sh +0 -924
  279. package/dist/templates/.cursor/hooks/validate-spec.sh +0 -83
  280. package/dist/templates/.cursor/hooks.json +0 -76
  281. package/dist/templates/.cursor/rules/00-claims-verification.mdc +0 -144
  282. package/dist/templates/.cursor/rules/01-working-style.mdc +0 -50
  283. package/dist/templates/.cursor/rules/02-quality-gates.mdc +0 -368
  284. package/dist/templates/.cursor/rules/03-naming-and-refactor.mdc +0 -33
  285. package/dist/templates/.cursor/rules/04-logging-language-style.mdc +0 -23
  286. package/dist/templates/.cursor/rules/05-safe-defaults-guards.mdc +0 -23
  287. package/dist/templates/.cursor/rules/06-typescript-conventions.mdc +0 -36
  288. package/dist/templates/.cursor/rules/07-process-ops.mdc +0 -20
  289. package/dist/templates/.cursor/rules/08-solid-and-architecture.mdc +0 -16
  290. package/dist/templates/.cursor/rules/09-docstrings.mdc +0 -89
  291. package/dist/templates/.cursor/rules/10-documentation-quality-standards.mdc +0 -385
  292. package/dist/templates/.cursor/rules/11-scope-management-waivers.mdc +0 -381
  293. package/dist/templates/.cursor/rules/12-implementation-completeness.mdc +0 -516
  294. package/dist/templates/.cursor/rules/13-language-agnostic-standards.mdc +0 -578
  295. package/dist/templates/.cursor/rules/README.md +0 -148
  296. package/dist/templates/.github/copilot-instructions.md +0 -82
  297. package/dist/templates/.idea/runConfigurations/CAWS_Evaluate.xml +0 -5
  298. package/dist/templates/.idea/runConfigurations/CAWS_Validate.xml +0 -5
  299. package/dist/templates/.junie/guidelines.md +0 -73
  300. package/dist/templates/.vscode/launch.json +0 -17
  301. package/dist/templates/.vscode/settings.json +0 -95
  302. package/dist/templates/.windsurf/rules/caws-quality-standards.md +0 -54
  303. package/dist/templates/.windsurf/workflows/caws-guided-development.md +0 -92
  304. package/dist/templates/CLAUDE.md +0 -174
  305. package/dist/templates/COMMIT_CONVENTIONS.md +0 -86
  306. package/dist/templates/OIDC_SETUP.md +0 -300
  307. package/dist/templates/agents.md +0 -145
  308. package/dist/templates/codemod/README.md +0 -1
  309. package/dist/templates/codemod/test.js +0 -93
  310. package/dist/templates/docs/README.md +0 -151
  311. package/dist/templates/scripts/new_feature.sh +0 -80
  312. package/dist/templates/scripts/quality-gates/check-god-objects.js +0 -146
  313. package/dist/templates/scripts/quality-gates/run-quality-gates.js +0 -50
  314. package/dist/templates/scripts/v3/analysis/todo_analyzer.py +0 -1997
  315. package/dist/test-analysis.js +0 -786
  316. package/dist/tool-interface.js +0 -314
  317. package/dist/tool-loader.js +0 -303
  318. package/dist/tool-validator.js +0 -393
  319. package/dist/utils/agent-session.js +0 -202
  320. package/dist/utils/async-utils.js +0 -188
  321. package/dist/utils/command-wrapper.js +0 -200
  322. package/dist/utils/event-log.js +0 -584
  323. package/dist/utils/event-renderer.js +0 -521
  324. package/dist/utils/finalization.js +0 -230
  325. package/dist/utils/git-lock.js +0 -119
  326. package/dist/utils/gitignore-updater.js +0 -158
  327. package/dist/utils/ide-detection.js +0 -133
  328. package/dist/utils/lifecycle-events.js +0 -94
  329. package/dist/utils/project-analysis.js +0 -367
  330. package/dist/utils/promise-utils.js +0 -72
  331. package/dist/utils/quality-gates-errors.js +0 -520
  332. package/dist/utils/quality-gates-utils.js +0 -387
  333. package/dist/utils/schema-validator.js +0 -50
  334. package/dist/utils/spec-resolver.js +0 -711
  335. package/dist/utils/typescript-detector.js +0 -369
  336. package/dist/utils/working-state.js +0 -530
  337. package/dist/utils/yaml-validation.js +0 -156
  338. package/dist/validation/spec-validation.js +0 -921
  339. package/dist/waivers-manager.js +0 -732
  340. package/dist/worktree/worktree-manager.js +0 -1374
  341. package/templates/.caws/schemas/policy.schema.json +0 -112
  342. package/templates/.caws/schemas/scope.schema.json +0 -52
  343. package/templates/.caws/schemas/waivers.schema.json +0 -106
  344. package/templates/.caws/schemas/working-spec.schema.json +0 -340
  345. package/templates/.caws/schemas/worktrees.schema.json +0 -38
  346. package/templates/.caws/templates/working-spec.template.yml +0 -80
  347. package/templates/.caws/tools/README.md +0 -18
  348. package/templates/.caws/tools/scope-guard.js +0 -203
  349. package/templates/.caws/tools-allow.json +0 -331
  350. package/templates/.caws/waivers.yml +0 -19
  351. package/templates/.claude/README.md +0 -190
  352. package/templates/.claude/hooks/audit.sh +0 -121
  353. package/templates/.claude/hooks/block-dangerous.sh +0 -203
  354. package/templates/.claude/hooks/classify_command.py +0 -592
  355. package/templates/.claude/hooks/doc-frontmatter-check.sh +0 -173
  356. package/templates/.claude/hooks/lite-sprawl-check.sh +0 -145
  357. package/templates/.claude/hooks/naming-check.sh +0 -100
  358. package/templates/.claude/hooks/protected-paths.sh +0 -39
  359. package/templates/.claude/hooks/quality-check.sh +0 -81
  360. package/templates/.claude/hooks/scan-secrets.sh +0 -85
  361. package/templates/.claude/hooks/scope-guard.sh +0 -381
  362. package/templates/.claude/hooks/session-caws-status.sh +0 -117
  363. package/templates/.claude/hooks/session-log.sh +0 -634
  364. package/templates/.claude/hooks/simplification-guard.sh +0 -92
  365. package/templates/.claude/hooks/stop-worktree-check.sh +0 -46
  366. package/templates/.claude/hooks/test_classify_command.py +0 -370
  367. package/templates/.claude/hooks/test_wrapper_smoke.sh +0 -96
  368. package/templates/.claude/hooks/validate-spec.sh +0 -76
  369. package/templates/.claude/hooks/worktree-guard.sh +0 -220
  370. package/templates/.claude/hooks/worktree-write-guard.sh +0 -190
  371. package/templates/.claude/rules/git-safety.md +0 -26
  372. package/templates/.claude/rules/worktree-isolation.md +0 -83
  373. package/templates/.claude/settings.json +0 -141
  374. package/templates/.cursor/README.md +0 -299
  375. package/templates/.cursor/hooks/audit.sh +0 -55
  376. package/templates/.cursor/hooks/block-dangerous.sh +0 -84
  377. package/templates/.cursor/hooks/caws-quality-check.sh +0 -52
  378. package/templates/.cursor/hooks/caws-scope-guard.sh +0 -130
  379. package/templates/.cursor/hooks/format.sh +0 -38
  380. package/templates/.cursor/hooks/naming-check.sh +0 -64
  381. package/templates/.cursor/hooks/scan-secrets.sh +0 -51
  382. package/templates/.cursor/hooks/scope-guard.sh +0 -52
  383. package/templates/.cursor/hooks/session-log.sh +0 -924
  384. package/templates/.cursor/hooks/validate-spec.sh +0 -83
  385. package/templates/.cursor/hooks.json +0 -76
  386. package/templates/.cursor/rules/00-claims-verification.mdc +0 -144
  387. package/templates/.cursor/rules/01-working-style.mdc +0 -50
  388. package/templates/.cursor/rules/02-quality-gates.mdc +0 -368
  389. package/templates/.cursor/rules/03-naming-and-refactor.mdc +0 -33
  390. package/templates/.cursor/rules/04-logging-language-style.mdc +0 -23
  391. package/templates/.cursor/rules/05-safe-defaults-guards.mdc +0 -23
  392. package/templates/.cursor/rules/06-typescript-conventions.mdc +0 -36
  393. package/templates/.cursor/rules/07-process-ops.mdc +0 -20
  394. package/templates/.cursor/rules/08-solid-and-architecture.mdc +0 -16
  395. package/templates/.cursor/rules/09-docstrings.mdc +0 -89
  396. package/templates/.cursor/rules/10-documentation-quality-standards.mdc +0 -385
  397. package/templates/.cursor/rules/11-scope-management-waivers.mdc +0 -381
  398. package/templates/.cursor/rules/12-implementation-completeness.mdc +0 -516
  399. package/templates/.cursor/rules/13-language-agnostic-standards.mdc +0 -578
  400. package/templates/.cursor/rules/README.md +0 -148
  401. package/templates/.github/copilot-instructions.md +0 -82
  402. package/templates/.idea/runConfigurations/CAWS_Evaluate.xml +0 -5
  403. package/templates/.idea/runConfigurations/CAWS_Validate.xml +0 -5
  404. package/templates/.junie/guidelines.md +0 -73
  405. package/templates/.vscode/launch.json +0 -17
  406. package/templates/.vscode/settings.json +0 -95
  407. package/templates/.windsurf/rules/caws-quality-standards.md +0 -54
  408. package/templates/.windsurf/workflows/caws-guided-development.md +0 -92
  409. package/templates/CLAUDE.md +0 -174
  410. package/templates/COMMIT_CONVENTIONS.md +0 -86
  411. package/templates/OIDC_SETUP.md +0 -300
  412. package/templates/agents.md +0 -145
  413. package/templates/codemod/README.md +0 -1
  414. package/templates/codemod/test.js +0 -93
  415. package/templates/docs/README.md +0 -151
  416. package/templates/scripts/new_feature.sh +0 -80
  417. package/templates/scripts/quality-gates/check-god-objects.js +0 -146
  418. package/templates/scripts/quality-gates/run-quality-gates.js +0 -50
  419. 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()