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,513 +0,0 @@
1
- #!/usr/bin/env bash
2
-
3
- # Post-Increment-Completion Hook
4
- # Runs after an increment is marked as complete
5
- #
6
- # This hook closes GitHub issues automatically when increments complete
7
-
8
- set +e # EMERGENCY FIX: Prevents Claude Code crashes
9
-
10
- # EMERGENCY KILL SWITCH
11
- if [[ "${SPECWEAVE_DISABLE_HOOKS:-0}" == "1" ]]; then
12
- exit 0
13
- fi
14
-
15
- HOOK_NAME="post-increment-completion"
16
- INCREMENT_ID="${1:-}"
17
-
18
- # Check if increment ID provided
19
- if [ -z "$INCREMENT_ID" ]; then
20
- echo "⚠️ $HOOK_NAME: No increment ID provided" >&2
21
- exit 0
22
- fi
23
-
24
- # Get project root (3 levels up from plugins/specweave/hooks/)
25
- PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../.." && pwd)"
26
- INCREMENT_DIR="$PROJECT_ROOT/.specweave/increments/$INCREMENT_ID"
27
-
28
- # ============================================================================
29
- # RECURSION PREVENTION (v0.26.1 - CRITICAL)
30
- # ============================================================================
31
- # PROBLEM: consolidated-sync.js does Edit/Write operations which trigger hooks.
32
- # If no guard exists, those hooks will run full sync → more Edit/Write → INFINITE LOOP.
33
- #
34
- # SOLUTION: Create recursion guard file BEFORE calling any sync scripts.
35
- # Other hooks check this file and exit early if it exists.
36
- #
37
- # See: ADR-0073 (Hook Recursion Prevention Strategy)
38
- # See: .specweave/increments/0051-*/reports/GITHUB-COMMENT-RECURSION-ROOT-CAUSE-2025-11-24.md
39
-
40
- RECURSION_GUARD_FILE="$PROJECT_ROOT/.specweave/state/.hook-recursion-guard"
41
-
42
- if [[ -f "$RECURSION_GUARD_FILE" ]]; then
43
- # Silent exit - we're already inside a hook chain
44
- exit 0
45
- fi
46
-
47
- # Create guard file (atomic operation)
48
- mkdir -p "$PROJECT_ROOT/.specweave/state" 2>/dev/null || true
49
- touch "$RECURSION_GUARD_FILE"
50
-
51
- # Ensure guard file is ALWAYS removed when script exits (even on error)
52
- trap 'rm -f "$RECURSION_GUARD_FILE" 2>/dev/null || true' EXIT SIGINT SIGTERM
53
-
54
- # Check if increment exists
55
- if [ ! -d "$INCREMENT_DIR" ]; then
56
- echo "⚠️ $HOOK_NAME: Increment $INCREMENT_ID not found" >&2
57
- exit 0
58
- fi
59
-
60
- # Read metadata.json
61
- METADATA_FILE="$INCREMENT_DIR/metadata.json"
62
- if [ ! -f "$METADATA_FILE" ]; then
63
- echo "⚠️ $HOOK_NAME: No metadata.json found for $INCREMENT_ID" >&2
64
- exit 0
65
- fi
66
-
67
- # Extract GitHub issue number
68
- ISSUE_NUMBER=$(jq -r '.github.issue // empty' "$METADATA_FILE" 2>/dev/null)
69
-
70
- if [ -z "$ISSUE_NUMBER" ] || [ "$ISSUE_NUMBER" = "null" ]; then
71
- # No GitHub issue linked - skip GitHub closure but continue with sync
72
- echo "ℹ️ No GitHub issue linked to increment $INCREMENT_ID"
73
- SKIP_GITHUB_CLOSURE=true
74
- else
75
- SKIP_GITHUB_CLOSURE=false
76
- fi
77
-
78
- # ============================================================================
79
- # GITHUB ISSUE CLOSURE (if linked)
80
- # ============================================================================
81
-
82
- if [ "$SKIP_GITHUB_CLOSURE" = "false" ]; then
83
- # Check if gh CLI is available
84
- if ! command -v gh &> /dev/null; then
85
- echo "⚠️ $HOOK_NAME: GitHub CLI (gh) not found - skipping issue closure" >&2
86
- else
87
- # Check if issue is already closed
88
- ISSUE_STATE=$(gh issue view "$ISSUE_NUMBER" --json state --jq '.state' 2>/dev/null || echo "")
89
-
90
- if [ "$ISSUE_STATE" = "CLOSED" ]; then
91
- echo "✓ GitHub issue #$ISSUE_NUMBER already closed"
92
- else
93
- # Close the GitHub issue with completion message
94
- echo "🔗 Closing GitHub issue #$ISSUE_NUMBER for increment $INCREMENT_ID..."
95
-
96
- # Create completion comment
97
- COMPLETION_COMMENT="## ✅ Increment Complete
98
-
99
- Increment \`$INCREMENT_ID\` has been marked as complete.
100
-
101
- **Completion Details:**
102
- - Completed: $(date -u +"%Y-%m-%dT%H:%M:%SZ")
103
- - All tasks completed
104
- - Tests passed
105
- - Documentation updated
106
-
107
- ---
108
- 🤖 Auto-closed by SpecWeave post-increment-completion hook"
109
-
110
- # Close issue with comment
111
- gh issue close "$ISSUE_NUMBER" --comment "$COMPLETION_COMMENT" 2>/dev/null || {
112
- echo "⚠️ Failed to close issue #$ISSUE_NUMBER" >&2
113
- }
114
-
115
- echo "✅ GitHub issue #$ISSUE_NUMBER closed successfully"
116
- fi
117
- fi
118
- fi
119
-
120
- # ============================================================================
121
- # SYNC SPEC.MD STATUS (CRITICAL - v0.28.8)
122
- # ============================================================================
123
- # PROBLEM: metadata.json is updated to "completed" but spec.md frontmatter
124
- # may still say "active". This causes desyncs that break status line.
125
- #
126
- # SOLUTION: Explicitly update spec.md frontmatter to match metadata.json.
127
- # This ensures source-of-truth discipline is maintained.
128
- #
129
- # See: Incident 2025-11-20 - metadata.json="completed" but spec.md="active"
130
- # See: /sw:sync-status command for manual recovery
131
-
132
- SPEC_FILE="$INCREMENT_DIR/spec.md"
133
-
134
- if [ -f "$SPEC_FILE" ]; then
135
- echo "🔄 Syncing spec.md status to 'completed'..."
136
-
137
- # Read current status from spec.md frontmatter
138
- # Use heredoc to avoid quote escaping issues in awk
139
- SPEC_STATUS=$(awk '
140
- BEGIN { in_frontmatter=0 }
141
- /^---$/ {
142
- if (in_frontmatter == 0) {
143
- in_frontmatter=1; next
144
- } else {
145
- exit
146
- }
147
- }
148
- in_frontmatter == 1 && /^status:/ {
149
- gsub(/^status:[ \t]*/, "");
150
- gsub(/["'"'"']/, "");
151
- print;
152
- exit
153
- }
154
- ' "$SPEC_FILE" | tr -d '\r\n')
155
-
156
- if [ "$SPEC_STATUS" != "completed" ]; then
157
- # Update spec.md frontmatter to "completed"
158
- # Use sed for atomic in-place update
159
- if [[ "$(uname)" == "Darwin" ]]; then
160
- # macOS sed requires different syntax
161
- sed -i '' 's/^status:.*$/status: completed/' "$SPEC_FILE" 2>/dev/null || {
162
- echo "⚠️ Failed to update spec.md status (non-blocking)" >&2
163
- }
164
- else
165
- # GNU sed
166
- sed -i 's/^status:.*$/status: completed/' "$SPEC_FILE" 2>/dev/null || {
167
- echo "⚠️ Failed to update spec.md status (non-blocking)" >&2
168
- }
169
- fi
170
- echo "✅ spec.md status updated: $SPEC_STATUS → completed"
171
- else
172
- echo "✅ spec.md status already 'completed'"
173
- fi
174
- else
175
- echo "⚠️ spec.md not found at $SPEC_FILE" >&2
176
- fi
177
-
178
- # Update status line cache (increment no longer open)
179
- HOOK_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
180
- bash "$HOOK_DIR/lib/update-status-line.sh" 2>/dev/null || true
181
-
182
- echo "✅ Status line cache updated"
183
-
184
- # ============================================================================
185
- # SYNC LIVING DOCS (NEW in v0.24.0 - Critical Missing Feature)
186
- # ============================================================================
187
- # After increment completes, perform FULL living docs sync to ensure:
188
- # - Feature specs finalized with all user stories marked complete
189
- # - ADRs created/updated with final architecture decisions
190
- # - Architecture docs updated with implementation details
191
- # - Delivery docs updated with what was shipped
192
- # - Internal/public docs reflect completed work
193
- #
194
- # This is the FINAL, COMPREHENSIVE sync that happens once per increment.
195
- # (Task-level sync in post-task-completion.sh handles incremental updates)
196
- #
197
- # Architecture Decision: Non-blocking execution
198
- # - If sync fails, log error but don't crash hook (GitHub issue already closed)
199
- # - Living docs can be manually synced later with /sw:sync-docs
200
- # - Failure mode: Graceful degradation (increment still completes)
201
-
202
- if command -v node &> /dev/null; then
203
- echo ""
204
- echo "📚 Performing final living docs sync for increment $INCREMENT_ID..."
205
-
206
- # ========================================================================
207
- # EXTRACT FEATURE ID (v0.23.0+)
208
- # ========================================================================
209
- # Extract epic field from spec.md frontmatter (e.g., epic: FS-047)
210
- # This ensures sync uses the explicitly defined feature ID rather than
211
- # auto-generating one, maintaining traceability with living docs structure.
212
-
213
- FEATURE_ID=""
214
- SPEC_MD_PATH="$INCREMENT_DIR/spec.md"
215
-
216
- if [ -f "$SPEC_MD_PATH" ]; then
217
- # Extract epic field from YAML frontmatter
218
- FEATURE_ID=$(awk '
219
- BEGIN { in_frontmatter=0 }
220
- /^---$/ {
221
- if (in_frontmatter == 0) {
222
- in_frontmatter=1; next
223
- } else {
224
- exit
225
- }
226
- }
227
- in_frontmatter == 1 && /^epic:/ {
228
- gsub(/^epic:[ \t]*/, "");
229
- gsub(/["'\'']/, "");
230
- print;
231
- exit
232
- }
233
- ' "$SPEC_MD_PATH" | tr -d '\r\n')
234
-
235
- if [ -n "$FEATURE_ID" ]; then
236
- echo " 📎 Using feature ID from spec.md: $FEATURE_ID"
237
- else
238
- echo " ℹ️ No epic field found in spec.md - will auto-generate feature ID"
239
- fi
240
- else
241
- echo " ⚠️ spec.md not found at $SPEC_MD_PATH" >&2
242
- fi
243
-
244
- # ========================================================================
245
- # EXTRACT PROJECT ID (v0.20.0+)
246
- # ========================================================================
247
- # Extract activeProject from config.json (defaults to "default")
248
- # Supports multi-project mode where specs are organized by project.
249
-
250
- PROJECT_ID="default"
251
- CONFIG_PATH="$PROJECT_ROOT/.specweave/config.json"
252
-
253
- if [ -f "$CONFIG_PATH" ]; then
254
- if command -v jq >/dev/null 2>&1; then
255
- ACTIVE_PROJECT=$(jq -r '.activeProject // "default"' "$CONFIG_PATH" 2>/dev/null || echo "default")
256
- if [ -n "$ACTIVE_PROJECT" ] && [ "$ACTIVE_PROJECT" != "null" ]; then
257
- PROJECT_ID="$ACTIVE_PROJECT"
258
- fi
259
- fi
260
- fi
261
- echo " 📁 Project ID: $PROJECT_ID"
262
-
263
- # ========================================================================
264
- # LOCATE SYNC SCRIPT
265
- # ========================================================================
266
- # Find sync-living-docs.js in order of preference:
267
- # 1. In-place compiled (development, esbuild output)
268
- # 2. Local dist (development, tsc output)
269
- # 3. node_modules (installed as dependency)
270
- # 4. Plugin marketplace (Claude Code global installation)
271
-
272
- SYNC_SCRIPT=""
273
- if [ -f "$PROJECT_ROOT/plugins/specweave/lib/hooks/sync-living-docs.js" ]; then
274
- # Development: Use in-place compiled hooks (esbuild, not tsc)
275
- SYNC_SCRIPT="$PROJECT_ROOT/plugins/specweave/lib/hooks/sync-living-docs.js"
276
- echo " 🔧 Using in-place compiled hook (development mode)"
277
- elif [ -f "$PROJECT_ROOT/dist/plugins/specweave/lib/hooks/sync-living-docs.js" ]; then
278
- # Development: Use project's compiled files (has node_modules)
279
- SYNC_SCRIPT="$PROJECT_ROOT/dist/plugins/specweave/lib/hooks/sync-living-docs.js"
280
- echo " 🔧 Using local dist (development mode)"
281
- elif [ -f "$PROJECT_ROOT/node_modules/specweave/dist/plugins/specweave/lib/hooks/sync-living-docs.js" ]; then
282
- # Installed as dependency: Use node_modules version
283
- SYNC_SCRIPT="$PROJECT_ROOT/node_modules/specweave/dist/plugins/specweave/lib/hooks/sync-living-docs.js"
284
- echo " 📦 Using node_modules version"
285
- elif [ -n "${CLAUDE_PLUGIN_ROOT}" ] && [ -f "${CLAUDE_PLUGIN_ROOT}/lib/hooks/sync-living-docs.js" ]; then
286
- # Fallback: Plugin marketplace (may fail if deps missing)
287
- SYNC_SCRIPT="${CLAUDE_PLUGIN_ROOT}/lib/hooks/sync-living-docs.js"
288
- echo " 🌐 Using plugin marketplace version"
289
- fi
290
-
291
- # ========================================================================
292
- # EXECUTE SYNC
293
- # ========================================================================
294
- # Run living docs sync with feature ID and project ID
295
- # Non-blocking: Errors logged but don't crash hook
296
-
297
- if [ -n "$SYNC_SCRIPT" ]; then
298
- # Pass FEATURE_ID and PROJECT_ID as environment variables if available
299
- if [ -n "$FEATURE_ID" ]; then
300
- (cd "$PROJECT_ROOT" && FEATURE_ID="$FEATURE_ID" PROJECT_ID="$PROJECT_ID" node "$SYNC_SCRIPT" "$INCREMENT_ID") 2>&1 || {
301
- echo " ⚠️ Failed to sync living docs (non-blocking - you can run /sw:sync-docs manually)" >&2
302
- }
303
- else
304
- # No explicit feature ID - sync will auto-generate
305
- (cd "$PROJECT_ROOT" && PROJECT_ID="$PROJECT_ID" node "$SYNC_SCRIPT" "$INCREMENT_ID") 2>&1 || {
306
- echo " ⚠️ Failed to sync living docs (non-blocking - you can run /sw:sync-docs manually)" >&2
307
- }
308
- fi
309
- echo " ✅ Living docs sync complete"
310
- echo ""
311
- else
312
- echo " ⚠️ sync-living-docs.js not found in any location - skipping living docs sync" >&2
313
- echo " 💡 To manually sync: /sw:sync-docs update" >&2
314
- echo ""
315
- fi
316
- else
317
- echo " ⚠️ Node.js not found - skipping living docs sync" >&2
318
- echo " 💡 Install Node.js to enable automatic living docs sync" >&2
319
- echo ""
320
- fi
321
-
322
- # ============================================================================
323
- # GITHUB SYNC (v0.26.1 - CRITICAL FIX)
324
- # ============================================================================
325
- # After living docs sync, create GitHub issues for user stories.
326
- # This is the AUTOMATIC GitHub sync that runs once per increment completion.
327
- #
328
- # CRITICAL: This was MISSING in v0.26.0, causing GitHub issues to NEVER be
329
- # created automatically. The consolidated-sync.js has the full logic for:
330
- # - Creating GitHub issues for user stories (with 3-layer idempotency)
331
- # - Syncing task completion comments to existing issues
332
- # - Format preservation sync for external tools
333
- #
334
- # GATE SYSTEM (4 gates - all checked inside consolidated-sync.js):
335
- # - GATE 1: canUpsertInternalItems (living docs sync enabled)
336
- # - GATE 2: canUpdateExternalItems (external tool sync enabled)
337
- # - GATE 3: autoSyncOnCompletion (automatic sync enabled)
338
- # - GATE 4: sync.github.enabled (GitHub-specific sync enabled)
339
- #
340
- # RECURSION SAFETY:
341
- # - Recursion guard created at script start (line 49)
342
- # - consolidated-sync.js does Edit/Write operations
343
- # - Other hooks see the guard and exit early
344
- # - Guard removed via trap on script exit
345
- #
346
- # USER PROJECT COMPATIBILITY:
347
- # - Script detection works for: development, dist/, node_modules/, marketplace
348
- # - Works in both SpecWeave framework repo AND user projects using SpecWeave
349
- # - GITHUB_TOKEN loaded from project's .env file
350
- #
351
- # See: Root cause analysis in initial implementation planning
352
- # See: ADR-0073 (Hook Recursion Prevention Strategy)
353
-
354
- if command -v node &> /dev/null; then
355
- echo ""
356
- echo "🔗 Creating GitHub issues for user stories..."
357
-
358
- # ========================================================================
359
- # LOCATE CONSOLIDATED SYNC SCRIPT
360
- # ========================================================================
361
- # Find consolidated-sync.js in order of preference:
362
- # 1. In-place compiled (development, esbuild output)
363
- # 2. Local dist (development, tsc output)
364
- # 3. node_modules (installed as dependency) ← USER PROJECTS
365
- # 4. Plugin marketplace (Claude Code global installation)
366
-
367
- CONSOLIDATED_SCRIPT=""
368
- if [ -f "$PROJECT_ROOT/plugins/specweave/lib/hooks/consolidated-sync.js" ]; then
369
- # Development: Use in-place compiled hooks (esbuild, not tsc)
370
- CONSOLIDATED_SCRIPT="$PROJECT_ROOT/plugins/specweave/lib/hooks/consolidated-sync.js"
371
- echo " 🔧 Using in-place compiled hook (development mode)"
372
- elif [ -f "$PROJECT_ROOT/dist/plugins/specweave/lib/hooks/consolidated-sync.js" ]; then
373
- # Development: Use project's compiled files (has node_modules)
374
- CONSOLIDATED_SCRIPT="$PROJECT_ROOT/dist/plugins/specweave/lib/hooks/consolidated-sync.js"
375
- echo " 🔧 Using local dist (development mode)"
376
- elif [ -f "$PROJECT_ROOT/node_modules/specweave/dist/plugins/specweave/lib/hooks/consolidated-sync.js" ]; then
377
- # Installed as dependency: Use node_modules version (MOST USER PROJECTS)
378
- CONSOLIDATED_SCRIPT="$PROJECT_ROOT/node_modules/specweave/dist/plugins/specweave/lib/hooks/consolidated-sync.js"
379
- echo " 📦 Using node_modules version"
380
- elif [ -n "${CLAUDE_PLUGIN_ROOT}" ] && [ -f "${CLAUDE_PLUGIN_ROOT}/lib/hooks/consolidated-sync.js" ]; then
381
- # Fallback: Plugin marketplace (may fail if deps missing)
382
- CONSOLIDATED_SCRIPT="${CLAUDE_PLUGIN_ROOT}/lib/hooks/consolidated-sync.js"
383
- echo " 🌐 Using plugin marketplace version"
384
- fi
385
-
386
- # ========================================================================
387
- # EXECUTE GITHUB SYNC
388
- # ========================================================================
389
- # Run consolidated sync to create GitHub issues and sync task completion.
390
- # Non-blocking: Errors logged but don't crash hook (increment already closed)
391
- #
392
- # CRITICAL: Do NOT set SKIP_GITHUB_SYNC=true here!
393
- # That flag is ONLY for post-task-completion hook to prevent duplicate comments.
394
- # On increment completion, we WANT GitHub sync to run.
395
-
396
- if [ -n "$CONSOLIDATED_SCRIPT" ]; then
397
- # Load GITHUB_TOKEN from .env for gh CLI authentication
398
- if [ -f "$PROJECT_ROOT/.env" ]; then
399
- # Extract GITHUB_TOKEN from .env (handles various formats)
400
- GITHUB_TOKEN_FROM_ENV=$(grep -E '^GITHUB_TOKEN=' "$PROJECT_ROOT/.env" 2>/dev/null | head -1 | cut -d'=' -f2- | sed 's/^["'\'']//' | sed 's/["'\'']$//')
401
- if [ -n "$GITHUB_TOKEN_FROM_ENV" ]; then
402
- export GITHUB_TOKEN="$GITHUB_TOKEN_FROM_ENV"
403
- echo " 🔑 GitHub token loaded from .env"
404
- fi
405
- fi
406
-
407
- # Run consolidated sync (synchronous - user sees immediate feedback)
408
- # This creates GitHub issues, syncs comments, and performs format preservation
409
- if (cd "$PROJECT_ROOT" && node "$CONSOLIDATED_SCRIPT" "$INCREMENT_ID") 2>&1; then
410
- echo " ✅ GitHub sync complete"
411
- echo ""
412
- else
413
- echo " ⚠️ Failed to sync GitHub issues (non-blocking - you can run /sw-github:sync manually)" >&2
414
- echo " 💡 Check that sync.github.enabled=true in .specweave/config.json" >&2
415
- echo ""
416
- fi
417
- else
418
- echo " ⚠️ consolidated-sync.js not found in any location - skipping GitHub sync" >&2
419
- echo " 💡 To manually sync: /sw-github:sync" >&2
420
- echo ""
421
- fi
422
- else
423
- echo ""
424
- echo " ⚠️ Node.js not found - skipping GitHub sync" >&2
425
- echo " 💡 Install Node.js to enable automatic GitHub sync" >&2
426
- echo ""
427
- fi
428
-
429
- # ============================================================================
430
- # GITHUB ISSUE CLOSURE (v0.28.1 - CRITICAL FIX)
431
- # ============================================================================
432
- # After creating/syncing GitHub issues, close User Story issues for this increment.
433
- # This was the MISSING feature causing issues to stay open indefinitely.
434
- #
435
- # WHY THIS IS SEPARATE FROM consolidated-sync.js:
436
- # - consolidated-sync.js handles task-level sync (called by post-task-completion too)
437
- # - sync-increment-closure.js ONLY runs on increment completion
438
- # - Closing issues is a DESTRUCTIVE operation that should only happen once
439
- #
440
- # GATE CHECK: All gates are checked inside sync-increment-closure.js
441
- # - canUpdateExternalItems must be true
442
- # - autoSyncOnCompletion must be true
443
- # - sync.github.enabled must be true
444
- #
445
- # See: Root cause analysis - User Story issues created but never closed
446
-
447
- if command -v node &> /dev/null; then
448
- echo ""
449
- echo "🔒 Closing GitHub issues for completed user stories..."
450
-
451
- # ========================================================================
452
- # LOCATE CLOSURE SYNC SCRIPT
453
- # ========================================================================
454
- # Find sync-increment-closure.js in order of preference:
455
- # 1. In-place compiled (development, esbuild output)
456
- # 2. Local dist (development, tsc output)
457
- # 3. node_modules (installed as dependency) ← USER PROJECTS
458
- # 4. Plugin marketplace (Claude Code global installation)
459
-
460
- CLOSURE_SCRIPT=""
461
- if [ -f "$PROJECT_ROOT/plugins/specweave/lib/hooks/sync-increment-closure.js" ]; then
462
- # Development: Use in-place compiled hooks (esbuild, not tsc)
463
- CLOSURE_SCRIPT="$PROJECT_ROOT/plugins/specweave/lib/hooks/sync-increment-closure.js"
464
- echo " 🔧 Using in-place compiled hook (development mode)"
465
- elif [ -f "$PROJECT_ROOT/dist/plugins/specweave/lib/hooks/sync-increment-closure.js" ]; then
466
- # Development: Use project's compiled files (has node_modules)
467
- CLOSURE_SCRIPT="$PROJECT_ROOT/dist/plugins/specweave/lib/hooks/sync-increment-closure.js"
468
- echo " 🔧 Using local dist (development mode)"
469
- elif [ -f "$PROJECT_ROOT/node_modules/specweave/dist/plugins/specweave/lib/hooks/sync-increment-closure.js" ]; then
470
- # Installed as dependency: Use node_modules version (MOST USER PROJECTS)
471
- CLOSURE_SCRIPT="$PROJECT_ROOT/node_modules/specweave/dist/plugins/specweave/lib/hooks/sync-increment-closure.js"
472
- echo " 📦 Using node_modules version"
473
- elif [ -n "${CLAUDE_PLUGIN_ROOT}" ] && [ -f "${CLAUDE_PLUGIN_ROOT}/lib/hooks/sync-increment-closure.js" ]; then
474
- # Fallback: Plugin marketplace (may fail if deps missing)
475
- CLOSURE_SCRIPT="${CLAUDE_PLUGIN_ROOT}/lib/hooks/sync-increment-closure.js"
476
- echo " 🌐 Using plugin marketplace version"
477
- fi
478
-
479
- # ========================================================================
480
- # EXECUTE CLOSURE SYNC
481
- # ========================================================================
482
- # Run closure sync to close all User Story GitHub issues.
483
- # Non-blocking: Errors logged but don't crash hook (increment already closed)
484
-
485
- if [ -n "$CLOSURE_SCRIPT" ]; then
486
- # Ensure GITHUB_TOKEN is available (may have been set earlier)
487
- if [ -z "$GITHUB_TOKEN" ] && [ -f "$PROJECT_ROOT/.env" ]; then
488
- GITHUB_TOKEN_FROM_ENV=$(grep -E '^GITHUB_TOKEN=' "$PROJECT_ROOT/.env" 2>/dev/null | head -1 | cut -d'=' -f2- | sed 's/^["'\'']//' | sed 's/["'\'']$//')
489
- if [ -n "$GITHUB_TOKEN_FROM_ENV" ]; then
490
- export GITHUB_TOKEN="$GITHUB_TOKEN_FROM_ENV"
491
- fi
492
- fi
493
-
494
- # Run closure sync (synchronous - user sees immediate feedback)
495
- if (cd "$PROJECT_ROOT" && node "$CLOSURE_SCRIPT" "$INCREMENT_ID") 2>&1; then
496
- echo " ✅ GitHub issue closure complete"
497
- echo ""
498
- else
499
- echo " ⚠️ Failed to close GitHub issues (non-blocking - you can close manually)" >&2
500
- echo ""
501
- fi
502
- else
503
- echo " ⚠️ sync-increment-closure.js not found in any location - skipping issue closure" >&2
504
- echo " 💡 User Story GitHub issues may remain open until manually closed" >&2
505
- echo ""
506
- fi
507
- else
508
- echo ""
509
- echo " ⚠️ Node.js not found - skipping GitHub issue closure" >&2
510
- echo ""
511
- fi
512
-
513
- exit 0