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.
- package/CLAUDE.md +140 -1235
- package/bin/specweave.js +23 -0
- package/dist/plugins/specweave-github/lib/github-client-v2.d.ts +3 -0
- package/dist/plugins/specweave-github/lib/github-client-v2.d.ts.map +1 -1
- package/dist/plugins/specweave-github/lib/github-client-v2.js +39 -0
- package/dist/plugins/specweave-github/lib/github-client-v2.js.map +1 -1
- package/dist/src/cli/commands/set-sync-target.d.ts +41 -0
- package/dist/src/cli/commands/set-sync-target.d.ts.map +1 -0
- package/dist/src/cli/commands/set-sync-target.js +126 -0
- package/dist/src/cli/commands/set-sync-target.js.map +1 -0
- package/dist/src/cli/helpers/issue-tracker/github-multi-repo.d.ts.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/github-multi-repo.js +5 -8
- package/dist/src/cli/helpers/issue-tracker/github-multi-repo.js.map +1 -1
- package/dist/src/core/hooks/HookScanner.d.ts +32 -0
- package/dist/src/core/hooks/HookScanner.d.ts.map +1 -1
- package/dist/src/core/hooks/HookScanner.js +125 -1
- package/dist/src/core/hooks/HookScanner.js.map +1 -1
- package/dist/src/core/hooks/types.d.ts +10 -1
- package/dist/src/core/hooks/types.d.ts.map +1 -1
- package/dist/src/core/increment/metadata-manager.d.ts +67 -1
- package/dist/src/core/increment/metadata-manager.d.ts.map +1 -1
- package/dist/src/core/increment/metadata-manager.js +93 -0
- package/dist/src/core/increment/metadata-manager.js.map +1 -1
- package/dist/src/core/project/index.d.ts +21 -0
- package/dist/src/core/project/index.d.ts.map +1 -0
- package/dist/src/core/project/index.js +22 -0
- package/dist/src/core/project/index.js.map +1 -0
- package/dist/src/core/project/project-service.d.ts +122 -0
- package/dist/src/core/project/project-service.d.ts.map +1 -0
- package/dist/src/core/project/project-service.js +334 -0
- package/dist/src/core/project/project-service.js.map +1 -0
- package/dist/src/core/sync/external-tool-resolver.d.ts +171 -0
- package/dist/src/core/sync/external-tool-resolver.d.ts.map +1 -0
- package/dist/src/core/sync/external-tool-resolver.js +569 -0
- package/dist/src/core/sync/external-tool-resolver.js.map +1 -0
- package/dist/src/core/types/increment-metadata.d.ts +92 -0
- package/dist/src/core/types/increment-metadata.d.ts.map +1 -1
- package/dist/src/hooks/processor.d.ts +7 -3
- package/dist/src/hooks/processor.d.ts.map +1 -1
- package/dist/src/hooks/processor.js +11 -5
- package/dist/src/hooks/processor.js.map +1 -1
- package/package.json +1 -1
- package/plugins/specweave/hooks/hooks.json +0 -69
- package/plugins/specweave/hooks/v2/handlers/project-bridge-handler.sh +96 -0
- package/plugins/specweave/hooks/v2/queue/processor.sh +13 -5
- package/plugins/specweave/lib/hooks/project-bridge.js +76 -0
- package/plugins/specweave/lib/hooks/update-tasks-md.js +0 -0
- package/plugins/specweave/lib/hooks/us-completion-orchestrator.js +0 -0
- package/plugins/specweave/lib/vendor/core/increment/metadata-manager.d.ts +67 -1
- package/plugins/specweave/lib/vendor/core/increment/metadata-manager.js +93 -0
- package/plugins/specweave/lib/vendor/core/increment/metadata-manager.js.map +1 -1
- package/plugins/specweave/lib/vendor/core/types/increment-metadata.d.ts +92 -0
- package/plugins/specweave-github/lib/github-client-v2.js +39 -0
- package/plugins/specweave-github/lib/github-client-v2.ts +44 -0
- package/plugins/specweave/hooks/docs-changed.sh +0 -87
- package/plugins/specweave/hooks/human-input-required.sh +0 -83
- package/plugins/specweave/hooks/post-edit-write-consolidated.sh +0 -428
- package/plugins/specweave/hooks/post-first-increment.sh +0 -61
- package/plugins/specweave/hooks/post-increment-change.sh +0 -103
- package/plugins/specweave/hooks/post-increment-completion.sh +0 -513
- package/plugins/specweave/hooks/post-increment-planning.sh +0 -1204
- package/plugins/specweave/hooks/post-increment-status-change.sh +0 -243
- package/plugins/specweave/hooks/post-metadata-change.sh +0 -246
- package/plugins/specweave/hooks/post-spec-update.sh +0 -158
- package/plugins/specweave/hooks/post-task-completion.sh +0 -557
- package/plugins/specweave/hooks/post-task-edit.sh +0 -47
- package/plugins/specweave/hooks/post-user-story-complete.sh +0 -230
- package/plugins/specweave/hooks/pre-command-deduplication.sh +0 -68
- package/plugins/specweave/hooks/pre-edit-write-consolidated.sh +0 -225
- package/plugins/specweave/hooks/pre-implementation.sh +0 -75
- package/plugins/specweave/hooks/pre-increment-start.sh +0 -173
- package/plugins/specweave/hooks/pre-task-completion-edit.sh +0 -355
- package/plugins/specweave/hooks/pre-task-completion.sh +0 -269
- package/plugins/specweave/hooks/pre-tool-use.sh +0 -137
- package/plugins/specweave/hooks/session-start-reconcile.sh +0 -139
- package/plugins/specweave/hooks/shared/bulk-operation-detector.sh +0 -167
- package/plugins/specweave/hooks/test-pretooluse-env.sh +0 -72
- package/plugins/specweave/hooks/validate-increment-completion.sh +0 -113
- 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
|