@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/test-analysis.js
DELETED
|
@@ -1,786 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @fileoverview Test Analysis Module - v0.1 Statistical Learning
|
|
3
|
-
* Learns from waivers and historical data to improve budget allocation and test selection
|
|
4
|
-
* @author @darianrosebrook
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
const fs = require('fs-extra');
|
|
8
|
-
const path = require('path');
|
|
9
|
-
const yaml = require('js-yaml');
|
|
10
|
-
const { resolveSpec } = require('./utils/spec-resolver');
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Waiver Pattern Learning Engine
|
|
14
|
-
* Analyzes waiver history to find systematic patterns in budget overruns
|
|
15
|
-
*/
|
|
16
|
-
class WaiverPatternLearner {
|
|
17
|
-
constructor(projectRoot = process.cwd()) {
|
|
18
|
-
this.projectRoot = projectRoot;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Analyze waiver patterns from historical data
|
|
23
|
-
*/
|
|
24
|
-
analyzePatterns() {
|
|
25
|
-
try {
|
|
26
|
-
const waivers = this.loadWaivers();
|
|
27
|
-
const specs = this.loadHistoricalSpecs();
|
|
28
|
-
|
|
29
|
-
if (waivers.length === 0) {
|
|
30
|
-
return {
|
|
31
|
-
status: 'insufficient_data',
|
|
32
|
-
message: 'No waiver data available for analysis',
|
|
33
|
-
patterns: {},
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const patterns = {
|
|
38
|
-
total_waivers: waivers.length,
|
|
39
|
-
budget_overruns: this.analyzeBudgetOverruns(waivers, specs),
|
|
40
|
-
common_reasons: this.analyzeCommonReasons(waivers),
|
|
41
|
-
risk_factors: this.identifyRiskFactors(waivers, specs),
|
|
42
|
-
generated_at: new Date().toISOString(),
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
return {
|
|
46
|
-
status: 'success',
|
|
47
|
-
patterns,
|
|
48
|
-
};
|
|
49
|
-
} catch (error) {
|
|
50
|
-
return {
|
|
51
|
-
status: 'error',
|
|
52
|
-
message: error.message,
|
|
53
|
-
patterns: {},
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Load all waiver files from .caws/waivers/
|
|
60
|
-
*/
|
|
61
|
-
loadWaivers() {
|
|
62
|
-
const waiversDir = path.join(this.projectRoot, '.caws', 'waivers');
|
|
63
|
-
if (!fs.existsSync(waiversDir)) {
|
|
64
|
-
return [];
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
const waiverFiles = fs
|
|
68
|
-
.readdirSync(waiversDir)
|
|
69
|
-
.filter((file) => file.endsWith('.yaml'))
|
|
70
|
-
.map((file) => {
|
|
71
|
-
try {
|
|
72
|
-
const waiverPath = path.join(waiversDir, file);
|
|
73
|
-
const waiver = yaml.load(fs.readFileSync(waiverPath, 'utf8'));
|
|
74
|
-
return { ...waiver, file: file };
|
|
75
|
-
} catch (error) {
|
|
76
|
-
console.warn(`Failed to load waiver ${file}: ${error.message}`);
|
|
77
|
-
return null;
|
|
78
|
-
}
|
|
79
|
-
})
|
|
80
|
-
.filter((waiver) => waiver !== null);
|
|
81
|
-
|
|
82
|
-
return waiverFiles;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Load historical working specs from git history
|
|
87
|
-
* Retrieves past versions of spec files to analyze patterns
|
|
88
|
-
*/
|
|
89
|
-
loadHistoricalSpecs() {
|
|
90
|
-
const { execSync } = require('child_process');
|
|
91
|
-
const specs = [];
|
|
92
|
-
|
|
93
|
-
try {
|
|
94
|
-
// Get list of commits that modified spec files
|
|
95
|
-
const specPaths = [
|
|
96
|
-
'.caws/working-spec.yaml',
|
|
97
|
-
'.caws/specs/*.yaml',
|
|
98
|
-
];
|
|
99
|
-
|
|
100
|
-
for (const specPattern of specPaths) {
|
|
101
|
-
try {
|
|
102
|
-
// Get commits that touched spec files
|
|
103
|
-
const logOutput = execSync(
|
|
104
|
-
`git log --pretty=format:"%H" --follow -- "${specPattern}" 2>/dev/null | head -20`,
|
|
105
|
-
{ cwd: this.projectRoot, encoding: 'utf8' }
|
|
106
|
-
).trim();
|
|
107
|
-
|
|
108
|
-
if (!logOutput) continue;
|
|
109
|
-
|
|
110
|
-
const commits = logOutput.split('\n').filter(Boolean);
|
|
111
|
-
|
|
112
|
-
for (const commitHash of commits) {
|
|
113
|
-
try {
|
|
114
|
-
// Get the list of files matching the pattern at that commit
|
|
115
|
-
const filesOutput = execSync(
|
|
116
|
-
`git ls-tree -r --name-only ${commitHash} -- "${specPattern}" 2>/dev/null`,
|
|
117
|
-
{ cwd: this.projectRoot, encoding: 'utf8' }
|
|
118
|
-
).trim();
|
|
119
|
-
|
|
120
|
-
if (!filesOutput) continue;
|
|
121
|
-
|
|
122
|
-
const files = filesOutput.split('\n').filter(Boolean);
|
|
123
|
-
|
|
124
|
-
for (const filePath of files) {
|
|
125
|
-
try {
|
|
126
|
-
// Get the spec content at that commit
|
|
127
|
-
const specContent = execSync(
|
|
128
|
-
`git show ${commitHash}:"${filePath}" 2>/dev/null`,
|
|
129
|
-
{ cwd: this.projectRoot, encoding: 'utf8' }
|
|
130
|
-
);
|
|
131
|
-
|
|
132
|
-
const spec = yaml.load(specContent);
|
|
133
|
-
if (spec && spec.id) {
|
|
134
|
-
// Get commit date for context
|
|
135
|
-
const commitDate = execSync(
|
|
136
|
-
`git show -s --format=%ci ${commitHash}`,
|
|
137
|
-
{ cwd: this.projectRoot, encoding: 'utf8' }
|
|
138
|
-
).trim();
|
|
139
|
-
|
|
140
|
-
specs.push({
|
|
141
|
-
...spec,
|
|
142
|
-
_commit: commitHash.substring(0, 7),
|
|
143
|
-
_date: commitDate,
|
|
144
|
-
_file: filePath,
|
|
145
|
-
});
|
|
146
|
-
}
|
|
147
|
-
} catch {
|
|
148
|
-
// Skip files that can't be loaded
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
} catch {
|
|
152
|
-
// Skip commits with issues
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
} catch {
|
|
156
|
-
// Pattern didn't match any files
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
// Also check archived specs in .caws/archive/
|
|
161
|
-
const archiveDir = path.join(this.projectRoot, '.caws', 'archive');
|
|
162
|
-
if (fs.existsSync(archiveDir)) {
|
|
163
|
-
const archiveFiles = fs.readdirSync(archiveDir)
|
|
164
|
-
.filter(f => f.endsWith('.yaml') || f.endsWith('.yml'));
|
|
165
|
-
|
|
166
|
-
for (const file of archiveFiles) {
|
|
167
|
-
try {
|
|
168
|
-
const archivePath = path.join(archiveDir, file);
|
|
169
|
-
const spec = yaml.load(fs.readFileSync(archivePath, 'utf8'));
|
|
170
|
-
if (spec && spec.id) {
|
|
171
|
-
specs.push({
|
|
172
|
-
...spec,
|
|
173
|
-
_source: 'archive',
|
|
174
|
-
_file: file,
|
|
175
|
-
});
|
|
176
|
-
}
|
|
177
|
-
} catch {
|
|
178
|
-
// Skip invalid archive files
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
// Deduplicate by spec ID, keeping the most recent version
|
|
184
|
-
const uniqueSpecs = new Map();
|
|
185
|
-
for (const spec of specs) {
|
|
186
|
-
const existing = uniqueSpecs.get(spec.id);
|
|
187
|
-
if (!existing || (spec._date && (!existing._date || spec._date > existing._date))) {
|
|
188
|
-
uniqueSpecs.set(spec.id, spec);
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
return Array.from(uniqueSpecs.values());
|
|
193
|
-
} catch (error) {
|
|
194
|
-
console.warn(`Failed to load historical specs: ${error.message}`);
|
|
195
|
-
return [];
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* Analyze budget overrun patterns
|
|
201
|
-
*/
|
|
202
|
-
analyzeBudgetOverruns(waivers, _specs) {
|
|
203
|
-
const budgetWaivers = waivers.filter((w) => w.gates?.includes('budget_limit'));
|
|
204
|
-
|
|
205
|
-
if (budgetWaivers.length === 0) {
|
|
206
|
-
return {
|
|
207
|
-
average_overrun_files: 0,
|
|
208
|
-
average_overrun_loc: 0,
|
|
209
|
-
common_patterns: [],
|
|
210
|
-
};
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
const overruns = budgetWaivers
|
|
214
|
-
.filter((w) => w.delta)
|
|
215
|
-
.map((w) => ({
|
|
216
|
-
files: w.delta.max_files || 0,
|
|
217
|
-
loc: w.delta.max_loc || 0,
|
|
218
|
-
reason: w.reason_code,
|
|
219
|
-
applies_to: w.applies_to,
|
|
220
|
-
}));
|
|
221
|
-
|
|
222
|
-
const avgFiles = overruns.reduce((sum, o) => sum + o.files, 0) / overruns.length;
|
|
223
|
-
const avgLoc = overruns.reduce((sum, o) => sum + o.loc, 0) / overruns.length;
|
|
224
|
-
|
|
225
|
-
// Group by reason
|
|
226
|
-
const byReason = overruns.reduce((acc, overrun) => {
|
|
227
|
-
acc[overrun.reason] = acc[overrun.reason] || [];
|
|
228
|
-
acc[overrun.reason].push(overrun);
|
|
229
|
-
return acc;
|
|
230
|
-
}, {});
|
|
231
|
-
|
|
232
|
-
const commonPatterns = Object.entries(byReason)
|
|
233
|
-
.map(([reason, overruns]) => ({
|
|
234
|
-
reason,
|
|
235
|
-
frequency: overruns.length / budgetWaivers.length,
|
|
236
|
-
avg_overrun_files: overruns.reduce((sum, o) => sum + o.files, 0) / overruns.length,
|
|
237
|
-
avg_overrun_loc: overruns.reduce((sum, o) => sum + o.loc, 0) / overruns.length,
|
|
238
|
-
}))
|
|
239
|
-
.sort((a, b) => b.frequency - a.frequency);
|
|
240
|
-
|
|
241
|
-
return {
|
|
242
|
-
total_budget_waivers: budgetWaivers.length,
|
|
243
|
-
average_overrun_files: Math.round(avgFiles),
|
|
244
|
-
average_overrun_loc: Math.round(avgLoc),
|
|
245
|
-
common_patterns: commonPatterns.slice(0, 5), // Top 5 patterns
|
|
246
|
-
};
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
/**
|
|
250
|
-
* Analyze most common waiver reasons
|
|
251
|
-
*/
|
|
252
|
-
analyzeCommonReasons(waivers) {
|
|
253
|
-
const reasons = waivers.reduce((acc, waiver) => {
|
|
254
|
-
acc[waiver.reason_code] = (acc[waiver.reason_code] || 0) + 1;
|
|
255
|
-
return acc;
|
|
256
|
-
}, {});
|
|
257
|
-
|
|
258
|
-
return Object.entries(reasons)
|
|
259
|
-
.map(([reason, count]) => ({
|
|
260
|
-
reason,
|
|
261
|
-
count,
|
|
262
|
-
frequency: count / waivers.length,
|
|
263
|
-
}))
|
|
264
|
-
.sort((a, b) => b.count - a.count);
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
/**
|
|
268
|
-
* Identify risk factors from waiver patterns
|
|
269
|
-
*/
|
|
270
|
-
identifyRiskFactors(waivers, _specs) {
|
|
271
|
-
// Simple risk factor identification based on waiver frequency
|
|
272
|
-
const riskFactors = [];
|
|
273
|
-
|
|
274
|
-
const reasons = this.analyzeCommonReasons(waivers);
|
|
275
|
-
if (reasons.length > 0) {
|
|
276
|
-
riskFactors.push({
|
|
277
|
-
factor: 'common_waiver_reasons',
|
|
278
|
-
description: `${reasons[0].reason} waivers occur in ${Math.round(reasons[0].frequency * 100)}% of cases`,
|
|
279
|
-
risk_level:
|
|
280
|
-
reasons[0].frequency > 0.5 ? 'high' : reasons[0].frequency > 0.3 ? 'medium' : 'low',
|
|
281
|
-
});
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
return riskFactors;
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
/**
|
|
289
|
-
* Project Similarity Matcher
|
|
290
|
-
* Finds historical projects similar to current work
|
|
291
|
-
*/
|
|
292
|
-
class ProjectSimilarityMatcher {
|
|
293
|
-
constructor(projectRoot = process.cwd()) {
|
|
294
|
-
this.projectRoot = projectRoot;
|
|
295
|
-
this.patternLearner = new WaiverPatternLearner(projectRoot);
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
/**
|
|
299
|
-
* Find projects similar to the current spec
|
|
300
|
-
* Uses real historical specs from git history when available
|
|
301
|
-
*/
|
|
302
|
-
findSimilarProjects(currentSpec) {
|
|
303
|
-
// Load real historical specs first
|
|
304
|
-
const historicalSpecs = this.patternLearner.loadHistoricalSpecs();
|
|
305
|
-
|
|
306
|
-
// Convert historical specs to project format with budget data
|
|
307
|
-
const historicalProjects = historicalSpecs
|
|
308
|
-
.filter(spec => spec.id !== currentSpec.id) // Exclude current spec
|
|
309
|
-
.map(spec => this.specToProject(spec));
|
|
310
|
-
|
|
311
|
-
// If we have real historical data, use it
|
|
312
|
-
if (historicalProjects.length > 0) {
|
|
313
|
-
return historicalProjects
|
|
314
|
-
.map((project) => ({
|
|
315
|
-
project: project.id,
|
|
316
|
-
similarity_score: this.calculateSimilarity(currentSpec, project),
|
|
317
|
-
budget_accuracy: project.allocated_budget.files > 0
|
|
318
|
-
? project.actual_budget.files / project.allocated_budget.files
|
|
319
|
-
: 1.0,
|
|
320
|
-
waiver_count: project.waivers?.length || 0,
|
|
321
|
-
details: project,
|
|
322
|
-
}))
|
|
323
|
-
.filter((p) => p.similarity_score > 0.3)
|
|
324
|
-
.sort((a, b) => b.similarity_score - a.similarity_score)
|
|
325
|
-
.slice(0, 5);
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
// Fallback to demo data if no historical specs found
|
|
329
|
-
const demoProjects = [
|
|
330
|
-
{
|
|
331
|
-
id: 'PROJ-0123',
|
|
332
|
-
title: 'API Enhancement',
|
|
333
|
-
risk_tier: 2,
|
|
334
|
-
mode: 'feature',
|
|
335
|
-
tech_stack: 'node',
|
|
336
|
-
feature_type: 'api',
|
|
337
|
-
actual_budget: { files: 85, loc: 8500 },
|
|
338
|
-
allocated_budget: { files: 70, loc: 7000 },
|
|
339
|
-
waivers: ['WV-0001'],
|
|
340
|
-
},
|
|
341
|
-
{
|
|
342
|
-
id: 'FEAT-0456',
|
|
343
|
-
title: 'UI Component Library',
|
|
344
|
-
risk_tier: 2,
|
|
345
|
-
mode: 'feature',
|
|
346
|
-
tech_stack: 'react',
|
|
347
|
-
feature_type: 'ui',
|
|
348
|
-
actual_budget: { files: 45, loc: 4200 },
|
|
349
|
-
allocated_budget: { files: 50, loc: 5000 },
|
|
350
|
-
waivers: [],
|
|
351
|
-
},
|
|
352
|
-
{
|
|
353
|
-
id: 'FIX-0789',
|
|
354
|
-
title: 'Data Migration',
|
|
355
|
-
risk_tier: 1,
|
|
356
|
-
mode: 'feature',
|
|
357
|
-
tech_stack: 'node',
|
|
358
|
-
feature_type: 'data',
|
|
359
|
-
actual_budget: { files: 25, loc: 2800 },
|
|
360
|
-
allocated_budget: { files: 20, loc: 2000 },
|
|
361
|
-
waivers: ['WV-0002'],
|
|
362
|
-
},
|
|
363
|
-
];
|
|
364
|
-
|
|
365
|
-
// Add a demo project similar to ARCH-0001 for demonstration
|
|
366
|
-
if (currentSpec.id === 'ARCH-0001') {
|
|
367
|
-
demoProjects.push({
|
|
368
|
-
id: 'ARCH-0002',
|
|
369
|
-
title: 'Policy System Refactor',
|
|
370
|
-
risk_tier: 1,
|
|
371
|
-
mode: 'feature',
|
|
372
|
-
tech_stack: 'node',
|
|
373
|
-
feature_type: 'architecture',
|
|
374
|
-
actual_budget: { files: 120, loc: 12000 },
|
|
375
|
-
allocated_budget: { files: 100, loc: 10000 },
|
|
376
|
-
waivers: ['WV-0002'],
|
|
377
|
-
});
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
return demoProjects
|
|
381
|
-
.map((project) => ({
|
|
382
|
-
project: project.id,
|
|
383
|
-
similarity_score: this.calculateSimilarity(currentSpec, project),
|
|
384
|
-
budget_accuracy: project.actual_budget.files / project.allocated_budget.files,
|
|
385
|
-
waiver_count: project.waivers.length,
|
|
386
|
-
details: project,
|
|
387
|
-
}))
|
|
388
|
-
.filter((p) => p.similarity_score > 0.3) // Lower threshold for demonstration
|
|
389
|
-
.sort((a, b) => b.similarity_score - a.similarity_score)
|
|
390
|
-
.slice(0, 5); // Top 5 matches
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
/**
|
|
394
|
-
* Convert a spec object to project format for similarity comparison
|
|
395
|
-
*/
|
|
396
|
-
specToProject(spec) {
|
|
397
|
-
// Extract budget info from spec
|
|
398
|
-
const budget = spec.budget || spec.scope?.budget || {};
|
|
399
|
-
const allocatedFiles = budget.max_files || budget.files || 50;
|
|
400
|
-
const allocatedLoc = budget.max_loc || budget.loc || 5000;
|
|
401
|
-
|
|
402
|
-
// If spec has actual metrics, use them; otherwise estimate from allocated
|
|
403
|
-
const actualFiles = spec.metrics?.files_changed || spec.actual_files || allocatedFiles;
|
|
404
|
-
const actualLoc = spec.metrics?.lines_changed || spec.actual_loc || allocatedLoc;
|
|
405
|
-
|
|
406
|
-
// Extract tech stack from spec metadata
|
|
407
|
-
let techStack = spec.tech_stack || spec.metadata?.tech_stack || 'unknown';
|
|
408
|
-
if (!techStack || techStack === 'unknown') {
|
|
409
|
-
// Try to infer from title or description
|
|
410
|
-
const text = `${spec.title || ''} ${spec.description || ''}`.toLowerCase();
|
|
411
|
-
if (text.includes('react') || text.includes('ui') || text.includes('component')) {
|
|
412
|
-
techStack = 'react';
|
|
413
|
-
} else if (text.includes('api') || text.includes('node') || text.includes('server')) {
|
|
414
|
-
techStack = 'node';
|
|
415
|
-
} else if (text.includes('python') || text.includes('django') || text.includes('flask')) {
|
|
416
|
-
techStack = 'python';
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
// Extract feature type
|
|
421
|
-
let featureType = spec.feature_type || spec.type || 'general';
|
|
422
|
-
if (featureType === 'general') {
|
|
423
|
-
const text = `${spec.title || ''} ${spec.description || ''}`.toLowerCase();
|
|
424
|
-
if (text.includes('api') || text.includes('endpoint')) {
|
|
425
|
-
featureType = 'api';
|
|
426
|
-
} else if (text.includes('ui') || text.includes('component') || text.includes('view')) {
|
|
427
|
-
featureType = 'ui';
|
|
428
|
-
} else if (text.includes('data') || text.includes('migration') || text.includes('database')) {
|
|
429
|
-
featureType = 'data';
|
|
430
|
-
} else if (text.includes('refactor') || text.includes('architecture')) {
|
|
431
|
-
featureType = 'architecture';
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
return {
|
|
436
|
-
id: spec.id,
|
|
437
|
-
title: spec.title || spec.name || spec.id,
|
|
438
|
-
risk_tier: spec.risk_tier || spec.tier || 2,
|
|
439
|
-
mode: spec.mode || 'feature',
|
|
440
|
-
tech_stack: techStack,
|
|
441
|
-
feature_type: featureType,
|
|
442
|
-
actual_budget: {
|
|
443
|
-
files: actualFiles,
|
|
444
|
-
loc: actualLoc,
|
|
445
|
-
},
|
|
446
|
-
allocated_budget: {
|
|
447
|
-
files: allocatedFiles,
|
|
448
|
-
loc: allocatedLoc,
|
|
449
|
-
},
|
|
450
|
-
waivers: spec.waivers || [],
|
|
451
|
-
_source: spec._source,
|
|
452
|
-
_date: spec._date,
|
|
453
|
-
};
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
/**
|
|
457
|
-
* Calculate similarity score between two specs/projects
|
|
458
|
-
*/
|
|
459
|
-
calculateSimilarity(spec1, spec2) {
|
|
460
|
-
let score = 0;
|
|
461
|
-
let factors = 0;
|
|
462
|
-
|
|
463
|
-
// Risk tier match
|
|
464
|
-
if (spec1.risk_tier === spec2.risk_tier) {
|
|
465
|
-
score += 0.3;
|
|
466
|
-
}
|
|
467
|
-
factors += 0.3;
|
|
468
|
-
|
|
469
|
-
// Mode match
|
|
470
|
-
if (spec1.mode === spec2.mode) {
|
|
471
|
-
score += 0.2;
|
|
472
|
-
}
|
|
473
|
-
factors += 0.2;
|
|
474
|
-
|
|
475
|
-
// Tech stack match (if available)
|
|
476
|
-
if (spec1.tech_stack && spec2.tech_stack && spec1.tech_stack === spec2.tech_stack) {
|
|
477
|
-
score += 0.2;
|
|
478
|
-
}
|
|
479
|
-
factors += 0.2;
|
|
480
|
-
|
|
481
|
-
// Feature type match (if available)
|
|
482
|
-
if (spec1.feature_type && spec2.feature_type && spec1.feature_type === spec2.feature_type) {
|
|
483
|
-
score += 0.3;
|
|
484
|
-
}
|
|
485
|
-
factors += 0.3;
|
|
486
|
-
|
|
487
|
-
return factors > 0 ? score / factors : 0;
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
/**
|
|
492
|
-
* Budget Predictor using statistical analysis
|
|
493
|
-
*/
|
|
494
|
-
class BudgetPredictor {
|
|
495
|
-
constructor(projectRoot = process.cwd()) {
|
|
496
|
-
this.projectRoot = projectRoot;
|
|
497
|
-
this.patternLearner = new WaiverPatternLearner(projectRoot);
|
|
498
|
-
this.similarityMatcher = new ProjectSimilarityMatcher(projectRoot);
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
/**
|
|
502
|
-
* Assess budget for a working spec
|
|
503
|
-
*/
|
|
504
|
-
assessBudget(spec) {
|
|
505
|
-
try {
|
|
506
|
-
const patterns = this.patternLearner.analyzePatterns();
|
|
507
|
-
const similarProjects = this.similarityMatcher.findSimilarProjects(spec);
|
|
508
|
-
|
|
509
|
-
if (patterns.status !== 'success' || similarProjects.length === 0) {
|
|
510
|
-
return {
|
|
511
|
-
status: 'insufficient_data',
|
|
512
|
-
message: 'Not enough historical data for accurate prediction',
|
|
513
|
-
recommendation: {
|
|
514
|
-
use_default_tier: true,
|
|
515
|
-
confidence: 0.0,
|
|
516
|
-
},
|
|
517
|
-
};
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
// Calculate recommended budget based on similar projects
|
|
521
|
-
const similarBudgets = similarProjects.map((p) => p.details.actual_budget);
|
|
522
|
-
const avgFiles = similarBudgets.reduce((sum, b) => sum + b.files, 0) / similarBudgets.length;
|
|
523
|
-
const avgLoc = similarBudgets.reduce((sum, b) => sum + b.loc, 0) / similarBudgets.length;
|
|
524
|
-
|
|
525
|
-
// Apply buffer based on waiver patterns
|
|
526
|
-
const fileBuffer = patterns.patterns.budget_overruns?.average_overrun_files || 0;
|
|
527
|
-
const locBuffer = patterns.patterns.budget_overruns?.average_overrun_loc || 0;
|
|
528
|
-
|
|
529
|
-
const recommendedFiles = Math.round(avgFiles * (1 + fileBuffer / 100));
|
|
530
|
-
const recommendedLoc = Math.round(avgLoc * (1 + locBuffer / 100));
|
|
531
|
-
|
|
532
|
-
// Calculate confidence based on sample size and variance
|
|
533
|
-
const confidence = Math.min(0.9, similarProjects.length / 10); // Max 90% confidence
|
|
534
|
-
|
|
535
|
-
return {
|
|
536
|
-
status: 'success',
|
|
537
|
-
assessment: {
|
|
538
|
-
similar_projects_analyzed: similarProjects.length,
|
|
539
|
-
recommended_budget: {
|
|
540
|
-
files: recommendedFiles,
|
|
541
|
-
loc: recommendedLoc,
|
|
542
|
-
},
|
|
543
|
-
baseline_budget: {
|
|
544
|
-
files: Math.round(avgFiles),
|
|
545
|
-
loc: Math.round(avgLoc),
|
|
546
|
-
},
|
|
547
|
-
buffer_applied: {
|
|
548
|
-
files_percent: Math.round((fileBuffer / avgFiles) * 100),
|
|
549
|
-
loc_percent: Math.round((locBuffer / avgLoc) * 100),
|
|
550
|
-
},
|
|
551
|
-
rationale: this.generateRationale(spec, similarProjects, patterns),
|
|
552
|
-
risk_factors: patterns.patterns.risk_factors || [],
|
|
553
|
-
confidence: Math.round(confidence * 100) / 100,
|
|
554
|
-
},
|
|
555
|
-
};
|
|
556
|
-
} catch (error) {
|
|
557
|
-
return {
|
|
558
|
-
status: 'error',
|
|
559
|
-
message: error.message,
|
|
560
|
-
recommendation: {
|
|
561
|
-
use_default_tier: true,
|
|
562
|
-
confidence: 0.0,
|
|
563
|
-
},
|
|
564
|
-
};
|
|
565
|
-
}
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
/**
|
|
569
|
-
* Generate human-readable rationale for the recommendation
|
|
570
|
-
*/
|
|
571
|
-
generateRationale(spec, similarProjects, patterns) {
|
|
572
|
-
const reasons = [];
|
|
573
|
-
|
|
574
|
-
if (similarProjects.length > 0) {
|
|
575
|
-
const topMatch = similarProjects[0];
|
|
576
|
-
reasons.push(
|
|
577
|
-
`Similar to ${topMatch.project} (${Math.round(topMatch.similarity_score * 100)}% match)`
|
|
578
|
-
);
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
if (patterns.patterns.budget_overruns?.common_patterns?.length > 0) {
|
|
582
|
-
const topPattern = patterns.patterns.budget_overruns.common_patterns[0];
|
|
583
|
-
reasons.push(
|
|
584
|
-
`Historical ${topPattern.reason} overruns add ${topPattern.avg_overrun_files} files on average`
|
|
585
|
-
);
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
if (spec.mode === 'feature') {
|
|
589
|
-
reasons.push('Feature development typically needs 15-25% budget buffer');
|
|
590
|
-
}
|
|
591
|
-
|
|
592
|
-
return reasons;
|
|
593
|
-
}
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
/**
|
|
597
|
-
* Main Test Analysis CLI handler
|
|
598
|
-
*/
|
|
599
|
-
async function testAnalysisCommand(subcommand, options = [], commandOptions = {}) {
|
|
600
|
-
const chalk = (await import('chalk')).default;
|
|
601
|
-
|
|
602
|
-
try {
|
|
603
|
-
switch (subcommand) {
|
|
604
|
-
case 'assess-budget':
|
|
605
|
-
return await handleAssessBudget(options, commandOptions);
|
|
606
|
-
case 'analyze-patterns':
|
|
607
|
-
return await handleAnalyzePatterns(options);
|
|
608
|
-
case 'find-similar':
|
|
609
|
-
return await handleFindSimilar(options, commandOptions);
|
|
610
|
-
default:
|
|
611
|
-
console.log(chalk.red('Unknown test-analysis subcommand'));
|
|
612
|
-
console.log('Available commands:');
|
|
613
|
-
console.log(' assess-budget - Analyze budget needs for current spec');
|
|
614
|
-
console.log(' analyze-patterns - Show waiver pattern analysis');
|
|
615
|
-
console.log(' find-similar - Find similar historical projects');
|
|
616
|
-
return;
|
|
617
|
-
}
|
|
618
|
-
} catch (error) {
|
|
619
|
-
console.error(chalk.red('Test analysis failed:'), error.message);
|
|
620
|
-
}
|
|
621
|
-
}
|
|
622
|
-
|
|
623
|
-
/**
|
|
624
|
-
* Resolve the current spec for analysis commands.
|
|
625
|
-
* Supports explicit `--spec <path>` for compatibility, but prefers
|
|
626
|
-
* the suite-standard resolver and `--spec-id`.
|
|
627
|
-
* @param {string[]} optionArgs
|
|
628
|
-
* @param {Object} commandOptions
|
|
629
|
-
* @returns {Promise<{spec: Object, specPath: string}>}
|
|
630
|
-
*/
|
|
631
|
-
async function resolveAnalysisSpec(optionArgs = [], commandOptions = {}) {
|
|
632
|
-
let specFile = null;
|
|
633
|
-
if (Array.isArray(optionArgs) && optionArgs.includes('--spec')) {
|
|
634
|
-
const specIndex = optionArgs.indexOf('--spec');
|
|
635
|
-
if (specIndex + 1 < optionArgs.length) {
|
|
636
|
-
specFile = optionArgs[specIndex + 1];
|
|
637
|
-
}
|
|
638
|
-
}
|
|
639
|
-
|
|
640
|
-
const resolved = await resolveSpec({
|
|
641
|
-
specId: commandOptions.specId,
|
|
642
|
-
specFile,
|
|
643
|
-
warnLegacy: false,
|
|
644
|
-
interactive: false,
|
|
645
|
-
});
|
|
646
|
-
|
|
647
|
-
return {
|
|
648
|
-
spec: resolved.spec,
|
|
649
|
-
specPath: resolved.path,
|
|
650
|
-
};
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
/**
|
|
654
|
-
* Handle budget assessment command
|
|
655
|
-
*/
|
|
656
|
-
async function handleAssessBudget(options, commandOptions = {}) {
|
|
657
|
-
const chalk = (await import('chalk')).default;
|
|
658
|
-
const predictor = new BudgetPredictor();
|
|
659
|
-
|
|
660
|
-
try {
|
|
661
|
-
const { spec, specPath } = await resolveAnalysisSpec(options, commandOptions);
|
|
662
|
-
|
|
663
|
-
console.log(chalk.cyan(`Budget Assessment for ${spec.id}`));
|
|
664
|
-
console.log('==============================================');
|
|
665
|
-
console.log(chalk.gray(`Spec: ${path.relative(process.cwd(), specPath)}`));
|
|
666
|
-
|
|
667
|
-
const result = predictor.assessBudget(spec);
|
|
668
|
-
|
|
669
|
-
if (result.status === 'success') {
|
|
670
|
-
const assessment = result.assessment;
|
|
671
|
-
console.log(
|
|
672
|
-
`Historical Analysis: ${assessment.similar_projects_analyzed} similar projects analyzed`
|
|
673
|
-
);
|
|
674
|
-
console.log(
|
|
675
|
-
`Recommended Budget: ${assessment.recommended_budget.files} files, ${assessment.recommended_budget.loc} LOC (+${assessment.buffer_applied.files_percent}% buffer)`
|
|
676
|
-
);
|
|
677
|
-
console.log(`Rationale: ${assessment.rationale.join('; ')}`);
|
|
678
|
-
|
|
679
|
-
if (assessment.risk_factors.length > 0) {
|
|
680
|
-
console.log(
|
|
681
|
-
chalk.yellow(
|
|
682
|
-
`Risk Factors: ${assessment.risk_factors.map((f) => f.description).join('; ')}`
|
|
683
|
-
)
|
|
684
|
-
);
|
|
685
|
-
}
|
|
686
|
-
|
|
687
|
-
const confidenceLevel =
|
|
688
|
-
assessment.confidence > 0.8 ? 'High' : assessment.confidence > 0.6 ? 'Medium' : 'Low';
|
|
689
|
-
console.log(
|
|
690
|
-
chalk.green(
|
|
691
|
-
`Confidence: ${confidenceLevel} (${Math.round(assessment.confidence * 100)}%)`
|
|
692
|
-
)
|
|
693
|
-
);
|
|
694
|
-
} else {
|
|
695
|
-
console.log(chalk.yellow(`${result.message}`));
|
|
696
|
-
console.log('Consider using default tier-based budgeting for now');
|
|
697
|
-
}
|
|
698
|
-
} catch (error) {
|
|
699
|
-
console.error(chalk.red('Failed to load spec:'), error.message);
|
|
700
|
-
}
|
|
701
|
-
}
|
|
702
|
-
|
|
703
|
-
/**
|
|
704
|
-
* Handle pattern analysis command
|
|
705
|
-
*/
|
|
706
|
-
async function handleAnalyzePatterns(_options) {
|
|
707
|
-
const chalk = (await import('chalk')).default;
|
|
708
|
-
const learner = new WaiverPatternLearner();
|
|
709
|
-
|
|
710
|
-
console.log(chalk.cyan('Analyzing Waiver Patterns'));
|
|
711
|
-
console.log('==============================================');
|
|
712
|
-
|
|
713
|
-
const result = learner.analyzePatterns();
|
|
714
|
-
|
|
715
|
-
if (result.status === 'success') {
|
|
716
|
-
const patterns = result.patterns;
|
|
717
|
-
|
|
718
|
-
console.log(`Total waivers analyzed: ${patterns.total_waivers}`);
|
|
719
|
-
|
|
720
|
-
if (patterns.budget_overruns) {
|
|
721
|
-
console.log('\nBudget Overrun Patterns:');
|
|
722
|
-
console.log(
|
|
723
|
-
` Average overrun: ${patterns.budget_overruns.average_overrun_files} files, ${patterns.budget_overruns.average_overrun_loc} LOC`
|
|
724
|
-
);
|
|
725
|
-
|
|
726
|
-
if (patterns.budget_overruns.common_patterns.length > 0) {
|
|
727
|
-
console.log(' Common patterns:');
|
|
728
|
-
patterns.budget_overruns.common_patterns.forEach((pattern) => {
|
|
729
|
-
console.log(
|
|
730
|
-
` ${pattern.reason}: ${Math.round(pattern.frequency * 100)}% frequency (+${pattern.avg_overrun_files} files avg)`
|
|
731
|
-
);
|
|
732
|
-
});
|
|
733
|
-
}
|
|
734
|
-
}
|
|
735
|
-
|
|
736
|
-
if (patterns.common_reasons.length > 0) {
|
|
737
|
-
console.log('\nMost Common Waiver Reasons:');
|
|
738
|
-
patterns.common_reasons.slice(0, 5).forEach((reason) => {
|
|
739
|
-
console.log(
|
|
740
|
-
` ${reason.reason}: ${reason.count} times (${Math.round(reason.frequency * 100)}%)`
|
|
741
|
-
);
|
|
742
|
-
});
|
|
743
|
-
}
|
|
744
|
-
} else {
|
|
745
|
-
console.log(chalk.yellow(`${result.message}`));
|
|
746
|
-
}
|
|
747
|
-
}
|
|
748
|
-
|
|
749
|
-
/**
|
|
750
|
-
* Handle find similar projects command
|
|
751
|
-
*/
|
|
752
|
-
async function handleFindSimilar(options, commandOptions = {}) {
|
|
753
|
-
const chalk = (await import('chalk')).default;
|
|
754
|
-
const matcher = new ProjectSimilarityMatcher();
|
|
755
|
-
|
|
756
|
-
try {
|
|
757
|
-
const { spec, specPath } = await resolveAnalysisSpec(options, commandOptions);
|
|
758
|
-
|
|
759
|
-
console.log(chalk.cyan(`Finding projects similar to ${spec.id}`));
|
|
760
|
-
console.log('==============================================');
|
|
761
|
-
console.log(chalk.gray(`Spec: ${path.relative(process.cwd(), specPath)}`));
|
|
762
|
-
|
|
763
|
-
const similar = matcher.findSimilarProjects(spec);
|
|
764
|
-
|
|
765
|
-
if (similar.length > 0) {
|
|
766
|
-
similar.forEach((project) => {
|
|
767
|
-
const similarityPercent = Math.round(project.similarity_score * 100);
|
|
768
|
-
const accuracyPercent = Math.round(project.budget_accuracy * 100);
|
|
769
|
-
console.log(
|
|
770
|
-
`${project.project}: ${similarityPercent}% similar, ${accuracyPercent}% budget accuracy, ${project.waiver_count} waivers`
|
|
771
|
-
);
|
|
772
|
-
});
|
|
773
|
-
} else {
|
|
774
|
-
console.log(chalk.yellow('No similar projects found'));
|
|
775
|
-
}
|
|
776
|
-
} catch (error) {
|
|
777
|
-
console.error(chalk.red('Failed to load spec:'), error.message);
|
|
778
|
-
}
|
|
779
|
-
}
|
|
780
|
-
|
|
781
|
-
module.exports = {
|
|
782
|
-
testAnalysisCommand,
|
|
783
|
-
WaiverPatternLearner,
|
|
784
|
-
ProjectSimilarityMatcher,
|
|
785
|
-
BudgetPredictor,
|
|
786
|
-
};
|