@paths.design/caws-cli 9.3.2 → 10.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +71 -32
- package/dist/budget-derivation.js +221 -74
- package/dist/commands/archive.js +67 -28
- package/dist/commands/burnup.js +20 -11
- package/dist/commands/diagnose.js +34 -22
- package/dist/commands/evaluate.js +41 -15
- package/dist/commands/gates.js +149 -0
- package/dist/commands/init.js +150 -19
- package/dist/commands/iterate.js +81 -4
- package/dist/commands/parallel.js +4 -0
- package/dist/commands/plan.js +9 -19
- package/dist/commands/provenance.js +53 -17
- package/dist/commands/quality-monitor.js +64 -45
- package/dist/commands/scope.js +264 -0
- package/dist/commands/sidecar.js +74 -0
- package/dist/commands/specs.js +381 -45
- package/dist/commands/status.js +117 -9
- package/dist/commands/templates.js +0 -8
- package/dist/commands/tutorial.js +10 -9
- package/dist/commands/validate.js +70 -6
- package/dist/commands/verify-acs.js +48 -76
- package/dist/commands/waivers.js +212 -13
- package/dist/commands/worktree.js +131 -26
- package/dist/error-handler.js +2 -13
- package/dist/gates/budget-limit.js +121 -0
- package/dist/gates/feedback.js +260 -0
- package/dist/gates/format.js +179 -0
- package/dist/gates/god-object.js +117 -0
- package/dist/gates/pipeline.js +167 -0
- package/dist/gates/scope-boundary.js +93 -0
- package/dist/gates/spec-completeness.js +109 -0
- package/dist/gates/todo-detection.js +205 -0
- package/dist/index.js +157 -151
- package/dist/parallel/parallel-manager.js +3 -3
- package/dist/policy/PolicyManager.js +51 -17
- package/dist/scaffold/claude-hooks.js +24 -1
- package/dist/scaffold/git-hooks.js +45 -102
- package/dist/scaffold/index.js +4 -3
- package/dist/session/session-manager.js +105 -14
- package/dist/sidecars/index.js +33 -0
- package/dist/sidecars/listeners.js +40 -0
- package/dist/sidecars/provenance-summary.js +238 -0
- package/dist/sidecars/quality-gaps.js +258 -0
- package/dist/sidecars/schema.js +149 -0
- package/dist/sidecars/spec-drift.js +151 -0
- package/dist/sidecars/waiver-draft.js +176 -0
- package/dist/templates/.caws/schemas/policy.schema.json +112 -0
- package/dist/templates/.caws/schemas/scope.schema.json +3 -3
- package/dist/templates/.caws/schemas/waivers.schema.json +96 -20
- package/dist/templates/.caws/schemas/working-spec.schema.json +264 -57
- package/dist/templates/.caws/schemas/worktrees.schema.json +3 -1
- package/dist/templates/.caws/templates/working-spec.template.yml +10 -4
- package/dist/templates/.caws/tools/scope-guard.js +66 -15
- package/dist/templates/.claude/README.md +1 -1
- package/dist/templates/.claude/hooks/audit.sh +0 -0
- package/dist/templates/.claude/hooks/block-dangerous.sh +52 -11
- package/dist/templates/.claude/hooks/classify_command.py +592 -0
- package/dist/templates/.claude/hooks/doc-frontmatter-check.sh +173 -0
- package/dist/templates/.claude/hooks/protected-paths.sh +39 -0
- package/dist/templates/.claude/hooks/quality-check.sh +23 -10
- package/dist/templates/.claude/hooks/scope-guard.sh +136 -55
- package/dist/templates/.claude/hooks/session-caws-status.sh +2 -2
- package/dist/templates/.claude/hooks/session-log.sh +76 -3
- package/dist/templates/.claude/hooks/stop-worktree-check.sh +1 -1
- package/dist/templates/.claude/hooks/test_classify_command.py +370 -0
- package/dist/templates/.claude/hooks/test_wrapper_smoke.sh +96 -0
- package/dist/templates/.claude/hooks/worktree-guard.sh +2 -2
- package/dist/templates/.claude/hooks/worktree-write-guard.sh +97 -4
- package/dist/templates/.claude/settings.json +31 -0
- package/dist/templates/.cursor/hooks/caws-quality-check.sh +4 -4
- package/dist/templates/.cursor/hooks/caws-scope-guard.sh +1 -1
- package/dist/templates/.cursor/hooks/session-log.sh +924 -0
- package/dist/templates/.cursor/hooks.json +25 -0
- package/dist/templates/.cursor/rules/02-quality-gates.mdc +3 -5
- package/dist/templates/.cursor/rules/10-documentation-quality-standards.mdc +6 -11
- package/dist/templates/.cursor/rules/11-scope-management-waivers.mdc +14 -18
- package/dist/templates/.cursor/rules/12-implementation-completeness.mdc +4 -4
- package/dist/templates/.cursor/rules/13-language-agnostic-standards.mdc +3 -13
- package/dist/templates/.github/copilot-instructions.md +5 -5
- package/dist/templates/.idea/runConfigurations/CAWS_Evaluate.xml +1 -1
- package/dist/templates/.junie/guidelines.md +2 -2
- package/dist/templates/.vscode/settings.json +3 -1
- package/dist/templates/.windsurf/rules/caws-quality-standards.md +2 -2
- package/dist/templates/.windsurf/workflows/caws-guided-development.md +3 -3
- package/dist/templates/CLAUDE.md +77 -8
- package/dist/templates/agents.md +50 -9
- package/dist/templates/docs/README.md +8 -7
- package/dist/templates/scripts/new_feature.sh +80 -0
- package/dist/test-analysis.js +43 -30
- package/dist/tool-loader.js +1 -1
- package/dist/utils/agent-session.js +202 -0
- package/dist/utils/detection.js +8 -2
- package/dist/utils/event-log.js +584 -0
- package/dist/utils/event-renderer.js +521 -0
- package/dist/utils/finalization.js +7 -6
- package/dist/utils/gitignore-updater.js +3 -0
- package/dist/utils/lifecycle-events.js +94 -0
- package/dist/utils/quality-gates-utils.js +29 -44
- package/dist/utils/schema-validator.js +50 -0
- package/dist/utils/spec-resolver.js +93 -21
- package/dist/utils/working-state.js +530 -0
- package/dist/validation/spec-validation.js +191 -31
- package/dist/waivers-manager.js +144 -6
- package/dist/worktree/worktree-manager.js +598 -95
- package/package.json +9 -8
- package/templates/.caws/schemas/policy.schema.json +112 -0
- package/templates/.caws/schemas/scope.schema.json +3 -3
- package/templates/.caws/schemas/waivers.schema.json +96 -20
- package/templates/.caws/schemas/working-spec.schema.json +264 -57
- package/templates/.caws/schemas/worktrees.schema.json +3 -1
- package/templates/.caws/templates/working-spec.template.yml +10 -4
- package/templates/.caws/tools/scope-guard.js +66 -15
- package/templates/.claude/README.md +1 -1
- package/templates/.claude/hooks/block-dangerous.sh +52 -11
- package/templates/.claude/hooks/classify_command.py +592 -0
- package/templates/.claude/hooks/doc-frontmatter-check.sh +173 -0
- package/templates/.claude/hooks/protected-paths.sh +39 -0
- package/templates/.claude/hooks/quality-check.sh +23 -10
- package/templates/.claude/hooks/scope-guard.sh +136 -55
- package/templates/.claude/hooks/session-caws-status.sh +2 -2
- package/templates/.claude/hooks/session-log.sh +76 -3
- package/templates/.claude/hooks/stop-worktree-check.sh +1 -1
- package/templates/.claude/hooks/test_classify_command.py +370 -0
- package/templates/.claude/hooks/test_wrapper_smoke.sh +96 -0
- package/templates/.claude/hooks/worktree-guard.sh +2 -2
- package/templates/.claude/hooks/worktree-write-guard.sh +97 -4
- package/templates/.claude/settings.json +31 -0
- package/templates/.cursor/hooks/caws-quality-check.sh +4 -4
- package/templates/.cursor/hooks/caws-scope-guard.sh +1 -1
- package/templates/.cursor/hooks/session-log.sh +924 -0
- package/templates/.cursor/hooks.json +25 -0
- package/templates/.cursor/rules/02-quality-gates.mdc +3 -5
- package/templates/.cursor/rules/10-documentation-quality-standards.mdc +6 -11
- package/templates/.cursor/rules/11-scope-management-waivers.mdc +14 -18
- package/templates/.cursor/rules/12-implementation-completeness.mdc +4 -4
- package/templates/.cursor/rules/13-language-agnostic-standards.mdc +3 -13
- package/templates/.github/copilot-instructions.md +5 -5
- package/templates/.idea/runConfigurations/CAWS_Evaluate.xml +1 -1
- package/templates/.junie/guidelines.md +2 -2
- package/templates/.vscode/settings.json +3 -1
- package/templates/.windsurf/rules/caws-quality-standards.md +2 -2
- package/templates/.windsurf/workflows/caws-guided-development.md +3 -3
- package/templates/CLAUDE.md +77 -8
- package/templates/{AGENTS.md → agents.md} +50 -9
- package/templates/docs/README.md +8 -7
- package/templates/scripts/new_feature.sh +80 -0
- package/dist/budget-derivation.d.ts +0 -74
- package/dist/budget-derivation.d.ts.map +0 -1
- package/dist/cicd-optimizer.d.ts +0 -142
- package/dist/cicd-optimizer.d.ts.map +0 -1
- package/dist/commands/archive.d.ts +0 -51
- package/dist/commands/archive.d.ts.map +0 -1
- package/dist/commands/burnup.d.ts +0 -6
- package/dist/commands/burnup.d.ts.map +0 -1
- package/dist/commands/diagnose.d.ts +0 -52
- package/dist/commands/diagnose.d.ts.map +0 -1
- package/dist/commands/evaluate.d.ts +0 -8
- package/dist/commands/evaluate.d.ts.map +0 -1
- package/dist/commands/init.d.ts +0 -5
- package/dist/commands/init.d.ts.map +0 -1
- package/dist/commands/iterate.d.ts +0 -8
- package/dist/commands/iterate.d.ts.map +0 -1
- package/dist/commands/mode.d.ts +0 -25
- package/dist/commands/mode.d.ts.map +0 -1
- package/dist/commands/parallel.d.ts +0 -7
- package/dist/commands/parallel.d.ts.map +0 -1
- package/dist/commands/plan.d.ts +0 -49
- package/dist/commands/plan.d.ts.map +0 -1
- package/dist/commands/provenance.d.ts +0 -32
- package/dist/commands/provenance.d.ts.map +0 -1
- package/dist/commands/quality-gates.d.ts +0 -6
- package/dist/commands/quality-gates.d.ts.map +0 -1
- package/dist/commands/quality-gates.js +0 -444
- package/dist/commands/quality-monitor.d.ts +0 -17
- package/dist/commands/quality-monitor.d.ts.map +0 -1
- package/dist/commands/session.d.ts +0 -7
- package/dist/commands/session.d.ts.map +0 -1
- package/dist/commands/specs.d.ts +0 -77
- package/dist/commands/specs.d.ts.map +0 -1
- package/dist/commands/status.d.ts +0 -44
- package/dist/commands/status.d.ts.map +0 -1
- package/dist/commands/templates.d.ts +0 -74
- package/dist/commands/templates.d.ts.map +0 -1
- package/dist/commands/tool.d.ts +0 -13
- package/dist/commands/tool.d.ts.map +0 -1
- package/dist/commands/troubleshoot.d.ts +0 -8
- package/dist/commands/troubleshoot.d.ts.map +0 -1
- package/dist/commands/troubleshoot.js +0 -104
- package/dist/commands/tutorial.d.ts +0 -55
- package/dist/commands/tutorial.d.ts.map +0 -1
- package/dist/commands/validate.d.ts +0 -15
- package/dist/commands/validate.d.ts.map +0 -1
- package/dist/commands/waivers.d.ts +0 -8
- package/dist/commands/waivers.d.ts.map +0 -1
- package/dist/commands/workflow.d.ts +0 -85
- package/dist/commands/workflow.d.ts.map +0 -1
- package/dist/commands/worktree.d.ts +0 -7
- package/dist/commands/worktree.d.ts.map +0 -1
- package/dist/config/index.d.ts +0 -29
- package/dist/config/index.d.ts.map +0 -1
- package/dist/config/lite-scope.d.ts +0 -33
- package/dist/config/lite-scope.d.ts.map +0 -1
- package/dist/config/modes.d.ts +0 -264
- package/dist/config/modes.d.ts.map +0 -1
- package/dist/constants/spec-types.d.ts +0 -93
- package/dist/constants/spec-types.d.ts.map +0 -1
- package/dist/error-handler.d.ts +0 -151
- package/dist/error-handler.d.ts.map +0 -1
- package/dist/generators/jest-config-generator.d.ts +0 -32
- package/dist/generators/jest-config-generator.d.ts.map +0 -1
- package/dist/generators/jest-config.d.ts +0 -32
- package/dist/generators/jest-config.d.ts.map +0 -1
- package/dist/generators/jest-config.js +0 -242
- package/dist/generators/working-spec.d.ts +0 -13
- package/dist/generators/working-spec.d.ts.map +0 -1
- package/dist/index-new.d.ts +0 -5
- package/dist/index-new.d.ts.map +0 -1
- package/dist/index-new.js +0 -317
- package/dist/index.d.ts +0 -5
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.backup +0 -4711
- package/dist/minimal-cli.d.ts +0 -3
- package/dist/minimal-cli.d.ts.map +0 -1
- package/dist/parallel/parallel-manager.d.ts +0 -67
- package/dist/parallel/parallel-manager.d.ts.map +0 -1
- package/dist/policy/PolicyManager.d.ts +0 -104
- package/dist/policy/PolicyManager.d.ts.map +0 -1
- package/dist/scaffold/claude-hooks.d.ts +0 -28
- package/dist/scaffold/claude-hooks.d.ts.map +0 -1
- package/dist/scaffold/cursor-hooks.d.ts +0 -7
- package/dist/scaffold/cursor-hooks.d.ts.map +0 -1
- package/dist/scaffold/git-hooks.d.ts +0 -38
- package/dist/scaffold/git-hooks.d.ts.map +0 -1
- package/dist/scaffold/index.d.ts +0 -17
- package/dist/scaffold/index.d.ts.map +0 -1
- package/dist/session/session-manager.d.ts +0 -94
- package/dist/session/session-manager.d.ts.map +0 -1
- package/dist/spec/SpecFileManager.d.ts +0 -146
- package/dist/spec/SpecFileManager.d.ts.map +0 -1
- package/dist/templates/.cursor/hooks/caws-tool-validation.sh +0 -121
- package/dist/templates/.github/copilot/instructions.md +0 -311
- package/dist/test-analysis.d.ts +0 -231
- package/dist/test-analysis.d.ts.map +0 -1
- package/dist/tool-interface.d.ts +0 -236
- package/dist/tool-interface.d.ts.map +0 -1
- package/dist/tool-loader.d.ts +0 -77
- package/dist/tool-loader.d.ts.map +0 -1
- package/dist/tool-validator.d.ts +0 -72
- package/dist/tool-validator.d.ts.map +0 -1
- package/dist/utils/async-utils.d.ts +0 -73
- package/dist/utils/async-utils.d.ts.map +0 -1
- package/dist/utils/command-wrapper.d.ts +0 -66
- package/dist/utils/command-wrapper.d.ts.map +0 -1
- package/dist/utils/detection.d.ts +0 -14
- package/dist/utils/detection.d.ts.map +0 -1
- package/dist/utils/error-categories.d.ts +0 -52
- package/dist/utils/error-categories.d.ts.map +0 -1
- package/dist/utils/finalization.d.ts +0 -17
- package/dist/utils/finalization.d.ts.map +0 -1
- package/dist/utils/git-lock.d.ts +0 -13
- package/dist/utils/git-lock.d.ts.map +0 -1
- package/dist/utils/gitignore-updater.d.ts +0 -39
- package/dist/utils/gitignore-updater.d.ts.map +0 -1
- package/dist/utils/ide-detection.d.ts +0 -89
- package/dist/utils/ide-detection.d.ts.map +0 -1
- package/dist/utils/project-analysis.d.ts +0 -34
- package/dist/utils/project-analysis.d.ts.map +0 -1
- package/dist/utils/promise-utils.d.ts +0 -30
- package/dist/utils/promise-utils.d.ts.map +0 -1
- package/dist/utils/quality-gates-utils.d.ts +0 -49
- package/dist/utils/quality-gates-utils.d.ts.map +0 -1
- package/dist/utils/quality-gates.d.ts +0 -49
- package/dist/utils/quality-gates.d.ts.map +0 -1
- package/dist/utils/quality-gates.js +0 -402
- package/dist/utils/spec-resolver.d.ts +0 -80
- package/dist/utils/spec-resolver.d.ts.map +0 -1
- package/dist/utils/typescript-detector.d.ts +0 -66
- package/dist/utils/typescript-detector.d.ts.map +0 -1
- package/dist/utils/yaml-validation.d.ts +0 -32
- package/dist/utils/yaml-validation.d.ts.map +0 -1
- package/dist/validation/spec-validation.d.ts +0 -43
- package/dist/validation/spec-validation.d.ts.map +0 -1
- package/dist/waivers-manager.d.ts +0 -167
- package/dist/waivers-manager.d.ts.map +0 -1
- package/dist/worktree/worktree-manager.d.ts +0 -54
- package/dist/worktree/worktree-manager.d.ts.map +0 -1
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Create a new CAWS feature spec + optional worktree
|
|
3
|
+
#
|
|
4
|
+
# Usage:
|
|
5
|
+
# scripts/new_feature.sh FEAT-001 "Feature description"
|
|
6
|
+
# scripts/new_feature.sh FEAT-001 "Feature description" --worktree
|
|
7
|
+
#
|
|
8
|
+
# This script:
|
|
9
|
+
# 1. Creates a feature spec in .caws/specs/<ID>.yaml
|
|
10
|
+
# 2. Optionally creates a git worktree for isolated development
|
|
11
|
+
|
|
12
|
+
set -euo pipefail
|
|
13
|
+
|
|
14
|
+
if [ $# -lt 2 ]; then
|
|
15
|
+
echo "usage: scripts/new_feature.sh <SPEC-ID> <title> [--worktree]" >&2
|
|
16
|
+
echo " example: scripts/new_feature.sh FEAT-001 'Add user authentication'" >&2
|
|
17
|
+
exit 1
|
|
18
|
+
fi
|
|
19
|
+
|
|
20
|
+
SPEC_ID="$1"
|
|
21
|
+
TITLE="$2"
|
|
22
|
+
USE_WORKTREE="${3:-}"
|
|
23
|
+
|
|
24
|
+
# Validate spec ID format (PREFIX-NUMBER, e.g., FEAT-001, AUTH-042)
|
|
25
|
+
if ! echo "$SPEC_ID" | grep -qE '^[A-Z]+-[0-9]+$'; then
|
|
26
|
+
echo "error: spec ID must be in format PREFIX-NUMBER (e.g., FEAT-001, AUTH-042)" >&2
|
|
27
|
+
exit 1
|
|
28
|
+
fi
|
|
29
|
+
|
|
30
|
+
SPEC_FILE=".caws/specs/${SPEC_ID}.yaml"
|
|
31
|
+
|
|
32
|
+
# Check if spec already exists
|
|
33
|
+
if [ -f "$SPEC_FILE" ]; then
|
|
34
|
+
echo "error: spec $SPEC_ID already exists at $SPEC_FILE" >&2
|
|
35
|
+
exit 1
|
|
36
|
+
fi
|
|
37
|
+
|
|
38
|
+
# Create spec directory if needed
|
|
39
|
+
mkdir -p .caws/specs
|
|
40
|
+
|
|
41
|
+
# Generate spec scaffold
|
|
42
|
+
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
43
|
+
cat > "$SPEC_FILE" << EOF
|
|
44
|
+
id: ${SPEC_ID}
|
|
45
|
+
type: feature
|
|
46
|
+
title: "${TITLE}"
|
|
47
|
+
status: draft
|
|
48
|
+
risk_tier: 2
|
|
49
|
+
mode: development
|
|
50
|
+
created_at: "${TIMESTAMP}"
|
|
51
|
+
updated_at: "${TIMESTAMP}"
|
|
52
|
+
blast_radius:
|
|
53
|
+
modules: []
|
|
54
|
+
data_migration: false
|
|
55
|
+
operational_rollback_slo: 5m
|
|
56
|
+
scope:
|
|
57
|
+
in: []
|
|
58
|
+
out:
|
|
59
|
+
- docs/reference/v1/
|
|
60
|
+
- .caws/
|
|
61
|
+
threats: []
|
|
62
|
+
invariants: []
|
|
63
|
+
acceptance: []
|
|
64
|
+
acceptance_criteria: []
|
|
65
|
+
milestones: []
|
|
66
|
+
EOF
|
|
67
|
+
|
|
68
|
+
echo "Created feature spec: $SPEC_FILE"
|
|
69
|
+
|
|
70
|
+
# Optionally create worktree
|
|
71
|
+
if [ "$USE_WORKTREE" = "--worktree" ]; then
|
|
72
|
+
BRANCH_NAME="feat/${SPEC_ID,,}" # lowercase
|
|
73
|
+
WORKTREE_DIR=".caws/worktrees/${SPEC_ID,,}"
|
|
74
|
+
|
|
75
|
+
git worktree add "$WORKTREE_DIR" -b "$BRANCH_NAME"
|
|
76
|
+
echo "Created worktree: $WORKTREE_DIR (branch: $BRANCH_NAME)"
|
|
77
|
+
echo ""
|
|
78
|
+
echo "To start working:"
|
|
79
|
+
echo " cd $WORKTREE_DIR"
|
|
80
|
+
fi
|
package/dist/test-analysis.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
const fs = require('fs-extra');
|
|
8
8
|
const path = require('path');
|
|
9
9
|
const yaml = require('js-yaml');
|
|
10
|
+
const { resolveSpec } = require('./utils/spec-resolver');
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Waiver Pattern Learning Engine
|
|
@@ -198,7 +199,7 @@ class WaiverPatternLearner {
|
|
|
198
199
|
/**
|
|
199
200
|
* Analyze budget overrun patterns
|
|
200
201
|
*/
|
|
201
|
-
analyzeBudgetOverruns(waivers,
|
|
202
|
+
analyzeBudgetOverruns(waivers, _specs) {
|
|
202
203
|
const budgetWaivers = waivers.filter((w) => w.gates?.includes('budget_limit'));
|
|
203
204
|
|
|
204
205
|
if (budgetWaivers.length === 0) {
|
|
@@ -266,7 +267,7 @@ class WaiverPatternLearner {
|
|
|
266
267
|
/**
|
|
267
268
|
* Identify risk factors from waiver patterns
|
|
268
269
|
*/
|
|
269
|
-
identifyRiskFactors(waivers,
|
|
270
|
+
identifyRiskFactors(waivers, _specs) {
|
|
270
271
|
// Simple risk factor identification based on waiver frequency
|
|
271
272
|
const riskFactors = [];
|
|
272
273
|
|
|
@@ -595,17 +596,17 @@ class BudgetPredictor {
|
|
|
595
596
|
/**
|
|
596
597
|
* Main Test Analysis CLI handler
|
|
597
598
|
*/
|
|
598
|
-
async function testAnalysisCommand(subcommand, options = []) {
|
|
599
|
+
async function testAnalysisCommand(subcommand, options = [], commandOptions = {}) {
|
|
599
600
|
const chalk = (await import('chalk')).default;
|
|
600
601
|
|
|
601
602
|
try {
|
|
602
603
|
switch (subcommand) {
|
|
603
604
|
case 'assess-budget':
|
|
604
|
-
return await handleAssessBudget(options);
|
|
605
|
+
return await handleAssessBudget(options, commandOptions);
|
|
605
606
|
case 'analyze-patterns':
|
|
606
607
|
return await handleAnalyzePatterns(options);
|
|
607
608
|
case 'find-similar':
|
|
608
|
-
return await handleFindSimilar(options);
|
|
609
|
+
return await handleFindSimilar(options, commandOptions);
|
|
609
610
|
default:
|
|
610
611
|
console.log(chalk.red('Unknown test-analysis subcommand'));
|
|
611
612
|
console.log('Available commands:');
|
|
@@ -619,28 +620,49 @@ async function testAnalysisCommand(subcommand, options = []) {
|
|
|
619
620
|
}
|
|
620
621
|
}
|
|
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
|
+
|
|
622
653
|
/**
|
|
623
654
|
* Handle budget assessment command
|
|
624
655
|
*/
|
|
625
|
-
async function handleAssessBudget(options) {
|
|
656
|
+
async function handleAssessBudget(options, commandOptions = {}) {
|
|
626
657
|
const chalk = (await import('chalk')).default;
|
|
627
658
|
const predictor = new BudgetPredictor();
|
|
628
659
|
|
|
629
|
-
// Load current spec
|
|
630
|
-
let specPath = '.caws/working-spec.yaml';
|
|
631
|
-
if (options.includes('--spec')) {
|
|
632
|
-
const specIndex = options.indexOf('--spec');
|
|
633
|
-
if (specIndex + 1 < options.length) {
|
|
634
|
-
specPath = options[specIndex + 1];
|
|
635
|
-
}
|
|
636
|
-
}
|
|
637
|
-
|
|
638
660
|
try {
|
|
639
|
-
const
|
|
640
|
-
const spec = yaml.load(specContent);
|
|
661
|
+
const { spec, specPath } = await resolveAnalysisSpec(options, commandOptions);
|
|
641
662
|
|
|
642
663
|
console.log(chalk.cyan(`Budget Assessment for ${spec.id}`));
|
|
643
664
|
console.log('==============================================');
|
|
665
|
+
console.log(chalk.gray(`Spec: ${path.relative(process.cwd(), specPath)}`));
|
|
644
666
|
|
|
645
667
|
const result = predictor.assessBudget(spec);
|
|
646
668
|
|
|
@@ -681,7 +703,7 @@ async function handleAssessBudget(options) {
|
|
|
681
703
|
/**
|
|
682
704
|
* Handle pattern analysis command
|
|
683
705
|
*/
|
|
684
|
-
async function handleAnalyzePatterns(
|
|
706
|
+
async function handleAnalyzePatterns(_options) {
|
|
685
707
|
const chalk = (await import('chalk')).default;
|
|
686
708
|
const learner = new WaiverPatternLearner();
|
|
687
709
|
|
|
@@ -727,25 +749,16 @@ async function handleAnalyzePatterns(options) {
|
|
|
727
749
|
/**
|
|
728
750
|
* Handle find similar projects command
|
|
729
751
|
*/
|
|
730
|
-
async function handleFindSimilar(options) {
|
|
752
|
+
async function handleFindSimilar(options, commandOptions = {}) {
|
|
731
753
|
const chalk = (await import('chalk')).default;
|
|
732
754
|
const matcher = new ProjectSimilarityMatcher();
|
|
733
755
|
|
|
734
|
-
// Load current spec
|
|
735
|
-
let specPath = '.caws/working-spec.yaml';
|
|
736
|
-
if (options.includes('--spec')) {
|
|
737
|
-
const specIndex = options.indexOf('--spec');
|
|
738
|
-
if (specIndex + 1 < options.length) {
|
|
739
|
-
specPath = options[specIndex + 1];
|
|
740
|
-
}
|
|
741
|
-
}
|
|
742
|
-
|
|
743
756
|
try {
|
|
744
|
-
const
|
|
745
|
-
const spec = yaml.load(specContent);
|
|
757
|
+
const { spec, specPath } = await resolveAnalysisSpec(options, commandOptions);
|
|
746
758
|
|
|
747
759
|
console.log(chalk.cyan(`Finding projects similar to ${spec.id}`));
|
|
748
760
|
console.log('==============================================');
|
|
761
|
+
console.log(chalk.gray(`Spec: ${path.relative(process.cwd(), specPath)}`));
|
|
749
762
|
|
|
750
763
|
const similar = matcher.findSimilarProjects(spec);
|
|
751
764
|
|
package/dist/tool-loader.js
CHANGED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Session Identity
|
|
3
|
+
*
|
|
4
|
+
* Provides a unified way to identify the current agent session across
|
|
5
|
+
* Claude Code, Cursor, and other IDE agent environments.
|
|
6
|
+
*
|
|
7
|
+
* Sources checked (first match wins):
|
|
8
|
+
* 1. CLAUDE_SESSION_ID — set by Claude Code automatically
|
|
9
|
+
* 2. .caws/agents.json — written by Cursor session-log hook (conversation_id)
|
|
10
|
+
* 3. CURSOR_TRACE_ID — set by Cursor (per-request, not stable, last resort)
|
|
11
|
+
*
|
|
12
|
+
* The agent registry (.caws/agents.json) also tracks active agents for
|
|
13
|
+
* multi-agent coordination. Entries expire after a configurable TTL.
|
|
14
|
+
*
|
|
15
|
+
* @author @darianrosebrook
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const fs = require('fs');
|
|
19
|
+
const path = require('path');
|
|
20
|
+
|
|
21
|
+
const AGENTS_REGISTRY = '.caws/agents.json';
|
|
22
|
+
const DEFAULT_TTL_MS = 30 * 60 * 1000; // 30 minutes
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Get the current agent's session ID from the best available source.
|
|
26
|
+
* @param {string} [projectRoot] - Project root (for reading agent registry)
|
|
27
|
+
* @returns {string|null} Session ID or null if not in an agent context
|
|
28
|
+
*/
|
|
29
|
+
function getAgentSessionId(projectRoot) {
|
|
30
|
+
// 1. Claude Code — most reliable, set automatically
|
|
31
|
+
if (process.env.CLAUDE_SESSION_ID) {
|
|
32
|
+
return process.env.CLAUDE_SESSION_ID;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// 2. Agent registry — written by Cursor session-log hook
|
|
36
|
+
if (projectRoot) {
|
|
37
|
+
const registry = loadAgentRegistry(projectRoot);
|
|
38
|
+
const active = findActiveAgent(registry);
|
|
39
|
+
if (active) {
|
|
40
|
+
return active.sessionId;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// 3. Cursor trace ID — per-request, not stable, but better than nothing
|
|
45
|
+
if (process.env.CURSOR_TRACE_ID) {
|
|
46
|
+
return `cursor:${process.env.CURSOR_TRACE_ID}`;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Get the agent platform name.
|
|
54
|
+
* @returns {string} 'claude-code' | 'cursor' | 'unknown'
|
|
55
|
+
*/
|
|
56
|
+
function getAgentPlatform() {
|
|
57
|
+
if (process.env.CLAUDE_SESSION_ID) return 'claude-code';
|
|
58
|
+
if (process.env.CURSOR_TRACE_ID) return 'cursor';
|
|
59
|
+
return 'unknown';
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Load the agent registry, pruning stale entries.
|
|
64
|
+
* @param {string} root - Project root
|
|
65
|
+
* @returns {object} Registry with { agents: { [sessionId]: entry } }
|
|
66
|
+
*/
|
|
67
|
+
function loadAgentRegistry(root) {
|
|
68
|
+
const registryPath = path.join(root, AGENTS_REGISTRY);
|
|
69
|
+
let registry = { version: 1, agents: {} };
|
|
70
|
+
|
|
71
|
+
if (fs.existsSync(registryPath)) {
|
|
72
|
+
try {
|
|
73
|
+
registry = JSON.parse(fs.readFileSync(registryPath, 'utf8'));
|
|
74
|
+
} catch {
|
|
75
|
+
// Corrupt file — start fresh
|
|
76
|
+
registry = { version: 1, agents: {} };
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Prune stale entries on every read
|
|
81
|
+
const now = Date.now();
|
|
82
|
+
let pruned = false;
|
|
83
|
+
for (const [id, entry] of Object.entries(registry.agents || {})) {
|
|
84
|
+
const ttl = entry.ttl || DEFAULT_TTL_MS;
|
|
85
|
+
const lastSeenTime = entry.lastSeen ? new Date(entry.lastSeen).getTime() : 0;
|
|
86
|
+
const lastSeen = isNaN(lastSeenTime) ? 0 : lastSeenTime;
|
|
87
|
+
if (now - lastSeen > ttl) {
|
|
88
|
+
delete registry.agents[id];
|
|
89
|
+
pruned = true;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (pruned) {
|
|
94
|
+
saveAgentRegistry(root, registry);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return registry;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Save the agent registry atomically (write-then-rename).
|
|
102
|
+
* @param {string} root - Project root
|
|
103
|
+
* @param {object} registry - Registry object
|
|
104
|
+
*/
|
|
105
|
+
function saveAgentRegistry(root, registry) {
|
|
106
|
+
const registryPath = path.join(root, AGENTS_REGISTRY);
|
|
107
|
+
const dir = path.dirname(registryPath);
|
|
108
|
+
if (!fs.existsSync(dir)) {
|
|
109
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
110
|
+
}
|
|
111
|
+
const tmpPath = registryPath + '.tmp.' + process.pid;
|
|
112
|
+
fs.writeFileSync(tmpPath, JSON.stringify(registry, null, 2));
|
|
113
|
+
fs.renameSync(tmpPath, registryPath);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Register or heartbeat an agent session.
|
|
118
|
+
* Called by session-log hooks to keep entries fresh.
|
|
119
|
+
* @param {string} root - Project root
|
|
120
|
+
* @param {object} agent - Agent info
|
|
121
|
+
* @param {string} agent.sessionId - Unique session/conversation ID
|
|
122
|
+
* @param {string} agent.platform - 'claude-code' | 'cursor' | 'unknown'
|
|
123
|
+
* @param {string} [agent.model] - Model name if known
|
|
124
|
+
* @param {string} [agent.specId] - Active spec ID if known
|
|
125
|
+
* @param {number} [agent.ttl] - Custom TTL in ms (default 30 min)
|
|
126
|
+
*/
|
|
127
|
+
function heartbeatAgent(root, agent) {
|
|
128
|
+
const registry = loadAgentRegistry(root);
|
|
129
|
+
const existing = registry.agents[agent.sessionId] || {};
|
|
130
|
+
|
|
131
|
+
registry.agents[agent.sessionId] = {
|
|
132
|
+
...existing,
|
|
133
|
+
sessionId: agent.sessionId,
|
|
134
|
+
platform: agent.platform || existing.platform || 'unknown',
|
|
135
|
+
model: agent.model || existing.model || null,
|
|
136
|
+
specId: agent.specId || existing.specId || null,
|
|
137
|
+
ttl: agent.ttl || existing.ttl || DEFAULT_TTL_MS,
|
|
138
|
+
firstSeen: existing.firstSeen || new Date().toISOString(),
|
|
139
|
+
lastSeen: new Date().toISOString(),
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
saveAgentRegistry(root, registry);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Remove an agent session from the registry.
|
|
147
|
+
* Called on session stop.
|
|
148
|
+
* @param {string} root - Project root
|
|
149
|
+
* @param {string} sessionId - Session to remove
|
|
150
|
+
*/
|
|
151
|
+
function removeAgent(root, sessionId) {
|
|
152
|
+
const registry = loadAgentRegistry(root);
|
|
153
|
+
delete registry.agents[sessionId];
|
|
154
|
+
saveAgentRegistry(root, registry);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Find the most recently active agent for this terminal/process.
|
|
159
|
+
* Prefers agents that match the current environment.
|
|
160
|
+
* @param {object} registry - Loaded registry
|
|
161
|
+
* @returns {object|null} Agent entry or null
|
|
162
|
+
*/
|
|
163
|
+
function findActiveAgent(registry) {
|
|
164
|
+
const agents = Object.values(registry.agents || {});
|
|
165
|
+
if (agents.length === 0) return null;
|
|
166
|
+
|
|
167
|
+
// If we're in Cursor, prefer cursor agents
|
|
168
|
+
const isCursor = !!process.env.CURSOR_TRACE_ID;
|
|
169
|
+
const preferred = agents.filter(a => {
|
|
170
|
+
if (isCursor) return a.platform === 'cursor';
|
|
171
|
+
return a.platform === 'claude-code';
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
const pool = preferred.length > 0 ? preferred : agents;
|
|
175
|
+
|
|
176
|
+
// Return most recently seen
|
|
177
|
+
pool.sort((a, b) => new Date(b.lastSeen) - new Date(a.lastSeen));
|
|
178
|
+
return pool[0];
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* List all currently active (non-expired) agents.
|
|
183
|
+
* @param {string} root - Project root
|
|
184
|
+
* @returns {object[]} Array of agent entries
|
|
185
|
+
*/
|
|
186
|
+
function listActiveAgents(root) {
|
|
187
|
+
const registry = loadAgentRegistry(root);
|
|
188
|
+
return Object.values(registry.agents || {});
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
module.exports = {
|
|
192
|
+
getAgentSessionId,
|
|
193
|
+
getAgentPlatform,
|
|
194
|
+
loadAgentRegistry,
|
|
195
|
+
saveAgentRegistry,
|
|
196
|
+
heartbeatAgent,
|
|
197
|
+
removeAgent,
|
|
198
|
+
findActiveAgent,
|
|
199
|
+
listActiveAgents,
|
|
200
|
+
AGENTS_REGISTRY,
|
|
201
|
+
DEFAULT_TTL_MS,
|
|
202
|
+
};
|
package/dist/utils/detection.js
CHANGED
|
@@ -33,11 +33,17 @@ function findPackageRoot(startDir = __dirname) {
|
|
|
33
33
|
* @returns {Object} Setup information
|
|
34
34
|
*/
|
|
35
35
|
function detectCAWSSetup(cwd = process.cwd()) {
|
|
36
|
-
// Skip logging for version/help commands
|
|
36
|
+
// Skip logging for version/help/quiet commands, or when CAWS_QUIET is set.
|
|
37
|
+
// Verbose detection output contributes to Claude Code context-window
|
|
38
|
+
// exhaustion when agents run many caws commands in a single session.
|
|
37
39
|
const isQuietCommand =
|
|
38
40
|
process.argv.includes('--version') ||
|
|
39
41
|
process.argv.includes('-V') ||
|
|
40
|
-
process.argv.includes('--help')
|
|
42
|
+
process.argv.includes('--help') ||
|
|
43
|
+
process.argv.includes('--json') ||
|
|
44
|
+
process.argv.includes('--quiet') ||
|
|
45
|
+
process.argv.includes('-q') ||
|
|
46
|
+
process.env.CAWS_QUIET === '1';
|
|
41
47
|
|
|
42
48
|
if (!isQuietCommand) {
|
|
43
49
|
console.log(chalk.blue('Detecting CAWS setup...'));
|