@paths.design/caws-cli 3.3.1 → 3.5.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 (43) hide show
  1. package/dist/commands/diagnose.d.ts.map +1 -1
  2. package/dist/commands/diagnose.js +39 -4
  3. package/dist/commands/evaluate.d.ts +8 -0
  4. package/dist/commands/evaluate.d.ts.map +1 -0
  5. package/dist/commands/evaluate.js +288 -0
  6. package/dist/commands/iterate.d.ts +8 -0
  7. package/dist/commands/iterate.d.ts.map +1 -0
  8. package/dist/commands/iterate.js +341 -0
  9. package/dist/commands/quality-monitor.d.ts +17 -0
  10. package/dist/commands/quality-monitor.d.ts.map +1 -0
  11. package/dist/commands/quality-monitor.js +265 -0
  12. package/dist/commands/status.d.ts +6 -1
  13. package/dist/commands/status.d.ts.map +1 -1
  14. package/dist/commands/status.js +120 -20
  15. package/dist/commands/troubleshoot.d.ts +8 -0
  16. package/dist/commands/troubleshoot.d.ts.map +1 -0
  17. package/dist/commands/troubleshoot.js +104 -0
  18. package/dist/commands/waivers.d.ts +8 -0
  19. package/dist/commands/waivers.d.ts.map +1 -0
  20. package/dist/commands/waivers.js +293 -0
  21. package/dist/commands/workflow.d.ts +85 -0
  22. package/dist/commands/workflow.d.ts.map +1 -0
  23. package/dist/commands/workflow.js +243 -0
  24. package/dist/error-handler.d.ts +91 -2
  25. package/dist/error-handler.d.ts.map +1 -1
  26. package/dist/error-handler.js +362 -16
  27. package/dist/index.js +95 -0
  28. package/dist/scaffold/git-hooks.d.ts.map +1 -1
  29. package/dist/scaffold/git-hooks.js +27 -6
  30. package/dist/utils/typescript-detector.d.ts +31 -0
  31. package/dist/utils/typescript-detector.d.ts.map +1 -1
  32. package/dist/utils/typescript-detector.js +245 -7
  33. package/package.json +2 -1
  34. package/templates/agents.md +6 -5
  35. package/templates/apps/tools/caws/gates.ts +34 -0
  36. package/templates/apps/tools/caws/shared/gate-checker.ts +265 -13
  37. package/templates/apps/tools/caws/templates/working-spec.template.yml +14 -0
  38. package/dist/index-new.d.ts +0 -5
  39. package/dist/index-new.d.ts.map +0 -1
  40. package/dist/index-new.js +0 -317
  41. package/dist/index.js.backup +0 -4711
  42. package/templates/apps/tools/caws/prompt-lint.js.backup +0 -274
  43. package/templates/apps/tools/caws/provenance.js.backup +0 -73
@@ -11,6 +11,37 @@ export function detectTypeScript(projectDir?: string): any;
11
11
  * @returns {Object} Testing framework detection result
12
12
  */
13
13
  export function detectTestFramework(projectDir?: string, packageJson?: any): any;
14
+ export function getWorkspaceDirectories(projectDir?: string): string[];
15
+ /**
16
+ * Get workspace directories from package.json
17
+ * @param {string} projectDir - Project directory path
18
+ * @returns {string[]} Array of workspace directories
19
+ */
20
+ /**
21
+ * Get workspace directories from npm/yarn package.json workspaces
22
+ * @param {string} projectDir - Project directory path
23
+ * @returns {string[]} Array of workspace directories
24
+ */
25
+ export function getNpmWorkspaces(projectDir: string): string[];
26
+ /**
27
+ * Get workspace directories from pnpm-workspace.yaml
28
+ * @param {string} projectDir - Project directory path
29
+ * @returns {string[]} Array of workspace directories
30
+ */
31
+ export function getPnpmWorkspaces(projectDir: string): string[];
32
+ /**
33
+ * Get workspace directories from lerna.json
34
+ * @param {string} projectDir - Project directory path
35
+ * @returns {string[]} Array of workspace directories
36
+ */
37
+ export function getLernaWorkspaces(projectDir: string): string[];
38
+ /**
39
+ * Check if a dependency exists in hoisted node_modules
40
+ * @param {string} depName - Dependency name to check
41
+ * @param {string} projectDir - Project directory path
42
+ * @returns {boolean} True if dependency found in hoisted node_modules
43
+ */
44
+ export function checkHoistedDependency(depName: string, projectDir: string): boolean;
14
45
  /**
15
46
  * Check if TypeScript project needs test configuration
16
47
  * @param {string} projectDir - Project directory path
@@ -1 +1 @@
1
- {"version":3,"file":"typescript-detector.d.ts","sourceRoot":"","sources":["../../src/utils/typescript-detector.js"],"names":[],"mappings":"AAUA;;;;GAIG;AACH,8CAHW,MAAM,OAkChB;AAED;;;;;GAKG;AACH,iDAJW,MAAM,0BAkDhB;AAED;;;;GAIG;AACH,uDAHW,MAAM,OAiBhB;AAED;;;;;GAKG;AACH,+EAFa,MAAM,EAAE,CAuBpB;AAED;;;GAGG;AACH,iEAoBC"}
1
+ {"version":3,"file":"typescript-detector.d.ts","sourceRoot":"","sources":["../../src/utils/typescript-detector.js"],"names":[],"mappings":"AAUA;;;;GAIG;AACH,8CAHW,MAAM,OAkChB;AAED;;;;;GAKG;AACH,iDAJW,MAAM,0BAkDhB;AAuKD,uEASC;AA9KD;;;;GAIG;AACH;;;;GAIG;AACH,6CAHW,MAAM,GACJ,MAAM,EAAE,CA6CpB;AAED;;;;GAIG;AACH,8CAHW,MAAM,GACJ,MAAM,EAAE,CA6CpB;AAED;;;;GAIG;AACH,+CAHW,MAAM,GACJ,MAAM,EAAE,CA4CpB;AAED;;;;;GAKG;AACH,gDAJW,MAAM,cACN,MAAM,GACJ,OAAO,CAKnB;AAaD;;;;GAIG;AACH,uDAHW,MAAM,OA0EhB;AAED;;;;;GAKG;AACH,+EAFa,MAAM,EAAE,CAuBpB;AAED;;;GAGG;AACH,iEAoBC"}
@@ -100,24 +100,257 @@ function detectTestFramework(projectDir = process.cwd(), packageJson = null) {
100
100
  };
101
101
  }
102
102
 
103
+ /**
104
+ * Get workspace directories from package.json
105
+ * @param {string} projectDir - Project directory path
106
+ * @returns {string[]} Array of workspace directories
107
+ */
108
+ /**
109
+ * Get workspace directories from npm/yarn package.json workspaces
110
+ * @param {string} projectDir - Project directory path
111
+ * @returns {string[]} Array of workspace directories
112
+ */
113
+ function getNpmWorkspaces(projectDir) {
114
+ const packageJsonPath = path.join(projectDir, 'package.json');
115
+
116
+ if (!fs.existsSync(packageJsonPath)) {
117
+ return [];
118
+ }
119
+
120
+ try {
121
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
122
+ const workspaces = packageJson.workspaces || [];
123
+
124
+ // Convert glob patterns to actual directories (simple implementation)
125
+ const workspaceDirs = [];
126
+ for (const ws of workspaces) {
127
+ // Handle simple patterns like "packages/*" or "iterations/*"
128
+ if (ws.includes('*')) {
129
+ const baseDir = ws.split('*')[0];
130
+ const fullBaseDir = path.join(projectDir, baseDir);
131
+
132
+ if (fs.existsSync(fullBaseDir)) {
133
+ const entries = fs.readdirSync(fullBaseDir, { withFileTypes: true });
134
+ for (const entry of entries) {
135
+ if (entry.isDirectory()) {
136
+ const wsPath = path.join(fullBaseDir, entry.name);
137
+ if (fs.existsSync(path.join(wsPath, 'package.json'))) {
138
+ workspaceDirs.push(wsPath);
139
+ }
140
+ }
141
+ }
142
+ }
143
+ } else {
144
+ // Direct path
145
+ const wsPath = path.join(projectDir, ws);
146
+ if (fs.existsSync(path.join(wsPath, 'package.json'))) {
147
+ workspaceDirs.push(wsPath);
148
+ }
149
+ }
150
+ }
151
+
152
+ return workspaceDirs;
153
+ } catch (error) {
154
+ return [];
155
+ }
156
+ }
157
+
158
+ /**
159
+ * Get workspace directories from pnpm-workspace.yaml
160
+ * @param {string} projectDir - Project directory path
161
+ * @returns {string[]} Array of workspace directories
162
+ */
163
+ function getPnpmWorkspaces(projectDir) {
164
+ const pnpmFile = path.join(projectDir, 'pnpm-workspace.yaml');
165
+
166
+ if (!fs.existsSync(pnpmFile)) {
167
+ return [];
168
+ }
169
+
170
+ try {
171
+ const yaml = require('js-yaml');
172
+ const config = yaml.load(fs.readFileSync(pnpmFile, 'utf8'));
173
+ const workspacePatterns = config.packages || [];
174
+
175
+ // Convert glob patterns to actual directories
176
+ const workspaceDirs = [];
177
+ for (const pattern of workspacePatterns) {
178
+ if (pattern.includes('*')) {
179
+ const baseDir = pattern.split('*')[0];
180
+ const fullBaseDir = path.join(projectDir, baseDir);
181
+
182
+ if (fs.existsSync(fullBaseDir)) {
183
+ const entries = fs.readdirSync(fullBaseDir, { withFileTypes: true });
184
+ for (const entry of entries) {
185
+ if (entry.isDirectory()) {
186
+ const wsPath = path.join(fullBaseDir, entry.name);
187
+ if (fs.existsSync(path.join(wsPath, 'package.json'))) {
188
+ workspaceDirs.push(wsPath);
189
+ }
190
+ }
191
+ }
192
+ }
193
+ } else {
194
+ // Direct path
195
+ const wsPath = path.join(projectDir, pattern);
196
+ if (fs.existsSync(path.join(wsPath, 'package.json'))) {
197
+ workspaceDirs.push(wsPath);
198
+ }
199
+ }
200
+ }
201
+
202
+ return workspaceDirs;
203
+ } catch (error) {
204
+ return [];
205
+ }
206
+ }
207
+
208
+ /**
209
+ * Get workspace directories from lerna.json
210
+ * @param {string} projectDir - Project directory path
211
+ * @returns {string[]} Array of workspace directories
212
+ */
213
+ function getLernaWorkspaces(projectDir) {
214
+ const lernaFile = path.join(projectDir, 'lerna.json');
215
+
216
+ if (!fs.existsSync(lernaFile)) {
217
+ return [];
218
+ }
219
+
220
+ try {
221
+ const config = JSON.parse(fs.readFileSync(lernaFile, 'utf8'));
222
+ const workspacePatterns = config.packages || ['packages/*'];
223
+
224
+ // Convert glob patterns to actual directories
225
+ const workspaceDirs = [];
226
+ for (const pattern of workspacePatterns) {
227
+ if (pattern.includes('*')) {
228
+ const baseDir = pattern.split('*')[0];
229
+ const fullBaseDir = path.join(projectDir, baseDir);
230
+
231
+ if (fs.existsSync(fullBaseDir)) {
232
+ const entries = fs.readdirSync(fullBaseDir, { withFileTypes: true });
233
+ for (const entry of entries) {
234
+ if (entry.isDirectory()) {
235
+ const wsPath = path.join(fullBaseDir, entry.name);
236
+ if (fs.existsSync(path.join(wsPath, 'package.json'))) {
237
+ workspaceDirs.push(wsPath);
238
+ }
239
+ }
240
+ }
241
+ }
242
+ } else {
243
+ // Direct path
244
+ const wsPath = path.join(projectDir, pattern);
245
+ if (fs.existsSync(path.join(wsPath, 'package.json'))) {
246
+ workspaceDirs.push(wsPath);
247
+ }
248
+ }
249
+ }
250
+
251
+ return workspaceDirs;
252
+ } catch (error) {
253
+ return [];
254
+ }
255
+ }
256
+
257
+ /**
258
+ * Check if a dependency exists in hoisted node_modules
259
+ * @param {string} depName - Dependency name to check
260
+ * @param {string} projectDir - Project directory path
261
+ * @returns {boolean} True if dependency found in hoisted node_modules
262
+ */
263
+ function checkHoistedDependency(depName, projectDir) {
264
+ const hoistedPath = path.join(projectDir, 'node_modules', depName, 'package.json');
265
+ return fs.existsSync(hoistedPath);
266
+ }
267
+
268
+ function getWorkspaceDirectories(projectDir = process.cwd()) {
269
+ const workspaceDirs = [
270
+ ...getNpmWorkspaces(projectDir),
271
+ ...getPnpmWorkspaces(projectDir),
272
+ ...getLernaWorkspaces(projectDir),
273
+ ];
274
+
275
+ // Remove duplicates
276
+ return [...new Set(workspaceDirs)];
277
+ }
278
+
103
279
  /**
104
280
  * Check if TypeScript project needs test configuration
105
281
  * @param {string} projectDir - Project directory path
106
282
  * @returns {Object} Configuration status
107
283
  */
108
284
  function checkTypeScriptTestConfig(projectDir = process.cwd()) {
109
- const tsDetection = detectTypeScript(projectDir);
110
- const testDetection = detectTestFramework(projectDir, tsDetection.packageJson);
285
+ // First check root directory
286
+ const rootTsDetection = detectTypeScript(projectDir);
287
+ const rootTestDetection = detectTestFramework(projectDir, rootTsDetection.packageJson);
288
+
289
+ // Get workspace directories and check them too
290
+ const workspaceDirs = getWorkspaceDirectories(projectDir);
291
+ const workspaceResults = [];
292
+
293
+ for (const wsDir of workspaceDirs) {
294
+ const wsTsDetection = detectTypeScript(wsDir);
295
+ const wsTestDetection = detectTestFramework(wsDir, wsTsDetection.packageJson);
296
+
297
+ workspaceResults.push({
298
+ directory: path.relative(projectDir, wsDir),
299
+ tsDetection: wsTsDetection,
300
+ testDetection: wsTestDetection,
301
+ });
302
+ }
303
+
304
+ // Determine overall status - prefer workspace results if they exist
305
+ let primaryTsDetection = rootTsDetection;
306
+ let primaryTestDetection = rootTestDetection;
307
+ let primaryWorkspace = null;
308
+
309
+ // Find the workspace with the most complete TypeScript setup
310
+ for (const wsResult of workspaceResults) {
311
+ if (wsResult.tsDetection.isTypeScript) {
312
+ if (
313
+ !primaryTsDetection.isTypeScript ||
314
+ (wsResult.tsDetection.hasTsConfig && !primaryTsDetection.hasTsConfig) ||
315
+ (wsResult.testDetection.framework !== 'none' && primaryTestDetection.framework === 'none')
316
+ ) {
317
+ primaryTsDetection = wsResult.tsDetection;
318
+ primaryTestDetection = wsResult.testDetection;
319
+ primaryWorkspace = wsResult.directory;
320
+ }
321
+ }
322
+ }
323
+
324
+ // Check for ts-jest in workspaces and hoisted node_modules
325
+ let hasTsJestAnywhere = primaryTestDetection.hasTsJest;
326
+
327
+ // If not found in primary workspace, check all workspaces
328
+ if (!hasTsJestAnywhere) {
329
+ hasTsJestAnywhere = workspaceResults.some((ws) => ws.testDetection.hasTsJest);
330
+ }
331
+
332
+ // If still not found, check hoisted node_modules
333
+ if (!hasTsJestAnywhere) {
334
+ hasTsJestAnywhere = checkHoistedDependency('ts-jest', projectDir);
335
+ }
111
336
 
112
337
  const needsConfig =
113
- tsDetection.isTypeScript && testDetection.framework === 'jest' && !testDetection.hasTsJest;
338
+ primaryTsDetection.isTypeScript &&
339
+ primaryTestDetection.framework === 'jest' &&
340
+ !hasTsJestAnywhere;
114
341
 
115
342
  return {
116
- ...tsDetection,
117
- testFramework: testDetection,
118
- needsJestConfig: tsDetection.isTypeScript && !testDetection.isConfigured,
343
+ ...primaryTsDetection,
344
+ testFramework: primaryTestDetection,
345
+ needsJestConfig: primaryTsDetection.isTypeScript && !primaryTestDetection.isConfigured,
119
346
  needsTsJest: needsConfig,
120
- recommendations: generateRecommendations(tsDetection, testDetection),
347
+ recommendations: generateRecommendations(primaryTsDetection, primaryTestDetection),
348
+ workspaceInfo: {
349
+ hasWorkspaces: workspaceDirs.length > 0,
350
+ workspaceCount: workspaceDirs.length,
351
+ primaryWorkspace,
352
+ allWorkspaces: workspaceResults.map((ws) => ws.directory),
353
+ },
121
354
  };
122
355
  }
123
356
 
@@ -179,6 +412,11 @@ function displayTypeScriptDetection(detection) {
179
412
  module.exports = {
180
413
  detectTypeScript,
181
414
  detectTestFramework,
415
+ getWorkspaceDirectories,
416
+ getNpmWorkspaces,
417
+ getPnpmWorkspaces,
418
+ getLernaWorkspaces,
419
+ checkHoistedDependency,
182
420
  checkTypeScriptTestConfig,
183
421
  generateRecommendations,
184
422
  displayTypeScriptDetection,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@paths.design/caws-cli",
3
- "version": "3.3.1",
3
+ "version": "3.5.0",
4
4
  "description": "CAWS CLI - Coding Agent Workflow System command line tools",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -68,6 +68,7 @@
68
68
  "@types/inquirer": "^8.2.6",
69
69
  "@types/js-yaml": "^4.0.0",
70
70
  "@types/node": "^20.0.0",
71
+ "esbuild": "0.25.10",
71
72
  "eslint": "^9.0.0",
72
73
  "jest": "30.1.3",
73
74
  "lint-staged": "15.5.2",
@@ -776,11 +776,11 @@ Real-time quality enforcement:
776
776
  ### Disabling Temporarily
777
777
 
778
778
  ```bash
779
- # If you need to bypass hooks temporarily
780
- # Cursor Settings Hooks → Disable
779
+ # If you need to bypass commit hooks temporarily
780
+ git commit --no-verify # Allowed for commits
781
781
 
782
- # Note: --no-verify is BANNED for git commits
783
- # Fix the issue instead of bypassing hooks
782
+ # Note: --no-verify is BLOCKED for git push
783
+ # Push operations must pass all quality gates
784
784
  ```
785
785
 
786
786
  ---
@@ -972,11 +972,12 @@ Only increase budget with human approval and strong justification.
972
972
 
973
973
  ### Q: What if lints fail but I think they're wrong?
974
974
 
975
- **A: Fix the lints.** Never use `--no-verify`. If the lint rule is incorrect:
975
+ **A: Fix the lints.** You can use `git commit --no-verify` to commit temporarily, but you cannot push without fixing. If the lint rule is incorrect:
976
976
 
977
977
  1. Fix the code to satisfy the lint
978
978
  2. Or request human discussion of the lint rule
979
979
  3. Human can update lint config if appropriate
980
+ 4. Note: `git push --no-verify` is BLOCKED
980
981
 
981
982
  ### Q: Can I commit without updating provenance?
982
983
 
@@ -87,6 +87,16 @@ class GatesCLI {
87
87
  if (result.errors && result.errors.length > 0) {
88
88
  result.errors.forEach((error) => console.error(` - ${error}`));
89
89
  }
90
+ if (result.details?.searched_paths) {
91
+ console.error(` Searched paths: ${result.details.searched_paths.join(', ')}`);
92
+ }
93
+ if (result.details?.run_command) {
94
+ console.error(` Run: ${result.details.run_command}`);
95
+ }
96
+ if (result.details?.waiver_available) {
97
+ console.error(` 💡 ${result.details.waiver_suggestion}`);
98
+ console.error(` ${result.details.waiver_command}`);
99
+ }
90
100
  return false;
91
101
  }
92
102
  } catch (error) {
@@ -118,6 +128,18 @@ class GatesCLI {
118
128
  if (result.errors && result.errors.length > 0) {
119
129
  result.errors.forEach((error) => console.error(` - ${error}`));
120
130
  }
131
+ if (result.details?.searched_paths) {
132
+ console.error(` Searched paths: ${result.details.searched_paths.join(', ')}`);
133
+ }
134
+ if (result.details?.run_command) {
135
+ console.error(` Run: ${result.details.run_command}`);
136
+ }
137
+ if (result.details?.waiver_available) {
138
+ console.error(` 💡 ${result.details.waiver_suggestion}`);
139
+ console.error(
140
+ ` caws waivers create --title="Mutation waiver" --reason=emergency_hotfix --gates=mutation`
141
+ );
142
+ }
121
143
  return false;
122
144
  }
123
145
  } catch (error) {
@@ -144,6 +166,18 @@ class GatesCLI {
144
166
  if (result.errors && result.errors.length > 0) {
145
167
  result.errors.forEach((error) => console.error(` - ${error}`));
146
168
  }
169
+ if (result.details?.searched_paths) {
170
+ console.error(` Searched paths: ${result.details.searched_paths.join(', ')}`);
171
+ }
172
+ if (result.details?.example_command) {
173
+ console.error(` Example: ${result.details.example_command}`);
174
+ }
175
+ console.error(
176
+ ` 💡 If contracts are not required for this tier, consider creating a waiver`
177
+ );
178
+ console.error(
179
+ ` caws waivers create --title="Contract waiver" --reason=experimental_feature --gates=contracts`
180
+ );
147
181
  return false;
148
182
  }
149
183
  } catch (error) {