specweave 1.0.30 → 1.0.32

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.
Files changed (79) hide show
  1. package/CLAUDE.md +140 -1235
  2. package/bin/specweave.js +23 -0
  3. package/dist/plugins/specweave-github/lib/github-client-v2.d.ts +3 -0
  4. package/dist/plugins/specweave-github/lib/github-client-v2.d.ts.map +1 -1
  5. package/dist/plugins/specweave-github/lib/github-client-v2.js +39 -0
  6. package/dist/plugins/specweave-github/lib/github-client-v2.js.map +1 -1
  7. package/dist/src/cli/commands/set-sync-target.d.ts +41 -0
  8. package/dist/src/cli/commands/set-sync-target.d.ts.map +1 -0
  9. package/dist/src/cli/commands/set-sync-target.js +126 -0
  10. package/dist/src/cli/commands/set-sync-target.js.map +1 -0
  11. package/dist/src/cli/helpers/issue-tracker/github-multi-repo.d.ts.map +1 -1
  12. package/dist/src/cli/helpers/issue-tracker/github-multi-repo.js +5 -8
  13. package/dist/src/cli/helpers/issue-tracker/github-multi-repo.js.map +1 -1
  14. package/dist/src/core/hooks/HookScanner.d.ts +32 -0
  15. package/dist/src/core/hooks/HookScanner.d.ts.map +1 -1
  16. package/dist/src/core/hooks/HookScanner.js +125 -1
  17. package/dist/src/core/hooks/HookScanner.js.map +1 -1
  18. package/dist/src/core/hooks/types.d.ts +10 -1
  19. package/dist/src/core/hooks/types.d.ts.map +1 -1
  20. package/dist/src/core/increment/metadata-manager.d.ts +67 -1
  21. package/dist/src/core/increment/metadata-manager.d.ts.map +1 -1
  22. package/dist/src/core/increment/metadata-manager.js +93 -0
  23. package/dist/src/core/increment/metadata-manager.js.map +1 -1
  24. package/dist/src/core/project/index.d.ts +21 -0
  25. package/dist/src/core/project/index.d.ts.map +1 -0
  26. package/dist/src/core/project/index.js +22 -0
  27. package/dist/src/core/project/index.js.map +1 -0
  28. package/dist/src/core/project/project-service.d.ts +122 -0
  29. package/dist/src/core/project/project-service.d.ts.map +1 -0
  30. package/dist/src/core/project/project-service.js +334 -0
  31. package/dist/src/core/project/project-service.js.map +1 -0
  32. package/dist/src/core/sync/external-tool-resolver.d.ts +171 -0
  33. package/dist/src/core/sync/external-tool-resolver.d.ts.map +1 -0
  34. package/dist/src/core/sync/external-tool-resolver.js +569 -0
  35. package/dist/src/core/sync/external-tool-resolver.js.map +1 -0
  36. package/dist/src/core/types/increment-metadata.d.ts +92 -0
  37. package/dist/src/core/types/increment-metadata.d.ts.map +1 -1
  38. package/dist/src/hooks/processor.d.ts +7 -3
  39. package/dist/src/hooks/processor.d.ts.map +1 -1
  40. package/dist/src/hooks/processor.js +11 -5
  41. package/dist/src/hooks/processor.js.map +1 -1
  42. package/package.json +1 -1
  43. package/plugins/specweave/hooks/hooks.json +0 -69
  44. package/plugins/specweave/hooks/v2/handlers/project-bridge-handler.sh +96 -0
  45. package/plugins/specweave/hooks/v2/queue/processor.sh +13 -5
  46. package/plugins/specweave/lib/hooks/project-bridge.js +76 -0
  47. package/plugins/specweave/lib/hooks/update-tasks-md.js +0 -0
  48. package/plugins/specweave/lib/hooks/us-completion-orchestrator.js +0 -0
  49. package/plugins/specweave/lib/vendor/core/increment/metadata-manager.d.ts +67 -1
  50. package/plugins/specweave/lib/vendor/core/increment/metadata-manager.js +93 -0
  51. package/plugins/specweave/lib/vendor/core/increment/metadata-manager.js.map +1 -1
  52. package/plugins/specweave/lib/vendor/core/types/increment-metadata.d.ts +92 -0
  53. package/plugins/specweave-github/lib/github-client-v2.js +39 -0
  54. package/plugins/specweave-github/lib/github-client-v2.ts +44 -0
  55. package/plugins/specweave/hooks/docs-changed.sh +0 -87
  56. package/plugins/specweave/hooks/human-input-required.sh +0 -83
  57. package/plugins/specweave/hooks/post-edit-write-consolidated.sh +0 -428
  58. package/plugins/specweave/hooks/post-first-increment.sh +0 -61
  59. package/plugins/specweave/hooks/post-increment-change.sh +0 -103
  60. package/plugins/specweave/hooks/post-increment-completion.sh +0 -513
  61. package/plugins/specweave/hooks/post-increment-planning.sh +0 -1204
  62. package/plugins/specweave/hooks/post-increment-status-change.sh +0 -243
  63. package/plugins/specweave/hooks/post-metadata-change.sh +0 -246
  64. package/plugins/specweave/hooks/post-spec-update.sh +0 -158
  65. package/plugins/specweave/hooks/post-task-completion.sh +0 -557
  66. package/plugins/specweave/hooks/post-task-edit.sh +0 -47
  67. package/plugins/specweave/hooks/post-user-story-complete.sh +0 -230
  68. package/plugins/specweave/hooks/pre-command-deduplication.sh +0 -68
  69. package/plugins/specweave/hooks/pre-edit-write-consolidated.sh +0 -225
  70. package/plugins/specweave/hooks/pre-implementation.sh +0 -75
  71. package/plugins/specweave/hooks/pre-increment-start.sh +0 -173
  72. package/plugins/specweave/hooks/pre-task-completion-edit.sh +0 -355
  73. package/plugins/specweave/hooks/pre-task-completion.sh +0 -269
  74. package/plugins/specweave/hooks/pre-tool-use.sh +0 -137
  75. package/plugins/specweave/hooks/session-start-reconcile.sh +0 -139
  76. package/plugins/specweave/hooks/shared/bulk-operation-detector.sh +0 -167
  77. package/plugins/specweave/hooks/test-pretooluse-env.sh +0 -72
  78. package/plugins/specweave/hooks/validate-increment-completion.sh +0 -113
  79. package/plugins/specweave/lib/hooks/consolidated-sync.js +0 -288
@@ -1,428 +0,0 @@
1
- #!/bin/bash
2
- #
3
- # Post-Edit/Write Consolidated Hook: Update Status Line After spec.md or tasks.md Changes
4
- #
5
- # Purpose: Unified hook for both Edit and Write tools
6
- # Triggers: After Edit/Write modifies spec.md (AC updates) or tasks.md (task completion)
7
- # Action: Updates status line cache to reflect latest AC/task progress
8
- #
9
- # CONSOLIDATION (v0.25.0):
10
- # - Replaces post-edit-spec.sh and post-write-spec.sh (identical code)
11
- # - Reduces hook overhead by 50% (2 post-hooks → 1)
12
- # - Single point of maintenance
13
- # - Combined with pre-edit-write-consolidated.sh, reduces 4 hooks → 2 hooks
14
- #
15
- # This ensures status line stays in sync when ACs are marked complete via Edit tool
16
- # (not just TodoWrite, which only tracks internal todo lists)
17
- #
18
- # EMERGENCY FIXES (v0.24.3):
19
- # - Kill switch: Set SPECWEAVE_DISABLE_HOOKS=1 to disable ALL hooks
20
- # - Circuit breaker: Auto-disable after 3 consecutive failures
21
- # - File locking: Prevent concurrent executions (max 1 at a time)
22
- # - Aggressive debouncing: Increased from 1s to 5s
23
- # - Complete error isolation: Never let errors reach Claude Code
24
- #
25
- # TIER 1 IMPROVEMENTS (v0.24.2):
26
- # - Debouncing: Skip if updated less than 5 seconds ago (90% overhead reduction)
27
- # - File mtime detection: Check recently modified spec.md/tasks.md as fallback
28
- # - Non-blocking: Run update-status-line.sh in background
29
- # - Smart detection: Only update if spec/tasks files actually changed
30
- #
31
- # Previous fix (v0.24.1): Enhanced file detection for increment completion
32
- # - Detects changes via TOOL_USE_CONTENT, TOOL_RESULT, and argument parsing
33
- # - Always updates status line for ANY spec.md/tasks.md change in increments folder
34
-
35
- # CRITICAL: Remove set -e to prevent hook errors from crashing Claude Code
36
- set +e
37
-
38
- # Find project root (must be BEFORE recursion guard to get PROJECT_ROOT)
39
- find_project_root() {
40
- local dir="$PWD"
41
- while [[ "$dir" != "/" ]]; do
42
- if [[ -d "$dir/.specweave" ]]; then
43
- echo "$dir"
44
- return 0
45
- fi
46
- dir=$(dirname "$dir")
47
- done
48
- echo "$PWD"
49
- }
50
-
51
- PROJECT_ROOT=$(find_project_root)
52
-
53
- # ULTRA-FAST EARLY EXIT FOR NON-SPECWEAVE PROJECTS (T-006 - v0.26.15)
54
- if [[ ! -d "$PROJECT_ROOT/.specweave" ]]; then
55
- exit 0
56
- fi
57
-
58
- LOGS_DIR="$PROJECT_ROOT/.specweave/logs"
59
- DEBUG_LOG="$LOGS_DIR/hooks-debug.log"
60
-
61
- # ============================================================================
62
- # RECURSION PREVENTION (CRITICAL - v0.26.0 - FILE-BASED GUARD)
63
- # ============================================================================
64
- # PROBLEM: Hooks that write files trigger other hooks, causing infinite loops.
65
- # OLD SOLUTION (v0.25.1): Environment variable SPECWEAVE_IN_HOOK=1
66
- # WHY IT FAILED: Background processes (&) create NEW shells that don't inherit env vars!
67
- #
68
- # NEW SOLUTION (v0.26.0): File-based recursion guard
69
- # - Guard file exists = already inside hook chain
70
- # - Works across ALL processes (not just current shell)
71
- # - Atomic operation (mkdir -p ensures thread safety)
72
- # - Cleanup guaranteed by trap EXIT
73
- #
74
- # See: .specweave/increments/0051-*/reports/GITHUB-COMMENT-RECURSION-ROOT-CAUSE-2025-11-24.md
75
- # See: ADR-0073 (Hook Recursion Prevention Strategy)
76
-
77
- RECURSION_GUARD_FILE="$PROJECT_ROOT/.specweave/state/.hook-recursion-guard"
78
-
79
- if [[ -f "$RECURSION_GUARD_FILE" ]]; then
80
- # Silent exit - we're already inside a hook chain
81
- # This is NORMAL and prevents recursion (not an error!)
82
- exit 0
83
- fi
84
-
85
- # Don't create guard file here - we only CHECK it
86
- # Guard file is ONLY created by post-task-completion.sh (the entry point)
87
- # All other hooks just check for its existence
88
-
89
- # EMERGENCY KILL SWITCH: Disable all hooks if env variable set
90
- if [[ "${SPECWEAVE_DISABLE_HOOKS:-0}" == "1" ]]; then
91
- exit 0
92
- fi
93
-
94
- # Ensure state and logs directories exist
95
- mkdir -p "$PROJECT_ROOT/.specweave/state" "$LOGS_DIR" 2>/dev/null || true
96
-
97
- # EMERGENCY CIRCUIT BREAKER: Track consecutive failures
98
- CIRCUIT_BREAKER_FILE="$PROJECT_ROOT/.specweave/state/.hook-circuit-breaker"
99
- CIRCUIT_BREAKER_THRESHOLD=3
100
-
101
- if [[ -f "$CIRCUIT_BREAKER_FILE" ]]; then
102
- FAILURE_COUNT=$(cat "$CIRCUIT_BREAKER_FILE" 2>/dev/null || echo 0)
103
- if (( FAILURE_COUNT >= CIRCUIT_BREAKER_THRESHOLD )); then
104
- echo "[$(date)] CIRCUIT BREAKER OPEN: Hooks disabled after $FAILURE_COUNT failures. Run: rm $CIRCUIT_BREAKER_FILE" >> "$DEBUG_LOG" 2>/dev/null || true
105
- exit 0
106
- fi
107
- fi
108
-
109
- # EMERGENCY FILE LOCK: Prevent concurrent executions
110
- LOCK_FILE="$PROJECT_ROOT/.specweave/state/.hook-post-edit-write.lock"
111
- LOCK_TIMEOUT=5 # seconds
112
-
113
- # Try to acquire lock with timeout
114
- LOCK_ACQUIRED=false
115
- for i in {1..5}; do
116
- if mkdir "$LOCK_FILE" 2>/dev/null; then
117
- LOCK_ACQUIRED=true
118
- trap 'rmdir "$LOCK_FILE" 2>/dev/null || true' EXIT
119
- break
120
- fi
121
-
122
- # Check if lock is stale (older than LOCK_TIMEOUT seconds)
123
- if [[ -d "$LOCK_FILE" ]]; then
124
- LOCK_AGE=$(($(date +%s) - $(stat -f "%m" "$LOCK_FILE" 2>/dev/null || echo 0)))
125
- if (( LOCK_AGE > LOCK_TIMEOUT )); then
126
- rmdir "$LOCK_FILE" 2>/dev/null || true
127
- continue
128
- fi
129
- fi
130
-
131
- sleep 0.2
132
- done
133
-
134
- if [[ "$LOCK_ACQUIRED" == "false" ]]; then
135
- echo "[$(date)] post-edit-write: Could not acquire lock, skipping" >> "$DEBUG_LOG" 2>/dev/null || true
136
- exit 0
137
- fi
138
-
139
- # Log rotation: Keep debug log under 100KB
140
- if [[ -f "$DEBUG_LOG" ]] && [[ $(wc -c < "$DEBUG_LOG" 2>/dev/null || echo 0) -gt 102400 ]]; then
141
- tail -100 "$DEBUG_LOG" > "$DEBUG_LOG.tmp" 2>/dev/null || true
142
- mv "$DEBUG_LOG.tmp" "$DEBUG_LOG" 2>/dev/null || true
143
- echo "[$(date)] Log rotated" >> "$DEBUG_LOG" 2>/dev/null || true
144
- fi
145
-
146
- # ============================================================================
147
- # BURST WRITE DETECTION (v0.26.2 - Prevent Write Storms)
148
- # ============================================================================
149
- # Problem: Architect agent creating multiple ADRs in one response (6+ writes/minute)
150
- # Solution: Detect burst writes and throttle if necessary
151
- # Incident: 2025-11-24 (Increment 0052 - architect created 6 ADRs at once)
152
- BURST_TIMESTAMPS_FILE="$PROJECT_ROOT/.specweave/state/.write-timestamps"
153
- BURST_WINDOW=10 # seconds
154
- BURST_THRESHOLD=5 # max writes in window
155
- BURST_THROTTLE=2 # seconds to wait if burst detected
156
-
157
- # Record this write timestamp
158
- mkdir -p "$(dirname "$BURST_TIMESTAMPS_FILE")" 2>/dev/null || true
159
- echo "$(date +%s)" >> "$BURST_TIMESTAMPS_FILE" 2>/dev/null || true
160
-
161
- # Count writes in the last BURST_WINDOW seconds
162
- if [[ -f "$BURST_TIMESTAMPS_FILE" ]]; then
163
- NOW=$(date +%s)
164
- CUTOFF=$((NOW - BURST_WINDOW))
165
-
166
- # Clean up old timestamps (older than BURST_WINDOW)
167
- grep -v "^$" "$BURST_TIMESTAMPS_FILE" 2>/dev/null | \
168
- awk -v cutoff="$CUTOFF" '$1 > cutoff' > "$BURST_TIMESTAMPS_FILE.tmp" 2>/dev/null || true
169
- mv "$BURST_TIMESTAMPS_FILE.tmp" "$BURST_TIMESTAMPS_FILE" 2>/dev/null || true
170
-
171
- # Count recent writes
172
- RECENT_WRITES=$(wc -l < "$BURST_TIMESTAMPS_FILE" 2>/dev/null || echo 0)
173
-
174
- if (( RECENT_WRITES > BURST_THRESHOLD )); then
175
- echo "[$(date)] ⚠️ BURST DETECTED: $RECENT_WRITES writes in ${BURST_WINDOW}s (threshold: $BURST_THRESHOLD)" >> "$DEBUG_LOG" 2>/dev/null || true
176
- echo "[$(date)] Throttling for ${BURST_THROTTLE}s to prevent overload..." >> "$DEBUG_LOG" 2>/dev/null || true
177
- sleep "$BURST_THROTTLE"
178
- fi
179
- fi
180
-
181
- # ============================================================================
182
- # TIER 1 FIX: Debouncing (Prevent Redundant Updates)
183
- # ============================================================================
184
- # Skip update if we updated less than 5 seconds ago (INCREASED FROM 1s)
185
- # This handles rapid consecutive changes (e.g., 10 tasks marked complete quickly)
186
- LAST_UPDATE_FILE="$PROJECT_ROOT/.specweave/state/.last-status-update"
187
- DEBOUNCE_SECONDS=5
188
-
189
- if [[ -f "$LAST_UPDATE_FILE" ]]; then
190
- LAST_UPDATE=$(cat "$LAST_UPDATE_FILE" 2>/dev/null || echo 0)
191
- NOW=$(date +%s)
192
- TIME_SINCE_UPDATE=$((NOW - LAST_UPDATE))
193
-
194
- if (( TIME_SINCE_UPDATE < DEBOUNCE_SECONDS )); then
195
- echo "[$(date)] post-edit-write: Debounced (${TIME_SINCE_UPDATE}s since last update)" >> "$DEBUG_LOG" 2>/dev/null || true
196
- exit 0 # Skip this update
197
- fi
198
- fi
199
-
200
- # ============================================================================
201
- # TIER 2: Check for PreToolUse Signal (Primary Detection Method)
202
- # ============================================================================
203
- PENDING_FILE="$PROJECT_ROOT/.specweave/state/.pending-status-update"
204
- METRICS_FILE="$PROJECT_ROOT/.specweave/state/hook-metrics.jsonl"
205
- DETECTED_FILE=""
206
- DETECTION_METHOD="none"
207
-
208
- # First, check if PreToolUse hook left a signal
209
- if [[ -f "$PENDING_FILE" ]]; then
210
- DETECTED_FILE=$(cat "$PENDING_FILE" 2>/dev/null || echo "")
211
- # Delete pending file immediately (consume signal)
212
- rm "$PENDING_FILE" 2>/dev/null || true
213
-
214
- if [[ -n "$DETECTED_FILE" ]]; then
215
- DETECTION_METHOD="pretooluse"
216
- echo "[$(date)] post-edit-write: File from PreToolUse signal: $DETECTED_FILE" >> "$DEBUG_LOG" 2>/dev/null || true
217
-
218
- # Record Tier 2 success metric
219
- TIMESTAMP=$(date -u +%Y-%m-%dT%H:%M:%SZ)
220
- echo "{\"timestamp\":\"$TIMESTAMP\",\"hook\":\"post-edit-write\",\"event\":\"tier2_success\",\"method\":\"pretooluse\"}" >> "$METRICS_FILE" 2>/dev/null || true
221
- fi
222
- fi
223
-
224
- # ============================================================================
225
- # TIER 1 FALLBACK: Environment Variable Detection
226
- # ============================================================================
227
- # If PreToolUse didn't provide signal, fall back to Tier 1 methods
228
- if [[ -z "$DETECTED_FILE" ]]; then
229
- # Method 1: TOOL_USE_CONTENT environment variable
230
- if [[ -n "${TOOL_USE_CONTENT:-}" ]]; then
231
- DETECTED_FILE="$TOOL_USE_CONTENT"
232
- DETECTION_METHOD="env_content"
233
- fi
234
-
235
- # Method 2: TOOL_RESULT environment variable
236
- if [[ -z "$DETECTED_FILE" ]] && [[ -n "${TOOL_RESULT:-}" ]]; then
237
- DETECTED_FILE=$(echo "$TOOL_RESULT" | grep -o '"file_path"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*"\([^"]*\)".*/\1/' || echo "")
238
- DETECTION_METHOD="env_result"
239
- fi
240
-
241
- # Method 3: TOOL_USE_ARGS
242
- if [[ -z "$DETECTED_FILE" ]] && [[ -n "${TOOL_USE_ARGS:-}" ]]; then
243
- DETECTED_FILE=$(echo "$TOOL_USE_ARGS" | grep -o '"file_path"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*"\([^"]*\)".*/\1/' || echo "")
244
- DETECTION_METHOD="env_args"
245
- fi
246
-
247
- # Log env var detection (for metrics)
248
- if [[ -n "$DETECTED_FILE" ]]; then
249
- echo "[$(date)] post-edit-write: File from env vars ($DETECTION_METHOD): $DETECTED_FILE" >> "$DEBUG_LOG" 2>/dev/null || true
250
- fi
251
- fi
252
-
253
- # Check if we detected a spec.md or tasks.md change in increments folder
254
- SHOULD_UPDATE=false
255
-
256
- if [[ -n "$DETECTED_FILE" ]]; then
257
- # Check if the file is spec.md or tasks.md
258
- if [[ "$DETECTED_FILE" == *"/spec.md" ]] || [[ "$DETECTED_FILE" == *"/tasks.md" ]]; then
259
- # Check if it's in an increment folder
260
- if [[ "$DETECTED_FILE" == *"/.specweave/increments/"* ]]; then
261
- SHOULD_UPDATE=true
262
- echo "[$(date)] post-edit-write: Increment file changed - will update status line" >> "$DEBUG_LOG" 2>/dev/null || true
263
- fi
264
- fi
265
- fi
266
-
267
- # ============================================================================
268
- # TIER 1 FIX: File Modification Time Detection (Fallback)
269
- # ============================================================================
270
- # If we couldn't detect the file via environment variables, check which files
271
- # were modified recently (within last 2 seconds) instead of blindly updating
272
- if [[ -z "$DETECTED_FILE" ]]; then
273
- echo "[$(date)] post-edit-write: Env vars empty - checking file mtimes" >> "$DEBUG_LOG" 2>/dev/null || true
274
-
275
- NOW=$(date +%s)
276
- INCREMENTS_DIR="$PROJECT_ROOT/.specweave/increments"
277
-
278
- # Check for recently modified spec.md or tasks.md files
279
- if [[ -d "$INCREMENTS_DIR" ]]; then
280
- for file in "$INCREMENTS_DIR"/*/spec.md "$INCREMENTS_DIR"/*/tasks.md; do
281
- if [[ -f "$file" ]]; then
282
- # Get file modification time (platform-specific)
283
- if [[ "$(uname)" == "Darwin" ]]; then
284
- MTIME=$(stat -f "%m" "$file" 2>/dev/null || echo 0)
285
- else
286
- MTIME=$(stat -c "%Y" "$file" 2>/dev/null || echo 0)
287
- fi
288
-
289
- # If file was modified in last 2 seconds, consider it the changed file
290
- TIME_DIFF=$((NOW - MTIME))
291
- if (( TIME_DIFF <= 2 )); then
292
- DETECTED_FILE="$file"
293
- echo "[$(date)] post-edit-write: Detected recent modification: $file (${TIME_DIFF}s ago)" >> "$DEBUG_LOG" 2>/dev/null || true
294
- SHOULD_UPDATE=true
295
- break
296
- fi
297
- fi
298
- done
299
- fi
300
-
301
- # If still no file detected, skip update (not a spec/tasks change)
302
- if [[ -z "$DETECTED_FILE" ]]; then
303
- echo "[$(date)] post-edit-write: No spec/tasks modifications detected - skipping" >> "$DEBUG_LOG" 2>/dev/null || true
304
- exit 0
305
- fi
306
- fi
307
-
308
- # ============================================================================
309
- # LIVING DOCS SYNC FOR NEW INCREMENTS (v0.27.1 - Critical Fix)
310
- # ============================================================================
311
- # When a NEW spec.md is created, trigger living docs sync to create FS-XXX folder.
312
- # This was previously in post-increment-planning.sh (hooks.json) but hooks.json
313
- # is NOT used - plugin.json is the active config and it only calls this script.
314
- #
315
- # Detection: spec.md in increment folder + no FS-XXX folder in living docs yet
316
- # See: Incident 2025-11-24 (FS-061 not created automatically)
317
-
318
- if [[ "$SHOULD_UPDATE" == "true" ]] && [[ "$DETECTED_FILE" == *"/spec.md" ]]; then
319
- # Extract increment ID from path (e.g., 0061-fix-multi-repo-init-ux)
320
- INCREMENT_ID=$(echo "$DETECTED_FILE" | grep -o '[0-9][0-9][0-9][0-9]-[^/]*' | head -1)
321
-
322
- if [[ -n "$INCREMENT_ID" ]]; then
323
- # Extract feature_id from spec.md frontmatter
324
- FEATURE_ID=$(awk '
325
- BEGIN { in_frontmatter=0 }
326
- /^---$/ {
327
- if (in_frontmatter == 0) { in_frontmatter=1; next }
328
- else { exit }
329
- }
330
- in_frontmatter == 1 && /^feature_id:/ {
331
- gsub(/^feature_id:[ \t]*/, "");
332
- gsub(/["'"'"']/, "");
333
- print;
334
- exit
335
- }
336
- ' "$DETECTED_FILE" 2>/dev/null | tr -d '\r\n')
337
-
338
- # Check if living docs folder exists for this feature
339
- LIVING_DOCS_PATH="$PROJECT_ROOT/.specweave/docs/internal/specs"
340
- FEATURE_FOLDER_EXISTS=false
341
-
342
- if [[ -n "$FEATURE_ID" ]]; then
343
- # Check in all project subfolders (multi-project support)
344
- for project_dir in "$LIVING_DOCS_PATH"/*; do
345
- if [[ -d "$project_dir/$FEATURE_ID" ]]; then
346
- FEATURE_FOLDER_EXISTS=true
347
- break
348
- fi
349
- done
350
- fi
351
-
352
- if [[ "$FEATURE_FOLDER_EXISTS" == "false" ]]; then
353
- echo "[$(date)] post-edit-write: NEW increment detected ($INCREMENT_ID) - triggering living docs sync" >> "$DEBUG_LOG" 2>/dev/null || true
354
-
355
- # Find sync script (same logic as post-increment-planning.sh)
356
- SYNC_SCRIPT=""
357
- if [[ -f "$PROJECT_ROOT/plugins/specweave/lib/hooks/sync-living-docs.js" ]]; then
358
- SYNC_SCRIPT="$PROJECT_ROOT/plugins/specweave/lib/hooks/sync-living-docs.js"
359
- elif [[ -f "$PROJECT_ROOT/dist/plugins/specweave/lib/hooks/sync-living-docs.js" ]]; then
360
- SYNC_SCRIPT="$PROJECT_ROOT/dist/plugins/specweave/lib/hooks/sync-living-docs.js"
361
- elif [[ -n "${CLAUDE_PLUGIN_ROOT:-}" ]] && [[ -f "${CLAUDE_PLUGIN_ROOT}/lib/hooks/sync-living-docs.js" ]]; then
362
- SYNC_SCRIPT="${CLAUDE_PLUGIN_ROOT}/lib/hooks/sync-living-docs.js"
363
- fi
364
-
365
- if [[ -n "$SYNC_SCRIPT" ]]; then
366
- # Run living docs sync in background (non-blocking)
367
- (
368
- set +e
369
- cd "$PROJECT_ROOT" || exit 0
370
-
371
- if [[ -n "$FEATURE_ID" ]]; then
372
- FEATURE_ID="$FEATURE_ID" node "$SYNC_SCRIPT" "$INCREMENT_ID" >> "$DEBUG_LOG" 2>&1
373
- else
374
- node "$SYNC_SCRIPT" "$INCREMENT_ID" >> "$DEBUG_LOG" 2>&1
375
- fi
376
-
377
- if [[ $? -eq 0 ]]; then
378
- echo "[$(date)] post-edit-write: Living docs sync completed for $INCREMENT_ID" >> "$DEBUG_LOG" 2>/dev/null || true
379
- else
380
- echo "[$(date)] post-edit-write: Living docs sync FAILED for $INCREMENT_ID (non-blocking)" >> "$DEBUG_LOG" 2>/dev/null || true
381
- fi
382
- ) &
383
- disown 2>/dev/null || true
384
-
385
- echo "[$(date)] post-edit-write: Living docs sync triggered in background" >> "$DEBUG_LOG" 2>/dev/null || true
386
- else
387
- echo "[$(date)] post-edit-write: sync-living-docs.js not found - skipping living docs sync" >> "$DEBUG_LOG" 2>/dev/null || true
388
- fi
389
- else
390
- echo "[$(date)] post-edit-write: Living docs folder already exists for $FEATURE_ID - skipping sync" >> "$DEBUG_LOG" 2>/dev/null || true
391
- fi
392
- fi
393
- fi
394
-
395
- # ============================================================================
396
- # TIER 1 FIX: Non-Blocking Background Update with COMPLETE ERROR ISOLATION
397
- # ============================================================================
398
- # Update status line if needed
399
- if [[ "$SHOULD_UPDATE" == "true" ]]; then
400
- echo "[$(date)] post-edit-write: Running update-status-line.sh (background)" >> "$DEBUG_LOG" 2>/dev/null || true
401
-
402
- # Record update time BEFORE spawning background process
403
- # This ensures debouncing works even if update hasn't completed yet
404
- echo "$(date +%s)" > "$LAST_UPDATE_FILE"
405
-
406
- # Run status line update in background with COMPLETE error isolation
407
- # This prevents Edit/Write tool from waiting for status line computation
408
- (
409
- set +e # Disable error propagation
410
-
411
- if "$PROJECT_ROOT/plugins/specweave/hooks/lib/update-status-line.sh" 2>&1 | tee -a "$DEBUG_LOG" >/dev/null; then
412
- echo "[$(date)] post-edit-write: Status line updated successfully" >> "$DEBUG_LOG" 2>/dev/null || true
413
- # Reset circuit breaker on success
414
- echo "0" > "$CIRCUIT_BREAKER_FILE" 2>/dev/null || true
415
- else
416
- echo "[$(date)] post-edit-write: Warning - status line update failed (non-blocking)" >> "$DEBUG_LOG" 2>/dev/null || true
417
- # Increment circuit breaker
418
- CURRENT_FAILURES=$(cat "$CIRCUIT_BREAKER_FILE" 2>/dev/null || echo 0)
419
- echo "$((CURRENT_FAILURES + 1))" > "$CIRCUIT_BREAKER_FILE" 2>/dev/null || true
420
- fi
421
- ) &
422
-
423
- # Disown the background process so it's not killed when hook exits
424
- disown 2>/dev/null || true
425
- fi
426
-
427
- # Always exit 0 to prevent hook errors from crashing Claude Code
428
- exit 0
@@ -1,61 +0,0 @@
1
- #!/usr/bin/env bash
2
- # SpecWeave Post-First-Increment Hook
3
- #
4
- # Triggers after the first increment is completed
5
- # Congratulates the user on completing their first increment
6
- #
7
- # NON-INTERACTIVE: Just shows a message (hooks run in background)
8
-
9
- set +e # EMERGENCY FIX: Changed from set -euo pipefail to prevent Claude Code crashes
10
-
11
- # Get project root (where .specweave/ lives)
12
- PROJECT_ROOT="$(pwd)"
13
-
14
- # Check if .specweave directory exists
15
- if [ ! -d ".specweave" ]; then
16
- # Not in SpecWeave project, skip
17
- exit 0
18
- fi
19
-
20
- # Check if this is the first increment completion
21
- # Count completed increments in .specweave/increments/
22
- COMPLETED_COUNT=0
23
- if [ -d ".specweave/increments" ]; then
24
- # Count directories that have COMPLETION-REPORT.md or completion metadata
25
- for inc_dir in .specweave/increments/[0-9][0-9][0-9][0-9]-*/; do
26
- if [ -d "$inc_dir" ]; then
27
- if [ -f "${inc_dir}reports/COMPLETION-REPORT.md" ] || \
28
- [ -f "${inc_dir}COMPLETION-SUMMARY.md" ] || \
29
- ([ -f "${inc_dir}metadata.json" ] && grep -q '"status".*"completed"' "${inc_dir}metadata.json" 2>/dev/null); then
30
- COMPLETED_COUNT=$((COMPLETED_COUNT + 1))
31
- fi
32
- fi
33
- done
34
- fi
35
-
36
- # Only trigger on first completion
37
- if [ "$COMPLETED_COUNT" -ne 1 ]; then
38
- exit 0
39
- fi
40
-
41
- # Show congratulations message (non-interactive)
42
- echo ""
43
- echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
44
- echo "🎉 Congratulations! You completed your first increment!"
45
- echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
46
- echo ""
47
- echo "✅ Your increment has been documented in:"
48
- echo " .specweave/increments/[increment-id]/"
49
- echo ""
50
- echo "📚 View your documentation:"
51
- echo " - Specs: .specweave/docs/internal/specs/"
52
- echo " - Architecture: .specweave/docs/internal/architecture/"
53
- echo ""
54
- echo "🚀 Next steps:"
55
- echo " - Review your increment: /sw:status"
56
- echo " - Start next increment: /sw:increment \"feature name\""
57
- echo ""
58
- echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
59
- echo ""
60
-
61
- exit 0
@@ -1,103 +0,0 @@
1
- #!/bin/bash
2
-
3
- # SpecWeave Post-Increment-Change Hook
4
- # Runs automatically after increment files (spec.md, plan.md, tasks.md) are modified
5
- #
6
- # Trigger: File watcher or git hook (pre-commit/post-commit)
7
- # Purpose: Sync increment file changes to GitHub issues
8
- #
9
- # What it does:
10
- # 1. Detects which file changed (spec.md, plan.md, tasks.md)
11
- # 2. Invokes GitHub sync for increment changes
12
- # 3. Updates GitHub issue with scope/plan/task changes
13
- #
14
- # Usage:
15
- # ./post-increment-change.sh <incrementId> <changedFile>
16
- #
17
- # Example:
18
- # ./post-increment-change.sh 0015-hierarchical-sync spec.md
19
-
20
- set +e # EMERGENCY FIX: Prevents Claude Code crashes
21
-
22
- # EMERGENCY KILL SWITCH
23
- if [[ "${SPECWEAVE_DISABLE_HOOKS:-0}" == "1" ]]; then
24
- exit 0
25
- fi
26
-
27
- # Find project root
28
- find_project_root() {
29
- local dir="$1"
30
- while [ "$dir" != "/" ]; do
31
- if [ -d "$dir/.specweave" ]; then
32
- echo "$dir"
33
- return 0
34
- fi
35
- dir="$(dirname "$dir")"
36
- done
37
- pwd
38
- }
39
-
40
- PROJECT_ROOT="$(find_project_root "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")"
41
- cd "$PROJECT_ROOT" 2>/dev/null || true
42
-
43
- # Configuration
44
- LOGS_DIR=".specweave/logs"
45
- DEBUG_LOG="$LOGS_DIR/hooks-debug.log"
46
-
47
- mkdir -p "$LOGS_DIR" 2>/dev/null || true
48
-
49
- # Arguments
50
- INCREMENT_ID="$1"
51
- CHANGED_FILE="$2"
52
-
53
- if [ -z "$INCREMENT_ID" ] || [ -z "$CHANGED_FILE" ]; then
54
- echo "Usage: $0 <incrementId> <changedFile>" >&2
55
- echo "Example: $0 0015-hierarchical-sync spec.md" >&2
56
- exit 1
57
- fi
58
-
59
- echo "[$(date)] 📝 Increment file changed: $CHANGED_FILE" >> "$DEBUG_LOG" 2>/dev/null || true
60
-
61
- # Validate changed file
62
- case "$CHANGED_FILE" in
63
- spec.md|plan.md|tasks.md)
64
- ;;
65
- *)
66
- echo "[$(date)] ⚠️ Unknown file type: $CHANGED_FILE (skipping sync)" >> "$DEBUG_LOG" 2>/dev/null || true
67
- exit 0
68
- ;;
69
- esac
70
-
71
- # Check if Node.js available
72
- if ! command -v node &> /dev/null; then
73
- echo "[$(date)] ⚠️ Node.js not found, skipping sync" >> "$DEBUG_LOG" 2>/dev/null || true
74
- exit 0
75
- fi
76
-
77
- # Check if GitHub CLI available
78
- if ! command -v gh &> /dev/null; then
79
- echo "[$(date)] ℹ️ GitHub CLI not found, skipping sync" >> "$DEBUG_LOG" 2>/dev/null || true
80
- exit 0
81
- fi
82
-
83
- # Check if authenticated
84
- if ! gh auth status &> /dev/null; then
85
- echo "[$(date)] ℹ️ GitHub CLI not authenticated, skipping sync" >> "$DEBUG_LOG" 2>/dev/null || true
86
- exit 0
87
- fi
88
-
89
- # Sync to GitHub
90
- echo "[$(date)] 🔄 Syncing $CHANGED_FILE changes to GitHub..." >> "$DEBUG_LOG" 2>/dev/null || true
91
-
92
- node dist/plugins/specweave-github/lib/github-sync-increment-changes.js "$INCREMENT_ID" "$CHANGED_FILE" 2>&1 | tee -a "$DEBUG_LOG" >/dev/null || {
93
- echo "[$(date)] ⚠️ Failed to sync increment changes (non-blocking)" >> "$DEBUG_LOG" 2>/dev/null || true
94
- }
95
-
96
- echo "[$(date)] ✅ Post-increment-change hook complete" >> "$DEBUG_LOG" 2>/dev/null || true
97
-
98
- # Update status line cache (increment changed)
99
- HOOK_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
100
- bash "$HOOK_DIR/lib/update-status-line.sh" 2>/dev/null || true
101
-
102
- # Return success (non-blocking)
103
- exit 0