specweave 0.23.10 → 0.23.12
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/.claude-plugin/marketplace.json +7 -7
- package/CLAUDE.md +384 -1449
- package/dist/src/cli/commands/cleanup-cache.d.ts +14 -0
- package/dist/src/cli/commands/cleanup-cache.d.ts.map +1 -0
- package/dist/src/cli/commands/cleanup-cache.js +63 -0
- package/dist/src/cli/commands/cleanup-cache.js.map +1 -0
- package/dist/src/cli/commands/init.js +40 -0
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/cli/helpers/async-project-loader.d.ts +148 -0
- package/dist/src/cli/helpers/async-project-loader.d.ts.map +1 -0
- package/dist/src/cli/helpers/async-project-loader.js +351 -0
- package/dist/src/cli/helpers/async-project-loader.js.map +1 -0
- package/dist/src/cli/helpers/cancelation-handler.d.ts +123 -0
- package/dist/src/cli/helpers/cancelation-handler.d.ts.map +1 -0
- package/dist/src/cli/helpers/cancelation-handler.js +187 -0
- package/dist/src/cli/helpers/cancelation-handler.js.map +1 -0
- package/dist/src/cli/helpers/import-strategy-prompter.d.ts +43 -0
- package/dist/src/cli/helpers/import-strategy-prompter.d.ts.map +1 -0
- package/dist/src/cli/helpers/import-strategy-prompter.js +136 -0
- package/dist/src/cli/helpers/import-strategy-prompter.js.map +1 -0
- package/dist/src/cli/helpers/issue-tracker/ado.d.ts +5 -2
- package/dist/src/cli/helpers/issue-tracker/ado.d.ts.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/ado.js +90 -40
- package/dist/src/cli/helpers/issue-tracker/ado.js.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/jira.d.ts +2 -1
- package/dist/src/cli/helpers/issue-tracker/jira.d.ts.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/jira.js +120 -35
- package/dist/src/cli/helpers/issue-tracker/jira.js.map +1 -1
- package/dist/src/cli/helpers/progress-tracker.d.ts +121 -0
- package/dist/src/cli/helpers/progress-tracker.d.ts.map +1 -0
- package/dist/src/cli/helpers/progress-tracker.js +202 -0
- package/dist/src/cli/helpers/progress-tracker.js.map +1 -0
- package/dist/src/cli/helpers/project-count-fetcher.d.ts +69 -0
- package/dist/src/cli/helpers/project-count-fetcher.d.ts.map +1 -0
- package/dist/src/cli/helpers/project-count-fetcher.js +173 -0
- package/dist/src/cli/helpers/project-count-fetcher.js.map +1 -0
- package/dist/src/config/types.d.ts +14 -14
- package/dist/src/core/cache/cache-manager.d.ts +119 -0
- package/dist/src/core/cache/cache-manager.d.ts.map +1 -0
- package/dist/src/core/cache/cache-manager.js +304 -0
- package/dist/src/core/cache/cache-manager.js.map +1 -0
- package/dist/src/core/cache/rate-limit-checker.d.ts +92 -0
- package/dist/src/core/cache/rate-limit-checker.d.ts.map +1 -0
- package/dist/src/core/cache/rate-limit-checker.js +160 -0
- package/dist/src/core/cache/rate-limit-checker.js.map +1 -0
- package/dist/src/core/progress/cancelation-handler.d.ts +79 -0
- package/dist/src/core/progress/cancelation-handler.d.ts.map +1 -0
- package/dist/src/core/progress/cancelation-handler.js +111 -0
- package/dist/src/core/progress/cancelation-handler.js.map +1 -0
- package/dist/src/core/progress/import-state.d.ts +71 -0
- package/dist/src/core/progress/import-state.d.ts.map +1 -0
- package/dist/src/core/progress/import-state.js +96 -0
- package/dist/src/core/progress/import-state.js.map +1 -0
- package/dist/src/core/progress/progress-tracker.d.ts +139 -0
- package/dist/src/core/progress/progress-tracker.d.ts.map +1 -0
- package/dist/src/core/progress/progress-tracker.js +223 -0
- package/dist/src/core/progress/progress-tracker.js.map +1 -0
- package/dist/src/init/architecture/types.d.ts +6 -6
- package/dist/src/integrations/ado/ado-client.d.ts +25 -0
- package/dist/src/integrations/ado/ado-client.d.ts.map +1 -1
- package/dist/src/integrations/ado/ado-client.js +67 -0
- package/dist/src/integrations/ado/ado-client.js.map +1 -1
- package/dist/src/integrations/ado/ado-dependency-loader.d.ts +99 -0
- package/dist/src/integrations/ado/ado-dependency-loader.d.ts.map +1 -0
- package/dist/src/integrations/ado/ado-dependency-loader.js +207 -0
- package/dist/src/integrations/ado/ado-dependency-loader.js.map +1 -0
- package/dist/src/integrations/jira/jira-client.d.ts +32 -0
- package/dist/src/integrations/jira/jira-client.d.ts.map +1 -1
- package/dist/src/integrations/jira/jira-client.js +81 -0
- package/dist/src/integrations/jira/jira-client.js.map +1 -1
- package/dist/src/integrations/jira/jira-dependency-loader.d.ts +101 -0
- package/dist/src/integrations/jira/jira-dependency-loader.d.ts.map +1 -0
- package/dist/src/integrations/jira/jira-dependency-loader.js +200 -0
- package/dist/src/integrations/jira/jira-dependency-loader.js.map +1 -0
- package/package.json +1 -1
- package/plugins/specweave/.claude-plugin/plugin.json +20 -0
- package/plugins/specweave/agents/architect/AGENT.md +100 -602
- package/plugins/specweave/agents/pm/AGENT.md +96 -597
- package/plugins/specweave/agents/pm/AGENT.md.bak +1893 -0
- package/plugins/specweave/agents/pm/AGENT.md.bak2 +1754 -0
- package/plugins/specweave/commands/check-hooks.md +257 -0
- package/plugins/specweave/hooks/post-edit-spec.sh +202 -31
- package/plugins/specweave/hooks/post-task-completion.sh +225 -228
- package/plugins/specweave/hooks/post-write-spec.sh +207 -31
- package/plugins/specweave/hooks/pre-edit-spec.sh +151 -0
- package/plugins/specweave/hooks/pre-task-completion.sh +5 -7
- package/plugins/specweave/hooks/pre-write-spec.sh +151 -0
- package/plugins/specweave/hooks/test-pretooluse-env.sh +72 -0
- package/plugins/specweave/skills/compliance-architecture/SKILL.md +374 -0
- package/plugins/specweave/skills/external-sync-wizard/SKILL.md +610 -0
- package/plugins/specweave/skills/pm-closure-validation/SKILL.md +541 -0
- package/plugins/specweave/skills/roadmap-planner/SKILL.md +473 -0
- package/plugins/specweave-ado/commands/refresh-cache.js +25 -0
- package/plugins/specweave-ado/commands/refresh-cache.ts +40 -0
- package/plugins/specweave-ado/hooks/post-task-completion.sh +1 -1
- package/plugins/specweave-github/hooks/post-task-completion.sh +1 -1
- package/plugins/specweave-jira/commands/refresh-cache.js +25 -0
- package/plugins/specweave-jira/commands/refresh-cache.ts +40 -0
- package/plugins/specweave-jira/hooks/post-task-completion.sh +1 -1
- package/plugins/specweave-kafka-streams/commands/topology.md +437 -0
- package/plugins/specweave-n8n/commands/workflow-template.md +262 -0
- package/plugins/specweave-release/hooks/.specweave/logs/dora-tracking.log +228 -6465
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Validate hook health and display performance metrics (Tier 2 monitoring)
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# /specweave:check-hooks - Hook Health Dashboard
|
|
6
|
+
|
|
7
|
+
**Purpose:** Display comprehensive hook performance metrics, detection rates, and health status.
|
|
8
|
+
|
|
9
|
+
**Tier 2 Feature:** This command validates the PreToolUse coordination layer is working correctly.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Instructions for Claude
|
|
14
|
+
|
|
15
|
+
When this command is executed, perform the following analysis:
|
|
16
|
+
|
|
17
|
+
### 1. **Read Hook Metrics File**
|
|
18
|
+
|
|
19
|
+
Location: `.specweave/state/hook-metrics.jsonl`
|
|
20
|
+
|
|
21
|
+
The metrics file contains JSONL (JSON Lines) format - one JSON object per line.
|
|
22
|
+
|
|
23
|
+
Each entry has:
|
|
24
|
+
```json
|
|
25
|
+
{
|
|
26
|
+
"timestamp": "2025-11-22T01:30:00Z",
|
|
27
|
+
"hook": "pre-edit-spec|post-edit-spec|pre-write-spec|post-write-spec",
|
|
28
|
+
"event": "file_detected|tier2_success|tier1_fallback",
|
|
29
|
+
"file_path": "/path/to/file.md",
|
|
30
|
+
"method": "pretooluse|env_content|env_result|env_args|mtime"
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### 2. **Calculate Key Metrics**
|
|
35
|
+
|
|
36
|
+
**Tier 2 Success Rate:**
|
|
37
|
+
```
|
|
38
|
+
Tier 2 Rate = (tier2_success events) / (total post-tool events) * 100%
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**Target:** >95% (Tier 2 should handle most cases)
|
|
42
|
+
|
|
43
|
+
**Detection Method Breakdown:**
|
|
44
|
+
- `pretooluse`: Tier 2 PreToolUse coordination (best)
|
|
45
|
+
- `env_content`: Environment variable (TOOL_USE_CONTENT)
|
|
46
|
+
- `env_result`: Environment variable (TOOL_RESULT)
|
|
47
|
+
- `env_args`: Environment variable (TOOL_USE_ARGS)
|
|
48
|
+
- `mtime`: File modification time fallback (Tier 1)
|
|
49
|
+
|
|
50
|
+
**Fallback Rate:**
|
|
51
|
+
```
|
|
52
|
+
Fallback Rate = (mtime detections) / (total detections) * 100%
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
**Target:** <5% (should rarely need mtime fallback)
|
|
56
|
+
|
|
57
|
+
### 3. **Check Hook Health Status**
|
|
58
|
+
|
|
59
|
+
**Circuit Breaker Status:**
|
|
60
|
+
- File: `.specweave/state/.hook-circuit-breaker`
|
|
61
|
+
- If exists: Read failure count
|
|
62
|
+
- If count ≥ 3: ⚠️ CIRCUIT BREAKER OPEN (hooks disabled)
|
|
63
|
+
- If count < 3: ✅ Circuit breaker OK
|
|
64
|
+
- If doesn't exist: ✅ No failures detected
|
|
65
|
+
|
|
66
|
+
**Kill Switch Status:**
|
|
67
|
+
- Check environment variable: `SPECWEAVE_DISABLE_HOOKS`
|
|
68
|
+
- If set to "1": ⚠️ HOOKS MANUALLY DISABLED
|
|
69
|
+
- If not set or "0": ✅ Hooks enabled
|
|
70
|
+
|
|
71
|
+
**Lock Files Status:**
|
|
72
|
+
- Check for stale locks:
|
|
73
|
+
- `.specweave/state/.hook-post-edit.lock`
|
|
74
|
+
- `.specweave/state/.hook-post-write.lock`
|
|
75
|
+
- If older than 10 seconds: ⚠️ Stale lock detected
|
|
76
|
+
- If not present: ✅ No locks
|
|
77
|
+
|
|
78
|
+
### 4. **Read Recent Hook Logs**
|
|
79
|
+
|
|
80
|
+
Location: `.specweave/logs/hooks-debug.log`
|
|
81
|
+
|
|
82
|
+
**Look for:**
|
|
83
|
+
- Recent errors or warnings
|
|
84
|
+
- Debounce effectiveness (count "Debounced" messages)
|
|
85
|
+
- PreToolUse signal messages
|
|
86
|
+
- Circuit breaker trips
|
|
87
|
+
|
|
88
|
+
**Time window:** Last 100 lines or last 1 hour
|
|
89
|
+
|
|
90
|
+
### 5. **Output Format**
|
|
91
|
+
|
|
92
|
+
Display results in this format:
|
|
93
|
+
|
|
94
|
+
```
|
|
95
|
+
🔍 SpecWeave Hook Health Dashboard (Tier 2)
|
|
96
|
+
═══════════════════════════════════════════════════════════
|
|
97
|
+
|
|
98
|
+
📊 DETECTION METRICS (Last 24 hours)
|
|
99
|
+
────────────────────────────────────
|
|
100
|
+
Total Hook Executions: 156
|
|
101
|
+
Tier 2 Success (PreToolUse): 149 (95.5%) ✅
|
|
102
|
+
Tier 1 Fallback (env vars): 5 (3.2%)
|
|
103
|
+
Tier 1 Fallback (mtime): 2 (1.3%)
|
|
104
|
+
|
|
105
|
+
Detection Method Breakdown:
|
|
106
|
+
• pretooluse: 149 (95.5%) ✅ Target: >95%
|
|
107
|
+
• env_content: 3 (1.9%)
|
|
108
|
+
• env_args: 2 (1.3%)
|
|
109
|
+
• mtime: 2 (1.3%) ✅ Target: <5%
|
|
110
|
+
|
|
111
|
+
🏥 HEALTH STATUS
|
|
112
|
+
────────────────────────────────────
|
|
113
|
+
Circuit Breaker: ✅ OK (0 failures)
|
|
114
|
+
Kill Switch: ✅ Hooks enabled
|
|
115
|
+
Stale Locks: ✅ None detected
|
|
116
|
+
Debounce Efficiency: 87% (136/156 skipped)
|
|
117
|
+
|
|
118
|
+
⚡ PERFORMANCE
|
|
119
|
+
────────────────────────────────────
|
|
120
|
+
Average Hook Latency: ~3ms
|
|
121
|
+
Debounce Window: 5 seconds
|
|
122
|
+
Background Updates: Active
|
|
123
|
+
Metrics Collection: Active
|
|
124
|
+
|
|
125
|
+
📝 RECENT ACTIVITY (Last 10 events)
|
|
126
|
+
────────────────────────────────────
|
|
127
|
+
[2025-11-22 01:30:15] post-edit-spec: File from PreToolUse signal: /path/to/spec.md
|
|
128
|
+
[2025-11-22 01:30:10] pre-edit-spec: Signaled PostToolUse for: /path/to/spec.md
|
|
129
|
+
[2025-11-22 01:29:45] post-edit-spec: Debounced (2s since last update)
|
|
130
|
+
...
|
|
131
|
+
|
|
132
|
+
✅ SUMMARY
|
|
133
|
+
────────────────────────────────────
|
|
134
|
+
Status: HEALTHY ✅
|
|
135
|
+
|
|
136
|
+
Tier 2 coordination is working correctly (95.5% success rate).
|
|
137
|
+
Fallback rate is within acceptable range (<5%).
|
|
138
|
+
No health issues detected.
|
|
139
|
+
|
|
140
|
+
Recommendations:
|
|
141
|
+
• None - system performing optimally
|
|
142
|
+
|
|
143
|
+
To disable hooks temporarily:
|
|
144
|
+
export SPECWEAVE_DISABLE_HOOKS=1
|
|
145
|
+
|
|
146
|
+
To reset circuit breaker:
|
|
147
|
+
rm .specweave/state/.hook-circuit-breaker
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### 6. **Health Assessment Logic**
|
|
151
|
+
|
|
152
|
+
**Determine overall status:**
|
|
153
|
+
|
|
154
|
+
- ✅ **HEALTHY** if:
|
|
155
|
+
- Tier 2 success rate >90%
|
|
156
|
+
- Fallback rate <10%
|
|
157
|
+
- No circuit breaker trips
|
|
158
|
+
- Hooks enabled
|
|
159
|
+
|
|
160
|
+
- ⚠️ **WARNING** if:
|
|
161
|
+
- Tier 2 success rate 70-90%
|
|
162
|
+
- Fallback rate 10-30%
|
|
163
|
+
- Circuit breaker count 1-2
|
|
164
|
+
|
|
165
|
+
- ❌ **CRITICAL** if:
|
|
166
|
+
- Tier 2 success rate <70%
|
|
167
|
+
- Fallback rate >30%
|
|
168
|
+
- Circuit breaker open (count ≥ 3)
|
|
169
|
+
- Hooks manually disabled
|
|
170
|
+
|
|
171
|
+
### 7. **Troubleshooting Recommendations**
|
|
172
|
+
|
|
173
|
+
Based on status, provide targeted recommendations:
|
|
174
|
+
|
|
175
|
+
**If Tier 2 success rate <95%:**
|
|
176
|
+
```
|
|
177
|
+
⚠️ PreToolUse coordination not working optimally
|
|
178
|
+
|
|
179
|
+
Recommendations:
|
|
180
|
+
1. Check if PreToolUse hooks are registered in plugin.json
|
|
181
|
+
2. Verify hook files are executable (chmod +x)
|
|
182
|
+
3. Review .specweave/logs/hooks-debug.log for PreToolUse errors
|
|
183
|
+
4. Consider filing bug with Anthropic (environment variable passing)
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
**If fallback rate >10%:**
|
|
187
|
+
```
|
|
188
|
+
⚠️ High fallback rate detected
|
|
189
|
+
|
|
190
|
+
Recommendations:
|
|
191
|
+
1. Tier 2 coordination may not be working
|
|
192
|
+
2. Environment variables still not being passed
|
|
193
|
+
3. Consider Tier 3 implementation (filesystem watcher)
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
**If circuit breaker open:**
|
|
197
|
+
```
|
|
198
|
+
❌ Hooks disabled due to consecutive failures
|
|
199
|
+
|
|
200
|
+
Immediate actions:
|
|
201
|
+
1. Review .specweave/logs/hooks-debug.log for errors
|
|
202
|
+
2. Fix underlying issues
|
|
203
|
+
3. Reset circuit breaker: rm .specweave/state/.hook-circuit-breaker
|
|
204
|
+
4. Restart Claude Code
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### 8. **Error Handling**
|
|
208
|
+
|
|
209
|
+
If metrics file doesn't exist:
|
|
210
|
+
```
|
|
211
|
+
⚠️ No metrics data available
|
|
212
|
+
|
|
213
|
+
This is normal for:
|
|
214
|
+
• New SpecWeave installation
|
|
215
|
+
• First run after Tier 2 upgrade
|
|
216
|
+
|
|
217
|
+
Metrics will be collected automatically as you work.
|
|
218
|
+
Run this command again after a few Edit/Write operations.
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
If logs not accessible:
|
|
222
|
+
```
|
|
223
|
+
⚠️ Could not read hook logs
|
|
224
|
+
|
|
225
|
+
Check file permissions:
|
|
226
|
+
.specweave/logs/hooks-debug.log
|
|
227
|
+
.specweave/state/hook-metrics.jsonl
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
## Implementation Notes
|
|
233
|
+
|
|
234
|
+
**For Claude:**
|
|
235
|
+
1. Parse JSONL file line by line (each line is a JSON object)
|
|
236
|
+
2. Calculate metrics using simple counting
|
|
237
|
+
3. Display results using the template above
|
|
238
|
+
4. Adjust recommendations based on actual metrics
|
|
239
|
+
5. Keep output concise but informative
|
|
240
|
+
|
|
241
|
+
**Time-based filtering:**
|
|
242
|
+
- Default: Last 24 hours
|
|
243
|
+
- Option: All time (if user requests)
|
|
244
|
+
- Filter by comparing timestamp field
|
|
245
|
+
|
|
246
|
+
**Edge cases:**
|
|
247
|
+
- Empty metrics file → Show "waiting for data" message
|
|
248
|
+
- Corrupted JSONL → Skip invalid lines, report count
|
|
249
|
+
- Missing state directory → Create it, show initialization message
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
## Related Documentation
|
|
254
|
+
|
|
255
|
+
- ADR-0060: Hook Performance Optimization
|
|
256
|
+
- `.specweave/increments/0050-*/reports/hook-crash-analysis.md`
|
|
257
|
+
- CLAUDE.md: "Hook Performance Best Practices"
|
|
@@ -8,12 +8,30 @@
|
|
|
8
8
|
# This ensures status line stays in sync when ACs are marked complete via Edit tool
|
|
9
9
|
# (not just TodoWrite, which only tracks internal todo lists)
|
|
10
10
|
#
|
|
11
|
-
#
|
|
11
|
+
# EMERGENCY FIXES (v0.24.3):
|
|
12
|
+
# - Kill switch: Set SPECWEAVE_DISABLE_HOOKS=1 to disable ALL hooks
|
|
13
|
+
# - Circuit breaker: Auto-disable after 3 consecutive failures
|
|
14
|
+
# - File locking: Prevent concurrent executions (max 1 at a time)
|
|
15
|
+
# - Aggressive debouncing: Increased from 1s to 5s
|
|
16
|
+
# - Complete error isolation: Never let errors reach Claude Code
|
|
17
|
+
#
|
|
18
|
+
# TIER 1 IMPROVEMENTS (v0.24.2):
|
|
19
|
+
# - Debouncing: Skip if updated less than 1 second ago (90% overhead reduction)
|
|
20
|
+
# - File mtime detection: Check recently modified spec.md/tasks.md as fallback
|
|
21
|
+
# - Non-blocking: Run update-status-line.sh in background
|
|
22
|
+
# - Smart detection: Only update if spec/tasks files actually changed
|
|
23
|
+
#
|
|
24
|
+
# Previous fix (v0.24.1): Enhanced file detection for increment completion
|
|
12
25
|
# - Detects edits via TOOL_USE_CONTENT, TOOL_RESULT, and argument parsing
|
|
13
26
|
# - Always updates status line for ANY spec.md/tasks.md edit in increments folder
|
|
14
|
-
# - Fixes bug where status line wasn't updating on increment close
|
|
15
27
|
|
|
16
|
-
set -e
|
|
28
|
+
# CRITICAL: Remove set -e to prevent hook errors from crashing Claude Code
|
|
29
|
+
set +e
|
|
30
|
+
|
|
31
|
+
# EMERGENCY KILL SWITCH: Disable all hooks if env variable set
|
|
32
|
+
if [[ "${SPECWEAVE_DISABLE_HOOKS:-0}" == "1" ]]; then
|
|
33
|
+
exit 0
|
|
34
|
+
fi
|
|
17
35
|
|
|
18
36
|
# Find project root
|
|
19
37
|
find_project_root() {
|
|
@@ -32,31 +50,129 @@ PROJECT_ROOT=$(find_project_root)
|
|
|
32
50
|
LOGS_DIR="$PROJECT_ROOT/.specweave/logs"
|
|
33
51
|
DEBUG_LOG="$LOGS_DIR/hooks-debug.log"
|
|
34
52
|
|
|
35
|
-
# Ensure logs
|
|
36
|
-
mkdir -p "$LOGS_DIR" 2>/dev/null || true
|
|
53
|
+
# Ensure state and logs directories exist
|
|
54
|
+
mkdir -p "$PROJECT_ROOT/.specweave/state" "$LOGS_DIR" 2>/dev/null || true
|
|
37
55
|
|
|
38
|
-
#
|
|
39
|
-
|
|
56
|
+
# EMERGENCY CIRCUIT BREAKER: Track consecutive failures
|
|
57
|
+
CIRCUIT_BREAKER_FILE="$PROJECT_ROOT/.specweave/state/.hook-circuit-breaker"
|
|
58
|
+
CIRCUIT_BREAKER_THRESHOLD=3
|
|
40
59
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
60
|
+
if [[ -f "$CIRCUIT_BREAKER_FILE" ]]; then
|
|
61
|
+
FAILURE_COUNT=$(cat "$CIRCUIT_BREAKER_FILE" 2>/dev/null || echo 0)
|
|
62
|
+
if (( FAILURE_COUNT >= CIRCUIT_BREAKER_THRESHOLD )); then
|
|
63
|
+
echo "[$(date)] CIRCUIT BREAKER OPEN: Hooks disabled after $FAILURE_COUNT failures. Run: rm $CIRCUIT_BREAKER_FILE" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
64
|
+
exit 0
|
|
65
|
+
fi
|
|
44
66
|
fi
|
|
45
67
|
|
|
46
|
-
#
|
|
47
|
-
|
|
48
|
-
#
|
|
49
|
-
|
|
68
|
+
# EMERGENCY FILE LOCK: Prevent concurrent executions
|
|
69
|
+
LOCK_FILE="$PROJECT_ROOT/.specweave/state/.hook-post-edit.lock"
|
|
70
|
+
LOCK_TIMEOUT=5 # seconds
|
|
71
|
+
|
|
72
|
+
# Try to acquire lock with timeout
|
|
73
|
+
LOCK_ACQUIRED=false
|
|
74
|
+
for i in {1..5}; do
|
|
75
|
+
if mkdir "$LOCK_FILE" 2>/dev/null; then
|
|
76
|
+
LOCK_ACQUIRED=true
|
|
77
|
+
trap 'rmdir "$LOCK_FILE" 2>/dev/null || true' EXIT
|
|
78
|
+
break
|
|
79
|
+
fi
|
|
80
|
+
|
|
81
|
+
# Check if lock is stale (older than LOCK_TIMEOUT seconds)
|
|
82
|
+
if [[ -d "$LOCK_FILE" ]]; then
|
|
83
|
+
LOCK_AGE=$(($(date +%s) - $(stat -f "%m" "$LOCK_FILE" 2>/dev/null || echo 0)))
|
|
84
|
+
if (( LOCK_AGE > LOCK_TIMEOUT )); then
|
|
85
|
+
rmdir "$LOCK_FILE" 2>/dev/null || true
|
|
86
|
+
continue
|
|
87
|
+
fi
|
|
88
|
+
fi
|
|
89
|
+
|
|
90
|
+
sleep 0.2
|
|
91
|
+
done
|
|
92
|
+
|
|
93
|
+
if [[ "$LOCK_ACQUIRED" == "false" ]]; then
|
|
94
|
+
echo "[$(date)] post-edit-spec: Could not acquire lock, skipping" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
95
|
+
exit 0
|
|
50
96
|
fi
|
|
51
97
|
|
|
52
|
-
#
|
|
53
|
-
if [[ -
|
|
54
|
-
|
|
55
|
-
|
|
98
|
+
# Log rotation: Keep debug log under 100KB
|
|
99
|
+
if [[ -f "$DEBUG_LOG" ]] && [[ $(wc -c < "$DEBUG_LOG" 2>/dev/null || echo 0) -gt 102400 ]]; then
|
|
100
|
+
tail -100 "$DEBUG_LOG" > "$DEBUG_LOG.tmp" 2>/dev/null || true
|
|
101
|
+
mv "$DEBUG_LOG.tmp" "$DEBUG_LOG" 2>/dev/null || true
|
|
102
|
+
echo "[$(date)] Log rotated" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
56
103
|
fi
|
|
57
104
|
|
|
58
|
-
#
|
|
59
|
-
|
|
105
|
+
# ============================================================================
|
|
106
|
+
# TIER 1 FIX: Debouncing (Prevent Redundant Updates)
|
|
107
|
+
# ============================================================================
|
|
108
|
+
# Skip update if we updated less than 5 seconds ago (INCREASED FROM 1s)
|
|
109
|
+
# This handles rapid consecutive edits (e.g., 10 tasks marked complete quickly)
|
|
110
|
+
LAST_UPDATE_FILE="$PROJECT_ROOT/.specweave/state/.last-status-update"
|
|
111
|
+
DEBOUNCE_SECONDS=5
|
|
112
|
+
|
|
113
|
+
if [[ -f "$LAST_UPDATE_FILE" ]]; then
|
|
114
|
+
LAST_UPDATE=$(cat "$LAST_UPDATE_FILE" 2>/dev/null || echo 0)
|
|
115
|
+
NOW=$(date +%s)
|
|
116
|
+
TIME_SINCE_UPDATE=$((NOW - LAST_UPDATE))
|
|
117
|
+
|
|
118
|
+
if (( TIME_SINCE_UPDATE < DEBOUNCE_SECONDS )); then
|
|
119
|
+
echo "[$(date)] post-edit-spec: Debounced (${TIME_SINCE_UPDATE}s since last update)" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
120
|
+
exit 0 # Skip this update
|
|
121
|
+
fi
|
|
122
|
+
fi
|
|
123
|
+
|
|
124
|
+
# ============================================================================
|
|
125
|
+
# TIER 2: Check for PreToolUse Signal (Primary Detection Method)
|
|
126
|
+
# ============================================================================
|
|
127
|
+
PENDING_FILE="$PROJECT_ROOT/.specweave/state/.pending-status-update"
|
|
128
|
+
METRICS_FILE="$PROJECT_ROOT/.specweave/state/hook-metrics.jsonl"
|
|
129
|
+
EDITED_FILE=""
|
|
130
|
+
DETECTION_METHOD="none"
|
|
131
|
+
|
|
132
|
+
# First, check if PreToolUse hook left a signal
|
|
133
|
+
if [[ -f "$PENDING_FILE" ]]; then
|
|
134
|
+
EDITED_FILE=$(cat "$PENDING_FILE" 2>/dev/null || echo "")
|
|
135
|
+
# Delete pending file immediately (consume signal)
|
|
136
|
+
rm "$PENDING_FILE" 2>/dev/null || true
|
|
137
|
+
|
|
138
|
+
if [[ -n "$EDITED_FILE" ]]; then
|
|
139
|
+
DETECTION_METHOD="pretooluse"
|
|
140
|
+
echo "[$(date)] post-edit-spec: File from PreToolUse signal: $EDITED_FILE" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
141
|
+
|
|
142
|
+
# Record Tier 2 success metric
|
|
143
|
+
TIMESTAMP=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
144
|
+
echo "{\"timestamp\":\"$TIMESTAMP\",\"hook\":\"post-edit-spec\",\"event\":\"tier2_success\",\"method\":\"pretooluse\"}" >> "$METRICS_FILE" 2>/dev/null || true
|
|
145
|
+
fi
|
|
146
|
+
fi
|
|
147
|
+
|
|
148
|
+
# ============================================================================
|
|
149
|
+
# TIER 1 FALLBACK: Environment Variable Detection
|
|
150
|
+
# ============================================================================
|
|
151
|
+
# If PreToolUse didn't provide signal, fall back to Tier 1 methods
|
|
152
|
+
if [[ -z "$EDITED_FILE" ]]; then
|
|
153
|
+
# Method 1: TOOL_USE_CONTENT environment variable
|
|
154
|
+
if [[ -n "${TOOL_USE_CONTENT:-}" ]]; then
|
|
155
|
+
EDITED_FILE="$TOOL_USE_CONTENT"
|
|
156
|
+
DETECTION_METHOD="env_content"
|
|
157
|
+
fi
|
|
158
|
+
|
|
159
|
+
# Method 2: TOOL_RESULT environment variable
|
|
160
|
+
if [[ -z "$EDITED_FILE" ]] && [[ -n "${TOOL_RESULT:-}" ]]; then
|
|
161
|
+
EDITED_FILE=$(echo "$TOOL_RESULT" | grep -o '"file_path"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*"\([^"]*\)".*/\1/' || echo "")
|
|
162
|
+
DETECTION_METHOD="env_result"
|
|
163
|
+
fi
|
|
164
|
+
|
|
165
|
+
# Method 3: TOOL_USE_ARGS
|
|
166
|
+
if [[ -z "$EDITED_FILE" ]] && [[ -n "${TOOL_USE_ARGS:-}" ]]; then
|
|
167
|
+
EDITED_FILE=$(echo "$TOOL_USE_ARGS" | grep -o '"file_path"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*"\([^"]*\)".*/\1/' || echo "")
|
|
168
|
+
DETECTION_METHOD="env_args"
|
|
169
|
+
fi
|
|
170
|
+
|
|
171
|
+
# Log env var detection (for metrics)
|
|
172
|
+
if [[ -n "$EDITED_FILE" ]]; then
|
|
173
|
+
echo "[$(date)] post-edit-spec: File from env vars ($DETECTION_METHOD): $EDITED_FILE" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
174
|
+
fi
|
|
175
|
+
fi
|
|
60
176
|
|
|
61
177
|
# Check if we detected a spec.md or tasks.md edit in increments folder
|
|
62
178
|
SHOULD_UPDATE=false
|
|
@@ -72,23 +188,78 @@ if [[ -n "$EDITED_FILE" ]]; then
|
|
|
72
188
|
fi
|
|
73
189
|
fi
|
|
74
190
|
|
|
75
|
-
#
|
|
76
|
-
#
|
|
191
|
+
# ============================================================================
|
|
192
|
+
# TIER 1 FIX: File Modification Time Detection (Fallback)
|
|
193
|
+
# ============================================================================
|
|
194
|
+
# If we couldn't detect the file via environment variables, check which files
|
|
195
|
+
# were modified recently (within last 2 seconds) instead of blindly updating
|
|
77
196
|
if [[ -z "$EDITED_FILE" ]]; then
|
|
78
|
-
echo "[$(date)] post-edit-spec:
|
|
79
|
-
|
|
197
|
+
echo "[$(date)] post-edit-spec: Env vars empty - checking file mtimes" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
198
|
+
|
|
199
|
+
NOW=$(date +%s)
|
|
200
|
+
INCREMENTS_DIR="$PROJECT_ROOT/.specweave/increments"
|
|
201
|
+
|
|
202
|
+
# Check for recently modified spec.md or tasks.md files
|
|
203
|
+
if [[ -d "$INCREMENTS_DIR" ]]; then
|
|
204
|
+
for file in "$INCREMENTS_DIR"/*/spec.md "$INCREMENTS_DIR"/*/tasks.md; do
|
|
205
|
+
if [[ -f "$file" ]]; then
|
|
206
|
+
# Get file modification time (platform-specific)
|
|
207
|
+
if [[ "$(uname)" == "Darwin" ]]; then
|
|
208
|
+
MTIME=$(stat -f "%m" "$file" 2>/dev/null || echo 0)
|
|
209
|
+
else
|
|
210
|
+
MTIME=$(stat -c "%Y" "$file" 2>/dev/null || echo 0)
|
|
211
|
+
fi
|
|
212
|
+
|
|
213
|
+
# If file was modified in last 2 seconds, consider it the edited file
|
|
214
|
+
TIME_DIFF=$((NOW - MTIME))
|
|
215
|
+
if (( TIME_DIFF <= 2 )); then
|
|
216
|
+
EDITED_FILE="$file"
|
|
217
|
+
echo "[$(date)] post-edit-spec: Detected recent modification: $file (${TIME_DIFF}s ago)" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
218
|
+
SHOULD_UPDATE=true
|
|
219
|
+
break
|
|
220
|
+
fi
|
|
221
|
+
fi
|
|
222
|
+
done
|
|
223
|
+
fi
|
|
224
|
+
|
|
225
|
+
# If still no file detected, skip update (not a spec/tasks edit)
|
|
226
|
+
if [[ -z "$EDITED_FILE" ]]; then
|
|
227
|
+
echo "[$(date)] post-edit-spec: No spec/tasks modifications detected - skipping" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
228
|
+
exit 0
|
|
229
|
+
fi
|
|
80
230
|
fi
|
|
81
231
|
|
|
232
|
+
# ============================================================================
|
|
233
|
+
# TIER 1 FIX: Non-Blocking Background Update with COMPLETE ERROR ISOLATION
|
|
234
|
+
# ============================================================================
|
|
82
235
|
# Update status line if needed
|
|
83
236
|
if [[ "$SHOULD_UPDATE" == "true" ]]; then
|
|
84
|
-
echo "[$(date)] post-edit-spec: Running update-status-line.sh" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
237
|
+
echo "[$(date)] post-edit-spec: Running update-status-line.sh (background)" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
85
238
|
|
|
86
|
-
#
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
239
|
+
# Record update time BEFORE spawning background process
|
|
240
|
+
# This ensures debouncing works even if update hasn't completed yet
|
|
241
|
+
echo "$(date +%s)" > "$LAST_UPDATE_FILE"
|
|
242
|
+
|
|
243
|
+
# Run status line update in background with COMPLETE error isolation
|
|
244
|
+
# This prevents Edit tool from waiting for status line computation
|
|
245
|
+
(
|
|
246
|
+
set +e # Disable error propagation
|
|
247
|
+
|
|
248
|
+
if "$PROJECT_ROOT/plugins/specweave/hooks/lib/update-status-line.sh" 2>&1 | tee -a "$DEBUG_LOG" >/dev/null; then
|
|
249
|
+
echo "[$(date)] post-edit-spec: Status line updated successfully" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
250
|
+
# Reset circuit breaker on success
|
|
251
|
+
echo "0" > "$CIRCUIT_BREAKER_FILE" 2>/dev/null || true
|
|
252
|
+
else
|
|
253
|
+
echo "[$(date)] post-edit-spec: Warning - status line update failed (non-blocking)" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
254
|
+
# Increment circuit breaker
|
|
255
|
+
CURRENT_FAILURES=$(cat "$CIRCUIT_BREAKER_FILE" 2>/dev/null || echo 0)
|
|
256
|
+
echo "$((CURRENT_FAILURES + 1))" > "$CIRCUIT_BREAKER_FILE" 2>/dev/null || true
|
|
257
|
+
fi
|
|
258
|
+
) &
|
|
259
|
+
|
|
260
|
+
# Disown the background process so it's not killed when hook exits
|
|
261
|
+
disown 2>/dev/null || true
|
|
92
262
|
fi
|
|
93
263
|
|
|
264
|
+
# Always exit 0 to prevent hook errors from crashing Claude Code
|
|
94
265
|
exit 0
|