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,269 +0,0 @@
1
- #!/bin/bash
2
-
3
- # SpecWeave Pre-Task-Completion Hook
4
- # CRITICAL QUALITY GATE: Validates AC tests before allowing task completion
5
- #
6
- # Runs automatically BEFORE any task is marked complete via TodoWrite
7
- #
8
- # WORKFLOW:
9
- # =========
10
- # 1. TodoWrite called with status="completed"
11
- # 2. This hook fires (pre-completion validation)
12
- # 3. Extract task ID from TodoWrite input
13
- # 4. Find task in tasks.md
14
- # 5. Run AC test validator
15
- # 6. If tests PASS → Allow completion (continue: true)
16
- # 7. If tests FAIL → Block completion (continue: false, show error)
17
- #
18
- # ENFORCEMENT:
19
- # ============
20
- # This is the ONLY way to mark tasks complete in SpecWeave.
21
- # Manual edits to tasks.md are detected and flagged by pre-commit hooks.
22
-
23
- set +e # EMERGENCY FIX: Prevents Claude Code crashes
24
-
25
- # ============================================================================
26
- # RECURSION PREVENTION (CRITICAL - v0.25.1)
27
- # ============================================================================
28
- # Skip if we're already inside a hook to prevent infinite recursion
29
- if [[ "${SPECWEAVE_IN_HOOK:-0}" == "1" ]]; then
30
- exit 0
31
- fi
32
-
33
- # Mark that we're now inside a hook
34
- export SPECWEAVE_IN_HOOK=1
35
-
36
- # EMERGENCY KILL SWITCH
37
- if [[ "${SPECWEAVE_DISABLE_HOOKS:-0}" == "1" ]]; then
38
- exit 0
39
- fi
40
-
41
- # Capture stdin FIRST to extract cwd from Claude's JSON input
42
- _EARLY_STDIN=$(mktemp)
43
- cat > "$_EARLY_STDIN"
44
-
45
- # Extract cwd from JSON (Claude always provides this)
46
- if command -v jq >/dev/null 2>&1; then
47
- PROJECT_ROOT=$(jq -r '.cwd // empty' "$_EARLY_STDIN" 2>/dev/null)
48
- fi
49
-
50
- # Fallback: find project root by walking up from script location
51
- if [ -z "$PROJECT_ROOT" ] || [ ! -d "$PROJECT_ROOT/.specweave" ]; then
52
- find_project_root() {
53
- local dir="$1"
54
- while [ "$dir" != "/" ]; do
55
- if [ -d "$dir/.specweave" ]; then
56
- echo "$dir"
57
- return 0
58
- fi
59
- dir="$(dirname "$dir")"
60
- done
61
- pwd
62
- }
63
- PROJECT_ROOT="$(find_project_root "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")"
64
- fi
65
-
66
- cd "$PROJECT_ROOT" 2>/dev/null || true
67
-
68
- # ============================================================================
69
- # EMERGENCY SAFETY CHECKS (v0.24.4 - Performance Fix)
70
- # ============================================================================
71
-
72
- LOGS_DIR=".specweave/logs"
73
- DEBUG_LOG="$LOGS_DIR/hooks-debug.log"
74
- mkdir -p "$LOGS_DIR" 2>/dev/null || true
75
-
76
- # CIRCUIT BREAKER: Auto-disable after consecutive failures
77
- CIRCUIT_BREAKER_FILE=".specweave/state/.hook-circuit-breaker-pre"
78
- CIRCUIT_BREAKER_THRESHOLD=3
79
-
80
- mkdir -p ".specweave/state" 2>/dev/null || true
81
-
82
- if [[ -f "$CIRCUIT_BREAKER_FILE" ]]; then
83
- FAILURE_COUNT=$(cat "$CIRCUIT_BREAKER_FILE" 2>/dev/null || echo 0)
84
- if (( FAILURE_COUNT >= CIRCUIT_BREAKER_THRESHOLD )); then
85
- # Circuit breaker is OPEN - hooks are disabled
86
- exit 0
87
- fi
88
- fi
89
-
90
- # FILE LOCK: Only allow 1 pre-task-completion hook at a time
91
- LOCK_FILE=".specweave/state/.hook-pre-task.lock"
92
- LOCK_TIMEOUT=5 # seconds (shorter than PostToolUse)
93
-
94
- LOCK_ACQUIRED=false
95
- for i in {1..5}; do
96
- if mkdir "$LOCK_FILE" 2>/dev/null; then
97
- LOCK_ACQUIRED=true
98
- trap 'rmdir "$LOCK_FILE" 2>/dev/null || true' EXIT
99
- break
100
- fi
101
-
102
- # Check for stale lock
103
- if [[ -d "$LOCK_FILE" ]]; then
104
- LOCK_AGE=$(($(date +%s) - $(stat -f "%m" "$LOCK_FILE" 2>/dev/null || echo 0)))
105
- if (( LOCK_AGE > LOCK_TIMEOUT )); then
106
- rmdir "$LOCK_FILE" 2>/dev/null || true
107
- continue
108
- fi
109
- fi
110
-
111
- sleep 0.1
112
- done
113
-
114
- if [[ "$LOCK_ACQUIRED" == "false" ]]; then
115
- # Another instance is running, skip
116
- exit 0
117
- fi
118
-
119
- # DEBOUNCING: Prevent duplicate hook fires
120
- LAST_FIRE_FILE="$LOGS_DIR/last-pre-hook-fire"
121
- DEBOUNCE_SECONDS=5 # Same as PostToolUse
122
-
123
- CURRENT_TIME=$(date +%s)
124
-
125
- if [ -f "$LAST_FIRE_FILE" ]; then
126
- LAST_FIRE=$(cat "$LAST_FIRE_FILE" 2>/dev/null || echo "0")
127
- TIME_DIFF=$((CURRENT_TIME - LAST_FIRE))
128
-
129
- if [ "$TIME_DIFF" -lt "$DEBOUNCE_SECONDS" ]; then
130
- # Debounced - skip this execution
131
- exit 0
132
- fi
133
- fi
134
-
135
- echo "$CURRENT_TIME" > "$LAST_FIRE_FILE"
136
-
137
- echo "[$(date)] 🔒 Pre-task-completion hook fired" >> "$DEBUG_LOG" 2>/dev/null || true
138
-
139
- # ============================================================================
140
- # CAPTURE INPUT
141
- # ============================================================================
142
-
143
- # Reuse the early stdin capture
144
- STDIN_DATA="$_EARLY_STDIN"
145
-
146
- echo "[$(date)] Input JSON:" >> "$DEBUG_LOG" 2>/dev/null || true
147
- cat "$STDIN_DATA" >> "$DEBUG_LOG" 2>/dev/null || true
148
-
149
- # ============================================================================
150
- # CHECK FOR TASK COMPLETION
151
- # ============================================================================
152
-
153
- # Only validate if a task is being marked complete
154
- COMPLETING_TASK=false
155
-
156
- if command -v jq >/dev/null 2>&1; then
157
- # Check if any task is transitioning to "completed" status
158
- COMPLETED_COUNT=$(jq -r '.tool_input.todos // [] | map(select(.status == "completed")) | length' "$STDIN_DATA" 2>/dev/null || echo "0")
159
-
160
- if [ "$COMPLETED_COUNT" != "0" ]; then
161
- COMPLETING_TASK=true
162
- echo "[$(date)] ✓ Detected task completion (${COMPLETED_COUNT} tasks)" >> "$DEBUG_LOG" 2>/dev/null || true
163
- fi
164
- fi
165
-
166
- # If no tasks being completed, allow without validation
167
- if [ "$COMPLETING_TASK" = "false" ]; then
168
- echo "[$(date)] ⏭️ No tasks being completed, skipping validation" >> "$DEBUG_LOG" 2>/dev/null || true
169
- rm -f "$STDIN_DATA"
170
- echo '{"continue":true}'
171
- exit 0
172
- fi
173
-
174
- # ============================================================================
175
- # DETECT CURRENT INCREMENT
176
- # ============================================================================
177
-
178
- CURRENT_INCREMENT=$(ls -td .specweave/increments/*/ 2>/dev/null | xargs -n1 basename | grep -v "_backlog" | grep -v "_archive" | grep -v "_working" | head -1)
179
-
180
- if [ -z "$CURRENT_INCREMENT" ]; then
181
- echo "[$(date)] ℹ️ No active increment found, skipping validation" >> "$DEBUG_LOG" 2>/dev/null || true
182
- rm -f "$STDIN_DATA"
183
- echo '{"continue":true}'
184
- exit 0
185
- fi
186
-
187
- TASKS_MD=".specweave/increments/$CURRENT_INCREMENT/tasks.md"
188
-
189
- if [ ! -f "$TASKS_MD" ]; then
190
- echo "[$(date)] ℹ️ tasks.md not found for $CURRENT_INCREMENT (increment may be in planning stage)" >> "$DEBUG_LOG" 2>/dev/null || true
191
- rm -f "$STDIN_DATA"
192
- echo '{"continue":true}'
193
- exit 0
194
- fi
195
-
196
- # ============================================================================
197
- # RUN AC TEST VALIDATION
198
- # ============================================================================
199
-
200
- echo "[$(date)] 🧪 Running AC test validation for $CURRENT_INCREMENT" >> "$DEBUG_LOG" 2>/dev/null || true
201
-
202
- # Determine which validation script to use
203
- # Priority order:
204
- # 1. SpecWeave development (dist/src/core/) - for contributors
205
- # 2. npm package installation (node_modules/specweave/dist/)
206
- # 3. Marketplace plugin (lib/vendor/core/) - for end users
207
- VALIDATOR_SCRIPT=""
208
- if [ -f "$PROJECT_ROOT/dist/src/core/ac-test-validator-cli.js" ]; then
209
- # SpecWeave development repo
210
- VALIDATOR_SCRIPT="$PROJECT_ROOT/dist/src/core/ac-test-validator-cli.js"
211
- elif [ -f "$PROJECT_ROOT/node_modules/specweave/dist/src/core/ac-test-validator-cli.js" ]; then
212
- # npm package installation
213
- VALIDATOR_SCRIPT="$PROJECT_ROOT/node_modules/specweave/dist/src/core/ac-test-validator-cli.js"
214
- elif [ -n "${CLAUDE_PLUGIN_ROOT}" ] && [ -f "${CLAUDE_PLUGIN_ROOT}/lib/vendor/core/ac-test-validator-cli.js" ]; then
215
- # Marketplace plugin (bundled in lib/vendor/)
216
- VALIDATOR_SCRIPT="${CLAUDE_PLUGIN_ROOT}/lib/vendor/core/ac-test-validator-cli.js"
217
- fi
218
-
219
- if [ -z "$VALIDATOR_SCRIPT" ] || ! command -v node &> /dev/null; then
220
- echo "[$(date)] ⚠️ AC test validator not found or Node.js missing" >> "$DEBUG_LOG" 2>/dev/null || true
221
- rm -f "$STDIN_DATA"
222
- echo '{"continue":true,"systemMessage":"⚠️ Warning: AC test validator not available. Task completion validation skipped. Install Node.js and rebuild SpecWeave to enable validation."}'
223
- exit 0
224
- fi
225
-
226
- # Run validator (captures exit code)
227
- VALIDATION_OUTPUT=$(mktemp)
228
- VALIDATION_EXIT_CODE=0
229
-
230
- (cd "$PROJECT_ROOT" && node "$VALIDATOR_SCRIPT" "$CURRENT_INCREMENT") > "$VALIDATION_OUTPUT" 2>&1 || VALIDATION_EXIT_CODE=$?
231
-
232
- echo "[$(date)] Validator exit code: $VALIDATION_EXIT_CODE" >> "$DEBUG_LOG" 2>/dev/null || true
233
- cat "$VALIDATION_OUTPUT" >> "$DEBUG_LOG" 2>/dev/null || true
234
-
235
- rm -f "$STDIN_DATA"
236
-
237
- # ============================================================================
238
- # DECISION LOGIC
239
- # ============================================================================
240
-
241
- if [ "$VALIDATION_EXIT_CODE" = "0" ]; then
242
- # Validation passed - allow completion
243
- echo "[$(date)] ✅ AC test validation passed" >> "$DEBUG_LOG" 2>/dev/null || true
244
-
245
- # Reset circuit breaker on success
246
- echo "0" > "$CIRCUIT_BREAKER_FILE" 2>/dev/null || true
247
-
248
- VALIDATION_SUMMARY=$(cat "$VALIDATION_OUTPUT" | tail -5 | tr '\n' ' ' | sed 's/"/\\"/g')
249
-
250
- rm -f "$VALIDATION_OUTPUT"
251
-
252
- printf '{"continue":true,"systemMessage":"✅ AC Test Validation Passed: All acceptance criteria have passing tests. Task completion allowed. %s"}\n' "$VALIDATION_SUMMARY"
253
- else
254
- # Validation failed - block completion
255
- echo "[$(date)] ❌ AC test validation failed" >> "$DEBUG_LOG" 2>/dev/null || true
256
-
257
- # Increment circuit breaker on failure
258
- CURRENT_FAILURES=$(cat "$CIRCUIT_BREAKER_FILE" 2>/dev/null || echo 0)
259
- echo "$((CURRENT_FAILURES + 1))" > "$CIRCUIT_BREAKER_FILE" 2>/dev/null || true
260
-
261
- VALIDATION_ERROR=$(cat "$VALIDATION_OUTPUT" | grep -A 10 "VALIDATION FAILED" | tr '\n' ' ' | cut -c 1-300 | sed 's/"/\\"/g')
262
-
263
- rm -f "$VALIDATION_OUTPUT"
264
-
265
- printf '{"continue":false,"systemMessage":"❌ AC TEST VALIDATION FAILED: Cannot mark task as complete until all acceptance criteria have passing tests. %s\\n\\nFix the failing tests and try again. Run tests manually: npm test"}\n' "$VALIDATION_ERROR"
266
- fi
267
-
268
- # ALWAYS exit 0 - NEVER let hook errors crash Claude Code
269
- exit 0
@@ -1,137 +0,0 @@
1
- #!/bin/bash
2
-
3
- # SpecWeave Pre-Tool-Use Hook
4
- # Runs BEFORE Claude calls any tool (PreToolUse event)
5
- #
6
- # PURPOSE: Detect when Claude asks questions via AskUserQuestion
7
- # - Plays sound IMMEDIATELY when question is about to be asked
8
- # - Complements post-task-completion hook (which only fires after TodoWrite)
9
- # - Ensures user is always notified when Claude needs input
10
- #
11
- # SCOPE:
12
- # - This hook fires for ALL tool calls (Read, Edit, Write, AskUserQuestion, etc.)
13
- # - We filter for AskUserQuestion specifically to play sound
14
- # - Non-blocking and fast (<10ms overhead)
15
-
16
- set +e # EMERGENCY FIX: Prevents Claude Code crashes
17
-
18
- # EMERGENCY KILL SWITCH
19
- if [[ "${SPECWEAVE_DISABLE_HOOKS:-0}" == "1" ]]; then
20
- exit 0
21
- fi
22
-
23
- # ============================================================================
24
- # CONFIGURATION
25
- # ============================================================================
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
- # Fallback
38
- if [ -d "$(pwd)/.specweave" ]; then
39
- pwd
40
- else
41
- echo "$(pwd)"
42
- fi
43
- }
44
-
45
- PROJECT_ROOT="$(find_project_root "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")"
46
- cd "$PROJECT_ROOT" 2>/dev/null || true
47
-
48
- # ULTRA-FAST EARLY EXIT FOR NON-SPECWEAVE PROJECTS (T-006 - v0.26.15)
49
- if [[ ! -d "$PROJECT_ROOT/.specweave" ]]; then
50
- exit 0
51
- fi
52
-
53
- LOGS_DIR=".specweave/logs"
54
- DEBUG_LOG="$LOGS_DIR/hooks-debug.log"
55
-
56
- mkdir -p "$LOGS_DIR" 2>/dev/null || true
57
-
58
- # ============================================================================
59
- # CAPTURE INPUT (Tool Call Details)
60
- # ============================================================================
61
-
62
- STDIN_DATA=$(mktemp)
63
- cat > "$STDIN_DATA"
64
-
65
- # Log the tool call for debugging
66
- echo "[$(date)] 🔧 PreToolUse hook fired" >> "$DEBUG_LOG" 2>/dev/null || true
67
- echo "[$(date)] Tool call JSON:" >> "$DEBUG_LOG" 2>/dev/null || true
68
- cat "$STDIN_DATA" >> "$DEBUG_LOG" 2>/dev/null || true
69
- echo "" >> "$DEBUG_LOG" 2>/dev/null || true
70
-
71
- # ============================================================================
72
- # DETECT AskUserQuestion TOOL
73
- # ============================================================================
74
-
75
- TOOL_NAME=""
76
-
77
- if command -v jq >/dev/null 2>&1; then
78
- # Use jq if available (most reliable)
79
- TOOL_NAME=$(jq -r '.tool_name // empty' "$STDIN_DATA" 2>/dev/null)
80
- else
81
- # Fallback: grep-based detection
82
- if grep -q '"tool_name"' "$STDIN_DATA" 2>/dev/null; then
83
- TOOL_NAME=$(grep -o '"tool_name":"[^"]*"' "$STDIN_DATA" | cut -d'"' -f4)
84
- fi
85
- fi
86
-
87
- echo "[$(date)] Tool name: $TOOL_NAME" >> "$DEBUG_LOG" 2>/dev/null || true
88
-
89
- # ============================================================================
90
- # PLAY SOUND IF AskUserQuestion
91
- # ============================================================================
92
-
93
- play_sound() {
94
- case "$(uname -s)" in
95
- Darwin)
96
- # macOS: Use afplay with a distinctive sound for questions
97
- afplay /System/Library/Sounds/Tink.aiff 2>/dev/null || true
98
- ;;
99
- Linux)
100
- # Linux: Use paplay or aplay
101
- paplay /usr/share/sounds/freedesktop/stereo/dialog-question.oga 2>/dev/null || \
102
- paplay /usr/share/sounds/freedesktop/stereo/message-new-instant.oga 2>/dev/null || \
103
- aplay /usr/share/sounds/alsa/Front_Center.wav 2>/dev/null || true
104
- ;;
105
- MINGW*|MSYS*|CYGWIN*)
106
- # Windows: Use PowerShell
107
- powershell -c "(New-Object Media.SoundPlayer 'C:\Windows\Media\Windows Notify.wav').PlaySync();" 2>/dev/null || true
108
- ;;
109
- esac
110
- }
111
-
112
- if [ "$TOOL_NAME" = "AskUserQuestion" ]; then
113
- echo "[$(date)] 🔔 QUESTION DETECTED! Playing notification sound" >> "$DEBUG_LOG" 2>/dev/null || true
114
- play_sound
115
-
116
- # Log this event
117
- echo "[$(date)] Claude is asking for user input via AskUserQuestion" >> "$DEBUG_LOG" 2>/dev/null || true
118
- fi
119
-
120
- # ============================================================================
121
- # CLEANUP
122
- # ============================================================================
123
-
124
- rm -f "$STDIN_DATA"
125
-
126
- # ============================================================================
127
- # OUTPUT TO CLAUDE (Always continue)
128
- # ============================================================================
129
-
130
- if [ "$TOOL_NAME" = "AskUserQuestion" ]; then
131
- echo '{"continue":true,"systemMessage":"🔔 Sound played - user notified of question request"}'
132
- else
133
- echo '{"continue":true}'
134
- fi
135
-
136
- # ALWAYS exit 0 - NEVER let hook errors crash Claude Code
137
- exit 0
@@ -1,139 +0,0 @@
1
- #!/bin/bash
2
-
3
- # SpecWeave Session Start Reconcile Hook (NEW in v0.28.33)
4
- #
5
- # Runs on Claude Code session start to detect and fix GitHub status drift.
6
- # This is a lightweight hook that runs in background to not block startup.
7
- #
8
- # Features:
9
- # - Debounced: Only runs if >1 hour since last reconcile
10
- # - Non-blocking: Runs in background, errors logged but don't crash
11
- # - Optional: Controlled by config.sync.github.autoReconcileOnSessionStart
12
- #
13
- # Trigger: SessionStart hook event
14
-
15
- set +e # Prevent crashes
16
-
17
- # EMERGENCY KILL SWITCH
18
- if [[ "${SPECWEAVE_DISABLE_HOOKS:-0}" == "1" ]]; then
19
- exit 0
20
- fi
21
-
22
- # Find project root
23
- find_project_root() {
24
- local dir="$PWD"
25
- while [[ "$dir" != "/" ]]; do
26
- if [[ -d "$dir/.specweave" ]]; then
27
- echo "$dir"
28
- return 0
29
- fi
30
- dir=$(dirname "$dir")
31
- done
32
- echo "$PWD"
33
- }
34
-
35
- PROJECT_ROOT=$(find_project_root)
36
- CONFIG_FILE="$PROJECT_ROOT/.specweave/config.json"
37
- STATE_DIR="$PROJECT_ROOT/.specweave/state"
38
- LAST_RECONCILE_FILE="$STATE_DIR/.last-reconcile-timestamp"
39
- DEBUG_LOG="$PROJECT_ROOT/.specweave/logs/hooks-debug.log"
40
-
41
- mkdir -p "$STATE_DIR" 2>/dev/null || true
42
- mkdir -p "$(dirname "$DEBUG_LOG")" 2>/dev/null || true
43
-
44
- # Consume stdin (required for hooks)
45
- cat > /dev/null
46
-
47
- echo "[$(date)] session-start-reconcile: Hook fired" >> "$DEBUG_LOG" 2>/dev/null || true
48
-
49
- # ============================================================================
50
- # CHECK IF AUTO-RECONCILE IS ENABLED
51
- # ============================================================================
52
-
53
- if [[ ! -f "$CONFIG_FILE" ]]; then
54
- echo "[$(date)] session-start-reconcile: No config.json - skipping" >> "$DEBUG_LOG" 2>/dev/null || true
55
- exit 0
56
- fi
57
-
58
- # Check config (requires jq)
59
- if ! command -v jq &> /dev/null; then
60
- echo "[$(date)] session-start-reconcile: jq not found - skipping" >> "$DEBUG_LOG" 2>/dev/null || true
61
- exit 0
62
- fi
63
-
64
- # Check if auto-reconcile is enabled
65
- AUTO_RECONCILE=$(jq -r '.sync.github.autoReconcileOnSessionStart // false' "$CONFIG_FILE" 2>/dev/null)
66
-
67
- if [[ "$AUTO_RECONCILE" != "true" ]]; then
68
- echo "[$(date)] session-start-reconcile: Disabled in config - skipping" >> "$DEBUG_LOG" 2>/dev/null || true
69
- exit 0
70
- fi
71
-
72
- echo "[$(date)] session-start-reconcile: Auto-reconcile enabled" >> "$DEBUG_LOG" 2>/dev/null || true
73
-
74
- # ============================================================================
75
- # DEBOUNCE: Only run if >1 hour since last reconcile
76
- # ============================================================================
77
-
78
- DEBOUNCE_SECONDS=3600 # 1 hour
79
-
80
- if [[ -f "$LAST_RECONCILE_FILE" ]]; then
81
- LAST_TIMESTAMP=$(cat "$LAST_RECONCILE_FILE" 2>/dev/null || echo "0")
82
- CURRENT_TIMESTAMP=$(date +%s)
83
- ELAPSED=$((CURRENT_TIMESTAMP - LAST_TIMESTAMP))
84
-
85
- if [[ $ELAPSED -lt $DEBOUNCE_SECONDS ]]; then
86
- REMAINING=$((DEBOUNCE_SECONDS - ELAPSED))
87
- echo "[$(date)] session-start-reconcile: Debounced - last run ${ELAPSED}s ago (wait ${REMAINING}s)" >> "$DEBUG_LOG" 2>/dev/null || true
88
- exit 0
89
- fi
90
- fi
91
-
92
- echo "[$(date)] session-start-reconcile: Debounce passed - running reconcile" >> "$DEBUG_LOG" 2>/dev/null || true
93
-
94
- # Update timestamp BEFORE running (prevents concurrent runs)
95
- date +%s > "$LAST_RECONCILE_FILE"
96
-
97
- # ============================================================================
98
- # RUN RECONCILE IN BACKGROUND (non-blocking)
99
- # ============================================================================
100
-
101
- if ! command -v node &> /dev/null; then
102
- echo "[$(date)] session-start-reconcile: Node.js not found - skipping" >> "$DEBUG_LOG" 2>/dev/null || true
103
- exit 0
104
- fi
105
-
106
- # Find reconcile script
107
- RECONCILE_SCRIPT=""
108
- if [[ -f "$PROJECT_ROOT/plugins/specweave/lib/hooks/session-start-reconcile-worker.js" ]]; then
109
- RECONCILE_SCRIPT="$PROJECT_ROOT/plugins/specweave/lib/hooks/session-start-reconcile-worker.js"
110
- elif [[ -f "$PROJECT_ROOT/dist/plugins/specweave/lib/hooks/session-start-reconcile-worker.js" ]]; then
111
- RECONCILE_SCRIPT="$PROJECT_ROOT/dist/plugins/specweave/lib/hooks/session-start-reconcile-worker.js"
112
- elif [[ -f "$PROJECT_ROOT/node_modules/specweave/dist/plugins/specweave/lib/hooks/session-start-reconcile-worker.js" ]]; then
113
- RECONCILE_SCRIPT="$PROJECT_ROOT/node_modules/specweave/dist/plugins/specweave/lib/hooks/session-start-reconcile-worker.js"
114
- fi
115
-
116
- if [[ -z "$RECONCILE_SCRIPT" ]]; then
117
- echo "[$(date)] session-start-reconcile: Worker script not found - skipping" >> "$DEBUG_LOG" 2>/dev/null || true
118
- exit 0
119
- fi
120
-
121
- # Load GITHUB_TOKEN from .env
122
- if [[ -f "$PROJECT_ROOT/.env" ]]; then
123
- GITHUB_TOKEN_FROM_ENV=$(grep -E '^GITHUB_TOKEN=' "$PROJECT_ROOT/.env" 2>/dev/null | head -1 | cut -d'=' -f2- | sed 's/^["'\'']//' | sed 's/["'\'']$//')
124
- if [[ -n "$GITHUB_TOKEN_FROM_ENV" ]]; then
125
- export GITHUB_TOKEN="$GITHUB_TOKEN_FROM_ENV"
126
- fi
127
- fi
128
-
129
- # Run in background with nohup (fully detached)
130
- # Output goes to debug log, doesn't block session start
131
- echo "[$(date)] session-start-reconcile: Starting background reconcile" >> "$DEBUG_LOG" 2>/dev/null || true
132
-
133
- (
134
- cd "$PROJECT_ROOT" && \
135
- node "$RECONCILE_SCRIPT" >> "$DEBUG_LOG" 2>&1
136
- ) &
137
-
138
- # Immediately exit (don't wait for background job)
139
- exit 0