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,475 +0,0 @@
1
- #!/bin/bash
2
- # task-ac-sync-guard.sh - Non-blocking Task-AC synchronization
3
- #
4
- # v1.0.43+: FULLY NON-BLOCKING - operations ALWAYS succeed, errors become warnings
5
- #
6
- # CRITICAL DESIGN PRINCIPLE:
7
- # - This hook MUST NEVER cause an Edit to fail
8
- # - All errors are logged as warnings
9
- # - Original operation ALWAYS succeeds
10
- # - If sync fails, user gets warning message (not error)
11
- #
12
- # When a task is marked complete in tasks.md, this hook:
13
- # 1. Marks all **Acceptance** checkboxes in the completed task as [x]
14
- # 2. Extracts the AC tags from the completed task (e.g., AC-US1-01, AC-US1-02)
15
- # 3. Automatically marks those ACs as complete in spec.md
16
- # 4. When ALL tasks are complete -> auto-transitions status to ready_for_review
17
- #
18
- # PostToolUse hook - runs AFTER Edit/Write tool completes on tasks.md
19
- #
20
- # CROSS-PLATFORM: Works on macOS, Linux, and Windows (Git Bash/WSL)
21
-
22
- set +e # CRITICAL: Never exit on error
23
-
24
- [[ "${SPECWEAVE_DISABLE_HOOKS:-0}" == "1" ]] && exit 0
25
-
26
- # ============================================================================
27
- # CONSTANTS
28
- # ============================================================================
29
-
30
- HOOK_NAME="task-ac-sync"
31
- HOOK_VERSION="1.0.43"
32
-
33
- # ============================================================================
34
- # PROJECT ROOT DETECTION (CRITICAL: must NOT fallback to pwd!)
35
- # ============================================================================
36
-
37
- find_project_root() {
38
- local dir="$PWD"
39
- while [[ "$dir" != "/" ]]; do
40
- if [[ -f "$dir/.specweave/config.json" ]]; then
41
- echo "$dir"
42
- return 0
43
- fi
44
- dir=$(dirname "$dir")
45
- done
46
- # Return empty - NOT pwd (prevents .specweave pollution)
47
- return 1
48
- }
49
-
50
- PROJECT_ROOT=$(find_project_root)
51
- [[ -z "$PROJECT_ROOT" ]] && exit 0
52
- [[ ! -f "$PROJECT_ROOT/.specweave/config.json" ]] && exit 0
53
-
54
- # ============================================================================
55
- # LOGGING INFRASTRUCTURE
56
- # ============================================================================
57
-
58
- LOGS_DIR="$PROJECT_ROOT/.specweave/logs"
59
- DEBUG_LOG="$LOGS_DIR/task-ac-sync.log"
60
- WARNING_LOG="$LOGS_DIR/hook-warnings.log"
61
- mkdir -p "$LOGS_DIR" 2>/dev/null || true
62
-
63
- log_debug() {
64
- echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" >> "$DEBUG_LOG" 2>/dev/null || true
65
- }
66
-
67
- log_warning() {
68
- local message="$1"
69
- local details="${2:-}"
70
-
71
- # Always log to file
72
- {
73
- echo "[$(date '+%Y-%m-%d %H:%M:%S')] WARNING [$HOOK_NAME]: $message"
74
- [[ -n "$details" ]] && echo " Details: $details"
75
- } >> "$WARNING_LOG" 2>/dev/null || true
76
-
77
- # Show to user - they should know the sync didn't work
78
- echo ""
79
- echo " [Hook Warning] $HOOK_NAME: $message"
80
- [[ -n "$details" ]] && echo " $details"
81
- echo " (File operation succeeded - sync issue only)"
82
- echo ""
83
- }
84
-
85
- log_success() {
86
- local message="$1"
87
- log_debug "SUCCESS: $message"
88
- }
89
-
90
- # ============================================================================
91
- # INPUT PARSING (with safe fallbacks)
92
- # ============================================================================
93
-
94
- # Accept file path as $1 argument (background mode) or fall back to stdin (sync mode)
95
- if [[ -n "${1:-}" ]] && [[ "$1" == *tasks.md ]]; then
96
- FILE_PATH="$1"
97
- else
98
- # Legacy: read from stdin (when called via safe_run_sync)
99
- INPUT=$(timeout 1 cat 2>/dev/null || cat 2>/dev/null || echo '{}')
100
- FILE_PATH=$(echo "$INPUT" | grep -o '"file_path"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*"\([^"]*\)"/\1/')
101
- fi
102
-
103
- # Only care about tasks.md files in increments folder
104
- if [[ "$FILE_PATH" != */.specweave/increments/*/tasks.md ]]; then
105
- exit 0
106
- fi
107
-
108
- log_debug "Task edit detected: $FILE_PATH"
109
-
110
- # Extract paths
111
- INCREMENT_DIR=$(dirname "$FILE_PATH")
112
- SPEC_FILE="$INCREMENT_DIR/spec.md"
113
- METADATA_FILE="$INCREMENT_DIR/metadata.json"
114
-
115
- # Verify files exist
116
- if [[ ! -f "$FILE_PATH" ]]; then
117
- log_warning "tasks.md not found (may have been moved)" "$FILE_PATH"
118
- exit 0
119
- fi
120
-
121
- # ============================================================================
122
- # STEP 0: Check if any task is marked complete
123
- # ============================================================================
124
-
125
- # Check if tasks.md has any completed tasks (check actual file, not edit input)
126
- if ! grep -qE '^\*\*Status\*\*:[[:space:]]*\[x\]' "$FILE_PATH" 2>/dev/null; then
127
- log_debug "No completed tasks found, skipping"
128
- exit 0
129
- fi
130
-
131
- log_debug "Completed tasks detected - syncing ACs..."
132
-
133
- # ============================================================================
134
- # STEP 1: Mark task's **Acceptance** checkboxes as complete (NON-BLOCKING)
135
- # ============================================================================
136
-
137
- sync_acceptance_checkboxes() {
138
- log_debug "Syncing acceptance checkboxes..."
139
-
140
- # Create temp file for safe editing
141
- local temp_file
142
- temp_file=$(mktemp 2>/dev/null) || {
143
- log_warning "Failed to create temp file for acceptance sync"
144
- return 0
145
- }
146
-
147
- # Process with awk (buffered approach - never modifies during read)
148
- if ! awk '
149
- BEGIN {
150
- task_start = 0
151
- task_lines = ""
152
- task_completed = 0
153
- }
154
-
155
- /^### T-[0-9]+:/ {
156
- if (task_start > 0) {
157
- n = split(task_lines, lines, "\n")
158
- in_acceptance = 0
159
- for (i = 1; i <= n; i++) {
160
- line = lines[i]
161
- if (line ~ /^\*\*Acceptance\*\*:/) in_acceptance = 1
162
- if (line ~ /^\*\*[A-Z]/ && line !~ /^\*\*Acceptance/) in_acceptance = 0
163
- if (in_acceptance && task_completed && line ~ /^[-*] \[ \]/) {
164
- sub(/\[ \]/, "[x]", line)
165
- }
166
- print line
167
- }
168
- }
169
- task_start = NR
170
- task_lines = $0
171
- task_completed = 0
172
- next
173
- }
174
-
175
- {
176
- if (task_start > 0) {
177
- task_lines = task_lines "\n" $0
178
- if ($0 ~ /^\*\*Status\*\*:[[:space:]]*\[x\]/) {
179
- task_completed = 1
180
- }
181
- } else {
182
- print
183
- }
184
- }
185
-
186
- END {
187
- if (task_start > 0) {
188
- n = split(task_lines, lines, "\n")
189
- in_acceptance = 0
190
- for (i = 1; i <= n; i++) {
191
- line = lines[i]
192
- if (line ~ /^\*\*Acceptance\*\*:/) in_acceptance = 1
193
- if (line ~ /^\*\*[A-Z]/ && line !~ /^\*\*Acceptance/) in_acceptance = 0
194
- if (in_acceptance && task_completed && line ~ /^[-*] \[ \]/) {
195
- sub(/\[ \]/, "[x]", line)
196
- }
197
- print line
198
- }
199
- }
200
- }
201
- ' "$FILE_PATH" > "$temp_file" 2>/dev/null; then
202
- log_warning "awk processing failed for acceptance checkboxes"
203
- rm -f "$temp_file" 2>/dev/null
204
- return 0
205
- fi
206
-
207
- # Verify output is valid (not empty, not truncated)
208
- if [[ ! -s "$temp_file" ]]; then
209
- log_warning "awk produced empty output, skipping acceptance sync"
210
- rm -f "$temp_file" 2>/dev/null
211
- return 0
212
- fi
213
-
214
- # Check if changes were made
215
- if diff -q "$FILE_PATH" "$temp_file" >/dev/null 2>&1; then
216
- log_debug "No acceptance checkboxes to update"
217
- rm -f "$temp_file" 2>/dev/null
218
- return 0
219
- fi
220
-
221
- # Apply changes
222
- if mv "$temp_file" "$FILE_PATH" 2>/dev/null; then
223
- log_success "Updated acceptance checkboxes for completed tasks"
224
- else
225
- log_warning "Failed to update acceptance checkboxes" "mv failed"
226
- rm -f "$temp_file" 2>/dev/null
227
- fi
228
-
229
- return 0
230
- }
231
-
232
- # Run acceptance sync (never fails)
233
- sync_acceptance_checkboxes
234
-
235
- # ============================================================================
236
- # STEP 2: Extract AC tags from completed tasks
237
- # ============================================================================
238
-
239
- extract_completed_acs() {
240
- local tasks_file="$1"
241
- local -a completed_acs=()
242
-
243
- # Normalize line endings for cross-platform compatibility
244
- local temp_normalized
245
- temp_normalized=$(mktemp 2>/dev/null) || {
246
- log_warning "Failed to create temp file for AC extraction"
247
- return 0
248
- }
249
-
250
- tr -d '\r' < "$tasks_file" > "$temp_normalized" 2>/dev/null || cat "$tasks_file" > "$temp_normalized"
251
-
252
- local current_task=""
253
- local current_acs=""
254
-
255
- while IFS= read -r line; do
256
- # Detect task header
257
- if [[ "$line" =~ ^###[[:space:]]+(T-[0-9]+): ]]; then
258
- current_task="${BASH_REMATCH[1]}"
259
- current_acs=""
260
- fi
261
-
262
- # Detect AC tags (handle whitespace variations)
263
- if [[ "$line" =~ ^\*\*Satisfies[[:space:]]*ACs?\*\*:[[:space:]]*(.*) ]]; then
264
- current_acs="${BASH_REMATCH[1]}"
265
- fi
266
-
267
- # Detect completion status
268
- if [[ "$line" =~ ^\*\*Status\*\*:[[:space:]]*\[x\] ]]; then
269
- if [[ -n "$current_acs" ]]; then
270
- # Split ACs by comma
271
- IFS=',' read -ra AC_ARRAY <<< "$current_acs"
272
- for ac in "${AC_ARRAY[@]}"; do
273
- # Trim whitespace and carriage returns
274
- ac=$(echo "$ac" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
275
- ac="${ac%$'\r'}"
276
- [[ -n "$ac" ]] && completed_acs+=("$ac")
277
- done
278
- fi
279
- fi
280
- done < "$temp_normalized"
281
-
282
- rm -f "$temp_normalized" 2>/dev/null
283
-
284
- # Output space-separated list
285
- echo "${completed_acs[*]}"
286
- }
287
-
288
- COMPLETED_ACS_STRING=$(extract_completed_acs "$FILE_PATH")
289
- read -ra COMPLETED_ACS <<< "$COMPLETED_ACS_STRING"
290
-
291
- log_debug "Completed ACs: ${COMPLETED_ACS[*]}"
292
-
293
- # ============================================================================
294
- # STEP 3: Mark ACs as complete in spec.md (NON-BLOCKING)
295
- # ============================================================================
296
-
297
- sync_spec_acs() {
298
- if [[ ! -f "$SPEC_FILE" ]]; then
299
- log_debug "spec.md not found, skipping AC sync"
300
- return 0
301
- fi
302
-
303
- if [[ ${#COMPLETED_ACS[@]} -eq 0 ]]; then
304
- log_debug "No ACs to sync"
305
- return 0
306
- fi
307
-
308
- local updated_count=0
309
- local not_found_count=0
310
- local not_found_acs=()
311
-
312
- for ac in "${COMPLETED_ACS[@]}"; do
313
- [[ -z "$ac" ]] && continue
314
-
315
- # Escape special characters for grep/sed
316
- local ac_escaped
317
- ac_escaped=$(printf '%s' "$ac" | sed 's/[.[\*^$()+?{|\\]/\\&/g')
318
-
319
- # Check if AC exists and is unchecked
320
- # Support multiple formats:
321
- # - [ ] **AC-US1-01**: Description
322
- # - [ ] **AC-US1-01** Description
323
- # - [ ] AC-US1-01: Description
324
- if grep -qE "^[-*][[:space:]]+\[ \][[:space:]]+(\*\*)?${ac_escaped}(\*\*)?" "$SPEC_FILE" 2>/dev/null; then
325
- # Try macOS sed first, then Linux
326
- if sed -i '' "s|^\([-*][[:space:]]\+\)\[ \]\([[:space:]]\+\)\(\*\*\)\?${ac_escaped}\(\*\*\)\?|\1[x]\2\3${ac}\4|" "$SPEC_FILE" 2>/dev/null || \
327
- sed -i "s|^\([-*][[:space:]]\+\)\[ \]\([[:space:]]\+\)\(\*\*\)\?${ac_escaped}\(\*\*\)\?|\1[x]\2\3${ac}\4|" "$SPEC_FILE" 2>/dev/null; then
328
- log_debug "Marked AC complete: $ac"
329
- ((updated_count++))
330
- else
331
- log_debug "sed failed for AC: $ac"
332
- not_found_acs+=("$ac")
333
- ((not_found_count++))
334
- fi
335
- else
336
- log_debug "AC not found or already complete: $ac"
337
- # Check if it's already complete
338
- if grep -qE "^[-*][[:space:]]+\[x\][[:space:]]+(\*\*)?${ac_escaped}(\*\*)?" "$SPEC_FILE" 2>/dev/null; then
339
- log_debug "AC already marked complete: $ac"
340
- else
341
- not_found_acs+=("$ac")
342
- ((not_found_count++))
343
- fi
344
- fi
345
- done
346
-
347
- if [[ $updated_count -gt 0 ]]; then
348
- log_success "Updated $updated_count ACs in spec.md"
349
- fi
350
-
351
- if [[ $not_found_count -gt 0 ]]; then
352
- log_warning "Some ACs could not be synced to spec.md" "Not found: ${not_found_acs[*]}"
353
- fi
354
-
355
- return 0
356
- }
357
-
358
- # Run spec AC sync (never fails)
359
- sync_spec_acs
360
-
361
- # ============================================================================
362
- # STEP 4: Check if ALL tasks complete -> auto-transition to ready_for_review
363
- # ============================================================================
364
-
365
- check_auto_transition() {
366
- local total_tasks
367
- local completed_tasks
368
-
369
- total_tasks=$(grep -c '^\*\*Status\*\*:' "$FILE_PATH" 2>/dev/null || echo 0)
370
- completed_tasks=$(grep -c '^\*\*Status\*\*:[[:space:]]*\[x\]' "$FILE_PATH" 2>/dev/null || echo 0)
371
-
372
- log_debug "Task progress: $completed_tasks / $total_tasks"
373
-
374
- # Not all complete? Exit early
375
- if [[ "$total_tasks" -eq 0 ]] || [[ "$completed_tasks" -ne "$total_tasks" ]]; then
376
- return 0
377
- fi
378
-
379
- log_debug "ALL TASKS COMPLETE! Checking for auto-transition..."
380
-
381
- # Need jq for JSON manipulation
382
- if ! command -v jq >/dev/null 2>&1; then
383
- log_warning "jq not installed - status auto-transition skipped" \
384
- "Install: brew install jq (macOS) | apt install jq (Linux)"
385
- return 0
386
- fi
387
-
388
- if [[ ! -f "$METADATA_FILE" ]]; then
389
- log_debug "metadata.json not found, skipping auto-transition"
390
- return 0
391
- fi
392
-
393
- local current_status
394
- current_status=$(jq -r '.status // "active"' "$METADATA_FILE" 2>/dev/null)
395
-
396
- if [[ "$current_status" != "active" ]] && [[ "$current_status" != "in-progress" ]]; then
397
- log_debug "Status is '$current_status', not auto-transitioning"
398
- return 0
399
- fi
400
-
401
- # Auto-transition to ready_for_review
402
- log_debug "Auto-transitioning: $current_status -> ready_for_review"
403
-
404
- local tmp_file
405
- tmp_file=$(mktemp 2>/dev/null) || {
406
- log_warning "Failed to create temp file for status update"
407
- return 0
408
- }
409
-
410
- if jq '.status = "ready_for_review" | .updated = (now | strftime("%Y-%m-%dT%H:%M:%S.000Z"))' \
411
- "$METADATA_FILE" > "$tmp_file" 2>/dev/null && [[ -s "$tmp_file" ]]; then
412
- if mv "$tmp_file" "$METADATA_FILE" 2>/dev/null; then
413
- log_success "Status updated to ready_for_review"
414
-
415
- # Show success banner to user
416
- echo ""
417
- echo " ALL TASKS COMPLETED! Status -> ready_for_review"
418
- echo " ------------------------------------------------"
419
- echo " Tasks: $completed_tasks/$total_tasks (100%)"
420
- echo ""
421
- echo " Next step: Run /sw:done to close the increment"
422
- echo " ------------------------------------------------"
423
- echo ""
424
- else
425
- log_warning "Failed to update metadata.json"
426
- rm -f "$tmp_file" 2>/dev/null
427
- fi
428
- else
429
- log_warning "jq failed to update metadata.json"
430
- rm -f "$tmp_file" 2>/dev/null
431
- fi
432
-
433
- return 0
434
- }
435
-
436
- # Run auto-transition check (never fails)
437
- check_auto_transition
438
-
439
- # ============================================================================
440
- # STEP 5: Trigger LifecycleHookDispatcher.onTaskCompleted (NON-BLOCKING)
441
- # ============================================================================
442
-
443
- trigger_sync_task() {
444
- # Extract increment folder name (e.g. "0400-sync-pipeline-reliability")
445
- local increment_id
446
- increment_id=$(basename "$INCREMENT_DIR")
447
-
448
- [[ -z "$increment_id" ]] && return 0
449
-
450
- # Find specweave CLI (npx fallback)
451
- local sw_bin=""
452
- if command -v specweave >/dev/null 2>&1; then
453
- sw_bin="specweave"
454
- elif command -v npx >/dev/null 2>&1; then
455
- sw_bin="npx specweave"
456
- else
457
- log_debug "specweave CLI not found, skipping sync-task"
458
- return 0
459
- fi
460
-
461
- # Run in background — must not block the Edit operation
462
- (cd "$PROJECT_ROOT" && $sw_bin sync-task "$increment_id" >>"$DEBUG_LOG" 2>&1) &
463
- log_debug "Spawned sync-task for $increment_id (pid $!)"
464
- return 0
465
- }
466
-
467
- # Run sync-task trigger (never fails, never blocks)
468
- trigger_sync_task
469
-
470
- # ============================================================================
471
- # ALWAYS EXIT SUCCESS
472
- # ============================================================================
473
-
474
- log_debug "Hook completed successfully"
475
- exit 0