specweave 1.0.550 → 1.0.552

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 (166) hide show
  1. package/CLAUDE.md +1 -1
  2. package/bin/specweave.js +23 -1
  3. package/dist/src/cli/commands/hook.d.ts +15 -0
  4. package/dist/src/cli/commands/hook.d.ts.map +1 -0
  5. package/dist/src/cli/commands/hook.js +61 -0
  6. package/dist/src/cli/commands/hook.js.map +1 -0
  7. package/dist/src/cli/commands/init.d.ts.map +1 -1
  8. package/dist/src/cli/commands/init.js +5 -0
  9. package/dist/src/cli/commands/init.js.map +1 -1
  10. package/dist/src/cli/commands/refresh-plugins.d.ts.map +1 -1
  11. package/dist/src/cli/commands/refresh-plugins.js +11 -1
  12. package/dist/src/cli/commands/refresh-plugins.js.map +1 -1
  13. package/dist/src/cli/commands/sync-setup.d.ts.map +1 -1
  14. package/dist/src/cli/commands/sync-setup.js +7 -3
  15. package/dist/src/cli/commands/sync-setup.js.map +1 -1
  16. package/dist/src/cli/helpers/issue-tracker/project-mapping-wizard.d.ts +9 -0
  17. package/dist/src/cli/helpers/issue-tracker/project-mapping-wizard.d.ts.map +1 -1
  18. package/dist/src/cli/helpers/issue-tracker/project-mapping-wizard.js +9 -3
  19. package/dist/src/cli/helpers/issue-tracker/project-mapping-wizard.js.map +1 -1
  20. package/dist/src/config/types.d.ts +2 -2
  21. package/dist/src/core/config/types.d.ts +18 -2
  22. package/dist/src/core/config/types.d.ts.map +1 -1
  23. package/dist/src/core/config/types.js.map +1 -1
  24. package/dist/src/core/hooks/handlers/hook-router.d.ts +19 -0
  25. package/dist/src/core/hooks/handlers/hook-router.d.ts.map +1 -0
  26. package/dist/src/core/hooks/handlers/hook-router.js +75 -0
  27. package/dist/src/core/hooks/handlers/hook-router.js.map +1 -0
  28. package/dist/src/core/hooks/handlers/index.d.ts +10 -0
  29. package/dist/src/core/hooks/handlers/index.d.ts.map +1 -0
  30. package/dist/src/core/hooks/handlers/index.js +9 -0
  31. package/dist/src/core/hooks/handlers/index.js.map +1 -0
  32. package/dist/src/core/hooks/handlers/post-tool-use-analytics.d.ts +11 -0
  33. package/dist/src/core/hooks/handlers/post-tool-use-analytics.d.ts.map +1 -0
  34. package/dist/src/core/hooks/handlers/post-tool-use-analytics.js +73 -0
  35. package/dist/src/core/hooks/handlers/post-tool-use-analytics.js.map +1 -0
  36. package/dist/src/core/hooks/handlers/post-tool-use.d.ts +11 -0
  37. package/dist/src/core/hooks/handlers/post-tool-use.d.ts.map +1 -0
  38. package/dist/src/core/hooks/handlers/post-tool-use.js +76 -0
  39. package/dist/src/core/hooks/handlers/post-tool-use.js.map +1 -0
  40. package/dist/src/core/hooks/handlers/pre-compact.d.ts +11 -0
  41. package/dist/src/core/hooks/handlers/pre-compact.d.ts.map +1 -0
  42. package/dist/src/core/hooks/handlers/pre-compact.js +77 -0
  43. package/dist/src/core/hooks/handlers/pre-compact.js.map +1 -0
  44. package/dist/src/core/hooks/handlers/pre-tool-use.d.ts +11 -0
  45. package/dist/src/core/hooks/handlers/pre-tool-use.d.ts.map +1 -0
  46. package/dist/src/core/hooks/handlers/pre-tool-use.js +318 -0
  47. package/dist/src/core/hooks/handlers/pre-tool-use.js.map +1 -0
  48. package/dist/src/core/hooks/handlers/session-start.d.ts +9 -0
  49. package/dist/src/core/hooks/handlers/session-start.d.ts.map +1 -0
  50. package/dist/src/core/hooks/handlers/session-start.js +111 -0
  51. package/dist/src/core/hooks/handlers/session-start.js.map +1 -0
  52. package/dist/src/core/hooks/handlers/stop-auto.d.ts +16 -0
  53. package/dist/src/core/hooks/handlers/stop-auto.d.ts.map +1 -0
  54. package/dist/src/core/hooks/handlers/stop-auto.js +122 -0
  55. package/dist/src/core/hooks/handlers/stop-auto.js.map +1 -0
  56. package/dist/src/core/hooks/handlers/stop-reflect.d.ts +14 -0
  57. package/dist/src/core/hooks/handlers/stop-reflect.d.ts.map +1 -0
  58. package/dist/src/core/hooks/handlers/stop-reflect.js +43 -0
  59. package/dist/src/core/hooks/handlers/stop-reflect.js.map +1 -0
  60. package/dist/src/core/hooks/handlers/stop-sync.d.ts +15 -0
  61. package/dist/src/core/hooks/handlers/stop-sync.d.ts.map +1 -0
  62. package/dist/src/core/hooks/handlers/stop-sync.js +68 -0
  63. package/dist/src/core/hooks/handlers/stop-sync.js.map +1 -0
  64. package/dist/src/core/hooks/handlers/types.d.ts +63 -0
  65. package/dist/src/core/hooks/handlers/types.d.ts.map +1 -0
  66. package/dist/src/core/hooks/handlers/types.js +27 -0
  67. package/dist/src/core/hooks/handlers/types.js.map +1 -0
  68. package/dist/src/core/hooks/handlers/user-prompt-submit.d.ts +14 -0
  69. package/dist/src/core/hooks/handlers/user-prompt-submit.d.ts.map +1 -0
  70. package/dist/src/core/hooks/handlers/user-prompt-submit.js +173 -0
  71. package/dist/src/core/hooks/handlers/user-prompt-submit.js.map +1 -0
  72. package/dist/src/core/hooks/handlers/utils.d.ts +25 -0
  73. package/dist/src/core/hooks/handlers/utils.d.ts.map +1 -0
  74. package/dist/src/core/hooks/handlers/utils.js +64 -0
  75. package/dist/src/core/hooks/handlers/utils.js.map +1 -0
  76. package/dist/src/core/increment/completion-validator.d.ts.map +1 -1
  77. package/dist/src/core/increment/completion-validator.js +32 -0
  78. package/dist/src/core/increment/completion-validator.js.map +1 -1
  79. package/dist/src/init/research/types.d.ts +1 -1
  80. package/dist/src/sync/sync-target-resolver.js.map +1 -1
  81. package/dist/src/utils/lock-manager.d.ts.map +1 -1
  82. package/dist/src/utils/lock-manager.js +5 -0
  83. package/dist/src/utils/lock-manager.js.map +1 -1
  84. package/dist/src/utils/plugin-copier.d.ts +10 -0
  85. package/dist/src/utils/plugin-copier.d.ts.map +1 -1
  86. package/dist/src/utils/plugin-copier.js +63 -35
  87. package/dist/src/utils/plugin-copier.js.map +1 -1
  88. package/package.json +1 -1
  89. package/plugins/specweave/agents/sw-closer.md +3 -2
  90. package/plugins/specweave/hooks/hooks.json +10 -10
  91. package/plugins/specweave/skills/code-reviewer/SKILL.md +180 -16
  92. package/plugins/specweave/skills/code-reviewer/agents/reviewer-comments.md +83 -0
  93. package/plugins/specweave/skills/code-reviewer/agents/reviewer-silent-failures.md +19 -0
  94. package/plugins/specweave/skills/code-reviewer/agents/reviewer-spec-compliance.md +19 -0
  95. package/plugins/specweave/skills/code-reviewer/agents/reviewer-tests.md +101 -0
  96. package/plugins/specweave/skills/code-reviewer/agents/reviewer-types.md +20 -0
  97. package/plugins/specweave/skills/done/SKILL.md +56 -21
  98. package/plugins/specweave/skills/grill/SKILL.md +1 -1
  99. package/plugins/specweave/skills/team-lead/agents/reviewer-logic.md +19 -0
  100. package/plugins/specweave/skills/team-lead/agents/reviewer-performance.md +20 -0
  101. package/plugins/specweave/skills/team-lead/agents/reviewer-security.md +20 -0
  102. package/src/templates/CLAUDE.md.template +7 -4
  103. package/plugins/specweave/hooks/README.md +0 -493
  104. package/plugins/specweave/hooks/_archive/stop-auto-v4-legacy.sh +0 -1319
  105. package/plugins/specweave/hooks/lib/common-setup.sh +0 -144
  106. package/plugins/specweave/hooks/lib/hook-errors.sh +0 -414
  107. package/plugins/specweave/hooks/lib/migrate-increment-work.sh +0 -245
  108. package/plugins/specweave/hooks/lib/resolve-package.sh +0 -146
  109. package/plugins/specweave/hooks/lib/scheduler-startup.sh +0 -135
  110. package/plugins/specweave/hooks/lib/score-increment.sh +0 -87
  111. package/plugins/specweave/hooks/lib/sync-spec-content.sh +0 -193
  112. package/plugins/specweave/hooks/lib/update-active-increment.sh +0 -95
  113. package/plugins/specweave/hooks/lib/update-status-line.sh +0 -233
  114. package/plugins/specweave/hooks/lib/validate-spec-status.sh +0 -171
  115. package/plugins/specweave/hooks/llm-judge-validator.sh +0 -219
  116. package/plugins/specweave/hooks/log-decision.sh +0 -168
  117. package/plugins/specweave/hooks/pre-compact.sh +0 -64
  118. package/plugins/specweave/hooks/startup-health-check.sh +0 -64
  119. package/plugins/specweave/hooks/stop-auto-v5.sh +0 -276
  120. package/plugins/specweave/hooks/stop-reflect.sh +0 -336
  121. package/plugins/specweave/hooks/stop-sync.sh +0 -283
  122. package/plugins/specweave/hooks/tests/test-auto-context-integration.sh +0 -126
  123. package/plugins/specweave/hooks/tests/test-stop-auto-enriched.sh +0 -128
  124. package/plugins/specweave/hooks/universal/dispatcher.mjs +0 -336
  125. package/plugins/specweave/hooks/universal/fail-fast-wrapper.sh +0 -325
  126. package/plugins/specweave/hooks/universal/hook-wrapper.cmd +0 -26
  127. package/plugins/specweave/hooks/universal/hook-wrapper.sh +0 -69
  128. package/plugins/specweave/hooks/universal/run-hook.sh +0 -20
  129. package/plugins/specweave/hooks/universal/session-start.cmd +0 -16
  130. package/plugins/specweave/hooks/universal/session-start.ps1 +0 -16
  131. package/plugins/specweave/hooks/user-prompt-submit.sh +0 -2550
  132. package/plugins/specweave/hooks/v2/detectors/lifecycle-detector.sh +0 -87
  133. package/plugins/specweave/hooks/v2/detectors/us-completion-detector.sh +0 -186
  134. package/plugins/specweave/hooks/v2/dispatchers/post-tool-use-analytics.sh +0 -83
  135. package/plugins/specweave/hooks/v2/dispatchers/post-tool-use.sh +0 -447
  136. package/plugins/specweave/hooks/v2/dispatchers/pre-tool-use.sh +0 -104
  137. package/plugins/specweave/hooks/v2/dispatchers/session-start.sh +0 -270
  138. package/plugins/specweave/hooks/v2/guards/completion-guard.sh +0 -14
  139. package/plugins/specweave/hooks/v2/guards/increment-duplicate-guard.sh +0 -14
  140. package/plugins/specweave/hooks/v2/guards/increment-existence-guard.sh +0 -240
  141. package/plugins/specweave/hooks/v2/guards/interview-enforcement-guard.sh +0 -171
  142. package/plugins/specweave/hooks/v2/guards/metadata-json-guard.sh +0 -14
  143. package/plugins/specweave/hooks/v2/guards/skill-chain-enforcement-guard.sh +0 -222
  144. package/plugins/specweave/hooks/v2/guards/spec-template-enforcement-guard.sh +0 -21
  145. package/plugins/specweave/hooks/v2/guards/spec-validation-guard.sh +0 -14
  146. package/plugins/specweave/hooks/v2/guards/status-completion-guard.sh +0 -84
  147. package/plugins/specweave/hooks/v2/guards/task-ac-sync-guard.sh +0 -475
  148. package/plugins/specweave/hooks/v2/guards/tdd-enforcement-guard.sh +0 -268
  149. package/plugins/specweave/hooks/v2/handlers/ac-sync-dispatcher.sh +0 -332
  150. package/plugins/specweave/hooks/v2/handlers/ac-validation-handler.sh +0 -50
  151. package/plugins/specweave/hooks/v2/handlers/github-sync-handler.sh +0 -347
  152. package/plugins/specweave/hooks/v2/handlers/living-docs-handler.sh +0 -83
  153. package/plugins/specweave/hooks/v2/handlers/living-specs-handler.sh +0 -268
  154. package/plugins/specweave/hooks/v2/handlers/project-bridge-handler.sh +0 -104
  155. package/plugins/specweave/hooks/v2/handlers/status-line-handler.sh +0 -165
  156. package/plugins/specweave/hooks/v2/handlers/status-update.sh +0 -61
  157. package/plugins/specweave/hooks/v2/handlers/universal-auto-create-dispatcher.sh +0 -270
  158. package/plugins/specweave/hooks/v2/integrations/ado-post-living-docs-update.sh +0 -367
  159. package/plugins/specweave/hooks/v2/integrations/ado-post-task.sh +0 -179
  160. package/plugins/specweave/hooks/v2/integrations/github-auto-create-handler.sh +0 -553
  161. package/plugins/specweave/hooks/v2/integrations/github-post-task.sh +0 -345
  162. package/plugins/specweave/hooks/v2/integrations/jira-post-task.sh +0 -180
  163. package/plugins/specweave/hooks/v2/lib/check-provider-enabled.sh +0 -52
  164. package/plugins/specweave/hooks/v2/queue/enqueue.sh +0 -81
  165. package/plugins/specweave/hooks/v2/session-end.sh +0 -139
  166. package/plugins/specweave/hooks/validate-skill-activations.sh +0 -227
@@ -1,447 +0,0 @@
1
- #!/bin/bash
2
- # post-tool-use.sh - Single dispatcher for ALL PostToolUse events
3
- #
4
- # v1.0.148+: NEW ARCHITECTURE - No background processor
5
- #
6
- # CRITICAL DESIGN PRINCIPLE:
7
- # - Tool operations ALWAYS succeed (Edit/Write never blocked by hooks)
8
- # - All hook errors become visible warnings to user
9
- # - Logs captured for debugging
10
- # - Background processes for heavy work
11
- #
12
- # Architecture (v1.0.148 - Simplified):
13
- # - Detectors run asynchronously (don't block tool results)
14
- # - CRITICAL events (increment.done/reopened) sync IMMEDIATELY
15
- # - Other events queued to pending.jsonl for stop-sync.sh (session end)
16
- # - NO background processor daemon
17
- #
18
- # Event flow:
19
- # 1. metadata.json change -> lifecycle-detector -> increment.* events
20
- # - IF done/reopened: IMMEDIATE sync via project-bridge-handler
21
- # - ELSE: queued for stop-sync.sh
22
- # 2. tasks.md/spec.md change -> queued for stop-sync.sh (batched at session end)
23
- #
24
- # Goal: Never crash Claude, always exit 0, warn on errors
25
-
26
- set +e # CRITICAL: Never exit on error
27
-
28
- [[ "${SPECWEAVE_DISABLE_HOOKS:-0}" == "1" ]] && exit 0
29
-
30
- # ============================================================================
31
- # CONSTANTS
32
- # ============================================================================
33
-
34
- HOOK_NAME="post-tool-use"
35
- HOOK_VERSION="1.0.148"
36
-
37
- # ============================================================================
38
- # PROJECT ROOT DETECTION
39
- # ============================================================================
40
-
41
- PROJECT_ROOT="$PWD"
42
- while [[ "$PROJECT_ROOT" != "/" ]] && [[ ! -f "$PROJECT_ROOT/.specweave/config.json" ]]; do
43
- PROJECT_ROOT=$(dirname "$PROJECT_ROOT")
44
- done
45
- [[ ! -f "$PROJECT_ROOT/.specweave/config.json" ]] && exit 0
46
-
47
- STATE_DIR="$PROJECT_ROOT/.specweave/state"
48
-
49
- # ============================================================================
50
- # LOGGING INFRASTRUCTURE
51
- # ============================================================================
52
-
53
- LOGS_DIR="$PROJECT_ROOT/.specweave/logs"
54
- DEBUG_LOG="$LOGS_DIR/post-tool-use.log"
55
- WARNING_LOG="$LOGS_DIR/hook-warnings.log"
56
- mkdir -p "$LOGS_DIR" 2>/dev/null || true
57
-
58
- log_debug() {
59
- echo "[$(date '+%Y-%m-%d %H:%M:%S')] [$HOOK_NAME] $*" >> "$DEBUG_LOG" 2>/dev/null || true
60
- }
61
-
62
- log_warning() {
63
- local message="$1"
64
- local details="${2:-}"
65
-
66
- # Always log to file
67
- {
68
- echo "[$(date '+%Y-%m-%d %H:%M:%S')] WARNING [$HOOK_NAME]: $message"
69
- [[ -n "$details" ]] && echo " Details: $details"
70
- } >> "$WARNING_LOG" 2>/dev/null || true
71
-
72
- # Show to user so they know something went wrong
73
- echo ""
74
- echo " [Hook Warning] $HOOK_NAME: $message"
75
- [[ -n "$details" ]] && echo " $details"
76
- echo " (Tool operation succeeded - hook issue only)"
77
- echo ""
78
- }
79
-
80
- # ============================================================================
81
- # SAFE EXECUTION HELPERS
82
- # ============================================================================
83
-
84
- # Run a hook script safely in background (never blocks, logs errors)
85
- safe_run_background() {
86
- local script="$1"
87
- local context="$2"
88
- shift 2
89
-
90
- if [[ ! -f "$script" ]]; then
91
- log_debug "Script not found (skipping): $script"
92
- return 0
93
- fi
94
-
95
- if [[ ! -x "$script" ]] && [[ ! "$script" == *.sh ]]; then
96
- log_debug "Script not executable (skipping): $script"
97
- return 0
98
- fi
99
-
100
- # Run in background, capture errors to log
101
- (
102
- set +e
103
- local output
104
- local exit_code
105
-
106
- output=$(bash "$script" "$@" 2>&1)
107
- exit_code=$?
108
-
109
- if [[ $exit_code -ne 0 ]]; then
110
- echo "[$(date '+%Y-%m-%d %H:%M:%S')] BACKGROUND ERROR [$context]: exit $exit_code" >> "$WARNING_LOG" 2>/dev/null || true
111
- echo " Output: $output" >> "$WARNING_LOG" 2>/dev/null || true
112
- fi
113
- ) &
114
-
115
- return 0
116
- }
117
-
118
- # Run a hook script safely in foreground (for sync guards)
119
- safe_run_sync() {
120
- local script="$1"
121
- local context="$2"
122
- local input="$3"
123
-
124
- if [[ ! -f "$script" ]]; then
125
- log_debug "Script not found (skipping): $script"
126
- return 0
127
- fi
128
-
129
- local output
130
- local exit_code
131
-
132
- # Run with timeout protection (5 second max)
133
- if command -v gtimeout >/dev/null 2>&1; then
134
- output=$(echo "$input" | gtimeout --kill-after=2 5 bash "$script" 2>&1)
135
- exit_code=$?
136
- elif command -v timeout >/dev/null 2>&1; then
137
- output=$(echo "$input" | timeout --kill-after=2 5 bash "$script" 2>&1)
138
- exit_code=$?
139
- else
140
- output=$(echo "$input" | bash "$script" 2>&1)
141
- exit_code=$?
142
- fi
143
-
144
- # Log errors but don't fail
145
- if [[ $exit_code -ne 0 ]]; then
146
- if [[ $exit_code -eq 124 ]] || [[ $exit_code -eq 137 ]]; then
147
- log_warning "Hook timed out: $context" "Script: $script"
148
- else
149
- log_debug "Hook exited with code $exit_code: $context"
150
- fi
151
- fi
152
-
153
- # Output any non-error output (for status messages, etc.)
154
- if [[ -n "$output" ]] && [[ "$output" != *"ERROR"* ]] && [[ "$output" != *"error"* ]]; then
155
- echo "$output"
156
- fi
157
-
158
- return 0 # Always succeed
159
- }
160
-
161
- # ============================================================================
162
- # TASK COMPLETION SOUND (plays when task marked [x])
163
- # ============================================================================
164
-
165
- play_task_completion_sound() {
166
- local tasks_file="$1"
167
- local state_file="$STATE_DIR/.last-task-completion"
168
- local session_file="$STATE_DIR/auto-mode.json"
169
-
170
- # DISABLED: Sound notifications are disabled by default
171
- # To re-enable, set SPECWEAVE_SOUND_ENABLED=1 in environment
172
- if [[ "${SPECWEAVE_SOUND_ENABLED:-0}" != "1" ]]; then
173
- log_debug "Sound disabled (set SPECWEAVE_SOUND_ENABLED=1 to enable)"
174
- return 0
175
- fi
176
-
177
- # CRITICAL: Skip sound if auto mode is active
178
- # Auto mode has its own completion sound via Stop hook (plays once at END)
179
- if [[ -f "$session_file" ]]; then
180
- local auto_status=$(jq -r '.status // "unknown"' "$session_file" 2>/dev/null || echo "unknown")
181
- if [[ "$auto_status" == "active" ]] || [[ "$auto_status" == "running" ]]; then
182
- log_debug "Auto mode active - skipping task completion sound (Stop hook will handle it)"
183
- return 0
184
- fi
185
- fi
186
-
187
- # Extract current completion count
188
- local current_count=$(grep -c '\*\*Status\*\*:.*\[x\]' "$tasks_file" 2>/dev/null || echo "0")
189
-
190
- # Read previous count
191
- local previous_count="0"
192
- if [[ -f "$state_file" ]]; then
193
- previous_count=$(cat "$state_file" 2>/dev/null || echo "0")
194
- fi
195
-
196
- # If count increased, a task was just completed
197
- if [[ "$current_count" -gt "$previous_count" ]]; then
198
- # Save new count
199
- echo "$current_count" > "$state_file" 2>/dev/null
200
-
201
- # Play completion sound (background, never blocks)
202
- (
203
- if [[ "$OSTYPE" == "darwin"* ]]; then
204
- # macOS - use Glass.aiff for pleasant completion sound
205
- afplay /System/Library/Sounds/Glass.aiff 2>/dev/null &
206
- elif command -v paplay >/dev/null 2>&1; then
207
- # Linux with PulseAudio
208
- paplay /usr/share/sounds/freedesktop/stereo/complete.oga 2>/dev/null &
209
- elif command -v aplay >/dev/null 2>&1; then
210
- # Linux with ALSA
211
- aplay /usr/share/sounds/alsa/Front_Center.wav 2>/dev/null &
212
- fi
213
- ) &
214
-
215
- log_debug "Task completion sound played (count: $previous_count → $current_count)"
216
- fi
217
- }
218
-
219
- # ============================================================================
220
- # INPUT PARSING (with safe fallbacks)
221
- # ============================================================================
222
-
223
- # Read stdin (tool result JSON) - with safe fallback and timeout
224
- INPUT=""
225
- if command -v gtimeout >/dev/null 2>&1; then
226
- INPUT=$(gtimeout 1 cat 2>/dev/null || echo '{}')
227
- elif command -v timeout >/dev/null 2>&1; then
228
- INPUT=$(timeout 1 cat 2>/dev/null || echo '{}')
229
- else
230
- INPUT=$(cat 2>/dev/null || echo '{}')
231
- fi
232
-
233
- # Extract file path (fast grep, no jq required)
234
- FILE_PATH=$(echo "$INPUT" | grep -o '"file_path"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*"\([^"]*\)".*/\1/')
235
- [[ -z "$FILE_PATH" ]] && exit 0
236
-
237
- # Extract increment ID from path
238
- INC_ID=$(echo "$FILE_PATH" | grep -o '[0-9][0-9][0-9][0-9]-[^/]*' | head -1)
239
- [[ -z "$INC_ID" ]] && exit 0
240
-
241
- log_debug "Processing: $FILE_PATH (increment: $INC_ID)"
242
-
243
- # ============================================================================
244
- # SETUP PATHS
245
- # ============================================================================
246
-
247
- # Script is at: hooks/v2/dispatchers/post-tool-use.sh
248
- # HOOK_DIR should be: hooks/v2 (one level up from dispatchers)
249
- # PLUGIN_ROOT should be: plugin root (TWO levels up from hooks/v2)
250
- HOOK_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
251
- PLUGIN_ROOT="$(cd "$HOOK_DIR/../.." && pwd)"
252
- DETECTOR_DIR="$HOOK_DIR/detectors"
253
- SCRIPTS_DIR="$PLUGIN_ROOT/scripts"
254
-
255
- # ============================================================================
256
- # EDA DISPATCHER: Route to detectors based on file type
257
- # All errors become warnings, never block the tool operation
258
- # ============================================================================
259
-
260
- case "$FILE_PATH" in
261
- */.specweave/increments/*/metadata.json)
262
- log_debug "Metadata change detected"
263
-
264
- # Metadata changed -> check for lifecycle transitions (background)
265
- safe_run_background "$DETECTOR_DIR/lifecycle-detector.sh" "lifecycle-detector" "$INC_ID"
266
-
267
- # Update dashboard cache (background)
268
- safe_run_background "$SCRIPTS_DIR/update-dashboard-cache.sh" "dashboard-cache" "$INC_ID" "metadata"
269
-
270
- # ========================================================================
271
- # IMMEDIATE EXTERNAL SYNC for done/reopened (v1.0.148)
272
- # ========================================================================
273
- # Critical events sync IMMEDIATELY - user expects external tools updated
274
- # Other events batched for session end (stop-sync.sh)
275
- METADATA_FILE="$PROJECT_ROOT/.specweave/increments/$INC_ID/metadata.json"
276
- if [[ -f "$METADATA_FILE" ]]; then
277
- CURRENT_STATUS=$(grep -o '"status"[[:space:]]*:[[:space:]]*"[^"]*"' "$METADATA_FILE" | head -1 | sed 's/.*"\([^"]*\)".*/\1/')
278
-
279
- if [[ "$CURRENT_STATUS" == "completed" ]] || [[ "$CURRENT_STATUS" == "done" ]] || [[ "$CURRENT_STATUS" == "reopened" ]]; then
280
- log_debug "IMMEDIATE SYNC: Status is $CURRENT_STATUS - syncing to external tools"
281
-
282
- # ====================================================================
283
- # SYNC MODE CHECK (0618): queued vs immediate
284
- # ====================================================================
285
- SYNC_CONFIG_PATH="$PROJECT_ROOT/.specweave/config.json"
286
- SYNC_MODE="queued"
287
- if command -v jq >/dev/null 2>&1 && [[ -f "$SYNC_CONFIG_PATH" ]]; then
288
- SYNC_MODE=$(jq -r '.sync.mode // "queued"' "$SYNC_CONFIG_PATH" 2>/dev/null || echo "queued")
289
- fi
290
-
291
- if [[ "$SYNC_MODE" == "queued" ]]; then
292
- # Queue event to pending.jsonl instead of direct sync
293
- QUEUE_DIR="$PROJECT_ROOT/.specweave/state/event-queue"
294
- mkdir -p "$QUEUE_DIR" 2>/dev/null || true
295
- TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
296
- echo "{\"incrementId\":\"$INC_ID\",\"eventType\":\"status.changed\",\"metadata\":{\"newStatus\":\"$CURRENT_STATUS\"},\"timestamp\":\"$TIMESTAMP\"}" >> "$QUEUE_DIR/pending.jsonl"
297
- log_debug "QUEUED SYNC: Event queued for $INC_ID (status.changed -> $CURRENT_STATUS)"
298
- else
299
- # IMMEDIATE MODE (legacy): direct sync calls
300
-
301
- # Map raw status to canonical event name (consistent with lifecycle-detector)
302
- case "$CURRENT_STATUS" in
303
- completed|done) BRIDGE_EVENT="increment.done" ;;
304
- reopened) BRIDGE_EVENT="increment.reopened" ;;
305
- *) BRIDGE_EVENT="increment.$CURRENT_STATUS" ;;
306
- esac
307
-
308
- BRIDGE_HANDLER="$HOOK_DIR/handlers/project-bridge-handler.sh"
309
- if [[ -f "$BRIDGE_HANDLER" ]]; then
310
- # Run synchronously but with timeout to not block too long
311
- (
312
- if command -v gtimeout >/dev/null 2>&1; then
313
- gtimeout 15 bash "$BRIDGE_HANDLER" "$BRIDGE_EVENT" "$INC_ID" 2>/dev/null || true
314
- elif command -v timeout >/dev/null 2>&1; then
315
- timeout 15 bash "$BRIDGE_HANDLER" "$BRIDGE_EVENT" "$INC_ID" 2>/dev/null || true
316
- else
317
- bash "$BRIDGE_HANDLER" "$BRIDGE_EVENT" "$INC_ID" 2>/dev/null || true
318
- fi
319
- )
320
- log_debug "IMMEDIATE SYNC completed for $INC_ID"
321
- fi
322
-
323
- # ========================================================================
324
- # EXPLICIT CLOSURE (v1.0.257+): Close external issues on completion
325
- # ========================================================================
326
- # Only on completed/done - triggers provider-agnostic closure for ALL
327
- # user stories, ensuring external issues are closed even if AC sync
328
- # missed them. NOT called on reopened or on every AC change.
329
- if [[ "$CURRENT_STATUS" == "completed" ]] || [[ "$CURRENT_STATUS" == "done" ]]; then
330
- AC_CLOSE_DISPATCHER="${HOOK_DIR}/handlers/ac-sync-dispatcher.sh"
331
- if [[ -f "$AC_CLOSE_DISPATCHER" ]]; then
332
- log_debug "EXPLICIT CLOSURE: Triggering provider-agnostic closure for $INC_ID"
333
- SPECWEAVE_CLOSE_ALL=1 safe_run_background "$AC_CLOSE_DISPATCHER" "ac-close" "$INC_ID"
334
- fi
335
- fi
336
- fi
337
- fi
338
- fi
339
- ;;
340
-
341
- */.specweave/increments/*/tasks.md|*/.specweave/increments/*/spec.md)
342
- log_debug "Tasks/spec change detected"
343
-
344
- # ========================================================================
345
- # TASK-AC SYNC (v0.35.2+): Sync task completion to spec.md ACs
346
- # ========================================================================
347
- # When tasks.md is edited, sync completed task ACs to spec.md
348
- # Runs in BACKGROUND (non-blocking) — FILE_PATH passed as $1 argument
349
- if [[ "$FILE_PATH" == *tasks.md ]]; then
350
- SYNC_SCRIPT="$HOOK_DIR/guards/task-ac-sync-guard.sh"
351
- if [[ -f "$SYNC_SCRIPT" ]]; then
352
- log_debug "Running task-ac-sync guard (background)"
353
- safe_run_background "$SYNC_SCRIPT" "task-ac-sync" "$FILE_PATH"
354
- fi
355
-
356
- # ========================================================================
357
- # PROVIDER-AGNOSTIC AC SYNC (v1.0.255+): Sync progress to all providers
358
- # ========================================================================
359
- AC_SYNC_DISPATCHER="${HOOK_DIR}/handlers/ac-sync-dispatcher.sh"
360
- if [[ -f "$AC_SYNC_DISPATCHER" ]]; then
361
- safe_run_background "$AC_SYNC_DISPATCHER" "ac-sync" "$INC_ID"
362
- fi
363
-
364
- # ========================================================================
365
- # TDD ENFORCEMENT (v1.0.160+): Enforce TDD discipline
366
- # ========================================================================
367
- # When tasks.md is edited in TDD mode, check for violations
368
- # v1.0.160: In STRICT mode, runs synchronously and shows blocking warning
369
- TDD_GUARD="$HOOK_DIR/guards/tdd-enforcement-guard.sh"
370
- if [[ -f "$TDD_GUARD" ]]; then
371
- # Check if strict TDD enforcement is enabled
372
- TDD_STRICT=false
373
- CONFIG_FILE="$PROJECT_ROOT/.specweave/config.json"
374
- if [[ -f "$CONFIG_FILE" ]] && command -v jq >/dev/null 2>&1; then
375
- TDD_ENFORCEMENT=$(jq -r '.testing.tddEnforcement // "warn"' "$CONFIG_FILE" 2>/dev/null)
376
- [[ "$TDD_ENFORCEMENT" == "strict" ]] && TDD_STRICT=true
377
- fi
378
-
379
- if [[ "$TDD_STRICT" == "true" ]]; then
380
- log_debug "Running TDD enforcement guard (STRICT - synchronous)"
381
- # Run synchronously and capture output for strict mode
382
- TDD_OUTPUT=$(bash "$TDD_GUARD" "$PROJECT_ROOT" "$FILE_PATH" "Edit" 2>&1)
383
- TDD_EXIT=$?
384
- if [[ $TDD_EXIT -ne 0 ]]; then
385
- # Show blocking warning to user
386
- echo ""
387
- echo " ⚠️ TDD STRICT MODE VIOLATION DETECTED"
388
- echo "$TDD_OUTPUT" | head -20
389
- echo ""
390
- log_debug "TDD violation detected (exit code: $TDD_EXIT)"
391
- fi
392
- else
393
- log_debug "Running TDD enforcement guard (warn mode - background)"
394
- safe_run_background "$TDD_GUARD" "tdd-enforcement" "$PROJECT_ROOT" "$FILE_PATH" "Edit"
395
- fi
396
- fi
397
-
398
- # Play completion sound if task was marked complete (v1.0.77+)
399
- play_task_completion_sound "$FILE_PATH"
400
- fi
401
-
402
- # ========================================================================
403
- # UNIVERSAL AUTO-CREATE (v1.0.256+): Create items in ALL enabled providers
404
- # ========================================================================
405
- # When spec.md is created/updated AND has user stories, auto-create
406
- # items in GitHub/JIRA/ADO if autoSync or auto_create is enabled.
407
- if [[ "$FILE_PATH" == *spec.md ]]; then
408
- UNIVERSAL_AUTO_CREATE="${HOOK_DIR}/handlers/universal-auto-create-dispatcher.sh"
409
- if [[ -f "$UNIVERSAL_AUTO_CREATE" ]]; then
410
- safe_run_background "$UNIVERSAL_AUTO_CREATE" "universal-auto-create" "$INC_ID"
411
- fi
412
- fi
413
-
414
- # Tasks or spec changed -> check for US completion (background)
415
- safe_run_background "$DETECTOR_DIR/us-completion-detector.sh" "us-completion-detector" "$INC_ID"
416
-
417
- # Queue events for backward compatibility (background)
418
- if [[ "$FILE_PATH" == *tasks.md ]]; then
419
- safe_run_background "$HOOK_DIR/queue/enqueue.sh" "enqueue-task" "task.updated" "$INC_ID"
420
- safe_run_background "$SCRIPTS_DIR/update-dashboard-cache.sh" "dashboard-cache" "$INC_ID" "tasks"
421
- else
422
- safe_run_background "$HOOK_DIR/queue/enqueue.sh" "enqueue-spec" "spec.updated" "$INC_ID"
423
- safe_run_background "$SCRIPTS_DIR/update-dashboard-cache.sh" "dashboard-cache" "$INC_ID" "spec"
424
- fi
425
- ;;
426
-
427
- */.specweave/increments/*/plan.md)
428
- log_debug "Plan change detected"
429
- # Queue plan update event (background)
430
- safe_run_background "$HOOK_DIR/queue/enqueue.sh" "enqueue-plan" "plan.updated" "$INC_ID"
431
- ;;
432
-
433
- *)
434
- # Not a specweave increment file, ignore
435
- exit 0
436
- ;;
437
- esac
438
-
439
- # ============================================================================
440
- # NO BACKGROUND PROCESSOR (v1.0.148)
441
- # ============================================================================
442
- # Events are now batched and processed by stop-sync.sh at session end.
443
- # Critical events (increment.done/reopened) sync immediately above.
444
- # This eliminates the need for a background processor daemon.
445
-
446
- log_debug "Dispatcher completed successfully"
447
- exit 0
@@ -1,104 +0,0 @@
1
- #!/bin/bash
2
- # pre-tool-use.sh - Dispatcher for PreToolUse guards
3
- #
4
- # Routes to appropriate guards based on tool type:
5
- # - Write: spec-template-enforcement-guard for spec.md
6
- # - Edit: status-completion-guard for metadata.json protection
7
- #
8
- # Returns: {"decision":"allow"} or {"decision":"block","reason":"..."}
9
- #
10
- # @since 1.0.167
11
- # @updated 1.0.196 - Added status-completion-guard for Edit operations
12
- # @updated 1.0.352 - Added interview-enforcement-guard for agent-spawned spec.md writes
13
-
14
- set +e # CRITICAL: Never exit on error - matches all other hook scripts
15
-
16
- # Read input once and store
17
- INPUT=$(cat)
18
-
19
- # Skip if hooks disabled
20
- [[ "${SPECWEAVE_DISABLE_HOOKS:-0}" == "1" ]] && echo '{"decision":"allow"}' && exit 0
21
-
22
- # Detect project root via walk-up (cwd may not be root)
23
- _DIR="$PWD"
24
- _LIMIT=0
25
- while [[ "$_DIR" != "/" ]] && [[ ! -f "$_DIR/.specweave/config.json" ]] && [[ $_LIMIT -lt 50 ]]; do
26
- _DIR=$(dirname "$_DIR")
27
- _LIMIT=$((_LIMIT + 1))
28
- done
29
- [[ ! -f "$_DIR/.specweave/config.json" ]] && echo '{"decision":"allow"}' && exit 0
30
-
31
- # Fast file_path check: skip non-increment files before jq (< 5ms)
32
- if ! echo "$INPUT" | grep -q '"file_path".*\.specweave/increments/'; then
33
- echo '{"decision":"allow"}'
34
- exit 0
35
- fi
36
-
37
- # Get plugin root for guard paths
38
- PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-$(dirname "$(dirname "$(dirname "$0")")")}"
39
- GUARDS_DIR="$PLUGIN_ROOT/hooks/v2/guards"
40
-
41
- # Extract tool info
42
- TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name // .toolName // ""')
43
-
44
- # ============================================================================
45
- # Edit Tool Guards
46
- # ============================================================================
47
-
48
- if [[ "$TOOL_NAME" == "Edit" ]]; then
49
- # Status Completion Guard - Prevents direct status changes to "completed"
50
- # RULE: Use /sw:done or /sw:auto instead of direct metadata.json edits
51
- STATUS_GUARD="$GUARDS_DIR/status-completion-guard.sh"
52
- if [[ -x "$STATUS_GUARD" ]]; then
53
- STATUS_RESULT=$(echo "$INPUT" | "$STATUS_GUARD" 2>/dev/null || echo '{"decision":"allow"}')
54
- STATUS_DECISION=$(echo "$STATUS_RESULT" | jq -r '.decision // "allow"')
55
-
56
- if [[ "$STATUS_DECISION" == "block" ]]; then
57
- echo "$STATUS_RESULT"
58
- exit 0
59
- fi
60
- fi
61
-
62
- echo '{"decision":"allow"}'
63
- exit 0
64
- fi
65
-
66
- # ============================================================================
67
- # Write Tool Guards
68
- # ============================================================================
69
-
70
- if [[ "$TOOL_NAME" == "Write" ]]; then
71
- # Spec Template Enforcement Guard
72
- # Enforces template-first workflow for spec.md (skill usage)
73
- SPEC_GUARD="$GUARDS_DIR/spec-template-enforcement-guard.sh"
74
- if [[ -x "$SPEC_GUARD" ]]; then
75
- SPEC_RESULT=$(echo "$INPUT" | "$SPEC_GUARD" 2>/dev/null || echo '{"decision":"allow"}')
76
- SPEC_DECISION=$(echo "$SPEC_RESULT" | jq -r '.decision // "allow"')
77
-
78
- if [[ "$SPEC_DECISION" == "block" ]]; then
79
- echo "$SPEC_RESULT"
80
- exit 0
81
- fi
82
- fi
83
-
84
- # Interview Enforcement Guard
85
- # Blocks spec.md writes until deep interview is complete (when strict mode enabled)
86
- # Needed here because agent-spawned writes don't inherit skill-level hooks
87
- INTERVIEW_GUARD="$GUARDS_DIR/interview-enforcement-guard.sh"
88
- if [[ -x "$INTERVIEW_GUARD" ]]; then
89
- INTERVIEW_RESULT=$(echo "$INPUT" | "$INTERVIEW_GUARD" 2>/dev/null || echo '{"decision":"allow"}')
90
- INTERVIEW_DECISION=$(echo "$INTERVIEW_RESULT" | jq -r '.decision // "allow"')
91
-
92
- if [[ "$INTERVIEW_DECISION" == "block" ]]; then
93
- echo "$INTERVIEW_RESULT"
94
- exit 0
95
- fi
96
- fi
97
-
98
- echo '{"decision":"allow"}'
99
- exit 0
100
- fi
101
-
102
- # Allow all other tools
103
- echo '{"decision":"allow"}'
104
- exit 0