@paths.design/caws-cli 9.3.2 → 10.1.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/README.md +71 -32
- package/dist/budget-derivation.js +221 -74
- package/dist/commands/archive.js +67 -28
- package/dist/commands/burnup.js +20 -11
- package/dist/commands/diagnose.js +34 -22
- package/dist/commands/evaluate.js +41 -15
- package/dist/commands/gates.js +149 -0
- package/dist/commands/init.js +150 -19
- package/dist/commands/iterate.js +81 -4
- package/dist/commands/parallel.js +4 -0
- package/dist/commands/plan.js +9 -19
- package/dist/commands/provenance.js +53 -17
- package/dist/commands/quality-monitor.js +64 -45
- package/dist/commands/scope.js +264 -0
- package/dist/commands/sidecar.js +74 -0
- package/dist/commands/specs.js +381 -45
- package/dist/commands/status.js +117 -9
- package/dist/commands/templates.js +0 -8
- package/dist/commands/tutorial.js +10 -9
- package/dist/commands/validate.js +70 -6
- package/dist/commands/verify-acs.js +48 -76
- package/dist/commands/waivers.js +212 -13
- package/dist/commands/worktree.js +131 -26
- package/dist/error-handler.js +2 -13
- package/dist/gates/budget-limit.js +121 -0
- package/dist/gates/feedback.js +260 -0
- package/dist/gates/format.js +179 -0
- package/dist/gates/god-object.js +117 -0
- package/dist/gates/pipeline.js +167 -0
- package/dist/gates/scope-boundary.js +93 -0
- package/dist/gates/spec-completeness.js +109 -0
- package/dist/gates/todo-detection.js +205 -0
- package/dist/index.js +157 -151
- package/dist/parallel/parallel-manager.js +3 -3
- package/dist/policy/PolicyManager.js +51 -17
- package/dist/scaffold/claude-hooks.js +24 -1
- package/dist/scaffold/git-hooks.js +45 -102
- package/dist/scaffold/index.js +4 -3
- package/dist/session/session-manager.js +105 -14
- package/dist/sidecars/index.js +33 -0
- package/dist/sidecars/listeners.js +40 -0
- package/dist/sidecars/provenance-summary.js +238 -0
- package/dist/sidecars/quality-gaps.js +258 -0
- package/dist/sidecars/schema.js +149 -0
- package/dist/sidecars/spec-drift.js +151 -0
- package/dist/sidecars/waiver-draft.js +176 -0
- package/dist/templates/.caws/schemas/policy.schema.json +112 -0
- package/dist/templates/.caws/schemas/scope.schema.json +3 -3
- package/dist/templates/.caws/schemas/waivers.schema.json +96 -20
- package/dist/templates/.caws/schemas/working-spec.schema.json +264 -57
- package/dist/templates/.caws/schemas/worktrees.schema.json +3 -1
- package/dist/templates/.caws/templates/working-spec.template.yml +10 -4
- package/dist/templates/.caws/tools/scope-guard.js +66 -15
- package/dist/templates/.claude/README.md +1 -1
- package/dist/templates/.claude/hooks/audit.sh +0 -0
- package/dist/templates/.claude/hooks/block-dangerous.sh +52 -11
- package/dist/templates/.claude/hooks/classify_command.py +592 -0
- package/dist/templates/.claude/hooks/doc-frontmatter-check.sh +173 -0
- package/dist/templates/.claude/hooks/protected-paths.sh +39 -0
- package/dist/templates/.claude/hooks/quality-check.sh +23 -10
- package/dist/templates/.claude/hooks/scope-guard.sh +136 -55
- package/dist/templates/.claude/hooks/session-caws-status.sh +2 -2
- package/dist/templates/.claude/hooks/session-log.sh +76 -3
- package/dist/templates/.claude/hooks/stop-worktree-check.sh +1 -1
- package/dist/templates/.claude/hooks/test_classify_command.py +370 -0
- package/dist/templates/.claude/hooks/test_wrapper_smoke.sh +96 -0
- package/dist/templates/.claude/hooks/worktree-guard.sh +2 -2
- package/dist/templates/.claude/hooks/worktree-write-guard.sh +97 -4
- package/dist/templates/.claude/settings.json +31 -0
- package/dist/templates/.cursor/hooks/caws-quality-check.sh +4 -4
- package/dist/templates/.cursor/hooks/caws-scope-guard.sh +1 -1
- package/dist/templates/.cursor/hooks/session-log.sh +924 -0
- package/dist/templates/.cursor/hooks.json +25 -0
- package/dist/templates/.cursor/rules/02-quality-gates.mdc +3 -5
- package/dist/templates/.cursor/rules/10-documentation-quality-standards.mdc +6 -11
- package/dist/templates/.cursor/rules/11-scope-management-waivers.mdc +14 -18
- package/dist/templates/.cursor/rules/12-implementation-completeness.mdc +4 -4
- package/dist/templates/.cursor/rules/13-language-agnostic-standards.mdc +3 -13
- package/dist/templates/.github/copilot-instructions.md +5 -5
- package/dist/templates/.idea/runConfigurations/CAWS_Evaluate.xml +1 -1
- package/dist/templates/.junie/guidelines.md +2 -2
- package/dist/templates/.vscode/settings.json +3 -1
- package/dist/templates/.windsurf/rules/caws-quality-standards.md +2 -2
- package/dist/templates/.windsurf/workflows/caws-guided-development.md +3 -3
- package/dist/templates/CLAUDE.md +77 -8
- package/dist/templates/agents.md +50 -9
- package/dist/templates/docs/README.md +8 -7
- package/dist/templates/scripts/new_feature.sh +80 -0
- package/dist/test-analysis.js +43 -30
- package/dist/tool-loader.js +1 -1
- package/dist/utils/agent-session.js +202 -0
- package/dist/utils/detection.js +8 -2
- package/dist/utils/event-log.js +584 -0
- package/dist/utils/event-renderer.js +521 -0
- package/dist/utils/finalization.js +7 -6
- package/dist/utils/gitignore-updater.js +3 -0
- package/dist/utils/lifecycle-events.js +94 -0
- package/dist/utils/quality-gates-utils.js +29 -44
- package/dist/utils/schema-validator.js +50 -0
- package/dist/utils/spec-resolver.js +93 -21
- package/dist/utils/working-state.js +530 -0
- package/dist/validation/spec-validation.js +191 -31
- package/dist/waivers-manager.js +144 -6
- package/dist/worktree/worktree-manager.js +598 -95
- package/package.json +9 -8
- package/templates/.caws/schemas/policy.schema.json +112 -0
- package/templates/.caws/schemas/scope.schema.json +3 -3
- package/templates/.caws/schemas/waivers.schema.json +96 -20
- package/templates/.caws/schemas/working-spec.schema.json +264 -57
- package/templates/.caws/schemas/worktrees.schema.json +3 -1
- package/templates/.caws/templates/working-spec.template.yml +10 -4
- package/templates/.caws/tools/scope-guard.js +66 -15
- package/templates/.claude/README.md +1 -1
- package/templates/.claude/hooks/block-dangerous.sh +52 -11
- package/templates/.claude/hooks/classify_command.py +592 -0
- package/templates/.claude/hooks/doc-frontmatter-check.sh +173 -0
- package/templates/.claude/hooks/protected-paths.sh +39 -0
- package/templates/.claude/hooks/quality-check.sh +23 -10
- package/templates/.claude/hooks/scope-guard.sh +136 -55
- package/templates/.claude/hooks/session-caws-status.sh +2 -2
- package/templates/.claude/hooks/session-log.sh +76 -3
- package/templates/.claude/hooks/stop-worktree-check.sh +1 -1
- package/templates/.claude/hooks/test_classify_command.py +370 -0
- package/templates/.claude/hooks/test_wrapper_smoke.sh +96 -0
- package/templates/.claude/hooks/worktree-guard.sh +2 -2
- package/templates/.claude/hooks/worktree-write-guard.sh +97 -4
- package/templates/.claude/settings.json +31 -0
- package/templates/.cursor/hooks/caws-quality-check.sh +4 -4
- package/templates/.cursor/hooks/caws-scope-guard.sh +1 -1
- package/templates/.cursor/hooks/session-log.sh +924 -0
- package/templates/.cursor/hooks.json +25 -0
- package/templates/.cursor/rules/02-quality-gates.mdc +3 -5
- package/templates/.cursor/rules/10-documentation-quality-standards.mdc +6 -11
- package/templates/.cursor/rules/11-scope-management-waivers.mdc +14 -18
- package/templates/.cursor/rules/12-implementation-completeness.mdc +4 -4
- package/templates/.cursor/rules/13-language-agnostic-standards.mdc +3 -13
- package/templates/.github/copilot-instructions.md +5 -5
- package/templates/.idea/runConfigurations/CAWS_Evaluate.xml +1 -1
- package/templates/.junie/guidelines.md +2 -2
- package/templates/.vscode/settings.json +3 -1
- package/templates/.windsurf/rules/caws-quality-standards.md +2 -2
- package/templates/.windsurf/workflows/caws-guided-development.md +3 -3
- package/templates/CLAUDE.md +77 -8
- package/templates/{AGENTS.md → agents.md} +50 -9
- package/templates/docs/README.md +8 -7
- package/templates/scripts/new_feature.sh +80 -0
- 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 -51
- 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 -25
- package/dist/commands/mode.d.ts.map +0 -1
- package/dist/commands/parallel.d.ts +0 -7
- package/dist/commands/parallel.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 -6
- package/dist/commands/quality-gates.d.ts.map +0 -1
- package/dist/commands/quality-gates.js +0 -444
- package/dist/commands/quality-monitor.d.ts +0 -17
- package/dist/commands/quality-monitor.d.ts.map +0 -1
- package/dist/commands/session.d.ts +0 -7
- package/dist/commands/session.d.ts.map +0 -1
- package/dist/commands/specs.d.ts +0 -77
- 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/troubleshoot.js +0 -104
- 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/commands/worktree.d.ts +0 -7
- package/dist/commands/worktree.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/lite-scope.d.ts +0 -33
- package/dist/config/lite-scope.d.ts.map +0 -1
- package/dist/config/modes.d.ts +0 -264
- package/dist/config/modes.d.ts.map +0 -1
- package/dist/constants/spec-types.d.ts +0 -93
- package/dist/constants/spec-types.d.ts.map +0 -1
- package/dist/error-handler.d.ts +0 -151
- package/dist/error-handler.d.ts.map +0 -1
- package/dist/generators/jest-config-generator.d.ts +0 -32
- package/dist/generators/jest-config-generator.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/jest-config.js +0 -242
- 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/parallel/parallel-manager.d.ts +0 -67
- package/dist/parallel/parallel-manager.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/claude-hooks.d.ts +0 -28
- package/dist/scaffold/claude-hooks.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 -38
- package/dist/scaffold/git-hooks.d.ts.map +0 -1
- package/dist/scaffold/index.d.ts +0 -17
- package/dist/scaffold/index.d.ts.map +0 -1
- package/dist/session/session-manager.d.ts +0 -94
- package/dist/session/session-manager.d.ts.map +0 -1
- package/dist/spec/SpecFileManager.d.ts +0 -146
- package/dist/spec/SpecFileManager.d.ts.map +0 -1
- package/dist/templates/.cursor/hooks/caws-tool-validation.sh +0 -121
- package/dist/templates/.github/copilot/instructions.md +0 -311
- package/dist/test-analysis.d.ts +0 -231
- 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/async-utils.d.ts +0 -73
- package/dist/utils/async-utils.d.ts.map +0 -1
- package/dist/utils/command-wrapper.d.ts +0 -66
- package/dist/utils/command-wrapper.d.ts.map +0 -1
- package/dist/utils/detection.d.ts +0 -14
- package/dist/utils/detection.d.ts.map +0 -1
- package/dist/utils/error-categories.d.ts +0 -52
- package/dist/utils/error-categories.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/git-lock.d.ts +0 -13
- package/dist/utils/git-lock.d.ts.map +0 -1
- package/dist/utils/gitignore-updater.d.ts +0 -39
- package/dist/utils/gitignore-updater.d.ts.map +0 -1
- package/dist/utils/ide-detection.d.ts +0 -89
- package/dist/utils/ide-detection.d.ts.map +0 -1
- package/dist/utils/project-analysis.d.ts +0 -34
- package/dist/utils/project-analysis.d.ts.map +0 -1
- package/dist/utils/promise-utils.d.ts +0 -30
- package/dist/utils/promise-utils.d.ts.map +0 -1
- package/dist/utils/quality-gates-utils.d.ts +0 -49
- package/dist/utils/quality-gates-utils.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/quality-gates.js +0 -402
- package/dist/utils/spec-resolver.d.ts +0 -80
- package/dist/utils/spec-resolver.d.ts.map +0 -1
- package/dist/utils/typescript-detector.d.ts +0 -66
- package/dist/utils/typescript-detector.d.ts.map +0 -1
- package/dist/utils/yaml-validation.d.ts +0 -32
- package/dist/utils/yaml-validation.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/dist/worktree/worktree-manager.d.ts +0 -54
- package/dist/worktree/worktree-manager.d.ts.map +0 -1
|
@@ -279,7 +279,7 @@ if [ -d ".caws" ]; then
|
|
|
279
279
|
var reg = JSON.parse(require('fs').readFileSync('.caws/worktrees.json', 'utf8'));
|
|
280
280
|
var wts = Object.values(reg.worktrees || {});
|
|
281
281
|
var active = wts.filter(function(w) {
|
|
282
|
-
return w.status === 'active' && w.baseBranch === '$CURRENT_BRANCH';
|
|
282
|
+
return (w.status === 'active' || w.status === 'fresh' || w.status === 'merged') && w.baseBranch === '$CURRENT_BRANCH';
|
|
283
283
|
});
|
|
284
284
|
console.log(active.length + ':' + active.map(function(w) { return w.name; }).join(','));
|
|
285
285
|
} catch(e) { console.log('0:'); }
|
|
@@ -338,7 +338,7 @@ if [ -d ".caws" ]; then
|
|
|
338
338
|
HAS_ACTIVE_WT=$(node -e "
|
|
339
339
|
try {
|
|
340
340
|
var reg = JSON.parse(require('fs').readFileSync('.caws/worktrees.json', 'utf8'));
|
|
341
|
-
var active = Object.values(reg.worktrees || {}).filter(function(w) { return w.status === 'active'; });
|
|
341
|
+
var active = Object.values(reg.worktrees || {}).filter(function(w) { return w.status === 'active' || w.status === 'fresh' || w.status === 'merged'; });
|
|
342
342
|
console.log(active.length > 0 ? 'yes' : 'no');
|
|
343
343
|
} catch(e) { console.log('no'); }
|
|
344
344
|
" 2>/dev/null)
|
|
@@ -358,110 +358,42 @@ if [ -d ".caws" ]; then
|
|
|
358
358
|
fi
|
|
359
359
|
# ===== End Multi-Agent Safety Guard =====
|
|
360
360
|
|
|
361
|
-
#
|
|
362
|
-
# 1. Try Node.js script (if exists)
|
|
363
|
-
# 2. Try CAWS CLI
|
|
364
|
-
# 3. Try Makefile target
|
|
365
|
-
# 4. Try Python scripts
|
|
366
|
-
# 5. Skip gracefully (warn only)
|
|
367
|
-
|
|
361
|
+
# Run CAWS quality gates
|
|
368
362
|
QUALITY_GATES_RAN=false
|
|
363
|
+
QUALITY_GATES_WARNED=false
|
|
369
364
|
|
|
370
|
-
#
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
exit 1
|
|
394
|
-
fi
|
|
395
|
-
fi
|
|
396
|
-
# Option 2: Legacy Node.js quality gates script (deprecated)
|
|
397
|
-
elif [ -f "scripts/quality-gates/run-quality-gates.js" ]; then
|
|
398
|
-
if command -v node >/dev/null 2>&1; then
|
|
399
|
-
echo "Running legacy Node.js quality gates script..."
|
|
400
|
-
if node scripts/quality-gates/run-quality-gates.js; then
|
|
401
|
-
echo "Quality gates passed"
|
|
402
|
-
QUALITY_GATES_RAN=true
|
|
403
|
-
else
|
|
404
|
-
echo "Quality gates failed - commit blocked"
|
|
405
|
-
echo "Fix the violations above before committing"
|
|
406
|
-
exit 1
|
|
407
|
-
fi
|
|
408
|
-
fi
|
|
409
|
-
# Option 3: CAWS CLI validation
|
|
410
|
-
elif command -v caws >/dev/null 2>&1; then
|
|
411
|
-
# In a worktree, validate only the associated spec to avoid false positives
|
|
412
|
-
CAWS_VALIDATE_ARGS="--quiet"
|
|
413
|
-
WORKTREE_BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "")
|
|
414
|
-
if [ -f ".caws/worktrees.json" ] && command -v node >/dev/null 2>&1; then
|
|
415
|
-
SPEC_ID=$(node -e "
|
|
416
|
-
try {
|
|
417
|
-
var reg = JSON.parse(require('fs').readFileSync('.caws/worktrees.json', 'utf8'));
|
|
418
|
-
var wt = Object.values(reg.worktrees || {}).find(function(w) {
|
|
419
|
-
return w.branch === '$WORKTREE_BRANCH';
|
|
420
|
-
});
|
|
421
|
-
if (wt && wt.specId) console.log(wt.specId);
|
|
422
|
-
} catch(e) {}
|
|
423
|
-
" 2>/dev/null || echo "")
|
|
424
|
-
if [ -n "$SPEC_ID" ]; then
|
|
425
|
-
CAWS_VALIDATE_ARGS="--quiet --spec-id $SPEC_ID"
|
|
426
|
-
fi
|
|
427
|
-
fi
|
|
428
|
-
echo "Running CAWS CLI validation..."
|
|
429
|
-
if caws validate $CAWS_VALIDATE_ARGS 2>/dev/null; then
|
|
430
|
-
echo "CAWS validation passed"
|
|
431
|
-
QUALITY_GATES_RAN=true
|
|
432
|
-
else
|
|
433
|
-
echo "CAWS validation failed, but allowing commit (non-blocking)"
|
|
434
|
-
echo "Run 'caws validate' for details"
|
|
435
|
-
QUALITY_GATES_RAN=true
|
|
436
|
-
fi
|
|
437
|
-
# Option 3: Makefile target
|
|
438
|
-
elif [ -f "Makefile" ] && grep -q "caws-validate\\|caws-gates" Makefile; then
|
|
439
|
-
echo "Running Makefile quality gates..."
|
|
440
|
-
if make caws-validate >/dev/null 2>&1 || make caws-gates >/dev/null 2>&1; then
|
|
441
|
-
echo "Makefile quality gates passed"
|
|
442
|
-
QUALITY_GATES_RAN=true
|
|
443
|
-
else
|
|
444
|
-
echo "Makefile quality gates failed, but allowing commit (non-blocking)"
|
|
445
|
-
QUALITY_GATES_RAN=true
|
|
446
|
-
fi
|
|
447
|
-
# Option 4: Python scripts
|
|
448
|
-
elif [ -f "scripts/simple_gates.py" ] && command -v python3 >/dev/null 2>&1; then
|
|
449
|
-
echo "Running Python quality gates script..."
|
|
450
|
-
if python3 scripts/simple_gates.py all --tier 2 --profile backend-api >/dev/null 2>&1; then
|
|
451
|
-
echo "Python quality gates passed"
|
|
365
|
+
# Resolve spec ID from worktree context if available
|
|
366
|
+
SPEC_ID=""
|
|
367
|
+
WORKTREE_BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "")
|
|
368
|
+
if [ -f ".caws/worktrees.json" ] && command -v node >/dev/null 2>&1; then
|
|
369
|
+
SPEC_ID=$(node -e "
|
|
370
|
+
try {
|
|
371
|
+
var reg = JSON.parse(require('fs').readFileSync('.caws/worktrees.json', 'utf8'));
|
|
372
|
+
var wt = Object.values(reg.worktrees || {}).find(function(w) {
|
|
373
|
+
return w.branch === '$WORKTREE_BRANCH';
|
|
374
|
+
});
|
|
375
|
+
if (wt && wt.specId) console.log(wt.specId);
|
|
376
|
+
} catch(e) {}
|
|
377
|
+
" 2>/dev/null || echo "")
|
|
378
|
+
fi
|
|
379
|
+
|
|
380
|
+
GATES_ARGS="--context=commit --quiet"
|
|
381
|
+
if [ -n "$SPEC_ID" ]; then
|
|
382
|
+
GATES_ARGS="$GATES_ARGS --spec-id $SPEC_ID"
|
|
383
|
+
fi
|
|
384
|
+
|
|
385
|
+
if command -v caws >/dev/null 2>&1; then
|
|
386
|
+
if caws gates run $GATES_ARGS; then
|
|
387
|
+
echo "Quality gates passed"
|
|
452
388
|
QUALITY_GATES_RAN=true
|
|
453
389
|
else
|
|
454
|
-
|
|
455
|
-
|
|
390
|
+
GATE_EXIT=$?
|
|
391
|
+
echo "Quality gates BLOCKED the commit (exit code $GATE_EXIT)"
|
|
392
|
+
exit 1
|
|
456
393
|
fi
|
|
457
|
-
# Option 5: Skip gracefully
|
|
458
394
|
else
|
|
459
|
-
echo "
|
|
460
|
-
echo "
|
|
461
|
-
echo " - Install quality gates: npm install --save-dev @paths.design/quality-gates"
|
|
462
|
-
echo " - Install CAWS CLI: npm install -g @paths.design/caws-cli"
|
|
463
|
-
echo " - Use Python: python3 scripts/simple_gates.py"
|
|
464
|
-
echo " - Use Makefile: make caws-gates"
|
|
395
|
+
echo "CAWS CLI not available — skipping quality gates"
|
|
396
|
+
echo "Install with: npm install -g @paths.design/caws-cli"
|
|
465
397
|
QUALITY_GATES_RAN=true
|
|
466
398
|
fi
|
|
467
399
|
|
|
@@ -534,7 +466,11 @@ ${todoSuggestion
|
|
|
534
466
|
fi
|
|
535
467
|
fi
|
|
536
468
|
|
|
537
|
-
|
|
469
|
+
if [ "$QUALITY_GATES_WARNED" = true ]; then
|
|
470
|
+
echo "Proceeding with commit (some quality checks had warnings)"
|
|
471
|
+
else
|
|
472
|
+
echo "All quality checks passed - proceeding with commit"
|
|
473
|
+
fi
|
|
538
474
|
exit 0
|
|
539
475
|
`;
|
|
540
476
|
}
|
|
@@ -554,6 +490,13 @@ function generatePostCommitHook() {
|
|
|
554
490
|
exit 0
|
|
555
491
|
fi
|
|
556
492
|
|
|
493
|
+
# Skip during merge operations — caws worktree merge triggers a merge
|
|
494
|
+
# commit, and writing to .caws/provenance/chain.json here would dirty
|
|
495
|
+
# the tree mid-merge, blocking subsequent operations.
|
|
496
|
+
if [ -f ".git/MERGE_HEAD" ] || [ -f "$(git rev-parse --git-dir 2>/dev/null)/MERGE_HEAD" ]; then
|
|
497
|
+
exit 0
|
|
498
|
+
fi
|
|
499
|
+
|
|
557
500
|
# Get the current commit hash
|
|
558
501
|
COMMIT_HASH=$(git rev-parse HEAD)
|
|
559
502
|
|
|
@@ -828,7 +771,7 @@ if [ -f "$CAWS_ROOT/.caws/worktrees.json" ] && command -v node >/dev/null 2>&1;
|
|
|
828
771
|
try {
|
|
829
772
|
var reg = JSON.parse(require('fs').readFileSync('$CAWS_ROOT/.caws/worktrees.json', 'utf8'));
|
|
830
773
|
var active = Object.values(reg.worktrees || {}).filter(function(w) {
|
|
831
|
-
return w.status === 'active' && w.baseBranch === '$CURRENT_BRANCH';
|
|
774
|
+
return (w.status === 'active' || w.status === 'fresh' || w.status === 'merged') && w.baseBranch === '$CURRENT_BRANCH';
|
|
832
775
|
});
|
|
833
776
|
console.log(active.length);
|
|
834
777
|
} catch(e) { console.log('0'); }
|
package/dist/scaffold/index.js
CHANGED
|
@@ -728,11 +728,12 @@ async function scaffoldProject(options) {
|
|
|
728
728
|
} else {
|
|
729
729
|
console.log('2. Run: caws validate (verify setup)');
|
|
730
730
|
console.log('3. Run: caws diagnose (check project health)');
|
|
731
|
-
console.log('4. Customize .caws/
|
|
732
|
-
console.log('5.
|
|
731
|
+
console.log('4. Customize .caws/specs/<spec-id>.yaml for your project');
|
|
732
|
+
console.log('5. Treat .caws/working-spec.yaml as a compatibility mirror');
|
|
733
|
+
console.log('6. Optional: Create .caws/policy.yaml for tier-specific budgets');
|
|
733
734
|
if (!qualityGatesAdded && !options.minimal) {
|
|
734
735
|
console.log(
|
|
735
|
-
chalk.gray('
|
|
736
|
+
chalk.gray('7. Note: Quality gates scripts skipped (git hooks use CAWS CLI by default)')
|
|
736
737
|
);
|
|
737
738
|
console.log(
|
|
738
739
|
chalk.gray(
|
|
@@ -11,6 +11,9 @@ const fs = require('fs-extra');
|
|
|
11
11
|
const path = require('path');
|
|
12
12
|
const crypto = require('crypto');
|
|
13
13
|
|
|
14
|
+
const { mergeFilesTouched } = require('../utils/working-state');
|
|
15
|
+
const { appendEventSync } = require('../utils/event-log');
|
|
16
|
+
|
|
14
17
|
const SESSIONS_DIR = '.caws/sessions';
|
|
15
18
|
const REGISTRY_FILE = '.caws/sessions.json';
|
|
16
19
|
const CAPSULE_SCHEMA_VERSION = 'caws.capsule.v1';
|
|
@@ -79,16 +82,62 @@ function getWorkspaceFingerprint(cwd) {
|
|
|
79
82
|
}
|
|
80
83
|
|
|
81
84
|
/**
|
|
82
|
-
*
|
|
85
|
+
* Load the best available spec synchronously (feature specs first, then legacy).
|
|
83
86
|
* @param {string} root - Repository root
|
|
87
|
+
* @param {string} [specId] - Optional specific spec ID
|
|
88
|
+
* @returns {object|null} Parsed spec object or null
|
|
89
|
+
*/
|
|
90
|
+
function loadBestSpecSync(root, specId) {
|
|
91
|
+
const yaml = require('js-yaml');
|
|
92
|
+
|
|
93
|
+
// If a specific spec ID is requested, load it directly
|
|
94
|
+
if (specId) {
|
|
95
|
+
for (const ext of ['.yaml', '.yml']) {
|
|
96
|
+
const p = path.join(root, '.caws/specs', `${specId}${ext}`);
|
|
97
|
+
if (fs.existsSync(p)) {
|
|
98
|
+
try { return yaml.load(fs.readFileSync(p, 'utf8')); } catch { /* skip */ }
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Check registry for active feature specs
|
|
104
|
+
const registryPath = path.join(root, '.caws/specs/registry.json');
|
|
105
|
+
if (fs.existsSync(registryPath)) {
|
|
106
|
+
try {
|
|
107
|
+
const registry = JSON.parse(fs.readFileSync(registryPath, 'utf8'));
|
|
108
|
+
const specs = registry.specs || {};
|
|
109
|
+
const activeIds = Object.keys(specs).filter(
|
|
110
|
+
id => specs[id].status !== 'closed' && specs[id].status !== 'archived'
|
|
111
|
+
);
|
|
112
|
+
for (const id of activeIds) {
|
|
113
|
+
const specEntry = specs[id];
|
|
114
|
+
const p = path.join(root, '.caws/specs', specEntry.path || `${id}.yaml`);
|
|
115
|
+
if (fs.existsSync(p)) {
|
|
116
|
+
try { return yaml.load(fs.readFileSync(p, 'utf8')); } catch { /* skip */ }
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
} catch { /* fall through */ }
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Legacy fallback
|
|
123
|
+
const legacyPath = path.join(root, '.caws/working-spec.yaml');
|
|
124
|
+
if (fs.existsSync(legacyPath)) {
|
|
125
|
+
try { return yaml.load(fs.readFileSync(legacyPath, 'utf8')); } catch { /* skip */ }
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Get project name from best available spec or directory
|
|
133
|
+
* @param {string} root - Repository root
|
|
134
|
+
* @param {string} [specId] - Optional specific spec ID
|
|
84
135
|
* @returns {string}
|
|
85
136
|
*/
|
|
86
|
-
function getProjectName(root) {
|
|
137
|
+
function getProjectName(root, specId) {
|
|
87
138
|
try {
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
if (fs.existsSync(specPath)) {
|
|
91
|
-
const spec = yaml.load(fs.readFileSync(specPath, 'utf8'));
|
|
139
|
+
const spec = loadBestSpecSync(root, specId);
|
|
140
|
+
if (spec) {
|
|
92
141
|
return spec.title || spec.id || path.basename(root);
|
|
93
142
|
}
|
|
94
143
|
} catch {
|
|
@@ -98,16 +147,15 @@ function getProjectName(root) {
|
|
|
98
147
|
}
|
|
99
148
|
|
|
100
149
|
/**
|
|
101
|
-
* Get skein ID from
|
|
150
|
+
* Get skein ID from best available spec
|
|
102
151
|
* @param {string} root - Repository root
|
|
152
|
+
* @param {string} [specId] - Optional specific spec ID
|
|
103
153
|
* @returns {string}
|
|
104
154
|
*/
|
|
105
|
-
function getSkeinId(root) {
|
|
155
|
+
function getSkeinId(root, specId) {
|
|
106
156
|
try {
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
if (fs.existsSync(specPath)) {
|
|
110
|
-
const spec = yaml.load(fs.readFileSync(specPath, 'utf8'));
|
|
157
|
+
const spec = loadBestSpecSync(root, specId);
|
|
158
|
+
if (spec) {
|
|
111
159
|
return spec.id || 'unknown';
|
|
112
160
|
}
|
|
113
161
|
} catch {
|
|
@@ -201,8 +249,8 @@ function startSession(options = {}) {
|
|
|
201
249
|
|
|
202
250
|
const capsule = {
|
|
203
251
|
schema: CAPSULE_SCHEMA_VERSION,
|
|
204
|
-
project: getProjectName(root),
|
|
205
|
-
skein_id: getSkeinId(root),
|
|
252
|
+
project: getProjectName(root, specId),
|
|
253
|
+
skein_id: getSkeinId(root, specId),
|
|
206
254
|
session_id: sessionId,
|
|
207
255
|
role,
|
|
208
256
|
spec_id: specId || null,
|
|
@@ -250,6 +298,22 @@ function startSession(options = {}) {
|
|
|
250
298
|
};
|
|
251
299
|
saveRegistry(root, registry);
|
|
252
300
|
|
|
301
|
+
// EVLOG-001: emit session_started event via the sync append path.
|
|
302
|
+
// spec_id is optional for this event type; we include it only when
|
|
303
|
+
// the session is bound to a spec.
|
|
304
|
+
const sessionStartedEvent = {
|
|
305
|
+
actor: 'session',
|
|
306
|
+
event: 'session_started',
|
|
307
|
+
data: {
|
|
308
|
+
session_id: sessionId,
|
|
309
|
+
role,
|
|
310
|
+
branch: capsule.base_state.branch,
|
|
311
|
+
head_rev: capsule.base_state.head_rev,
|
|
312
|
+
},
|
|
313
|
+
};
|
|
314
|
+
if (specId) sessionStartedEvent.spec_id = specId;
|
|
315
|
+
appendEventSync(sessionStartedEvent, { projectRoot: root, session_id: sessionId });
|
|
316
|
+
|
|
253
317
|
return capsule;
|
|
254
318
|
}
|
|
255
319
|
|
|
@@ -318,6 +382,11 @@ function checkpointSession(data = {}) {
|
|
|
318
382
|
// Write updated capsule
|
|
319
383
|
fs.writeFileSync(capsulePath, JSON.stringify(capsule, null, 2));
|
|
320
384
|
|
|
385
|
+
// Bridge to working state (per-spec)
|
|
386
|
+
if (capsule.spec_id && capsule.work_summary.paths_touched.length > 0) {
|
|
387
|
+
try { mergeFilesTouched(capsule.spec_id, capsule.work_summary.paths_touched, root); } catch { /* non-fatal */ }
|
|
388
|
+
}
|
|
389
|
+
|
|
321
390
|
return capsule;
|
|
322
391
|
}
|
|
323
392
|
|
|
@@ -385,11 +454,33 @@ function endSession(data = {}) {
|
|
|
385
454
|
// Write finalized capsule
|
|
386
455
|
fs.writeFileSync(capsulePath, JSON.stringify(capsule, null, 2));
|
|
387
456
|
|
|
457
|
+
// Bridge to working state (per-spec)
|
|
458
|
+
if (capsule.spec_id && capsule.work_summary.paths_touched.length > 0) {
|
|
459
|
+
try { mergeFilesTouched(capsule.spec_id, capsule.work_summary.paths_touched, root); } catch { /* non-fatal */ }
|
|
460
|
+
}
|
|
461
|
+
|
|
388
462
|
// Update registry
|
|
389
463
|
registry.sessions[sessionId].status = 'completed';
|
|
390
464
|
registry.sessions[sessionId].ended_at = capsule.ended_at;
|
|
391
465
|
saveRegistry(root, registry);
|
|
392
466
|
|
|
467
|
+
// EVLOG-001: emit session_ended event with final files_touched list.
|
|
468
|
+
// The renderer uses this to merge file touches into the spec view.
|
|
469
|
+
const sessionEndedEvent = {
|
|
470
|
+
actor: 'session',
|
|
471
|
+
event: 'session_ended',
|
|
472
|
+
data: {
|
|
473
|
+
session_id: sessionId,
|
|
474
|
+
files_touched: capsule.work_summary.paths_touched || [],
|
|
475
|
+
outcome: capsule.known_issues.some((i) => i.type === 'error') ? 'error' : 'success',
|
|
476
|
+
},
|
|
477
|
+
};
|
|
478
|
+
if (capsule.spec_id) {
|
|
479
|
+
sessionEndedEvent.spec_id = capsule.spec_id;
|
|
480
|
+
sessionEndedEvent.data.spec_id = capsule.spec_id;
|
|
481
|
+
}
|
|
482
|
+
appendEventSync(sessionEndedEvent, { projectRoot: root, session_id: sessionId });
|
|
483
|
+
|
|
393
484
|
return capsule;
|
|
394
485
|
}
|
|
395
486
|
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Sidecar Registry
|
|
3
|
+
* Central registry of all bounded governance sidecars.
|
|
4
|
+
* @author @darianrosebrook
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { analyzeSpecDrift } = require('./spec-drift');
|
|
8
|
+
const { diagnoseQualityGaps } = require('./quality-gaps');
|
|
9
|
+
const { draftWaiver } = require('./waiver-draft');
|
|
10
|
+
const { summarizeProvenance } = require('./provenance-summary');
|
|
11
|
+
const { createSidecarOutput, createNoStateOutput, formatSidecarText } = require('./schema');
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Registry of available sidecars.
|
|
15
|
+
* Each entry has a function and a short description for help text.
|
|
16
|
+
*/
|
|
17
|
+
const SIDECARS = {
|
|
18
|
+
drift: { fn: analyzeSpecDrift, description: 'Analyze spec drift vs implementation evidence' },
|
|
19
|
+
gaps: { fn: diagnoseQualityGaps, description: 'Diagnose quality gaps preventing phase advancement' },
|
|
20
|
+
'waiver-draft': { fn: draftWaiver, description: 'Generate pre-filled waiver templates from gate failures' },
|
|
21
|
+
provenance: { fn: summarizeProvenance, description: 'Summarize work provenance for merge readiness' },
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
module.exports = {
|
|
25
|
+
SIDECARS,
|
|
26
|
+
analyzeSpecDrift,
|
|
27
|
+
diagnoseQualityGaps,
|
|
28
|
+
draftWaiver,
|
|
29
|
+
summarizeProvenance,
|
|
30
|
+
createSidecarOutput,
|
|
31
|
+
createNoStateOutput,
|
|
32
|
+
formatSidecarText,
|
|
33
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Sidecar Lifecycle Listeners
|
|
3
|
+
* Registers lightweight event handlers that print hints to run sidecars
|
|
4
|
+
* at governance-significant moments. Non-blocking, non-fatal.
|
|
5
|
+
* @author @darianrosebrook
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const { lifecycle, EVENTS } = require('../utils/lifecycle-events');
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Register sidecar hint listeners on the lifecycle emitter.
|
|
12
|
+
* Call once during CLI startup.
|
|
13
|
+
*/
|
|
14
|
+
function registerSidecarListeners() {
|
|
15
|
+
// On gate blocked → suggest waiver draft
|
|
16
|
+
lifecycle.on(EVENTS.GATES_BLOCKED, (payload) => {
|
|
17
|
+
try {
|
|
18
|
+
if (process.env.CAWS_QUIET === '1') return;
|
|
19
|
+
const specFlag = payload.specId ? ` --spec-id ${payload.specId}` : '';
|
|
20
|
+
const gateFlag = payload.gateName ? ` --gate ${payload.gateName}` : '';
|
|
21
|
+
console.log(
|
|
22
|
+
`\n [Sidecar] Waiver draft available: caws sidecar waiver-draft${specFlag}${gateFlag}`
|
|
23
|
+
);
|
|
24
|
+
} catch { /* non-fatal */ }
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// On phase transition (non-complete) → suggest quality gap analysis
|
|
28
|
+
lifecycle.on(EVENTS.PHASE_TRANSITION, (payload) => {
|
|
29
|
+
try {
|
|
30
|
+
if (process.env.CAWS_QUIET === '1') return;
|
|
31
|
+
if (payload.newPhase === 'complete') return;
|
|
32
|
+
const specFlag = payload.specId ? ` --spec-id ${payload.specId}` : '';
|
|
33
|
+
console.log(
|
|
34
|
+
`\n [Sidecar] Phase changed to ${payload.newPhase}. Run: caws sidecar gaps${specFlag}`
|
|
35
|
+
);
|
|
36
|
+
} catch { /* non-fatal */ }
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
module.exports = { registerSidecarListeners };
|