specweave 1.0.2 → 1.0.6

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 (46) hide show
  1. package/CLAUDE.md +42 -0
  2. package/dist/src/cli/commands/init.d.ts.map +1 -1
  3. package/dist/src/cli/commands/init.js +6 -3
  4. package/dist/src/cli/commands/init.js.map +1 -1
  5. package/dist/src/cli/helpers/issue-tracker/github-multi-repo.d.ts.map +1 -1
  6. package/dist/src/cli/helpers/issue-tracker/github-multi-repo.js +6 -2
  7. package/dist/src/cli/helpers/issue-tracker/github-multi-repo.js.map +1 -1
  8. package/dist/src/cli/helpers/issue-tracker/github.d.ts +11 -2
  9. package/dist/src/cli/helpers/issue-tracker/github.d.ts.map +1 -1
  10. package/dist/src/cli/helpers/issue-tracker/github.js +68 -2
  11. package/dist/src/cli/helpers/issue-tracker/github.js.map +1 -1
  12. package/dist/src/cli/helpers/issue-tracker/index.js +3 -3
  13. package/dist/src/cli/helpers/issue-tracker/index.js.map +1 -1
  14. package/dist/src/cli/helpers/issue-tracker/types.d.ts +5 -0
  15. package/dist/src/cli/helpers/issue-tracker/types.d.ts.map +1 -1
  16. package/dist/src/cli/helpers/issue-tracker/types.js.map +1 -1
  17. package/dist/src/core/repo-structure/repo-structure-manager.d.ts.map +1 -1
  18. package/dist/src/core/repo-structure/repo-structure-manager.js +5 -2
  19. package/dist/src/core/repo-structure/repo-structure-manager.js.map +1 -1
  20. package/package.json +1 -1
  21. package/plugins/specweave/hooks/docs-changed.sh.backup +79 -0
  22. package/plugins/specweave/hooks/human-input-required.sh.backup +75 -0
  23. package/plugins/specweave/hooks/post-first-increment.sh.backup +61 -0
  24. package/plugins/specweave/hooks/post-increment-change.sh.backup +98 -0
  25. package/plugins/specweave/hooks/post-increment-completion.sh.backup +231 -0
  26. package/plugins/specweave/hooks/post-increment-planning.sh.backup +1048 -0
  27. package/plugins/specweave/hooks/post-increment-status-change.sh.backup +147 -0
  28. package/plugins/specweave/hooks/post-spec-update.sh.backup +158 -0
  29. package/plugins/specweave/hooks/post-user-story-complete.sh.backup +179 -0
  30. package/plugins/specweave/hooks/pre-command-deduplication.sh.backup +83 -0
  31. package/plugins/specweave/hooks/pre-implementation.sh.backup +67 -0
  32. package/plugins/specweave/hooks/pre-task-completion.sh.backup +194 -0
  33. package/plugins/specweave/hooks/pre-tool-use.sh.backup +133 -0
  34. package/plugins/specweave/hooks/user-prompt-submit.sh.backup +386 -0
  35. package/plugins/specweave/hooks/v2/dispatchers/post-tool-use.sh +13 -0
  36. package/plugins/specweave/hooks/v2/guards/task-ac-sync-guard.sh +357 -0
  37. package/plugins/specweave-ado/hooks/post-living-docs-update.sh.backup +353 -0
  38. package/plugins/specweave-ado/hooks/post-task-completion.sh.backup +172 -0
  39. package/plugins/specweave-ado/lib/enhanced-ado-sync.js +170 -0
  40. package/plugins/specweave-github/hooks/.specweave/logs/hooks-debug.log +1262 -0
  41. package/plugins/specweave-github/hooks/post-task-completion.sh.backup +258 -0
  42. package/plugins/specweave-github/lib/enhanced-github-sync.js +220 -0
  43. package/plugins/specweave-jira/hooks/post-task-completion.sh.backup +172 -0
  44. package/plugins/specweave-jira/lib/enhanced-jira-sync.js +134 -0
  45. package/plugins/specweave-release/hooks/.specweave/logs/dora-tracking.log +1254 -0
  46. package/plugins/specweave-release/hooks/post-task-completion.sh.backup +110 -0
@@ -0,0 +1,357 @@
1
+ #!/bin/bash
2
+ # task-ac-sync-guard.sh - Enforce Task-AC synchronization on tasks.md edits
3
+ #
4
+ # v0.35.2+: When a task is marked complete in tasks.md, this hook:
5
+ # 1. Marks all **Acceptance** checkboxes in the completed task as [x]
6
+ # 2. Extracts the AC tags from the completed task (e.g., AC-US1-01, AC-US1-02)
7
+ # 3. Automatically marks those ACs as complete in spec.md
8
+ # 4. When ALL tasks are complete → auto-transitions status to ready_for_review
9
+ #
10
+ # This implements EDA (Event-Driven Architecture) for SpecWeave task-AC sync.
11
+ #
12
+ # PostToolUse hook - runs AFTER Edit/Write tool completes on tasks.md
13
+ #
14
+ # CROSS-PLATFORM: Works on macOS, Linux, and Windows (Git Bash/WSL)
15
+ # - Uses portable sed syntax with fallbacks
16
+ # - Handles CRLF line endings (Windows)
17
+ # - Supports both - and * bullet formats
18
+ #
19
+ # CRITICAL: This hook must be NON-BLOCKING to prevent Claude Code crashes
20
+ set +e
21
+
22
+ [[ "${SPECWEAVE_DISABLE_HOOKS:-0}" == "1" ]] && exit 0
23
+
24
+ # Find project root
25
+ find_project_root() {
26
+ local dir="$PWD"
27
+ while [[ "$dir" != "/" ]]; do
28
+ if [[ -d "$dir/.specweave" ]]; then
29
+ echo "$dir"
30
+ return 0
31
+ fi
32
+ dir=$(dirname "$dir")
33
+ done
34
+ echo "$PWD"
35
+ }
36
+
37
+ PROJECT_ROOT=$(find_project_root)
38
+
39
+ # Skip if not a SpecWeave project
40
+ [[ ! -d "$PROJECT_ROOT/.specweave" ]] && exit 0
41
+
42
+ LOGS_DIR="$PROJECT_ROOT/.specweave/logs"
43
+ DEBUG_LOG="$LOGS_DIR/task-ac-sync.log"
44
+ mkdir -p "$LOGS_DIR" 2>/dev/null || true
45
+
46
+ # Read stdin for tool input
47
+ INPUT=$(cat)
48
+
49
+ # Extract file_path from tool input
50
+ FILE_PATH=$(echo "$INPUT" | grep -o '"file_path"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*"\([^"]*\)"/\1/')
51
+
52
+ # Only care about tasks.md files in increments folder
53
+ if [[ "$FILE_PATH" != */.specweave/increments/*/tasks.md ]]; then
54
+ exit 0
55
+ fi
56
+
57
+ echo "[$(date)] 📋 Task edit detected: $FILE_PATH" >> "$DEBUG_LOG" 2>/dev/null || true
58
+
59
+ # Extract increment directory from file path
60
+ INCREMENT_DIR=$(dirname "$FILE_PATH")
61
+ SPEC_FILE="$INCREMENT_DIR/spec.md"
62
+ METADATA_FILE="$INCREMENT_DIR/metadata.json"
63
+
64
+ # Check if this edit marks a task as complete
65
+ # Look for pattern: **Status**: [x] completed
66
+ NEW_CONTENT=$(echo "$INPUT" | grep -o '"new_string"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1)
67
+
68
+ if ! echo "$NEW_CONTENT" | grep -qE '\[x\].*completed'; then
69
+ echo "[$(date)] ⏭️ Not a task completion edit, skipping" >> "$DEBUG_LOG" 2>/dev/null || true
70
+ exit 0
71
+ fi
72
+
73
+ echo "[$(date)] ✅ Task completion detected!" >> "$DEBUG_LOG" 2>/dev/null || true
74
+
75
+ # ============================================================================
76
+ # STEP 1: Mark task's **Acceptance** checkboxes as complete
77
+ # ============================================================================
78
+ # When a task is marked complete, all its Acceptance points should be checked.
79
+ # Format in tasks.md:
80
+ # ### T-001: Task Title
81
+ # **Acceptance**:
82
+ # - [ ] Point 1
83
+ # - [ ] Point 2
84
+ # **Status**: [x] completed
85
+ #
86
+ # We need to find the task that was just completed and check its Acceptance items.
87
+ # Strategy: Parse tasks.md, find completed tasks, mark their unchecked Acceptance items.
88
+
89
+ ACCEPTANCE_UPDATED=0
90
+
91
+ # Create a temp file for safe in-place editing
92
+ TASKS_EDIT_TEMP=$(mktemp)
93
+ cp "$FILE_PATH" "$TASKS_EDIT_TEMP" 2>/dev/null || true
94
+
95
+ # Track state while parsing
96
+ IN_ACCEPTANCE_SECTION=0
97
+ CURRENT_TASK_COMPLETED=0
98
+ CURRENT_TASK_ID=""
99
+
100
+ # Process line by line to identify and update Acceptance checkboxes
101
+ while IFS= read -r line; do
102
+ # Detect task header - reset state
103
+ if [[ "$line" =~ ^###[[:space:]]+(T-[0-9]+): ]]; then
104
+ IN_ACCEPTANCE_SECTION=0
105
+ CURRENT_TASK_COMPLETED=0
106
+ CURRENT_TASK_ID="${BASH_REMATCH[1]}"
107
+ fi
108
+
109
+ # Detect **Acceptance**: section start
110
+ if [[ "$line" =~ ^\*\*Acceptance\*\*: ]]; then
111
+ IN_ACCEPTANCE_SECTION=1
112
+ fi
113
+
114
+ # Detect end of Acceptance section (next section or blank line followed by **)
115
+ if [[ $IN_ACCEPTANCE_SECTION -eq 1 ]] && [[ "$line" =~ ^\*\*[A-Z] ]] && [[ ! "$line" =~ ^\*\*Acceptance ]]; then
116
+ IN_ACCEPTANCE_SECTION=0
117
+ fi
118
+
119
+ # Detect completion status for current task
120
+ if [[ "$line" =~ ^\*\*Status\*\*:[[:space:]]*\[x\] ]]; then
121
+ CURRENT_TASK_COMPLETED=1
122
+ fi
123
+ done < "$FILE_PATH"
124
+
125
+ # Now do the actual replacement: for completed tasks, check all Acceptance items
126
+ # We use awk with two-pass logic:
127
+ # Pass 1: Build list of completed task IDs (tasks where Status has [x])
128
+ # Pass 2: For those tasks, check their Acceptance items
129
+ #
130
+ # Since awk reads sequentially and Acceptance comes BEFORE Status in the file,
131
+ # we need to buffer the entire task block and process it when we see the next task.
132
+ awk '
133
+ BEGIN {
134
+ task_start = 0
135
+ task_lines = ""
136
+ task_completed = 0
137
+ }
138
+
139
+ # Task header - process previous task block first, then start new one
140
+ /^### T-[0-9]+:/ {
141
+ # Output previous task block (with modifications if completed)
142
+ if (task_start > 0) {
143
+ n = split(task_lines, lines, "\n")
144
+ in_acceptance = 0
145
+ for (i = 1; i <= n; i++) {
146
+ line = lines[i]
147
+ # Track Acceptance section
148
+ if (line ~ /^\*\*Acceptance\*\*:/) in_acceptance = 1
149
+ if (line ~ /^\*\*[A-Z]/ && line !~ /^\*\*Acceptance/) in_acceptance = 0
150
+ # Check unchecked items in Acceptance section of completed tasks
151
+ if (in_acceptance && task_completed && line ~ /^[-*] \[ \]/) {
152
+ sub(/\[ \]/, "[x]", line)
153
+ }
154
+ print line
155
+ }
156
+ }
157
+ # Start new task block
158
+ task_start = NR
159
+ task_lines = $0
160
+ task_completed = 0
161
+ next
162
+ }
163
+
164
+ # Accumulate lines and detect completion
165
+ {
166
+ if (task_start > 0) {
167
+ task_lines = task_lines "\n" $0
168
+ if ($0 ~ /^\*\*Status\*\*:[[:space:]]*\[x\]/) {
169
+ task_completed = 1
170
+ }
171
+ } else {
172
+ # Lines before first task (header content)
173
+ print
174
+ }
175
+ }
176
+
177
+ # End of file - process last task block
178
+ END {
179
+ if (task_start > 0) {
180
+ n = split(task_lines, lines, "\n")
181
+ in_acceptance = 0
182
+ for (i = 1; i <= n; i++) {
183
+ line = lines[i]
184
+ if (line ~ /^\*\*Acceptance\*\*:/) in_acceptance = 1
185
+ if (line ~ /^\*\*[A-Z]/ && line !~ /^\*\*Acceptance/) in_acceptance = 0
186
+ if (in_acceptance && task_completed && line ~ /^[-*] \[ \]/) {
187
+ sub(/\[ \]/, "[x]", line)
188
+ }
189
+ print line
190
+ }
191
+ }
192
+ }
193
+ ' "$FILE_PATH" > "$TASKS_EDIT_TEMP" 2>/dev/null
194
+
195
+ # Check if changes were made
196
+ if ! diff -q "$FILE_PATH" "$TASKS_EDIT_TEMP" >/dev/null 2>&1; then
197
+ # Changes detected - update the file
198
+ mv "$TASKS_EDIT_TEMP" "$FILE_PATH" 2>/dev/null
199
+ ACCEPTANCE_UPDATED=1
200
+ echo "[$(date)] ✅ Updated Acceptance checkboxes for completed tasks" >> "$DEBUG_LOG" 2>/dev/null || true
201
+ else
202
+ rm -f "$TASKS_EDIT_TEMP" 2>/dev/null || true
203
+ echo "[$(date)] ⏭️ No Acceptance checkboxes to update" >> "$DEBUG_LOG" 2>/dev/null || true
204
+ fi
205
+
206
+ # ============================================================================
207
+ # STEP 2: Extract AC tags from the completed task
208
+ # ============================================================================
209
+ # The task format is:
210
+ # ### T-XXX: Task Title
211
+ # **Satisfies ACs**: AC-US1-01, AC-US1-02
212
+ # **Status**: [x] completed
213
+
214
+ # Read tasks.md to find completed tasks and their ACs
215
+ if [[ ! -f "$FILE_PATH" ]]; then
216
+ echo "[$(date)] ⚠️ tasks.md not found: $FILE_PATH" >> "$DEBUG_LOG" 2>/dev/null || true
217
+ exit 0
218
+ fi
219
+
220
+ # CROSS-PLATFORM: Convert CRLF to LF for Windows compatibility
221
+ # Create temp file with normalized line endings
222
+ TASKS_TEMP=$(mktemp)
223
+ tr -d '\r' < "$FILE_PATH" > "$TASKS_TEMP" 2>/dev/null || cat "$FILE_PATH" > "$TASKS_TEMP"
224
+
225
+ # Find all completed tasks and their AC tags
226
+ COMPLETED_ACS=()
227
+ CURRENT_TASK=""
228
+ CURRENT_ACS=""
229
+
230
+ while IFS= read -r line; do
231
+ # Detect task header
232
+ if [[ "$line" =~ ^###[[:space:]]+(T-[0-9]+): ]]; then
233
+ CURRENT_TASK="${BASH_REMATCH[1]}"
234
+ CURRENT_ACS=""
235
+ fi
236
+
237
+ # Detect AC tags (handle optional whitespace variations)
238
+ if [[ "$line" =~ ^\*\*Satisfies[[:space:]]*ACs\*\*:[[:space:]]*(.*) ]]; then
239
+ CURRENT_ACS="${BASH_REMATCH[1]}"
240
+ fi
241
+
242
+ # Detect completion status
243
+ if [[ "$line" =~ ^\*\*Status\*\*:[[:space:]]*\[x\] ]]; then
244
+ if [[ -n "$CURRENT_ACS" ]]; then
245
+ # Split ACs by comma and add to array
246
+ IFS=',' read -ra AC_ARRAY <<< "$CURRENT_ACS"
247
+ for ac in "${AC_ARRAY[@]}"; do
248
+ ac=$(echo "$ac" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') # Trim whitespace
249
+ # Also remove any trailing \r (Windows)
250
+ ac="${ac%$'\r'}"
251
+ if [[ -n "$ac" ]]; then
252
+ COMPLETED_ACS+=("$ac")
253
+ fi
254
+ done
255
+ fi
256
+ fi
257
+ done < "$TASKS_TEMP"
258
+
259
+ # Cleanup temp file
260
+ rm -f "$TASKS_TEMP" 2>/dev/null || true
261
+
262
+ echo "[$(date)] 📊 Completed ACs: ${COMPLETED_ACS[*]}" >> "$DEBUG_LOG" 2>/dev/null || true
263
+
264
+ # ============================================================================
265
+ # STEP 2: Mark ACs as complete in spec.md
266
+ # ============================================================================
267
+ # AC format in spec.md:
268
+ # - [ ] **AC-US1-01**: Description
269
+ # Should become:
270
+ # - [x] **AC-US1-01**: Description
271
+
272
+ if [[ ! -f "$SPEC_FILE" ]]; then
273
+ echo "[$(date)] ⚠️ spec.md not found: $SPEC_FILE" >> "$DEBUG_LOG" 2>/dev/null || true
274
+ exit 0
275
+ fi
276
+
277
+ AC_UPDATED=0
278
+ for ac in "${COMPLETED_ACS[@]}"; do
279
+ # Check if this AC exists and is not already marked complete
280
+ # CROSS-PLATFORM: Support both - and * bullet formats, use # delimiter (AC names may contain /)
281
+ if grep -qE "^[-*] \[ \] \*\*$ac\*\*" "$SPEC_FILE" 2>/dev/null; then
282
+ # Update AC to complete (macOS sed -i '' vs Linux sed -i)
283
+ # Use # as delimiter since AC names like "AC-US1/01" would break /
284
+ sed -i '' "s#^[-*] \[ \] \*\*$ac\*\*#- [x] **$ac**#" "$SPEC_FILE" 2>/dev/null || \
285
+ sed -i "s#^[-*] \[ \] \*\*$ac\*\*#- [x] **$ac**#" "$SPEC_FILE" 2>/dev/null
286
+ echo "[$(date)] ✅ Marked AC complete: $ac" >> "$DEBUG_LOG" 2>/dev/null || true
287
+ ((AC_UPDATED++))
288
+ else
289
+ echo "[$(date)] ⏭️ AC already complete or not found: $ac" >> "$DEBUG_LOG" 2>/dev/null || true
290
+ fi
291
+ done
292
+
293
+ if [[ $AC_UPDATED -gt 0 ]]; then
294
+ echo "[$(date)] 📝 Updated $AC_UPDATED ACs in spec.md" >> "$DEBUG_LOG" 2>/dev/null || true
295
+ fi
296
+
297
+ # ============================================================================
298
+ # STEP 3: Check if ALL tasks are complete → auto-transition to ready_for_review
299
+ # ============================================================================
300
+
301
+ TOTAL_TASKS=$(grep -c '^\*\*Status\*\*:' "$FILE_PATH" 2>/dev/null || echo 0)
302
+ COMPLETED_TASKS=$(grep -c '^\*\*Status\*\*:[[:space:]]*\[x\]' "$FILE_PATH" 2>/dev/null || echo 0)
303
+
304
+ echo "[$(date)] 📊 Task progress: $COMPLETED_TASKS / $TOTAL_TASKS" >> "$DEBUG_LOG" 2>/dev/null || true
305
+
306
+ if [[ "$TOTAL_TASKS" -gt 0 ]] && [[ "$COMPLETED_TASKS" -eq "$TOTAL_TASKS" ]]; then
307
+ echo "[$(date)] 🎉 ALL TASKS COMPLETE! Checking for auto-transition..." >> "$DEBUG_LOG" 2>/dev/null || true
308
+
309
+ # Check current status (requires jq for JSON manipulation)
310
+ if ! command -v jq >/dev/null 2>&1; then
311
+ echo "[$(date)] ⚠️ jq not installed - status auto-transition skipped" >> "$DEBUG_LOG" 2>/dev/null || true
312
+ echo ""
313
+ echo "⚠️ WARNING: jq not installed. Status auto-transition to ready_for_review skipped."
314
+ echo " Install jq: brew install jq (macOS) | apt install jq (Linux) | choco install jq (Windows)"
315
+ echo ""
316
+ exit 0
317
+ fi
318
+
319
+ if [[ -f "$METADATA_FILE" ]]; then
320
+ CURRENT_STATUS=$(jq -r '.status // "active"' "$METADATA_FILE" 2>/dev/null)
321
+
322
+ if [[ "$CURRENT_STATUS" == "active" ]] || [[ "$CURRENT_STATUS" == "in-progress" ]]; then
323
+ # Auto-transition to ready_for_review (NEVER directly to completed!)
324
+ echo "[$(date)] 🔄 Auto-transitioning status: $CURRENT_STATUS → ready_for_review" >> "$DEBUG_LOG" 2>/dev/null || true
325
+
326
+ # Update metadata.json
327
+ TMP_FILE=$(mktemp)
328
+ jq '.status = "ready_for_review" | .updated = (now | strftime("%Y-%m-%dT%H:%M:%S.000Z"))' "$METADATA_FILE" > "$TMP_FILE" 2>/dev/null
329
+ if [[ -s "$TMP_FILE" ]]; then
330
+ mv "$TMP_FILE" "$METADATA_FILE"
331
+ echo "[$(date)] ✅ Status updated to ready_for_review" >> "$DEBUG_LOG" 2>/dev/null || true
332
+
333
+ # Output message to Claude
334
+ echo ""
335
+ echo "════════════════════════════════════════════════════════════════════"
336
+ echo " 🎉 ALL TASKS COMPLETED! Status → ready_for_review"
337
+ echo "════════════════════════════════════════════════════════════════════"
338
+ echo ""
339
+ echo " Tasks: $COMPLETED_TASKS/$TOTAL_TASKS (100%)"
340
+ echo " ACs synced: $AC_UPDATED"
341
+ echo ""
342
+ echo " Next step: Run /sw:done to close the increment"
343
+ echo " (PM validation will verify all ACs are complete)"
344
+ echo ""
345
+ echo "════════════════════════════════════════════════════════════════════"
346
+ else
347
+ rm -f "$TMP_FILE"
348
+ echo "[$(date)] ⚠️ Failed to update metadata.json" >> "$DEBUG_LOG" 2>/dev/null || true
349
+ fi
350
+ else
351
+ echo "[$(date)] ⏭️ Status is '$CURRENT_STATUS', not auto-transitioning" >> "$DEBUG_LOG" 2>/dev/null || true
352
+ fi
353
+ fi
354
+ fi
355
+
356
+ # Always exit 0 - never crash Claude Code
357
+ exit 0