anvil-dev-framework 0.1.6
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 +719 -0
- package/VERSION +1 -0
- package/docs/ANVIL-REPO-IMPLEMENTATION-PLAN.md +441 -0
- package/docs/FIRST-SKILL-TUTORIAL.md +408 -0
- package/docs/INSTALLATION-RETRO-NOTES.md +458 -0
- package/docs/INSTALLATION.md +984 -0
- package/docs/anvil-hud.md +469 -0
- package/docs/anvil-init.md +255 -0
- package/docs/anvil-state.md +210 -0
- package/docs/boris-cherny-ralph-wiggum-insights.md +608 -0
- package/docs/command-reference.md +2022 -0
- package/docs/hooks-tts.md +368 -0
- package/docs/implementation-guide.md +810 -0
- package/docs/linear-github-integration.md +247 -0
- package/docs/local-issues.md +677 -0
- package/docs/patterns/README.md +419 -0
- package/docs/planning-responsibilities.md +139 -0
- package/docs/session-workflow.md +573 -0
- package/docs/simplification-plan-template.md +297 -0
- package/docs/simplification-principles.md +129 -0
- package/docs/specifications/CCS-RALPH-INTEGRATION-DESIGN.md +633 -0
- package/docs/specifications/CCS-RESEARCH-REPORT.md +169 -0
- package/docs/specifications/PLAN-ANV-verification-ralph-wiggum.md +403 -0
- package/docs/specifications/PLAN-parallel-tracks-anvil-memory-ccs.md +494 -0
- package/docs/specifications/SPEC-ANV-VRW/component-01-verify.md +208 -0
- package/docs/specifications/SPEC-ANV-VRW/component-02-stop-gate.md +226 -0
- package/docs/specifications/SPEC-ANV-VRW/component-03-posttooluse.md +209 -0
- package/docs/specifications/SPEC-ANV-VRW/component-04-ralph-wiggum.md +604 -0
- package/docs/specifications/SPEC-ANV-VRW/component-05-atomic-actions.md +311 -0
- package/docs/specifications/SPEC-ANV-VRW/component-06-verify-subagent.md +264 -0
- package/docs/specifications/SPEC-ANV-VRW/component-07-claude-md.md +363 -0
- package/docs/specifications/SPEC-ANV-VRW/index.md +182 -0
- package/docs/specifications/SPEC-ANV-anvil-memory.md +573 -0
- package/docs/specifications/SPEC-ANV-context-checkpoints.md +781 -0
- package/docs/specifications/SPEC-ANV-verification-ralph-wiggum.md +789 -0
- package/docs/sync.md +122 -0
- package/global/CLAUDE.md +140 -0
- package/global/agents/verify-app.md +164 -0
- package/global/commands/anvil-settings.md +527 -0
- package/global/commands/anvil-sync.md +121 -0
- package/global/commands/change.md +197 -0
- package/global/commands/clarify.md +252 -0
- package/global/commands/cleanup.md +292 -0
- package/global/commands/commit-push-pr.md +207 -0
- package/global/commands/decay-review.md +127 -0
- package/global/commands/discover.md +158 -0
- package/global/commands/doc-coverage.md +122 -0
- package/global/commands/evidence.md +307 -0
- package/global/commands/explore.md +121 -0
- package/global/commands/force-exit.md +135 -0
- package/global/commands/handoff.md +191 -0
- package/global/commands/healthcheck.md +302 -0
- package/global/commands/hud.md +84 -0
- package/global/commands/insights.md +319 -0
- package/global/commands/linear-setup.md +184 -0
- package/global/commands/lint-fix.md +198 -0
- package/global/commands/orient.md +510 -0
- package/global/commands/plan.md +228 -0
- package/global/commands/ralph.md +346 -0
- package/global/commands/ready.md +182 -0
- package/global/commands/release.md +305 -0
- package/global/commands/retro.md +96 -0
- package/global/commands/shard.md +166 -0
- package/global/commands/spec.md +227 -0
- package/global/commands/sprint.md +184 -0
- package/global/commands/tasks.md +228 -0
- package/global/commands/test-and-commit.md +151 -0
- package/global/commands/validate.md +132 -0
- package/global/commands/verify.md +251 -0
- package/global/commands/weekly-review.md +156 -0
- package/global/hooks/__pycache__/ralph_context_monitor.cpython-314.pyc +0 -0
- package/global/hooks/__pycache__/statusline_agent_sync.cpython-314.pyc +0 -0
- package/global/hooks/anvil_memory_observe.ts +322 -0
- package/global/hooks/anvil_memory_session.ts +166 -0
- package/global/hooks/anvil_memory_stop.ts +187 -0
- package/global/hooks/parse_transcript.py +116 -0
- package/global/hooks/post_merge_cleanup.sh +132 -0
- package/global/hooks/post_tool_format.sh +215 -0
- package/global/hooks/ralph_context_monitor.py +240 -0
- package/global/hooks/ralph_stop.sh +502 -0
- package/global/hooks/statusline.sh +1110 -0
- package/global/hooks/statusline_agent_sync.py +224 -0
- package/global/hooks/stop_gate.sh +250 -0
- package/global/lib/.claude/anvil-state.json +21 -0
- package/global/lib/__pycache__/agent_registry.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/claim_service.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/coderabbit_service.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/config_service.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/coordination_service.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/doc_coverage_service.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/gate_logger.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/github_service.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/hygiene_service.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/issue_models.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/issue_provider.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/linear_data_service.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/linear_provider.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/local_provider.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/quality_service.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/ralph_state.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/state_manager.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/transcript_parser.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/verification_runner.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/verify_iteration.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/verify_subagent.cpython-314.pyc +0 -0
- package/global/lib/agent_registry.py +995 -0
- package/global/lib/anvil-state.sh +435 -0
- package/global/lib/claim_service.py +515 -0
- package/global/lib/coderabbit_service.py +314 -0
- package/global/lib/config_service.py +423 -0
- package/global/lib/coordination_service.py +331 -0
- package/global/lib/doc_coverage_service.py +1305 -0
- package/global/lib/gate_logger.py +316 -0
- package/global/lib/github_service.py +310 -0
- package/global/lib/handoff_generator.py +775 -0
- package/global/lib/hygiene_service.py +712 -0
- package/global/lib/issue_models.py +257 -0
- package/global/lib/issue_provider.py +339 -0
- package/global/lib/linear_data_service.py +210 -0
- package/global/lib/linear_provider.py +987 -0
- package/global/lib/linear_provider.py.backup +671 -0
- package/global/lib/local_provider.py +486 -0
- package/global/lib/orient_fast.py +457 -0
- package/global/lib/quality_service.py +470 -0
- package/global/lib/ralph_prompt_generator.py +563 -0
- package/global/lib/ralph_state.py +1202 -0
- package/global/lib/state_manager.py +417 -0
- package/global/lib/transcript_parser.py +597 -0
- package/global/lib/verification_runner.py +557 -0
- package/global/lib/verify_iteration.py +490 -0
- package/global/lib/verify_subagent.py +250 -0
- package/global/skills/README.md +155 -0
- package/global/skills/quality-gates/SKILL.md +252 -0
- package/global/skills/skill-template/SKILL.md +109 -0
- package/global/skills/testing-strategies/SKILL.md +337 -0
- package/global/templates/CHANGE-template.md +105 -0
- package/global/templates/HANDOFF-template.md +63 -0
- package/global/templates/PLAN-template.md +111 -0
- package/global/templates/SPEC-template.md +93 -0
- package/global/templates/ralph/PROMPT.md.template +89 -0
- package/global/templates/ralph/fix_plan.md.template +31 -0
- package/global/templates/ralph/progress.txt.template +23 -0
- package/global/tests/__pycache__/test_doc_coverage.cpython-314.pyc +0 -0
- package/global/tests/test_doc_coverage.py +520 -0
- package/global/tests/test_issue_models.py +299 -0
- package/global/tests/test_local_provider.py +323 -0
- package/global/tools/README.md +178 -0
- package/global/tools/__pycache__/anvil-hud.cpython-314.pyc +0 -0
- package/global/tools/anvil-hud.py +3622 -0
- package/global/tools/anvil-hud.py.bak +3318 -0
- package/global/tools/anvil-issue.py +432 -0
- package/global/tools/anvil-memory/CLAUDE.md +49 -0
- package/global/tools/anvil-memory/README.md +42 -0
- package/global/tools/anvil-memory/bun.lock +25 -0
- package/global/tools/anvil-memory/bunfig.toml +9 -0
- package/global/tools/anvil-memory/package.json +23 -0
- package/global/tools/anvil-memory/src/__tests__/ccs/context-monitor.test.ts +535 -0
- package/global/tools/anvil-memory/src/__tests__/ccs/edge-cases.test.ts +645 -0
- package/global/tools/anvil-memory/src/__tests__/ccs/fixtures.ts +363 -0
- package/global/tools/anvil-memory/src/__tests__/ccs/index.ts +8 -0
- package/global/tools/anvil-memory/src/__tests__/ccs/integration.test.ts +417 -0
- package/global/tools/anvil-memory/src/__tests__/ccs/prompt-generator.test.ts +571 -0
- package/global/tools/anvil-memory/src/__tests__/ccs/ralph-stop.test.ts +440 -0
- package/global/tools/anvil-memory/src/__tests__/ccs/test-utils.ts +252 -0
- package/global/tools/anvil-memory/src/__tests__/commands.test.ts +657 -0
- package/global/tools/anvil-memory/src/__tests__/db.test.ts +641 -0
- package/global/tools/anvil-memory/src/__tests__/hooks.test.ts +272 -0
- package/global/tools/anvil-memory/src/__tests__/performance.test.ts +427 -0
- package/global/tools/anvil-memory/src/__tests__/test-utils.ts +113 -0
- package/global/tools/anvil-memory/src/commands/checkpoint.ts +197 -0
- package/global/tools/anvil-memory/src/commands/get.ts +115 -0
- package/global/tools/anvil-memory/src/commands/init.ts +94 -0
- package/global/tools/anvil-memory/src/commands/observe.ts +163 -0
- package/global/tools/anvil-memory/src/commands/search.ts +112 -0
- package/global/tools/anvil-memory/src/db.ts +638 -0
- package/global/tools/anvil-memory/src/index.ts +205 -0
- package/global/tools/anvil-memory/src/types.ts +122 -0
- package/global/tools/anvil-memory/tsconfig.json +29 -0
- package/global/tools/ralph-loop.sh +359 -0
- package/package.json +45 -0
- package/scripts/anvil +822 -0
- package/scripts/extract_patterns.py +222 -0
- package/scripts/init-project.sh +541 -0
- package/scripts/install.sh +229 -0
- package/scripts/postinstall.js +41 -0
- package/scripts/rollback.sh +188 -0
- package/scripts/sync.sh +623 -0
- package/scripts/test-statusline.sh +248 -0
- package/scripts/update_claude_md.py +224 -0
- package/scripts/verify.sh +255 -0
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
---
|
|
2
|
+
shard_id: SPEC-ANV-VRW/component-02
|
|
3
|
+
parent: SPEC-ANV-VRW
|
|
4
|
+
title: Stop Hook Verification Gate
|
|
5
|
+
status: draft
|
|
6
|
+
linear_issue: ANV-142
|
|
7
|
+
priority: P0
|
|
8
|
+
estimated_hours: 3-4
|
|
9
|
+
dependencies:
|
|
10
|
+
- component-01-verify
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# Component 2: Stop Hook Verification Gate
|
|
14
|
+
|
|
15
|
+
## Overview
|
|
16
|
+
|
|
17
|
+
A stop hook that prevents Claude from exiting when verification fails. This ensures the AI cannot prematurely complete tasks with broken code.
|
|
18
|
+
|
|
19
|
+
> Boris Cherny: "Non-zero exit blocks stopping"
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Requirements
|
|
24
|
+
|
|
25
|
+
| ID | Requirement | Priority | Acceptance Criteria |
|
|
26
|
+
|----|-------------|----------|---------------------|
|
|
27
|
+
| REQ-SH-100 | Run verification checks before allowing exit | P0 | Checks execute on stop attempt |
|
|
28
|
+
| REQ-SH-101 | Return non-zero exit code to block stopping | P0 | Exit code 1 prevents stop |
|
|
29
|
+
| REQ-SH-102 | Provide clear feedback on what's blocking exit | P0 | User sees specific failure |
|
|
30
|
+
| REQ-SH-103 | Allow override with explicit user command | P1 | `/force-exit` bypasses gate |
|
|
31
|
+
| REQ-SH-104 | Configure which checks are mandatory | P1 | Config controls checks |
|
|
32
|
+
| REQ-SH-105 | Log all gate events for debugging | P2 | Events logged with timestamp |
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Behavior Flow
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
User: Attempts to stop session
|
|
40
|
+
|
|
41
|
+
Stop Hook:
|
|
42
|
+
1. Check ANVIL_REQUIRE_VERIFICATION env var
|
|
43
|
+
- If "false" → Allow exit immediately
|
|
44
|
+
|
|
45
|
+
2. Check ANVIL_FORCE_EXIT env var
|
|
46
|
+
- If "true" → Log warning, allow exit
|
|
47
|
+
|
|
48
|
+
3. Run verification checks:
|
|
49
|
+
- npm test
|
|
50
|
+
- npm run lint
|
|
51
|
+
- npm run typecheck
|
|
52
|
+
|
|
53
|
+
4. If ALL pass:
|
|
54
|
+
✅ Verification gate passed
|
|
55
|
+
exit 0 (allow stop)
|
|
56
|
+
|
|
57
|
+
5. If ANY fail:
|
|
58
|
+
❌ Tests failing - cannot exit
|
|
59
|
+
Fix failing tests or use /force-exit to bypass
|
|
60
|
+
exit 1 (block stop)
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## Implementation Tasks
|
|
66
|
+
|
|
67
|
+
### Task 1: Create Stop Gate Hook
|
|
68
|
+
**File**: `global/hooks/stop_gate.sh`
|
|
69
|
+
**Estimated**: 1.5 hours
|
|
70
|
+
|
|
71
|
+
- [ ] Check `ANVIL_REQUIRE_VERIFICATION` env var
|
|
72
|
+
- [ ] Check `ANVIL_FORCE_EXIT` override flag
|
|
73
|
+
- [ ] Run test suite verification
|
|
74
|
+
- [ ] Run lint verification
|
|
75
|
+
- [ ] Run typecheck verification
|
|
76
|
+
- [ ] Return appropriate exit code
|
|
77
|
+
- [ ] Provide clear error messages
|
|
78
|
+
|
|
79
|
+
### Task 2: Create Force Exit Command
|
|
80
|
+
**File**: `global/commands/force-exit.md`
|
|
81
|
+
**Estimated**: 0.5 hours
|
|
82
|
+
|
|
83
|
+
- [ ] Set `ANVIL_FORCE_EXIT=true` env var
|
|
84
|
+
- [ ] Log override with reason
|
|
85
|
+
- [ ] Trigger actual exit
|
|
86
|
+
- [ ] Document usage and warnings
|
|
87
|
+
|
|
88
|
+
### Task 3: Update Settings Registration
|
|
89
|
+
**File**: `.claude/settings.json` (hooks section)
|
|
90
|
+
**Estimated**: 0.5 hours
|
|
91
|
+
|
|
92
|
+
- [ ] Register stop_gate.sh in Stop hooks
|
|
93
|
+
- [ ] Document hook ordering
|
|
94
|
+
- [ ] Test hook registration
|
|
95
|
+
|
|
96
|
+
### Task 4: Add Gate Logging
|
|
97
|
+
**File**: `global/lib/gate_logger.py`
|
|
98
|
+
**Estimated**: 0.5 hours
|
|
99
|
+
|
|
100
|
+
- [ ] Create log file at `.claude/logs/stop_gate.log`
|
|
101
|
+
- [ ] Log each gate event with timestamp
|
|
102
|
+
- [ ] Log pass/fail status and reason
|
|
103
|
+
- [ ] Include verification output summary
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## Hook Implementation
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
#!/bin/bash
|
|
111
|
+
# global/hooks/stop_gate.sh
|
|
112
|
+
# Stop hook that gates on verification
|
|
113
|
+
|
|
114
|
+
set -e
|
|
115
|
+
|
|
116
|
+
# Check if verification is required
|
|
117
|
+
REQUIRE_VERIFY="${ANVIL_REQUIRE_VERIFICATION:-true}"
|
|
118
|
+
|
|
119
|
+
if [[ "$REQUIRE_VERIFY" != "true" ]]; then
|
|
120
|
+
exit 0 # Allow exit
|
|
121
|
+
fi
|
|
122
|
+
|
|
123
|
+
# Check for explicit override
|
|
124
|
+
if [[ "$ANVIL_FORCE_EXIT" == "true" ]]; then
|
|
125
|
+
echo "⚠️ Force exit requested - bypassing verification"
|
|
126
|
+
exit 0
|
|
127
|
+
fi
|
|
128
|
+
|
|
129
|
+
echo "🔒 Running verification gate..."
|
|
130
|
+
|
|
131
|
+
# Run test suite
|
|
132
|
+
if ! npm test --silent 2>/dev/null; then
|
|
133
|
+
echo "❌ Tests failing - cannot exit"
|
|
134
|
+
echo "Fix failing tests or use /force-exit to bypass"
|
|
135
|
+
exit 1 # Block exit
|
|
136
|
+
fi
|
|
137
|
+
|
|
138
|
+
# Run lint
|
|
139
|
+
if ! npm run lint --silent 2>/dev/null; then
|
|
140
|
+
echo "❌ Lint errors - cannot exit"
|
|
141
|
+
echo "Fix lint errors or use /force-exit to bypass"
|
|
142
|
+
exit 1
|
|
143
|
+
fi
|
|
144
|
+
|
|
145
|
+
# Run typecheck
|
|
146
|
+
if ! npm run typecheck --silent 2>/dev/null; then
|
|
147
|
+
echo "❌ Type errors - cannot exit"
|
|
148
|
+
echo "Fix type errors or use /force-exit to bypass"
|
|
149
|
+
exit 1
|
|
150
|
+
fi
|
|
151
|
+
|
|
152
|
+
echo "✅ Verification gate passed"
|
|
153
|
+
exit 0
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## Settings Configuration
|
|
159
|
+
|
|
160
|
+
```json
|
|
161
|
+
{
|
|
162
|
+
"hooks": {
|
|
163
|
+
"Stop": [{
|
|
164
|
+
"type": "command",
|
|
165
|
+
"command": "bash global/hooks/stop_gate.sh"
|
|
166
|
+
}]
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## `/force-exit` Command
|
|
174
|
+
|
|
175
|
+
```markdown
|
|
176
|
+
# /force-exit - Bypass Verification Gate
|
|
177
|
+
|
|
178
|
+
> Force exit even when verification fails.
|
|
179
|
+
|
|
180
|
+
## Usage
|
|
181
|
+
/force-exit "reason for bypassing"
|
|
182
|
+
|
|
183
|
+
## Behavior
|
|
184
|
+
1. Sets ANVIL_FORCE_EXIT=true
|
|
185
|
+
2. Logs bypass with reason
|
|
186
|
+
3. Allows stop hook to pass
|
|
187
|
+
|
|
188
|
+
## Warning
|
|
189
|
+
This bypasses quality gates. Use only when:
|
|
190
|
+
- Known test flakiness
|
|
191
|
+
- Urgent context compaction needed
|
|
192
|
+
- Explicitly instructed by user
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## Test Cases
|
|
198
|
+
|
|
199
|
+
| Test Case | Setup | Expected |
|
|
200
|
+
|-----------|-------|----------|
|
|
201
|
+
| All pass | Clean codebase | Exit allowed |
|
|
202
|
+
| Failing tests | 1 test failure | Exit blocked, message shown |
|
|
203
|
+
| Lint errors | ESLint errors | Exit blocked, message shown |
|
|
204
|
+
| Type errors | TSC errors | Exit blocked, message shown |
|
|
205
|
+
| Force exit | `/force-exit` used | Exit allowed with warning |
|
|
206
|
+
| Verification disabled | `ANVIL_REQUIRE_VERIFICATION=false` | Exit allowed immediately |
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## Error Messages
|
|
211
|
+
|
|
212
|
+
| Condition | Message |
|
|
213
|
+
|-----------|---------|
|
|
214
|
+
| Tests failing | `❌ Tests failing - cannot exit\nFix failing tests or use /force-exit to bypass` |
|
|
215
|
+
| Lint errors | `❌ Lint errors - cannot exit\nFix lint errors or use /force-exit to bypass` |
|
|
216
|
+
| Type errors | `❌ Type errors - cannot exit\nFix type errors or use /force-exit to bypass` |
|
|
217
|
+
| Force bypass | `⚠️ Force exit requested - bypassing verification` |
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## Integration Points
|
|
222
|
+
|
|
223
|
+
- **Trigger**: Claude Code stop event
|
|
224
|
+
- **Input**: Verification results from component-01
|
|
225
|
+
- **Output**: Exit code (0 = allow, 1 = block)
|
|
226
|
+
- **Override**: `/force-exit` command
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
---
|
|
2
|
+
shard_id: SPEC-ANV-VRW/component-03
|
|
3
|
+
parent: SPEC-ANV-VRW
|
|
4
|
+
title: PostToolUse Formatting Hook
|
|
5
|
+
status: draft
|
|
6
|
+
linear_issue: ANV-143
|
|
7
|
+
priority: P0
|
|
8
|
+
estimated_hours: 2-3
|
|
9
|
+
dependencies: none
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Component 3: PostToolUse Formatting Hook
|
|
13
|
+
|
|
14
|
+
## Overview
|
|
15
|
+
|
|
16
|
+
Automatically format code files after every Edit or Write operation. This catches the "last 10%" of formatting issues that Claude often misses.
|
|
17
|
+
|
|
18
|
+
> Boris Cherny: "PostToolUse hooks for formatting"
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Requirements
|
|
23
|
+
|
|
24
|
+
| ID | Requirement | Priority | Acceptance Criteria |
|
|
25
|
+
|----|-------------|----------|---------------------|
|
|
26
|
+
| REQ-PTU-100 | Run formatter on files after Edit tool | P0 | Formatter executes on Edit |
|
|
27
|
+
| REQ-PTU-101 | Run formatter on files after Write tool | P0 | Formatter executes on Write |
|
|
28
|
+
| REQ-PTU-102 | Support project-specific formatter (prettier, black, etc.) | P0 | Config selects formatter |
|
|
29
|
+
| REQ-PTU-103 | Execute in <500ms to avoid slowdown | P1 | Timed execution |
|
|
30
|
+
| REQ-PTU-104 | Skip binary files and node_modules | P1 | Path filtering works |
|
|
31
|
+
| REQ-PTU-105 | Log formatting changes for visibility | P2 | Changes logged |
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Supported Formatters
|
|
36
|
+
|
|
37
|
+
| File Type | Primary Formatter | Fallback |
|
|
38
|
+
|-----------|------------------|----------|
|
|
39
|
+
| `.ts`, `.tsx`, `.js`, `.jsx` | prettier | eslint --fix |
|
|
40
|
+
| `.json`, `.md`, `.css`, `.html` | prettier | - |
|
|
41
|
+
| `.py` | black | ruff format |
|
|
42
|
+
| `.go` | gofmt | - |
|
|
43
|
+
| `.sh` | shfmt | - |
|
|
44
|
+
| `.rs` | rustfmt | - |
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Implementation Tasks
|
|
49
|
+
|
|
50
|
+
### Task 1: Create PostToolUse Hook
|
|
51
|
+
**File**: `global/hooks/post_tool_format.sh`
|
|
52
|
+
**Estimated**: 1 hour
|
|
53
|
+
|
|
54
|
+
- [ ] Extract `CLAUDE_FILE_PATH` from environment
|
|
55
|
+
- [ ] Skip if no file path provided
|
|
56
|
+
- [ ] Skip non-existent files
|
|
57
|
+
- [ ] Skip binary and excluded paths
|
|
58
|
+
- [ ] Detect file type from extension
|
|
59
|
+
- [ ] Run appropriate formatter
|
|
60
|
+
- [ ] Handle formatter not installed gracefully
|
|
61
|
+
|
|
62
|
+
### Task 2: Configure Formatter Detection
|
|
63
|
+
**Estimated**: 0.5 hours
|
|
64
|
+
|
|
65
|
+
- [ ] TypeScript/JavaScript: npx prettier
|
|
66
|
+
- [ ] Python: black or ruff
|
|
67
|
+
- [ ] Go: gofmt
|
|
68
|
+
- [ ] Bash: shfmt
|
|
69
|
+
- [ ] Add fallback for missing formatters
|
|
70
|
+
|
|
71
|
+
### Task 3: Performance Optimization
|
|
72
|
+
**Estimated**: 0.5 hours
|
|
73
|
+
|
|
74
|
+
- [ ] Measure execution time
|
|
75
|
+
- [ ] Skip if formatter not installed
|
|
76
|
+
- [ ] Use `--silent` flags
|
|
77
|
+
- [ ] Add timeout protection
|
|
78
|
+
|
|
79
|
+
### Task 4: Register Hook
|
|
80
|
+
**File**: `.claude/settings.json`
|
|
81
|
+
**Estimated**: 0.5 hours
|
|
82
|
+
|
|
83
|
+
- [ ] Add PostToolUse hook entry
|
|
84
|
+
- [ ] Configure matcher for "Edit|Write"
|
|
85
|
+
- [ ] Test with both Edit and Write operations
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Hook Implementation
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
#!/bin/bash
|
|
93
|
+
# global/hooks/post_tool_format.sh
|
|
94
|
+
# PostToolUse hook for auto-formatting
|
|
95
|
+
|
|
96
|
+
FILE_PATH="$CLAUDE_FILE_PATH"
|
|
97
|
+
|
|
98
|
+
# Skip if no file path
|
|
99
|
+
if [[ -z "$FILE_PATH" ]]; then
|
|
100
|
+
exit 0
|
|
101
|
+
fi
|
|
102
|
+
|
|
103
|
+
# Skip non-existent files
|
|
104
|
+
if [[ ! -f "$FILE_PATH" ]]; then
|
|
105
|
+
exit 0
|
|
106
|
+
fi
|
|
107
|
+
|
|
108
|
+
# Skip binary and excluded paths
|
|
109
|
+
case "$FILE_PATH" in
|
|
110
|
+
*/node_modules/*|*/.git/*|*.png|*.jpg|*.ico|*.woff*|*.ttf|*.eot)
|
|
111
|
+
exit 0
|
|
112
|
+
;;
|
|
113
|
+
esac
|
|
114
|
+
|
|
115
|
+
# Determine formatter based on file type
|
|
116
|
+
case "$FILE_PATH" in
|
|
117
|
+
*.ts|*.tsx|*.js|*.jsx|*.json|*.md|*.css|*.html)
|
|
118
|
+
if command -v npx &> /dev/null; then
|
|
119
|
+
npx prettier --write "$FILE_PATH" 2>/dev/null || true
|
|
120
|
+
fi
|
|
121
|
+
;;
|
|
122
|
+
*.py)
|
|
123
|
+
if command -v black &> /dev/null; then
|
|
124
|
+
black --quiet "$FILE_PATH" 2>/dev/null || true
|
|
125
|
+
elif command -v ruff &> /dev/null; then
|
|
126
|
+
ruff format --quiet "$FILE_PATH" 2>/dev/null || true
|
|
127
|
+
fi
|
|
128
|
+
;;
|
|
129
|
+
*.go)
|
|
130
|
+
if command -v gofmt &> /dev/null; then
|
|
131
|
+
gofmt -w "$FILE_PATH" 2>/dev/null || true
|
|
132
|
+
fi
|
|
133
|
+
;;
|
|
134
|
+
*.sh)
|
|
135
|
+
if command -v shfmt &> /dev/null; then
|
|
136
|
+
shfmt -w "$FILE_PATH" 2>/dev/null || true
|
|
137
|
+
fi
|
|
138
|
+
;;
|
|
139
|
+
*.rs)
|
|
140
|
+
if command -v rustfmt &> /dev/null; then
|
|
141
|
+
rustfmt "$FILE_PATH" 2>/dev/null || true
|
|
142
|
+
fi
|
|
143
|
+
;;
|
|
144
|
+
esac
|
|
145
|
+
|
|
146
|
+
exit 0
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## Settings Configuration
|
|
152
|
+
|
|
153
|
+
```json
|
|
154
|
+
{
|
|
155
|
+
"hooks": {
|
|
156
|
+
"PostToolUse": [{
|
|
157
|
+
"matcher": "Edit|Write",
|
|
158
|
+
"hooks": [{
|
|
159
|
+
"type": "command",
|
|
160
|
+
"command": "bash global/hooks/post_tool_format.sh"
|
|
161
|
+
}]
|
|
162
|
+
}]
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## Test Cases
|
|
170
|
+
|
|
171
|
+
| Test Case | Input | Expected |
|
|
172
|
+
|-----------|-------|----------|
|
|
173
|
+
| Edit TS file | Unformatted TypeScript | File formatted with prettier |
|
|
174
|
+
| Write new Python | New .py file | File formatted with black |
|
|
175
|
+
| Edit binary | .png file | Skipped (no formatting) |
|
|
176
|
+
| Edit node_modules | node_modules/*.js | Skipped (excluded path) |
|
|
177
|
+
| Missing formatter | No prettier installed | Graceful skip, no error |
|
|
178
|
+
| Large file | 10k line file | Completes in <500ms |
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## Performance Considerations
|
|
183
|
+
|
|
184
|
+
| Concern | Solution |
|
|
185
|
+
|---------|----------|
|
|
186
|
+
| Slow formatting | Use `--quiet` flags |
|
|
187
|
+
| Timeout | Add 500ms timeout wrapper |
|
|
188
|
+
| Missing formatter | Check `command -v` first |
|
|
189
|
+
| Network calls | Use local formatters only |
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## Excluded Paths
|
|
194
|
+
|
|
195
|
+
Files in these paths are never formatted:
|
|
196
|
+
- `node_modules/`
|
|
197
|
+
- `.git/`
|
|
198
|
+
- `dist/`, `build/`, `out/`
|
|
199
|
+
- Binary files (images, fonts)
|
|
200
|
+
- Lock files (`package-lock.json`, `yarn.lock`)
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## Integration Points
|
|
205
|
+
|
|
206
|
+
- **Trigger**: Edit or Write tool completion
|
|
207
|
+
- **Input**: `CLAUDE_FILE_PATH` environment variable
|
|
208
|
+
- **Output**: Formatted file (in-place)
|
|
209
|
+
- **Independent**: No dependencies on other components
|