@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
@@ -0,0 +1,205 @@
1
+ /**
2
+ * @fileoverview TODO/FIXME scanning gate
3
+ * Detects actionable TODO, FIXME, HACK, XXX markers in comments.
4
+ * Filters out false positives: string literals, regex definitions, test assertions,
5
+ * and documentation about the TODO system itself.
6
+ * Context-aware: commit context scans staged diff, cli/edit context scans file content.
7
+ * @author @darianrosebrook
8
+ */
9
+
10
+ const { execSync } = require('child_process');
11
+ const fs = require('fs');
12
+ const path = require('path');
13
+
14
+ const name = 'todo_detection';
15
+
16
+ const TODO_MARKERS = /\b(TODO|FIXME|HACK|XXX)\b/g;
17
+
18
+ /**
19
+ * Comment patterns for languages we scan.
20
+ * A line is a "comment TODO" if the TODO marker appears after a comment introducer.
21
+ */
22
+ const COMMENT_TODO = /(?:\/\/|#|\/?\*|\{\/\*)\s*\b(TODO|FIXME|HACK|XXX)\b/;
23
+
24
+ /**
25
+ * Patterns that indicate the line is ABOUT the TODO system, not an actual TODO.
26
+ * These are lines where TODO appears as data, not as intent.
27
+ */
28
+ const FALSE_POSITIVE_PATTERNS = [
29
+ /TODO_PATTERN/, // regex variable name
30
+ /TODO\/FIXME/, // describing the pattern itself
31
+ /\btoMatch\b|\btoContain\b|\bexpect\(/, // test assertions
32
+ /writeFileSync.*TODO/, // test fixture data
33
+ /\bdescribe\(.*TODO|\btest\(.*TODO|\bit\(.*TODO/, // test names
34
+ /Pattern.*TODO|regex.*TODO/i, // documentation about patterns
35
+ /["'`].*\bTODO\b.*["'`]/, // string literals containing TODO
36
+ ];
37
+
38
+ /** Directories to skip when scanning files directly */
39
+ const EXCLUDE_DIRS = ['node_modules/', 'dist/', 'dist-bundle/', 'build/', '.next/', 'coverage/', 'vendor/', '__pycache__/'];
40
+
41
+ /** Files that are part of the TODO detection system itself — skip to avoid self-analysis */
42
+ const SELF_FILES = ['todo-detection.js', 'todo_detection.js', 'todo_analyzer.py', 'todo-analyzer'];
43
+
44
+ /** Extensions to scan */
45
+ const SOURCE_EXTENSIONS = ['.js', '.ts', '.tsx', '.jsx', '.py', '.rs', '.go', '.java', '.rb', '.cs', '.sh'];
46
+
47
+ /**
48
+ * Check if a file should be excluded from scanning.
49
+ * @param {string} filePath - Relative file path
50
+ * @returns {boolean}
51
+ */
52
+ function isExcluded(filePath) {
53
+ for (const dir of EXCLUDE_DIRS) {
54
+ if (filePath.startsWith(dir) || filePath.includes('/' + dir)) return true;
55
+ }
56
+ // Skip the gate's own implementation files
57
+ const basename = path.basename(filePath);
58
+ for (const self of SELF_FILES) {
59
+ if (basename === self || basename.includes(self)) return true;
60
+ }
61
+ return false;
62
+ }
63
+
64
+ /**
65
+ * Check if a line contains a real TODO comment (not a false positive).
66
+ * Returns the marker name if real, null if false positive.
67
+ * @param {string} line - Source line
68
+ * @returns {string|null} The marker found, or null
69
+ */
70
+ function findRealTodo(line) {
71
+ const trimmed = line.trim();
72
+
73
+ // Must contain a marker at all
74
+ TODO_MARKERS.lastIndex = 0;
75
+ if (!TODO_MARKERS.test(trimmed)) return null;
76
+
77
+ // Filter out false positives
78
+ for (const fp of FALSE_POSITIVE_PATTERNS) {
79
+ if (fp.test(trimmed)) return null;
80
+ }
81
+
82
+ // Must look like a comment containing the marker — not just any line with TODO in it
83
+ if (!COMMENT_TODO.test(trimmed)) return null;
84
+
85
+ // Extract which marker
86
+ TODO_MARKERS.lastIndex = 0;
87
+ const match = TODO_MARKERS.exec(trimmed);
88
+ return match ? match[1] : null;
89
+ }
90
+
91
+ /**
92
+ * Scan staged diff for newly-added TODO markers.
93
+ * Used in commit context — only flags markers being added, not pre-existing ones.
94
+ */
95
+ function scanStagedDiff(projectRoot) {
96
+ const messages = [];
97
+ let totalCount = 0;
98
+
99
+ const diff = execSync('git diff --cached -U0', {
100
+ cwd: projectRoot,
101
+ encoding: 'utf8',
102
+ stdio: ['ignore', 'pipe', 'pipe'],
103
+ });
104
+
105
+ let currentFile = null;
106
+ let lineNum = 0;
107
+
108
+ for (const line of diff.split('\n')) {
109
+ if (line.startsWith('+++ b/')) {
110
+ currentFile = line.slice(6);
111
+ continue;
112
+ }
113
+ if (line.startsWith('@@')) {
114
+ const match = line.match(/@@ -\d+(?:,\d+)? \+(\d+)/);
115
+ if (match) {
116
+ lineNum = parseInt(match[1], 10) - 1;
117
+ }
118
+ continue;
119
+ }
120
+ if (line.startsWith('+') && !line.startsWith('+++')) {
121
+ lineNum++;
122
+ const content = line.slice(1); // remove the leading +
123
+ const marker = findRealTodo(content);
124
+ if (marker) {
125
+ totalCount++;
126
+ messages.push(`${currentFile}:${lineNum}: ${marker} found`);
127
+ }
128
+ } else if (!line.startsWith('-')) {
129
+ lineNum++;
130
+ }
131
+ }
132
+
133
+ return { totalCount, messages };
134
+ }
135
+
136
+ /**
137
+ * Scan file contents directly for TODO markers.
138
+ * Used in cli/edit context — reports all existing markers in the given files.
139
+ */
140
+ function scanFiles(stagedFiles, projectRoot) {
141
+ const messages = [];
142
+ let totalCount = 0;
143
+
144
+ const filesToScan = stagedFiles.filter(f =>
145
+ SOURCE_EXTENSIONS.some(ext => f.endsWith(ext)) && !isExcluded(f)
146
+ );
147
+
148
+ for (const file of filesToScan) {
149
+ try {
150
+ const fullPath = path.resolve(projectRoot, file);
151
+ if (!fs.existsSync(fullPath)) continue;
152
+
153
+ const content = fs.readFileSync(fullPath, 'utf8');
154
+ const lines = content.split('\n');
155
+
156
+ for (let i = 0; i < lines.length; i++) {
157
+ const marker = findRealTodo(lines[i]);
158
+ if (marker) {
159
+ totalCount++;
160
+ messages.push(`${file}:${i + 1}: ${marker} found`);
161
+ }
162
+ }
163
+ } catch {
164
+ // Skip unreadable files
165
+ }
166
+ }
167
+
168
+ return { totalCount, messages };
169
+ }
170
+
171
+ /**
172
+ * Run the TODO detection gate
173
+ * @param {Object} params - Gate parameters
174
+ * @param {string[]} params.stagedFiles - File paths to check
175
+ * @param {string} params.projectRoot - Project root
176
+ * @param {string} [params.context] - Execution context (commit, cli, edit)
177
+ * @returns {Promise<Object>} Gate result with status and messages
178
+ */
179
+ async function run({ stagedFiles, projectRoot, context }) {
180
+ try {
181
+ let result;
182
+
183
+ if (context === 'commit') {
184
+ // Commit context: scan only newly-added lines in staged diff
185
+ result = scanStagedDiff(projectRoot);
186
+ } else {
187
+ // CLI/edit context: scan file contents directly
188
+ result = scanFiles(stagedFiles, projectRoot);
189
+ }
190
+
191
+ if (result.totalCount > 0) {
192
+ result.messages.unshift(`Found ${result.totalCount} TODO/FIXME/HACK/XXX marker(s)${context === 'commit' ? ' in staged changes' : ''}`);
193
+ return { status: 'warn', messages: result.messages };
194
+ }
195
+
196
+ return { status: 'pass', messages: [] };
197
+ } catch (err) {
198
+ return {
199
+ status: 'warn',
200
+ messages: [`Cannot scan for TODO markers: ${err.message}`],
201
+ };
202
+ }
203
+ }
204
+
205
+ module.exports = { name, run };
package/dist/index.js CHANGED
@@ -8,14 +8,16 @@
8
8
  */
9
9
 
10
10
  const { Command } = require('commander');
11
- // eslint-disable-next-line no-unused-vars
12
- const fs = require('fs-extra');
13
- // eslint-disable-next-line no-unused-vars
14
- const path = require('path');
15
- // eslint-disable-next-line no-unused-vars
16
- const yaml = require('js-yaml');
17
11
  const chalk = require('chalk');
18
12
 
13
+ if (
14
+ process.argv.includes('--json') ||
15
+ process.argv.includes('--quiet') ||
16
+ process.argv.includes('-q')
17
+ ) {
18
+ process.env.CAWS_QUIET = '1';
19
+ }
20
+
19
21
  // Import configuration and utilities
20
22
  const {
21
23
  CLI_VERSION,
@@ -42,8 +44,7 @@ const { iterateCommand } = require('./commands/iterate');
42
44
  const { waiversCommand } = require('./commands/waivers');
43
45
  const { workflowCommand } = require('./commands/workflow');
44
46
  const { qualityMonitorCommand } = require('./commands/quality-monitor');
45
- const { qualityGatesCommand } = require('./commands/quality-gates');
46
- const { troubleshootCommand } = require('./commands/troubleshoot');
47
+ const { gatesCommand } = require('./commands/gates');
47
48
  const { archiveCommand } = require('./commands/archive');
48
49
  const { specsCommand } = require('./commands/specs');
49
50
  const { modeCommand } = require('./commands/mode');
@@ -53,6 +54,7 @@ const { worktreeCommand } = require('./commands/worktree');
53
54
  const { sessionCommand } = require('./commands/session');
54
55
  const { parallelCommand } = require('./commands/parallel');
55
56
  const { verifyAcsCommand } = require('./commands/verify-acs');
57
+ const { sidecarCommand } = require('./commands/sidecar');
56
58
 
57
59
  // Import scaffold functionality
58
60
  const { scaffoldProject, setScaffoldDependencies } = require('./scaffold');
@@ -60,16 +62,8 @@ const { scaffoldProject, setScaffoldDependencies } = require('./scaffold');
60
62
  // Import git hooks functionality
61
63
  const { scaffoldGitHooks, removeGitHooks, checkGitHooksStatus } = require('./scaffold/git-hooks');
62
64
 
63
- // Import validation functionality
64
- // eslint-disable-next-line no-unused-vars
65
- const { validateWorkingSpecWithSuggestions } = require('./validation/spec-validation');
66
-
67
65
  // Import finalization utilities
68
66
  const {
69
- // eslint-disable-next-line no-unused-vars
70
- finalizeProject,
71
- // eslint-disable-next-line no-unused-vars
72
- continueToSuccess,
73
67
  setFinalizationDependencies,
74
68
  } = require('./utils/finalization');
75
69
 
@@ -139,84 +133,40 @@ program
139
133
  .option('--format <format>', 'Output format (text, json)', 'text')
140
134
  .action(validateCommand);
141
135
 
142
- // Quality Gates command
136
+ // Gates command group (v2 pipeline)
137
+ const gatesCmd = program
138
+ .command('gates')
139
+ .description('Run quality gate checks');
140
+
141
+ gatesCmd
142
+ .command('run')
143
+ .description('Run quality gates against staged files or a specific file')
144
+ .option('--context <context>', 'Execution context (cli, commit, edit)', 'cli')
145
+ .option('--spec-id <id>', 'Target spec ID')
146
+ .option('--file <path>', 'Single file to check (for edit context)')
147
+ .option('--json', 'Output as JSON', false)
148
+ .option('--quiet', 'Minimal output', false)
149
+ .action((options) => gatesCommand(options));
150
+
151
+ // Quality Gates command (legacy alias — delegates to gates command)
143
152
  program
144
153
  .command('quality-gates')
145
- .description('Run comprehensive quality gates (naming, duplication, god objects, documentation)')
154
+ .description('Run quality gates (alias for "caws gates run")')
146
155
  .option('--ci', 'CI mode - exit with error code if violations found', false)
147
156
  .option('--json', 'Output machine-readable JSON to stdout', false)
148
- .option(
149
- '--gates <gates>',
150
- 'Run only specific gates (comma-separated: naming,code_freeze,duplication,god_objects,hidden-todo,documentation,placeholders)',
151
- ''
152
- )
153
- .option('--fix', 'Attempt automatic fixes (experimental)', false)
154
- .option('--context <context>', 'Execution context: commit (staged files), push (all tracked files), or ci (all tracked files)', 'commit')
157
+ .option('--context <context>', 'Execution context: commit, push, ci', 'commit')
155
158
  .option('--all-files', 'Check all tracked files (equivalent to --context=ci)', false)
156
- .option('--help', 'Show detailed help and usage examples', false)
159
+ .option('--spec-id <id>', 'Target spec ID')
160
+ .option('--quiet', 'Minimal output', false)
157
161
  .action(async (options) => {
158
- // Handle --help flag
159
- if (options.help) {
160
- console.log(`
161
- CAWS Quality Gates - Enterprise Code Quality Enforcement
162
-
163
- USAGE:
164
- caws quality-gates [options]
165
-
166
- DESCRIPTION:
167
- Runs comprehensive quality gates to maintain code quality standards.
168
- Supports selective gate execution, JSON output, and CI/CD integration.
169
-
170
- OPTIONS:
171
- --ci CI mode - exit with error code if violations found
172
- --json Output machine-readable JSON to stdout
173
- --gates=<gates> Run only specific gates (comma-separated)
174
- --fix Attempt automatic fixes (experimental)
175
- --context=<ctx> Execution context: commit (staged files), push (all tracked), ci (all tracked)
176
- --all-files Check all tracked files (shortcut for --context=ci)
177
- --help Show this help message
178
-
179
- VALID GATES:
180
- naming Check naming conventions and banned modifiers
181
- code_freeze Enforce code freeze compliance
182
- duplication Detect functional duplication
183
- god_objects Prevent oversized files
184
- hidden-todo Detect hidden incomplete implementations
185
- documentation Check documentation quality
186
- placeholders Placeholder governance (explicit degradations)
187
-
188
- EXAMPLES:
189
- # Run all gates in development mode
190
- caws quality-gates
191
-
192
- # Run only specific gates
193
- caws quality-gates --gates=naming,duplication
194
-
195
- # CI mode with JSON output
196
- caws quality-gates --ci --json
197
-
198
- # Check all files in repository (not just staged)
199
- caws quality-gates --all-files
200
-
201
- # Use specific context
202
- caws quality-gates --context=ci
203
-
204
- # Show detailed help
205
- caws quality-gates --help
206
-
207
- OUTPUT:
208
- - Console: Human-readable results with enforcement levels
209
- - JSON: Machine-readable structured data (--json flag)
210
- - Artifacts: docs-status/quality-gates-report.json
211
- - GitHub Actions: Automatic step summaries when GITHUB_STEP_SUMMARY is set
212
-
213
- For more information, see: packages/quality-gates/README.md
214
- `);
215
- process.exit(0);
216
- }
217
-
218
- // Call the actual quality gates runner
219
- await qualityGatesCommand(options);
162
+ // Map legacy options to new gates command options
163
+ const gateOpts = {
164
+ context: options.allFiles ? 'ci' : (options.context || 'cli'),
165
+ specId: options.specId,
166
+ json: options.json,
167
+ quiet: options.quiet,
168
+ };
169
+ await gatesCommand(gateOpts);
220
170
  });
221
171
 
222
172
  // Status command
@@ -234,6 +184,7 @@ program
234
184
  .command('archive <change-id>')
235
185
  .description('Archive completed change')
236
186
  .option('--spec-id <id>', 'Feature-specific spec ID (e.g., user-auth)')
187
+ .option('-s, --spec <path>', 'Path to spec file (explicit override)')
237
188
  .option('-f, --force', 'Force archive even if criteria not met', false)
238
189
  .option('--dry-run', 'Preview archive without performing it', false)
239
190
  .action(archiveCommand);
@@ -300,6 +251,38 @@ specsCmd
300
251
  .description('Show available spec types')
301
252
  .action(() => specsCommand('types', {}));
302
253
 
254
+ // Sidecar command group
255
+ const sidecarCmd = program.command('sidecar').description('Advisory analysis tools (drift, gaps, waivers, provenance)');
256
+
257
+ sidecarCmd
258
+ .command('drift')
259
+ .description('Analyze spec drift vs implementation evidence')
260
+ .option('--spec-id <id>', 'Target spec ID')
261
+ .option('--json', 'Output as JSON', false)
262
+ .action((options) => sidecarCommand('drift', options));
263
+
264
+ sidecarCmd
265
+ .command('gaps')
266
+ .description('Diagnose quality gaps preventing phase advancement')
267
+ .option('--spec-id <id>', 'Target spec ID')
268
+ .option('--json', 'Output as JSON', false)
269
+ .action((options) => sidecarCommand('gaps', options));
270
+
271
+ sidecarCmd
272
+ .command('waiver-draft')
273
+ .description('Generate pre-filled waiver templates from gate failures')
274
+ .option('--spec-id <id>', 'Target spec ID')
275
+ .option('--gate <gate>', 'Specific gate to draft waiver for')
276
+ .option('--json', 'Output as JSON', false)
277
+ .action((options) => sidecarCommand('waiver-draft', options));
278
+
279
+ sidecarCmd
280
+ .command('provenance')
281
+ .description('Summarize work provenance for merge readiness')
282
+ .option('--spec-id <id>', 'Target spec ID')
283
+ .option('--json', 'Output as JSON', false)
284
+ .action((options) => sidecarCommand('provenance', options));
285
+
303
286
  // Mode command group
304
287
  const modeCmd = program.command('mode').description('Manage CAWS complexity tiers');
305
288
 
@@ -314,13 +297,6 @@ modeCmd
314
297
  .description('Set CAWS complexity tier')
315
298
  .action((mode) => modeCommand('set', { mode }));
316
299
 
317
- modeCmd
318
- .command('set')
319
- .description('Set CAWS complexity tier (interactive)')
320
- .option('-i, --interactive', 'Interactive mode selection', false)
321
- .option('-m, --mode <mode>', 'Specific mode to set')
322
- .action((options) => modeCommand('set', options));
323
-
324
300
  modeCmd
325
301
  .command('compare')
326
302
  .description('Compare all available tiers')
@@ -393,13 +369,15 @@ worktreeCmd
393
369
  .command('prune')
394
370
  .description('Clean up stale worktree entries')
395
371
  .option('--max-age <days>', 'Remove entries older than N days', '30')
372
+ .option('--force', 'Allow pruning entries owned by other sessions', false)
396
373
  .action((options) => worktreeCommand('prune', options));
397
374
 
398
375
  worktreeCmd
399
376
  .command('repair')
400
377
  .description('Reconcile registry with git and filesystem state')
401
378
  .option('--dry-run', 'Report only, do not persist changes', false)
402
- .option('--prune', 'Remove destroyed and stale-merged entries', false)
379
+ .option('--prune', 'Remove destroyed, stale-merged, and missing entries', false)
380
+ .option('--force', 'Allow pruning entries owned by other sessions', false)
403
381
  .action((options) => worktreeCommand('repair', options));
404
382
 
405
383
  // Session command group
@@ -525,6 +503,14 @@ program
525
503
  .option('-v, --verbose', 'Show detailed error information', false)
526
504
  .action(iterateCommand);
527
505
 
506
+ // Burnup command
507
+ program
508
+ .command('burnup [spec-file]')
509
+ .description('Generate budget burn-up report for scope visibility')
510
+ .option('--spec-id <id>', 'Feature-specific spec ID (e.g., user-auth)')
511
+ .option('-v, --verbose', 'Show detailed error information', false)
512
+ .action(burnupCommand);
513
+
528
514
  // Waivers command group
529
515
  const waiversCmd = program.command('waivers').description('Manage CAWS quality gate waivers');
530
516
 
@@ -567,7 +553,7 @@ waiversCmd
567
553
  .action((id, options) => waiversCommand('revoke', { ...options, id }));
568
554
 
569
555
  // Workflow command group
570
- const workflowCmd = program
556
+ program
571
557
  .command('workflow <type>')
572
558
  .description('Get workflow-specific guidance')
573
559
  .option('--spec-id <id>', 'Feature-specific spec ID (e.g., user-auth)')
@@ -603,7 +589,9 @@ program
603
589
  .command('test-analysis <subcommand> [options...]')
604
590
  .description('Statistical analysis for budget prediction')
605
591
  .option('--spec-id <id>', 'Feature-specific spec ID (e.g., user-auth)')
606
- .action(testAnalysisCommand);
592
+ .action((subcommand, optionArgs, command) => {
593
+ testAnalysisCommand(subcommand, optionArgs, command.opts());
594
+ });
607
595
 
608
596
  // Provenance command group
609
597
  const provenanceCmd = program.command('provenance').description('Manage CAWS provenance tracking');
@@ -613,6 +601,8 @@ provenanceCmd
613
601
  .command('update')
614
602
  .description('Add new commit to provenance chain')
615
603
  .requiredOption('-c, --commit <hash>', 'Git commit hash')
604
+ .option('--spec-id <id>', 'Feature-specific spec ID')
605
+ .option('-s, --spec <path>', 'Path to spec file (explicit override)')
616
606
  .option('-m, --message <msg>', 'Commit message')
617
607
  .option('-a, --author <info>', 'Author information')
618
608
  .option('-q, --quiet', 'Suppress output')
@@ -649,6 +639,8 @@ provenanceCmd
649
639
  provenanceCmd
650
640
  .command('init')
651
641
  .description('Initialize provenance tracking for the project')
642
+ .option('--spec-id <id>', 'Feature-specific spec ID')
643
+ .option('-s, --spec <path>', 'Path to spec file (explicit override)')
652
644
  .option('-o, --output <path>', 'Output path for provenance files', '.caws/provenance')
653
645
  .option('--cursor-api <url>', 'Cursor tracking API endpoint')
654
646
  .option('--cursor-key <key>', 'Cursor API key')
@@ -725,6 +717,36 @@ program.configureHelp({
725
717
  showError: () => {}, // Suppress default error display
726
718
  });
727
719
 
720
+ const VALID_COMMANDS = [
721
+ 'init',
722
+ 'validate',
723
+ 'scaffold',
724
+ 'status',
725
+ 'archive',
726
+ 'specs',
727
+ 'sidecar',
728
+ 'mode',
729
+ 'tutorial',
730
+ 'plan',
731
+ 'templates',
732
+ 'diagnose',
733
+ 'evaluate',
734
+ 'iterate',
735
+ 'waivers',
736
+ 'workflow',
737
+ 'quality-monitor',
738
+ 'quality-gates',
739
+ 'gates',
740
+ 'provenance',
741
+ 'hooks',
742
+ 'burnup',
743
+ 'tool',
744
+ 'worktree',
745
+ 'session',
746
+ 'parallel',
747
+ 'verify-acs',
748
+ ];
749
+
728
750
  program.exitOverride((err) => {
729
751
  // Handle help and version requests gracefully
730
752
  if (
@@ -739,34 +761,7 @@ program.exitOverride((err) => {
739
761
 
740
762
  // Check for unknown command
741
763
  if (err.code === 'commander.unknownCommand') {
742
- const validCommands = [
743
- 'init',
744
- 'validate',
745
- 'scaffold',
746
- 'status',
747
- 'archive',
748
- 'specs',
749
- 'mode',
750
- 'tutorial',
751
- 'plan',
752
- 'templates',
753
- 'diagnose',
754
- 'evaluate',
755
- 'iterate',
756
- 'waivers',
757
- 'workflow',
758
- 'quality-monitor',
759
- 'troubleshoot',
760
- 'provenance',
761
- 'hooks',
762
- 'burnup',
763
- 'tool',
764
- 'worktree',
765
- 'session',
766
- 'parallel',
767
- 'verify-acs',
768
- ];
769
- const similar = findSimilarCommand(commandName, validCommands);
764
+ const similar = findSimilarCommand(commandName, VALID_COMMANDS);
770
765
 
771
766
  console.error(chalk.red(`\nUnknown command: ${commandName}`));
772
767
 
@@ -774,9 +769,7 @@ program.exitOverride((err) => {
774
769
  console.error(chalk.yellow(`\nDid you mean: caws ${similar}?`));
775
770
  }
776
771
 
777
- console.error(
778
- chalk.yellow('Available commands: init, validate, scaffold, provenance, hooks')
779
- );
772
+ console.error(chalk.yellow('Run: caws --help for the full command list'));
780
773
  console.error(chalk.yellow('Try: caws --help for full command list'));
781
774
  console.error(
782
775
  chalk.blue(
@@ -821,6 +814,12 @@ program.exitOverride((err) => {
821
814
  process.exit(1);
822
815
  });
823
816
 
817
+ // Register sidecar lifecycle listeners (non-fatal hints)
818
+ try {
819
+ const { registerSidecarListeners } = require('./sidecars/listeners');
820
+ registerSidecarListeners();
821
+ } catch { /* sidecars module not available — non-fatal */ }
822
+
824
823
  // Parse and run
825
824
  if (require.main === module) {
826
825
  try {
@@ -844,25 +843,7 @@ if (require.main === module) {
844
843
 
845
844
  // Check for unknown command
846
845
  if (error.code === 'commander.unknownCommand') {
847
- const validCommands = [
848
- 'init',
849
- 'validate',
850
- 'scaffold',
851
- 'status',
852
- 'archive',
853
- 'specs',
854
- 'mode',
855
- 'tutorial',
856
- 'plan',
857
- 'provenance',
858
- 'hooks',
859
- 'burnup',
860
- 'tool',
861
- 'worktree',
862
- 'session',
863
- 'parallel',
864
- ];
865
- const similar = findSimilarCommand(commandName, validCommands);
846
+ const similar = findSimilarCommand(commandName, VALID_COMMANDS);
866
847
 
867
848
  console.error(chalk.red(`\nUnknown command: ${commandName}`));
868
849
 
@@ -870,9 +851,7 @@ if (require.main === module) {
870
851
  console.error(chalk.yellow(`\nDid you mean: caws ${similar}?`));
871
852
  }
872
853
 
873
- console.error(
874
- chalk.yellow('Available commands: init, validate, scaffold, provenance, hooks, parallel')
875
- );
854
+ console.error(chalk.yellow('Run: caws --help for the full command list'));
876
855
  console.error(chalk.yellow('Try: caws --help for full command list'));
877
856
  console.error(
878
857
  chalk.blue(
@@ -192,7 +192,7 @@ function getParallelStatus() {
192
192
  let commitCount = 0;
193
193
  let dirty = false;
194
194
 
195
- if (wt && wt.status === 'active') {
195
+ if (wt && (wt.status === 'active' || wt.status === 'fresh' || wt.status === 'merged')) {
196
196
  try {
197
197
  const log = execFileSync(
198
198
  'git',
@@ -250,7 +250,7 @@ function detectFileConflicts(baseBranch, agentStatuses) {
250
250
  const filesByAgent = {};
251
251
 
252
252
  for (const agent of agentStatuses) {
253
- if (agent.status !== 'active') continue;
253
+ if (agent.status !== 'active' && agent.status !== 'fresh' && agent.status !== 'merged') continue;
254
254
  try {
255
255
  const diff = execFileSync(
256
256
  'git',
@@ -302,7 +302,7 @@ function mergeParallel(options = {}) {
302
302
  const wt = worktrees.find((w) => w.name === a.name);
303
303
  return wt ? { ...a, ...wt } : null;
304
304
  })
305
- .filter((a) => a && a.status === 'active');
305
+ .filter((a) => a && (a.status === 'active' || a.status === 'fresh' || a.status === 'merged'));
306
306
 
307
307
  // Check for dirty worktrees
308
308
  for (const agent of activeAgents) {