@paths.design/caws-cli 9.3.2 → 10.0.1

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 (273) hide show
  1. package/README.md +58 -27
  2. package/dist/commands/archive.js +67 -28
  3. package/dist/commands/burnup.js +20 -11
  4. package/dist/commands/diagnose.js +34 -22
  5. package/dist/commands/evaluate.js +27 -15
  6. package/dist/commands/gates.js +122 -0
  7. package/dist/commands/init.js +143 -15
  8. package/dist/commands/iterate.js +77 -4
  9. package/dist/commands/parallel.js +4 -0
  10. package/dist/commands/plan.js +9 -19
  11. package/dist/commands/provenance.js +53 -17
  12. package/dist/commands/quality-monitor.js +64 -45
  13. package/dist/commands/sidecar.js +71 -0
  14. package/dist/commands/specs.js +233 -44
  15. package/dist/commands/status.js +113 -9
  16. package/dist/commands/tutorial.js +10 -9
  17. package/dist/commands/validate.js +49 -6
  18. package/dist/commands/verify-acs.js +35 -78
  19. package/dist/commands/waivers.js +69 -12
  20. package/dist/commands/worktree.js +50 -25
  21. package/dist/error-handler.js +2 -13
  22. package/dist/gates/budget-limit.js +116 -0
  23. package/dist/gates/feedback.js +260 -0
  24. package/dist/gates/format.js +179 -0
  25. package/dist/gates/god-object.js +117 -0
  26. package/dist/gates/pipeline.js +167 -0
  27. package/dist/gates/scope-boundary.js +93 -0
  28. package/dist/gates/spec-completeness.js +102 -0
  29. package/dist/gates/todo-detection.js +205 -0
  30. package/dist/index.js +130 -151
  31. package/dist/parallel/parallel-manager.js +3 -3
  32. package/dist/policy/PolicyManager.js +42 -10
  33. package/dist/scaffold/claude-hooks.js +24 -1
  34. package/dist/scaffold/git-hooks.js +45 -102
  35. package/dist/scaffold/index.js +4 -3
  36. package/dist/session/session-manager.js +71 -14
  37. package/dist/sidecars/index.js +33 -0
  38. package/dist/sidecars/listeners.js +40 -0
  39. package/dist/sidecars/provenance-summary.js +238 -0
  40. package/dist/sidecars/quality-gaps.js +258 -0
  41. package/dist/sidecars/schema.js +149 -0
  42. package/dist/sidecars/spec-drift.js +151 -0
  43. package/dist/sidecars/waiver-draft.js +176 -0
  44. package/dist/templates/.caws/schemas/policy.schema.json +50 -0
  45. package/dist/templates/.caws/schemas/waivers.schema.json +30 -24
  46. package/dist/templates/.caws/schemas/working-spec.schema.json +51 -8
  47. package/dist/templates/.caws/schemas/worktrees.schema.json +3 -1
  48. package/dist/templates/.caws/templates/working-spec.template.yml +7 -3
  49. package/dist/templates/.claude/hooks/audit.sh +0 -0
  50. package/dist/templates/.claude/hooks/block-dangerous.sh +52 -11
  51. package/dist/templates/.claude/hooks/classify_command.py +592 -0
  52. package/dist/templates/.claude/hooks/doc-frontmatter-check.sh +173 -0
  53. package/dist/templates/.claude/hooks/quality-check.sh +23 -10
  54. package/dist/templates/.claude/hooks/scope-guard.sh +34 -32
  55. package/dist/templates/.claude/hooks/session-caws-status.sh +2 -2
  56. package/dist/templates/.claude/hooks/session-log.sh +76 -3
  57. package/dist/templates/.claude/hooks/stop-worktree-check.sh +1 -1
  58. package/dist/templates/.claude/hooks/test_classify_command.py +370 -0
  59. package/dist/templates/.claude/hooks/test_wrapper_smoke.sh +96 -0
  60. package/dist/templates/.claude/hooks/worktree-guard.sh +2 -2
  61. package/dist/templates/.claude/hooks/worktree-write-guard.sh +1 -1
  62. package/dist/templates/.claude/settings.json +26 -0
  63. package/dist/templates/.cursor/hooks/caws-quality-check.sh +4 -4
  64. package/dist/templates/.cursor/hooks/caws-scope-guard.sh +1 -1
  65. package/dist/templates/.cursor/hooks/session-log.sh +924 -0
  66. package/dist/templates/.cursor/hooks.json +25 -0
  67. package/dist/templates/.cursor/rules/02-quality-gates.mdc +3 -5
  68. package/dist/templates/.cursor/rules/10-documentation-quality-standards.mdc +6 -11
  69. package/dist/templates/.cursor/rules/11-scope-management-waivers.mdc +14 -18
  70. package/dist/templates/.cursor/rules/12-implementation-completeness.mdc +4 -4
  71. package/dist/templates/.cursor/rules/13-language-agnostic-standards.mdc +3 -13
  72. package/dist/templates/.github/copilot-instructions.md +5 -5
  73. package/dist/templates/.idea/runConfigurations/CAWS_Evaluate.xml +1 -1
  74. package/dist/templates/.junie/guidelines.md +2 -2
  75. package/dist/templates/.vscode/settings.json +3 -1
  76. package/dist/templates/.windsurf/rules/caws-quality-standards.md +2 -2
  77. package/dist/templates/.windsurf/workflows/caws-guided-development.md +3 -3
  78. package/dist/templates/CLAUDE.md +43 -8
  79. package/dist/templates/agents.md +29 -9
  80. package/dist/templates/docs/README.md +8 -7
  81. package/dist/templates/scripts/new_feature.sh +80 -0
  82. package/dist/test-analysis.js +43 -30
  83. package/dist/tool-loader.js +1 -1
  84. package/dist/utils/agent-session.js +202 -0
  85. package/dist/utils/detection.js +8 -2
  86. package/dist/utils/finalization.js +7 -6
  87. package/dist/utils/gitignore-updater.js +3 -0
  88. package/dist/utils/lifecycle-events.js +94 -0
  89. package/dist/utils/quality-gates-utils.js +29 -44
  90. package/dist/utils/schema-validator.js +42 -0
  91. package/dist/utils/spec-resolver.js +93 -21
  92. package/dist/utils/working-state.js +505 -0
  93. package/dist/validation/spec-validation.js +92 -22
  94. package/dist/waivers-manager.js +60 -6
  95. package/dist/worktree/worktree-manager.js +390 -93
  96. package/package.json +6 -6
  97. package/templates/.caws/schemas/policy.schema.json +50 -0
  98. package/templates/.caws/schemas/waivers.schema.json +30 -24
  99. package/templates/.caws/schemas/working-spec.schema.json +51 -8
  100. package/templates/.caws/schemas/worktrees.schema.json +3 -1
  101. package/templates/.caws/templates/working-spec.template.yml +7 -3
  102. package/templates/.claude/hooks/block-dangerous.sh +52 -11
  103. package/templates/.claude/hooks/classify_command.py +592 -0
  104. package/templates/.claude/hooks/doc-frontmatter-check.sh +173 -0
  105. package/templates/.claude/hooks/quality-check.sh +23 -10
  106. package/templates/.claude/hooks/scope-guard.sh +34 -32
  107. package/templates/.claude/hooks/session-caws-status.sh +2 -2
  108. package/templates/.claude/hooks/session-log.sh +76 -3
  109. package/templates/.claude/hooks/stop-worktree-check.sh +1 -1
  110. package/templates/.claude/hooks/test_classify_command.py +370 -0
  111. package/templates/.claude/hooks/test_wrapper_smoke.sh +96 -0
  112. package/templates/.claude/hooks/worktree-guard.sh +2 -2
  113. package/templates/.claude/hooks/worktree-write-guard.sh +1 -1
  114. package/templates/.claude/settings.json +26 -0
  115. package/templates/.cursor/hooks/caws-quality-check.sh +4 -4
  116. package/templates/.cursor/hooks/caws-scope-guard.sh +1 -1
  117. package/templates/.cursor/hooks/session-log.sh +924 -0
  118. package/templates/.cursor/hooks.json +25 -0
  119. package/templates/.cursor/rules/02-quality-gates.mdc +3 -5
  120. package/templates/.cursor/rules/10-documentation-quality-standards.mdc +6 -11
  121. package/templates/.cursor/rules/11-scope-management-waivers.mdc +14 -18
  122. package/templates/.cursor/rules/12-implementation-completeness.mdc +4 -4
  123. package/templates/.cursor/rules/13-language-agnostic-standards.mdc +3 -13
  124. package/templates/.github/copilot-instructions.md +5 -5
  125. package/templates/.idea/runConfigurations/CAWS_Evaluate.xml +1 -1
  126. package/templates/.junie/guidelines.md +2 -2
  127. package/templates/.vscode/settings.json +3 -1
  128. package/templates/.windsurf/rules/caws-quality-standards.md +2 -2
  129. package/templates/.windsurf/workflows/caws-guided-development.md +3 -3
  130. package/templates/CLAUDE.md +43 -8
  131. package/templates/{AGENTS.md → agents.md} +29 -9
  132. package/templates/docs/README.md +8 -7
  133. package/templates/scripts/new_feature.sh +80 -0
  134. package/dist/budget-derivation.d.ts +0 -74
  135. package/dist/budget-derivation.d.ts.map +0 -1
  136. package/dist/cicd-optimizer.d.ts +0 -142
  137. package/dist/cicd-optimizer.d.ts.map +0 -1
  138. package/dist/commands/archive.d.ts +0 -51
  139. package/dist/commands/archive.d.ts.map +0 -1
  140. package/dist/commands/burnup.d.ts +0 -6
  141. package/dist/commands/burnup.d.ts.map +0 -1
  142. package/dist/commands/diagnose.d.ts +0 -52
  143. package/dist/commands/diagnose.d.ts.map +0 -1
  144. package/dist/commands/evaluate.d.ts +0 -8
  145. package/dist/commands/evaluate.d.ts.map +0 -1
  146. package/dist/commands/init.d.ts +0 -5
  147. package/dist/commands/init.d.ts.map +0 -1
  148. package/dist/commands/iterate.d.ts +0 -8
  149. package/dist/commands/iterate.d.ts.map +0 -1
  150. package/dist/commands/mode.d.ts +0 -25
  151. package/dist/commands/mode.d.ts.map +0 -1
  152. package/dist/commands/parallel.d.ts +0 -7
  153. package/dist/commands/parallel.d.ts.map +0 -1
  154. package/dist/commands/plan.d.ts +0 -49
  155. package/dist/commands/plan.d.ts.map +0 -1
  156. package/dist/commands/provenance.d.ts +0 -32
  157. package/dist/commands/provenance.d.ts.map +0 -1
  158. package/dist/commands/quality-gates.d.ts +0 -6
  159. package/dist/commands/quality-gates.d.ts.map +0 -1
  160. package/dist/commands/quality-gates.js +0 -444
  161. package/dist/commands/quality-monitor.d.ts +0 -17
  162. package/dist/commands/quality-monitor.d.ts.map +0 -1
  163. package/dist/commands/session.d.ts +0 -7
  164. package/dist/commands/session.d.ts.map +0 -1
  165. package/dist/commands/specs.d.ts +0 -77
  166. package/dist/commands/specs.d.ts.map +0 -1
  167. package/dist/commands/status.d.ts +0 -44
  168. package/dist/commands/status.d.ts.map +0 -1
  169. package/dist/commands/templates.d.ts +0 -74
  170. package/dist/commands/templates.d.ts.map +0 -1
  171. package/dist/commands/tool.d.ts +0 -13
  172. package/dist/commands/tool.d.ts.map +0 -1
  173. package/dist/commands/troubleshoot.d.ts +0 -8
  174. package/dist/commands/troubleshoot.d.ts.map +0 -1
  175. package/dist/commands/troubleshoot.js +0 -104
  176. package/dist/commands/tutorial.d.ts +0 -55
  177. package/dist/commands/tutorial.d.ts.map +0 -1
  178. package/dist/commands/validate.d.ts +0 -15
  179. package/dist/commands/validate.d.ts.map +0 -1
  180. package/dist/commands/waivers.d.ts +0 -8
  181. package/dist/commands/waivers.d.ts.map +0 -1
  182. package/dist/commands/workflow.d.ts +0 -85
  183. package/dist/commands/workflow.d.ts.map +0 -1
  184. package/dist/commands/worktree.d.ts +0 -7
  185. package/dist/commands/worktree.d.ts.map +0 -1
  186. package/dist/config/index.d.ts +0 -29
  187. package/dist/config/index.d.ts.map +0 -1
  188. package/dist/config/lite-scope.d.ts +0 -33
  189. package/dist/config/lite-scope.d.ts.map +0 -1
  190. package/dist/config/modes.d.ts +0 -264
  191. package/dist/config/modes.d.ts.map +0 -1
  192. package/dist/constants/spec-types.d.ts +0 -93
  193. package/dist/constants/spec-types.d.ts.map +0 -1
  194. package/dist/error-handler.d.ts +0 -151
  195. package/dist/error-handler.d.ts.map +0 -1
  196. package/dist/generators/jest-config-generator.d.ts +0 -32
  197. package/dist/generators/jest-config-generator.d.ts.map +0 -1
  198. package/dist/generators/jest-config.d.ts +0 -32
  199. package/dist/generators/jest-config.d.ts.map +0 -1
  200. package/dist/generators/jest-config.js +0 -242
  201. package/dist/generators/working-spec.d.ts +0 -13
  202. package/dist/generators/working-spec.d.ts.map +0 -1
  203. package/dist/index-new.d.ts +0 -5
  204. package/dist/index-new.d.ts.map +0 -1
  205. package/dist/index-new.js +0 -317
  206. package/dist/index.d.ts +0 -5
  207. package/dist/index.d.ts.map +0 -1
  208. package/dist/index.js.backup +0 -4711
  209. package/dist/minimal-cli.d.ts +0 -3
  210. package/dist/minimal-cli.d.ts.map +0 -1
  211. package/dist/parallel/parallel-manager.d.ts +0 -67
  212. package/dist/parallel/parallel-manager.d.ts.map +0 -1
  213. package/dist/policy/PolicyManager.d.ts +0 -104
  214. package/dist/policy/PolicyManager.d.ts.map +0 -1
  215. package/dist/scaffold/claude-hooks.d.ts +0 -28
  216. package/dist/scaffold/claude-hooks.d.ts.map +0 -1
  217. package/dist/scaffold/cursor-hooks.d.ts +0 -7
  218. package/dist/scaffold/cursor-hooks.d.ts.map +0 -1
  219. package/dist/scaffold/git-hooks.d.ts +0 -38
  220. package/dist/scaffold/git-hooks.d.ts.map +0 -1
  221. package/dist/scaffold/index.d.ts +0 -17
  222. package/dist/scaffold/index.d.ts.map +0 -1
  223. package/dist/session/session-manager.d.ts +0 -94
  224. package/dist/session/session-manager.d.ts.map +0 -1
  225. package/dist/spec/SpecFileManager.d.ts +0 -146
  226. package/dist/spec/SpecFileManager.d.ts.map +0 -1
  227. package/dist/templates/.cursor/hooks/caws-tool-validation.sh +0 -121
  228. package/dist/templates/.github/copilot/instructions.md +0 -311
  229. package/dist/test-analysis.d.ts +0 -231
  230. package/dist/test-analysis.d.ts.map +0 -1
  231. package/dist/tool-interface.d.ts +0 -236
  232. package/dist/tool-interface.d.ts.map +0 -1
  233. package/dist/tool-loader.d.ts +0 -77
  234. package/dist/tool-loader.d.ts.map +0 -1
  235. package/dist/tool-validator.d.ts +0 -72
  236. package/dist/tool-validator.d.ts.map +0 -1
  237. package/dist/utils/async-utils.d.ts +0 -73
  238. package/dist/utils/async-utils.d.ts.map +0 -1
  239. package/dist/utils/command-wrapper.d.ts +0 -66
  240. package/dist/utils/command-wrapper.d.ts.map +0 -1
  241. package/dist/utils/detection.d.ts +0 -14
  242. package/dist/utils/detection.d.ts.map +0 -1
  243. package/dist/utils/error-categories.d.ts +0 -52
  244. package/dist/utils/error-categories.d.ts.map +0 -1
  245. package/dist/utils/finalization.d.ts +0 -17
  246. package/dist/utils/finalization.d.ts.map +0 -1
  247. package/dist/utils/git-lock.d.ts +0 -13
  248. package/dist/utils/git-lock.d.ts.map +0 -1
  249. package/dist/utils/gitignore-updater.d.ts +0 -39
  250. package/dist/utils/gitignore-updater.d.ts.map +0 -1
  251. package/dist/utils/ide-detection.d.ts +0 -89
  252. package/dist/utils/ide-detection.d.ts.map +0 -1
  253. package/dist/utils/project-analysis.d.ts +0 -34
  254. package/dist/utils/project-analysis.d.ts.map +0 -1
  255. package/dist/utils/promise-utils.d.ts +0 -30
  256. package/dist/utils/promise-utils.d.ts.map +0 -1
  257. package/dist/utils/quality-gates-utils.d.ts +0 -49
  258. package/dist/utils/quality-gates-utils.d.ts.map +0 -1
  259. package/dist/utils/quality-gates.d.ts +0 -49
  260. package/dist/utils/quality-gates.d.ts.map +0 -1
  261. package/dist/utils/quality-gates.js +0 -402
  262. package/dist/utils/spec-resolver.d.ts +0 -80
  263. package/dist/utils/spec-resolver.d.ts.map +0 -1
  264. package/dist/utils/typescript-detector.d.ts +0 -66
  265. package/dist/utils/typescript-detector.d.ts.map +0 -1
  266. package/dist/utils/yaml-validation.d.ts +0 -32
  267. package/dist/utils/yaml-validation.d.ts.map +0 -1
  268. package/dist/validation/spec-validation.d.ts +0 -43
  269. package/dist/validation/spec-validation.d.ts.map +0 -1
  270. package/dist/waivers-manager.d.ts +0 -167
  271. package/dist/waivers-manager.d.ts.map +0 -1
  272. package/dist/worktree/worktree-manager.d.ts +0 -54
  273. package/dist/worktree/worktree-manager.d.ts.map +0 -1
package/README.md CHANGED
@@ -12,8 +12,8 @@ The CAWS CLI serves as the central control point for:
12
12
  - **Quality Validation**: Run comprehensive validation against working specifications
13
13
  - **Agent Integration**: Programmatic APIs for AI agents to evaluate and guide development
14
14
  - **Waiver Management**: Fast-lane escape hatches with full audit trails
15
- - **CI/CD Optimization**: Pipeline generation and optimization tools
16
- - **Experimental Features**: Dry-run capabilities for experimental functionality
15
+ - **Quality Gates**: v2 pipeline with configurable gate modules
16
+ - **Session Management**: Track and manage agent work sessions
17
17
 
18
18
  ## Installation
19
19
 
@@ -86,40 +86,69 @@ caws waivers list
86
86
  caws waivers revoke WV-0001
87
87
  ```
88
88
 
89
- ### CI/CD Optimization
89
+ ### Quality Gates
90
90
 
91
91
  ```bash
92
- # Analyze project for CI/CD optimizations
93
- caws cicd analyze
92
+ # Run quality gates v2 pipeline
93
+ caws gates run
94
94
 
95
- # Generate optimized GitHub Actions workflow
96
- caws cicd generate github --output .github/workflows/caws-gates.yml
95
+ # Run legacy quality gates
96
+ caws quality-gates
97
+ ```
98
+
99
+ ### Worktree Management
100
+
101
+ ```bash
102
+ # Create an isolated worktree for parallel agent work
103
+ caws worktree create <name>
104
+
105
+ # List active worktrees
106
+ caws worktree list
97
107
 
98
- # Smart test selection based on changes
99
- caws cicd test-selection --from-commit HEAD~1
108
+ # Merge a completed worktree back to base
109
+ caws worktree merge <name>
110
+
111
+ # Destroy a worktree
112
+ caws worktree destroy <name>
100
113
  ```
101
114
 
102
- ### Experimental Features
115
+ ### Session Management
103
116
 
104
117
  ```bash
105
- # Dry-run validation without side effects
106
- caws experimental --dry-run validate .caws/working-spec.yaml
118
+ # Start a tracked session
119
+ caws session start
120
+
121
+ # Create a session checkpoint
122
+ caws session checkpoint
107
123
 
108
- # Experimental quality gates
109
- caws experimental quality-gates .caws/working-spec.yaml --parallel-execution
124
+ # End a session
125
+ caws session end
126
+
127
+ # List past sessions
128
+ caws session list
110
129
  ```
111
130
 
112
- ### Tool Management
131
+ ### Spec Management
113
132
 
114
133
  ```bash
115
- # List available CAWS tools
116
- caws tools list
134
+ # List all specs (project + feature)
135
+ caws specs list
136
+
137
+ # Create a feature spec
138
+ caws specs create FEAT-001 --type feature --title "description"
139
+
140
+ # Show a spec
141
+ caws specs show FEAT-001
142
+
143
+ # Check for scope conflicts between specs
144
+ caws specs conflicts
145
+ ```
117
146
 
118
- # Execute specific tool
119
- caws tools run validate
147
+ ### Tool Management
120
148
 
121
- # Manage tool configurations
122
- caws tools --help
149
+ ```bash
150
+ # Run the CAWS tool interface
151
+ caws tool
123
152
  ```
124
153
 
125
154
  ## Architecture
@@ -131,7 +160,7 @@ caws-cli/
131
160
  ├── src/
132
161
  │ ├── index.js # Main CLI entry point
133
162
  │ ├── waivers-manager.js # Waiver system implementation
134
- │ ├── cicd-optimizer.js # CI/CD optimization logic
163
+ │ ├── quality-gates/ # v2 gate modules
135
164
  │ └── tool-loader.js # Dynamic tool loading system
136
165
  ├── templates/ # Project templates
137
166
  └── dist/ # Compiled output
@@ -142,7 +171,7 @@ caws-cli/
142
171
  - **Command Parser**: Commander.js-based CLI with subcommands
143
172
  - **Tool System**: Dynamic loading of quality gate tools
144
173
  - **Waiver Manager**: Fast-lane escape hatch management
145
- - **CI/CD Optimizer**: Pipeline analysis and generation
174
+ - **Quality Gates v2**: Modular gate pipeline with configurable modules
146
175
  - **Agent Interface**: JSON APIs for programmatic agent integration
147
176
 
148
177
  ## Integration with CAWS Ecosystem
@@ -168,14 +197,16 @@ caws-cli/
168
197
 
169
198
  ### Quality Gates Integration
170
199
 
171
- The CLI automatically executes quality gates defined in the template:
200
+ The v2 quality gates pipeline (`caws gates run`) executes modular gate checks:
172
201
 
173
- 1. **Spec Validation**: Validates working specifications against schema
202
+ 1. **Spec Validation**: Validates working specifications against schema (mode, blast_radius, rollback SLO)
174
203
  2. **Security Scanning**: Runs security checks and secret detection
175
- 3. **Code Quality**: Executes linting, type checking, and formatting
176
- 4. **Test Execution**: Runs unit, integration, and contract tests
204
+ 3. **Scope Enforcement**: Verifies changes stay within spec-defined boundaries
205
+ 4. **Test & Coverage**: Runs tests and validates coverage thresholds per risk tier
177
206
  5. **Performance Checks**: Validates performance budgets and metrics
178
207
 
208
+ Gates can be configured per-spec with `mode` (block/warn/skip) and custom `thresholds` in policy.yaml.
209
+
179
210
  ### Agent Workflow Integration
180
211
 
181
212
  The CLI provides structured APIs for agents:
@@ -10,6 +10,7 @@ const yaml = require('js-yaml');
10
10
  const chalk = require('chalk');
11
11
  const { execSync } = require('child_process');
12
12
  const { safeAsync, outputResult } = require('../error-handler');
13
+ const { findProjectRoot } = require('../utils/detection');
13
14
 
14
15
  // Import spec resolution system
15
16
  const { resolveSpec } = require('../utils/spec-resolver');
@@ -20,7 +21,8 @@ const { resolveSpec } = require('../utils/spec-resolver');
20
21
  * @returns {Promise<Object|null>} Change data or null
21
22
  */
22
23
  async function loadChange(changeId) {
23
- const changesDir = '.caws/changes';
24
+ const projectRoot = findProjectRoot();
25
+ const changesDir = path.join(projectRoot, '.caws/changes');
24
26
  const changePath = path.join(changesDir, changeId);
25
27
 
26
28
  if (!(await fs.pathExists(changePath))) {
@@ -44,10 +46,11 @@ async function loadChange(changeId) {
44
46
  path: changePath,
45
47
  metadata,
46
48
  workingSpec,
49
+ workingSpecPath: (await fs.pathExists(workingSpecPath)) ? workingSpecPath : null,
47
50
  exists: true,
48
51
  };
49
52
  } catch (error) {
50
- return null;
53
+ throw new Error(`Failed to load change '${changeId}': ${error.message}`);
51
54
  }
52
55
  }
53
56
 
@@ -57,18 +60,24 @@ async function loadChange(changeId) {
57
60
  * @returns {Promise<Object>} Validation result
58
61
  */
59
62
  async function validateAcceptanceCriteria(workingSpec) {
60
- if (!workingSpec || !workingSpec.acceptance_criteria) {
63
+ const criteria = Array.isArray(workingSpec?.acceptance_criteria)
64
+ ? workingSpec.acceptance_criteria
65
+ : Array.isArray(workingSpec?.acceptance)
66
+ ? workingSpec.acceptance
67
+ : [];
68
+
69
+ if (!workingSpec || criteria.length === 0) {
61
70
  return {
62
71
  valid: false,
63
72
  message: 'No acceptance criteria found in working spec',
64
73
  };
65
74
  }
66
75
 
67
- const criteria = workingSpec.acceptance_criteria;
76
+ const hasCompletionTracking = criteria.some((criterion) => criterion.completed !== undefined);
68
77
  const incomplete = [];
69
78
 
70
79
  for (const criterion of criteria) {
71
- if (!criterion.completed) {
80
+ if (criterion.completed === false) {
72
81
  incomplete.push(criterion.id || 'unknown');
73
82
  }
74
83
  }
@@ -80,6 +89,13 @@ async function validateAcceptanceCriteria(workingSpec) {
80
89
  };
81
90
  }
82
91
 
92
+ if (!hasCompletionTracking) {
93
+ return {
94
+ valid: true,
95
+ message: `Acceptance criteria present (${criteria.length}); no explicit completion flags found`,
96
+ };
97
+ }
98
+
83
99
  return {
84
100
  valid: true,
85
101
  message: `All ${criteria.length} acceptance criteria completed`,
@@ -212,8 +228,8 @@ async function validateQualityGates(_changeId) {
212
228
  * @param {Object} change - Change data
213
229
  * @returns {Promise<string>} Summary text
214
230
  */
215
- async function generateChangeSummary(change) {
216
- const { workingSpec, metadata } = change;
231
+ async function generateChangeSummary(change, workingSpec) {
232
+ const { metadata } = change;
217
233
 
218
234
  let summary = `# Change Summary: ${change.id}\n\n`;
219
235
 
@@ -267,7 +283,7 @@ async function archiveChange(change) {
267
283
  * @param {Object} change - Change data
268
284
  * @returns {Promise<void>}
269
285
  */
270
- async function updateProvenance(change) {
286
+ async function updateProvenance(change, specSelection) {
271
287
  const provenanceDir = '.caws/provenance';
272
288
  const chainPath = path.join(provenanceDir, 'chain.json');
273
289
 
@@ -284,8 +300,11 @@ async function updateProvenance(change) {
284
300
  action: 'change_completed',
285
301
  change_id: change.id,
286
302
  metadata: {
287
- title: change.workingSpec?.title,
288
- risk_tier: change.workingSpec?.risk_tier,
303
+ title: specSelection?.spec?.title || change.workingSpec?.title,
304
+ risk_tier: specSelection?.spec?.risk_tier || change.workingSpec?.risk_tier,
305
+ spec_id: specSelection?.spec?.id || change.workingSpec?.id || null,
306
+ spec_path: specSelection?.path || change.workingSpecPath || null,
307
+ spec_type: specSelection?.type || (change.workingSpecPath ? 'change-snapshot' : null),
289
308
  files_changed: change.metadata?.files_changed || 0,
290
309
  lines_added: change.metadata?.lines_added || 0,
291
310
  lines_removed: change.metadata?.lines_removed || 0,
@@ -309,10 +328,20 @@ async function updateProvenance(change) {
309
328
  * @param {Object} validation - Validation result
310
329
  * @param {Object} qualityGates - Quality gates result
311
330
  */
312
- function displayArchiveResults(change, validation, qualityGates) {
331
+ function displayArchiveResults(change, validation, qualityGates, specSelection) {
313
332
  console.log(chalk.bold.cyan(`\nArchiving Change: ${change.id}`));
314
333
  console.log(chalk.cyan('==============================================\n'));
315
334
 
335
+ if (specSelection?.spec) {
336
+ console.log(chalk.blue('Spec Context:'));
337
+ console.log(
338
+ chalk.gray(
339
+ ` ${specSelection.spec.id || 'unknown'} (${specSelection.type}) -> ${specSelection.path}`
340
+ )
341
+ );
342
+ console.log('');
343
+ }
344
+
316
345
  // Validation status
317
346
  if (validation.valid) {
318
347
  console.log(chalk.green('Acceptance Criteria'));
@@ -363,22 +392,27 @@ async function archiveCommand(changeId, options = {}) {
363
392
  }
364
393
 
365
394
  // Resolve spec using priority system
366
- let workingSpec = change.workingSpec;
367
- if (!workingSpec && options.specId) {
368
- // If change doesn't have a working spec but spec-id is provided, load it
369
- try {
370
- const resolved = await resolveSpec({
371
- specId: options.specId,
372
- warnLegacy: false,
373
- });
374
- workingSpec = resolved.spec;
375
- } catch (error) {
376
- console.log(
377
- chalk.yellow(`Could not load spec '${options.specId}': ${error.message}`)
378
- );
379
- }
395
+ let specSelection = null;
396
+ if (options.specId || options.specFile) {
397
+ specSelection = await resolveSpec({
398
+ specId: options.specId,
399
+ specFile: options.specFile,
400
+ warnLegacy: false,
401
+ });
402
+ } else if (change.workingSpec) {
403
+ specSelection = {
404
+ path: change.workingSpecPath || path.join(change.path, 'working-spec.yaml'),
405
+ type: 'change-snapshot',
406
+ spec: change.workingSpec,
407
+ };
408
+ } else {
409
+ specSelection = await resolveSpec({
410
+ warnLegacy: false,
411
+ });
380
412
  }
381
413
 
414
+ const workingSpec = specSelection.spec;
415
+
382
416
  // Validate acceptance criteria
383
417
  const validation = await validateAcceptanceCriteria(workingSpec);
384
418
 
@@ -386,7 +420,7 @@ async function archiveCommand(changeId, options = {}) {
386
420
  const qualityGates = await validateQualityGates(changeId);
387
421
 
388
422
  // Display results
389
- displayArchiveResults(change, validation, qualityGates);
423
+ displayArchiveResults(change, validation, qualityGates, specSelection);
390
424
 
391
425
  // Check if we should proceed with archival
392
426
  if (!validation.valid) {
@@ -423,7 +457,7 @@ async function archiveCommand(changeId, options = {}) {
423
457
  change.metadata.archived = true;
424
458
 
425
459
  // Generate and save summary
426
- const summary = await generateChangeSummary(change);
460
+ const summary = await generateChangeSummary(change, workingSpec);
427
461
  const summaryPath = path.join(change.path, 'archive-summary.md');
428
462
  await fs.writeFile(summaryPath, summary);
429
463
 
@@ -431,7 +465,7 @@ async function archiveCommand(changeId, options = {}) {
431
465
  await archiveChange(change);
432
466
 
433
467
  // Update provenance
434
- await updateProvenance(change);
468
+ await updateProvenance(change, specSelection);
435
469
 
436
470
  console.log(chalk.green(`\nSuccessfully archived change: ${changeId}`));
437
471
 
@@ -439,6 +473,11 @@ async function archiveCommand(changeId, options = {}) {
439
473
  command: 'archive',
440
474
  change: changeId,
441
475
  archived: true,
476
+ specSelection: {
477
+ id: workingSpec?.id || null,
478
+ path: specSelection?.path || null,
479
+ type: specSelection?.type || null,
480
+ },
442
481
  validation: validation.valid,
443
482
  qualityGates: qualityGates.valid,
444
483
  summary: summary,
@@ -11,6 +11,7 @@ const chalk = require('chalk');
11
11
  const { execSync } = require('child_process');
12
12
 
13
13
  const { deriveBudget, generateBurnupReport } = require('../budget-derivation');
14
+ const { resolveSpec } = require('../utils/spec-resolver');
14
15
 
15
16
  /**
16
17
  * Get actual git change statistics from the repository
@@ -86,24 +87,32 @@ function getGitChangeStats(specDir) {
86
87
 
87
88
  /**
88
89
  * Burn-up command handler
89
- * @param {string} specFile - Path to spec file
90
+ * @param {string} specFile - Path to spec file (positional, optional)
91
+ * @param {object} options - Command options including --spec-id
90
92
  */
91
- async function burnupCommand(specFile) {
93
+ async function burnupCommand(specFile, options = {}) {
92
94
  try {
93
- let specPath = specFile || path.join('.caws', 'working-spec.yaml');
94
-
95
- if (!fs.existsSync(specPath)) {
96
- console.error(chalk.red(`Spec file not found: ${specPath}`));
97
- process.exit(1);
95
+ let specPath;
96
+ let spec;
97
+
98
+ // Resolve spec: explicit file > --spec-id > resolver default
99
+ if (specFile) {
100
+ specPath = specFile;
101
+ if (!fs.existsSync(specPath)) {
102
+ console.error(chalk.red(`Spec file not found: ${specPath}`));
103
+ process.exit(1);
104
+ }
105
+ spec = yaml.load(fs.readFileSync(specPath, 'utf8'));
106
+ } else {
107
+ const resolved = await resolveSpec({ specId: options.specId });
108
+ specPath = resolved.path;
109
+ spec = resolved.spec;
98
110
  }
99
111
 
100
- const specContent = fs.readFileSync(specPath, 'utf8');
101
- const spec = yaml.load(specContent);
102
-
103
112
  console.log(chalk.cyan('Generating CAWS budget burn-up report...'));
104
113
 
105
114
  // Derive budget
106
- const derivedBudget = deriveBudget(spec, path.dirname(specPath));
115
+ const derivedBudget = await deriveBudget(spec, path.dirname(specPath));
107
116
 
108
117
  // Get actual git change statistics
109
118
  const gitStats = getGitChangeStats(path.dirname(specPath));
@@ -6,8 +6,8 @@
6
6
 
7
7
  const fs = require('fs-extra');
8
8
  const path = require('path');
9
- const yaml = require('js-yaml');
10
9
  const chalk = require('chalk');
10
+ const { resolveSpec } = require('../utils/spec-resolver');
11
11
 
12
12
  // Import utilities
13
13
  const { checkTypeScriptTestConfig } = require('../utils/typescript-detector');
@@ -17,29 +17,23 @@ const { configureJestForTypeScript } = require('../generators/jest-config-genera
17
17
  * Health check: Working spec validity
18
18
  * @returns {Promise<Object>} Check result
19
19
  */
20
- async function checkWorkingSpec() {
21
- const specPath = '.caws/working-spec.yaml';
22
-
23
- if (!(await fs.pathExists(specPath))) {
24
- return {
25
- passed: false,
26
- severity: 'high',
27
- message: 'Working spec not found',
28
- fix: 'Initialize CAWS: caws init .',
29
- autoFixable: false,
30
- };
31
- }
32
-
20
+ async function checkWorkingSpec(options = {}) {
33
21
  try {
34
- const content = await fs.readFile(specPath, 'utf8');
35
- const spec = yaml.load(content);
22
+ const resolved = await resolveSpec({
23
+ specId: options.specId,
24
+ specFile: options.spec,
25
+ warnLegacy: false,
26
+ interactive: false,
27
+ });
28
+ const spec = resolved.spec;
29
+ const specPath = path.relative(process.cwd(), resolved.path);
36
30
 
37
31
  // Basic validation
38
32
  if (!spec.id || !spec.title || !spec.risk_tier) {
39
33
  return {
40
34
  passed: false,
41
35
  severity: 'high',
42
- message: 'Working spec missing required fields',
36
+ message: `Spec missing required fields (${specPath})`,
43
37
  fix: 'Run: caws validate for details',
44
38
  autoFixable: false,
45
39
  };
@@ -47,13 +41,31 @@ async function checkWorkingSpec() {
47
41
 
48
42
  return {
49
43
  passed: true,
50
- message: 'Working spec is valid',
44
+ message: `Spec is valid (${specPath})`,
51
45
  };
52
46
  } catch (error) {
47
+ if (error.message === 'Spec ID required when multiple specs exist' && !options.specId) {
48
+ return {
49
+ passed: false,
50
+ severity: 'high',
51
+ message: 'Multiple specs detected, but no --spec-id was provided',
52
+ fix: 'Run: caws diagnose --spec-id <id>',
53
+ autoFixable: false,
54
+ };
55
+ }
56
+ if (error.message.includes('No CAWS spec found')) {
57
+ return {
58
+ passed: false,
59
+ severity: 'high',
60
+ message: 'No CAWS spec found',
61
+ fix: 'Initialize CAWS: caws init . or create a feature spec with caws specs create <id>',
62
+ autoFixable: false,
63
+ };
64
+ }
53
65
  return {
54
66
  passed: false,
55
67
  severity: 'high',
56
- message: `Working spec has errors: ${error.message}`,
68
+ message: `Spec has errors: ${error.message}`,
57
69
  fix: 'Run: caws validate for details',
58
70
  autoFixable: false,
59
71
  };
@@ -285,9 +297,9 @@ async function checkCAWSTools() {
285
297
  * Run all health checks
286
298
  * @returns {Promise<Object>} Diagnosis results
287
299
  */
288
- async function runDiagnosis() {
300
+ async function runDiagnosis(options = {}) {
289
301
  const checks = [
290
- { name: 'Working spec validity', fn: checkWorkingSpec },
302
+ { name: 'Working spec validity', fn: () => checkWorkingSpec(options) },
291
303
  { name: 'Git repository', fn: checkGitSetup },
292
304
  { name: 'Git hooks', fn: checkGitHooks },
293
305
  { name: 'TypeScript configuration', fn: checkTypeScriptConfig },
@@ -447,7 +459,7 @@ async function applyAutoFixes(results) {
447
459
  async function diagnoseCommand(options = {}) {
448
460
  try {
449
461
  // Run all health checks
450
- const results = await runDiagnosis();
462
+ const results = await runDiagnosis(options);
451
463
 
452
464
  // Display results
453
465
  displayResults(results);
@@ -7,11 +7,11 @@
7
7
  * @author @darianrosebrook
8
8
  */
9
9
 
10
- const fs = require('fs');
11
10
  const path = require('path');
12
- const yaml = require('js-yaml');
13
11
  const chalk = require('chalk');
14
12
  const { initializeGlobalSetup } = require('../config');
13
+ const { resolveSpec } = require('../utils/spec-resolver');
14
+ const { recordEvaluation } = require('../utils/working-state');
15
15
 
16
16
  /**
17
17
  * Evaluate command handler
@@ -19,30 +19,29 @@ const { initializeGlobalSetup } = require('../config');
19
19
  * @param {string} specFile - Path to working spec file
20
20
  * @param {object} options - Command options
21
21
  */
22
- async function evaluateCommand(specFile = '.caws/working-spec.yaml', options = {}) {
22
+ async function evaluateCommand(specFile, options = {}) {
23
23
  try {
24
24
  console.log('Detecting CAWS setup...');
25
25
  const setup = initializeGlobalSetup();
26
26
 
27
27
  if (setup.hasWorkingSpec) {
28
- console.log(`Detected ${setup.setupType} CAWS setup`);
28
+ console.log(`Detected ${setup.type} CAWS setup`);
29
29
  console.log(` Capabilities: ${setup.capabilities.join(', ')}`);
30
30
  }
31
31
 
32
- // Load working spec
33
- const specPath = path.isAbsolute(specFile) ? specFile : path.join(process.cwd(), specFile);
34
-
35
- if (!fs.existsSync(specPath)) {
36
- console.error(chalk.red(`\nWorking spec not found: ${specFile}`));
37
- console.error(chalk.yellow('Run: caws init to create a working spec'));
38
- process.exit(1);
39
- }
40
-
41
- const specContent = fs.readFileSync(specPath, 'utf8');
42
- const spec = yaml.load(specContent);
32
+ const resolved = await resolveSpec({
33
+ specId: options.specId,
34
+ specFile: specFile || undefined,
35
+ warnLegacy: false,
36
+ interactive: false,
37
+ });
38
+ const specPath = resolved.path;
39
+ const spec = resolved.spec;
43
40
 
44
41
  console.log(chalk.blue('\nEvaluating CAWS Quality Standards\n'));
45
42
  console.log('-'.repeat(60));
43
+ console.log(chalk.gray(`Spec: ${path.relative(process.cwd(), specPath)}`));
44
+ console.log(chalk.gray(`Type: ${resolved.type}`));
46
45
 
47
46
  // Evaluation results
48
47
  const results = {
@@ -203,6 +202,19 @@ async function evaluateCommand(specFile = '.caws/working-spec.yaml', options = {
203
202
  ? 'D'
204
203
  : 'F';
205
204
 
205
+ // Record to working state
206
+ try {
207
+ const checksPassed = results.checks.filter(c => c.status === 'pass').length;
208
+ recordEvaluation(spec.id, {
209
+ score: results.score,
210
+ max_score: results.maxScore,
211
+ percentage,
212
+ grade,
213
+ checks_passed: checksPassed,
214
+ checks_total: results.checks.length,
215
+ });
216
+ } catch { /* non-fatal */ }
217
+
206
218
  console.log('\n' + '-'.repeat(60));
207
219
  console.log(
208
220
  chalk.bold(