specweave 1.0.550 → 1.0.552

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (166) hide show
  1. package/CLAUDE.md +1 -1
  2. package/bin/specweave.js +23 -1
  3. package/dist/src/cli/commands/hook.d.ts +15 -0
  4. package/dist/src/cli/commands/hook.d.ts.map +1 -0
  5. package/dist/src/cli/commands/hook.js +61 -0
  6. package/dist/src/cli/commands/hook.js.map +1 -0
  7. package/dist/src/cli/commands/init.d.ts.map +1 -1
  8. package/dist/src/cli/commands/init.js +5 -0
  9. package/dist/src/cli/commands/init.js.map +1 -1
  10. package/dist/src/cli/commands/refresh-plugins.d.ts.map +1 -1
  11. package/dist/src/cli/commands/refresh-plugins.js +11 -1
  12. package/dist/src/cli/commands/refresh-plugins.js.map +1 -1
  13. package/dist/src/cli/commands/sync-setup.d.ts.map +1 -1
  14. package/dist/src/cli/commands/sync-setup.js +7 -3
  15. package/dist/src/cli/commands/sync-setup.js.map +1 -1
  16. package/dist/src/cli/helpers/issue-tracker/project-mapping-wizard.d.ts +9 -0
  17. package/dist/src/cli/helpers/issue-tracker/project-mapping-wizard.d.ts.map +1 -1
  18. package/dist/src/cli/helpers/issue-tracker/project-mapping-wizard.js +9 -3
  19. package/dist/src/cli/helpers/issue-tracker/project-mapping-wizard.js.map +1 -1
  20. package/dist/src/config/types.d.ts +2 -2
  21. package/dist/src/core/config/types.d.ts +18 -2
  22. package/dist/src/core/config/types.d.ts.map +1 -1
  23. package/dist/src/core/config/types.js.map +1 -1
  24. package/dist/src/core/hooks/handlers/hook-router.d.ts +19 -0
  25. package/dist/src/core/hooks/handlers/hook-router.d.ts.map +1 -0
  26. package/dist/src/core/hooks/handlers/hook-router.js +75 -0
  27. package/dist/src/core/hooks/handlers/hook-router.js.map +1 -0
  28. package/dist/src/core/hooks/handlers/index.d.ts +10 -0
  29. package/dist/src/core/hooks/handlers/index.d.ts.map +1 -0
  30. package/dist/src/core/hooks/handlers/index.js +9 -0
  31. package/dist/src/core/hooks/handlers/index.js.map +1 -0
  32. package/dist/src/core/hooks/handlers/post-tool-use-analytics.d.ts +11 -0
  33. package/dist/src/core/hooks/handlers/post-tool-use-analytics.d.ts.map +1 -0
  34. package/dist/src/core/hooks/handlers/post-tool-use-analytics.js +73 -0
  35. package/dist/src/core/hooks/handlers/post-tool-use-analytics.js.map +1 -0
  36. package/dist/src/core/hooks/handlers/post-tool-use.d.ts +11 -0
  37. package/dist/src/core/hooks/handlers/post-tool-use.d.ts.map +1 -0
  38. package/dist/src/core/hooks/handlers/post-tool-use.js +76 -0
  39. package/dist/src/core/hooks/handlers/post-tool-use.js.map +1 -0
  40. package/dist/src/core/hooks/handlers/pre-compact.d.ts +11 -0
  41. package/dist/src/core/hooks/handlers/pre-compact.d.ts.map +1 -0
  42. package/dist/src/core/hooks/handlers/pre-compact.js +77 -0
  43. package/dist/src/core/hooks/handlers/pre-compact.js.map +1 -0
  44. package/dist/src/core/hooks/handlers/pre-tool-use.d.ts +11 -0
  45. package/dist/src/core/hooks/handlers/pre-tool-use.d.ts.map +1 -0
  46. package/dist/src/core/hooks/handlers/pre-tool-use.js +318 -0
  47. package/dist/src/core/hooks/handlers/pre-tool-use.js.map +1 -0
  48. package/dist/src/core/hooks/handlers/session-start.d.ts +9 -0
  49. package/dist/src/core/hooks/handlers/session-start.d.ts.map +1 -0
  50. package/dist/src/core/hooks/handlers/session-start.js +111 -0
  51. package/dist/src/core/hooks/handlers/session-start.js.map +1 -0
  52. package/dist/src/core/hooks/handlers/stop-auto.d.ts +16 -0
  53. package/dist/src/core/hooks/handlers/stop-auto.d.ts.map +1 -0
  54. package/dist/src/core/hooks/handlers/stop-auto.js +122 -0
  55. package/dist/src/core/hooks/handlers/stop-auto.js.map +1 -0
  56. package/dist/src/core/hooks/handlers/stop-reflect.d.ts +14 -0
  57. package/dist/src/core/hooks/handlers/stop-reflect.d.ts.map +1 -0
  58. package/dist/src/core/hooks/handlers/stop-reflect.js +43 -0
  59. package/dist/src/core/hooks/handlers/stop-reflect.js.map +1 -0
  60. package/dist/src/core/hooks/handlers/stop-sync.d.ts +15 -0
  61. package/dist/src/core/hooks/handlers/stop-sync.d.ts.map +1 -0
  62. package/dist/src/core/hooks/handlers/stop-sync.js +68 -0
  63. package/dist/src/core/hooks/handlers/stop-sync.js.map +1 -0
  64. package/dist/src/core/hooks/handlers/types.d.ts +63 -0
  65. package/dist/src/core/hooks/handlers/types.d.ts.map +1 -0
  66. package/dist/src/core/hooks/handlers/types.js +27 -0
  67. package/dist/src/core/hooks/handlers/types.js.map +1 -0
  68. package/dist/src/core/hooks/handlers/user-prompt-submit.d.ts +14 -0
  69. package/dist/src/core/hooks/handlers/user-prompt-submit.d.ts.map +1 -0
  70. package/dist/src/core/hooks/handlers/user-prompt-submit.js +173 -0
  71. package/dist/src/core/hooks/handlers/user-prompt-submit.js.map +1 -0
  72. package/dist/src/core/hooks/handlers/utils.d.ts +25 -0
  73. package/dist/src/core/hooks/handlers/utils.d.ts.map +1 -0
  74. package/dist/src/core/hooks/handlers/utils.js +64 -0
  75. package/dist/src/core/hooks/handlers/utils.js.map +1 -0
  76. package/dist/src/core/increment/completion-validator.d.ts.map +1 -1
  77. package/dist/src/core/increment/completion-validator.js +32 -0
  78. package/dist/src/core/increment/completion-validator.js.map +1 -1
  79. package/dist/src/init/research/types.d.ts +1 -1
  80. package/dist/src/sync/sync-target-resolver.js.map +1 -1
  81. package/dist/src/utils/lock-manager.d.ts.map +1 -1
  82. package/dist/src/utils/lock-manager.js +5 -0
  83. package/dist/src/utils/lock-manager.js.map +1 -1
  84. package/dist/src/utils/plugin-copier.d.ts +10 -0
  85. package/dist/src/utils/plugin-copier.d.ts.map +1 -1
  86. package/dist/src/utils/plugin-copier.js +63 -35
  87. package/dist/src/utils/plugin-copier.js.map +1 -1
  88. package/package.json +1 -1
  89. package/plugins/specweave/agents/sw-closer.md +3 -2
  90. package/plugins/specweave/hooks/hooks.json +10 -10
  91. package/plugins/specweave/skills/code-reviewer/SKILL.md +180 -16
  92. package/plugins/specweave/skills/code-reviewer/agents/reviewer-comments.md +83 -0
  93. package/plugins/specweave/skills/code-reviewer/agents/reviewer-silent-failures.md +19 -0
  94. package/plugins/specweave/skills/code-reviewer/agents/reviewer-spec-compliance.md +19 -0
  95. package/plugins/specweave/skills/code-reviewer/agents/reviewer-tests.md +101 -0
  96. package/plugins/specweave/skills/code-reviewer/agents/reviewer-types.md +20 -0
  97. package/plugins/specweave/skills/done/SKILL.md +56 -21
  98. package/plugins/specweave/skills/grill/SKILL.md +1 -1
  99. package/plugins/specweave/skills/team-lead/agents/reviewer-logic.md +19 -0
  100. package/plugins/specweave/skills/team-lead/agents/reviewer-performance.md +20 -0
  101. package/plugins/specweave/skills/team-lead/agents/reviewer-security.md +20 -0
  102. package/src/templates/CLAUDE.md.template +7 -4
  103. package/plugins/specweave/hooks/README.md +0 -493
  104. package/plugins/specweave/hooks/_archive/stop-auto-v4-legacy.sh +0 -1319
  105. package/plugins/specweave/hooks/lib/common-setup.sh +0 -144
  106. package/plugins/specweave/hooks/lib/hook-errors.sh +0 -414
  107. package/plugins/specweave/hooks/lib/migrate-increment-work.sh +0 -245
  108. package/plugins/specweave/hooks/lib/resolve-package.sh +0 -146
  109. package/plugins/specweave/hooks/lib/scheduler-startup.sh +0 -135
  110. package/plugins/specweave/hooks/lib/score-increment.sh +0 -87
  111. package/plugins/specweave/hooks/lib/sync-spec-content.sh +0 -193
  112. package/plugins/specweave/hooks/lib/update-active-increment.sh +0 -95
  113. package/plugins/specweave/hooks/lib/update-status-line.sh +0 -233
  114. package/plugins/specweave/hooks/lib/validate-spec-status.sh +0 -171
  115. package/plugins/specweave/hooks/llm-judge-validator.sh +0 -219
  116. package/plugins/specweave/hooks/log-decision.sh +0 -168
  117. package/plugins/specweave/hooks/pre-compact.sh +0 -64
  118. package/plugins/specweave/hooks/startup-health-check.sh +0 -64
  119. package/plugins/specweave/hooks/stop-auto-v5.sh +0 -276
  120. package/plugins/specweave/hooks/stop-reflect.sh +0 -336
  121. package/plugins/specweave/hooks/stop-sync.sh +0 -283
  122. package/plugins/specweave/hooks/tests/test-auto-context-integration.sh +0 -126
  123. package/plugins/specweave/hooks/tests/test-stop-auto-enriched.sh +0 -128
  124. package/plugins/specweave/hooks/universal/dispatcher.mjs +0 -336
  125. package/plugins/specweave/hooks/universal/fail-fast-wrapper.sh +0 -325
  126. package/plugins/specweave/hooks/universal/hook-wrapper.cmd +0 -26
  127. package/plugins/specweave/hooks/universal/hook-wrapper.sh +0 -69
  128. package/plugins/specweave/hooks/universal/run-hook.sh +0 -20
  129. package/plugins/specweave/hooks/universal/session-start.cmd +0 -16
  130. package/plugins/specweave/hooks/universal/session-start.ps1 +0 -16
  131. package/plugins/specweave/hooks/user-prompt-submit.sh +0 -2550
  132. package/plugins/specweave/hooks/v2/detectors/lifecycle-detector.sh +0 -87
  133. package/plugins/specweave/hooks/v2/detectors/us-completion-detector.sh +0 -186
  134. package/plugins/specweave/hooks/v2/dispatchers/post-tool-use-analytics.sh +0 -83
  135. package/plugins/specweave/hooks/v2/dispatchers/post-tool-use.sh +0 -447
  136. package/plugins/specweave/hooks/v2/dispatchers/pre-tool-use.sh +0 -104
  137. package/plugins/specweave/hooks/v2/dispatchers/session-start.sh +0 -270
  138. package/plugins/specweave/hooks/v2/guards/completion-guard.sh +0 -14
  139. package/plugins/specweave/hooks/v2/guards/increment-duplicate-guard.sh +0 -14
  140. package/plugins/specweave/hooks/v2/guards/increment-existence-guard.sh +0 -240
  141. package/plugins/specweave/hooks/v2/guards/interview-enforcement-guard.sh +0 -171
  142. package/plugins/specweave/hooks/v2/guards/metadata-json-guard.sh +0 -14
  143. package/plugins/specweave/hooks/v2/guards/skill-chain-enforcement-guard.sh +0 -222
  144. package/plugins/specweave/hooks/v2/guards/spec-template-enforcement-guard.sh +0 -21
  145. package/plugins/specweave/hooks/v2/guards/spec-validation-guard.sh +0 -14
  146. package/plugins/specweave/hooks/v2/guards/status-completion-guard.sh +0 -84
  147. package/plugins/specweave/hooks/v2/guards/task-ac-sync-guard.sh +0 -475
  148. package/plugins/specweave/hooks/v2/guards/tdd-enforcement-guard.sh +0 -268
  149. package/plugins/specweave/hooks/v2/handlers/ac-sync-dispatcher.sh +0 -332
  150. package/plugins/specweave/hooks/v2/handlers/ac-validation-handler.sh +0 -50
  151. package/plugins/specweave/hooks/v2/handlers/github-sync-handler.sh +0 -347
  152. package/plugins/specweave/hooks/v2/handlers/living-docs-handler.sh +0 -83
  153. package/plugins/specweave/hooks/v2/handlers/living-specs-handler.sh +0 -268
  154. package/plugins/specweave/hooks/v2/handlers/project-bridge-handler.sh +0 -104
  155. package/plugins/specweave/hooks/v2/handlers/status-line-handler.sh +0 -165
  156. package/plugins/specweave/hooks/v2/handlers/status-update.sh +0 -61
  157. package/plugins/specweave/hooks/v2/handlers/universal-auto-create-dispatcher.sh +0 -270
  158. package/plugins/specweave/hooks/v2/integrations/ado-post-living-docs-update.sh +0 -367
  159. package/plugins/specweave/hooks/v2/integrations/ado-post-task.sh +0 -179
  160. package/plugins/specweave/hooks/v2/integrations/github-auto-create-handler.sh +0 -553
  161. package/plugins/specweave/hooks/v2/integrations/github-post-task.sh +0 -345
  162. package/plugins/specweave/hooks/v2/integrations/jira-post-task.sh +0 -180
  163. package/plugins/specweave/hooks/v2/lib/check-provider-enabled.sh +0 -52
  164. package/plugins/specweave/hooks/v2/queue/enqueue.sh +0 -81
  165. package/plugins/specweave/hooks/v2/session-end.sh +0 -139
  166. package/plugins/specweave/hooks/validate-skill-activations.sh +0 -227
@@ -1,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