@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
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$schema": "
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
3
|
"title": "CAWS Working Spec",
|
|
4
4
|
"type": "object",
|
|
5
5
|
"required": [
|
|
@@ -15,119 +15,326 @@
|
|
|
15
15
|
"non_functional",
|
|
16
16
|
"contracts"
|
|
17
17
|
],
|
|
18
|
+
"not": {
|
|
19
|
+
"required": [
|
|
20
|
+
"change_budget"
|
|
21
|
+
]
|
|
22
|
+
},
|
|
18
23
|
"properties": {
|
|
19
|
-
"id": {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
24
|
+
"id": {
|
|
25
|
+
"type": "string",
|
|
26
|
+
"pattern": "^[A-Z][A-Z0-9]*(-[A-Z0-9]+)*-\\d+$",
|
|
27
|
+
"description": "Unique identifier for the change. Format: uppercase/digit PREFIX segments separated by dashes, final segment is one+ digits (e.g. CAWSFIX-16, P03-TRUTH-001, ALG-001A-HARDEN-01). Matches SPEC_ID_PATTERN in spec-validation.js (CAWSFIX-21 alignment)."
|
|
28
|
+
},
|
|
29
|
+
"title": {
|
|
30
|
+
"type": "string",
|
|
31
|
+
"minLength": 10,
|
|
32
|
+
"maxLength": 200,
|
|
33
|
+
"description": "Clear, descriptive title"
|
|
34
|
+
},
|
|
35
|
+
"type": {
|
|
36
|
+
"type": "string",
|
|
37
|
+
"enum": [
|
|
38
|
+
"feature",
|
|
39
|
+
"fix",
|
|
40
|
+
"refactor",
|
|
41
|
+
"chore",
|
|
42
|
+
"doc",
|
|
43
|
+
"docs"
|
|
44
|
+
],
|
|
45
|
+
"description": "Type of work (informational; `mode` is the enforced gate input)"
|
|
46
|
+
},
|
|
47
|
+
"status": {
|
|
48
|
+
"type": "string",
|
|
49
|
+
"enum": [
|
|
50
|
+
"draft",
|
|
51
|
+
"active",
|
|
52
|
+
"in_progress",
|
|
53
|
+
"completed",
|
|
54
|
+
"closed",
|
|
55
|
+
"archived"
|
|
56
|
+
]
|
|
57
|
+
},
|
|
58
|
+
"created_at": {
|
|
59
|
+
"type": "string"
|
|
60
|
+
},
|
|
61
|
+
"updated_at": {
|
|
62
|
+
"type": "string"
|
|
63
|
+
},
|
|
64
|
+
"worktree": {
|
|
65
|
+
"type": "string",
|
|
66
|
+
"description": "CAWS worktree name assigned to this spec"
|
|
67
|
+
},
|
|
68
|
+
"risk_tier": {
|
|
69
|
+
"type": [
|
|
70
|
+
"integer",
|
|
71
|
+
"string"
|
|
72
|
+
],
|
|
73
|
+
"enum": [
|
|
74
|
+
1,
|
|
75
|
+
2,
|
|
76
|
+
3,
|
|
77
|
+
"1",
|
|
78
|
+
"2",
|
|
79
|
+
"3"
|
|
80
|
+
],
|
|
81
|
+
"description": "Risk level (1=high, 2=medium, 3=low)"
|
|
82
|
+
},
|
|
83
|
+
"mode": {
|
|
84
|
+
"type": "string",
|
|
85
|
+
"enum": [
|
|
86
|
+
"feature",
|
|
87
|
+
"refactor",
|
|
88
|
+
"fix",
|
|
89
|
+
"doc",
|
|
90
|
+
"docs",
|
|
91
|
+
"chore",
|
|
92
|
+
"development"
|
|
93
|
+
],
|
|
94
|
+
"description": "Mode of change. `development` is the default used by `caws specs create`; feature/refactor/fix/doc/chore are the classic modes the legacy validator accepted."
|
|
95
|
+
},
|
|
23
96
|
"waiver_ids": {
|
|
24
97
|
"type": "array",
|
|
25
|
-
"items": {
|
|
98
|
+
"items": {
|
|
99
|
+
"type": "string",
|
|
100
|
+
"pattern": "^WV-\\d{4}$"
|
|
101
|
+
},
|
|
26
102
|
"description": "IDs of active waivers applying to this spec"
|
|
27
103
|
},
|
|
28
104
|
"blast_radius": {
|
|
29
105
|
"type": "object",
|
|
30
|
-
"required": [
|
|
106
|
+
"required": [
|
|
107
|
+
"modules",
|
|
108
|
+
"data_migration"
|
|
109
|
+
],
|
|
31
110
|
"properties": {
|
|
32
|
-
"modules": {
|
|
33
|
-
|
|
34
|
-
|
|
111
|
+
"modules": {
|
|
112
|
+
"type": "array",
|
|
113
|
+
"items": {
|
|
114
|
+
"type": "string"
|
|
115
|
+
},
|
|
116
|
+
"description": "List of modules/paths the change touches"
|
|
117
|
+
},
|
|
118
|
+
"data_migration": {
|
|
119
|
+
"type": "boolean",
|
|
120
|
+
"description": "Whether the change requires a data migration"
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
"additionalProperties": true
|
|
124
|
+
},
|
|
125
|
+
"operational_rollback_slo": {
|
|
126
|
+
"type": "string",
|
|
127
|
+
"minLength": 1,
|
|
128
|
+
"description": "Time target for operational rollback (e.g. '5m', '30m', '1h')"
|
|
35
129
|
},
|
|
36
|
-
"operational_rollback_slo": { "type": "string" },
|
|
37
130
|
"scope": {
|
|
38
131
|
"type": "object",
|
|
39
|
-
"required": [
|
|
132
|
+
"required": [
|
|
133
|
+
"in"
|
|
134
|
+
],
|
|
40
135
|
"properties": {
|
|
41
|
-
"in": {
|
|
42
|
-
|
|
43
|
-
|
|
136
|
+
"in": {
|
|
137
|
+
"type": "array",
|
|
138
|
+
"items": {
|
|
139
|
+
"type": "string"
|
|
140
|
+
},
|
|
141
|
+
"minItems": 1,
|
|
142
|
+
"description": "Files/paths allowed to be edited (non-empty)"
|
|
143
|
+
},
|
|
144
|
+
"out": {
|
|
145
|
+
"type": "array",
|
|
146
|
+
"items": {
|
|
147
|
+
"type": "string"
|
|
148
|
+
},
|
|
149
|
+
"description": "Files/paths explicitly excluded from edits"
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
"additionalProperties": true
|
|
153
|
+
},
|
|
154
|
+
"invariants": {
|
|
155
|
+
"type": "array",
|
|
156
|
+
"items": {
|
|
157
|
+
"type": "string"
|
|
158
|
+
},
|
|
159
|
+
"minItems": 1,
|
|
160
|
+
"description": "Properties that must hold across the change (non-empty)"
|
|
44
161
|
},
|
|
45
|
-
"invariants": { "type": "array", "items": { "type": "string" }, "minItems": 1 },
|
|
46
162
|
"acceptance": {
|
|
47
163
|
"type": "array",
|
|
48
164
|
"minItems": 1,
|
|
165
|
+
"description": "Given/When/Then acceptance criteria (non-empty)",
|
|
49
166
|
"items": {
|
|
50
167
|
"type": "object",
|
|
51
|
-
"required": [
|
|
168
|
+
"required": [
|
|
169
|
+
"id",
|
|
170
|
+
"given",
|
|
171
|
+
"when",
|
|
172
|
+
"then"
|
|
173
|
+
],
|
|
52
174
|
"properties": {
|
|
53
|
-
"id": {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
175
|
+
"id": {
|
|
176
|
+
"type": "string",
|
|
177
|
+
"minLength": 1
|
|
178
|
+
},
|
|
179
|
+
"given": {
|
|
180
|
+
"type": "string",
|
|
181
|
+
"minLength": 1
|
|
182
|
+
},
|
|
183
|
+
"when": {
|
|
184
|
+
"type": "string",
|
|
185
|
+
"minLength": 1
|
|
186
|
+
},
|
|
187
|
+
"then": {
|
|
188
|
+
"type": "string",
|
|
189
|
+
"minLength": 1
|
|
190
|
+
}
|
|
191
|
+
},
|
|
192
|
+
"additionalProperties": true
|
|
58
193
|
}
|
|
59
194
|
},
|
|
60
195
|
"non_functional": {
|
|
61
196
|
"type": "object",
|
|
197
|
+
"required": [
|
|
198
|
+
"a11y",
|
|
199
|
+
"perf",
|
|
200
|
+
"security"
|
|
201
|
+
],
|
|
62
202
|
"properties": {
|
|
63
|
-
"a11y": {
|
|
203
|
+
"a11y": {
|
|
204
|
+
"type": "array",
|
|
205
|
+
"items": {
|
|
206
|
+
"type": "string"
|
|
207
|
+
},
|
|
208
|
+
"description": "Accessibility requirements (may be empty array if not applicable)"
|
|
209
|
+
},
|
|
64
210
|
"perf": {
|
|
65
211
|
"type": "object",
|
|
66
|
-
"
|
|
67
|
-
"api_p95_ms": { "type": "integer", "minimum": 1 },
|
|
68
|
-
"lcp_ms": { "type": "integer", "minimum": 1 }
|
|
69
|
-
},
|
|
70
|
-
"additionalProperties": false
|
|
212
|
+
"description": "Performance requirements (e.g. api_p95_ms, lcp_ms)"
|
|
71
213
|
},
|
|
72
|
-
"security": {
|
|
214
|
+
"security": {
|
|
215
|
+
"type": "array",
|
|
216
|
+
"items": {
|
|
217
|
+
"type": "string"
|
|
218
|
+
},
|
|
219
|
+
"description": "Security requirements (may be empty array if not applicable)"
|
|
220
|
+
}
|
|
73
221
|
},
|
|
74
|
-
"additionalProperties":
|
|
222
|
+
"additionalProperties": true
|
|
75
223
|
},
|
|
76
224
|
"contracts": {
|
|
77
225
|
"type": "array",
|
|
78
|
-
"
|
|
226
|
+
"description": "API contracts. Empty array is permitted; CAWSFIX-06 will warn (not fail) when mode=feature with empty contracts.",
|
|
79
227
|
"items": {
|
|
80
228
|
"type": "object",
|
|
81
|
-
"required": [
|
|
229
|
+
"required": [
|
|
230
|
+
"type",
|
|
231
|
+
"path"
|
|
232
|
+
],
|
|
82
233
|
"properties": {
|
|
83
|
-
"type": {
|
|
84
|
-
|
|
85
|
-
|
|
234
|
+
"type": {
|
|
235
|
+
"type": "string",
|
|
236
|
+
"enum": [
|
|
237
|
+
"openapi",
|
|
238
|
+
"graphql",
|
|
239
|
+
"proto",
|
|
240
|
+
"pact",
|
|
241
|
+
"project_setup"
|
|
242
|
+
]
|
|
243
|
+
},
|
|
244
|
+
"path": {
|
|
245
|
+
"type": "string"
|
|
246
|
+
},
|
|
247
|
+
"description": {
|
|
248
|
+
"type": "string"
|
|
249
|
+
},
|
|
250
|
+
"version": {
|
|
251
|
+
"type": "string"
|
|
252
|
+
}
|
|
253
|
+
},
|
|
254
|
+
"additionalProperties": true
|
|
86
255
|
}
|
|
87
256
|
},
|
|
88
257
|
"observability": {
|
|
258
|
+
"type": "object"
|
|
259
|
+
},
|
|
260
|
+
"migrations": {
|
|
261
|
+
"type": "array",
|
|
262
|
+
"items": {
|
|
263
|
+
"type": "string"
|
|
264
|
+
}
|
|
265
|
+
},
|
|
266
|
+
"rollback": {
|
|
267
|
+
"type": "array",
|
|
268
|
+
"items": {
|
|
269
|
+
"type": "string"
|
|
270
|
+
}
|
|
271
|
+
},
|
|
272
|
+
"experimental_mode": {
|
|
89
273
|
"type": "object",
|
|
274
|
+
"required": [
|
|
275
|
+
"enabled",
|
|
276
|
+
"rationale",
|
|
277
|
+
"expires_at"
|
|
278
|
+
],
|
|
90
279
|
"properties": {
|
|
91
|
-
"
|
|
92
|
-
|
|
93
|
-
|
|
280
|
+
"enabled": {
|
|
281
|
+
"type": "boolean"
|
|
282
|
+
},
|
|
283
|
+
"rationale": {
|
|
284
|
+
"type": "string"
|
|
285
|
+
},
|
|
286
|
+
"expires_at": {
|
|
287
|
+
"type": "string"
|
|
288
|
+
}
|
|
94
289
|
}
|
|
95
290
|
},
|
|
96
|
-
"migrations": { "type": "array", "items": { "type": "string" } },
|
|
97
|
-
"rollback": { "type": "array", "items": { "type": "string" } },
|
|
98
|
-
"experiment_mode": {
|
|
99
|
-
"type": "boolean",
|
|
100
|
-
"description": "Enables experimental mode with reduced requirements"
|
|
101
|
-
},
|
|
102
291
|
"timeboxed_hours": {
|
|
103
292
|
"type": "integer",
|
|
104
|
-
"minimum": 1
|
|
105
|
-
"description": "Time limit for experimental features in hours"
|
|
293
|
+
"minimum": 1
|
|
106
294
|
},
|
|
107
295
|
"human_override": {
|
|
108
296
|
"type": "object",
|
|
297
|
+
"required": [
|
|
298
|
+
"approved_by",
|
|
299
|
+
"reason"
|
|
300
|
+
],
|
|
109
301
|
"properties": {
|
|
110
|
-
"approved_by": {
|
|
111
|
-
|
|
302
|
+
"approved_by": {
|
|
303
|
+
"type": "string"
|
|
304
|
+
},
|
|
305
|
+
"reason": {
|
|
306
|
+
"type": "string"
|
|
307
|
+
},
|
|
112
308
|
"waived_requirements": {
|
|
113
309
|
"type": "array",
|
|
114
310
|
"items": {
|
|
115
|
-
"type": "string"
|
|
116
|
-
"enum": ["mutation_testing", "contract_tests", "coverage", "manual_review"]
|
|
311
|
+
"type": "string"
|
|
117
312
|
}
|
|
118
313
|
},
|
|
119
|
-
"expiry_date": {
|
|
120
|
-
|
|
121
|
-
|
|
314
|
+
"expiry_date": {
|
|
315
|
+
"type": "string"
|
|
316
|
+
}
|
|
317
|
+
}
|
|
122
318
|
},
|
|
123
319
|
"ai_assessment": {
|
|
124
320
|
"type": "object",
|
|
125
321
|
"properties": {
|
|
126
|
-
"confidence_level": {
|
|
127
|
-
|
|
128
|
-
|
|
322
|
+
"confidence_level": {
|
|
323
|
+
"type": "integer",
|
|
324
|
+
"minimum": 1,
|
|
325
|
+
"maximum": 10
|
|
326
|
+
},
|
|
327
|
+
"uncertainty_areas": {
|
|
328
|
+
"type": "array",
|
|
329
|
+
"items": {
|
|
330
|
+
"type": "string"
|
|
331
|
+
}
|
|
332
|
+
},
|
|
333
|
+
"recommended_pairing": {
|
|
334
|
+
"type": "boolean"
|
|
335
|
+
}
|
|
129
336
|
}
|
|
130
337
|
}
|
|
131
338
|
},
|
|
132
|
-
"additionalProperties":
|
|
339
|
+
"additionalProperties": true
|
|
133
340
|
}
|
|
@@ -21,11 +21,13 @@
|
|
|
21
21
|
"baseBranch": { "type": "string" },
|
|
22
22
|
"scope": { "type": ["string", "null"] },
|
|
23
23
|
"specId": { "type": ["string", "null"] },
|
|
24
|
+
"owner": { "type": ["string", "null"], "description": "CLAUDE_SESSION_ID of the creating agent" },
|
|
24
25
|
"createdAt": { "type": "string", "format": "date-time" },
|
|
25
26
|
"destroyedAt": { "type": "string", "format": "date-time" },
|
|
27
|
+
"autoRegistered": { "type": "boolean" },
|
|
26
28
|
"status": {
|
|
27
29
|
"type": "string",
|
|
28
|
-
"enum": ["active", "orphaned", "missing", "destroyed"]
|
|
30
|
+
"enum": ["fresh", "active", "merged", "orphaned", "missing", "stale-merged", "destroyed"]
|
|
29
31
|
}
|
|
30
32
|
},
|
|
31
33
|
"additionalProperties": false
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
id: '{{FEATURE_ID}}'
|
|
2
2
|
title: '{{FEATURE_TITLE}}'
|
|
3
|
-
|
|
3
|
+
# Recommended when the spec belongs to a CAWS worktree:
|
|
4
|
+
# worktree: '{{WORKTREE_NAME}}'
|
|
5
|
+
risk_tier: {{TIER}}
|
|
6
|
+
mode: feature
|
|
7
|
+
blast_radius:
|
|
8
|
+
modules: []
|
|
9
|
+
data_migration: false
|
|
10
|
+
operational_rollback_slo: "30m"
|
|
4
11
|
scope:
|
|
5
12
|
in:
|
|
6
13
|
- '{{SCOPE_ITEM_1}}'
|
|
@@ -37,8 +44,8 @@ non_functional:
|
|
|
37
44
|
a11y:
|
|
38
45
|
- '{{ACCESSIBILITY_REQUIREMENT}}'
|
|
39
46
|
perf:
|
|
40
|
-
api_p95_ms: {
|
|
41
|
-
lcp_ms: {
|
|
47
|
+
api_p95_ms: {{PERF_BUDGET}}
|
|
48
|
+
lcp_ms: {{LCP_BUDGET}}
|
|
42
49
|
security:
|
|
43
50
|
- '{{SECURITY_REQUIREMENT}}'
|
|
44
51
|
contracts:
|
|
@@ -71,4 +78,3 @@ rollback:
|
|
|
71
78
|
# reason: "Urgent production fix - bypassing mutation tests for immediate deployment"
|
|
72
79
|
# waived_requirements: ["mutation_testing", "manual_review"]
|
|
73
80
|
# expiry_date: "2025-10-01T00:00:00Z"
|
|
74
|
-
|
|
@@ -70,26 +70,71 @@ function checkFileScope(filePath, projectDir) {
|
|
|
70
70
|
return { inScope: true, reason: 'js-yaml not available' };
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
|
|
73
|
+
// --- Authoritative spec detection ---
|
|
74
|
+
// If inside a worktree with a mutual spec binding, only check that spec.
|
|
75
|
+
let authoritativeSpec = null;
|
|
76
|
+
let mode = 'union';
|
|
74
77
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
78
|
+
const registryPath = path.join(projectDir, '.caws', 'worktrees.json');
|
|
79
|
+
const worktreesBase = path.join(projectDir, '.caws', 'worktrees');
|
|
80
|
+
const cwd = process.cwd();
|
|
81
|
+
|
|
82
|
+
if (cwd.startsWith(worktreesBase + path.sep)) {
|
|
83
|
+
const relative = path.relative(worktreesBase, cwd);
|
|
84
|
+
const worktreeName = relative.split(path.sep)[0];
|
|
85
|
+
|
|
86
|
+
if (worktreeName && fs.existsSync(registryPath)) {
|
|
87
|
+
try {
|
|
88
|
+
const reg = JSON.parse(fs.readFileSync(registryPath, 'utf8'));
|
|
89
|
+
const entry = reg.worktrees && reg.worktrees[worktreeName];
|
|
90
|
+
|
|
91
|
+
if (entry && entry.specId) {
|
|
92
|
+
const specCandidates = [
|
|
93
|
+
path.join(specsDir, entry.specId + '.yaml'),
|
|
94
|
+
path.join(specsDir, entry.specId + '.yml'),
|
|
95
|
+
];
|
|
96
|
+
for (const candidate of specCandidates) {
|
|
97
|
+
if (fs.existsSync(candidate)) {
|
|
98
|
+
try {
|
|
99
|
+
const s = yaml.load(fs.readFileSync(candidate, 'utf8'));
|
|
100
|
+
if (s && !TERMINAL.has(s.status) && s.worktree === worktreeName) {
|
|
101
|
+
authoritativeSpec = { source: path.basename(candidate), spec: s };
|
|
102
|
+
mode = 'authoritative';
|
|
103
|
+
}
|
|
104
|
+
} catch (_) {}
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
} catch (_) {}
|
|
110
|
+
}
|
|
82
111
|
}
|
|
83
112
|
|
|
84
|
-
|
|
85
|
-
|
|
113
|
+
// --- Collect specs based on mode ---
|
|
114
|
+
const specs = [];
|
|
115
|
+
|
|
116
|
+
if (authoritativeSpec) {
|
|
117
|
+
specs.push(authoritativeSpec);
|
|
118
|
+
} else {
|
|
119
|
+
if (fs.existsSync(specFile)) {
|
|
86
120
|
try {
|
|
87
|
-
const s = yaml.load(fs.readFileSync(
|
|
121
|
+
const s = yaml.load(fs.readFileSync(specFile, 'utf8'));
|
|
88
122
|
if (s && !TERMINAL.has(s.status)) {
|
|
89
|
-
specs.push({ source:
|
|
123
|
+
specs.push({ source: 'working-spec', spec: s });
|
|
90
124
|
}
|
|
91
125
|
} catch (_) {}
|
|
92
126
|
}
|
|
127
|
+
|
|
128
|
+
if (fs.existsSync(specsDir)) {
|
|
129
|
+
for (const f of fs.readdirSync(specsDir).filter(f => f.endsWith('.yaml') || f.endsWith('.yml'))) {
|
|
130
|
+
try {
|
|
131
|
+
const s = yaml.load(fs.readFileSync(path.join(specsDir, f), 'utf8'));
|
|
132
|
+
if (s && !TERMINAL.has(s.status)) {
|
|
133
|
+
specs.push({ source: f, spec: s });
|
|
134
|
+
}
|
|
135
|
+
} catch (_) {}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
93
138
|
}
|
|
94
139
|
|
|
95
140
|
if (specs.length === 0) {
|
|
@@ -100,17 +145,23 @@ function checkFileScope(filePath, projectDir) {
|
|
|
100
145
|
for (const { source, spec } of specs) {
|
|
101
146
|
for (const pattern of (spec.scope?.out || [])) {
|
|
102
147
|
if (globToRegex(pattern).test(filePath)) {
|
|
103
|
-
|
|
148
|
+
const modeHint = mode === 'union'
|
|
149
|
+
? '. No authoritative spec bound — checking all active specs. Fix: caws worktree bind <spec-id>'
|
|
150
|
+
: '';
|
|
151
|
+
return { inScope: false, reason: `out-of-scope in ${source} (pattern: ${pattern})${modeHint}` };
|
|
104
152
|
}
|
|
105
153
|
}
|
|
106
154
|
}
|
|
107
155
|
|
|
108
|
-
//
|
|
156
|
+
// scope.in — must match at least one
|
|
109
157
|
const allIn = specs.flatMap(({ spec }) => spec.scope?.in || []);
|
|
110
158
|
if (allIn.length > 0) {
|
|
111
159
|
const found = allIn.some(pattern => globToRegex(pattern).test(filePath));
|
|
112
160
|
if (!found) {
|
|
113
|
-
|
|
161
|
+
const modeHint = mode === 'union'
|
|
162
|
+
? '. No authoritative spec bound — checking all active specs. Fix: caws worktree bind <spec-id>'
|
|
163
|
+
: '';
|
|
164
|
+
return { inScope: false, reason: `not in any active spec scope.in${modeHint}` };
|
|
114
165
|
}
|
|
115
166
|
}
|
|
116
167
|
|
|
@@ -38,7 +38,7 @@ Run before Claude executes a tool:
|
|
|
38
38
|
|------|---------|---------|
|
|
39
39
|
| `block-dangerous.sh` | `Bash` | Block destructive shell commands |
|
|
40
40
|
| `scan-secrets.sh` | `Read` | Warn when reading sensitive files |
|
|
41
|
-
| `scope-guard.sh` | `Write\|Edit` | Check scope boundaries before edits |
|
|
41
|
+
| `scope-guard.sh` | `Write\|Edit` | Check scope boundaries before edits (use `caws scope show` to diagnose blocks) |
|
|
42
42
|
|
|
43
43
|
### PostToolUse Hooks
|
|
44
44
|
|
|
@@ -1,23 +1,70 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
-
# CAWS
|
|
3
|
-
#
|
|
2
|
+
# CAWS Command Safety Gate for Claude Code
|
|
3
|
+
# Delegates to classify_command.py for robust command parsing and classification.
|
|
4
|
+
# Falls back to bash pattern matching if Python is unavailable.
|
|
5
|
+
#
|
|
6
|
+
# The Python classifier handles:
|
|
7
|
+
# - Heredoc-aware parsing (won't false-positive on quoted dangerous commands)
|
|
8
|
+
# - Quoted-region stripping (echo "git reset --hard" is safe)
|
|
9
|
+
# - Pipeline-aware dangers (curl | sh)
|
|
10
|
+
# - Context-aware rm classification (safe prefixes vs dangerous targets)
|
|
11
|
+
# - Proper shell segmentation (&&, ||, ;, |)
|
|
12
|
+
#
|
|
4
13
|
# @author @darianrosebrook
|
|
5
14
|
|
|
6
15
|
set -euo pipefail
|
|
7
16
|
|
|
17
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
18
|
+
|
|
8
19
|
# Read JSON input from Claude Code
|
|
9
20
|
INPUT=$(cat)
|
|
10
21
|
|
|
11
22
|
# Extract tool info
|
|
12
|
-
TOOL_NAME=$(
|
|
13
|
-
COMMAND=$(
|
|
23
|
+
TOOL_NAME=$(printf '%s' "$INPUT" | jq -r '.tool_name // ""')
|
|
24
|
+
COMMAND=$(printf '%s' "$INPUT" | jq -r '.tool_input.command // ""')
|
|
14
25
|
|
|
15
26
|
# Only check Bash tool
|
|
16
27
|
if [[ "$TOOL_NAME" != "Bash" ]] || [[ -z "$COMMAND" ]]; then
|
|
17
28
|
exit 0
|
|
18
29
|
fi
|
|
19
30
|
|
|
20
|
-
#
|
|
31
|
+
# --- Try Python classifier first (preferred) ---
|
|
32
|
+
CLASSIFIER="$SCRIPT_DIR/classify_command.py"
|
|
33
|
+
if [[ -f "$CLASSIFIER" ]] && command -v python3 >/dev/null 2>&1; then
|
|
34
|
+
REPO_ROOT="${CLAUDE_PROJECT_DIR:-.}"
|
|
35
|
+
CLASSIFIER_STDERR=$(mktemp)
|
|
36
|
+
RESULT=$(printf '%s' "$COMMAND" | python3 "$CLASSIFIER" \
|
|
37
|
+
--repo-root "$REPO_ROOT" \
|
|
38
|
+
--home "$HOME" \
|
|
39
|
+
--cwd "$(pwd)" 2>"$CLASSIFIER_STDERR") || {
|
|
40
|
+
DIAG=$(head -c 200 "$CLASSIFIER_STDERR" 2>/dev/null || true)
|
|
41
|
+
rm -f "$CLASSIFIER_STDERR"
|
|
42
|
+
RESULT="{\"decision\":\"ask\",\"reason\":\"command classifier failed: ${DIAG:-unknown error}\"}"
|
|
43
|
+
}
|
|
44
|
+
rm -f "$CLASSIFIER_STDERR"
|
|
45
|
+
|
|
46
|
+
DECISION=$(printf '%s' "$RESULT" | jq -r '.decision // "ask"')
|
|
47
|
+
REASON=$(printf '%s' "$RESULT" | jq -r '.reason // "unknown"')
|
|
48
|
+
|
|
49
|
+
case "$DECISION" in
|
|
50
|
+
allow)
|
|
51
|
+
exit 0
|
|
52
|
+
;;
|
|
53
|
+
deny)
|
|
54
|
+
echo "BLOCKED: $REASON" >&2
|
|
55
|
+
echo "Command was: $COMMAND" >&2
|
|
56
|
+
exit 2
|
|
57
|
+
;;
|
|
58
|
+
ask)
|
|
59
|
+
echo "WARNING: $REASON" >&2
|
|
60
|
+
echo "Command was: $COMMAND" >&2
|
|
61
|
+
exit 1
|
|
62
|
+
;;
|
|
63
|
+
esac
|
|
64
|
+
fi
|
|
65
|
+
|
|
66
|
+
# --- Fallback: bash pattern matching (less precise, no heredoc/quote awareness) ---
|
|
67
|
+
|
|
21
68
|
DANGEROUS_PATTERNS=(
|
|
22
69
|
# Destructive file operations
|
|
23
70
|
'rm -rf /'
|
|
@@ -96,7 +143,6 @@ for pattern in "${DANGEROUS_PATTERNS[@]}"; do
|
|
|
96
143
|
# Allow git rebase/cherry-pick only when no worktrees are active
|
|
97
144
|
if [[ "$pattern" == *"git rebase"* ]] || [[ "$pattern" == *"git cherry-pick"* ]]; then
|
|
98
145
|
PROJECT_DIR="${CLAUDE_PROJECT_DIR:-.}"
|
|
99
|
-
# Resolve to main repo root if we're in a worktree
|
|
100
146
|
if command -v git >/dev/null 2>&1; then
|
|
101
147
|
GIT_COMMON=$(cd "$PROJECT_DIR" && git rev-parse --git-common-dir 2>/dev/null || echo "")
|
|
102
148
|
if [[ -n "$GIT_COMMON" ]] && [[ "$GIT_COMMON" != ".git" ]]; then
|
|
@@ -116,7 +162,6 @@ for pattern in "${DANGEROUS_PATTERNS[@]}"; do
|
|
|
116
162
|
} catch(e) { console.log(0); }
|
|
117
163
|
" 2>/dev/null || echo "0")
|
|
118
164
|
if [[ "$ACTIVE_COUNT" -gt 0 ]]; then
|
|
119
|
-
# Extract the specific git subcommand for the message
|
|
120
165
|
GIT_SUBCMD="git operation"
|
|
121
166
|
[[ "$pattern" == *"git rebase"* ]] && GIT_SUBCMD="git rebase"
|
|
122
167
|
[[ "$pattern" == *"git cherry-pick"* ]] && GIT_SUBCMD="git cherry-pick"
|
|
@@ -126,7 +171,6 @@ for pattern in "${DANGEROUS_PATTERNS[@]}"; do
|
|
|
126
171
|
exit 2
|
|
127
172
|
fi
|
|
128
173
|
fi
|
|
129
|
-
# No active worktrees — allow
|
|
130
174
|
continue
|
|
131
175
|
fi
|
|
132
176
|
|
|
@@ -142,11 +186,8 @@ for pattern in "${DANGEROUS_PATTERNS[@]}"; do
|
|
|
142
186
|
fi
|
|
143
187
|
fi
|
|
144
188
|
|
|
145
|
-
# Output to stderr for Claude to see
|
|
146
189
|
echo "BLOCKED: Command matches dangerous pattern: $pattern" >&2
|
|
147
190
|
echo "Command was: $COMMAND" >&2
|
|
148
|
-
|
|
149
|
-
# Exit code 2 blocks the tool and shows stderr to Claude
|
|
150
191
|
exit 2
|
|
151
192
|
fi
|
|
152
193
|
done
|