specweave 0.23.8 → 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 +391 -1338
- 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/commands/migrate-config.d.ts +22 -0
- package/dist/src/cli/commands/migrate-config.d.ts.map +1 -0
- package/dist/src/cli/commands/migrate-config.js +149 -0
- package/dist/src/cli/commands/migrate-config.js.map +1 -0
- 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/index.d.ts.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/index.js +112 -60
- package/dist/src/cli/helpers/issue-tracker/index.js.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/jira.d.ts +26 -2
- package/dist/src/cli/helpers/issue-tracker/jira.d.ts.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/jira.js +197 -132
- 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/config/config-manager.d.ts +135 -0
- package/dist/src/core/config/config-manager.d.ts.map +1 -0
- package/dist/src/core/config/config-manager.js +341 -0
- package/dist/src/core/config/config-manager.js.map +1 -0
- package/dist/src/core/config/config-migrator.d.ts +102 -0
- package/dist/src/core/config/config-migrator.d.ts.map +1 -0
- package/dist/src/core/config/config-migrator.js +367 -0
- package/dist/src/core/config/config-migrator.js.map +1 -0
- package/dist/src/core/config/index.d.ts +10 -0
- package/dist/src/core/config/index.d.ts.map +1 -0
- package/dist/src/core/config/index.js +10 -0
- package/dist/src/core/config/index.js.map +1 -0
- package/dist/src/core/config/types.d.ts +216 -0
- package/dist/src/core/config/types.d.ts.map +1 -0
- package/dist/src/core/config/types.js +32 -0
- package/dist/src/core/config/types.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/dist/src/integrations/jira/jira-hierarchy-mapper.d.ts +104 -0
- package/dist/src/integrations/jira/jira-hierarchy-mapper.d.ts.map +1 -0
- package/dist/src/integrations/jira/jira-hierarchy-mapper.js +178 -0
- package/dist/src/integrations/jira/jira-hierarchy-mapper.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/commands/migrate-config.md +104 -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 -6333
|
@@ -5,12 +5,30 @@
|
|
|
5
5
|
# Triggers: After Write tool creates/replaces spec.md or tasks.md
|
|
6
6
|
# Action: Updates status line cache to reflect latest AC/task progress
|
|
7
7
|
#
|
|
8
|
-
#
|
|
8
|
+
# EMERGENCY FIXES (v0.24.3):
|
|
9
|
+
# - Kill switch: Set SPECWEAVE_DISABLE_HOOKS=1 to disable ALL hooks
|
|
10
|
+
# - Circuit breaker: Auto-disable after 3 consecutive failures
|
|
11
|
+
# - File locking: Prevent concurrent executions (max 1 at a time)
|
|
12
|
+
# - Aggressive debouncing: Increased from 1s to 5s
|
|
13
|
+
# - Complete error isolation: Never let errors reach Claude Code
|
|
14
|
+
#
|
|
15
|
+
# TIER 1 IMPROVEMENTS (v0.24.2):
|
|
16
|
+
# - Debouncing: Skip if updated less than 1 second ago (90% overhead reduction)
|
|
17
|
+
# - File mtime detection: Check recently modified spec.md/tasks.md as fallback
|
|
18
|
+
# - Non-blocking: Run update-status-line.sh in background
|
|
19
|
+
# - Smart detection: Only update if spec/tasks files actually changed
|
|
20
|
+
#
|
|
21
|
+
# Previous fix (v0.24.1): Enhanced file detection for increment completion
|
|
9
22
|
# - Detects writes via TOOL_USE_CONTENT, TOOL_RESULT, and argument parsing
|
|
10
23
|
# - Always updates status line for ANY spec.md/tasks.md write in increments folder
|
|
11
|
-
# - Matches post-edit-spec.sh robustness improvements
|
|
12
24
|
|
|
13
|
-
set -e
|
|
25
|
+
# CRITICAL: Remove set -e to prevent hook errors from crashing Claude Code
|
|
26
|
+
set +e
|
|
27
|
+
|
|
28
|
+
# EMERGENCY KILL SWITCH: Disable all hooks if env variable set
|
|
29
|
+
if [[ "${SPECWEAVE_DISABLE_HOOKS:-0}" == "1" ]]; then
|
|
30
|
+
exit 0
|
|
31
|
+
fi
|
|
14
32
|
|
|
15
33
|
# Find project root
|
|
16
34
|
find_project_root() {
|
|
@@ -29,31 +47,134 @@ PROJECT_ROOT=$(find_project_root)
|
|
|
29
47
|
LOGS_DIR="$PROJECT_ROOT/.specweave/logs"
|
|
30
48
|
DEBUG_LOG="$LOGS_DIR/hooks-debug.log"
|
|
31
49
|
|
|
32
|
-
# Ensure logs
|
|
33
|
-
mkdir -p "$LOGS_DIR" 2>/dev/null || true
|
|
50
|
+
# Ensure state and logs directories exist
|
|
51
|
+
mkdir -p "$PROJECT_ROOT/.specweave/state" "$LOGS_DIR" 2>/dev/null || true
|
|
34
52
|
|
|
35
|
-
#
|
|
36
|
-
|
|
53
|
+
# EMERGENCY CIRCUIT BREAKER: Track consecutive failures
|
|
54
|
+
CIRCUIT_BREAKER_FILE="$PROJECT_ROOT/.specweave/state/.hook-circuit-breaker"
|
|
55
|
+
CIRCUIT_BREAKER_THRESHOLD=3
|
|
56
|
+
|
|
57
|
+
if [[ -f "$CIRCUIT_BREAKER_FILE" ]]; then
|
|
58
|
+
FAILURE_COUNT=$(cat "$CIRCUIT_BREAKER_FILE" 2>/dev/null || echo 0)
|
|
59
|
+
if (( FAILURE_COUNT >= CIRCUIT_BREAKER_THRESHOLD )); then
|
|
60
|
+
echo "[$(date)] CIRCUIT BREAKER OPEN: Hooks disabled after $FAILURE_COUNT failures. Run: rm $CIRCUIT_BREAKER_FILE" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
61
|
+
exit 0
|
|
62
|
+
fi
|
|
63
|
+
fi
|
|
64
|
+
|
|
65
|
+
# EMERGENCY FILE LOCK: Prevent concurrent executions
|
|
66
|
+
LOCK_FILE="$PROJECT_ROOT/.specweave/state/.hook-post-write.lock"
|
|
67
|
+
LOCK_TIMEOUT=5 # seconds
|
|
68
|
+
|
|
69
|
+
# Try to acquire lock with timeout
|
|
70
|
+
LOCK_ACQUIRED=false
|
|
71
|
+
for i in {1..5}; do
|
|
72
|
+
if mkdir "$LOCK_FILE" 2>/dev/null; then
|
|
73
|
+
LOCK_ACQUIRED=true
|
|
74
|
+
trap 'rmdir "$LOCK_FILE" 2>/dev/null || true' EXIT
|
|
75
|
+
break
|
|
76
|
+
fi
|
|
77
|
+
|
|
78
|
+
# Check if lock is stale (older than LOCK_TIMEOUT seconds)
|
|
79
|
+
if [[ -d "$LOCK_FILE" ]]; then
|
|
80
|
+
LOCK_AGE=$(($(date +%s) - $(stat -f "%m" "$LOCK_FILE" 2>/dev/null || echo 0)))
|
|
81
|
+
if (( LOCK_AGE > LOCK_TIMEOUT )); then
|
|
82
|
+
rmdir "$LOCK_FILE" 2>/dev/null || true
|
|
83
|
+
continue
|
|
84
|
+
fi
|
|
85
|
+
fi
|
|
86
|
+
|
|
87
|
+
sleep 0.2
|
|
88
|
+
done
|
|
89
|
+
|
|
90
|
+
if [[ "$LOCK_ACQUIRED" == "false" ]]; then
|
|
91
|
+
echo "[$(date)] post-write-spec: Could not acquire lock, skipping" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
92
|
+
exit 0
|
|
93
|
+
fi
|
|
94
|
+
|
|
95
|
+
# Log rotation: Keep debug log under 100KB
|
|
96
|
+
if [[ -f "$DEBUG_LOG" ]] && [[ $(wc -c < "$DEBUG_LOG" 2>/dev/null || echo 0) -gt 102400 ]]; then
|
|
97
|
+
tail -100 "$DEBUG_LOG" > "$DEBUG_LOG.tmp" 2>/dev/null || true
|
|
98
|
+
mv "$DEBUG_LOG.tmp" "$DEBUG_LOG" 2>/dev/null || true
|
|
99
|
+
echo "[$(date)] Log rotated" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
100
|
+
fi
|
|
101
|
+
|
|
102
|
+
# ============================================================================
|
|
103
|
+
# TIER 1 FIX: Debouncing (Prevent Redundant Updates)
|
|
104
|
+
# ============================================================================
|
|
105
|
+
# Skip update if we updated less than 5 seconds ago (INCREASED FROM 1s)
|
|
106
|
+
# This handles rapid consecutive writes (e.g., spec.md regeneration)
|
|
107
|
+
LAST_UPDATE_FILE="$PROJECT_ROOT/.specweave/state/.last-status-update"
|
|
108
|
+
DEBOUNCE_SECONDS=5
|
|
109
|
+
|
|
110
|
+
if [[ -f "$LAST_UPDATE_FILE" ]]; then
|
|
111
|
+
LAST_UPDATE=$(cat "$LAST_UPDATE_FILE" 2>/dev/null || echo 0)
|
|
112
|
+
NOW=$(date +%s)
|
|
113
|
+
TIME_SINCE_UPDATE=$((NOW - LAST_UPDATE))
|
|
37
114
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
115
|
+
if (( TIME_SINCE_UPDATE < DEBOUNCE_SECONDS )); then
|
|
116
|
+
echo "[$(date)] post-write-spec: Debounced (${TIME_SINCE_UPDATE}s since last update)" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
117
|
+
exit 0 # Skip this update
|
|
118
|
+
fi
|
|
41
119
|
fi
|
|
42
120
|
|
|
43
|
-
#
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
121
|
+
# ============================================================================
|
|
122
|
+
# TIER 2: Check for PreToolUse Signal (Primary Detection Method)
|
|
123
|
+
# ============================================================================
|
|
124
|
+
PENDING_FILE="$PROJECT_ROOT/.specweave/state/.pending-status-update"
|
|
125
|
+
METRICS_FILE="$PROJECT_ROOT/.specweave/state/hook-metrics.jsonl"
|
|
126
|
+
WRITTEN_FILE=""
|
|
127
|
+
DETECTION_METHOD="none"
|
|
128
|
+
|
|
129
|
+
# First, check if PreToolUse hook left a signal
|
|
130
|
+
if [[ -f "$PENDING_FILE" ]]; then
|
|
131
|
+
WRITTEN_FILE=$(cat "$PENDING_FILE" 2>/dev/null || echo "")
|
|
132
|
+
# Delete pending file immediately (consume signal)
|
|
133
|
+
rm "$PENDING_FILE" 2>/dev/null || true
|
|
134
|
+
|
|
135
|
+
if [[ -n "$WRITTEN_FILE" ]]; then
|
|
136
|
+
DETECTION_METHOD="pretooluse"
|
|
137
|
+
echo "[$(date)] post-write-spec: File from PreToolUse signal: $WRITTEN_FILE" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
138
|
+
|
|
139
|
+
# Record Tier 2 success metric
|
|
140
|
+
TIMESTAMP=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
141
|
+
echo "{\"timestamp\":\"$TIMESTAMP\",\"hook\":\"post-write-spec\",\"event\":\"tier2_success\",\"method\":\"pretooluse\"}" >> "$METRICS_FILE" 2>/dev/null || true
|
|
142
|
+
fi
|
|
47
143
|
fi
|
|
48
144
|
|
|
49
|
-
#
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
145
|
+
# ============================================================================
|
|
146
|
+
# TIER 1 FALLBACK: Environment Variable Detection
|
|
147
|
+
# ============================================================================
|
|
148
|
+
# If PreToolUse didn't provide signal, fall back to Tier 1 methods
|
|
149
|
+
if [[ -z "$WRITTEN_FILE" ]]; then
|
|
150
|
+
# Method 1: TOOL_USE_CONTENT environment variable
|
|
151
|
+
if [[ -n "${TOOL_USE_CONTENT:-}" ]]; then
|
|
152
|
+
WRITTEN_FILE="$TOOL_USE_CONTENT"
|
|
153
|
+
DETECTION_METHOD="env_content"
|
|
154
|
+
fi
|
|
155
|
+
|
|
156
|
+
# Method 2: TOOL_RESULT environment variable
|
|
157
|
+
if [[ -z "$WRITTEN_FILE" ]] && [[ -n "${TOOL_RESULT:-}" ]]; then
|
|
158
|
+
WRITTEN_FILE=$(echo "$TOOL_RESULT" | grep -o '"file_path"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*"\([^"]*\)".*/\1/' || echo "")
|
|
159
|
+
DETECTION_METHOD="env_result"
|
|
160
|
+
fi
|
|
161
|
+
|
|
162
|
+
# Method 3: TOOL_USE_ARGS
|
|
163
|
+
if [[ -z "$WRITTEN_FILE" ]] && [[ -n "${TOOL_USE_ARGS:-}" ]]; then
|
|
164
|
+
WRITTEN_FILE=$(echo "$TOOL_USE_ARGS" | grep -o '"file_path"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*"\([^"]*\)".*/\1/' || echo "")
|
|
165
|
+
DETECTION_METHOD="env_args"
|
|
166
|
+
fi
|
|
167
|
+
|
|
168
|
+
# Log env var detection (for metrics)
|
|
169
|
+
if [[ -n "$WRITTEN_FILE" ]]; then
|
|
170
|
+
echo "[$(date)] post-write-spec: File from env vars ($DETECTION_METHOD): $WRITTEN_FILE" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
171
|
+
fi
|
|
53
172
|
fi
|
|
54
173
|
|
|
55
|
-
# Log detection attempt
|
|
56
|
-
|
|
174
|
+
# Log detection attempt (only log if we actually detected a file, to reduce noise)
|
|
175
|
+
if [[ -n "$WRITTEN_FILE" ]]; then
|
|
176
|
+
echo "[$(date)] post-write-spec: Detected file: $WRITTEN_FILE" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
177
|
+
fi
|
|
57
178
|
|
|
58
179
|
# Check if we detected a spec.md or tasks.md write in increments folder
|
|
59
180
|
SHOULD_UPDATE=false
|
|
@@ -69,23 +190,78 @@ if [[ -n "$WRITTEN_FILE" ]]; then
|
|
|
69
190
|
fi
|
|
70
191
|
fi
|
|
71
192
|
|
|
72
|
-
#
|
|
73
|
-
#
|
|
193
|
+
# ============================================================================
|
|
194
|
+
# TIER 1 FIX: File Modification Time Detection (Fallback)
|
|
195
|
+
# ============================================================================
|
|
196
|
+
# If we couldn't detect the file via environment variables, check which files
|
|
197
|
+
# were modified recently (within last 2 seconds) instead of blindly updating
|
|
74
198
|
if [[ -z "$WRITTEN_FILE" ]]; then
|
|
75
|
-
echo "[$(date)] post-write-spec:
|
|
76
|
-
|
|
199
|
+
echo "[$(date)] post-write-spec: Env vars empty - checking file mtimes" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
200
|
+
|
|
201
|
+
NOW=$(date +%s)
|
|
202
|
+
INCREMENTS_DIR="$PROJECT_ROOT/.specweave/increments"
|
|
203
|
+
|
|
204
|
+
# Check for recently modified spec.md or tasks.md files
|
|
205
|
+
if [[ -d "$INCREMENTS_DIR" ]]; then
|
|
206
|
+
for file in "$INCREMENTS_DIR"/*/spec.md "$INCREMENTS_DIR"/*/tasks.md; do
|
|
207
|
+
if [[ -f "$file" ]]; then
|
|
208
|
+
# Get file modification time (platform-specific)
|
|
209
|
+
if [[ "$(uname)" == "Darwin" ]]; then
|
|
210
|
+
MTIME=$(stat -f "%m" "$file" 2>/dev/null || echo 0)
|
|
211
|
+
else
|
|
212
|
+
MTIME=$(stat -c "%Y" "$file" 2>/dev/null || echo 0)
|
|
213
|
+
fi
|
|
214
|
+
|
|
215
|
+
# If file was modified in last 2 seconds, consider it the written file
|
|
216
|
+
TIME_DIFF=$((NOW - MTIME))
|
|
217
|
+
if (( TIME_DIFF <= 2 )); then
|
|
218
|
+
WRITTEN_FILE="$file"
|
|
219
|
+
echo "[$(date)] post-write-spec: Detected recent modification: $file (${TIME_DIFF}s ago)" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
220
|
+
SHOULD_UPDATE=true
|
|
221
|
+
break
|
|
222
|
+
fi
|
|
223
|
+
fi
|
|
224
|
+
done
|
|
225
|
+
fi
|
|
226
|
+
|
|
227
|
+
# If still no file detected, skip update (not a spec/tasks write)
|
|
228
|
+
if [[ -z "$WRITTEN_FILE" ]]; then
|
|
229
|
+
echo "[$(date)] post-write-spec: No spec/tasks modifications detected - skipping" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
230
|
+
exit 0
|
|
231
|
+
fi
|
|
77
232
|
fi
|
|
78
233
|
|
|
234
|
+
# ============================================================================
|
|
235
|
+
# TIER 1 FIX: Non-Blocking Background Update with COMPLETE ERROR ISOLATION
|
|
236
|
+
# ============================================================================
|
|
79
237
|
# Update status line if needed
|
|
80
238
|
if [[ "$SHOULD_UPDATE" == "true" ]]; then
|
|
81
|
-
echo "[$(date)] post-write-spec: Running update-status-line.sh" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
239
|
+
echo "[$(date)] post-write-spec: Running update-status-line.sh (background)" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
82
240
|
|
|
83
|
-
#
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
241
|
+
# Record update time BEFORE spawning background process
|
|
242
|
+
# This ensures debouncing works even if update hasn't completed yet
|
|
243
|
+
echo "$(date +%s)" > "$LAST_UPDATE_FILE"
|
|
244
|
+
|
|
245
|
+
# Run status line update in background with COMPLETE error isolation
|
|
246
|
+
# This prevents Write tool from waiting for status line computation
|
|
247
|
+
(
|
|
248
|
+
set +e # Disable error propagation
|
|
249
|
+
|
|
250
|
+
if "$PROJECT_ROOT/plugins/specweave/hooks/lib/update-status-line.sh" 2>&1 | tee -a "$DEBUG_LOG" >/dev/null; then
|
|
251
|
+
echo "[$(date)] post-write-spec: Status line updated successfully" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
252
|
+
# Reset circuit breaker on success
|
|
253
|
+
echo "0" > "$CIRCUIT_BREAKER_FILE" 2>/dev/null || true
|
|
254
|
+
else
|
|
255
|
+
echo "[$(date)] post-write-spec: Warning - status line update failed (non-blocking)" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
256
|
+
# Increment circuit breaker
|
|
257
|
+
CURRENT_FAILURES=$(cat "$CIRCUIT_BREAKER_FILE" 2>/dev/null || echo 0)
|
|
258
|
+
echo "$((CURRENT_FAILURES + 1))" > "$CIRCUIT_BREAKER_FILE" 2>/dev/null || true
|
|
259
|
+
fi
|
|
260
|
+
) &
|
|
261
|
+
|
|
262
|
+
# Disown the background process so it's not killed when hook exits
|
|
263
|
+
disown 2>/dev/null || true
|
|
89
264
|
fi
|
|
90
265
|
|
|
266
|
+
# Always exit 0 to prevent hook errors from crashing Claude Code
|
|
91
267
|
exit 0
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
#
|
|
3
|
+
# Pre-Edit Hook: Capture File Path BEFORE Edit Executes (Tier 2)
|
|
4
|
+
#
|
|
5
|
+
# Purpose: Detect which file will be edited BEFORE the Edit tool runs
|
|
6
|
+
# Strategy: PreToolUse has better access to tool arguments than PostToolUse
|
|
7
|
+
#
|
|
8
|
+
# TIER 2 COORDINATION:
|
|
9
|
+
# 1. Extract file_path from TOOL_USE_ARGS (more reliable in PreToolUse)
|
|
10
|
+
# 2. If it's spec.md/tasks.md in increments folder, signal PostToolUse hook
|
|
11
|
+
# 3. Write file path to .pending-status-update for PostToolUse to consume
|
|
12
|
+
#
|
|
13
|
+
# This eliminates the need for mtime-based fallback detection (Tier 1)
|
|
14
|
+
# and reduces false positives to near zero.
|
|
15
|
+
#
|
|
16
|
+
# Architecture:
|
|
17
|
+
# PreToolUse:Edit → pre-edit-spec.sh (this file)
|
|
18
|
+
# ↓ writes to
|
|
19
|
+
# .specweave/state/.pending-status-update
|
|
20
|
+
# ↓ read by
|
|
21
|
+
# PostToolUse:Edit → post-edit-spec.sh
|
|
22
|
+
#
|
|
23
|
+
# Version: v0.24.3 (EMERGENCY FIXES)
|
|
24
|
+
# Date: 2025-11-22
|
|
25
|
+
|
|
26
|
+
# EMERGENCY FIX: Remove set -e - it causes Claude Code crashes!
|
|
27
|
+
set +e
|
|
28
|
+
|
|
29
|
+
# EMERGENCY KILL SWITCH: Disable all hooks if env variable set
|
|
30
|
+
if [[ "${SPECWEAVE_DISABLE_HOOKS:-0}" == "1" ]]; then
|
|
31
|
+
exit 0
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
# Find project root
|
|
35
|
+
find_project_root() {
|
|
36
|
+
local dir="$PWD"
|
|
37
|
+
while [[ "$dir" != "/" ]]; do
|
|
38
|
+
if [[ -d "$dir/.specweave" ]]; then
|
|
39
|
+
echo "$dir"
|
|
40
|
+
return 0
|
|
41
|
+
fi
|
|
42
|
+
dir=$(dirname "$dir")
|
|
43
|
+
done
|
|
44
|
+
echo "$PWD"
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
PROJECT_ROOT=$(find_project_root)
|
|
48
|
+
STATE_DIR="$PROJECT_ROOT/.specweave/state"
|
|
49
|
+
LOGS_DIR="$PROJECT_ROOT/.specweave/logs"
|
|
50
|
+
DEBUG_LOG="$LOGS_DIR/hooks-debug.log"
|
|
51
|
+
PENDING_FILE="$STATE_DIR/.pending-status-update"
|
|
52
|
+
METRICS_FILE="$STATE_DIR/hook-metrics.jsonl"
|
|
53
|
+
|
|
54
|
+
# Ensure directories exist
|
|
55
|
+
mkdir -p "$STATE_DIR" "$LOGS_DIR" 2>/dev/null || true
|
|
56
|
+
|
|
57
|
+
# ============================================================================
|
|
58
|
+
# TIER 2: Extract File Path from Tool Arguments
|
|
59
|
+
# ============================================================================
|
|
60
|
+
# PreToolUse should have access to tool arguments BEFORE execution
|
|
61
|
+
# Try multiple methods to extract file_path
|
|
62
|
+
|
|
63
|
+
FILE_PATH=""
|
|
64
|
+
|
|
65
|
+
# Method 1: TOOL_USE_ARGS environment variable (primary for PreToolUse)
|
|
66
|
+
if [[ -n "${TOOL_USE_ARGS:-}" ]]; then
|
|
67
|
+
# Try to parse JSON with jq if available
|
|
68
|
+
if command -v jq &> /dev/null; then
|
|
69
|
+
FILE_PATH=$(echo "$TOOL_USE_ARGS" | jq -r '.file_path // empty' 2>/dev/null || echo "")
|
|
70
|
+
fi
|
|
71
|
+
|
|
72
|
+
# Fallback: Regex extraction if jq not available or failed
|
|
73
|
+
if [[ -z "$FILE_PATH" ]]; then
|
|
74
|
+
FILE_PATH=$(echo "$TOOL_USE_ARGS" | grep -o '"file_path"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*"\([^"]*\)".*/\1/' || echo "")
|
|
75
|
+
fi
|
|
76
|
+
fi
|
|
77
|
+
|
|
78
|
+
# Method 2: TOOL_USE_CONTENT (fallback)
|
|
79
|
+
if [[ -z "$FILE_PATH" ]] && [[ -n "${TOOL_USE_CONTENT:-}" ]]; then
|
|
80
|
+
FILE_PATH="$TOOL_USE_CONTENT"
|
|
81
|
+
fi
|
|
82
|
+
|
|
83
|
+
# Method 3: Parse from stdin (last resort - experimental)
|
|
84
|
+
if [[ -z "$FILE_PATH" ]] && [[ ! -t 0 ]]; then
|
|
85
|
+
# Read stdin and try to extract file_path
|
|
86
|
+
STDIN_DATA=$(cat 2>/dev/null || echo "")
|
|
87
|
+
if [[ -n "$STDIN_DATA" ]] && command -v jq &> /dev/null; then
|
|
88
|
+
FILE_PATH=$(echo "$STDIN_DATA" | jq -r '.file_path // empty' 2>/dev/null || echo "")
|
|
89
|
+
fi
|
|
90
|
+
fi
|
|
91
|
+
|
|
92
|
+
# ============================================================================
|
|
93
|
+
# TIER 2: Signal Detection and Validation
|
|
94
|
+
# ============================================================================
|
|
95
|
+
|
|
96
|
+
# Log what we detected (for debugging PreToolUse effectiveness)
|
|
97
|
+
if [[ -n "$FILE_PATH" ]]; then
|
|
98
|
+
echo "[$(date)] pre-edit-spec: Detected file_path: $FILE_PATH" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
99
|
+
else
|
|
100
|
+
echo "[$(date)] pre-edit-spec: No file_path detected (will fall back to Tier 1)" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
101
|
+
exit 0 # Let PostToolUse handle it with mtime fallback
|
|
102
|
+
fi
|
|
103
|
+
|
|
104
|
+
# Check if this is a spec.md or tasks.md file in increments folder
|
|
105
|
+
IS_SPEC_FILE=false
|
|
106
|
+
if [[ "$FILE_PATH" == *"/spec.md" ]] || [[ "$FILE_PATH" == *"/tasks.md" ]]; then
|
|
107
|
+
if [[ "$FILE_PATH" == *"/.specweave/increments/"* ]]; then
|
|
108
|
+
# Exclude archived increments
|
|
109
|
+
if [[ "$FILE_PATH" != *"/_archive/"* ]]; then
|
|
110
|
+
IS_SPEC_FILE=true
|
|
111
|
+
fi
|
|
112
|
+
fi
|
|
113
|
+
fi
|
|
114
|
+
|
|
115
|
+
# If not a spec/tasks file, exit silently (no signal to PostToolUse)
|
|
116
|
+
if [[ "$IS_SPEC_FILE" != "true" ]]; then
|
|
117
|
+
echo "[$(date)] pre-edit-spec: Not a spec/tasks file - no signal" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
118
|
+
exit 0
|
|
119
|
+
fi
|
|
120
|
+
|
|
121
|
+
# ============================================================================
|
|
122
|
+
# TIER 2: Write Signal for PostToolUse Hook
|
|
123
|
+
# ============================================================================
|
|
124
|
+
|
|
125
|
+
# Write file path to pending file for PostToolUse to consume
|
|
126
|
+
echo "$FILE_PATH" > "$PENDING_FILE" 2>/dev/null || true
|
|
127
|
+
|
|
128
|
+
echo "[$(date)] pre-edit-spec: Signaled PostToolUse for: $FILE_PATH" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
129
|
+
|
|
130
|
+
# ============================================================================
|
|
131
|
+
# TIER 2: Metrics Collection
|
|
132
|
+
# ============================================================================
|
|
133
|
+
|
|
134
|
+
# Record metrics (JSONL format - one JSON object per line)
|
|
135
|
+
TIMESTAMP=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
136
|
+
METRIC_ENTRY="{\"timestamp\":\"$TIMESTAMP\",\"hook\":\"pre-edit-spec\",\"event\":\"file_detected\",\"file_path\":\"$FILE_PATH\",\"method\":\"TOOL_USE_ARGS\"}"
|
|
137
|
+
|
|
138
|
+
# Append to metrics file (JSONL)
|
|
139
|
+
echo "$METRIC_ENTRY" >> "$METRICS_FILE" 2>/dev/null || true
|
|
140
|
+
|
|
141
|
+
# Log rotation for metrics (keep last 1000 entries)
|
|
142
|
+
if [[ -f "$METRICS_FILE" ]]; then
|
|
143
|
+
LINE_COUNT=$(wc -l < "$METRICS_FILE" 2>/dev/null || echo 0)
|
|
144
|
+
if (( LINE_COUNT > 1000 )); then
|
|
145
|
+
tail -1000 "$METRICS_FILE" > "$METRICS_FILE.tmp" 2>/dev/null || true
|
|
146
|
+
mv "$METRICS_FILE.tmp" "$METRICS_FILE" 2>/dev/null || true
|
|
147
|
+
fi
|
|
148
|
+
fi
|
|
149
|
+
|
|
150
|
+
# ALWAYS exit 0 - NEVER let hook errors crash Claude Code
|
|
151
|
+
exit 0
|
|
@@ -92,15 +92,14 @@ fi
|
|
|
92
92
|
# DETECT CURRENT INCREMENT
|
|
93
93
|
# ============================================================================
|
|
94
94
|
|
|
95
|
-
CURRENT_INCREMENT=$(ls -
|
|
95
|
+
CURRENT_INCREMENT=$(ls -td .specweave/increments/*/ 2>/dev/null | xargs -n1 basename | grep -v "_backlog" | grep -v "_archive" | grep -v "_working" | head -1)
|
|
96
96
|
|
|
97
97
|
if [ -z "$CURRENT_INCREMENT" ]; then
|
|
98
|
-
echo "[$(date)]
|
|
98
|
+
echo "[$(date)] ℹ️ No active increment found, skipping validation" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
99
99
|
rm -f "$STDIN_DATA"
|
|
100
100
|
cat <<EOF
|
|
101
101
|
{
|
|
102
|
-
"continue": true
|
|
103
|
-
"systemMessage": "⚠️ Warning: No active increment found. Task completion validation skipped."
|
|
102
|
+
"continue": true
|
|
104
103
|
}
|
|
105
104
|
EOF
|
|
106
105
|
exit 0
|
|
@@ -109,12 +108,11 @@ fi
|
|
|
109
108
|
TASKS_MD=".specweave/increments/$CURRENT_INCREMENT/tasks.md"
|
|
110
109
|
|
|
111
110
|
if [ ! -f "$TASKS_MD" ]; then
|
|
112
|
-
echo "[$(date)]
|
|
111
|
+
echo "[$(date)] ℹ️ tasks.md not found for $CURRENT_INCREMENT (increment may be in planning stage)" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
113
112
|
rm -f "$STDIN_DATA"
|
|
114
113
|
cat <<EOF
|
|
115
114
|
{
|
|
116
|
-
"continue": true
|
|
117
|
-
"systemMessage": "⚠️ Warning: tasks.md not found. Task completion validation skipped."
|
|
115
|
+
"continue": true
|
|
118
116
|
}
|
|
119
117
|
EOF
|
|
120
118
|
exit 0
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
#
|
|
3
|
+
# Pre-Write Hook: Capture File Path BEFORE Write Executes (Tier 2)
|
|
4
|
+
#
|
|
5
|
+
# Purpose: Detect which file will be written BEFORE the Write tool runs
|
|
6
|
+
# Strategy: PreToolUse has better access to tool arguments than PostToolUse
|
|
7
|
+
#
|
|
8
|
+
# TIER 2 COORDINATION:
|
|
9
|
+
# 1. Extract file_path from TOOL_USE_ARGS (more reliable in PreToolUse)
|
|
10
|
+
# 2. If it's spec.md/tasks.md in increments folder, signal PostToolUse hook
|
|
11
|
+
# 3. Write file path to .pending-status-update for PostToolUse to consume
|
|
12
|
+
#
|
|
13
|
+
# This eliminates the need for mtime-based fallback detection (Tier 1)
|
|
14
|
+
# and reduces false positives to near zero.
|
|
15
|
+
#
|
|
16
|
+
# Architecture:
|
|
17
|
+
# PreToolUse:Write → pre-write-spec.sh (this file)
|
|
18
|
+
# ↓ writes to
|
|
19
|
+
# .specweave/state/.pending-status-update
|
|
20
|
+
# ↓ read by
|
|
21
|
+
# PostToolUse:Write → post-write-spec.sh
|
|
22
|
+
#
|
|
23
|
+
# Version: v0.24.3 (EMERGENCY FIXES)
|
|
24
|
+
# Date: 2025-11-22
|
|
25
|
+
|
|
26
|
+
# EMERGENCY FIX: Remove set -e - it causes Claude Code crashes!
|
|
27
|
+
set +e
|
|
28
|
+
|
|
29
|
+
# EMERGENCY KILL SWITCH: Disable all hooks if env variable set
|
|
30
|
+
if [[ "${SPECWEAVE_DISABLE_HOOKS:-0}" == "1" ]]; then
|
|
31
|
+
exit 0
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
# Find project root
|
|
35
|
+
find_project_root() {
|
|
36
|
+
local dir="$PWD"
|
|
37
|
+
while [[ "$dir" != "/" ]]; do
|
|
38
|
+
if [[ -d "$dir/.specweave" ]]; then
|
|
39
|
+
echo "$dir"
|
|
40
|
+
return 0
|
|
41
|
+
fi
|
|
42
|
+
dir=$(dirname "$dir")
|
|
43
|
+
done
|
|
44
|
+
echo "$PWD"
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
PROJECT_ROOT=$(find_project_root)
|
|
48
|
+
STATE_DIR="$PROJECT_ROOT/.specweave/state"
|
|
49
|
+
LOGS_DIR="$PROJECT_ROOT/.specweave/logs"
|
|
50
|
+
DEBUG_LOG="$LOGS_DIR/hooks-debug.log"
|
|
51
|
+
PENDING_FILE="$STATE_DIR/.pending-status-update"
|
|
52
|
+
METRICS_FILE="$STATE_DIR/hook-metrics.jsonl"
|
|
53
|
+
|
|
54
|
+
# Ensure directories exist
|
|
55
|
+
mkdir -p "$STATE_DIR" "$LOGS_DIR" 2>/dev/null || true
|
|
56
|
+
|
|
57
|
+
# ============================================================================
|
|
58
|
+
# TIER 2: Extract File Path from Tool Arguments
|
|
59
|
+
# ============================================================================
|
|
60
|
+
# PreToolUse should have access to tool arguments BEFORE execution
|
|
61
|
+
# Try multiple methods to extract file_path
|
|
62
|
+
|
|
63
|
+
FILE_PATH=""
|
|
64
|
+
|
|
65
|
+
# Method 1: TOOL_USE_ARGS environment variable (primary for PreToolUse)
|
|
66
|
+
if [[ -n "${TOOL_USE_ARGS:-}" ]]; then
|
|
67
|
+
# Try to parse JSON with jq if available
|
|
68
|
+
if command -v jq &> /dev/null; then
|
|
69
|
+
FILE_PATH=$(echo "$TOOL_USE_ARGS" | jq -r '.file_path // empty' 2>/dev/null || echo "")
|
|
70
|
+
fi
|
|
71
|
+
|
|
72
|
+
# Fallback: Regex extraction if jq not available or failed
|
|
73
|
+
if [[ -z "$FILE_PATH" ]]; then
|
|
74
|
+
FILE_PATH=$(echo "$TOOL_USE_ARGS" | grep -o '"file_path"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*"\([^"]*\)".*/\1/' || echo "")
|
|
75
|
+
fi
|
|
76
|
+
fi
|
|
77
|
+
|
|
78
|
+
# Method 2: TOOL_USE_CONTENT (fallback)
|
|
79
|
+
if [[ -z "$FILE_PATH" ]] && [[ -n "${TOOL_USE_CONTENT:-}" ]]; then
|
|
80
|
+
FILE_PATH="$TOOL_USE_CONTENT"
|
|
81
|
+
fi
|
|
82
|
+
|
|
83
|
+
# Method 3: Parse from stdin (last resort - experimental)
|
|
84
|
+
if [[ -z "$FILE_PATH" ]] && [[ ! -t 0 ]]; then
|
|
85
|
+
# Read stdin and try to extract file_path
|
|
86
|
+
STDIN_DATA=$(cat 2>/dev/null || echo "")
|
|
87
|
+
if [[ -n "$STDIN_DATA" ]] && command -v jq &> /dev/null; then
|
|
88
|
+
FILE_PATH=$(echo "$STDIN_DATA" | jq -r '.file_path // empty' 2>/dev/null || echo "")
|
|
89
|
+
fi
|
|
90
|
+
fi
|
|
91
|
+
|
|
92
|
+
# ============================================================================
|
|
93
|
+
# TIER 2: Signal Detection and Validation
|
|
94
|
+
# ============================================================================
|
|
95
|
+
|
|
96
|
+
# Log what we detected (for debugging PreToolUse effectiveness)
|
|
97
|
+
if [[ -n "$FILE_PATH" ]]; then
|
|
98
|
+
echo "[$(date)] pre-write-spec: Detected file_path: $FILE_PATH" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
99
|
+
else
|
|
100
|
+
echo "[$(date)] pre-write-spec: No file_path detected (will fall back to Tier 1)" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
101
|
+
exit 0 # Let PostToolUse handle it with mtime fallback
|
|
102
|
+
fi
|
|
103
|
+
|
|
104
|
+
# Check if this is a spec.md or tasks.md file in increments folder
|
|
105
|
+
IS_SPEC_FILE=false
|
|
106
|
+
if [[ "$FILE_PATH" == *"/spec.md" ]] || [[ "$FILE_PATH" == *"/tasks.md" ]]; then
|
|
107
|
+
if [[ "$FILE_PATH" == *"/.specweave/increments/"* ]]; then
|
|
108
|
+
# Exclude archived increments
|
|
109
|
+
if [[ "$FILE_PATH" != *"/_archive/"* ]]; then
|
|
110
|
+
IS_SPEC_FILE=true
|
|
111
|
+
fi
|
|
112
|
+
fi
|
|
113
|
+
fi
|
|
114
|
+
|
|
115
|
+
# If not a spec/tasks file, exit silently (no signal to PostToolUse)
|
|
116
|
+
if [[ "$IS_SPEC_FILE" != "true" ]]; then
|
|
117
|
+
echo "[$(date)] pre-write-spec: Not a spec/tasks file - no signal" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
118
|
+
exit 0
|
|
119
|
+
fi
|
|
120
|
+
|
|
121
|
+
# ============================================================================
|
|
122
|
+
# TIER 2: Write Signal for PostToolUse Hook
|
|
123
|
+
# ============================================================================
|
|
124
|
+
|
|
125
|
+
# Write file path to pending file for PostToolUse to consume
|
|
126
|
+
echo "$FILE_PATH" > "$PENDING_FILE" 2>/dev/null || true
|
|
127
|
+
|
|
128
|
+
echo "[$(date)] pre-write-spec: Signaled PostToolUse for: $FILE_PATH" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
129
|
+
|
|
130
|
+
# ============================================================================
|
|
131
|
+
# TIER 2: Metrics Collection
|
|
132
|
+
# ============================================================================
|
|
133
|
+
|
|
134
|
+
# Record metrics (JSONL format - one JSON object per line)
|
|
135
|
+
TIMESTAMP=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
136
|
+
METRIC_ENTRY="{\"timestamp\":\"$TIMESTAMP\",\"hook\":\"pre-write-spec\",\"event\":\"file_detected\",\"file_path\":\"$FILE_PATH\",\"method\":\"TOOL_USE_ARGS\"}"
|
|
137
|
+
|
|
138
|
+
# Append to metrics file (JSONL)
|
|
139
|
+
echo "$METRIC_ENTRY" >> "$METRICS_FILE" 2>/dev/null || true
|
|
140
|
+
|
|
141
|
+
# Log rotation for metrics (keep last 1000 entries)
|
|
142
|
+
if [[ -f "$METRICS_FILE" ]]; then
|
|
143
|
+
LINE_COUNT=$(wc -l < "$METRICS_FILE" 2>/dev/null || echo 0)
|
|
144
|
+
if (( LINE_COUNT > 1000 )); then
|
|
145
|
+
tail -1000 "$METRICS_FILE" > "$METRICS_FILE.tmp" 2>/dev/null || true
|
|
146
|
+
mv "$METRICS_FILE.tmp" "$METRICS_FILE" 2>/dev/null || true
|
|
147
|
+
fi
|
|
148
|
+
fi
|
|
149
|
+
|
|
150
|
+
# ALWAYS exit 0 - NEVER let hook errors crash Claude Code
|
|
151
|
+
exit 0
|