@paths.design/caws-cli 10.1.0 → 11.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/README.md +125 -374
- package/dist/index.js +43 -756
- package/dist/shell/binding/resolve-binding.d.ts +4 -0
- package/dist/shell/binding/resolve-binding.d.ts.map +1 -0
- package/dist/shell/binding/resolve-binding.js +228 -0
- package/dist/shell/binding/resolve-binding.js.map +1 -0
- package/dist/shell/binding/types.d.ts +42 -0
- package/dist/shell/binding/types.d.ts.map +1 -0
- package/dist/shell/binding/types.js +21 -0
- package/dist/shell/binding/types.js.map +1 -0
- package/dist/shell/commands/claim.d.ts +14 -0
- package/dist/shell/commands/claim.d.ts.map +1 -0
- package/dist/shell/commands/claim.js +197 -0
- package/dist/shell/commands/claim.js.map +1 -0
- package/dist/shell/commands/doctor.d.ts +13 -0
- package/dist/shell/commands/doctor.d.ts.map +1 -0
- package/dist/shell/commands/doctor.js +97 -0
- package/dist/shell/commands/doctor.js.map +1 -0
- package/dist/shell/commands/evidence.d.ts +28 -0
- package/dist/shell/commands/evidence.d.ts.map +1 -0
- package/dist/shell/commands/evidence.js +166 -0
- package/dist/shell/commands/evidence.js.map +1 -0
- package/dist/shell/commands/gates.d.ts +19 -0
- package/dist/shell/commands/gates.d.ts.map +1 -0
- package/dist/shell/commands/gates.js +181 -0
- package/dist/shell/commands/gates.js.map +1 -0
- package/dist/shell/commands/init.d.ts +8 -0
- package/dist/shell/commands/init.d.ts.map +1 -0
- package/dist/shell/commands/init.js +64 -0
- package/dist/shell/commands/init.js.map +1 -0
- package/dist/shell/commands/scope.d.ts +11 -0
- package/dist/shell/commands/scope.d.ts.map +1 -0
- package/dist/shell/commands/scope.js +92 -0
- package/dist/shell/commands/scope.js.map +1 -0
- package/dist/shell/commands/status.d.ts +15 -0
- package/dist/shell/commands/status.d.ts.map +1 -0
- package/dist/shell/commands/status.js +106 -0
- package/dist/shell/commands/status.js.map +1 -0
- package/dist/shell/commands/waiver.d.ts +38 -0
- package/dist/shell/commands/waiver.d.ts.map +1 -0
- package/dist/shell/commands/waiver.js +240 -0
- package/dist/shell/commands/waiver.js.map +1 -0
- package/dist/shell/gates/disposition.d.ts +23 -0
- package/dist/shell/gates/disposition.d.ts.map +1 -0
- package/dist/shell/gates/disposition.js +87 -0
- package/dist/shell/gates/disposition.js.map +1 -0
- package/dist/shell/gates/gate-result-contract.d.ts +39 -0
- package/dist/shell/gates/gate-result-contract.d.ts.map +1 -0
- package/dist/shell/gates/gate-result-contract.js +150 -0
- package/dist/shell/gates/gate-result-contract.js.map +1 -0
- package/dist/shell/gates/quality-gates-adapter.d.ts +55 -0
- package/dist/shell/gates/quality-gates-adapter.d.ts.map +1 -0
- package/dist/shell/gates/quality-gates-adapter.js +161 -0
- package/dist/shell/gates/quality-gates-adapter.js.map +1 -0
- package/dist/shell/gates/waiver-filter.d.ts +58 -0
- package/dist/shell/gates/waiver-filter.d.ts.map +1 -0
- package/dist/shell/gates/waiver-filter.js +119 -0
- package/dist/shell/gates/waiver-filter.js.map +1 -0
- package/dist/shell/index.d.ts +50 -0
- package/dist/shell/index.d.ts.map +1 -0
- package/dist/shell/index.js +73 -0
- package/dist/shell/index.js.map +1 -0
- package/dist/shell/register.d.ts +11 -0
- package/dist/shell/register.d.ts.map +1 -0
- package/dist/shell/register.js +274 -0
- package/dist/shell/register.js.map +1 -0
- package/dist/shell/render/claim.d.ts +22 -0
- package/dist/shell/render/claim.d.ts.map +1 -0
- package/dist/shell/render/claim.js +75 -0
- package/dist/shell/render/claim.js.map +1 -0
- package/dist/shell/render/decision.d.ts +15 -0
- package/dist/shell/render/decision.d.ts.map +1 -0
- package/dist/shell/render/decision.js +66 -0
- package/dist/shell/render/decision.js.map +1 -0
- package/dist/shell/render/diagnostic.d.ts +19 -0
- package/dist/shell/render/diagnostic.d.ts.map +1 -0
- package/dist/shell/render/diagnostic.js +76 -0
- package/dist/shell/render/diagnostic.js.map +1 -0
- package/dist/shell/render/finding.d.ts +15 -0
- package/dist/shell/render/finding.d.ts.map +1 -0
- package/dist/shell/render/finding.js +57 -0
- package/dist/shell/render/finding.js.map +1 -0
- package/dist/shell/render/gates.d.ts +3 -0
- package/dist/shell/render/gates.d.ts.map +1 -0
- package/dist/shell/render/gates.js +56 -0
- package/dist/shell/render/gates.js.map +1 -0
- package/dist/shell/render/init.d.ts +11 -0
- package/dist/shell/render/init.d.ts.map +1 -0
- package/dist/shell/render/init.js +32 -0
- package/dist/shell/render/init.js.map +1 -0
- package/dist/shell/render/status.d.ts +26 -0
- package/dist/shell/render/status.d.ts.map +1 -0
- package/dist/shell/render/status.js +143 -0
- package/dist/shell/render/status.js.map +1 -0
- package/dist/shell/render/waiver.d.ts +21 -0
- package/dist/shell/render/waiver.d.ts.map +1 -0
- package/dist/shell/render/waiver.js +94 -0
- package/dist/shell/render/waiver.js.map +1 -0
- package/dist/shell/rules.d.ts +37 -0
- package/dist/shell/rules.d.ts.map +1 -0
- package/dist/shell/rules.js +51 -0
- package/dist/shell/rules.js.map +1 -0
- package/dist/shell/session/actor.d.ts +14 -0
- package/dist/shell/session/actor.d.ts.map +1 -0
- package/dist/shell/session/actor.js +34 -0
- package/dist/shell/session/actor.js.map +1 -0
- package/dist/shell/session/resolve-session.d.ts +5 -0
- package/dist/shell/session/resolve-session.d.ts.map +1 -0
- package/dist/shell/session/resolve-session.js +239 -0
- package/dist/shell/session/resolve-session.js.map +1 -0
- package/dist/shell/session/types.d.ts +56 -0
- package/dist/shell/session/types.d.ts.map +1 -0
- package/dist/shell/session/types.js +15 -0
- package/dist/shell/session/types.js.map +1 -0
- package/dist/store/agents-store.d.ts +3 -0
- package/dist/store/agents-store.d.ts.map +1 -0
- package/dist/store/agents-store.js +63 -0
- package/dist/store/agents-store.js.map +1 -0
- package/dist/store/apply-patch.d.ts +16 -0
- package/dist/store/apply-patch.d.ts.map +1 -0
- package/dist/store/apply-patch.js +191 -0
- package/dist/store/apply-patch.js.map +1 -0
- package/dist/store/atomic-write.d.ts +16 -0
- package/dist/store/atomic-write.d.ts.map +1 -0
- package/dist/store/atomic-write.js +132 -0
- package/dist/store/atomic-write.js.map +1 -0
- package/dist/store/doctor-snapshot.d.ts +20 -0
- package/dist/store/doctor-snapshot.d.ts.map +1 -0
- package/dist/store/doctor-snapshot.js +176 -0
- package/dist/store/doctor-snapshot.js.map +1 -0
- package/dist/store/events-store.d.ts +33 -0
- package/dist/store/events-store.d.ts.map +1 -0
- package/dist/store/events-store.js +297 -0
- package/dist/store/events-store.js.map +1 -0
- package/dist/store/index.d.ts +21 -0
- package/dist/store/index.d.ts.map +1 -0
- package/dist/store/index.js +47 -0
- package/dist/store/index.js.map +1 -0
- package/dist/store/init-store.d.ts +21 -0
- package/dist/store/init-store.d.ts.map +1 -0
- package/dist/store/init-store.js +295 -0
- package/dist/store/init-store.js.map +1 -0
- package/dist/store/json-store.d.ts +3 -0
- package/dist/store/json-store.d.ts.map +1 -0
- package/dist/store/json-store.js +65 -0
- package/dist/store/json-store.js.map +1 -0
- package/dist/store/policy-store.d.ts +3 -0
- package/dist/store/policy-store.d.ts.map +1 -0
- package/dist/store/policy-store.js +65 -0
- package/dist/store/policy-store.js.map +1 -0
- package/dist/store/repo-root.d.ts +46 -0
- package/dist/store/repo-root.d.ts.map +1 -0
- package/dist/store/repo-root.js +145 -0
- package/dist/store/repo-root.js.map +1 -0
- package/dist/store/rules.d.ts +53 -0
- package/dist/store/rules.d.ts.map +1 -0
- package/dist/store/rules.js +78 -0
- package/dist/store/rules.js.map +1 -0
- package/dist/store/specs-store.d.ts +3 -0
- package/dist/store/specs-store.d.ts.map +1 -0
- package/dist/store/specs-store.js +131 -0
- package/dist/store/specs-store.js.map +1 -0
- package/dist/store/types.d.ts +84 -0
- package/dist/store/types.d.ts.map +1 -0
- package/dist/store/types.js +14 -0
- package/dist/store/types.js.map +1 -0
- package/dist/store/waivers-store.d.ts +25 -0
- package/dist/store/waivers-store.d.ts.map +1 -0
- package/dist/store/waivers-store.js +232 -0
- package/dist/store/waivers-store.js.map +1 -0
- package/dist/store/worktrees-store.d.ts +3 -0
- package/dist/store/worktrees-store.d.ts.map +1 -0
- package/dist/store/worktrees-store.js +62 -0
- package/dist/store/worktrees-store.js.map +1 -0
- package/dist/store/yaml-store.d.ts +9 -0
- package/dist/store/yaml-store.d.ts.map +1 -0
- package/dist/store/yaml-store.js +121 -0
- package/dist/store/yaml-store.js.map +1 -0
- package/package.json +15 -13
- package/dist/budget-derivation.js +0 -751
- package/dist/cicd-optimizer.js +0 -504
- package/dist/commands/archive.js +0 -500
- package/dist/commands/burnup.js +0 -198
- package/dist/commands/diagnose.js +0 -525
- package/dist/commands/evaluate.js +0 -314
- package/dist/commands/gates.js +0 -149
- package/dist/commands/init.js +0 -857
- package/dist/commands/iterate.js +0 -417
- package/dist/commands/mode.js +0 -269
- package/dist/commands/parallel.js +0 -242
- package/dist/commands/plan.js +0 -438
- package/dist/commands/provenance.js +0 -1143
- package/dist/commands/quality-monitor.js +0 -284
- package/dist/commands/scope.js +0 -264
- package/dist/commands/session.js +0 -312
- package/dist/commands/sidecar.js +0 -74
- package/dist/commands/specs.js +0 -1448
- package/dist/commands/status.js +0 -1151
- package/dist/commands/templates.js +0 -237
- package/dist/commands/tool.js +0 -136
- package/dist/commands/tutorial.js +0 -480
- package/dist/commands/validate.js +0 -357
- package/dist/commands/verify-acs.js +0 -443
- package/dist/commands/waivers.js +0 -599
- package/dist/commands/workflow.js +0 -243
- package/dist/commands/worktree.js +0 -386
- package/dist/config/lite-scope.js +0 -158
- package/dist/config/modes.js +0 -347
- package/dist/constants/spec-types.js +0 -65
- package/dist/gates/budget-limit.js +0 -121
- package/dist/gates/feedback.js +0 -260
- package/dist/gates/format.js +0 -179
- package/dist/gates/god-object.js +0 -117
- package/dist/gates/pipeline.js +0 -167
- package/dist/gates/scope-boundary.js +0 -93
- package/dist/gates/spec-completeness.js +0 -109
- package/dist/gates/todo-detection.js +0 -205
- package/dist/generators/jest-config-generator.js +0 -242
- package/dist/generators/working-spec.js +0 -237
- package/dist/minimal-cli.js +0 -88
- package/dist/parallel/parallel-manager.js +0 -433
- package/dist/policy/PolicyManager.js +0 -465
- package/dist/scaffold/claude-hooks.js +0 -443
- package/dist/scaffold/cursor-hooks.js +0 -177
- package/dist/scaffold/git-hooks.js +0 -928
- package/dist/scaffold/index.js +0 -794
- package/dist/session/session-manager.js +0 -653
- package/dist/sidecars/index.js +0 -33
- package/dist/sidecars/listeners.js +0 -40
- package/dist/sidecars/provenance-summary.js +0 -238
- package/dist/sidecars/quality-gaps.js +0 -258
- package/dist/sidecars/schema.js +0 -149
- package/dist/sidecars/spec-drift.js +0 -151
- package/dist/sidecars/waiver-draft.js +0 -176
- package/dist/spec/SpecFileManager.js +0 -419
- package/dist/templates/.caws/schemas/policy.schema.json +0 -112
- package/dist/templates/.caws/schemas/scope.schema.json +0 -52
- package/dist/templates/.caws/schemas/waivers.schema.json +0 -106
- package/dist/templates/.caws/schemas/working-spec.schema.json +0 -340
- package/dist/templates/.caws/schemas/worktrees.schema.json +0 -38
- package/dist/templates/.caws/templates/working-spec.template.yml +0 -80
- package/dist/templates/.caws/tools/README.md +0 -18
- package/dist/templates/.caws/tools/scope-guard.js +0 -203
- package/dist/templates/.caws/tools-allow.json +0 -331
- package/dist/templates/.caws/waivers.yml +0 -19
- package/dist/templates/.claude/README.md +0 -190
- package/dist/templates/.claude/hooks/audit.sh +0 -121
- package/dist/templates/.claude/hooks/block-dangerous.sh +0 -203
- package/dist/templates/.claude/hooks/classify_command.py +0 -592
- package/dist/templates/.claude/hooks/doc-frontmatter-check.sh +0 -173
- package/dist/templates/.claude/hooks/lite-sprawl-check.sh +0 -145
- package/dist/templates/.claude/hooks/naming-check.sh +0 -100
- package/dist/templates/.claude/hooks/protected-paths.sh +0 -39
- package/dist/templates/.claude/hooks/quality-check.sh +0 -81
- package/dist/templates/.claude/hooks/scan-secrets.sh +0 -85
- package/dist/templates/.claude/hooks/scope-guard.sh +0 -381
- package/dist/templates/.claude/hooks/session-caws-status.sh +0 -117
- package/dist/templates/.claude/hooks/session-log.sh +0 -634
- package/dist/templates/.claude/hooks/simplification-guard.sh +0 -92
- package/dist/templates/.claude/hooks/stop-worktree-check.sh +0 -46
- package/dist/templates/.claude/hooks/test_classify_command.py +0 -370
- package/dist/templates/.claude/hooks/test_wrapper_smoke.sh +0 -96
- package/dist/templates/.claude/hooks/validate-spec.sh +0 -76
- package/dist/templates/.claude/hooks/worktree-guard.sh +0 -220
- package/dist/templates/.claude/hooks/worktree-write-guard.sh +0 -190
- package/dist/templates/.claude/rules/git-safety.md +0 -26
- package/dist/templates/.claude/rules/worktree-isolation.md +0 -83
- package/dist/templates/.claude/settings.json +0 -141
- package/dist/templates/.cursor/README.md +0 -299
- package/dist/templates/.cursor/hooks/audit.sh +0 -55
- package/dist/templates/.cursor/hooks/block-dangerous.sh +0 -84
- package/dist/templates/.cursor/hooks/caws-quality-check.sh +0 -52
- package/dist/templates/.cursor/hooks/caws-scope-guard.sh +0 -130
- package/dist/templates/.cursor/hooks/format.sh +0 -38
- package/dist/templates/.cursor/hooks/naming-check.sh +0 -64
- package/dist/templates/.cursor/hooks/scan-secrets.sh +0 -51
- package/dist/templates/.cursor/hooks/scope-guard.sh +0 -52
- package/dist/templates/.cursor/hooks/session-log.sh +0 -924
- package/dist/templates/.cursor/hooks/validate-spec.sh +0 -83
- package/dist/templates/.cursor/hooks.json +0 -76
- package/dist/templates/.cursor/rules/00-claims-verification.mdc +0 -144
- package/dist/templates/.cursor/rules/01-working-style.mdc +0 -50
- package/dist/templates/.cursor/rules/02-quality-gates.mdc +0 -368
- package/dist/templates/.cursor/rules/03-naming-and-refactor.mdc +0 -33
- package/dist/templates/.cursor/rules/04-logging-language-style.mdc +0 -23
- package/dist/templates/.cursor/rules/05-safe-defaults-guards.mdc +0 -23
- package/dist/templates/.cursor/rules/06-typescript-conventions.mdc +0 -36
- package/dist/templates/.cursor/rules/07-process-ops.mdc +0 -20
- package/dist/templates/.cursor/rules/08-solid-and-architecture.mdc +0 -16
- package/dist/templates/.cursor/rules/09-docstrings.mdc +0 -89
- package/dist/templates/.cursor/rules/10-documentation-quality-standards.mdc +0 -385
- package/dist/templates/.cursor/rules/11-scope-management-waivers.mdc +0 -381
- package/dist/templates/.cursor/rules/12-implementation-completeness.mdc +0 -516
- package/dist/templates/.cursor/rules/13-language-agnostic-standards.mdc +0 -578
- package/dist/templates/.cursor/rules/README.md +0 -148
- package/dist/templates/.github/copilot-instructions.md +0 -82
- package/dist/templates/.idea/runConfigurations/CAWS_Evaluate.xml +0 -5
- package/dist/templates/.idea/runConfigurations/CAWS_Validate.xml +0 -5
- package/dist/templates/.junie/guidelines.md +0 -73
- package/dist/templates/.vscode/launch.json +0 -17
- package/dist/templates/.vscode/settings.json +0 -95
- package/dist/templates/.windsurf/rules/caws-quality-standards.md +0 -54
- package/dist/templates/.windsurf/workflows/caws-guided-development.md +0 -92
- package/dist/templates/CLAUDE.md +0 -174
- package/dist/templates/COMMIT_CONVENTIONS.md +0 -86
- package/dist/templates/OIDC_SETUP.md +0 -300
- package/dist/templates/agents.md +0 -145
- package/dist/templates/codemod/README.md +0 -1
- package/dist/templates/codemod/test.js +0 -93
- package/dist/templates/docs/README.md +0 -151
- package/dist/templates/scripts/new_feature.sh +0 -80
- package/dist/templates/scripts/quality-gates/check-god-objects.js +0 -146
- package/dist/templates/scripts/quality-gates/run-quality-gates.js +0 -50
- package/dist/templates/scripts/v3/analysis/todo_analyzer.py +0 -1997
- package/dist/test-analysis.js +0 -786
- package/dist/tool-interface.js +0 -314
- package/dist/tool-loader.js +0 -303
- package/dist/tool-validator.js +0 -393
- package/dist/utils/agent-session.js +0 -202
- package/dist/utils/async-utils.js +0 -188
- package/dist/utils/command-wrapper.js +0 -200
- package/dist/utils/event-log.js +0 -584
- package/dist/utils/event-renderer.js +0 -521
- package/dist/utils/finalization.js +0 -230
- package/dist/utils/git-lock.js +0 -119
- package/dist/utils/gitignore-updater.js +0 -158
- package/dist/utils/ide-detection.js +0 -133
- package/dist/utils/lifecycle-events.js +0 -94
- package/dist/utils/project-analysis.js +0 -367
- package/dist/utils/promise-utils.js +0 -72
- package/dist/utils/quality-gates-errors.js +0 -520
- package/dist/utils/quality-gates-utils.js +0 -387
- package/dist/utils/schema-validator.js +0 -50
- package/dist/utils/spec-resolver.js +0 -711
- package/dist/utils/typescript-detector.js +0 -369
- package/dist/utils/working-state.js +0 -530
- package/dist/utils/yaml-validation.js +0 -156
- package/dist/validation/spec-validation.js +0 -921
- package/dist/waivers-manager.js +0 -732
- package/dist/worktree/worktree-manager.js +0 -1374
- package/templates/.caws/schemas/policy.schema.json +0 -112
- package/templates/.caws/schemas/scope.schema.json +0 -52
- package/templates/.caws/schemas/waivers.schema.json +0 -106
- package/templates/.caws/schemas/working-spec.schema.json +0 -340
- package/templates/.caws/schemas/worktrees.schema.json +0 -38
- package/templates/.caws/templates/working-spec.template.yml +0 -80
- package/templates/.caws/tools/README.md +0 -18
- package/templates/.caws/tools/scope-guard.js +0 -203
- package/templates/.caws/tools-allow.json +0 -331
- package/templates/.caws/waivers.yml +0 -19
- package/templates/.claude/README.md +0 -190
- package/templates/.claude/hooks/audit.sh +0 -121
- package/templates/.claude/hooks/block-dangerous.sh +0 -203
- package/templates/.claude/hooks/classify_command.py +0 -592
- package/templates/.claude/hooks/doc-frontmatter-check.sh +0 -173
- package/templates/.claude/hooks/lite-sprawl-check.sh +0 -145
- package/templates/.claude/hooks/naming-check.sh +0 -100
- package/templates/.claude/hooks/protected-paths.sh +0 -39
- package/templates/.claude/hooks/quality-check.sh +0 -81
- package/templates/.claude/hooks/scan-secrets.sh +0 -85
- package/templates/.claude/hooks/scope-guard.sh +0 -381
- package/templates/.claude/hooks/session-caws-status.sh +0 -117
- package/templates/.claude/hooks/session-log.sh +0 -634
- package/templates/.claude/hooks/simplification-guard.sh +0 -92
- package/templates/.claude/hooks/stop-worktree-check.sh +0 -46
- package/templates/.claude/hooks/test_classify_command.py +0 -370
- package/templates/.claude/hooks/test_wrapper_smoke.sh +0 -96
- package/templates/.claude/hooks/validate-spec.sh +0 -76
- package/templates/.claude/hooks/worktree-guard.sh +0 -220
- package/templates/.claude/hooks/worktree-write-guard.sh +0 -190
- package/templates/.claude/rules/git-safety.md +0 -26
- package/templates/.claude/rules/worktree-isolation.md +0 -83
- package/templates/.claude/settings.json +0 -141
- package/templates/.cursor/README.md +0 -299
- package/templates/.cursor/hooks/audit.sh +0 -55
- package/templates/.cursor/hooks/block-dangerous.sh +0 -84
- package/templates/.cursor/hooks/caws-quality-check.sh +0 -52
- package/templates/.cursor/hooks/caws-scope-guard.sh +0 -130
- package/templates/.cursor/hooks/format.sh +0 -38
- package/templates/.cursor/hooks/naming-check.sh +0 -64
- package/templates/.cursor/hooks/scan-secrets.sh +0 -51
- package/templates/.cursor/hooks/scope-guard.sh +0 -52
- package/templates/.cursor/hooks/session-log.sh +0 -924
- package/templates/.cursor/hooks/validate-spec.sh +0 -83
- package/templates/.cursor/hooks.json +0 -76
- package/templates/.cursor/rules/00-claims-verification.mdc +0 -144
- package/templates/.cursor/rules/01-working-style.mdc +0 -50
- package/templates/.cursor/rules/02-quality-gates.mdc +0 -368
- package/templates/.cursor/rules/03-naming-and-refactor.mdc +0 -33
- package/templates/.cursor/rules/04-logging-language-style.mdc +0 -23
- package/templates/.cursor/rules/05-safe-defaults-guards.mdc +0 -23
- package/templates/.cursor/rules/06-typescript-conventions.mdc +0 -36
- package/templates/.cursor/rules/07-process-ops.mdc +0 -20
- package/templates/.cursor/rules/08-solid-and-architecture.mdc +0 -16
- package/templates/.cursor/rules/09-docstrings.mdc +0 -89
- package/templates/.cursor/rules/10-documentation-quality-standards.mdc +0 -385
- package/templates/.cursor/rules/11-scope-management-waivers.mdc +0 -381
- package/templates/.cursor/rules/12-implementation-completeness.mdc +0 -516
- package/templates/.cursor/rules/13-language-agnostic-standards.mdc +0 -578
- package/templates/.cursor/rules/README.md +0 -148
- package/templates/.github/copilot-instructions.md +0 -82
- package/templates/.idea/runConfigurations/CAWS_Evaluate.xml +0 -5
- package/templates/.idea/runConfigurations/CAWS_Validate.xml +0 -5
- package/templates/.junie/guidelines.md +0 -73
- package/templates/.vscode/launch.json +0 -17
- package/templates/.vscode/settings.json +0 -95
- package/templates/.windsurf/rules/caws-quality-standards.md +0 -54
- package/templates/.windsurf/workflows/caws-guided-development.md +0 -92
- package/templates/CLAUDE.md +0 -174
- package/templates/COMMIT_CONVENTIONS.md +0 -86
- package/templates/OIDC_SETUP.md +0 -300
- package/templates/agents.md +0 -145
- package/templates/codemod/README.md +0 -1
- package/templates/codemod/test.js +0 -93
- package/templates/docs/README.md +0 -151
- package/templates/scripts/new_feature.sh +0 -80
- package/templates/scripts/quality-gates/check-god-objects.js +0 -146
- package/templates/scripts/quality-gates/run-quality-gates.js +0 -50
- package/templates/scripts/v3/analysis/todo_analyzer.py +0 -1997
package/dist/commands/waivers.js
DELETED
|
@@ -1,599 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CAWS Waivers Command
|
|
3
|
-
*
|
|
4
|
-
* Manage quality gate waivers for exceptional circumstances.
|
|
5
|
-
* Waivers allow temporary exceptions to quality requirements
|
|
6
|
-
* with proper documentation and approval.
|
|
7
|
-
*
|
|
8
|
-
* @author @darianrosebrook
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
const fs = require('fs');
|
|
12
|
-
const path = require('path');
|
|
13
|
-
const yaml = require('js-yaml');
|
|
14
|
-
const chalk = require('chalk');
|
|
15
|
-
const { initializeGlobalSetup } = require('../config');
|
|
16
|
-
const { getAgentSessionId } = require('../utils/agent-session');
|
|
17
|
-
const WaiversManager = require('../waivers-manager');
|
|
18
|
-
const { commandWrapper, Output } = require('../utils/command-wrapper');
|
|
19
|
-
|
|
20
|
-
const WAIVER_DIR = '.caws/waivers';
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Valid gate identifiers recognized by the quality-gates package.
|
|
24
|
-
* These must match the gate names used in processViolations() calls
|
|
25
|
-
* within the check-*.mjs files.
|
|
26
|
-
*/
|
|
27
|
-
const VALID_GATES = [
|
|
28
|
-
'budget_limit',
|
|
29
|
-
'spec_completeness',
|
|
30
|
-
'scope_boundary',
|
|
31
|
-
'god_object',
|
|
32
|
-
'todo_detection',
|
|
33
|
-
'*', // wildcard — waiver applies to all gates
|
|
34
|
-
];
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Waivers command handler
|
|
38
|
-
*
|
|
39
|
-
* @param {string} subcommand - create, list, show, revoke
|
|
40
|
-
* @param {object} options - Command options
|
|
41
|
-
*/
|
|
42
|
-
async function waiversCommand(subcommand = 'list', options = {}) {
|
|
43
|
-
return commandWrapper(
|
|
44
|
-
async () => {
|
|
45
|
-
Output.info('Detecting CAWS setup...');
|
|
46
|
-
const setup = initializeGlobalSetup();
|
|
47
|
-
|
|
48
|
-
if (setup.hasWorkingSpec) {
|
|
49
|
-
Output.success(`Detected ${setup.type} CAWS setup`, {
|
|
50
|
-
capabilities: setup.capabilities,
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// Ensure waivers directory exists
|
|
55
|
-
const waiversDir = path.join(process.cwd(), WAIVER_DIR);
|
|
56
|
-
if (!fs.existsSync(waiversDir)) {
|
|
57
|
-
fs.mkdirSync(waiversDir, { recursive: true });
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
switch (subcommand) {
|
|
61
|
-
case 'create':
|
|
62
|
-
return await createWaiver(options);
|
|
63
|
-
case 'list':
|
|
64
|
-
return await listWaivers(options);
|
|
65
|
-
case 'show':
|
|
66
|
-
return await showWaiver(options.id, options);
|
|
67
|
-
case 'revoke':
|
|
68
|
-
return await revokeWaiver(options.id, options);
|
|
69
|
-
case 'prune':
|
|
70
|
-
return await pruneWaivers(options);
|
|
71
|
-
default:
|
|
72
|
-
throw new Error(
|
|
73
|
-
`Unknown waiver subcommand: ${subcommand}.\n` +
|
|
74
|
-
'Available subcommands: create, list, show, revoke, prune'
|
|
75
|
-
);
|
|
76
|
-
}
|
|
77
|
-
},
|
|
78
|
-
{
|
|
79
|
-
commandName: `waivers ${subcommand}`,
|
|
80
|
-
context: { subcommand, options },
|
|
81
|
-
}
|
|
82
|
-
);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Create a new waiver
|
|
87
|
-
*/
|
|
88
|
-
async function createWaiver(options) {
|
|
89
|
-
// Validate all required fields upfront (report all missing at once)
|
|
90
|
-
const required = [
|
|
91
|
-
{ field: 'title', flag: '--title', example: '"Emergency hotfix waiver"' },
|
|
92
|
-
{ field: 'reason', flag: '--reason', example: 'emergency_hotfix' },
|
|
93
|
-
{ field: 'description', flag: '--description', example: '"Critical production bug requires immediate fix"' },
|
|
94
|
-
{ field: 'gates', flag: '--gates', example: `placeholders,naming (valid: ${VALID_GATES.join(', ')})` },
|
|
95
|
-
{ field: 'expiresAt', flag: '--expires-at', example: '2025-12-31T23:59:59Z' },
|
|
96
|
-
{ field: 'approvedBy', flag: '--approved-by', example: '"@manager"' },
|
|
97
|
-
{ field: 'impactLevel', flag: '--impact-level', example: 'high' },
|
|
98
|
-
{ field: 'mitigationPlan', flag: '--mitigation-plan', example: '"Will add tests in follow-up PR within 48h"' },
|
|
99
|
-
];
|
|
100
|
-
const missing = required.filter((r) => !options[r.field]);
|
|
101
|
-
|
|
102
|
-
if (missing.length > 0) {
|
|
103
|
-
console.error(chalk.red(`\nMissing ${missing.length} required option(s):\n`));
|
|
104
|
-
missing.forEach((r) => {
|
|
105
|
-
console.error(` ${chalk.yellow(r.flag)} e.g. ${r.example}`);
|
|
106
|
-
});
|
|
107
|
-
console.log(chalk.dim('\nFull example:'));
|
|
108
|
-
console.log(' caws waivers create \\');
|
|
109
|
-
required.forEach((r, i) => {
|
|
110
|
-
const sep = i < required.length - 1 ? ' \\' : '';
|
|
111
|
-
console.log(` ${r.flag}=${r.example}${sep}`);
|
|
112
|
-
});
|
|
113
|
-
process.exit(1);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// Parse gates
|
|
117
|
-
const gates =
|
|
118
|
-
typeof options.gates === 'string'
|
|
119
|
-
? options.gates.split(',').map((g) => g.trim())
|
|
120
|
-
: options.gates;
|
|
121
|
-
|
|
122
|
-
// Validate gate names against known identifiers
|
|
123
|
-
const invalidGates = gates.filter((g) => !VALID_GATES.includes(g));
|
|
124
|
-
if (invalidGates.length > 0) {
|
|
125
|
-
console.error(chalk.red(`\nUnrecognized gate name(s): ${invalidGates.join(', ')}`));
|
|
126
|
-
console.log(`\nValid gate names: ${VALID_GATES.join(', ')}`);
|
|
127
|
-
|
|
128
|
-
// Suggest close matches
|
|
129
|
-
invalidGates.forEach((bad) => {
|
|
130
|
-
const suggestion = VALID_GATES.find(
|
|
131
|
-
(v) => v !== '*' && (v.includes(bad) || bad.includes(v))
|
|
132
|
-
);
|
|
133
|
-
if (suggestion) {
|
|
134
|
-
console.log(chalk.yellow(` "${bad}" -> did you mean "${suggestion}"?`));
|
|
135
|
-
}
|
|
136
|
-
});
|
|
137
|
-
process.exit(1);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
// Self-approval prevention: creator cannot be approver
|
|
141
|
-
// Uses strict equality — the previous .includes() check was an asymmetric
|
|
142
|
-
// substring match that produced false positives (blocking legitimate approvers
|
|
143
|
-
// whose name happened to contain the session ID) while missing the reverse
|
|
144
|
-
// case (approver is a prefix of the session ID).
|
|
145
|
-
// When CLAUDE_SESSION_ID is unset or empty, we can't identify the creator,
|
|
146
|
-
// so self-approval prevention is skipped ('' || null → null → falsy guard).
|
|
147
|
-
const creatorSession = getAgentSessionId(process.cwd());
|
|
148
|
-
if (creatorSession && options.approvedBy) {
|
|
149
|
-
if (options.approvedBy === creatorSession) {
|
|
150
|
-
throw new Error(
|
|
151
|
-
'Waiver creator cannot be the approver.\n' +
|
|
152
|
-
'A different agent or human must approve this waiver.\n' +
|
|
153
|
-
`Creator session: ${creatorSession}`
|
|
154
|
-
);
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
// Generate waiver ID
|
|
159
|
-
const waiverId = `WV-${Date.now().toString().slice(-4)}`;
|
|
160
|
-
const timestamp = new Date().toISOString();
|
|
161
|
-
|
|
162
|
-
// Create waiver object
|
|
163
|
-
const waiver = {
|
|
164
|
-
id: waiverId,
|
|
165
|
-
title: options.title,
|
|
166
|
-
reason: options.reason,
|
|
167
|
-
description: options.description,
|
|
168
|
-
gates: gates,
|
|
169
|
-
created_at: timestamp,
|
|
170
|
-
expires_at: options.expiresAt,
|
|
171
|
-
approved_by: options.approvedBy,
|
|
172
|
-
impact_level: options.impactLevel,
|
|
173
|
-
mitigation_plan: options.mitigationPlan,
|
|
174
|
-
status: 'active',
|
|
175
|
-
created_by_session: creatorSession,
|
|
176
|
-
};
|
|
177
|
-
|
|
178
|
-
// Validate waiver against schema before persisting
|
|
179
|
-
try {
|
|
180
|
-
const { createValidator, getSchemaPath } = require('../utils/schema-validator');
|
|
181
|
-
const schemaPath = getSchemaPath('waivers.schema.json', process.cwd());
|
|
182
|
-
const validate = createValidator(schemaPath);
|
|
183
|
-
// waivers.schema.json validates a single waiver document directly (CAWSFIX-17)
|
|
184
|
-
const result = validate(waiver);
|
|
185
|
-
if (!result.valid) {
|
|
186
|
-
console.warn(chalk.yellow('Waiver has schema violations:'));
|
|
187
|
-
result.errors.forEach((err) => {
|
|
188
|
-
console.warn(chalk.yellow(` ${err.instancePath}: ${err.message}`));
|
|
189
|
-
});
|
|
190
|
-
}
|
|
191
|
-
} catch (schemaErr) {
|
|
192
|
-
// Non-fatal — don't block waiver creation on schema issues
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
// Save individual waiver file
|
|
196
|
-
const waiverPath = path.join(process.cwd(), WAIVER_DIR, `${waiverId}.yaml`);
|
|
197
|
-
fs.writeFileSync(waiverPath, yaml.dump(waiver, { lineWidth: -1 }));
|
|
198
|
-
|
|
199
|
-
// Also add to active waivers file
|
|
200
|
-
try {
|
|
201
|
-
await addToActiveWaivers(waiver);
|
|
202
|
-
} catch (error) {
|
|
203
|
-
console.error(`Failed to add waiver to active waivers: ${error.message}`);
|
|
204
|
-
console.error(error.stack);
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
console.log(chalk.green(`\nWaiver created: ${waiverId}`));
|
|
208
|
-
console.log(` Title: ${waiver.title}`);
|
|
209
|
-
console.log(` Reason: ${waiver.reason}`);
|
|
210
|
-
console.log(` Gates: ${waiver.gates.join(', ')}`);
|
|
211
|
-
console.log(` Expires: ${waiver.expires_at}`);
|
|
212
|
-
console.log(` Approved by: ${waiver.approved_by}`);
|
|
213
|
-
console.log(` Impact: ${waiver.impact_level}`);
|
|
214
|
-
console.log(chalk.yellow(`\n Note: This waiver expires on ${waiver.expires_at}`));
|
|
215
|
-
console.log(chalk.yellow(` Mitigation plan: ${waiver.mitigation_plan}\n`));
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
/**
|
|
219
|
-
* List all waivers
|
|
220
|
-
*/
|
|
221
|
-
async function listWaivers(_options) {
|
|
222
|
-
const waiversDir = path.join(process.cwd(), WAIVER_DIR);
|
|
223
|
-
|
|
224
|
-
if (!fs.existsSync(waiversDir)) {
|
|
225
|
-
console.log(chalk.yellow('\nNo waivers found.\n'));
|
|
226
|
-
return;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
const waiverFiles = fs.readdirSync(waiversDir).filter((f) => f.endsWith('.yaml'));
|
|
230
|
-
|
|
231
|
-
if (waiverFiles.length === 0) {
|
|
232
|
-
console.log(chalk.yellow('\nNo waivers found.\n'));
|
|
233
|
-
return;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
// Load a schema validator once for all waiver files (if available)
|
|
237
|
-
let waiverValidate = null;
|
|
238
|
-
try {
|
|
239
|
-
const { createValidator, getSchemaPath } = require('../utils/schema-validator');
|
|
240
|
-
const schemaPath = getSchemaPath('waivers.schema.json', process.cwd());
|
|
241
|
-
waiverValidate = createValidator(schemaPath);
|
|
242
|
-
} catch {
|
|
243
|
-
// Schema not available — skip validation
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
const waivers = waiverFiles.map((file) => {
|
|
247
|
-
const content = fs.readFileSync(path.join(waiversDir, file), 'utf8');
|
|
248
|
-
const waiver = yaml.load(content);
|
|
249
|
-
|
|
250
|
-
// Validate each loaded waiver against schema
|
|
251
|
-
if (waiverValidate && waiver && waiver.id) {
|
|
252
|
-
const result = waiverValidate(waiver);
|
|
253
|
-
if (!result.valid) {
|
|
254
|
-
console.warn(chalk.yellow(`Schema warning for ${file}:`));
|
|
255
|
-
result.errors.forEach((err) => {
|
|
256
|
-
console.warn(chalk.yellow(` ${err.instancePath}: ${err.message}`));
|
|
257
|
-
});
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
return waiver;
|
|
262
|
-
});
|
|
263
|
-
|
|
264
|
-
// Filter by status
|
|
265
|
-
const activeWaivers = waivers.filter(
|
|
266
|
-
(w) => w.status === 'active' && new Date(w.expires_at) > new Date()
|
|
267
|
-
);
|
|
268
|
-
const expiredWaivers = waivers.filter(
|
|
269
|
-
(w) => w.status === 'active' && new Date(w.expires_at) <= new Date()
|
|
270
|
-
);
|
|
271
|
-
const revokedWaivers = waivers.filter((w) => w.status === 'revoked');
|
|
272
|
-
|
|
273
|
-
console.log(chalk.blue('\nCAWS Quality Gate Waivers\n'));
|
|
274
|
-
console.log('-'.repeat(60));
|
|
275
|
-
|
|
276
|
-
if (activeWaivers.length > 0) {
|
|
277
|
-
console.log(chalk.green('\nActive Waivers:\n'));
|
|
278
|
-
activeWaivers.forEach((waiver) => {
|
|
279
|
-
const daysLeft = Math.ceil(
|
|
280
|
-
(new Date(waiver.expires_at) - new Date()) / (1000 * 60 * 60 * 24)
|
|
281
|
-
);
|
|
282
|
-
console.log(` ${chalk.bold(waiver.id)}: ${waiver.title}`);
|
|
283
|
-
console.log(` Reason: ${waiver.reason}`);
|
|
284
|
-
console.log(` Gates: ${waiver.gates.join(', ')}`);
|
|
285
|
-
console.log(` Expires: ${waiver.expires_at} (${daysLeft} days)`);
|
|
286
|
-
console.log(` Impact: ${waiver.impact_level}`);
|
|
287
|
-
console.log();
|
|
288
|
-
});
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
if (expiredWaivers.length > 0) {
|
|
292
|
-
console.log(chalk.yellow('\nExpired Waivers:\n'));
|
|
293
|
-
expiredWaivers.forEach((waiver) => {
|
|
294
|
-
console.log(` ${chalk.bold(waiver.id)}: ${waiver.title}`);
|
|
295
|
-
console.log(` Expired: ${waiver.expires_at}`);
|
|
296
|
-
console.log();
|
|
297
|
-
});
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
if (revokedWaivers.length > 0) {
|
|
301
|
-
console.log(chalk.red('\nRevoked Waivers:\n'));
|
|
302
|
-
revokedWaivers.forEach((waiver) => {
|
|
303
|
-
console.log(` ${chalk.bold(waiver.id)}: ${waiver.title}`);
|
|
304
|
-
console.log(` Revoked: ${waiver.revoked_at}`);
|
|
305
|
-
console.log();
|
|
306
|
-
});
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
console.log(chalk.blue('Summary:\n'));
|
|
310
|
-
console.log(` Active: ${activeWaivers.length}`);
|
|
311
|
-
console.log(` Expired: ${expiredWaivers.length}`);
|
|
312
|
-
console.log(` Revoked: ${revokedWaivers.length}`);
|
|
313
|
-
console.log(` Total: ${waivers.length}\n`);
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
/**
|
|
317
|
-
* Show waiver details
|
|
318
|
-
*/
|
|
319
|
-
async function showWaiver(waiverId, _options) {
|
|
320
|
-
if (!waiverId) {
|
|
321
|
-
console.error(chalk.red('\nWaiver ID required'));
|
|
322
|
-
console.log(chalk.yellow('Usage: caws waivers show WV-1234\n'));
|
|
323
|
-
process.exit(1);
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
const waiverPath = path.join(process.cwd(), WAIVER_DIR, `${waiverId}.yaml`);
|
|
327
|
-
|
|
328
|
-
if (!fs.existsSync(waiverPath)) {
|
|
329
|
-
console.error(chalk.red(`\nWaiver not found: ${waiverId}\n`));
|
|
330
|
-
process.exit(1);
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
const content = fs.readFileSync(waiverPath, 'utf8');
|
|
334
|
-
const waiver = yaml.load(content);
|
|
335
|
-
|
|
336
|
-
const isExpired = new Date(waiver.expires_at) <= new Date();
|
|
337
|
-
const isActive = waiver.status === 'active' && !isExpired;
|
|
338
|
-
const statusLabel = isActive ? chalk.green('Active') : isExpired ? chalk.yellow('Expired') : chalk.red(waiver.status);
|
|
339
|
-
|
|
340
|
-
console.log(chalk.blue('\nWaiver Details\n'));
|
|
341
|
-
console.log('-'.repeat(60));
|
|
342
|
-
console.log(`\nStatus: ${statusLabel}`);
|
|
343
|
-
console.log(`\n${chalk.bold(waiver.title)}`);
|
|
344
|
-
console.log(` ID: ${waiver.id}`);
|
|
345
|
-
console.log(` Reason: ${waiver.reason}`);
|
|
346
|
-
console.log(` Impact Level: ${waiver.impact_level}`);
|
|
347
|
-
console.log(`\nDescription:`);
|
|
348
|
-
console.log(` ${waiver.description}`);
|
|
349
|
-
console.log(`\nWaived Quality Gates:`);
|
|
350
|
-
waiver.gates.forEach((gate) => {
|
|
351
|
-
console.log(` - ${gate}`);
|
|
352
|
-
});
|
|
353
|
-
console.log(`\nMitigation Plan:`);
|
|
354
|
-
console.log(` ${waiver.mitigation_plan}`);
|
|
355
|
-
console.log(`\nTimeline:`);
|
|
356
|
-
console.log(` Created: ${waiver.created_at}`);
|
|
357
|
-
console.log(` Expires: ${waiver.expires_at}`);
|
|
358
|
-
if (waiver.revoked_at) {
|
|
359
|
-
console.log(` Revoked: ${waiver.revoked_at}`);
|
|
360
|
-
}
|
|
361
|
-
console.log(`\nApproved by: ${waiver.approved_by}\n`);
|
|
362
|
-
|
|
363
|
-
if (isExpired && waiver.status === 'active') {
|
|
364
|
-
console.log(chalk.yellow('Warning: This waiver has expired. Consider revoking it.\n'));
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
/**
|
|
369
|
-
* Revoke a waiver
|
|
370
|
-
*/
|
|
371
|
-
async function revokeWaiver(waiverId, options) {
|
|
372
|
-
if (!waiverId) {
|
|
373
|
-
console.error(chalk.red('\nWaiver ID required'));
|
|
374
|
-
console.log(chalk.yellow('Usage: caws waivers revoke WV-1234\n'));
|
|
375
|
-
process.exit(1);
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
const waiverPath = path.join(process.cwd(), WAIVER_DIR, `${waiverId}.yaml`);
|
|
379
|
-
|
|
380
|
-
if (!fs.existsSync(waiverPath)) {
|
|
381
|
-
console.error(chalk.red(`\nWaiver not found: ${waiverId}\n`));
|
|
382
|
-
process.exit(1);
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
const content = fs.readFileSync(waiverPath, 'utf8');
|
|
386
|
-
const waiver = yaml.load(content);
|
|
387
|
-
|
|
388
|
-
if (waiver.status === 'revoked') {
|
|
389
|
-
console.log(chalk.yellow(`\nWaiver ${waiverId} is already revoked\n`));
|
|
390
|
-
return;
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
// Update waiver status
|
|
394
|
-
waiver.status = 'revoked';
|
|
395
|
-
waiver.revoked_at = new Date().toISOString();
|
|
396
|
-
waiver.revoked_by = options.revokedBy || 'system';
|
|
397
|
-
waiver.revocation_reason = options.reason || 'Manual revocation';
|
|
398
|
-
|
|
399
|
-
// Save updated waiver
|
|
400
|
-
fs.writeFileSync(waiverPath, yaml.dump(waiver, { lineWidth: -1 }));
|
|
401
|
-
|
|
402
|
-
console.log(chalk.green(`\nWaiver revoked: ${waiverId}`));
|
|
403
|
-
console.log(` Title: ${waiver.title}`);
|
|
404
|
-
console.log(` Revoked at: ${waiver.revoked_at}`);
|
|
405
|
-
console.log(` Revoked by: ${waiver.revoked_by}`);
|
|
406
|
-
console.log(` Reason: ${waiver.revocation_reason}\n`);
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
/**
|
|
410
|
-
* Prune expired waivers.
|
|
411
|
-
*
|
|
412
|
-
* Behavior per CAWSFIX-04 AC3-A6:
|
|
413
|
-
* --expired : dry run — list prunable waivers, no disk changes,
|
|
414
|
-
* no events emitted. Exit 0.
|
|
415
|
-
* --expired --apply : transition each prunable waiver from
|
|
416
|
-
* `status: active` to `status: expired` in place
|
|
417
|
-
* (file is updated, NOT deleted, to preserve the
|
|
418
|
-
* audit trail) and append a `waiver_pruned` event
|
|
419
|
-
* to the event log for each.
|
|
420
|
-
*
|
|
421
|
-
* A waiver is "prunable" iff `status === 'active'` AND `expires_at < now`.
|
|
422
|
-
* Waivers already `expired` or `revoked` are untouched (A4). Non-expired
|
|
423
|
-
* active waivers are untouched (A5). Empty registries exit 0 with a
|
|
424
|
-
* friendly message (A6).
|
|
425
|
-
*
|
|
426
|
-
* @param {object} options
|
|
427
|
-
* @param {boolean} [options.expired] — currently the only prune criterion
|
|
428
|
-
* @param {boolean} [options.apply] — if false, dry-run (default)
|
|
429
|
-
* @param {boolean} [options.json] — machine-readable output
|
|
430
|
-
*/
|
|
431
|
-
async function pruneWaivers(options = {}) {
|
|
432
|
-
if (!options.expired) {
|
|
433
|
-
console.error(chalk.red('\n`caws waivers prune` requires --expired\n'));
|
|
434
|
-
console.log(chalk.yellow('Usage: caws waivers prune --expired [--apply]\n'));
|
|
435
|
-
process.exit(1);
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
const waiversManager = new WaiversManager();
|
|
439
|
-
|
|
440
|
-
// Fast path: no waivers directory or no waiver files at all.
|
|
441
|
-
const allWaivers = waiversManager.enumerateWaiverFiles();
|
|
442
|
-
if (allWaivers.length === 0) {
|
|
443
|
-
const msg = 'No active waivers to check.';
|
|
444
|
-
if (options.json) {
|
|
445
|
-
console.log(JSON.stringify({ status: 'ok', pruned: [], message: msg }));
|
|
446
|
-
} else {
|
|
447
|
-
console.log(chalk.yellow(`\n${msg}\n`));
|
|
448
|
-
}
|
|
449
|
-
return { pruned: [], applied: false };
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
const candidates = waiversManager.findExpiredWaivers();
|
|
453
|
-
|
|
454
|
-
// No prunable waivers — report and return.
|
|
455
|
-
if (candidates.length === 0) {
|
|
456
|
-
const msg = 'No expired waivers to prune.';
|
|
457
|
-
if (options.json) {
|
|
458
|
-
console.log(JSON.stringify({ status: 'ok', pruned: [], message: msg }));
|
|
459
|
-
} else {
|
|
460
|
-
console.log(chalk.green(`\n${msg}\n`));
|
|
461
|
-
}
|
|
462
|
-
return { pruned: [], applied: false };
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
const apply = Boolean(options.apply);
|
|
466
|
-
|
|
467
|
-
if (!apply) {
|
|
468
|
-
// Dry run — report only, no disk changes, no events.
|
|
469
|
-
if (options.json) {
|
|
470
|
-
console.log(
|
|
471
|
-
JSON.stringify({
|
|
472
|
-
status: 'dry_run',
|
|
473
|
-
applied: false,
|
|
474
|
-
pruned: candidates.map((c) => ({ id: c.id, expires_at: c.expires_at })),
|
|
475
|
-
})
|
|
476
|
-
);
|
|
477
|
-
} else {
|
|
478
|
-
console.log(chalk.yellow(`\nDry run — ${candidates.length} waiver(s) would be pruned:\n`));
|
|
479
|
-
candidates.forEach((c) => {
|
|
480
|
-
console.log(` ${chalk.bold(c.id)} expired at ${c.expires_at}`);
|
|
481
|
-
});
|
|
482
|
-
console.log(chalk.dim('\nRe-run with --apply to transition status to expired.\n'));
|
|
483
|
-
}
|
|
484
|
-
return { pruned: candidates, applied: false };
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
// Apply path — transition each file and emit events.
|
|
488
|
-
const { appendEvent } = require('../utils/event-log');
|
|
489
|
-
const pruned = [];
|
|
490
|
-
const failures = [];
|
|
491
|
-
|
|
492
|
-
for (const c of candidates) {
|
|
493
|
-
try {
|
|
494
|
-
const updated = waiversManager.markWaiverExpired(c.path);
|
|
495
|
-
|
|
496
|
-
// Emit waiver_pruned event. spec_id is optional for this event
|
|
497
|
-
// (waivers may or may not be tied to a spec). Using the waiver's
|
|
498
|
-
// applies_to field when available, otherwise omitting.
|
|
499
|
-
const spec_id =
|
|
500
|
-
updated && typeof updated.applies_to === 'string' && updated.applies_to.trim() !== ''
|
|
501
|
-
? updated.applies_to
|
|
502
|
-
: undefined;
|
|
503
|
-
|
|
504
|
-
await appendEvent({
|
|
505
|
-
actor: 'cli',
|
|
506
|
-
event: 'waiver_pruned',
|
|
507
|
-
spec_id,
|
|
508
|
-
data: {
|
|
509
|
-
waiver_id: c.id,
|
|
510
|
-
expires_at: c.expires_at,
|
|
511
|
-
previous_status: 'active',
|
|
512
|
-
new_status: 'expired',
|
|
513
|
-
},
|
|
514
|
-
});
|
|
515
|
-
|
|
516
|
-
pruned.push({ id: c.id, expires_at: c.expires_at });
|
|
517
|
-
} catch (err) {
|
|
518
|
-
failures.push({ id: c.id, error: err.message });
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
if (options.json) {
|
|
523
|
-
console.log(
|
|
524
|
-
JSON.stringify({
|
|
525
|
-
status: failures.length === 0 ? 'ok' : 'partial',
|
|
526
|
-
applied: true,
|
|
527
|
-
pruned,
|
|
528
|
-
failures,
|
|
529
|
-
})
|
|
530
|
-
);
|
|
531
|
-
} else {
|
|
532
|
-
console.log(
|
|
533
|
-
chalk.green(`\nPruned ${pruned.length} expired waiver(s):\n`)
|
|
534
|
-
);
|
|
535
|
-
pruned.forEach((p) => {
|
|
536
|
-
console.log(` ${chalk.bold(p.id)} (was expired at ${p.expires_at})`);
|
|
537
|
-
});
|
|
538
|
-
if (failures.length > 0) {
|
|
539
|
-
console.log(chalk.red(`\n${failures.length} failure(s):\n`));
|
|
540
|
-
failures.forEach((f) => {
|
|
541
|
-
console.log(` ${chalk.bold(f.id)}: ${f.error}`);
|
|
542
|
-
});
|
|
543
|
-
}
|
|
544
|
-
console.log();
|
|
545
|
-
}
|
|
546
|
-
|
|
547
|
-
return { pruned, applied: true, failures };
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
/**
|
|
551
|
-
* Add waiver to active waivers file for quality gates integration
|
|
552
|
-
*/
|
|
553
|
-
async function addToActiveWaivers(waiver) {
|
|
554
|
-
try {
|
|
555
|
-
const waiversManager = new WaiversManager();
|
|
556
|
-
|
|
557
|
-
// Load existing active waivers
|
|
558
|
-
const activeWaivers = await waiversManager.loadActiveWaivers();
|
|
559
|
-
|
|
560
|
-
// Check if waiver already exists
|
|
561
|
-
const existingIndex = activeWaivers.findIndex((w) => w.id === waiver.id);
|
|
562
|
-
|
|
563
|
-
// Normalize waiver format
|
|
564
|
-
const normalizedWaiver = {
|
|
565
|
-
id: waiver.id,
|
|
566
|
-
title: waiver.title || waiver.description || waiver.id,
|
|
567
|
-
reason: waiver.reason || waiver.reason_code || 'unknown',
|
|
568
|
-
description: waiver.description || waiver.title || waiver.id,
|
|
569
|
-
gates: Array.isArray(waiver.gates) ? waiver.gates : [waiver.gates],
|
|
570
|
-
expires_at: waiver.expires_at,
|
|
571
|
-
approved_by: waiver.approved_by || waiver.risk_owner || 'unknown',
|
|
572
|
-
created_at: waiver.created_at || waiver.approved_at || new Date().toISOString(),
|
|
573
|
-
risk_assessment: waiver.risk_assessment || {
|
|
574
|
-
impact_level: waiver.impact_level || 'medium',
|
|
575
|
-
mitigation_plan: waiver.mitigation || waiver.mitigation_plan || 'Unknown mitigation',
|
|
576
|
-
},
|
|
577
|
-
metadata: waiver.metadata || {},
|
|
578
|
-
};
|
|
579
|
-
|
|
580
|
-
if (existingIndex >= 0) {
|
|
581
|
-
// Update existing waiver
|
|
582
|
-
activeWaivers[existingIndex] = normalizedWaiver;
|
|
583
|
-
} else {
|
|
584
|
-
// Add new waiver
|
|
585
|
-
activeWaivers.push(normalizedWaiver);
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
// Save updated active waivers
|
|
589
|
-
await waiversManager.saveActiveWaivers(activeWaivers);
|
|
590
|
-
} catch (error) {
|
|
591
|
-
// Enhanced error logging
|
|
592
|
-
console.error(`Error adding waiver to active waivers: ${error.message}`);
|
|
593
|
-
console.error(error.stack);
|
|
594
|
-
console.warn(`Warning: Could not add waiver to active waivers file: ${error.message}`);
|
|
595
|
-
// Don't fail the waiver creation if this fails
|
|
596
|
-
}
|
|
597
|
-
}
|
|
598
|
-
|
|
599
|
-
module.exports = { waiversCommand };
|