@paths.design/caws-cli 10.2.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 -785
- 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/agents.js +0 -124
- 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 -1656
- package/dist/commands/status.js +0 -1172
- 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 -502
- 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 -112
- 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 -470
- 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 -117
- 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 -101
- 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 -196
- package/dist/templates/COMMIT_CONVENTIONS.md +0 -86
- package/dist/templates/OIDC_SETUP.md +0 -300
- package/dist/templates/agents.md +0 -171
- 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-display.js +0 -210
- package/dist/utils/agent-session.js +0 -344
- 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 -924
- package/dist/waivers-manager.js +0 -732
- package/dist/worktree/worktree-manager.js +0 -1735
- package/templates/.caws/schemas/policy.schema.json +0 -117
- 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 -101
- 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 -196
- package/templates/COMMIT_CONVENTIONS.md +0 -86
- package/templates/OIDC_SETUP.md +0 -300
- package/templates/agents.md +0 -171
- 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/tool-validator.js
DELETED
|
@@ -1,393 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* @fileoverview CAWS Tool Validator - Security validation for dynamically loaded tools
|
|
5
|
-
* Validates tools against allowlists, scans for security violations, and ensures safe execution
|
|
6
|
-
* @author @darianrosebrook
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
const fs = require('fs');
|
|
10
|
-
const path = require('path');
|
|
11
|
-
const crypto = require('crypto');
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Tool Validator - Security validation and allowlist enforcement
|
|
15
|
-
*/
|
|
16
|
-
class ToolValidator {
|
|
17
|
-
constructor(options = {}) {
|
|
18
|
-
// Check new location first, fall back to legacy location
|
|
19
|
-
const newAllowlistPath = path.join(process.cwd(), '.caws/tools-allow.json');
|
|
20
|
-
const legacyAllowlistPath = path.join(process.cwd(), 'apps/tools/caws/tools-allow.json');
|
|
21
|
-
const defaultAllowlistPath = fs.existsSync(newAllowlistPath)
|
|
22
|
-
? newAllowlistPath
|
|
23
|
-
: legacyAllowlistPath;
|
|
24
|
-
|
|
25
|
-
this.options = {
|
|
26
|
-
allowlistPath: options.allowlistPath || defaultAllowlistPath,
|
|
27
|
-
strictMode: options.strictMode !== false,
|
|
28
|
-
maxFileSize: options.maxFileSize || 1024 * 1024, // 1MB
|
|
29
|
-
...options,
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
this.allowlist = null;
|
|
33
|
-
this.validationCache = new Map();
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Load and parse the tools allowlist
|
|
38
|
-
* @returns {Promise<Array<string>>} Array of allowed commands/patterns
|
|
39
|
-
*/
|
|
40
|
-
async loadAllowlist() {
|
|
41
|
-
if (this.allowlist) return this.allowlist;
|
|
42
|
-
|
|
43
|
-
try {
|
|
44
|
-
if (!fs.existsSync(this.options.allowlistPath)) {
|
|
45
|
-
throw new Error(`Allowlist file not found: ${this.options.allowlistPath}`);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const content = await fs.promises.readFile(this.options.allowlistPath, 'utf8');
|
|
49
|
-
this.allowlist = JSON.parse(content);
|
|
50
|
-
|
|
51
|
-
if (!Array.isArray(this.allowlist)) {
|
|
52
|
-
throw new Error('Allowlist must be an array of strings');
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
return this.allowlist;
|
|
56
|
-
} catch (error) {
|
|
57
|
-
throw new Error(`Failed to load allowlist: ${error.message}`);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Validate a tool against security requirements
|
|
63
|
-
* @param {Object} tool - Tool object with module and metadata
|
|
64
|
-
* @returns {Promise<Object>} Validation result
|
|
65
|
-
*/
|
|
66
|
-
async validateTool(tool) {
|
|
67
|
-
const toolId = tool.metadata?.id || path.basename(tool.path, '.js');
|
|
68
|
-
const cacheKey = crypto
|
|
69
|
-
.createHash('md5')
|
|
70
|
-
.update(toolId + tool.loadedAt)
|
|
71
|
-
.digest('hex');
|
|
72
|
-
|
|
73
|
-
// Check cache first
|
|
74
|
-
if (this.validationCache.has(cacheKey)) {
|
|
75
|
-
return this.validationCache.get(cacheKey);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
const result = {
|
|
79
|
-
valid: true,
|
|
80
|
-
checks: [],
|
|
81
|
-
warnings: [],
|
|
82
|
-
errors: [],
|
|
83
|
-
score: 100,
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
try {
|
|
87
|
-
// Load allowlist if not loaded
|
|
88
|
-
await this.loadAllowlist();
|
|
89
|
-
|
|
90
|
-
// Run all validation checks
|
|
91
|
-
const checks = await Promise.allSettled([
|
|
92
|
-
this.checkFileSecurity(tool),
|
|
93
|
-
this.checkCodeSecurity(tool),
|
|
94
|
-
this.checkInterfaceCompliance(tool),
|
|
95
|
-
this.checkMetadataValidity(tool),
|
|
96
|
-
this.checkDependencySafety(tool),
|
|
97
|
-
]);
|
|
98
|
-
|
|
99
|
-
// Process check results
|
|
100
|
-
checks.forEach((check, index) => {
|
|
101
|
-
const checkName = [
|
|
102
|
-
'fileSecurity',
|
|
103
|
-
'codeSecurity',
|
|
104
|
-
'interfaceCompliance',
|
|
105
|
-
'metadataValidity',
|
|
106
|
-
'dependencySafety',
|
|
107
|
-
][index];
|
|
108
|
-
|
|
109
|
-
if (check.status === 'fulfilled') {
|
|
110
|
-
const checkResult = check.value;
|
|
111
|
-
result.checks.push({
|
|
112
|
-
name: checkName,
|
|
113
|
-
passed: checkResult.passed,
|
|
114
|
-
message: checkResult.message,
|
|
115
|
-
severity: checkResult.severity || 'info',
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
if (!checkResult.passed) {
|
|
119
|
-
result.valid = false;
|
|
120
|
-
if (checkResult.severity === 'error') {
|
|
121
|
-
result.errors.push(checkResult.message);
|
|
122
|
-
result.score -= 20;
|
|
123
|
-
} else {
|
|
124
|
-
result.warnings.push(checkResult.message);
|
|
125
|
-
result.score -= 5;
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
} else {
|
|
129
|
-
result.checks.push({
|
|
130
|
-
name: checkName,
|
|
131
|
-
passed: false,
|
|
132
|
-
message: `Check failed: ${check.reason.message}`,
|
|
133
|
-
severity: 'error',
|
|
134
|
-
});
|
|
135
|
-
result.valid = false;
|
|
136
|
-
result.errors.push(check.reason.message);
|
|
137
|
-
result.score -= 20;
|
|
138
|
-
}
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
// Cache result
|
|
142
|
-
this.validationCache.set(cacheKey, result);
|
|
143
|
-
} catch (error) {
|
|
144
|
-
result.valid = false;
|
|
145
|
-
result.errors.push(`Validation failed: ${error.message}`);
|
|
146
|
-
result.score = 0;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
return result;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* Check file-level security
|
|
154
|
-
* @private
|
|
155
|
-
* @param {Object} tool - Tool object
|
|
156
|
-
*/
|
|
157
|
-
async checkFileSecurity(tool) {
|
|
158
|
-
const issues = [];
|
|
159
|
-
|
|
160
|
-
try {
|
|
161
|
-
const stats = await fs.promises.stat(tool.path);
|
|
162
|
-
|
|
163
|
-
// Check file size
|
|
164
|
-
if (stats.size > this.options.maxFileSize) {
|
|
165
|
-
issues.push(`File too large: ${stats.size} bytes > ${this.options.maxFileSize} bytes`);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// Check file permissions (should be readable)
|
|
169
|
-
const mode = stats.mode;
|
|
170
|
-
if (!(mode & parseInt('0444', 8))) {
|
|
171
|
-
// Owner, group, others can read
|
|
172
|
-
issues.push('File permissions too restrictive');
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
// Check if file is executable (should not be)
|
|
176
|
-
if (mode & parseInt('0111', 8)) {
|
|
177
|
-
// Execute permissions
|
|
178
|
-
issues.push('Tool file should not have execute permissions');
|
|
179
|
-
}
|
|
180
|
-
} catch (error) {
|
|
181
|
-
issues.push(`File access error: ${error.message}`);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
return {
|
|
185
|
-
passed: issues.length === 0,
|
|
186
|
-
message: issues.length > 0 ? issues.join('; ') : 'File security check passed',
|
|
187
|
-
severity: issues.length > 0 ? 'error' : 'info',
|
|
188
|
-
};
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
/**
|
|
192
|
-
* Check code-level security
|
|
193
|
-
* @private
|
|
194
|
-
* @param {Object} tool - Tool object
|
|
195
|
-
*/
|
|
196
|
-
async checkCodeSecurity(tool) {
|
|
197
|
-
const issues = [];
|
|
198
|
-
|
|
199
|
-
try {
|
|
200
|
-
const content = await fs.promises.readFile(tool.path, 'utf8');
|
|
201
|
-
|
|
202
|
-
// Check for dangerous patterns
|
|
203
|
-
const dangerousPatterns = [
|
|
204
|
-
{ pattern: /require\(['"`]child_process['"`]\)/g, message: 'Direct child_process usage' },
|
|
205
|
-
{ pattern: /require\(['"`]fs['"`]\)\.writeFileSync/g, message: 'Synchronous file writing' },
|
|
206
|
-
{ pattern: /process\.exit\(/g, message: 'Process termination' },
|
|
207
|
-
{ pattern: /eval\(/g, message: 'Code evaluation' },
|
|
208
|
-
{ pattern: /Function\(['"`]/g, message: 'Dynamic function creation' },
|
|
209
|
-
{ pattern: /require\(['"`]\.\./g, message: 'Directory traversal in require' },
|
|
210
|
-
];
|
|
211
|
-
|
|
212
|
-
dangerousPatterns.forEach(({ pattern, message }) => {
|
|
213
|
-
const matches = content.match(pattern);
|
|
214
|
-
if (matches) {
|
|
215
|
-
issues.push(`${message} (${matches.length} occurrences)`);
|
|
216
|
-
}
|
|
217
|
-
});
|
|
218
|
-
|
|
219
|
-
// Check for secrets (basic pattern matching)
|
|
220
|
-
const secretPatterns = [
|
|
221
|
-
/password\s*[=:]\s*['"`][^'"]{8,}['"`]/gi,
|
|
222
|
-
/token\s*[=:]\s*['"`][^'"]{20,}['"`]/gi,
|
|
223
|
-
/key\s*[=:]\s*['"`][^'"]{16,}['"`]/gi,
|
|
224
|
-
/secret\s*[=:]\s*['"`][^'"]{16,}['"`]/gi,
|
|
225
|
-
];
|
|
226
|
-
|
|
227
|
-
secretPatterns.forEach((pattern) => {
|
|
228
|
-
if (content.match(pattern)) {
|
|
229
|
-
issues.push('Potential hardcoded secrets detected');
|
|
230
|
-
}
|
|
231
|
-
});
|
|
232
|
-
} catch (error) {
|
|
233
|
-
issues.push(`Code analysis error: ${error.message}`);
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
return {
|
|
237
|
-
passed: issues.length === 0,
|
|
238
|
-
message:
|
|
239
|
-
issues.length > 0 ? `Security issues: ${issues.join('; ')}` : 'Code security check passed',
|
|
240
|
-
severity: issues.length > 0 ? 'error' : 'info',
|
|
241
|
-
};
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
/**
|
|
245
|
-
* Check interface compliance
|
|
246
|
-
* @private
|
|
247
|
-
* @param {Object} tool - Tool object
|
|
248
|
-
*/
|
|
249
|
-
async checkInterfaceCompliance(tool) {
|
|
250
|
-
const requiredMethods = ['execute', 'getMetadata'];
|
|
251
|
-
const missingMethods = [];
|
|
252
|
-
|
|
253
|
-
requiredMethods.forEach((method) => {
|
|
254
|
-
if (typeof tool.module[method] !== 'function') {
|
|
255
|
-
missingMethods.push(method);
|
|
256
|
-
}
|
|
257
|
-
});
|
|
258
|
-
|
|
259
|
-
return {
|
|
260
|
-
passed: missingMethods.length === 0,
|
|
261
|
-
message:
|
|
262
|
-
missingMethods.length > 0
|
|
263
|
-
? `Missing required methods: ${missingMethods.join(', ')}`
|
|
264
|
-
: 'Interface compliance check passed',
|
|
265
|
-
severity: missingMethods.length > 0 ? 'error' : 'info',
|
|
266
|
-
};
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
/**
|
|
270
|
-
* Check metadata validity
|
|
271
|
-
* @private
|
|
272
|
-
* @param {Object} tool - Tool object
|
|
273
|
-
*/
|
|
274
|
-
async checkMetadataValidity(tool) {
|
|
275
|
-
const metadata = tool.metadata || {};
|
|
276
|
-
const requiredFields = ['id', 'name', 'version'];
|
|
277
|
-
const missingFields = [];
|
|
278
|
-
const invalidFields = [];
|
|
279
|
-
|
|
280
|
-
// Check required fields
|
|
281
|
-
requiredFields.forEach((field) => {
|
|
282
|
-
if (!metadata[field]) {
|
|
283
|
-
missingFields.push(field);
|
|
284
|
-
}
|
|
285
|
-
});
|
|
286
|
-
|
|
287
|
-
// Validate field types and formats
|
|
288
|
-
if (metadata.id && typeof metadata.id !== 'string') {
|
|
289
|
-
invalidFields.push('id must be string');
|
|
290
|
-
}
|
|
291
|
-
if (metadata.name && typeof metadata.name !== 'string') {
|
|
292
|
-
invalidFields.push('name must be string');
|
|
293
|
-
}
|
|
294
|
-
if (metadata.version && typeof metadata.version !== 'string') {
|
|
295
|
-
invalidFields.push('version must be string');
|
|
296
|
-
}
|
|
297
|
-
if (metadata.capabilities && !Array.isArray(metadata.capabilities)) {
|
|
298
|
-
invalidFields.push('capabilities must be array');
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
const issues = [...missingFields.map((f) => `missing ${f}`), ...invalidFields];
|
|
302
|
-
|
|
303
|
-
return {
|
|
304
|
-
passed: issues.length === 0,
|
|
305
|
-
message:
|
|
306
|
-
issues.length > 0
|
|
307
|
-
? `Metadata issues: ${issues.join(', ')}`
|
|
308
|
-
: 'Metadata validity check passed',
|
|
309
|
-
severity: issues.length > 0 ? 'error' : 'info',
|
|
310
|
-
};
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
/**
|
|
314
|
-
* Check dependency safety
|
|
315
|
-
* @private
|
|
316
|
-
* @param {Object} tool - Tool object
|
|
317
|
-
*/
|
|
318
|
-
async checkDependencySafety(tool) {
|
|
319
|
-
const metadata = tool.metadata || {};
|
|
320
|
-
const issues = [];
|
|
321
|
-
|
|
322
|
-
if (metadata.dependencies) {
|
|
323
|
-
if (!Array.isArray(metadata.dependencies)) {
|
|
324
|
-
issues.push('dependencies must be array');
|
|
325
|
-
} else {
|
|
326
|
-
// Check for potentially unsafe dependencies
|
|
327
|
-
const unsafeDeps = ['child_process', 'fs-extra', 'execa', 'shelljs'];
|
|
328
|
-
const foundUnsafe = metadata.dependencies.filter((dep) =>
|
|
329
|
-
unsafeDeps.some((unsafe) => dep.includes(unsafe))
|
|
330
|
-
);
|
|
331
|
-
|
|
332
|
-
if (foundUnsafe.length > 0) {
|
|
333
|
-
issues.push(`Potentially unsafe dependencies: ${foundUnsafe.join(', ')}`);
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
return {
|
|
339
|
-
passed: issues.length === 0,
|
|
340
|
-
message:
|
|
341
|
-
issues.length > 0
|
|
342
|
-
? `Dependency issues: ${issues.join('; ')}`
|
|
343
|
-
: 'Dependency safety check passed',
|
|
344
|
-
severity: issues.length > 0 ? 'warning' : 'info',
|
|
345
|
-
};
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
/**
|
|
349
|
-
* Validate a command against the allowlist
|
|
350
|
-
* @param {string} command - Command to validate
|
|
351
|
-
* @returns {boolean} True if command is allowed
|
|
352
|
-
*/
|
|
353
|
-
async validateCommand(command) {
|
|
354
|
-
const allowlist = await this.loadAllowlist();
|
|
355
|
-
|
|
356
|
-
// Check exact matches first
|
|
357
|
-
if (allowlist.includes(command)) {
|
|
358
|
-
return true;
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
// Check pattern matches
|
|
362
|
-
return allowlist.some((allowed) => {
|
|
363
|
-
if (allowed.includes('*')) {
|
|
364
|
-
// Simple wildcard matching
|
|
365
|
-
const regex = new RegExp(allowed.replace(/\*/g, '.*'));
|
|
366
|
-
return regex.test(command);
|
|
367
|
-
}
|
|
368
|
-
return false;
|
|
369
|
-
});
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
/**
|
|
373
|
-
* Clear validation cache
|
|
374
|
-
*/
|
|
375
|
-
clearCache() {
|
|
376
|
-
this.validationCache.clear();
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
/**
|
|
380
|
-
* Get validator statistics
|
|
381
|
-
* @returns {Object} Statistics object
|
|
382
|
-
*/
|
|
383
|
-
getStats() {
|
|
384
|
-
return {
|
|
385
|
-
allowlistLoaded: this.allowlist !== null,
|
|
386
|
-
allowlistSize: this.allowlist?.length || 0,
|
|
387
|
-
cacheSize: this.validationCache.size,
|
|
388
|
-
strictMode: this.options.strictMode,
|
|
389
|
-
};
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
module.exports = ToolValidator;
|
|
@@ -1,210 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @fileoverview CAWSFIX-31 — agent claim display formatters.
|
|
3
|
-
*
|
|
4
|
-
* Single-purpose helpers for rendering agent / claim information so the
|
|
5
|
-
* format ("<sessionId>:<platform>", claim panels, soft-block warnings)
|
|
6
|
-
* is consistent across `caws status`, `caws agents`, and the
|
|
7
|
-
* worktree-manager soft-block surface.
|
|
8
|
-
*
|
|
9
|
-
* Display only — no I/O of its own beyond the small loaders it needs.
|
|
10
|
-
*
|
|
11
|
-
* @author @darianrosebrook
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
const path = require('path');
|
|
15
|
-
const fs = require('fs');
|
|
16
|
-
|
|
17
|
-
const {
|
|
18
|
-
loadAgentRegistry,
|
|
19
|
-
findSessionLogs,
|
|
20
|
-
} = require('./agent-session');
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Composite identifier used in every visible reference to an agent.
|
|
24
|
-
* Format: `<sessionId>:<platform>`. Lets readers trace provenance to
|
|
25
|
-
* platform-specific transcript directories.
|
|
26
|
-
*
|
|
27
|
-
* @param {string} sessionId
|
|
28
|
-
* @param {string} platform - 'claude-code' | 'cursor' | 'unknown'
|
|
29
|
-
* @returns {string}
|
|
30
|
-
*/
|
|
31
|
-
function formatAgentRef(sessionId, platform) {
|
|
32
|
-
const sid = sessionId || 'unknown';
|
|
33
|
-
const plat = platform || 'unknown';
|
|
34
|
-
return `${sid}:${plat}`;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Compute a short human-readable age for a heartbeat timestamp.
|
|
39
|
-
* @param {string|null} iso
|
|
40
|
-
* @returns {string}
|
|
41
|
-
*/
|
|
42
|
-
function formatHeartbeatAge(iso) {
|
|
43
|
-
if (!iso) return 'unknown';
|
|
44
|
-
const t = Date.parse(iso);
|
|
45
|
-
if (isNaN(t)) return 'unknown';
|
|
46
|
-
const ms = Date.now() - t;
|
|
47
|
-
if (ms < 0) return 'in the future';
|
|
48
|
-
const sec = Math.round(ms / 1000);
|
|
49
|
-
if (sec < 60) return `${sec}s ago`;
|
|
50
|
-
const min = Math.round(sec / 60);
|
|
51
|
-
if (min < 60) return `${min} min ago`;
|
|
52
|
-
const hr = Math.round(min / 60);
|
|
53
|
-
if (hr < 24) return `${hr}h ago`;
|
|
54
|
-
const days = Math.round(hr / 24);
|
|
55
|
-
return `${days}d ago`;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Format a single session-log pointer for inclusion in a warning.
|
|
60
|
-
* Path is project-relative when possible.
|
|
61
|
-
*
|
|
62
|
-
* @param {object} log - Result from findSessionLogs
|
|
63
|
-
* @param {string} root - Project root (for relative path)
|
|
64
|
-
* @returns {string}
|
|
65
|
-
*/
|
|
66
|
-
function formatSessionLogPointer(log, root) {
|
|
67
|
-
const rel = path.relative(root, log.path) || log.path;
|
|
68
|
-
const parts = [`tmp/${path.basename(log.path)}`, `${log.turnCount} turns`];
|
|
69
|
-
if (log.lastTurn) parts.push(`last turn ${log.lastTurn}`);
|
|
70
|
-
return ` Session log: ${rel}\n ${parts.join(', ')}`;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Build the structured warning printed when a foreign claim is
|
|
75
|
-
* detected on a worktree (for `assertWorktreeOwnership` soft-block,
|
|
76
|
-
* `caws worktree claim` read-only mode, etc.).
|
|
77
|
-
*
|
|
78
|
-
* @param {object} args
|
|
79
|
-
* @param {string} args.worktree - Worktree name
|
|
80
|
-
* @param {object|null} args.priorOwnerEntry - The agents.json entry for the
|
|
81
|
-
* prior owner, or null when TTL-pruned.
|
|
82
|
-
* @param {string} args.priorOwnerSessionId - Sid from worktrees.json:owner
|
|
83
|
-
* @param {Array} args.sessionLogs - findSessionLogs() result
|
|
84
|
-
* @param {string} args.root - Project root for relative paths
|
|
85
|
-
* @param {string} args.takeoverCommand - Exact command to suggest
|
|
86
|
-
* @returns {string}
|
|
87
|
-
*/
|
|
88
|
-
function formatClaimNotice(args) {
|
|
89
|
-
const {
|
|
90
|
-
worktree,
|
|
91
|
-
priorOwnerEntry,
|
|
92
|
-
priorOwnerSessionId,
|
|
93
|
-
sessionLogs = [],
|
|
94
|
-
root,
|
|
95
|
-
takeoverCommand,
|
|
96
|
-
} = args;
|
|
97
|
-
|
|
98
|
-
const platform = priorOwnerEntry ? priorOwnerEntry.platform : 'unknown';
|
|
99
|
-
const ref = formatAgentRef(priorOwnerSessionId, platform);
|
|
100
|
-
|
|
101
|
-
const lines = [
|
|
102
|
-
`Worktree '${worktree}' is claimed by ${ref}`,
|
|
103
|
-
];
|
|
104
|
-
|
|
105
|
-
if (priorOwnerEntry) {
|
|
106
|
-
const age = formatHeartbeatAge(priorOwnerEntry.lastSeen);
|
|
107
|
-
lines.push(` Last heartbeat: ${priorOwnerEntry.lastSeen} (${age})`);
|
|
108
|
-
} else {
|
|
109
|
-
lines.push(` Last heartbeat: no live agent registry entry (pruned or stale)`);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
for (const log of sessionLogs) {
|
|
113
|
-
lines.push(formatSessionLogPointer(log, root));
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
if (takeoverCommand) {
|
|
117
|
-
lines.push(` To proceed: ${takeoverCommand}`);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
return lines.join('\n');
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Build a softer hint when a worktree has no CAWS-tracked owner but a
|
|
125
|
-
* matching session-log directory exists (the "may still be active"
|
|
126
|
-
* scenario from AC A8).
|
|
127
|
-
*
|
|
128
|
-
* @param {object} args
|
|
129
|
-
* @param {string} args.worktree
|
|
130
|
-
* @param {Array} args.sessionLogs
|
|
131
|
-
* @param {string} args.root
|
|
132
|
-
* @returns {string}
|
|
133
|
-
*/
|
|
134
|
-
function formatOrphanLogHint(args) {
|
|
135
|
-
const { worktree, sessionLogs = [], root } = args;
|
|
136
|
-
const lines = [
|
|
137
|
-
`No active CAWS claim on worktree '${worktree}', but a session log exists.`,
|
|
138
|
-
` The previous session may still be active — read for context before continuing:`,
|
|
139
|
-
];
|
|
140
|
-
for (const log of sessionLogs) {
|
|
141
|
-
lines.push(formatSessionLogPointer(log, root));
|
|
142
|
-
}
|
|
143
|
-
return lines.join('\n');
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Render the Claim panel that `caws status` includes when cwd is
|
|
148
|
-
* inside a worktree. Returns a multi-line string (caller prints it).
|
|
149
|
-
*
|
|
150
|
-
* @param {string} root - Project root
|
|
151
|
-
* @param {string} worktreeName - Worktree to inspect
|
|
152
|
-
* @returns {string}
|
|
153
|
-
*/
|
|
154
|
-
function renderClaimPanel(root, worktreeName) {
|
|
155
|
-
let entry = null;
|
|
156
|
-
try {
|
|
157
|
-
const wtRegistryPath = path.join(root, '.caws', 'worktrees.json');
|
|
158
|
-
if (fs.existsSync(wtRegistryPath)) {
|
|
159
|
-
const reg = JSON.parse(fs.readFileSync(wtRegistryPath, 'utf8'));
|
|
160
|
-
entry = reg.worktrees && reg.worktrees[worktreeName];
|
|
161
|
-
}
|
|
162
|
-
} catch {
|
|
163
|
-
// Best-effort.
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
if (!entry || !entry.owner) {
|
|
167
|
-
return `Claim: no active claim on worktree '${worktreeName}'`;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
const agentRegistry = loadAgentRegistry(root);
|
|
171
|
-
const ownerEntry = agentRegistry.agents[entry.owner] || null;
|
|
172
|
-
const platform = ownerEntry ? ownerEntry.platform : 'unknown';
|
|
173
|
-
const ref = formatAgentRef(entry.owner, platform);
|
|
174
|
-
|
|
175
|
-
const lines = [`Claim: worktree '${worktreeName}' owned by ${ref}`];
|
|
176
|
-
if (ownerEntry) {
|
|
177
|
-
lines.push(
|
|
178
|
-
` Last heartbeat: ${ownerEntry.lastSeen} (${formatHeartbeatAge(ownerEntry.lastSeen)})`
|
|
179
|
-
);
|
|
180
|
-
if (ownerEntry.specId) {
|
|
181
|
-
lines.push(` Spec: ${ownerEntry.specId}`);
|
|
182
|
-
}
|
|
183
|
-
} else {
|
|
184
|
-
lines.push(` Last heartbeat: no live agent registry entry (pruned)`);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
// Surface session-log pointers if present (filter by branch when known).
|
|
188
|
-
const branch = entry.branch || null;
|
|
189
|
-
const logs = findSessionLogs(root, { sessionId: entry.owner }).concat(
|
|
190
|
-
branch ? findSessionLogs(root, { branch }) : []
|
|
191
|
-
);
|
|
192
|
-
// Dedupe by path
|
|
193
|
-
const seen = new Set();
|
|
194
|
-
for (const log of logs) {
|
|
195
|
-
if (seen.has(log.path)) continue;
|
|
196
|
-
seen.add(log.path);
|
|
197
|
-
lines.push(formatSessionLogPointer(log, root));
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
return lines.join('\n');
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
module.exports = {
|
|
204
|
-
formatAgentRef,
|
|
205
|
-
formatHeartbeatAge,
|
|
206
|
-
formatSessionLogPointer,
|
|
207
|
-
formatClaimNotice,
|
|
208
|
-
formatOrphanLogHint,
|
|
209
|
-
renderClaimPanel,
|
|
210
|
-
};
|