specweave 1.0.551 → 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 (132) hide show
  1. package/bin/specweave.js +23 -1
  2. package/dist/src/cli/commands/hook.d.ts +15 -0
  3. package/dist/src/cli/commands/hook.d.ts.map +1 -0
  4. package/dist/src/cli/commands/hook.js +61 -0
  5. package/dist/src/cli/commands/hook.js.map +1 -0
  6. package/dist/src/config/types.d.ts +2 -2
  7. package/dist/src/core/hooks/handlers/hook-router.d.ts +19 -0
  8. package/dist/src/core/hooks/handlers/hook-router.d.ts.map +1 -0
  9. package/dist/src/core/hooks/handlers/hook-router.js +75 -0
  10. package/dist/src/core/hooks/handlers/hook-router.js.map +1 -0
  11. package/dist/src/core/hooks/handlers/index.d.ts +10 -0
  12. package/dist/src/core/hooks/handlers/index.d.ts.map +1 -0
  13. package/dist/src/core/hooks/handlers/index.js +9 -0
  14. package/dist/src/core/hooks/handlers/index.js.map +1 -0
  15. package/dist/src/core/hooks/handlers/post-tool-use-analytics.d.ts +11 -0
  16. package/dist/src/core/hooks/handlers/post-tool-use-analytics.d.ts.map +1 -0
  17. package/dist/src/core/hooks/handlers/post-tool-use-analytics.js +73 -0
  18. package/dist/src/core/hooks/handlers/post-tool-use-analytics.js.map +1 -0
  19. package/dist/src/core/hooks/handlers/post-tool-use.d.ts +11 -0
  20. package/dist/src/core/hooks/handlers/post-tool-use.d.ts.map +1 -0
  21. package/dist/src/core/hooks/handlers/post-tool-use.js +76 -0
  22. package/dist/src/core/hooks/handlers/post-tool-use.js.map +1 -0
  23. package/dist/src/core/hooks/handlers/pre-compact.d.ts +11 -0
  24. package/dist/src/core/hooks/handlers/pre-compact.d.ts.map +1 -0
  25. package/dist/src/core/hooks/handlers/pre-compact.js +77 -0
  26. package/dist/src/core/hooks/handlers/pre-compact.js.map +1 -0
  27. package/dist/src/core/hooks/handlers/pre-tool-use.d.ts +11 -0
  28. package/dist/src/core/hooks/handlers/pre-tool-use.d.ts.map +1 -0
  29. package/dist/src/core/hooks/handlers/pre-tool-use.js +318 -0
  30. package/dist/src/core/hooks/handlers/pre-tool-use.js.map +1 -0
  31. package/dist/src/core/hooks/handlers/session-start.d.ts +9 -0
  32. package/dist/src/core/hooks/handlers/session-start.d.ts.map +1 -0
  33. package/dist/src/core/hooks/handlers/session-start.js +111 -0
  34. package/dist/src/core/hooks/handlers/session-start.js.map +1 -0
  35. package/dist/src/core/hooks/handlers/stop-auto.d.ts +16 -0
  36. package/dist/src/core/hooks/handlers/stop-auto.d.ts.map +1 -0
  37. package/dist/src/core/hooks/handlers/stop-auto.js +122 -0
  38. package/dist/src/core/hooks/handlers/stop-auto.js.map +1 -0
  39. package/dist/src/core/hooks/handlers/stop-reflect.d.ts +14 -0
  40. package/dist/src/core/hooks/handlers/stop-reflect.d.ts.map +1 -0
  41. package/dist/src/core/hooks/handlers/stop-reflect.js +43 -0
  42. package/dist/src/core/hooks/handlers/stop-reflect.js.map +1 -0
  43. package/dist/src/core/hooks/handlers/stop-sync.d.ts +15 -0
  44. package/dist/src/core/hooks/handlers/stop-sync.d.ts.map +1 -0
  45. package/dist/src/core/hooks/handlers/stop-sync.js +68 -0
  46. package/dist/src/core/hooks/handlers/stop-sync.js.map +1 -0
  47. package/dist/src/core/hooks/handlers/types.d.ts +63 -0
  48. package/dist/src/core/hooks/handlers/types.d.ts.map +1 -0
  49. package/dist/src/core/hooks/handlers/types.js +27 -0
  50. package/dist/src/core/hooks/handlers/types.js.map +1 -0
  51. package/dist/src/core/hooks/handlers/user-prompt-submit.d.ts +14 -0
  52. package/dist/src/core/hooks/handlers/user-prompt-submit.d.ts.map +1 -0
  53. package/dist/src/core/hooks/handlers/user-prompt-submit.js +173 -0
  54. package/dist/src/core/hooks/handlers/user-prompt-submit.js.map +1 -0
  55. package/dist/src/core/hooks/handlers/utils.d.ts +25 -0
  56. package/dist/src/core/hooks/handlers/utils.d.ts.map +1 -0
  57. package/dist/src/core/hooks/handlers/utils.js +64 -0
  58. package/dist/src/core/hooks/handlers/utils.js.map +1 -0
  59. package/dist/src/init/research/types.d.ts +1 -1
  60. package/dist/src/sync/sync-target-resolver.js.map +1 -1
  61. package/dist/src/utils/lock-manager.d.ts.map +1 -1
  62. package/dist/src/utils/lock-manager.js +5 -0
  63. package/dist/src/utils/lock-manager.js.map +1 -1
  64. package/dist/src/utils/plugin-copier.d.ts.map +1 -1
  65. package/dist/src/utils/plugin-copier.js +3 -30
  66. package/dist/src/utils/plugin-copier.js.map +1 -1
  67. package/package.json +1 -1
  68. package/plugins/specweave/hooks/hooks.json +10 -10
  69. package/plugins/specweave/hooks/README.md +0 -493
  70. package/plugins/specweave/hooks/_archive/stop-auto-v4-legacy.sh +0 -1319
  71. package/plugins/specweave/hooks/lib/common-setup.sh +0 -144
  72. package/plugins/specweave/hooks/lib/hook-errors.sh +0 -414
  73. package/plugins/specweave/hooks/lib/migrate-increment-work.sh +0 -245
  74. package/plugins/specweave/hooks/lib/resolve-package.sh +0 -146
  75. package/plugins/specweave/hooks/lib/scheduler-startup.sh +0 -135
  76. package/plugins/specweave/hooks/lib/score-increment.sh +0 -87
  77. package/plugins/specweave/hooks/lib/sync-spec-content.sh +0 -193
  78. package/plugins/specweave/hooks/lib/update-active-increment.sh +0 -95
  79. package/plugins/specweave/hooks/lib/update-status-line.sh +0 -233
  80. package/plugins/specweave/hooks/lib/validate-spec-status.sh +0 -171
  81. package/plugins/specweave/hooks/llm-judge-validator.sh +0 -219
  82. package/plugins/specweave/hooks/log-decision.sh +0 -168
  83. package/plugins/specweave/hooks/pre-compact.sh +0 -64
  84. package/plugins/specweave/hooks/startup-health-check.sh +0 -64
  85. package/plugins/specweave/hooks/stop-auto-v5.sh +0 -276
  86. package/plugins/specweave/hooks/stop-reflect.sh +0 -336
  87. package/plugins/specweave/hooks/stop-sync.sh +0 -283
  88. package/plugins/specweave/hooks/tests/test-auto-context-integration.sh +0 -126
  89. package/plugins/specweave/hooks/tests/test-stop-auto-enriched.sh +0 -128
  90. package/plugins/specweave/hooks/universal/dispatcher.mjs +0 -336
  91. package/plugins/specweave/hooks/universal/fail-fast-wrapper.sh +0 -325
  92. package/plugins/specweave/hooks/universal/hook-wrapper.cmd +0 -26
  93. package/plugins/specweave/hooks/universal/hook-wrapper.sh +0 -69
  94. package/plugins/specweave/hooks/universal/run-hook.sh +0 -20
  95. package/plugins/specweave/hooks/universal/session-start.cmd +0 -16
  96. package/plugins/specweave/hooks/universal/session-start.ps1 +0 -16
  97. package/plugins/specweave/hooks/user-prompt-submit.sh +0 -2550
  98. package/plugins/specweave/hooks/v2/detectors/lifecycle-detector.sh +0 -87
  99. package/plugins/specweave/hooks/v2/detectors/us-completion-detector.sh +0 -186
  100. package/plugins/specweave/hooks/v2/dispatchers/post-tool-use-analytics.sh +0 -83
  101. package/plugins/specweave/hooks/v2/dispatchers/post-tool-use.sh +0 -447
  102. package/plugins/specweave/hooks/v2/dispatchers/pre-tool-use.sh +0 -104
  103. package/plugins/specweave/hooks/v2/dispatchers/session-start.sh +0 -270
  104. package/plugins/specweave/hooks/v2/guards/completion-guard.sh +0 -14
  105. package/plugins/specweave/hooks/v2/guards/increment-duplicate-guard.sh +0 -14
  106. package/plugins/specweave/hooks/v2/guards/increment-existence-guard.sh +0 -240
  107. package/plugins/specweave/hooks/v2/guards/interview-enforcement-guard.sh +0 -171
  108. package/plugins/specweave/hooks/v2/guards/metadata-json-guard.sh +0 -14
  109. package/plugins/specweave/hooks/v2/guards/skill-chain-enforcement-guard.sh +0 -222
  110. package/plugins/specweave/hooks/v2/guards/spec-template-enforcement-guard.sh +0 -21
  111. package/plugins/specweave/hooks/v2/guards/spec-validation-guard.sh +0 -14
  112. package/plugins/specweave/hooks/v2/guards/status-completion-guard.sh +0 -84
  113. package/plugins/specweave/hooks/v2/guards/task-ac-sync-guard.sh +0 -475
  114. package/plugins/specweave/hooks/v2/guards/tdd-enforcement-guard.sh +0 -268
  115. package/plugins/specweave/hooks/v2/handlers/ac-sync-dispatcher.sh +0 -332
  116. package/plugins/specweave/hooks/v2/handlers/ac-validation-handler.sh +0 -50
  117. package/plugins/specweave/hooks/v2/handlers/github-sync-handler.sh +0 -347
  118. package/plugins/specweave/hooks/v2/handlers/living-docs-handler.sh +0 -83
  119. package/plugins/specweave/hooks/v2/handlers/living-specs-handler.sh +0 -268
  120. package/plugins/specweave/hooks/v2/handlers/project-bridge-handler.sh +0 -104
  121. package/plugins/specweave/hooks/v2/handlers/status-line-handler.sh +0 -165
  122. package/plugins/specweave/hooks/v2/handlers/status-update.sh +0 -61
  123. package/plugins/specweave/hooks/v2/handlers/universal-auto-create-dispatcher.sh +0 -270
  124. package/plugins/specweave/hooks/v2/integrations/ado-post-living-docs-update.sh +0 -367
  125. package/plugins/specweave/hooks/v2/integrations/ado-post-task.sh +0 -179
  126. package/plugins/specweave/hooks/v2/integrations/github-auto-create-handler.sh +0 -553
  127. package/plugins/specweave/hooks/v2/integrations/github-post-task.sh +0 -345
  128. package/plugins/specweave/hooks/v2/integrations/jira-post-task.sh +0 -180
  129. package/plugins/specweave/hooks/v2/lib/check-provider-enabled.sh +0 -52
  130. package/plugins/specweave/hooks/v2/queue/enqueue.sh +0 -81
  131. package/plugins/specweave/hooks/v2/session-end.sh +0 -139
  132. package/plugins/specweave/hooks/validate-skill-activations.sh +0 -227
@@ -1,347 +0,0 @@
1
- #!/bin/bash
2
- # github-sync-handler.sh - Sync increment to GitHub (create/update issues for User Stories)
3
- # Called async by processor, non-blocking, error-tolerant
4
- #
5
- # Argument formats supported:
6
- # 1. (event_type, increment_id) - from lifecycle/spec.updated events
7
- # 2. (event_type, INC_ID:US_ID) - from user-story.completed/reopened events (v1.0.45+)
8
- # 3. (increment_id) - from metadata.changed events (legacy)
9
- #
10
- # CRITICAL FIX (v1.0.45): Added user-story.completed/reopened support
11
- # Root cause: GitHub issues were created but NEVER UPDATED when User Stories completed!
12
- #
13
- # IMPORTANT: Never crash Claude, always exit 0
14
- # v1.0.71 - Fixed: Use specweave package location, not PROJECT_ROOT/dist
15
- set +e
16
-
17
- [[ "${SPECWEAVE_DISABLE_HOOKS:-0}" == "1" ]] && exit 0
18
-
19
- # Resolve specweave package location (do this early, before PROJECT_ROOT)
20
- HANDLER_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
21
- source "$HANDLER_DIR/../../lib/resolve-package.sh" 2>/dev/null || true
22
-
23
- # Parse arguments - support multiple formats
24
- EVENT_TYPE="${1:-}"
25
- EVENT_DATA="${2:-}"
26
- INC_ID=""
27
- US_ID=""
28
-
29
- if [[ "$EVENT_TYPE" == user-story.* ]]; then
30
- # user-story.completed/reopened: $2 = INC_ID:US_ID
31
- INC_ID="${EVENT_DATA%%:*}"
32
- US_ID="${EVENT_DATA##*:}"
33
- elif [[ "$EVENT_TYPE" == increment.* ]] || [[ "$EVENT_TYPE" == spec.* ]] || [[ "$EVENT_TYPE" == metadata.* ]]; then
34
- # Lifecycle events: $2 = increment_id
35
- INC_ID="$EVENT_DATA"
36
- else
37
- # Legacy format: $1 = increment_id directly
38
- INC_ID="$EVENT_TYPE"
39
- fi
40
-
41
- [[ -z "$INC_ID" ]] && exit 0
42
-
43
- # Find project root
44
- PROJECT_ROOT="$PWD"
45
- while [[ "$PROJECT_ROOT" != "/" ]] && [[ ! -f "$PROJECT_ROOT/.specweave/config.json" ]]; do
46
- PROJECT_ROOT=$(dirname "$PROJECT_ROOT")
47
- done
48
- [[ ! -f "$PROJECT_ROOT/.specweave/config.json" ]] && exit 0
49
-
50
- CONFIG_FILE="$PROJECT_ROOT/.specweave/config.json"
51
- [[ ! -f "$CONFIG_FILE" ]] && exit 0
52
-
53
- # Initialize throttle log early (used throughout the script for diagnostics)
54
- THROTTLE_LOG="$PROJECT_ROOT/.specweave/logs/throttle.log"
55
- mkdir -p "$(dirname "$THROTTLE_LOG")" 2>/dev/null
56
-
57
- # Check if GitHub sync is enabled
58
- # FIXED (v1.0.46): Support BOTH config formats:
59
- #
60
- # FORMAT 1 - PROFILES (current, multi-project):
61
- # sync.profiles["sw-content-repurposer-api"]: { provider: "github", config: {...} }
62
- # + sync.settings.canUpdateExternalItems: true
63
- #
64
- # FORMAT 2 - LEGACY (direct github section):
65
- # sync.github: { enabled: true, owner, repo }
66
- #
67
- # FORMAT 3 - LEGACY (provider field):
68
- # sync: { enabled: true, provider: "github" }
69
- #
70
- # NOTE: The actual permission gates (canUpdateExternalItems, etc.) are checked
71
- # downstream by GitHubFeatureSync, which respects the full permission model.
72
- GITHUB_ENABLED=""
73
-
74
- # Method 1: Check for PROFILES format (sync.profiles with provider: "github")
75
- # This is the current recommended format for multi-project setups
76
- if grep -q '"profiles"[[:space:]]*:' "$CONFIG_FILE" 2>/dev/null; then
77
- # Check if ANY profile has provider: "github"
78
- if grep -q '"provider"[[:space:]]*:[[:space:]]*"github"' "$CONFIG_FILE" 2>/dev/null; then
79
- # Also check if canUpdateExternalItems is true (required for GitHub sync)
80
- if grep -q '"canUpdateExternalItems"[[:space:]]*:[[:space:]]*true' "$CONFIG_FILE" 2>/dev/null; then
81
- GITHUB_ENABLED="true"
82
- else
83
- echo "[$(date '+%Y-%m-%d %H:%M:%S')] [github-sync] WARNING: GitHub profile found but canUpdateExternalItems=false" >> "$THROTTLE_LOG" 2>/dev/null
84
- fi
85
- fi
86
- fi
87
-
88
- # Method 2: Check for explicit sync.github.enabled (legacy direct style)
89
- if [[ -z "$GITHUB_ENABLED" ]]; then
90
- if grep -q '"github"[[:space:]]*:' "$CONFIG_FILE" 2>/dev/null; then
91
- if grep -A5 '"github"[[:space:]]*:' "$CONFIG_FILE" 2>/dev/null | grep -q '"enabled"[[:space:]]*:[[:space:]]*true'; then
92
- GITHUB_ENABLED="true"
93
- fi
94
- fi
95
- fi
96
-
97
- # Method 3: Check for provider: github with sync.enabled (legacy style)
98
- if [[ -z "$GITHUB_ENABLED" ]]; then
99
- # Only check this if there are NO profiles (pure legacy config)
100
- if ! grep -q '"profiles"[[:space:]]*:' "$CONFIG_FILE" 2>/dev/null; then
101
- if grep -q '"provider"[[:space:]]*:[[:space:]]*"github"' "$CONFIG_FILE" 2>/dev/null; then
102
- if grep -q '"sync"' "$CONFIG_FILE" && grep -A2 '"sync"' "$CONFIG_FILE" | grep -q '"enabled"[[:space:]]*:[[:space:]]*true'; then
103
- GITHUB_ENABLED="true"
104
- fi
105
- fi
106
- fi
107
- fi
108
-
109
- if [[ -z "$GITHUB_ENABLED" ]]; then
110
- echo "[$(date '+%Y-%m-%d %H:%M:%S')] [github-sync] SKIPPED: No GitHub config found or canUpdateExternalItems=false" >> "$THROTTLE_LOG" 2>/dev/null
111
- exit 0
112
- fi
113
-
114
- # Throttle configuration:
115
- # - Full sync (increment lifecycle): 5 minutes (creates all issues)
116
- # - US completion sync: 60 seconds (more targeted, less aggressive)
117
- # Note: THROTTLE_LOG already initialized above (line 49)
118
-
119
- if [[ -n "$US_ID" ]]; then
120
- # Per-US throttle (60 seconds) - more frequent for targeted updates
121
- THROTTLE_FILE="$PROJECT_ROOT/.specweave/state/.github-sync-$INC_ID-$US_ID"
122
- THROTTLE_WINDOW=60
123
- SYNC_TYPE="US:$US_ID"
124
- else
125
- # Per-increment throttle (5 minutes) - less frequent for full sync
126
- THROTTLE_FILE="$PROJECT_ROOT/.specweave/state/.github-sync-$INC_ID"
127
- THROTTLE_WINDOW=300
128
- SYNC_TYPE="increment"
129
- fi
130
-
131
- if [[ -f "$THROTTLE_FILE" ]]; then
132
- if [[ "$(uname)" == "Darwin" ]]; then
133
- AGE=$(($(date +%s) - $(stat -f %m "$THROTTLE_FILE" 2>/dev/null || echo 0)))
134
- else
135
- AGE=$(($(date +%s) - $(stat -c %Y "$THROTTLE_FILE" 2>/dev/null || echo 0)))
136
- fi
137
- if [[ $AGE -lt $THROTTLE_WINDOW ]]; then
138
- REMAINING=$((THROTTLE_WINDOW - AGE))
139
- echo "[$(date '+%Y-%m-%d %H:%M:%S')] [github-sync] THROTTLED $INC_ID ($SYNC_TYPE, wait ${REMAINING}s)" >> "$THROTTLE_LOG" 2>/dev/null
140
- exit 0
141
- fi
142
- fi
143
- touch "$THROTTLE_FILE"
144
- echo "[$(date '+%Y-%m-%d %H:%M:%S')] [github-sync] EXECUTING $INC_ID ($SYNC_TYPE) event=$EVENT_TYPE" >> "$THROTTLE_LOG" 2>/dev/null
145
-
146
- # Cross-platform timeout wrapper
147
- # FIXED (v1.0.302): Don't suppress stderr from inner commands — only suppress
148
- # stderr from timeout/gtimeout binary itself (e.g., "command not found").
149
- # The caller already redirects stderr to log files via 2>&1.
150
- run_with_timeout() {
151
- local timeout_secs="$1"
152
- shift
153
- if command -v timeout >/dev/null 2>&1; then
154
- timeout "$timeout_secs" "$@" || true
155
- elif command -v gtimeout >/dev/null 2>&1; then
156
- gtimeout "$timeout_secs" "$@" || true
157
- else
158
- "$@" || true
159
- fi
160
- }
161
-
162
- # Load GitHub token - fallback chain mirrors auth-helpers.ts:
163
- # 1. .env GITHUB_TOKEN (explicit config)
164
- # 2. .env GH_TOKEN (alternative name)
165
- # 3. gh auth token (gh CLI - most common for local dev!)
166
- # FIXED (v1.0.57): Added GH_TOKEN and gh auth fallback - critical for local development!
167
- GITHUB_TOKEN=""
168
-
169
- # Try .env GITHUB_TOKEN first
170
- if [[ -f "$PROJECT_ROOT/.env" ]]; then
171
- GITHUB_TOKEN=$(grep -E "^GITHUB_TOKEN=" "$PROJECT_ROOT/.env" | cut -d'=' -f2- | tr -d '"'"'")
172
- # Try GH_TOKEN as alternative
173
- [[ -z "$GITHUB_TOKEN" ]] && GITHUB_TOKEN=$(grep -E "^GH_TOKEN=" "$PROJECT_ROOT/.env" | cut -d'=' -f2- | tr -d '"'"'")
174
- fi
175
-
176
- # Fallback to gh CLI (most common for local development!)
177
- if [[ -z "$GITHUB_TOKEN" ]] && command -v gh >/dev/null 2>&1; then
178
- GITHUB_TOKEN=$(gh auth token 2>/dev/null || true)
179
- if [[ -n "$GITHUB_TOKEN" ]]; then
180
- echo "[$(date '+%Y-%m-%d %H:%M:%S')] [github-sync] Using token from gh auth (not .env)" >> "$THROTTLE_LOG" 2>/dev/null
181
- fi
182
- fi
183
-
184
- if [[ -z "$GITHUB_TOKEN" ]]; then
185
- echo "[$(date '+%Y-%m-%d %H:%M:%S')] [github-sync] ERROR: No GitHub token found" >> "$THROTTLE_LOG" 2>/dev/null
186
- echo "[$(date '+%Y-%m-%d %H:%M:%S')] [github-sync] Checked: $PROJECT_ROOT/.env (GITHUB_TOKEN, GH_TOKEN)" >> "$THROTTLE_LOG" 2>/dev/null
187
- echo "[$(date '+%Y-%m-%d %H:%M:%S')] [github-sync] Checked: gh auth token (gh CLI not authenticated?)" >> "$THROTTLE_LOG" 2>/dev/null
188
- echo "[$(date '+%Y-%m-%d %H:%M:%S')] [github-sync] Fix: Run 'gh auth login' OR add GITHUB_TOKEN to .env" >> "$THROTTLE_LOG" 2>/dev/null
189
- exit 0
190
- fi
191
-
192
- echo "[$(date '+%Y-%m-%d %H:%M:%S')] [github-sync] Token found (length: ${#GITHUB_TOKEN})" >> "$THROTTLE_LOG" 2>/dev/null
193
-
194
- # Find sync script
195
- # FIXED (v1.0.46): Support compiled JS AND TypeScript with tsx
196
- # Priority order:
197
- # 1. Local development dist/ (compiled JS)
198
- # 2. Local plugins/ source (TypeScript via tsx)
199
- # 3. Marketplace cache (compiled JS)
200
- # 4. Marketplace source (TypeScript via tsx)
201
- # 5. Legacy CLAUDE_PLUGIN_ROOT
202
- #
203
- # Note: Marketplace installations often have .ts source only, not compiled .js
204
- # We detect this and use tsx (fast TypeScript runner) when available
205
-
206
- SYNC_SCRIPT=""
207
- NEEDS_TSX=false
208
-
209
- # Paths to check - JS files first, then TS files
210
- # SPECWEAVE_PKG takes priority (resolved from npm package location)
211
- JS_PATHS=(
212
- "${SPECWEAVE_PKG:-}/dist/plugins/specweave-github/lib/github-feature-sync-cli.js"
213
- "$PROJECT_ROOT/dist/plugins/specweave-github/lib/github-feature-sync-cli.js"
214
- "$HOME/.claude/plugins/cache/specweave/sw-github/*/lib/github-feature-sync-cli.js"
215
- "${CLAUDE_PLUGIN_ROOT:-}/lib/github-feature-sync-cli.js"
216
- )
217
-
218
- TS_PATHS=(
219
- "${SPECWEAVE_PKG:-}/plugins/specweave-github/lib/github-feature-sync-cli.ts"
220
- "$PROJECT_ROOT/plugins/specweave-github/lib/github-feature-sync-cli.ts"
221
- "$HOME/.claude/plugins/marketplaces/specweave/plugins/specweave-github/lib/github-feature-sync-cli.ts"
222
- "$HOME/.claude/plugins/cache/specweave/sw-github/*/lib/github-feature-sync-cli.ts"
223
- )
224
-
225
- # Try JS files first (no tsx needed)
226
- for pattern in "${JS_PATHS[@]}"; do
227
- # Handle glob patterns
228
- for path in $pattern; do
229
- if [[ -f "$path" ]]; then
230
- SYNC_SCRIPT="$path"
231
- break 2
232
- fi
233
- done
234
- done
235
-
236
- # If no JS found, try TS files (need tsx)
237
- if [[ -z "$SYNC_SCRIPT" ]]; then
238
- for pattern in "${TS_PATHS[@]}"; do
239
- for path in $pattern; do
240
- if [[ -f "$path" ]]; then
241
- SYNC_SCRIPT="$path"
242
- NEEDS_TSX=true
243
- break 2
244
- fi
245
- done
246
- done
247
- fi
248
-
249
- if [[ -z "$SYNC_SCRIPT" ]]; then
250
- echo "[$(date '+%Y-%m-%d %H:%M:%S')] [github-sync] ERROR: github-feature-sync-cli not found" >> "$THROTTLE_LOG" 2>/dev/null
251
- echo " Searched JS paths:" >> "$THROTTLE_LOG" 2>/dev/null
252
- for p in "${JS_PATHS[@]}"; do echo " - $p" >> "$THROTTLE_LOG" 2>/dev/null; done
253
- echo " Searched TS paths:" >> "$THROTTLE_LOG" 2>/dev/null
254
- for p in "${TS_PATHS[@]}"; do echo " - $p" >> "$THROTTLE_LOG" 2>/dev/null; done
255
- exit 0
256
- fi
257
-
258
- # Verify tsx is available if needed
259
- if [[ "$NEEDS_TSX" == "true" ]]; then
260
- if ! command -v tsx >/dev/null 2>&1 && ! command -v npx >/dev/null 2>&1; then
261
- echo "[$(date '+%Y-%m-%d %H:%M:%S')] [github-sync] ERROR: Found TS file but tsx/npx not available" >> "$THROTTLE_LOG" 2>/dev/null
262
- echo " Install tsx: npm install -g tsx" >> "$THROTTLE_LOG" 2>/dev/null
263
- exit 0
264
- fi
265
- fi
266
-
267
- echo "[$(date '+%Y-%m-%d %H:%M:%S')] [github-sync] Found sync script: $SYNC_SCRIPT (tsx=$NEEDS_TSX)" >> "$THROTTLE_LOG" 2>/dev/null
268
-
269
- # Extract feature ID - check multiple locations in priority order
270
- # FIXED (v1.0.58): Per ADR-0140, feature_id was REMOVED from metadata.json in v0.29.0
271
- # Feature ID is now DERIVED from increment ID: 0149-... → FS-149
272
- #
273
- # Priority order (v1.0.58):
274
- # 1. DERIVE from increment ID (PRIMARY - per ADR-0140)
275
- # 2. metadata.json: epic_id field (for external/brownfield increments)
276
- # 3. spec.md YAML frontmatter: feature_id: or epic: (explicit override)
277
- #
278
- META_FILE="$PROJECT_ROOT/.specweave/increments/$INC_ID/metadata.json"
279
- SPEC_FILE="$PROJECT_ROOT/.specweave/increments/$INC_ID/spec.md"
280
- FEATURE_ID=""
281
-
282
- # Method 0 (v1.0.58): DERIVE from increment ID (PRIMARY method per ADR-0140)
283
- # Extract leading digits and optional E suffix, format as FS-XXX
284
- # Examples: 0149-usage-analytics → FS-149, 0111E-external → FS-111E
285
- INC_NUMBER=$(echo "$INC_ID" | grep -oE '^[0-9]+')
286
- INC_EXTERNAL=$(echo "$INC_ID" | grep -oE '^[0-9]+E' | grep -o 'E$' || echo "")
287
- if [[ -n "$INC_NUMBER" ]]; then
288
- # Remove leading zeros for numeric value, then pad to 3 digits
289
- INC_NUM_CLEAN=$((10#$INC_NUMBER)) # Force decimal interpretation
290
- FEATURE_ID=$(printf "FS-%03d%s" "$INC_NUM_CLEAN" "$INC_EXTERNAL")
291
- echo "[$(date '+%Y-%m-%d %H:%M:%S')] [github-sync] Derived feature_id=$FEATURE_ID from increment $INC_ID" >> "$THROTTLE_LOG" 2>/dev/null
292
- fi
293
-
294
- # Method 1: Check metadata.json for epic_id (external/brownfield increments only)
295
- if [[ -z "$FEATURE_ID" ]] && [[ -f "$META_FILE" ]]; then
296
- FEATURE_ID=$(grep -o '"epic_id"[[:space:]]*:[[:space:]]*"[^"]*"' "$META_FILE" | head -1 | sed 's/.*:[[:space:]]*"\([^"]*\)".*/\1/')
297
- [[ "$FEATURE_ID" == "null" ]] && FEATURE_ID=""
298
- fi
299
-
300
- # Method 2: Check spec.md YAML frontmatter (explicit override)
301
- if [[ -z "$FEATURE_ID" ]] && [[ -f "$SPEC_FILE" ]]; then
302
- # Try start-of-line format: feature_id: FS-001 or epic: FS-001
303
- FEATURE_ID=$(grep -E "^(epic|feature_id|feature):" "$SPEC_FILE" | head -1 | sed 's/.*:[[:space:]]*//' | tr -d '"'"'" | tr -d ' ')
304
- # Also try indented YAML frontmatter style
305
- if [[ -z "$FEATURE_ID" ]]; then
306
- FEATURE_ID=$(grep -E "^[[:space:]]*(epic|feature_id|feature):" "$SPEC_FILE" | head -1 | sed 's/.*:[[:space:]]*//' | tr -d '"'"'" | tr -d ' ')
307
- fi
308
- fi
309
-
310
- if [[ -z "$FEATURE_ID" ]]; then
311
- echo "[$(date '+%Y-%m-%d %H:%M:%S')] [github-sync] WARNING: No feature ID found" >> "$THROTTLE_LOG" 2>/dev/null
312
- echo " Increment ID: $INC_ID" >> "$THROTTLE_LOG" 2>/dev/null
313
- echo " This should not happen - derivation from increment ID should always work" >> "$THROTTLE_LOG" 2>/dev/null
314
- exit 0
315
- fi
316
-
317
- echo "[$(date '+%Y-%m-%d %H:%M:%S')] [github-sync] Found feature_id=$FEATURE_ID" >> "$THROTTLE_LOG" 2>/dev/null
318
-
319
- # Run sync (timeout 60s)
320
- # The github-feature-sync-cli script will:
321
- # 1. Find all User Stories in the feature
322
- # 2. For each US, call updateUserStoryIssue() which:
323
- # - Updates issue body with latest content
324
- # - Calculates completion via CompletionCalculator (verifies [x] checkboxes)
325
- # - CLOSES the issue if ALL ACs and tasks are verified complete
326
- # - Updates status labels (status:complete, status:active, status:not_started)
327
- cd "$PROJECT_ROOT" || exit 0
328
-
329
- # Build the run command based on file type
330
- if [[ "$NEEDS_TSX" == "true" ]]; then
331
- # TypeScript file - use tsx or npx tsx
332
- if command -v tsx >/dev/null 2>&1; then
333
- RUN_CMD="tsx"
334
- else
335
- RUN_CMD="npx tsx"
336
- fi
337
- echo "[$(date '+%Y-%m-%d %H:%M:%S')] [github-sync] Running: $RUN_CMD $SYNC_SCRIPT $FEATURE_ID" >> "$THROTTLE_LOG" 2>/dev/null
338
- GITHUB_TOKEN="$GITHUB_TOKEN" run_with_timeout 60 $RUN_CMD "$SYNC_SCRIPT" "$FEATURE_ID" >> "$THROTTLE_LOG" 2>&1
339
- else
340
- # JavaScript file - use node directly
341
- echo "[$(date '+%Y-%m-%d %H:%M:%S')] [github-sync] Running: node $SYNC_SCRIPT $FEATURE_ID" >> "$THROTTLE_LOG" 2>/dev/null
342
- GITHUB_TOKEN="$GITHUB_TOKEN" run_with_timeout 60 node "$SYNC_SCRIPT" "$FEATURE_ID" >> "$THROTTLE_LOG" 2>&1
343
- fi
344
-
345
- SYNC_EXIT=$?
346
- echo "[$(date '+%Y-%m-%d %H:%M:%S')] [github-sync] COMPLETED $INC_ID ($SYNC_TYPE) exit=$SYNC_EXIT" >> "$THROTTLE_LOG" 2>/dev/null
347
- exit 0
@@ -1,83 +0,0 @@
1
- #!/bin/bash
2
- # living-docs-handler.sh - Sync increment to living docs
3
- # Called async by processor, non-blocking, error-tolerant
4
- #
5
- # IMPORTANT: Never crash Claude, always exit 0
6
- # v1.0.71 - Fixed: Use specweave package location, not PROJECT_ROOT/dist
7
- set +e
8
-
9
- [[ "${SPECWEAVE_DISABLE_HOOKS:-0}" == "1" ]] && exit 0
10
-
11
- INC_ID="${1:-}"
12
- [[ -z "$INC_ID" ]] && exit 0
13
-
14
- # Find project root
15
- PROJECT_ROOT="$PWD"
16
- while [[ "$PROJECT_ROOT" != "/" ]] && [[ ! -f "$PROJECT_ROOT/.specweave/config.json" ]]; do
17
- PROJECT_ROOT=$(dirname "$PROJECT_ROOT")
18
- done
19
- [[ ! -f "$PROJECT_ROOT/.specweave/config.json" ]] && exit 0
20
-
21
- # Resolve specweave package location
22
- HANDLER_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
23
- source "$HANDLER_DIR/../../lib/resolve-package.sh" 2>/dev/null || true
24
-
25
- # Throttle: max once per minute per increment
26
- THROTTLE_FILE="$PROJECT_ROOT/.specweave/state/.living-docs-$INC_ID"
27
- THROTTLE_LOG="$PROJECT_ROOT/.specweave/logs/throttle.log"
28
- THROTTLE_WINDOW=60 # 1 minute
29
- mkdir -p "$(dirname "$THROTTLE_LOG")" 2>/dev/null
30
-
31
- if [[ -f "$THROTTLE_FILE" ]]; then
32
- if [[ "$(uname)" == "Darwin" ]]; then
33
- AGE=$(($(date +%s) - $(stat -f %m "$THROTTLE_FILE" 2>/dev/null || echo 0)))
34
- else
35
- AGE=$(($(date +%s) - $(stat -c %Y "$THROTTLE_FILE" 2>/dev/null || echo 0)))
36
- fi
37
- if [[ $AGE -lt $THROTTLE_WINDOW ]]; then
38
- REMAINING=$((THROTTLE_WINDOW - AGE))
39
- echo "[$(date '+%Y-%m-%d %H:%M:%S')] [living-docs] THROTTLED $INC_ID (wait ${REMAINING}s)" >> "$THROTTLE_LOG" 2>/dev/null
40
- exit 0
41
- fi
42
- fi
43
- touch "$THROTTLE_FILE"
44
- echo "[$(date '+%Y-%m-%d %H:%M:%S')] [living-docs] EXECUTING $INC_ID" >> "$THROTTLE_LOG" 2>/dev/null
45
-
46
- # Cross-platform timeout wrapper
47
- run_with_timeout() {
48
- local timeout_secs="$1"
49
- shift
50
- if command -v timeout >/dev/null 2>&1; then
51
- timeout "$timeout_secs" "$@" 2>/dev/null || true
52
- elif command -v gtimeout >/dev/null 2>&1; then
53
- gtimeout "$timeout_secs" "$@" 2>/dev/null || true
54
- else
55
- "$@" 2>/dev/null || true
56
- fi
57
- }
58
-
59
- # Find sync script (check SPECWEAVE_PKG first)
60
- SYNC_SCRIPT=""
61
- for path in \
62
- "${SPECWEAVE_PKG:-}/dist/plugins/specweave/lib/hooks/sync-living-docs.js" \
63
- "${SPECWEAVE_PKG:-}/plugins/specweave/lib/hooks/sync-living-docs.js" \
64
- "${CLAUDE_PLUGIN_ROOT:-}/lib/hooks/sync-living-docs.js" \
65
- "$PROJECT_ROOT/dist/plugins/specweave/lib/hooks/sync-living-docs.js" \
66
- "$PROJECT_ROOT/plugins/specweave/lib/hooks/sync-living-docs.js"; do
67
- [[ -f "$path" ]] && { SYNC_SCRIPT="$path"; break; }
68
- done
69
- [[ -z "$SYNC_SCRIPT" ]] && exit 0
70
-
71
- # Extract feature ID from spec.md
72
- SPEC_FILE="$PROJECT_ROOT/.specweave/increments/$INC_ID/spec.md"
73
- FEATURE_ID=""
74
- [[ -f "$SPEC_FILE" ]] && FEATURE_ID=$(grep -E "^(epic|feature_id):" "$SPEC_FILE" | head -1 | sed 's/.*:[[:space:]]*//' | tr -d '"'"'")
75
-
76
- # Run sync (timeout 30s)
77
- cd "$PROJECT_ROOT" || exit 0
78
- if [[ -n "$FEATURE_ID" ]]; then
79
- FEATURE_ID="$FEATURE_ID" run_with_timeout 30 node "$SYNC_SCRIPT" "$INC_ID" >/dev/null 2>&1
80
- else
81
- run_with_timeout 30 node "$SYNC_SCRIPT" "$INC_ID" >/dev/null 2>&1
82
- fi
83
- exit 0