@paths.design/caws-cli 7.0.1 → 7.0.3
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 +26 -20
- package/dist/commands/init.js +72 -5
- package/dist/commands/specs.js +40 -1
- package/dist/commands/status.js +2 -2
- package/dist/commands/templates.js +10 -0
- package/dist/commands/tool.js +2 -3
- package/dist/commands/validate.js +12 -0
- package/dist/config/index.js +17 -8
- package/dist/generators/working-spec.js +42 -9
- package/dist/index.js +3 -1
- package/dist/scaffold/cursor-hooks.js +10 -2
- package/dist/scaffold/git-hooks.js +189 -32
- package/dist/scaffold/index.js +105 -17
- package/dist/templates/.caws/tools/README.md +20 -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 +34 -6
- package/dist/utils/git-lock.js +118 -0
- package/dist/utils/gitignore-updater.js +148 -0
- package/dist/utils/quality-gates.js +47 -7
- package/dist/utils/spec-resolver.js +23 -3
- package/dist/utils/yaml-validation.js +155 -0
- package/dist/validation/spec-validation.js +105 -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 +20 -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/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
|
@@ -238,6 +238,42 @@ function validateWorkingSpecWithSuggestions(spec, options = {}) {
|
|
|
238
238
|
}
|
|
239
239
|
}
|
|
240
240
|
|
|
241
|
+
// Validate scope.out doesn't contain glob patterns
|
|
242
|
+
if (spec.scope && spec.scope.out && Array.isArray(spec.scope.out)) {
|
|
243
|
+
const globPatterns = spec.scope.out.filter(
|
|
244
|
+
(pattern) => pattern.includes('*') || pattern.includes('?')
|
|
245
|
+
);
|
|
246
|
+
if (globPatterns.length > 0) {
|
|
247
|
+
errors.push({
|
|
248
|
+
instancePath: '/scope/out',
|
|
249
|
+
message: `Unsupported glob patterns in scope.out: ${globPatterns.join(', ')}`,
|
|
250
|
+
suggestion:
|
|
251
|
+
'Use directory paths only (e.g., __pycache__/ instead of *.pyc or **/*.pyc). Python cache files are already covered by __pycache__/',
|
|
252
|
+
canAutoFix: true,
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
// Auto-fix: remove glob patterns and keep only directory paths
|
|
256
|
+
if (autoFix) {
|
|
257
|
+
const fixedOut = spec.scope.out
|
|
258
|
+
.filter((pattern) => !pattern.includes('*') && !pattern.includes('?'))
|
|
259
|
+
.map((pattern) => {
|
|
260
|
+
// Ensure directory paths end with /
|
|
261
|
+
if (!pattern.includes('.') && !pattern.endsWith('/')) {
|
|
262
|
+
return pattern + '/';
|
|
263
|
+
}
|
|
264
|
+
return pattern;
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
fixes.push({
|
|
268
|
+
field: 'scope.out',
|
|
269
|
+
value: fixedOut,
|
|
270
|
+
description: `Removed glob patterns from scope.out: ${globPatterns.join(', ')}`,
|
|
271
|
+
reason: 'Glob patterns are not supported in scope.out',
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
241
277
|
// Auto-fix missing scope.out
|
|
242
278
|
if (spec.scope && !spec.scope.out) {
|
|
243
279
|
fixes.push({
|
|
@@ -325,11 +361,36 @@ function validateWorkingSpecWithSuggestions(spec, options = {}) {
|
|
|
325
361
|
// Tier-specific validations
|
|
326
362
|
if (spec.risk_tier === 1 || spec.risk_tier === 2) {
|
|
327
363
|
if (!spec.contracts || spec.contracts.length === 0) {
|
|
364
|
+
const isChoreMode = spec.mode === 'chore';
|
|
365
|
+
const suggestion = isChoreMode
|
|
366
|
+
? 'For infrastructure/setup work, add a minimal project_setup contract or create a waiver'
|
|
367
|
+
: 'Add API contracts (OpenAPI, GraphQL, etc.) or change mode to "chore" for maintenance work';
|
|
368
|
+
|
|
328
369
|
errors.push({
|
|
329
370
|
instancePath: '/contracts',
|
|
330
|
-
message:
|
|
331
|
-
suggestion:
|
|
371
|
+
message: `Contracts required for Tier ${spec.risk_tier} changes`,
|
|
372
|
+
suggestion: suggestion,
|
|
332
373
|
canAutoFix: false,
|
|
374
|
+
example: isChoreMode
|
|
375
|
+
? {
|
|
376
|
+
contracts: [
|
|
377
|
+
{
|
|
378
|
+
type: 'project_setup',
|
|
379
|
+
path: '.caws/working-spec.yaml',
|
|
380
|
+
description:
|
|
381
|
+
'Project-level CAWS configuration. Feature-specific contracts will be added as features are developed.',
|
|
382
|
+
},
|
|
383
|
+
],
|
|
384
|
+
}
|
|
385
|
+
: {
|
|
386
|
+
contracts: [
|
|
387
|
+
{
|
|
388
|
+
type: 'openapi',
|
|
389
|
+
path: 'docs/api/feature.yaml',
|
|
390
|
+
version: '1.0.0',
|
|
391
|
+
},
|
|
392
|
+
],
|
|
393
|
+
},
|
|
333
394
|
});
|
|
334
395
|
}
|
|
335
396
|
}
|
|
@@ -368,6 +429,48 @@ function validateWorkingSpecWithSuggestions(spec, options = {}) {
|
|
|
368
429
|
}
|
|
369
430
|
}
|
|
370
431
|
|
|
432
|
+
// Validate rollback format if present (for all tiers)
|
|
433
|
+
if (spec.rollback !== undefined) {
|
|
434
|
+
if (!Array.isArray(spec.rollback)) {
|
|
435
|
+
errors.push({
|
|
436
|
+
instancePath: '/rollback',
|
|
437
|
+
message: 'rollback must be an array of strings',
|
|
438
|
+
suggestion: 'Use format: ["Step 1", "Step 2", "Step 3"]',
|
|
439
|
+
canAutoFix: false,
|
|
440
|
+
});
|
|
441
|
+
} else {
|
|
442
|
+
// Check for duplicates
|
|
443
|
+
const uniqueSteps = [...new Set(spec.rollback)];
|
|
444
|
+
if (uniqueSteps.length !== spec.rollback.length) {
|
|
445
|
+
warnings.push({
|
|
446
|
+
instancePath: '/rollback',
|
|
447
|
+
message: 'Duplicate entries found in rollback array',
|
|
448
|
+
suggestion: 'Remove duplicate entries',
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
if (autoFix) {
|
|
452
|
+
fixes.push({
|
|
453
|
+
field: 'rollback',
|
|
454
|
+
value: uniqueSteps,
|
|
455
|
+
description: 'Removed duplicate rollback entries',
|
|
456
|
+
reason: 'Duplicate entries detected',
|
|
457
|
+
});
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
// Validate each entry is a string
|
|
462
|
+
const invalidEntries = spec.rollback.filter((entry) => typeof entry !== 'string');
|
|
463
|
+
if (invalidEntries.length > 0) {
|
|
464
|
+
errors.push({
|
|
465
|
+
instancePath: '/rollback',
|
|
466
|
+
message: `Invalid rollback entries (must be strings): ${invalidEntries.length}`,
|
|
467
|
+
suggestion: 'All rollback entries must be string descriptions',
|
|
468
|
+
canAutoFix: false,
|
|
469
|
+
});
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
|
|
371
474
|
// Validate waiver_ids format if present
|
|
372
475
|
if (spec.waiver_ids) {
|
|
373
476
|
if (!Array.isArray(spec.waiver_ids)) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@paths.design/caws-cli",
|
|
3
|
-
"version": "7.0.
|
|
3
|
+
"version": "7.0.3",
|
|
4
4
|
"description": "CAWS CLI - Coding Agent Workflow System command line tools",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"templates"
|
|
14
14
|
],
|
|
15
15
|
"scripts": {
|
|
16
|
-
"build": "mkdir -p dist && cp -r src/* dist/",
|
|
16
|
+
"build": "mkdir -p dist && cp -r src/* dist/ && cp -r templates dist/ 2>/dev/null || true",
|
|
17
17
|
"dev": "mkdir -p dist && cp -r src/* dist/ && node dist/index.js",
|
|
18
18
|
"typecheck": "tsc --emitDeclarationOnly --outDir dist",
|
|
19
19
|
"start": "node dist/index.js",
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"title": "CAWS Waivers Configuration",
|
|
4
|
+
"type": "object",
|
|
5
|
+
"patternProperties": {
|
|
6
|
+
".*": {
|
|
7
|
+
"type": "object",
|
|
8
|
+
"required": ["gate", "reason", "owner", "expiry"],
|
|
9
|
+
"properties": {
|
|
10
|
+
"gate": {
|
|
11
|
+
"type": "string",
|
|
12
|
+
"enum": ["coverage", "mutation", "contracts", "a11y", "perf", "security"]
|
|
13
|
+
},
|
|
14
|
+
"reason": { "type": "string", "minLength": 10 },
|
|
15
|
+
"owner": { "type": "string" },
|
|
16
|
+
"expiry": { "type": "string", "format": "date-time" },
|
|
17
|
+
"compensating_control": { "type": "string" },
|
|
18
|
+
"ticket_url": { "type": "string", "format": "uri" },
|
|
19
|
+
"approved_by": { "type": "string" },
|
|
20
|
+
"created_at": { "type": "string", "format": "date-time" },
|
|
21
|
+
"status": {
|
|
22
|
+
"type": "string",
|
|
23
|
+
"enum": ["active", "expired", "revoked"],
|
|
24
|
+
"default": "active"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"additionalProperties": false
|
|
30
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"title": "CAWS Working Spec",
|
|
4
|
+
"type": "object",
|
|
5
|
+
"required": [
|
|
6
|
+
"id",
|
|
7
|
+
"title",
|
|
8
|
+
"risk_tier",
|
|
9
|
+
"mode",
|
|
10
|
+
"blast_radius",
|
|
11
|
+
"operational_rollback_slo",
|
|
12
|
+
"scope",
|
|
13
|
+
"invariants",
|
|
14
|
+
"acceptance",
|
|
15
|
+
"non_functional",
|
|
16
|
+
"contracts"
|
|
17
|
+
],
|
|
18
|
+
"properties": {
|
|
19
|
+
"id": { "type": "string", "pattern": "^(PROJ|FEAT|FIX|ARCH)-\\d{4}$" },
|
|
20
|
+
"title": { "type": "string", "minLength": 10, "maxLength": 200 },
|
|
21
|
+
"risk_tier": { "type": ["integer", "string"], "enum": [1, 2, 3, "1", "2", "3"] },
|
|
22
|
+
"mode": { "type": "string", "enum": ["feature", "refactor", "fix", "doc", "chore"] },
|
|
23
|
+
"waiver_ids": {
|
|
24
|
+
"type": "array",
|
|
25
|
+
"items": { "type": "string", "pattern": "^WV-\\d{4}$" },
|
|
26
|
+
"description": "IDs of active waivers applying to this spec"
|
|
27
|
+
},
|
|
28
|
+
"blast_radius": {
|
|
29
|
+
"type": "object",
|
|
30
|
+
"required": ["modules"],
|
|
31
|
+
"properties": {
|
|
32
|
+
"modules": { "type": "array", "items": { "type": "string" } },
|
|
33
|
+
"data_migration": { "type": "boolean" }
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"operational_rollback_slo": { "type": "string" },
|
|
37
|
+
"scope": {
|
|
38
|
+
"type": "object",
|
|
39
|
+
"required": ["in", "out"],
|
|
40
|
+
"properties": {
|
|
41
|
+
"in": { "type": "array", "items": { "type": "string" }, "minItems": 1 },
|
|
42
|
+
"out": { "type": "array", "items": { "type": "string" } }
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
"invariants": { "type": "array", "items": { "type": "string" }, "minItems": 1 },
|
|
46
|
+
"acceptance": {
|
|
47
|
+
"type": "array",
|
|
48
|
+
"minItems": 1,
|
|
49
|
+
"items": {
|
|
50
|
+
"type": "object",
|
|
51
|
+
"required": ["id", "given", "when", "then"],
|
|
52
|
+
"properties": {
|
|
53
|
+
"id": { "type": "string", "pattern": "^A\\d+$" },
|
|
54
|
+
"given": { "type": "string" },
|
|
55
|
+
"when": { "type": "string" },
|
|
56
|
+
"then": { "type": "string" }
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
"non_functional": {
|
|
61
|
+
"type": "object",
|
|
62
|
+
"properties": {
|
|
63
|
+
"a11y": { "type": "array", "items": { "type": "string" } },
|
|
64
|
+
"perf": {
|
|
65
|
+
"type": "object",
|
|
66
|
+
"properties": {
|
|
67
|
+
"api_p95_ms": { "type": "integer", "minimum": 1 },
|
|
68
|
+
"lcp_ms": { "type": "integer", "minimum": 1 }
|
|
69
|
+
},
|
|
70
|
+
"additionalProperties": false
|
|
71
|
+
},
|
|
72
|
+
"security": { "type": "array", "items": { "type": "string" } }
|
|
73
|
+
},
|
|
74
|
+
"additionalProperties": false
|
|
75
|
+
},
|
|
76
|
+
"contracts": {
|
|
77
|
+
"type": "array",
|
|
78
|
+
"minItems": 1,
|
|
79
|
+
"items": {
|
|
80
|
+
"type": "object",
|
|
81
|
+
"required": ["type", "path"],
|
|
82
|
+
"properties": {
|
|
83
|
+
"type": { "type": "string", "enum": ["openapi", "graphql", "proto", "pact"] },
|
|
84
|
+
"path": { "type": "string" }
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
"observability": {
|
|
89
|
+
"type": "object",
|
|
90
|
+
"properties": {
|
|
91
|
+
"logs": { "type": "array", "items": { "type": "string" } },
|
|
92
|
+
"metrics": { "type": "array", "items": { "type": "string" } },
|
|
93
|
+
"traces": { "type": "array", "items": { "type": "string" } }
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
"migrations": { "type": "array", "items": { "type": "string" } },
|
|
97
|
+
"rollback": { "type": "array", "items": { "type": "string" } },
|
|
98
|
+
"experiment_mode": {
|
|
99
|
+
"type": "boolean",
|
|
100
|
+
"description": "Enables experimental mode with reduced requirements"
|
|
101
|
+
},
|
|
102
|
+
"timeboxed_hours": {
|
|
103
|
+
"type": "integer",
|
|
104
|
+
"minimum": 1,
|
|
105
|
+
"description": "Time limit for experimental features in hours"
|
|
106
|
+
},
|
|
107
|
+
"human_override": {
|
|
108
|
+
"type": "object",
|
|
109
|
+
"properties": {
|
|
110
|
+
"approved_by": { "type": "string" },
|
|
111
|
+
"reason": { "type": "string" },
|
|
112
|
+
"waived_requirements": {
|
|
113
|
+
"type": "array",
|
|
114
|
+
"items": {
|
|
115
|
+
"type": "string",
|
|
116
|
+
"enum": ["mutation_testing", "contract_tests", "coverage", "manual_review"]
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
"expiry_date": { "type": "string", "format": "date-time" }
|
|
120
|
+
},
|
|
121
|
+
"required": ["approved_by", "reason"]
|
|
122
|
+
},
|
|
123
|
+
"ai_assessment": {
|
|
124
|
+
"type": "object",
|
|
125
|
+
"properties": {
|
|
126
|
+
"confidence_level": { "type": "integer", "minimum": 1, "maximum": 10 },
|
|
127
|
+
"uncertainty_areas": { "type": "array", "items": { "type": "string" } },
|
|
128
|
+
"recommended_pairing": { "type": "boolean" }
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
"additionalProperties": false
|
|
133
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
id: '{{FEATURE_ID}}'
|
|
2
|
+
title: '{{FEATURE_TITLE}}'
|
|
3
|
+
risk_tier: { { TIER } }
|
|
4
|
+
scope:
|
|
5
|
+
in:
|
|
6
|
+
- '{{SCOPE_ITEM_1}}'
|
|
7
|
+
- '{{SCOPE_ITEM_2}}'
|
|
8
|
+
out:
|
|
9
|
+
- '{{OUT_OF_SCOPE_ITEM_1}}'
|
|
10
|
+
invariants:
|
|
11
|
+
- '{{BUSINESS_RULE_1}}'
|
|
12
|
+
- '{{BUSINESS_RULE_2}}'
|
|
13
|
+
acceptance:
|
|
14
|
+
- id: A1
|
|
15
|
+
given: '{{GIVEN_CONDITION}}'
|
|
16
|
+
when: '{{WHEN_ACTION}}'
|
|
17
|
+
then: '{{THEN_OUTCOME}}'
|
|
18
|
+
status: pending # pending | in_progress | completed
|
|
19
|
+
# Optional: detailed progress tracking
|
|
20
|
+
# tests:
|
|
21
|
+
# written: 0
|
|
22
|
+
# passing: 0
|
|
23
|
+
# coverage: 0.0
|
|
24
|
+
# last_updated: '2025-10-09T14:30:00Z'
|
|
25
|
+
- id: A2
|
|
26
|
+
given: '{{GIVEN_CONDITION_2}}'
|
|
27
|
+
when: '{{WHEN_ACTION_2}}'
|
|
28
|
+
then: '{{THEN_OUTCOME_2}}'
|
|
29
|
+
status: pending # pending | in_progress | completed
|
|
30
|
+
# Optional: detailed progress tracking
|
|
31
|
+
# tests:
|
|
32
|
+
# written: 0
|
|
33
|
+
# passing: 0
|
|
34
|
+
# coverage: 0.0
|
|
35
|
+
# last_updated: '2025-10-09T14:30:00Z'
|
|
36
|
+
non_functional:
|
|
37
|
+
a11y:
|
|
38
|
+
- '{{ACCESSIBILITY_REQUIREMENT}}'
|
|
39
|
+
perf:
|
|
40
|
+
api_p95_ms: { { PERF_BUDGET } }
|
|
41
|
+
lcp_ms: { { LCP_BUDGET } }
|
|
42
|
+
security:
|
|
43
|
+
- '{{SECURITY_REQUIREMENT}}'
|
|
44
|
+
contracts:
|
|
45
|
+
- type: '{{CONTRACT_TYPE}}'
|
|
46
|
+
path: '{{CONTRACT_PATH}}'
|
|
47
|
+
observability:
|
|
48
|
+
logs:
|
|
49
|
+
- '{{LOG_STATEMENT}}'
|
|
50
|
+
metrics:
|
|
51
|
+
- '{{METRIC_NAME}}'
|
|
52
|
+
traces:
|
|
53
|
+
- '{{TRACE_SPAN}}'
|
|
54
|
+
migrations:
|
|
55
|
+
- '{{MIGRATION_DESCRIPTION}}'
|
|
56
|
+
rollback:
|
|
57
|
+
- '{{ROLLBACK_STRATEGY}}'
|
|
58
|
+
# Optional: Enable for experimental features with reduced requirements
|
|
59
|
+
# experiment_mode: true
|
|
60
|
+
# timeboxed_hours: 24
|
|
61
|
+
|
|
62
|
+
# Optional: AI confidence assessment
|
|
63
|
+
# ai_assessment:
|
|
64
|
+
# confidence_level: 8
|
|
65
|
+
# uncertainty_areas: ["complex business logic", "performance implications"]
|
|
66
|
+
# recommended_pairing: false
|
|
67
|
+
|
|
68
|
+
# Optional: Human override for special cases (hotfixes, urgent changes)
|
|
69
|
+
# human_override:
|
|
70
|
+
# approved_by: "senior-dev-username"
|
|
71
|
+
# reason: "Urgent production fix - bypassing mutation tests for immediate deployment"
|
|
72
|
+
# waived_requirements: ["mutation_testing", "manual_review"]
|
|
73
|
+
# expiry_date: "2025-10-01T00:00:00Z"
|
|
74
|
+
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# CAWS Tools
|
|
2
|
+
|
|
3
|
+
This directory contains CAWS-specific tools that aren't available in the CLI.
|
|
4
|
+
|
|
5
|
+
## scope-guard.js
|
|
6
|
+
|
|
7
|
+
Enforces that experimental code stays within designated sandbox areas. Used by Cursor hooks for scope validation.
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# Validate experimental code containment
|
|
11
|
+
node .caws/tools/scope-guard.js validate
|
|
12
|
+
|
|
13
|
+
# Check containment status
|
|
14
|
+
node .caws/tools/scope-guard.js check .caws/working-spec.yaml
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
**Usage in Cursor Hooks:**
|
|
18
|
+
|
|
19
|
+
The `.cursor/hooks/scope-guard.sh` hook automatically uses this tool to validate file attachments against working spec scope boundaries.
|
|
20
|
+
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview CAWS Scope Guard
|
|
5
|
+
* Enforces that experimental code stays within designated sandbox areas
|
|
6
|
+
* @author @darianrosebrook
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const fs = require('fs');
|
|
10
|
+
const { execSync } = require('child_process');
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Check if experimental code is properly contained
|
|
14
|
+
* @param {string} workingSpecPath - Path to working spec file
|
|
15
|
+
* @returns {Object} Scope validation results
|
|
16
|
+
*/
|
|
17
|
+
function checkExperimentalContainment(workingSpecPath = '.caws/working-spec.yaml') {
|
|
18
|
+
try {
|
|
19
|
+
if (!fs.existsSync(workingSpecPath)) {
|
|
20
|
+
console.error('❌ Working spec not found:', workingSpecPath);
|
|
21
|
+
return { valid: false, errors: ['Working spec not found'] };
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const yaml = require('js-yaml');
|
|
25
|
+
const spec = yaml.load(fs.readFileSync(workingSpecPath, 'utf8'));
|
|
26
|
+
|
|
27
|
+
const results = {
|
|
28
|
+
valid: true,
|
|
29
|
+
errors: [],
|
|
30
|
+
warnings: [],
|
|
31
|
+
experimentalFiles: [],
|
|
32
|
+
nonExperimentalFiles: [],
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
// Only check if experimental mode is enabled
|
|
36
|
+
if (!spec.experimental_mode?.enabled) {
|
|
37
|
+
console.log('ℹ️ Experimental mode not enabled - skipping containment check');
|
|
38
|
+
return results;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const sandboxLocation = spec.experimental_mode.sandbox_location || 'experimental/';
|
|
42
|
+
console.log(`🔍 Checking containment for experimental code in: ${sandboxLocation}`);
|
|
43
|
+
|
|
44
|
+
// Get list of changed files (this would typically come from git diff)
|
|
45
|
+
const changedFiles = getChangedFiles();
|
|
46
|
+
|
|
47
|
+
if (changedFiles.length === 0) {
|
|
48
|
+
console.log('ℹ️ No files changed - skipping scope check');
|
|
49
|
+
return results;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Check each changed file
|
|
53
|
+
changedFiles.forEach((file) => {
|
|
54
|
+
const isInSandbox =
|
|
55
|
+
file.startsWith(sandboxLocation) ||
|
|
56
|
+
file.includes(`/${sandboxLocation}`) ||
|
|
57
|
+
file.includes(sandboxLocation);
|
|
58
|
+
|
|
59
|
+
if (isInSandbox) {
|
|
60
|
+
results.experimentalFiles.push(file);
|
|
61
|
+
console.log(`✅ Experimental file properly contained: ${file}`);
|
|
62
|
+
} else {
|
|
63
|
+
results.nonExperimentalFiles.push(file);
|
|
64
|
+
results.valid = false;
|
|
65
|
+
results.errors.push(`Experimental code found outside sandbox: ${file}`);
|
|
66
|
+
console.error(`❌ Experimental code outside sandbox: ${file}`);
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// Check if experimental files actually exist
|
|
71
|
+
results.experimentalFiles.forEach((file) => {
|
|
72
|
+
if (!fs.existsSync(file)) {
|
|
73
|
+
results.warnings.push(`Experimental file not found (may have been deleted): ${file}`);
|
|
74
|
+
console.warn(`⚠️ Experimental file not found: ${file}`);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
return results;
|
|
79
|
+
} catch (error) {
|
|
80
|
+
console.error('❌ Error checking experimental containment:', error.message);
|
|
81
|
+
return { valid: false, errors: [error.message] };
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Get list of changed files from git
|
|
87
|
+
* @returns {Array} List of changed file paths
|
|
88
|
+
*/
|
|
89
|
+
function getChangedFiles() {
|
|
90
|
+
try {
|
|
91
|
+
// Get files that are staged or modified
|
|
92
|
+
const staged = execSync('git diff --cached --name-only', { encoding: 'utf8' })
|
|
93
|
+
.split('\n')
|
|
94
|
+
.filter((file) => file.trim());
|
|
95
|
+
|
|
96
|
+
const modified = execSync('git diff --name-only', { encoding: 'utf8' })
|
|
97
|
+
.split('\n')
|
|
98
|
+
.filter((file) => file.trim());
|
|
99
|
+
|
|
100
|
+
// Combine and deduplicate
|
|
101
|
+
const allFiles = [...new Set([...staged, ...modified])];
|
|
102
|
+
|
|
103
|
+
// Filter out deleted files (they might still be in the diff)
|
|
104
|
+
return allFiles.filter((file) => {
|
|
105
|
+
try {
|
|
106
|
+
return fs.existsSync(file);
|
|
107
|
+
} catch {
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
} catch (error) {
|
|
112
|
+
console.warn('⚠️ Could not get changed files from git:', error.message);
|
|
113
|
+
return [];
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Validate that experimental code follows containment rules
|
|
119
|
+
* @param {string} workingSpecPath - Path to working spec file
|
|
120
|
+
*/
|
|
121
|
+
function validateExperimentalScope(workingSpecPath = '.caws/working-spec.yaml') {
|
|
122
|
+
console.log('🔍 Validating experimental code containment...');
|
|
123
|
+
|
|
124
|
+
const results = checkExperimentalContainment(workingSpecPath);
|
|
125
|
+
|
|
126
|
+
if (!results.valid) {
|
|
127
|
+
console.error('\n❌ Experimental containment validation failed:');
|
|
128
|
+
results.errors.forEach((error) => {
|
|
129
|
+
console.error(` - ${error}`);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
if (results.warnings.length > 0) {
|
|
133
|
+
console.warn('\n⚠️ Warnings:');
|
|
134
|
+
results.warnings.forEach((warning) => {
|
|
135
|
+
console.warn(` - ${warning}`);
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
console.error('\n💡 To fix containment issues:');
|
|
140
|
+
console.error(' 1. Move experimental code to the designated sandbox location');
|
|
141
|
+
console.error(' 2. Update the sandbox_location in your working spec');
|
|
142
|
+
console.error(' 3. Or disable experimental mode if this is production code');
|
|
143
|
+
|
|
144
|
+
process.exit(1);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (results.warnings.length > 0) {
|
|
148
|
+
console.warn('\n⚠️ Experimental containment warnings:');
|
|
149
|
+
results.warnings.forEach((warning) => {
|
|
150
|
+
console.warn(` - ${warning}`);
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
console.log('✅ Experimental code containment validated');
|
|
155
|
+
console.log(` - Files in sandbox: ${results.experimentalFiles.length}`);
|
|
156
|
+
console.log(` - Files outside sandbox: ${results.nonExperimentalFiles.length}`);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// CLI interface
|
|
160
|
+
if (require.main === module) {
|
|
161
|
+
const command = process.argv[2];
|
|
162
|
+
const specPath = process.argv[3] || '.caws/working-spec.yaml';
|
|
163
|
+
|
|
164
|
+
switch (command) {
|
|
165
|
+
case 'validate':
|
|
166
|
+
validateExperimentalScope(specPath);
|
|
167
|
+
break;
|
|
168
|
+
|
|
169
|
+
case 'check':
|
|
170
|
+
const results = checkExperimentalContainment(specPath);
|
|
171
|
+
console.log('\n📊 Containment Check Results:');
|
|
172
|
+
console.log(` Valid: ${results.valid}`);
|
|
173
|
+
console.log(` Experimental files: ${results.experimentalFiles.length}`);
|
|
174
|
+
console.log(` Non-experimental files: ${results.nonExperimentalFiles.length}`);
|
|
175
|
+
console.log(` Errors: ${results.errors.length}`);
|
|
176
|
+
console.log(` Warnings: ${results.warnings.length}`);
|
|
177
|
+
|
|
178
|
+
if (results.errors.length > 0) {
|
|
179
|
+
console.log('\n❌ Errors:');
|
|
180
|
+
results.errors.forEach((error) => console.log(` - ${error}`));
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (results.warnings.length > 0) {
|
|
184
|
+
console.log('\n⚠️ Warnings:');
|
|
185
|
+
results.warnings.forEach((warning) => console.log(` - ${warning}`));
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
process.exit(results.valid ? 0 : 1);
|
|
189
|
+
break;
|
|
190
|
+
|
|
191
|
+
default:
|
|
192
|
+
console.log('CAWS Scope Guard');
|
|
193
|
+
console.log('Usage:');
|
|
194
|
+
console.log(' node scope-guard.js validate [spec-path]');
|
|
195
|
+
console.log(' node scope-guard.js check [spec-path]');
|
|
196
|
+
console.log('');
|
|
197
|
+
console.log('Examples:');
|
|
198
|
+
console.log(' node scope-guard.js validate');
|
|
199
|
+
console.log(' node scope-guard.js check .caws/working-spec.yaml');
|
|
200
|
+
process.exit(1);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
module.exports = {
|
|
205
|
+
checkExperimentalContainment,
|
|
206
|
+
validateExperimentalScope,
|
|
207
|
+
getChangedFiles,
|
|
208
|
+
};
|