@paths.design/caws-cli 7.0.2 ā 8.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/budget-derivation.js +5 -4
- package/dist/commands/diagnose.js +24 -19
- package/dist/commands/init.js +51 -4
- package/dist/commands/quality-gates.js +147 -9
- package/dist/commands/specs.js +148 -14
- package/dist/commands/status.js +2 -2
- package/dist/commands/tool.js +2 -4
- package/dist/config/index.js +17 -8
- package/dist/generators/working-spec.js +19 -6
- package/dist/scaffold/git-hooks.js +245 -46
- package/dist/scaffold/index.js +53 -7
- package/dist/templates/.caws/tools/README.md +21 -0
- package/dist/templates/.cursor/README.md +311 -0
- package/dist/templates/.cursor/hooks/audit.sh +55 -0
- package/dist/templates/.cursor/hooks/block-dangerous.sh +83 -0
- package/dist/templates/.cursor/hooks/caws-quality-check.sh +52 -0
- package/dist/templates/.cursor/hooks/caws-scope-guard.sh +130 -0
- package/dist/templates/.cursor/hooks/caws-tool-validation.sh +121 -0
- package/dist/templates/.cursor/hooks/format.sh +38 -0
- package/dist/templates/.cursor/hooks/naming-check.sh +64 -0
- package/dist/templates/.cursor/hooks/scan-secrets.sh +46 -0
- package/dist/templates/.cursor/hooks/scope-guard.sh +52 -0
- package/dist/templates/.cursor/hooks/validate-spec.sh +83 -0
- package/dist/templates/.cursor/hooks.json +59 -0
- package/dist/templates/.cursor/rules/00-claims-verification.mdc +144 -0
- package/dist/templates/.cursor/rules/01-working-style.mdc +50 -0
- package/dist/templates/.cursor/rules/02-quality-gates.mdc +370 -0
- package/dist/templates/.cursor/rules/03-naming-and-refactor.mdc +33 -0
- package/dist/templates/.cursor/rules/04-logging-language-style.mdc +23 -0
- package/dist/templates/.cursor/rules/05-safe-defaults-guards.mdc +23 -0
- package/dist/templates/.cursor/rules/06-typescript-conventions.mdc +36 -0
- package/dist/templates/.cursor/rules/07-process-ops.mdc +20 -0
- package/dist/templates/.cursor/rules/08-solid-and-architecture.mdc +16 -0
- package/dist/templates/.cursor/rules/09-docstrings.mdc +89 -0
- package/dist/templates/.cursor/rules/10-documentation-quality-standards.mdc +390 -0
- package/dist/templates/.cursor/rules/11-scope-management-waivers.mdc +385 -0
- package/dist/templates/.cursor/rules/12-implementation-completeness.mdc +516 -0
- package/dist/templates/.cursor/rules/13-language-agnostic-standards.mdc +588 -0
- package/dist/templates/.cursor/rules/README.md +148 -0
- package/dist/templates/.github/copilot/instructions.md +311 -0
- package/dist/templates/.idea/runConfigurations/CAWS_Evaluate.xml +5 -0
- package/dist/templates/.idea/runConfigurations/CAWS_Validate.xml +5 -0
- package/dist/templates/.vscode/launch.json +56 -0
- package/dist/templates/.vscode/settings.json +93 -0
- package/dist/templates/.windsurf/workflows/caws-guided-development.md +92 -0
- package/dist/templates/COMMIT_CONVENTIONS.md +86 -0
- package/dist/templates/OIDC_SETUP.md +300 -0
- package/dist/templates/agents.md +1047 -0
- package/dist/templates/codemod/README.md +1 -0
- package/dist/templates/codemod/test.js +93 -0
- package/dist/templates/docs/README.md +150 -0
- package/dist/templates/scripts/quality-gates/check-god-objects.js +146 -0
- package/dist/templates/scripts/quality-gates/run-quality-gates.js +50 -0
- package/dist/templates/scripts/v3/analysis/todo_analyzer.py +1997 -0
- package/dist/tool-loader.js +6 -1
- package/dist/tool-validator.js +8 -2
- package/dist/utils/detection.js +4 -3
- package/dist/utils/git-lock.js +119 -0
- package/dist/utils/gitignore-updater.js +148 -0
- package/dist/utils/project-analysis.js +176 -16
- package/dist/utils/quality-gates.js +48 -7
- package/dist/utils/spec-resolver.js +27 -3
- package/dist/utils/yaml-validation.js +156 -0
- package/dist/validation/spec-validation.js +81 -2
- package/package.json +2 -2
- package/templates/.caws/schemas/waivers.schema.json +30 -0
- package/templates/.caws/schemas/working-spec.schema.json +133 -0
- package/templates/.caws/templates/working-spec.template.yml +74 -0
- package/templates/.caws/tools/README.md +21 -0
- package/templates/.caws/tools/scope-guard.js +208 -0
- package/templates/.caws/tools-allow.json +331 -0
- package/templates/.caws/waivers.yml +19 -0
- package/templates/.cursor/hooks/scope-guard.sh +2 -2
- package/templates/.cursor/hooks/validate-spec.sh +42 -7
- package/dist/budget-derivation.d.ts +0 -74
- package/dist/budget-derivation.d.ts.map +0 -1
- package/dist/cicd-optimizer.d.ts +0 -142
- package/dist/cicd-optimizer.d.ts.map +0 -1
- package/dist/commands/archive.d.ts +0 -50
- package/dist/commands/archive.d.ts.map +0 -1
- package/dist/commands/burnup.d.ts +0 -6
- package/dist/commands/burnup.d.ts.map +0 -1
- package/dist/commands/diagnose.d.ts +0 -52
- package/dist/commands/diagnose.d.ts.map +0 -1
- package/dist/commands/evaluate.d.ts +0 -8
- package/dist/commands/evaluate.d.ts.map +0 -1
- package/dist/commands/init.d.ts +0 -5
- package/dist/commands/init.d.ts.map +0 -1
- package/dist/commands/iterate.d.ts +0 -8
- package/dist/commands/iterate.d.ts.map +0 -1
- package/dist/commands/mode.d.ts +0 -24
- package/dist/commands/mode.d.ts.map +0 -1
- package/dist/commands/plan.d.ts +0 -49
- package/dist/commands/plan.d.ts.map +0 -1
- package/dist/commands/provenance.d.ts +0 -32
- package/dist/commands/provenance.d.ts.map +0 -1
- package/dist/commands/quality-gates.d.ts +0 -52
- package/dist/commands/quality-gates.d.ts.map +0 -1
- package/dist/commands/quality-monitor.d.ts +0 -17
- package/dist/commands/quality-monitor.d.ts.map +0 -1
- package/dist/commands/specs.d.ts +0 -71
- package/dist/commands/specs.d.ts.map +0 -1
- package/dist/commands/status.d.ts +0 -44
- package/dist/commands/status.d.ts.map +0 -1
- package/dist/commands/templates.d.ts +0 -74
- package/dist/commands/templates.d.ts.map +0 -1
- package/dist/commands/tool.d.ts +0 -13
- package/dist/commands/tool.d.ts.map +0 -1
- package/dist/commands/troubleshoot.d.ts +0 -8
- package/dist/commands/troubleshoot.d.ts.map +0 -1
- package/dist/commands/tutorial.d.ts +0 -55
- package/dist/commands/tutorial.d.ts.map +0 -1
- package/dist/commands/validate.d.ts +0 -15
- package/dist/commands/validate.d.ts.map +0 -1
- package/dist/commands/waivers.d.ts +0 -8
- package/dist/commands/waivers.d.ts.map +0 -1
- package/dist/commands/workflow.d.ts +0 -85
- package/dist/commands/workflow.d.ts.map +0 -1
- package/dist/config/index.d.ts +0 -29
- package/dist/config/index.d.ts.map +0 -1
- package/dist/config/modes.d.ts +0 -225
- package/dist/config/modes.d.ts.map +0 -1
- package/dist/constants/spec-types.d.ts +0 -41
- package/dist/constants/spec-types.d.ts.map +0 -1
- package/dist/error-handler.d.ts +0 -164
- package/dist/error-handler.d.ts.map +0 -1
- package/dist/generators/jest-config.d.ts +0 -32
- package/dist/generators/jest-config.d.ts.map +0 -1
- package/dist/generators/working-spec.d.ts +0 -13
- package/dist/generators/working-spec.d.ts.map +0 -1
- package/dist/index-new.d.ts +0 -5
- package/dist/index-new.d.ts.map +0 -1
- package/dist/index-new.js +0 -317
- package/dist/index.d.ts +0 -5
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.backup +0 -4711
- package/dist/minimal-cli.d.ts +0 -3
- package/dist/minimal-cli.d.ts.map +0 -1
- package/dist/policy/PolicyManager.d.ts +0 -104
- package/dist/policy/PolicyManager.d.ts.map +0 -1
- package/dist/scaffold/cursor-hooks.d.ts +0 -7
- package/dist/scaffold/cursor-hooks.d.ts.map +0 -1
- package/dist/scaffold/git-hooks.d.ts +0 -20
- package/dist/scaffold/git-hooks.d.ts.map +0 -1
- package/dist/scaffold/index.d.ts +0 -20
- package/dist/scaffold/index.d.ts.map +0 -1
- package/dist/spec/SpecFileManager.d.ts +0 -146
- package/dist/spec/SpecFileManager.d.ts.map +0 -1
- package/dist/test-analysis.d.ts +0 -182
- package/dist/test-analysis.d.ts.map +0 -1
- package/dist/tool-interface.d.ts +0 -236
- package/dist/tool-interface.d.ts.map +0 -1
- package/dist/tool-loader.d.ts +0 -77
- package/dist/tool-loader.d.ts.map +0 -1
- package/dist/tool-validator.d.ts +0 -72
- package/dist/tool-validator.d.ts.map +0 -1
- package/dist/utils/detection.d.ts +0 -7
- package/dist/utils/detection.d.ts.map +0 -1
- package/dist/utils/finalization.d.ts +0 -17
- package/dist/utils/finalization.d.ts.map +0 -1
- package/dist/utils/project-analysis.d.ts +0 -14
- package/dist/utils/project-analysis.d.ts.map +0 -1
- package/dist/utils/quality-gates.d.ts +0 -49
- package/dist/utils/quality-gates.d.ts.map +0 -1
- package/dist/utils/spec-resolver.d.ts +0 -88
- package/dist/utils/spec-resolver.d.ts.map +0 -1
- package/dist/utils/typescript-detector.d.ts +0 -63
- package/dist/utils/typescript-detector.d.ts.map +0 -1
- package/dist/validation/spec-validation.d.ts +0 -43
- package/dist/validation/spec-validation.d.ts.map +0 -1
- package/dist/waivers-manager.d.ts +0 -167
- package/dist/waivers-manager.d.ts.map +0 -1
- package/templates/apps/tools/caws/COMPLETION_REPORT.md +0 -331
- package/templates/apps/tools/caws/MIGRATION_SUMMARY.md +0 -360
- package/templates/apps/tools/caws/README.md +0 -463
- package/templates/apps/tools/caws/TEST_STATUS.md +0 -365
- package/templates/apps/tools/caws/attest.js +0 -357
- package/templates/apps/tools/caws/ci-optimizer.js +0 -642
- package/templates/apps/tools/caws/config.ts +0 -245
- package/templates/apps/tools/caws/cross-functional.js +0 -876
- package/templates/apps/tools/caws/dashboard.js +0 -1112
- package/templates/apps/tools/caws/flake-detector.ts +0 -362
- package/templates/apps/tools/caws/gates.js +0 -198
- package/templates/apps/tools/caws/gates.ts +0 -271
- package/templates/apps/tools/caws/language-adapters.ts +0 -381
- package/templates/apps/tools/caws/language-support.d.ts +0 -367
- package/templates/apps/tools/caws/language-support.d.ts.map +0 -1
- package/templates/apps/tools/caws/language-support.js +0 -585
- package/templates/apps/tools/caws/legacy-assessment.ts +0 -408
- package/templates/apps/tools/caws/legacy-assessor.js +0 -764
- package/templates/apps/tools/caws/mutant-analyzer.js +0 -734
- package/templates/apps/tools/caws/perf-budgets.ts +0 -349
- package/templates/apps/tools/caws/prompt-lint.js.backup +0 -274
- package/templates/apps/tools/caws/property-testing.js +0 -707
- package/templates/apps/tools/caws/provenance.d.ts +0 -14
- package/templates/apps/tools/caws/provenance.d.ts.map +0 -1
- package/templates/apps/tools/caws/provenance.js +0 -132
- package/templates/apps/tools/caws/provenance.js.backup +0 -73
- package/templates/apps/tools/caws/provenance.ts +0 -211
- package/templates/apps/tools/caws/security-provenance.ts +0 -483
- package/templates/apps/tools/caws/shared/base-tool.ts +0 -281
- package/templates/apps/tools/caws/shared/config-manager.ts +0 -366
- package/templates/apps/tools/caws/shared/gate-checker.ts +0 -849
- package/templates/apps/tools/caws/shared/types.ts +0 -444
- package/templates/apps/tools/caws/shared/validator.ts +0 -305
- package/templates/apps/tools/caws/shared/waivers-manager.ts +0 -174
- package/templates/apps/tools/caws/spec-test-mapper.ts +0 -391
- package/templates/apps/tools/caws/test-quality.js +0 -578
- package/templates/apps/tools/caws/validate.js +0 -76
- package/templates/apps/tools/caws/validate.ts +0 -228
- package/templates/apps/tools/caws/waivers.js +0 -344
- /package/{templates/apps/tools/caws ā dist/templates/.caws}/schemas/waivers.schema.json +0 -0
- /package/{templates/apps/tools/caws ā dist/templates/.caws}/schemas/working-spec.schema.json +0 -0
- /package/{templates/apps/tools/caws ā dist/templates/.caws}/templates/working-spec.template.yml +0 -0
- /package/{templates/apps/tools/caws ā dist/templates/.caws/tools}/scope-guard.js +0 -0
- /package/{templates/apps/tools/caws ā dist/templates/.caws}/tools-allow.json +0 -0
- /package/{templates/apps/tools/caws ā dist/templates/.caws}/waivers.yml +0 -0
|
@@ -196,10 +196,11 @@ async function deriveBudget(spec, projectRoot = process.cwd(), options = {}) {
|
|
|
196
196
|
' This may be a path resolution or caching issue\n'
|
|
197
197
|
);
|
|
198
198
|
} else {
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
199
|
+
// Policy.yaml is optional - defaults work fine, so don't warn unnecessarily
|
|
200
|
+
// Only show info message if user explicitly wants to see it
|
|
201
|
+
if (options.showPolicyInfo !== false) {
|
|
202
|
+
// Silent by default - policy.yaml is optional
|
|
203
|
+
}
|
|
203
204
|
}
|
|
204
205
|
}
|
|
205
206
|
|
|
@@ -240,41 +240,44 @@ async function checkTestFiles() {
|
|
|
240
240
|
* @returns {Promise<Object>} Check result
|
|
241
241
|
*/
|
|
242
242
|
async function checkCAWSTools() {
|
|
243
|
-
|
|
243
|
+
// Check new location first, then legacy location for backward compatibility
|
|
244
|
+
const toolsPath = '.caws/tools';
|
|
245
|
+
const legacyToolsPath = 'apps/tools/caws';
|
|
244
246
|
|
|
245
|
-
if (!(await fs.pathExists(toolsPath))) {
|
|
247
|
+
if (!(await fs.pathExists(toolsPath)) && !(await fs.pathExists(legacyToolsPath))) {
|
|
246
248
|
return {
|
|
247
|
-
passed:
|
|
248
|
-
severity: '
|
|
249
|
-
message: 'CAWS tools directory not found',
|
|
250
|
-
fix: '
|
|
249
|
+
passed: true,
|
|
250
|
+
severity: 'info',
|
|
251
|
+
message: 'CAWS tools directory not found (optional - use CLI commands instead)',
|
|
252
|
+
fix: 'Core functionality available via: caws validate, caws quality-gates, caws provenance',
|
|
251
253
|
autoFixable: false,
|
|
252
254
|
};
|
|
253
255
|
}
|
|
254
256
|
|
|
255
|
-
//
|
|
256
|
-
const
|
|
257
|
-
|
|
257
|
+
// Tools directory exists - check for specialized tools (not core CLI duplicates)
|
|
258
|
+
const specializedTools = ['flake-detector.ts', 'spec-test-mapper.ts', 'perf-budgets.ts'];
|
|
259
|
+
const foundTools = [];
|
|
258
260
|
|
|
259
|
-
for (const tool of
|
|
260
|
-
if (
|
|
261
|
-
|
|
261
|
+
for (const tool of specializedTools) {
|
|
262
|
+
if (await fs.pathExists(path.join(toolsPath, tool))) {
|
|
263
|
+
foundTools.push(tool);
|
|
262
264
|
}
|
|
263
265
|
}
|
|
264
266
|
|
|
265
|
-
if (
|
|
267
|
+
if (foundTools.length === 0) {
|
|
266
268
|
return {
|
|
267
|
-
passed:
|
|
268
|
-
severity: '
|
|
269
|
-
message:
|
|
270
|
-
fix: '
|
|
269
|
+
passed: true,
|
|
270
|
+
severity: 'info',
|
|
271
|
+
message: 'No specialized tools found (optional - use CLI commands for core functionality)',
|
|
272
|
+
fix: 'Core functionality available via: caws validate, caws quality-gates, caws provenance',
|
|
271
273
|
autoFixable: false,
|
|
272
274
|
};
|
|
273
275
|
}
|
|
274
276
|
|
|
275
277
|
return {
|
|
276
278
|
passed: true,
|
|
277
|
-
message:
|
|
279
|
+
message: `Found ${foundTools.length} specialized tool(s): ${foundTools.join(', ')}`,
|
|
280
|
+
note: 'Core functionality (validate, quality-gates, provenance) available via CLI commands',
|
|
278
281
|
};
|
|
279
282
|
}
|
|
280
283
|
|
|
@@ -484,7 +487,9 @@ async function diagnoseCommand(options = {}) {
|
|
|
484
487
|
console.log(chalk.blue(' ⢠Run: caws status --visual to view project health'));
|
|
485
488
|
console.log(chalk.blue(' ⢠Run: caws validate to check working spec'));
|
|
486
489
|
console.log(chalk.blue(' ⢠Optional: Create .caws/policy.yaml for custom budgets'));
|
|
487
|
-
console.log(
|
|
490
|
+
console.log(
|
|
491
|
+
chalk.blue(' ⢠Start implementing: caws iterate --current-state "Ready to begin"')
|
|
492
|
+
);
|
|
488
493
|
}
|
|
489
494
|
} catch (error) {
|
|
490
495
|
console.error(chalk.red('\nā Error running diagnosis:'), error.message);
|
package/dist/commands/init.js
CHANGED
|
@@ -17,6 +17,7 @@ const { generateWorkingSpec } = require('../generators/working-spec');
|
|
|
17
17
|
const { finalizeProject } = require('../utils/finalization');
|
|
18
18
|
const { scaffoldCursorHooks } = require('../scaffold/cursor-hooks');
|
|
19
19
|
const { scaffoldIDEIntegrations } = require('../scaffold/index');
|
|
20
|
+
const { updateGitignore } = require('../utils/gitignore-updater');
|
|
20
21
|
|
|
21
22
|
/**
|
|
22
23
|
* Initialize a new project with CAWS
|
|
@@ -361,6 +362,18 @@ async function initProject(projectName, options) {
|
|
|
361
362
|
await fs.writeFile(path.join('.caws', 'working-spec.yaml'), specContent);
|
|
362
363
|
console.log(chalk.green('ā
Created .caws/working-spec.yaml'));
|
|
363
364
|
|
|
365
|
+
// Optionally create policy.yaml (optional - defaults work fine)
|
|
366
|
+
const policyPath = path.join('.caws', 'policy.yaml');
|
|
367
|
+
if (!fs.existsSync(policyPath)) {
|
|
368
|
+
const { PolicyManager } = require('../policy/PolicyManager');
|
|
369
|
+
const policyManager = new PolicyManager();
|
|
370
|
+
const defaultPolicy = policyManager.getDefaultPolicy();
|
|
371
|
+
const yaml = require('js-yaml');
|
|
372
|
+
const policyContent = yaml.dump(defaultPolicy, { indent: 2 });
|
|
373
|
+
await fs.writeFile(policyPath, policyContent);
|
|
374
|
+
console.log(chalk.green('ā
Created .caws/policy.yaml (optional - defaults work fine)'));
|
|
375
|
+
}
|
|
376
|
+
|
|
364
377
|
// Generate additional files if requested
|
|
365
378
|
if (answers.generateExamples) {
|
|
366
379
|
console.log(chalk.blue('š Generating example files...'));
|
|
@@ -409,6 +422,17 @@ Happy coding! šÆ
|
|
|
409
422
|
console.log(chalk.blue('šØ Setting up IDE integrations...'));
|
|
410
423
|
await scaffoldIDEIntegrations(process.cwd(), { force: false });
|
|
411
424
|
|
|
425
|
+
// Update .gitignore to exclude CAWS local runtime files
|
|
426
|
+
console.log(chalk.blue('š Updating .gitignore...'));
|
|
427
|
+
const gitignoreUpdated = await updateGitignore(process.cwd());
|
|
428
|
+
if (gitignoreUpdated) {
|
|
429
|
+
console.log(chalk.green('ā
Updated .gitignore to exclude CAWS local runtime files'));
|
|
430
|
+
console.log(
|
|
431
|
+
chalk.gray(' Tracked: Specs, policy, waivers, provenance, plans (shared with team)')
|
|
432
|
+
);
|
|
433
|
+
console.log(chalk.gray(' Ignored: Agent runtime, temp files, logs (local-only)'));
|
|
434
|
+
}
|
|
435
|
+
|
|
412
436
|
// Finalize project
|
|
413
437
|
await finalizeProject(projectName, options, answers);
|
|
414
438
|
} else {
|
|
@@ -456,7 +480,7 @@ Happy coding! šÆ
|
|
|
456
480
|
experimentalSandbox: '',
|
|
457
481
|
aiConfidence: 0.8,
|
|
458
482
|
uncertaintyAreas: '',
|
|
459
|
-
complexityFactors: ''
|
|
483
|
+
complexityFactors: '',
|
|
460
484
|
};
|
|
461
485
|
|
|
462
486
|
const specContent = generateWorkingSpec(defaultAnswers);
|
|
@@ -464,6 +488,18 @@ Happy coding! šÆ
|
|
|
464
488
|
await fs.writeFile(path.join('.caws', 'working-spec.yaml'), specContent);
|
|
465
489
|
console.log(chalk.green('ā
Created .caws/working-spec.yaml'));
|
|
466
490
|
|
|
491
|
+
// Optionally create policy.yaml (optional - defaults work fine)
|
|
492
|
+
const policyPath = path.join('.caws', 'policy.yaml');
|
|
493
|
+
if (!fs.existsSync(policyPath)) {
|
|
494
|
+
const { PolicyManager } = require('../policy/PolicyManager');
|
|
495
|
+
const policyManager = new PolicyManager();
|
|
496
|
+
const defaultPolicy = policyManager.getDefaultPolicy();
|
|
497
|
+
const yaml = require('js-yaml');
|
|
498
|
+
const policyContent = yaml.dump(defaultPolicy, { indent: 2 });
|
|
499
|
+
await fs.writeFile(policyPath, policyContent);
|
|
500
|
+
console.log(chalk.green('ā
Created .caws/policy.yaml (optional - defaults work fine)'));
|
|
501
|
+
}
|
|
502
|
+
|
|
467
503
|
// Setup Cursor hooks by default in non-interactive mode
|
|
468
504
|
console.log(chalk.blue('šÆ Setting up Cursor hooks...'));
|
|
469
505
|
await scaffoldCursorHooks(process.cwd());
|
|
@@ -472,6 +508,17 @@ Happy coding! šÆ
|
|
|
472
508
|
console.log(chalk.blue('šØ Setting up IDE integrations...'));
|
|
473
509
|
await scaffoldIDEIntegrations(process.cwd(), { force: false });
|
|
474
510
|
|
|
511
|
+
// Update .gitignore to exclude CAWS local runtime files
|
|
512
|
+
console.log(chalk.blue('š Updating .gitignore...'));
|
|
513
|
+
const gitignoreUpdated = await updateGitignore(process.cwd());
|
|
514
|
+
if (gitignoreUpdated) {
|
|
515
|
+
console.log(chalk.green('ā
Updated .gitignore to exclude CAWS local runtime files'));
|
|
516
|
+
console.log(
|
|
517
|
+
chalk.gray(' Tracked: Specs, policy, waivers, provenance, plans (shared with team)')
|
|
518
|
+
);
|
|
519
|
+
console.log(chalk.gray(' Ignored: Agent runtime, temp files, logs (local-only)'));
|
|
520
|
+
}
|
|
521
|
+
|
|
475
522
|
// Finalize project
|
|
476
523
|
await finalizeProject(projectName, options, defaultAnswers);
|
|
477
524
|
}
|
|
@@ -481,7 +528,7 @@ Happy coding! šÆ
|
|
|
481
528
|
console.log(chalk.blue('\nNext steps:'));
|
|
482
529
|
console.log('1. Review .caws/working-spec.yaml');
|
|
483
530
|
console.log('2. Customize the specification for your needs');
|
|
484
|
-
|
|
531
|
+
|
|
485
532
|
// Show contract requirements if Tier 1 or 2
|
|
486
533
|
// Use answers if available (interactive mode), otherwise default to 2
|
|
487
534
|
const riskTier = answers?.riskTier || 2;
|
|
@@ -495,7 +542,7 @@ Happy coding! šÆ
|
|
|
495
542
|
console.log(chalk.gray(' description: "Project-level CAWS configuration"'));
|
|
496
543
|
console.log(' Or use "chore" mode for maintenance work (mode: chore)');
|
|
497
544
|
}
|
|
498
|
-
|
|
545
|
+
|
|
499
546
|
console.log('\nš Recommended Setup Workflow:');
|
|
500
547
|
console.log(' 1. Review .caws/working-spec.yaml');
|
|
501
548
|
console.log(' 2. Run: caws scaffold (adds tools and templates)');
|
|
@@ -511,7 +558,7 @@ Happy coding! šÆ
|
|
|
511
558
|
if (error.stack) {
|
|
512
559
|
console.error(chalk.gray(error.stack));
|
|
513
560
|
}
|
|
514
|
-
|
|
561
|
+
|
|
515
562
|
// Cleanup on error (only for new directory creation)
|
|
516
563
|
if (projectName && projectName !== '.' && fs.existsSync(projectName)) {
|
|
517
564
|
try {
|
|
@@ -44,14 +44,66 @@ async function qualityGatesCommand(options = {}) {
|
|
|
44
44
|
const packagesDir = path.dirname(cliPackageDir);
|
|
45
45
|
const monorepoRunner = path.join(packagesDir, 'quality-gates', 'run-quality-gates.mjs');
|
|
46
46
|
|
|
47
|
-
// Option 2: Check
|
|
47
|
+
// Option 2: Check globally installed CLI for bundled quality gates
|
|
48
|
+
let globalCliPath = null;
|
|
49
|
+
try {
|
|
50
|
+
const { execSync } = require('child_process');
|
|
51
|
+
const whichCaws = execSync('which caws', { encoding: 'utf8', stdio: 'pipe' }).trim();
|
|
52
|
+
if (whichCaws) {
|
|
53
|
+
// Resolve symlink to actual path
|
|
54
|
+
const realPath = fs.realpathSync(whichCaws);
|
|
55
|
+
const globalCliDir = path.dirname(realPath);
|
|
56
|
+
// Check for bundled quality gates in global CLI installation
|
|
57
|
+
const possibleBundledPaths = [
|
|
58
|
+
path.join(
|
|
59
|
+
globalCliDir,
|
|
60
|
+
'..',
|
|
61
|
+
'lib',
|
|
62
|
+
'node_modules',
|
|
63
|
+
'@paths.design',
|
|
64
|
+
'caws-cli',
|
|
65
|
+
'node_modules',
|
|
66
|
+
'@paths.design',
|
|
67
|
+
'quality-gates',
|
|
68
|
+
'run-quality-gates.mjs'
|
|
69
|
+
),
|
|
70
|
+
path.join(
|
|
71
|
+
globalCliDir,
|
|
72
|
+
'..',
|
|
73
|
+
'lib',
|
|
74
|
+
'node_modules',
|
|
75
|
+
'@paths.design',
|
|
76
|
+
'quality-gates',
|
|
77
|
+
'run-quality-gates.mjs'
|
|
78
|
+
),
|
|
79
|
+
path.join(
|
|
80
|
+
globalCliDir,
|
|
81
|
+
'..',
|
|
82
|
+
'node_modules',
|
|
83
|
+
'@paths.design',
|
|
84
|
+
'quality-gates',
|
|
85
|
+
'run-quality-gates.mjs'
|
|
86
|
+
),
|
|
87
|
+
];
|
|
88
|
+
for (const bundledPath of possibleBundledPaths) {
|
|
89
|
+
if (fs.existsSync(bundledPath)) {
|
|
90
|
+
globalCliPath = bundledPath;
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
} catch (e) {
|
|
96
|
+
// Ignore errors finding global CLI
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Option 3: Check VS Code extension bundled (if running from extension context)
|
|
48
100
|
const vscodeExtensionPath =
|
|
49
101
|
process.env.VSCODE_EXTENSION_PATH || process.env.VSCODE_EXTENSION_DIR;
|
|
50
102
|
const bundledRunner = vscodeExtensionPath
|
|
51
103
|
? path.join(vscodeExtensionPath, 'bundled', 'quality-gates', 'run-quality-gates.mjs')
|
|
52
104
|
: null;
|
|
53
105
|
|
|
54
|
-
// Option
|
|
106
|
+
// Option 4: Check node_modules for quality-gates package (prioritize published package)
|
|
55
107
|
const nodeModulesPaths = [
|
|
56
108
|
// Published npm package (priority)
|
|
57
109
|
path.join(
|
|
@@ -69,6 +121,8 @@ async function qualityGatesCommand(options = {}) {
|
|
|
69
121
|
// Try all possible paths in order
|
|
70
122
|
if (fs.existsSync(monorepoRunner)) {
|
|
71
123
|
qualityGatesRunner = monorepoRunner;
|
|
124
|
+
} else if (globalCliPath) {
|
|
125
|
+
qualityGatesRunner = globalCliPath;
|
|
72
126
|
} else if (bundledRunner && fs.existsSync(bundledRunner)) {
|
|
73
127
|
qualityGatesRunner = bundledRunner;
|
|
74
128
|
} else {
|
|
@@ -132,14 +186,98 @@ async function qualityGatesCommand(options = {}) {
|
|
|
132
186
|
}
|
|
133
187
|
}
|
|
134
188
|
|
|
135
|
-
//
|
|
189
|
+
// Option 5: Try npx (no installation required) - works if Node.js is available
|
|
136
190
|
if (!qualityGatesRunner) {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
'
|
|
141
|
-
|
|
142
|
-
|
|
191
|
+
try {
|
|
192
|
+
const { execSync } = require('child_process');
|
|
193
|
+
// Check if npx is available
|
|
194
|
+
execSync('command -v npx', { encoding: 'utf8', stdio: 'ignore' });
|
|
195
|
+
|
|
196
|
+
Output.info('Using npx to run quality gates (no installation required)...');
|
|
197
|
+
|
|
198
|
+
// Build npx command - the package exposes 'caws-quality-gates' bin command
|
|
199
|
+
// Use npx to download and run without installing
|
|
200
|
+
const npxArgs = ['npx', '--yes', '@paths.design/quality-gates'];
|
|
201
|
+
|
|
202
|
+
// Map CLI options to runner options
|
|
203
|
+
if (options.ci) {
|
|
204
|
+
npxArgs.push('--ci');
|
|
205
|
+
}
|
|
206
|
+
if (options.json) {
|
|
207
|
+
npxArgs.push('--json');
|
|
208
|
+
}
|
|
209
|
+
if (options.gates && options.gates.trim()) {
|
|
210
|
+
npxArgs.push('--gates', options.gates.trim());
|
|
211
|
+
}
|
|
212
|
+
if (options.fix) {
|
|
213
|
+
npxArgs.push('--fix');
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
Output.progress('Executing quality gates via npx...');
|
|
217
|
+
Output.info(`Command: ${npxArgs.join(' ')}`);
|
|
218
|
+
|
|
219
|
+
// Execute via npx
|
|
220
|
+
const { execSync: execSyncNpx } = require('child_process');
|
|
221
|
+
execSyncNpx(npxArgs.join(' '), {
|
|
222
|
+
stdio: 'inherit',
|
|
223
|
+
cwd: projectRoot,
|
|
224
|
+
env: {
|
|
225
|
+
...process.env,
|
|
226
|
+
CAWS_CLI_INTEGRATION: 'true',
|
|
227
|
+
CAWS_CLI_VERSION: require(path.join(cliPackageDir, 'package.json')).version,
|
|
228
|
+
},
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
Output.success('Quality gates completed successfully');
|
|
232
|
+
return;
|
|
233
|
+
} catch (npxError) {
|
|
234
|
+
// npx not available or failed - continue to error message
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// If still no runner found, provide helpful error with language-agnostic suggestions
|
|
239
|
+
if (!qualityGatesRunner) {
|
|
240
|
+
// Check if Node.js/npx is available (language-agnostic check)
|
|
241
|
+
let hasNodeJs = false;
|
|
242
|
+
try {
|
|
243
|
+
const { execSync } = require('child_process');
|
|
244
|
+
execSync('command -v node', { encoding: 'utf8', stdio: 'ignore' });
|
|
245
|
+
execSync('command -v npx', { encoding: 'utf8', stdio: 'ignore' });
|
|
246
|
+
hasNodeJs = true;
|
|
247
|
+
} catch (e) {
|
|
248
|
+
// Node.js/npx not available
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
const suggestions = [];
|
|
252
|
+
|
|
253
|
+
if (hasNodeJs) {
|
|
254
|
+
// Node.js available - suggest npx (works for any language, no installation)
|
|
255
|
+
suggestions.push(
|
|
256
|
+
'Use npx (no installation required): npx --yes @paths.design/quality-gates'
|
|
257
|
+
);
|
|
258
|
+
suggestions.push('Install globally: npm install -g @paths.design/quality-gates');
|
|
259
|
+
suggestions.push('Install locally: npm install --save-dev @paths.design/quality-gates');
|
|
260
|
+
} else {
|
|
261
|
+
// Node.js not available - suggest installation or alternatives
|
|
262
|
+
suggestions.push('Install Node.js to use quality gates: https://nodejs.org/');
|
|
263
|
+
suggestions.push(
|
|
264
|
+
'Then use: npx --yes @paths.design/quality-gates (no installation required)'
|
|
265
|
+
);
|
|
266
|
+
suggestions.push('Or install globally: npm install -g @paths.design/quality-gates');
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Language-agnostic fallback options (if they exist)
|
|
270
|
+
const pythonScript = path.join(projectRoot, 'scripts', 'simple_gates.py');
|
|
271
|
+
const makefile = path.join(projectRoot, 'Makefile');
|
|
272
|
+
|
|
273
|
+
if (fs.existsSync(pythonScript)) {
|
|
274
|
+
suggestions.push(`Use project script: python3 ${pythonScript} all --tier 2`);
|
|
275
|
+
}
|
|
276
|
+
if (fs.existsSync(makefile)) {
|
|
277
|
+
suggestions.push('Use Makefile target: make caws-gates');
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
suggestions.push('Run from CAWS monorepo root (if developing CAWS itself)');
|
|
143
281
|
|
|
144
282
|
throw new Error(
|
|
145
283
|
'Quality gates runner not found.\n\n' +
|
package/dist/commands/specs.js
CHANGED
|
@@ -154,9 +154,13 @@ async function createSpec(id, options = {}) {
|
|
|
154
154
|
console.log(chalk.blue('ā¹ļø Spec creation canceled.'));
|
|
155
155
|
return null;
|
|
156
156
|
} else if (answer === 'rename') {
|
|
157
|
-
// Generate new name with
|
|
158
|
-
|
|
159
|
-
const
|
|
157
|
+
// Generate new name with valid PREFIX-NUMBER format
|
|
158
|
+
// Extract prefix from existing ID or use default
|
|
159
|
+
const prefixMatch = id.match(/^([A-Z]+)-\d+$/);
|
|
160
|
+
const prefix = prefixMatch ? prefixMatch[1] : 'FEAT';
|
|
161
|
+
// Generate sequential number based on timestamp
|
|
162
|
+
const number = Date.now().toString().slice(-6); // Last 6 digits of timestamp
|
|
163
|
+
const newId = `${prefix}-${number}`;
|
|
160
164
|
console.log(chalk.blue(`š Creating spec with new name: ${newId}`));
|
|
161
165
|
return await createSpec(newId, { ...options, interactive: false });
|
|
162
166
|
} else if (answer === 'merge') {
|
|
@@ -183,9 +187,10 @@ async function createSpec(id, options = {}) {
|
|
|
183
187
|
// Ensure specs directory exists
|
|
184
188
|
await fs.ensureDir(SPECS_DIR);
|
|
185
189
|
|
|
186
|
-
// Generate spec content
|
|
187
|
-
|
|
188
|
-
|
|
190
|
+
// Generate spec content with all required fields
|
|
191
|
+
// Merge template carefully to preserve required fields and structure
|
|
192
|
+
const defaultSpec = {
|
|
193
|
+
id, // Always use the provided id parameter
|
|
189
194
|
type,
|
|
190
195
|
title,
|
|
191
196
|
status: 'draft',
|
|
@@ -193,8 +198,64 @@ async function createSpec(id, options = {}) {
|
|
|
193
198
|
mode,
|
|
194
199
|
created_at: new Date().toISOString(),
|
|
195
200
|
updated_at: new Date().toISOString(),
|
|
196
|
-
|
|
201
|
+
// Required fields for validation
|
|
202
|
+
blast_radius: {
|
|
203
|
+
modules: [],
|
|
204
|
+
data_migration: false,
|
|
205
|
+
},
|
|
206
|
+
operational_rollback_slo: '5m',
|
|
207
|
+
scope: {
|
|
208
|
+
in: ['src/', 'tests/'],
|
|
209
|
+
out: ['node_modules/', 'dist/', 'build/'],
|
|
210
|
+
},
|
|
211
|
+
invariants: ['System maintains data consistency'],
|
|
212
|
+
acceptance: [], // Note: validation expects 'acceptance', not 'acceptance_criteria'
|
|
213
|
+
acceptance_criteria: [], // Keep for backward compatibility
|
|
214
|
+
non_functional: {
|
|
215
|
+
a11y: [],
|
|
216
|
+
perf: {},
|
|
217
|
+
security: [],
|
|
218
|
+
},
|
|
219
|
+
contracts: [],
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
// Merge template, but preserve required structure
|
|
223
|
+
// Map template.criteria to acceptance if present
|
|
224
|
+
const templateAcceptance = template?.criteria || template?.acceptance;
|
|
225
|
+
|
|
226
|
+
const specContent = {
|
|
227
|
+
...defaultSpec,
|
|
197
228
|
...(template || {}),
|
|
229
|
+
// Always preserve these critical fields
|
|
230
|
+
id, // Never allow template to override id
|
|
231
|
+
// Map criteria to acceptance if template uses criteria
|
|
232
|
+
acceptance: templateAcceptance || defaultSpec.acceptance,
|
|
233
|
+
acceptance_criteria: templateAcceptance || defaultSpec.acceptance_criteria,
|
|
234
|
+
// Deep merge scope if template provides it
|
|
235
|
+
scope: template?.scope
|
|
236
|
+
? {
|
|
237
|
+
in: template.scope.in || defaultSpec.scope.in,
|
|
238
|
+
out: template.scope.out || defaultSpec.scope.out,
|
|
239
|
+
}
|
|
240
|
+
: defaultSpec.scope,
|
|
241
|
+
// Deep merge blast_radius if template provides it
|
|
242
|
+
blast_radius: template?.blast_radius
|
|
243
|
+
? {
|
|
244
|
+
modules: template.blast_radius.modules || defaultSpec.blast_radius.modules,
|
|
245
|
+
data_migration:
|
|
246
|
+
template.blast_radius.data_migration !== undefined
|
|
247
|
+
? template.blast_radius.data_migration
|
|
248
|
+
: defaultSpec.blast_radius.data_migration,
|
|
249
|
+
}
|
|
250
|
+
: defaultSpec.blast_radius,
|
|
251
|
+
// Deep merge non_functional if template provides it
|
|
252
|
+
non_functional: template?.non_functional
|
|
253
|
+
? {
|
|
254
|
+
a11y: template.non_functional.a11y || defaultSpec.non_functional.a11y,
|
|
255
|
+
perf: template.non_functional.perf || defaultSpec.non_functional.perf,
|
|
256
|
+
security: template.non_functional.security || defaultSpec.non_functional.security,
|
|
257
|
+
}
|
|
258
|
+
: defaultSpec.non_functional,
|
|
198
259
|
};
|
|
199
260
|
|
|
200
261
|
// Create file path
|
|
@@ -202,7 +263,46 @@ async function createSpec(id, options = {}) {
|
|
|
202
263
|
const filePath = path.join(SPECS_DIR, fileName);
|
|
203
264
|
|
|
204
265
|
// Write spec file
|
|
205
|
-
|
|
266
|
+
const yamlContent = yaml.dump(specContent, { indent: 2 });
|
|
267
|
+
await fs.writeFile(filePath, yamlContent);
|
|
268
|
+
|
|
269
|
+
// Validate written file (YAML syntax and structure)
|
|
270
|
+
try {
|
|
271
|
+
const writtenContent = await fs.readFile(filePath, 'utf8');
|
|
272
|
+
const parsed = yaml.load(writtenContent);
|
|
273
|
+
|
|
274
|
+
// Validate YAML syntax was preserved
|
|
275
|
+
if (!parsed || typeof parsed !== 'object') {
|
|
276
|
+
await fs.remove(filePath);
|
|
277
|
+
throw new Error('Failed to parse written spec file - invalid YAML structure');
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// Validate spec structure using CAWS validation
|
|
281
|
+
const { validateWorkingSpec } = require('../validation/spec-validation');
|
|
282
|
+
const validation = validateWorkingSpec(parsed);
|
|
283
|
+
|
|
284
|
+
if (!validation.valid) {
|
|
285
|
+
await fs.remove(filePath);
|
|
286
|
+
const errorMessages = validation.errors
|
|
287
|
+
.map((e) => `${e.instancePath}: ${e.message}`)
|
|
288
|
+
.join('; ');
|
|
289
|
+
throw new Error(`Spec validation failed: ${errorMessages}`);
|
|
290
|
+
}
|
|
291
|
+
} catch (error) {
|
|
292
|
+
// Clean up invalid file if it exists
|
|
293
|
+
if (await fs.pathExists(filePath)) {
|
|
294
|
+
await fs.remove(filePath);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// Re-throw with helpful message
|
|
298
|
+
if (error.message.includes('YAMLException') || error.message.includes('yaml')) {
|
|
299
|
+
throw new Error(
|
|
300
|
+
`Failed to create valid spec: YAML syntax error. ${error.message}\n` +
|
|
301
|
+
'š” Consider using the interactive mode: caws specs create <id> --interactive'
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
throw error;
|
|
305
|
+
}
|
|
206
306
|
|
|
207
307
|
// Update registry
|
|
208
308
|
const registry = await loadSpecsRegistry();
|
|
@@ -403,9 +503,10 @@ function displaySpecDetails(spec) {
|
|
|
403
503
|
/**
|
|
404
504
|
* Migrate from legacy working-spec.yaml to feature-specific specs
|
|
405
505
|
* @param {Object} options - Migration options
|
|
506
|
+
* @param {Function} [createSpecFn] - Function to create specs (for testing)
|
|
406
507
|
* @returns {Promise<Object>} Migration result
|
|
407
508
|
*/
|
|
408
|
-
async function migrateFromLegacy(options = {}) {
|
|
509
|
+
async function migrateFromLegacy(options = {}, createSpecFn = createSpec) {
|
|
409
510
|
const fs = require('fs-extra');
|
|
410
511
|
const path = require('path');
|
|
411
512
|
const yaml = require('js-yaml');
|
|
@@ -422,6 +523,14 @@ async function migrateFromLegacy(options = {}) {
|
|
|
422
523
|
const legacyContent = await fs.readFile(legacyPath, 'utf8');
|
|
423
524
|
const legacySpec = yaml.load(legacyContent);
|
|
424
525
|
|
|
526
|
+
if (!legacySpec) {
|
|
527
|
+
throw new Error('Legacy working-spec.yaml is empty or invalid');
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
if (!legacySpec.acceptance || !Array.isArray(legacySpec.acceptance)) {
|
|
531
|
+
throw new Error('Legacy working-spec.yaml must have an acceptance array');
|
|
532
|
+
}
|
|
533
|
+
|
|
425
534
|
// Suggest feature breakdown based on acceptance criteria
|
|
426
535
|
const features = suggestFeatureBreakdown(legacySpec);
|
|
427
536
|
|
|
@@ -441,15 +550,32 @@ async function migrateFromLegacy(options = {}) {
|
|
|
441
550
|
}
|
|
442
551
|
|
|
443
552
|
if (options.features && options.features.length > 0) {
|
|
553
|
+
// Filter by original feature IDs (before transformation)
|
|
444
554
|
selectedFeatures = features.filter((f) => options.features.includes(f.id));
|
|
445
|
-
|
|
555
|
+
if (selectedFeatures.length === 0) {
|
|
556
|
+
const errorMsg = `No features found matching: ${options.features.join(', ')}. Available features: ${features.map((f) => f.id).join(', ')}`;
|
|
557
|
+
console.log(chalk.yellow(`ā ļø ${errorMsg}`));
|
|
558
|
+
throw new Error(errorMsg);
|
|
559
|
+
} else {
|
|
560
|
+
console.log(chalk.blue(`\nš Migrating selected features: ${options.features.join(', ')}`));
|
|
561
|
+
}
|
|
446
562
|
}
|
|
447
563
|
|
|
448
564
|
// Create each feature spec
|
|
449
565
|
const createdSpecs = [];
|
|
566
|
+
let featureCounter = 1;
|
|
450
567
|
for (const feature of selectedFeatures) {
|
|
451
568
|
try {
|
|
452
|
-
|
|
569
|
+
// Transform feature ID to proper format (PREFIX-NUMBER) if needed
|
|
570
|
+
let specId = feature.id;
|
|
571
|
+
if (!/^[A-Z]+-\d+$/.test(specId)) {
|
|
572
|
+
// Convert 'auth' -> 'FEAT-001', 'payment' -> 'FEAT-002', etc.
|
|
573
|
+
const prefix = specId.toUpperCase().replace(/[^A-Z0-9]/g, '');
|
|
574
|
+
specId = `${prefix || 'FEAT'}-${String(featureCounter).padStart(3, '0')}`;
|
|
575
|
+
featureCounter++;
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
await createSpecFn(specId, {
|
|
453
579
|
type: 'feature',
|
|
454
580
|
title: feature.title,
|
|
455
581
|
risk_tier: 'T3', // Default tier
|
|
@@ -457,10 +583,14 @@ async function migrateFromLegacy(options = {}) {
|
|
|
457
583
|
template: feature,
|
|
458
584
|
});
|
|
459
585
|
|
|
460
|
-
createdSpecs.push(
|
|
461
|
-
console.log(chalk.green(` ā
Created spec: ${
|
|
586
|
+
createdSpecs.push(specId);
|
|
587
|
+
console.log(chalk.green(` ā
Created spec: ${specId}`));
|
|
462
588
|
} catch (error) {
|
|
589
|
+
// Log full error details for debugging
|
|
463
590
|
console.log(chalk.red(` ā Failed to create spec ${feature.id}: ${error.message}`));
|
|
591
|
+
if (process.env.DEBUG_MIGRATION) {
|
|
592
|
+
console.log(chalk.gray(` Error details: ${error.stack}`));
|
|
593
|
+
}
|
|
464
594
|
}
|
|
465
595
|
}
|
|
466
596
|
|
|
@@ -589,7 +719,11 @@ async function specsCommand(action, options = {}) {
|
|
|
589
719
|
}
|
|
590
720
|
|
|
591
721
|
case 'migrate': {
|
|
592
|
-
|
|
722
|
+
// Allow tests to inject createSpec function
|
|
723
|
+
const createSpecFn = options._createSpecFn || createSpec;
|
|
724
|
+
const migrationOptions = { ...options };
|
|
725
|
+
delete migrationOptions._createSpecFn; // Remove test-only option
|
|
726
|
+
const result = await migrateFromLegacy(migrationOptions, createSpecFn);
|
|
593
727
|
|
|
594
728
|
return outputResult({
|
|
595
729
|
command: 'specs migrate',
|
package/dist/commands/status.js
CHANGED
|
@@ -182,10 +182,10 @@ async function loadWaiverStatus() {
|
|
|
182
182
|
*/
|
|
183
183
|
async function checkQualityGates() {
|
|
184
184
|
// For now, return a placeholder
|
|
185
|
-
//
|
|
185
|
+
// Quality gates are available via CLI or MCP
|
|
186
186
|
return {
|
|
187
187
|
checked: false,
|
|
188
|
-
message: 'Run:
|
|
188
|
+
message: 'Run: caws quality-gates or use MCP tool caws_quality_gates_run for full gate status',
|
|
189
189
|
};
|
|
190
190
|
}
|
|
191
191
|
|
package/dist/commands/tool.js
CHANGED
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
* @author @darianrosebrook
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
const path = require('path');
|
|
8
7
|
const { commandWrapper, Output } = require('../utils/command-wrapper');
|
|
9
8
|
|
|
10
9
|
// Import tool system
|
|
@@ -23,9 +22,8 @@ async function initializeToolSystem() {
|
|
|
23
22
|
if (toolLoader) return toolLoader;
|
|
24
23
|
|
|
25
24
|
try {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
});
|
|
25
|
+
// ToolLoader now checks .caws/tools first, then falls back to legacy location
|
|
26
|
+
toolLoader = new ToolLoader();
|
|
29
27
|
|
|
30
28
|
toolValidator = new ToolValidator();
|
|
31
29
|
|