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,345 +0,0 @@
1
- #!/bin/bash
2
-
3
- # SpecWeave GitHub Sync Hook
4
- # Runs after task completion to sync progress to GitHub Projects
5
- #
6
- # ARCHITECTURE (v0.19.0+): IMMUTABLE DESCRIPTIONS + PROGRESS COMMENTS
7
- # - User Story files (.specweave/docs/internal/specs/) ↔ GitHub Issues
8
- # - Issue descriptions created once (IMMUTABLE snapshot)
9
- # - All updates via progress comments (audit trail)
10
- #
11
- # This hook is part of the specweave-github plugin and handles:
12
- # - Finding which spec user stories the current work belongs to
13
- # - Syncing progress via GitHub comments (NOT editing issue body)
14
- # - Creating audit trail of all changes over time
15
- # - Notifying stakeholders via GitHub notifications
16
- #
17
- # Dependencies:
18
- # - Node.js and TypeScript CLI (dist/cli/commands/sync-spec-content.js)
19
- # - GitHub CLI (gh) must be installed and authenticated
20
- # - ProgressCommentBuilder (lib/progress-comment-builder.ts)
21
-
22
- set +e # EMERGENCY FIX: Prevents Claude Code crashes
23
-
24
- # EMERGENCY KILL SWITCH
25
- if [[ "${SPECWEAVE_DISABLE_HOOKS:-0}" == "1" ]]; then
26
- exit 0
27
- fi
28
-
29
- # ============================================================================
30
- # PROJECT ROOT DETECTION (MUST BE FIRST - before any mkdir!)
31
- # ============================================================================
32
-
33
- # Find project root by searching upward for .specweave/ directory
34
- find_project_root() {
35
- local dir="$1"
36
- while [ "$dir" != "/" ]; do
37
- if [ -f "$dir/.specweave/config.json" ]; then
38
- echo "$dir"
39
- return 0
40
- fi
41
- dir="$(dirname "$dir")"
42
- done
43
- return 1 # NOT FOUND - return error, do NOT fallback to pwd
44
- }
45
-
46
- PROJECT_ROOT="$(find_project_root "$(pwd)")"
47
- if [[ -z "$PROJECT_ROOT" ]]; then
48
- # NOT a SpecWeave project - exit silently (no .specweave pollution!)
49
- exit 0
50
- fi
51
- cd "$PROJECT_ROOT" 2>/dev/null || exit 0
52
-
53
- # ============================================================================
54
- # CIRCUIT BREAKER & FILE LOCKING
55
- # ============================================================================
56
-
57
- # CIRCUIT BREAKER: Auto-disable after consecutive failures
58
- CIRCUIT_BREAKER_FILE="$PROJECT_ROOT/.specweave/state/.hook-circuit-breaker-github"
59
- CIRCUIT_BREAKER_THRESHOLD=3
60
-
61
- mkdir -p "$PROJECT_ROOT/.specweave/state" 2>/dev/null || true
62
-
63
- if [[ -f "$CIRCUIT_BREAKER_FILE" ]]; then
64
- FAILURE_COUNT=$(cat "$CIRCUIT_BREAKER_FILE" 2>/dev/null || echo 0)
65
- if (( FAILURE_COUNT >= CIRCUIT_BREAKER_THRESHOLD )); then
66
- # Circuit breaker is OPEN - hooks are disabled
67
- exit 0
68
- fi
69
- fi
70
-
71
- # FILE LOCK: Only allow 1 GitHub sync hook at a time
72
- LOCK_FILE="$PROJECT_ROOT/.specweave/state/.hook-github-sync.lock"
73
- LOCK_TIMEOUT=15 # seconds (GitHub sync can take longer)
74
-
75
- LOCK_ACQUIRED=false
76
- for i in {1..15}; do
77
- if mkdir "$LOCK_FILE" 2>/dev/null; then
78
- LOCK_ACQUIRED=true
79
- trap 'rmdir "$LOCK_FILE" 2>/dev/null || true' EXIT
80
- break
81
- fi
82
-
83
- # Check for stale lock (POSIX-portable: works on macOS and Linux)
84
- if [[ -d "$LOCK_FILE" ]]; then
85
- # Use find -mmin which works on both macOS and Linux
86
- LOCK_TIMEOUT_MIN=$(( (LOCK_TIMEOUT + 59) / 60 )) # Convert seconds to minutes (ceil)
87
- [[ $LOCK_TIMEOUT_MIN -lt 1 ]] && LOCK_TIMEOUT_MIN=1
88
- STALE=$(find "$LOCK_FILE" -maxdepth 0 -mmin +${LOCK_TIMEOUT_MIN} 2>/dev/null)
89
- if [[ -n "$STALE" ]]; then
90
- rmdir "$LOCK_FILE" 2>/dev/null || true
91
- continue
92
- fi
93
- fi
94
-
95
- sleep 0.2
96
- done
97
-
98
- if [[ "$LOCK_ACQUIRED" == "false" ]]; then
99
- # Another instance is running, skip
100
- exit 0
101
- fi
102
-
103
- # NOTE: PROJECT_ROOT already detected at top of script (before any mkdir)
104
-
105
- # ============================================================================
106
- # CONFIGURATION
107
- # ============================================================================
108
-
109
- LOGS_DIR=".specweave/logs"
110
- DEBUG_LOG="$LOGS_DIR/hooks-debug.log"
111
-
112
- mkdir -p "$LOGS_DIR" 2>/dev/null || true
113
-
114
- # ============================================================================
115
- # PRECONDITIONS CHECK
116
- # ============================================================================
117
-
118
- echo "[$(date)] [GitHub] 🔗 GitHub sync hook fired" >> "$DEBUG_LOG" 2>/dev/null || true
119
-
120
- # Check if Node.js is available
121
- if ! command -v node &> /dev/null; then
122
- echo "[$(date)] [GitHub] ⚠️ Node.js not found, skipping GitHub sync" >> "$DEBUG_LOG" 2>/dev/null || true
123
- cat <<EOF
124
- {
125
- "continue": true
126
- }
127
- EOF
128
- exit 0
129
- fi
130
-
131
- # Find sync-spec-content CLI — check multiple locations
132
- SYNC_CLI=""
133
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
134
- # Derive package root: hooks/ → specweave-github/ → plugins/ → package root (3 levels up)
135
- _PKG_ROOT="$(cd "$SCRIPT_DIR/../../.." 2>/dev/null && pwd)"
136
- # Source resolve-package.sh for dynamic specweave path resolution
137
- RESOLVE_LIB="$SCRIPT_DIR/../../specweave/hooks/lib/resolve-package.sh"
138
- if [[ -f "$RESOLVE_LIB" ]]; then
139
- source "$RESOLVE_LIB"
140
- fi
141
- # 0. SPECWEAVE_PKG (set by hook infrastructure)
142
- [[ -n "${SPECWEAVE_PKG:-}" ]] && [[ -f "${SPECWEAVE_PKG}/dist/src/cli/commands/sync-spec-content.js" ]] && SYNC_CLI="${SPECWEAVE_PKG}/dist/src/cli/commands/sync-spec-content.js"
143
- # 1. Package root (derived from script location)
144
- [[ -z "$SYNC_CLI" ]] && [[ -f "${_PKG_ROOT}/dist/src/cli/commands/sync-spec-content.js" ]] && SYNC_CLI="${_PKG_ROOT}/dist/src/cli/commands/sync-spec-content.js"
145
- # 2. resolve-package.sh (dynamic resolution)
146
- [[ -z "$SYNC_CLI" ]] && SYNC_CLI=$(find_specweave_script "dist/src/cli/commands/sync-spec-content.js" 2>/dev/null)
147
- # 3. Legacy: PROJECT_ROOT/dist/
148
- [[ -z "$SYNC_CLI" ]] && [[ -f "$PROJECT_ROOT/dist/src/cli/commands/sync-spec-content.js" ]] && SYNC_CLI="$PROJECT_ROOT/dist/src/cli/commands/sync-spec-content.js"
149
-
150
- if [ -z "$SYNC_CLI" ]; then
151
- echo "[$(date)] [GitHub] ⚠️ sync-spec-content CLI not found at any known path, skipping sync" >> "$DEBUG_LOG" 2>/dev/null || true
152
- cat <<EOF
153
- {
154
- "continue": true
155
- }
156
- EOF
157
- exit 0
158
- fi
159
- echo "[$(date)] [GitHub] Using sync CLI: $SYNC_CLI" >> "$DEBUG_LOG" 2>/dev/null || true
160
-
161
- # Check for gh CLI
162
- if ! command -v gh &> /dev/null; then
163
- echo "[$(date)] [GitHub] ⚠️ GitHub CLI (gh) not found, skipping sync" >> "$DEBUG_LOG" 2>/dev/null || true
164
- cat <<EOF
165
- {
166
- "continue": true
167
- }
168
- EOF
169
- exit 0
170
- fi
171
-
172
- # ============================================================================
173
- # DETECT ALL SPECS (Multi-Spec Support)
174
- # ============================================================================
175
-
176
- # Strategy: Use multi-spec detector to find ALL specs referenced in current increment
177
-
178
- # 1. Detect current increment (temporary context)
179
- CURRENT_INCREMENT=$(ls -td .specweave/increments/*/ 2>/dev/null | xargs -n1 basename | grep -v "_backlog" | grep -v "_archive" | grep -v "_working" | head -1)
180
-
181
- if [ -z "$CURRENT_INCREMENT" ]; then
182
- echo "[$(date)] [GitHub] ℹ️ No active increment, checking for spec changes..." >> "$DEBUG_LOG" 2>/dev/null || true
183
- # Fall through to sync all changed specs
184
- fi
185
-
186
- # 2. Use TypeScript CLI to detect all specs — check multiple locations
187
- DETECT_CLI=""
188
- [[ -n "${SPECWEAVE_PKG:-}" ]] && [[ -f "${SPECWEAVE_PKG}/dist/src/cli/commands/detect-specs.js" ]] && DETECT_CLI="${SPECWEAVE_PKG}/dist/src/cli/commands/detect-specs.js"
189
- [[ -z "$DETECT_CLI" ]] && [[ -f "${_PKG_ROOT}/dist/src/cli/commands/detect-specs.js" ]] && DETECT_CLI="${_PKG_ROOT}/dist/src/cli/commands/detect-specs.js"
190
- [[ -z "$DETECT_CLI" ]] && DETECT_CLI=$(find_specweave_script "dist/src/cli/commands/detect-specs.js" 2>/dev/null)
191
- [[ -z "$DETECT_CLI" ]] && [[ -f "$PROJECT_ROOT/dist/src/cli/commands/detect-specs.js" ]] && DETECT_CLI="$PROJECT_ROOT/dist/src/cli/commands/detect-specs.js"
192
-
193
- if [ -n "$DETECT_CLI" ] && [ -f "$DETECT_CLI" ]; then
194
- echo "[$(date)] [GitHub] 🔍 Detecting all specs in increment $CURRENT_INCREMENT..." >> "$DEBUG_LOG" 2>/dev/null || true
195
-
196
- # Call detect-specs CLI and capture JSON output
197
- DETECTION_RESULT=$(node "$DETECT_CLI" 2>> "$DEBUG_LOG" || echo "{}")
198
-
199
- # Extract spec count
200
- SPEC_COUNT=$(echo "$DETECTION_RESULT" | node -e "const fs=require('fs'); const data=JSON.parse(fs.readFileSync(0,'utf-8')); console.log(data.specs?.length || 0)")
201
-
202
- echo "[$(date)] [GitHub] 📋 Detected $SPEC_COUNT spec(s)" >> "$DEBUG_LOG" 2>/dev/null || true
203
-
204
- # Store detection result for later use
205
- echo "$DETECTION_RESULT" > /tmp/specweave-detected-specs.json
206
- else
207
- echo "[$(date)] [GitHub] ⚠️ detect-specs CLI not found at any known path, falling back to git diff" >> "$DEBUG_LOG" 2>/dev/null || true
208
- SPEC_COUNT=0
209
- fi
210
-
211
- # ============================================================================
212
- # SYNC ALL DETECTED SPECS TO GITHUB (Multi-Spec Support)
213
- # ============================================================================
214
-
215
- if [ -f /tmp/specweave-detected-specs.json ] && [ "$SPEC_COUNT" -gt 0 ]; then
216
- # Multi-spec sync: Loop through all detected specs
217
- echo "[$(date)] [GitHub] 🔄 Syncing $SPEC_COUNT spec(s) to GitHub..." >> "$DEBUG_LOG" 2>/dev/null || true
218
-
219
- # Extract spec paths using Node.js
220
- SPEC_PATHS=$(node -e "
221
- const fs = require('fs');
222
- const data = JSON.parse(fs.readFileSync('/tmp/specweave-detected-specs.json', 'utf-8'));
223
- const syncable = data.specs.filter(s => s.syncEnabled && s.project !== '_parent');
224
- syncable.forEach(s => console.log(s.path));
225
- " 2>> "$DEBUG_LOG")
226
-
227
- # Count syncable specs
228
- SYNCABLE_COUNT=$(echo "$SPEC_PATHS" | grep -v '^$' | wc -l | tr -d ' ')
229
-
230
- if [ "$SYNCABLE_COUNT" -gt 0 ]; then
231
- echo "[$(date)] [GitHub] 📋 Syncing $SYNCABLE_COUNT syncable spec(s) (excluding _parent)" >> "$DEBUG_LOG" 2>/dev/null || true
232
-
233
- # Sync each spec
234
- echo "$SPEC_PATHS" | while read -r SPEC_FILE; do
235
- if [ -n "$SPEC_FILE" ] && [ -f "$SPEC_FILE" ]; then
236
- # Extract project and spec ID from path
237
- SPEC_NAME=$(basename "$SPEC_FILE" .md)
238
- PROJECT=$(basename "$(dirname "$SPEC_FILE")")
239
-
240
- echo "[$(date)] [GitHub] 🔄 Syncing $PROJECT/$SPEC_NAME..." >> "$DEBUG_LOG" 2>/dev/null || true
241
-
242
- (cd "$PROJECT_ROOT" && node "$SYNC_CLI" --spec "$SPEC_FILE" --provider github) 2>&1 | tee -a "$DEBUG_LOG" >/dev/null || {
243
- echo "[$(date)] [GitHub] ⚠️ Spec sync failed for $PROJECT/$SPEC_NAME (non-blocking)" >> "$DEBUG_LOG" 2>/dev/null || true
244
- }
245
-
246
- echo "[$(date)] [GitHub] ✅ Synced $PROJECT/$SPEC_NAME" >> "$DEBUG_LOG" 2>/dev/null || true
247
- fi
248
- done
249
-
250
- echo "[$(date)] [GitHub] ✅ Multi-spec sync complete ($SYNCABLE_COUNT synced)" >> "$DEBUG_LOG" 2>/dev/null || true
251
- else
252
- echo "[$(date)] [GitHub] ℹ️ No syncable specs (all specs are _parent or syncEnabled=false)" >> "$DEBUG_LOG" 2>/dev/null || true
253
- fi
254
-
255
- # Cleanup temp file
256
- rm -f /tmp/specweave-detected-specs.json 2>/dev/null || true
257
- else
258
- # Fallback: Sync all modified specs (check git diff)
259
- echo "[$(date)] [GitHub] 🔄 Checking for modified specs..." >> "$DEBUG_LOG" 2>/dev/null || true
260
-
261
- MODIFIED_SPECS=$(git diff --name-only HEAD .specweave/docs/internal/specs/**/*.md 2>/dev/null || echo "")
262
-
263
- if [ -n "$MODIFIED_SPECS" ]; then
264
- echo "[$(date)] [GitHub] 📝 Found modified specs:" >> "$DEBUG_LOG" 2>/dev/null || true
265
- echo "$MODIFIED_SPECS" >> "$DEBUG_LOG" 2>/dev/null || true
266
-
267
- # Sync each modified spec
268
- echo "$MODIFIED_SPECS" | while read -r SPEC_FILE; do
269
- if [ -n "$SPEC_FILE" ] && [ -f "$SPEC_FILE" ]; then
270
- echo "[$(date)] [GitHub] 🔄 Syncing $SPEC_FILE..." >> "$DEBUG_LOG" 2>/dev/null || true
271
- (cd "$PROJECT_ROOT" && node "$SYNC_CLI" --spec "$SPEC_FILE" --provider github) 2>&1 | tee -a "$DEBUG_LOG" >/dev/null || true
272
- fi
273
- done
274
-
275
- echo "[$(date)] [GitHub] ✅ Batch spec sync complete" >> "$DEBUG_LOG" 2>/dev/null || true
276
- else
277
- echo "[$(date)] [GitHub] ℹ️ No modified specs found, skipping sync" >> "$DEBUG_LOG" 2>/dev/null || true
278
- fi
279
- fi
280
-
281
- # ============================================================================
282
- # EPIC GITHUB ISSUE SYNC (DEPRECATED v0.24.0+)
283
- # ============================================================================
284
- #
285
- # ⚠️ DEPRECATED: SpecWeave now syncs ONLY at User Story level.
286
- #
287
- # Feature/Epic-level issues are no longer updated.
288
- # Use /sw-github:sync instead to sync User Story issues.
289
- #
290
- # To re-enable (NOT recommended):
291
- # export SPECWEAVE_ENABLE_EPIC_SYNC=true
292
- #
293
- # @see .specweave/increments/0047-us-task-linkage/reports/GITHUB-TITLE-FORMAT-FIX-PLAN.md
294
- # ============================================================================
295
-
296
- if [ "$SPECWEAVE_ENABLE_EPIC_SYNC" = "true" ]; then
297
- echo "[$(date)] [GitHub] 🔄 Checking for Epic GitHub issue update (DEPRECATED)..." >> "$DEBUG_LOG" 2>/dev/null || true
298
-
299
- # Find active increment ID
300
- ACTIVE_INCREMENT=$(ls -t .specweave/increments/ | grep -v '^\.' | while read inc; do
301
- if [ -f ".specweave/increments/$inc/metadata.json" ]; then
302
- STATUS=$(grep -o '"status"[[:space:]]*:[[:space:]]*"[^"]*"' ".specweave/increments/$inc/metadata.json" 2>/dev/null | sed 's/.*"\([^"]*\)".*/\1/' || true)
303
- if [ "$STATUS" = "active" ]; then
304
- echo "$inc"
305
- break
306
- fi
307
- fi
308
- done | head -1)
309
-
310
- if [ -n "$ACTIVE_INCREMENT" ]; then
311
- echo "[$(date)] [GitHub] 🎯 Active increment: $ACTIVE_INCREMENT" >> "$DEBUG_LOG" 2>/dev/null || true
312
-
313
- # Run Epic sync script (silently, errors logged to debug log)
314
- if [ -f "$PROJECT_ROOT/scripts/update-epic-github-issue.sh" ]; then
315
- echo "[$(date)] [GitHub] 🚀 Updating Epic GitHub issue (DEPRECATED)..." >> "$DEBUG_LOG" 2>/dev/null || true
316
- "$PROJECT_ROOT/scripts/update-epic-github-issue.sh" "$ACTIVE_INCREMENT" >> "$DEBUG_LOG" 2>&1 || true
317
- echo "[$(date)] [GitHub] ⚠️ Epic sync is deprecated. Use /sw-github:sync instead." >> "$DEBUG_LOG" 2>/dev/null || true
318
- else
319
- echo "[$(date)] [GitHub] ⚠️ Epic sync script not found, skipping" >> "$DEBUG_LOG" 2>/dev/null || true
320
- fi
321
- else
322
- echo "[$(date)] [GitHub] ℹ️ No active increment found, skipping Epic sync" >> "$DEBUG_LOG" 2>/dev/null || true
323
- fi
324
- else
325
- echo "[$(date)] [GitHub] ℹ️ Epic sync disabled (sync at User Story level only)" >> "$DEBUG_LOG" 2>/dev/null || true
326
- fi
327
-
328
- # ============================================================================
329
- # CIRCUIT BREAKER UPDATE
330
- # ============================================================================
331
- # Reset circuit breaker on successful completion (all errors are caught above)
332
- echo "0" > "$CIRCUIT_BREAKER_FILE" 2>/dev/null || true
333
-
334
- # ============================================================================
335
- # OUTPUT TO CLAUDE
336
- # ============================================================================
337
-
338
- cat <<EOF
339
- {
340
- "continue": true
341
- }
342
- EOF
343
-
344
- # ALWAYS exit 0 - NEVER let hook errors crash Claude Code
345
- exit 0
@@ -1,180 +0,0 @@
1
- #!/bin/bash
2
-
3
- # SpecWeave JIRA Sync Hook
4
- # Runs after task completion to sync progress to JIRA Issues
5
- #
6
- # This hook is part of the specweave-jira plugin and handles:
7
- # - Syncing task completion state to JIRA issues
8
- # - Updating JIRA issue status based on increment progress
9
- #
10
- # Dependencies:
11
- # - Node.js for running sync scripts
12
- # - jq for JSON parsing
13
- # - metadata.json must have .jira.issue field
14
- # - JIRA API credentials in .env
15
-
16
- set +e # EMERGENCY FIX: Prevents Claude Code crashes
17
-
18
- # EMERGENCY KILL SWITCH
19
- if [[ "${SPECWEAVE_DISABLE_HOOKS:-0}" == "1" ]]; then
20
- exit 0
21
- fi
22
-
23
- # ============================================================================
24
- # PROJECT ROOT DETECTION (CRITICAL - must NOT fallback to pwd!)
25
- # ============================================================================
26
-
27
- # Find project root by searching upward for .specweave/ directory
28
- find_project_root() {
29
- local dir="$1"
30
- while [ "$dir" != "/" ]; do
31
- if [ -f "$dir/.specweave/config.json" ]; then
32
- echo "$dir"
33
- return 0
34
- fi
35
- dir="$(dirname "$dir")"
36
- done
37
- return 1 # NOT FOUND - do NOT fallback to pwd (prevents .specweave pollution)
38
- }
39
-
40
- PROJECT_ROOT="$(find_project_root "$(pwd)")"
41
- if [[ -z "$PROJECT_ROOT" ]]; then
42
- # NOT a SpecWeave project - exit silently without creating any files
43
- exit 0
44
- fi
45
- cd "$PROJECT_ROOT" 2>/dev/null || exit 0
46
-
47
- # ============================================================================
48
- # CONFIGURATION
49
- # ============================================================================
50
-
51
- LOGS_DIR=".specweave/logs"
52
- DEBUG_LOG="$LOGS_DIR/hooks-debug.log"
53
-
54
- mkdir -p "$LOGS_DIR" 2>/dev/null || true
55
-
56
- # ============================================================================
57
- # PRECONDITIONS CHECK
58
- # ============================================================================
59
-
60
- echo "[$(date)] [JIRA] 🔗 JIRA sync hook fired" >> "$DEBUG_LOG" 2>/dev/null || true
61
-
62
- # Detect current increment
63
- CURRENT_INCREMENT=$(ls -td .specweave/increments/*/ 2>/dev/null | xargs -n1 basename | grep -v "_backlog" | grep -v "_archive" | grep -v "_working" | head -1)
64
-
65
- if [ -z "$CURRENT_INCREMENT" ]; then
66
- echo "[$(date)] [JIRA] ℹ️ No active increment, skipping JIRA sync" >> "$DEBUG_LOG" 2>/dev/null || true
67
- cat <<EOF
68
- {
69
- "continue": true
70
- }
71
- EOF
72
- exit 0
73
- fi
74
-
75
- # Check for metadata.json
76
- METADATA_FILE=".specweave/increments/$CURRENT_INCREMENT/metadata.json"
77
-
78
- if [ ! -f "$METADATA_FILE" ]; then
79
- echo "[$(date)] [JIRA] ℹ️ No metadata.json for $CURRENT_INCREMENT, skipping JIRA sync" >> "$DEBUG_LOG" 2>/dev/null || true
80
- cat <<EOF
81
- {
82
- "continue": true
83
- }
84
- EOF
85
- exit 0
86
- fi
87
-
88
- # Check for JIRA issue link
89
- if ! command -v jq &> /dev/null; then
90
- echo "[$(date)] [JIRA] ⚠️ jq not found, skipping JIRA sync" >> "$DEBUG_LOG" 2>/dev/null || true
91
- cat <<EOF
92
- {
93
- "continue": true
94
- }
95
- EOF
96
- exit 0
97
- fi
98
-
99
- # Read JIRA issue key: canonical path first, then legacy fallbacks
100
- JIRA_ISSUE=$(jq -r '.external_sync.jira.issueKey // .jira.issueKey // .jira.issue // empty' "$METADATA_FILE" 2>/dev/null)
101
-
102
- if [ -z "$JIRA_ISSUE" ]; then
103
- echo "[$(date)] [JIRA] ℹ️ No JIRA issue linked to $CURRENT_INCREMENT, skipping sync" >> "$DEBUG_LOG" 2>/dev/null || true
104
- cat <<EOF
105
- {
106
- "continue": true
107
- }
108
- EOF
109
- exit 0
110
- fi
111
-
112
- # Check for Node.js
113
- if ! command -v node &> /dev/null; then
114
- echo "[$(date)] [JIRA] ⚠️ Node.js not found, skipping JIRA sync" >> "$DEBUG_LOG" 2>/dev/null || true
115
- cat <<EOF
116
- {
117
- "continue": true
118
- }
119
- EOF
120
- exit 0
121
- fi
122
-
123
- # Check for JIRA sync script
124
- if [ ! -f "dist/commands/jira-sync.js" ]; then
125
- echo "[$(date)] [JIRA] ⚠️ jira-sync.js not found, skipping JIRA sync" >> "$DEBUG_LOG" 2>/dev/null || true
126
- cat <<EOF
127
- {
128
- "continue": true
129
- }
130
- EOF
131
- exit 0
132
- fi
133
-
134
- # ============================================================================
135
- # JIRA SYNC LOGIC
136
- # ============================================================================
137
-
138
- echo "[$(date)] [JIRA] 🔄 Syncing to JIRA issue $JIRA_ISSUE" >> "$DEBUG_LOG" 2>/dev/null || true
139
-
140
- # Run JIRA sync command (non-blocking)
141
- node dist/commands/jira-sync.js "$CURRENT_INCREMENT" 2>&1 | tee -a "$DEBUG_LOG" >/dev/null || {
142
- echo "[$(date)] [JIRA] ⚠️ Failed to sync to JIRA (non-blocking)" >> "$DEBUG_LOG" 2>/dev/null || true
143
- }
144
-
145
- echo "[$(date)] [JIRA] ✅ JIRA sync complete" >> "$DEBUG_LOG" 2>/dev/null || true
146
-
147
- # ============================================================================
148
- # SPEC COMMIT SYNC (NEW!)
149
- # ============================================================================
150
-
151
- echo "[$(date)] [JIRA] 🔗 Checking for spec commit sync..." >> "$DEBUG_LOG" 2>/dev/null || true
152
-
153
- # Call TypeScript CLI to sync commits
154
- if command -v node &> /dev/null && [ -f "$PROJECT_ROOT/dist/cli/commands/sync-spec-commits.js" ]; then
155
- echo "[$(date)] [JIRA] 🚀 Running spec commit sync..." >> "$DEBUG_LOG" 2>/dev/null || true
156
-
157
- node "$PROJECT_ROOT/dist/cli/commands/sync-spec-commits.js" \
158
- --increment "$PROJECT_ROOT/.specweave/increments/$CURRENT_INCREMENT" \
159
- --provider jira \
160
- 2>&1 | tee -a "$DEBUG_LOG" >/dev/null || {
161
- echo "[$(date)] [JIRA] ⚠️ Spec commit sync failed (non-blocking)" >> "$DEBUG_LOG" 2>/dev/null || true
162
- }
163
-
164
- echo "[$(date)] [JIRA] ✅ Spec commit sync complete" >> "$DEBUG_LOG" 2>/dev/null || true
165
- else
166
- echo "[$(date)] [JIRA] ℹ️ Spec commit sync not available (node or script not found)" >> "$DEBUG_LOG" 2>/dev/null || true
167
- fi
168
-
169
- # ============================================================================
170
- # OUTPUT TO CLAUDE
171
- # ============================================================================
172
-
173
- cat <<EOF
174
- {
175
- "continue": true
176
- }
177
- EOF
178
-
179
- # ALWAYS exit 0 - NEVER let hook errors crash Claude Code
180
- exit 0
@@ -1,52 +0,0 @@
1
- #!/bin/bash
2
- # check-provider-enabled.sh - Shared provider config detection for SpecWeave hooks
3
- #
4
- # Supports ALL 3 config formats:
5
- # 1. PROFILES: sync.profiles.*.provider == "github" + canUpdateExternalItems
6
- # 2. LEGACY DIRECT: sync.github.enabled == true
7
- # 3. LEGACY PROVIDER: sync.provider == "github" + sync.enabled == true
8
- #
9
- # Usage:
10
- # source "path/to/check-provider-enabled.sh"
11
- # if check_provider_enabled "$CONFIG_PATH" "github"; then
12
- # echo "GitHub enabled"
13
- # fi
14
- #
15
- # Returns: 0 = enabled, 1 = disabled
16
- # Reference: github-sync-handler.sh:72-107 (canonical implementation)
17
-
18
- check_provider_enabled() {
19
- local config_file="$1"
20
- local provider="$2"
21
-
22
- [[ ! -f "$config_file" ]] && return 1
23
-
24
- # Method 1: PROFILES format (sync.profiles with provider field)
25
- if grep -q '"profiles"[[:space:]]*:' "$config_file" 2>/dev/null; then
26
- if grep -q "\"provider\"[[:space:]]*:[[:space:]]*\"$provider\"" "$config_file" 2>/dev/null; then
27
- # Also check canUpdateExternalItems (required for sync)
28
- if grep -q '"canUpdateExternalItems"[[:space:]]*:[[:space:]]*true' "$config_file" 2>/dev/null; then
29
- return 0
30
- fi
31
- fi
32
- fi
33
-
34
- # Method 2: LEGACY DIRECT (sync.{provider}.enabled: true)
35
- if grep -q "\"$provider\"[[:space:]]*:" "$config_file" 2>/dev/null; then
36
- if grep -A5 "\"$provider\"[[:space:]]*:" "$config_file" 2>/dev/null | grep -q '"enabled"[[:space:]]*:[[:space:]]*true'; then
37
- return 0
38
- fi
39
- fi
40
-
41
- # Method 3: LEGACY PROVIDER (sync.provider: "provider" + sync.enabled: true)
42
- # Only check if no profiles section (pure legacy config)
43
- if ! grep -q '"profiles"[[:space:]]*:' "$config_file" 2>/dev/null; then
44
- if grep -q "\"provider\"[[:space:]]*:[[:space:]]*\"$provider\"" "$config_file" 2>/dev/null; then
45
- if grep -q '"sync"' "$config_file" && grep -A2 '"sync"' "$config_file" | grep -q '"enabled"[[:space:]]*:[[:space:]]*true'; then
46
- return 0
47
- fi
48
- fi
49
- fi
50
-
51
- return 1
52
- }
@@ -1,81 +0,0 @@
1
- #!/bin/bash
2
- # enqueue.sh - Add event to queue (v1.0.148 - simplified)
3
- # Usage: enqueue.sh <event_type> <event_data>
4
- #
5
- # v1.0.148: Writes to pending.jsonl (processed by stop-sync.sh at session end)
6
- # Events are coalesced (deduplicated) by type+data hash within 10 second window.
7
- #
8
- # IMPORTANT: This script must be fast (<5ms) and never crash
9
- set +e
10
-
11
- [[ "${SPECWEAVE_DISABLE_HOOKS:-0}" == "1" ]] && exit 0
12
-
13
- EVENT_TYPE="${1:-unknown}"
14
- EVENT_DATA="${2:-}"
15
-
16
- # Find project root
17
- PROJECT_ROOT="$PWD"
18
- while [[ "$PROJECT_ROOT" != "/" ]] && [[ ! -f "$PROJECT_ROOT/.specweave/config.json" ]]; do
19
- PROJECT_ROOT=$(dirname "$PROJECT_ROOT")
20
- done
21
- [[ ! -f "$PROJECT_ROOT/.specweave/config.json" ]] && exit 0
22
-
23
- QUEUE_DIR="$PROJECT_ROOT/.specweave/state/event-queue"
24
- PENDING_FILE="$QUEUE_DIR/pending.jsonl"
25
- mkdir -p "$QUEUE_DIR" 2>/dev/null || exit 0
26
-
27
- # ============================================================================
28
- # DEDUPLICATION: Skip if same event within 10s window
29
- # ============================================================================
30
-
31
- # Cross-platform md5 (works on macOS, Linux, Windows Git Bash)
32
- if command -v md5 >/dev/null 2>&1; then
33
- HASH=$(echo "${EVENT_TYPE}:${EVENT_DATA}" | md5 | cut -c1-8)
34
- elif command -v md5sum >/dev/null 2>&1; then
35
- HASH=$(echo "${EVENT_TYPE}:${EVENT_DATA}" | md5sum | cut -c1-8)
36
- else
37
- # Fallback: simple hash from type and data
38
- HASH=$(printf "%s" "${EVENT_TYPE}:${EVENT_DATA}" | cksum | cut -d' ' -f1)
39
- fi
40
-
41
- DEDUP_FILE="$QUEUE_DIR/.dedup-$HASH"
42
- DEDUP_TTL=10 # 10 second deduplication window
43
-
44
- # Coalescing check: skip if same event within TTL
45
- if [[ -f "$DEDUP_FILE" ]]; then
46
- if [[ "$(uname)" == "Darwin" ]]; then
47
- AGE=$(($(date +%s) - $(stat -f %m "$DEDUP_FILE" 2>/dev/null || echo 0)))
48
- else
49
- AGE=$(($(date +%s) - $(stat -c %Y "$DEDUP_FILE" 2>/dev/null || echo 0)))
50
- fi
51
- [[ $AGE -lt $DEDUP_TTL ]] && exit 0
52
- fi
53
- touch "$DEDUP_FILE"
54
-
55
- # ============================================================================
56
- # ENQUEUE: Append to pending.jsonl (atomic via temp file)
57
- # ============================================================================
58
-
59
- TIMESTAMP=$(date -u +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date +%Y-%m-%dT%H:%M:%SZ)
60
- EVENT_JSON="{\"type\":\"$EVENT_TYPE\",\"data\":\"$EVENT_DATA\",\"ts\":\"$TIMESTAMP\",\"hash\":\"$HASH\"}"
61
-
62
- # Atomic append: write to temp, then append and rename
63
- # This prevents partial writes if process is killed
64
- TMP_FILE="$QUEUE_DIR/.pending-$$.tmp"
65
- {
66
- [[ -f "$PENDING_FILE" ]] && cat "$PENDING_FILE"
67
- echo "$EVENT_JSON"
68
- } > "$TMP_FILE" 2>/dev/null
69
-
70
- mv "$TMP_FILE" "$PENDING_FILE" 2>/dev/null || {
71
- # Fallback: direct append (less safe but usually works)
72
- echo "$EVENT_JSON" >> "$PENDING_FILE" 2>/dev/null
73
- rm -f "$TMP_FILE" 2>/dev/null
74
- }
75
-
76
- # ============================================================================
77
- # CLEANUP: Remove old dedup files (>1 minute) - non-blocking background
78
- # ============================================================================
79
-
80
- find "$QUEUE_DIR" -name ".dedup-*" -mmin +1 -delete 2>/dev/null &
81
- exit 0