specweave 0.30.19 → 0.32.2

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 (242) hide show
  1. package/CLAUDE.md +176 -2
  2. package/README.md +22 -0
  3. package/bin/specweave.js +18 -1
  4. package/dist/src/cli/commands/cache.d.ts +17 -0
  5. package/dist/src/cli/commands/cache.d.ts.map +1 -0
  6. package/dist/src/cli/commands/cache.js +126 -0
  7. package/dist/src/cli/commands/cache.js.map +1 -0
  8. package/dist/src/cli/commands/init.js +1 -1
  9. package/dist/src/cli/commands/init.js.map +1 -1
  10. package/dist/src/cli/commands/plan/increment-detector.js +2 -2
  11. package/dist/src/cli/commands/plan/increment-detector.js.map +1 -1
  12. package/dist/src/cli/commands/sync-spec-commits.js +1 -1
  13. package/dist/src/cli/commands/sync-spec-commits.js.map +1 -1
  14. package/dist/src/cli/commands/sync-specs.js +2 -2
  15. package/dist/src/cli/commands/sync-specs.js.map +1 -1
  16. package/dist/src/cli/helpers/github/increment-profile-selector.js +1 -1
  17. package/dist/src/cli/helpers/github/increment-profile-selector.js.map +1 -1
  18. package/dist/src/cli/workers/living-docs-worker.js +66 -1
  19. package/dist/src/cli/workers/living-docs-worker.js.map +1 -1
  20. package/dist/src/config/types.d.ts +203 -1208
  21. package/dist/src/config/types.d.ts.map +1 -1
  22. package/dist/src/core/discrepancy/increment-generator.d.ts.map +1 -1
  23. package/dist/src/core/discrepancy/increment-generator.js +5 -2
  24. package/dist/src/core/discrepancy/increment-generator.js.map +1 -1
  25. package/dist/src/core/external-tools/external-items-counter.d.ts +62 -0
  26. package/dist/src/core/external-tools/external-items-counter.d.ts.map +1 -0
  27. package/dist/src/core/external-tools/external-items-counter.js +206 -0
  28. package/dist/src/core/external-tools/external-items-counter.js.map +1 -0
  29. package/dist/src/core/external-tools/external-items-display.d.ts +39 -0
  30. package/dist/src/core/external-tools/external-items-display.d.ts.map +1 -0
  31. package/dist/src/core/external-tools/external-items-display.js +185 -0
  32. package/dist/src/core/external-tools/external-items-display.js.map +1 -0
  33. package/dist/src/core/external-tools/index.d.ts +8 -0
  34. package/dist/src/core/external-tools/index.d.ts.map +1 -0
  35. package/dist/src/core/external-tools/index.js +8 -0
  36. package/dist/src/core/external-tools/index.js.map +1 -0
  37. package/dist/src/core/external-tools/providers/ado-items-adapter.d.ts +39 -0
  38. package/dist/src/core/external-tools/providers/ado-items-adapter.d.ts.map +1 -0
  39. package/dist/src/core/external-tools/providers/ado-items-adapter.js +188 -0
  40. package/dist/src/core/external-tools/providers/ado-items-adapter.js.map +1 -0
  41. package/dist/src/core/external-tools/providers/github-items-adapter.d.ts +38 -0
  42. package/dist/src/core/external-tools/providers/github-items-adapter.d.ts.map +1 -0
  43. package/dist/src/core/external-tools/providers/github-items-adapter.js +136 -0
  44. package/dist/src/core/external-tools/providers/github-items-adapter.js.map +1 -0
  45. package/dist/src/core/external-tools/providers/index.d.ts +7 -0
  46. package/dist/src/core/external-tools/providers/index.d.ts.map +1 -0
  47. package/dist/src/core/external-tools/providers/index.js +7 -0
  48. package/dist/src/core/external-tools/providers/index.js.map +1 -0
  49. package/dist/src/core/external-tools/providers/jira-items-adapter.d.ts +42 -0
  50. package/dist/src/core/external-tools/providers/jira-items-adapter.d.ts.map +1 -0
  51. package/dist/src/core/external-tools/providers/jira-items-adapter.js +153 -0
  52. package/dist/src/core/external-tools/providers/jira-items-adapter.js.map +1 -0
  53. package/dist/src/core/external-tools/types.d.ts +78 -0
  54. package/dist/src/core/external-tools/types.d.ts.map +1 -0
  55. package/dist/src/core/external-tools/types.js +19 -0
  56. package/dist/src/core/external-tools/types.js.map +1 -0
  57. package/dist/src/core/increment/duplicate-detector.js +2 -2
  58. package/dist/src/core/increment/duplicate-detector.js.map +1 -1
  59. package/dist/src/core/increment/increment-archiver.d.ts +24 -0
  60. package/dist/src/core/increment/increment-archiver.d.ts.map +1 -1
  61. package/dist/src/core/increment/increment-archiver.js +59 -2
  62. package/dist/src/core/increment/increment-archiver.js.map +1 -1
  63. package/dist/src/core/increment/increment-status.js +2 -2
  64. package/dist/src/core/increment/increment-status.js.map +1 -1
  65. package/dist/src/core/increment/increment-utils.d.ts +98 -37
  66. package/dist/src/core/increment/increment-utils.d.ts.map +1 -1
  67. package/dist/src/core/increment/increment-utils.js +119 -68
  68. package/dist/src/core/increment/increment-utils.js.map +1 -1
  69. package/dist/src/core/increment/metadata-validator.js +1 -1
  70. package/dist/src/core/increment/metadata-validator.js.map +1 -1
  71. package/dist/src/core/increment/status-change-sync-trigger.d.ts.map +1 -1
  72. package/dist/src/core/increment/status-change-sync-trigger.js +4 -0
  73. package/dist/src/core/increment/status-change-sync-trigger.js.map +1 -1
  74. package/dist/src/core/living-docs/feature-id-manager.js +1 -1
  75. package/dist/src/core/living-docs/feature-id-manager.js.map +1 -1
  76. package/dist/src/core/living-docs/hierarchy-mapper.js +3 -3
  77. package/dist/src/core/living-docs/hierarchy-mapper.js.map +1 -1
  78. package/dist/src/core/living-docs/intelligent-analyzer/architecture-generator.d.ts +18 -0
  79. package/dist/src/core/living-docs/intelligent-analyzer/architecture-generator.d.ts.map +1 -0
  80. package/dist/src/core/living-docs/intelligent-analyzer/architecture-generator.js +247 -0
  81. package/dist/src/core/living-docs/intelligent-analyzer/architecture-generator.js.map +1 -0
  82. package/dist/src/core/living-docs/intelligent-analyzer/deep-repo-analyzer.d.ts +15 -0
  83. package/dist/src/core/living-docs/intelligent-analyzer/deep-repo-analyzer.d.ts.map +1 -0
  84. package/dist/src/core/living-docs/intelligent-analyzer/deep-repo-analyzer.js +138 -0
  85. package/dist/src/core/living-docs/intelligent-analyzer/deep-repo-analyzer.js.map +1 -0
  86. package/dist/src/core/living-docs/intelligent-analyzer/file-sampler.d.ts +24 -0
  87. package/dist/src/core/living-docs/intelligent-analyzer/file-sampler.d.ts.map +1 -0
  88. package/dist/src/core/living-docs/intelligent-analyzer/file-sampler.js +198 -0
  89. package/dist/src/core/living-docs/intelligent-analyzer/file-sampler.js.map +1 -0
  90. package/dist/src/core/living-docs/intelligent-analyzer/inconsistency-detector.d.ts +17 -0
  91. package/dist/src/core/living-docs/intelligent-analyzer/inconsistency-detector.d.ts.map +1 -0
  92. package/dist/src/core/living-docs/intelligent-analyzer/inconsistency-detector.js +241 -0
  93. package/dist/src/core/living-docs/intelligent-analyzer/inconsistency-detector.js.map +1 -0
  94. package/dist/src/core/living-docs/intelligent-analyzer/index.d.ts +28 -0
  95. package/dist/src/core/living-docs/intelligent-analyzer/index.d.ts.map +1 -0
  96. package/dist/src/core/living-docs/intelligent-analyzer/index.js +197 -0
  97. package/dist/src/core/living-docs/intelligent-analyzer/index.js.map +1 -0
  98. package/dist/src/core/living-docs/intelligent-analyzer/organization-synthesizer.d.ts +18 -0
  99. package/dist/src/core/living-docs/intelligent-analyzer/organization-synthesizer.d.ts.map +1 -0
  100. package/dist/src/core/living-docs/intelligent-analyzer/organization-synthesizer.js +154 -0
  101. package/dist/src/core/living-docs/intelligent-analyzer/organization-synthesizer.js.map +1 -0
  102. package/dist/src/core/living-docs/intelligent-analyzer/strategy-generator.d.ts +42 -0
  103. package/dist/src/core/living-docs/intelligent-analyzer/strategy-generator.d.ts.map +1 -0
  104. package/dist/src/core/living-docs/intelligent-analyzer/strategy-generator.js +343 -0
  105. package/dist/src/core/living-docs/intelligent-analyzer/strategy-generator.js.map +1 -0
  106. package/dist/src/core/living-docs/intelligent-analyzer/types.d.ts +146 -0
  107. package/dist/src/core/living-docs/intelligent-analyzer/types.d.ts.map +1 -0
  108. package/dist/src/core/living-docs/intelligent-analyzer/types.js +7 -0
  109. package/dist/src/core/living-docs/intelligent-analyzer/types.js.map +1 -0
  110. package/dist/src/core/living-docs/living-docs-sync.d.ts +5 -0
  111. package/dist/src/core/living-docs/living-docs-sync.d.ts.map +1 -1
  112. package/dist/src/core/living-docs/living-docs-sync.js +36 -2
  113. package/dist/src/core/living-docs/living-docs-sync.js.map +1 -1
  114. package/dist/src/core/llm/providers/azure-openai-provider.d.ts.map +1 -1
  115. package/dist/src/core/llm/providers/azure-openai-provider.js +1 -0
  116. package/dist/src/core/llm/providers/azure-openai-provider.js.map +1 -1
  117. package/dist/src/core/llm/providers/bedrock-provider.d.ts.map +1 -1
  118. package/dist/src/core/llm/providers/bedrock-provider.js +2 -0
  119. package/dist/src/core/llm/providers/bedrock-provider.js.map +1 -1
  120. package/dist/src/core/llm/providers/openai-provider.d.ts.map +1 -1
  121. package/dist/src/core/llm/providers/openai-provider.js +1 -0
  122. package/dist/src/core/llm/providers/openai-provider.js.map +1 -1
  123. package/dist/src/core/llm/providers/vertex-ai-provider.d.ts.map +1 -1
  124. package/dist/src/core/llm/providers/vertex-ai-provider.js +1 -0
  125. package/dist/src/core/llm/providers/vertex-ai-provider.js.map +1 -1
  126. package/dist/src/core/sync/spec-increment-mapper.js +3 -3
  127. package/dist/src/core/sync/spec-increment-mapper.js.map +1 -1
  128. package/dist/src/importers/item-converter.d.ts +25 -0
  129. package/dist/src/importers/item-converter.d.ts.map +1 -1
  130. package/dist/src/importers/item-converter.js +135 -5
  131. package/dist/src/importers/item-converter.js.map +1 -1
  132. package/dist/src/init/architecture/types.d.ts +33 -140
  133. package/dist/src/init/architecture/types.d.ts.map +1 -1
  134. package/dist/src/init/compliance/types.d.ts +30 -27
  135. package/dist/src/init/compliance/types.d.ts.map +1 -1
  136. package/dist/src/init/repo/types.d.ts +11 -34
  137. package/dist/src/init/repo/types.d.ts.map +1 -1
  138. package/dist/src/init/research/src/config/types.d.ts +15 -82
  139. package/dist/src/init/research/src/config/types.d.ts.map +1 -1
  140. package/dist/src/init/research/types.d.ts +38 -93
  141. package/dist/src/init/research/types.d.ts.map +1 -1
  142. package/dist/src/init/team/types.d.ts +4 -42
  143. package/dist/src/init/team/types.d.ts.map +1 -1
  144. package/dist/src/types/dashboard-cache.d.ts +181 -0
  145. package/dist/src/types/dashboard-cache.d.ts.map +1 -0
  146. package/dist/src/types/dashboard-cache.js +65 -0
  147. package/dist/src/types/dashboard-cache.js.map +1 -0
  148. package/dist/src/utils/docs-validator.d.ts +131 -0
  149. package/dist/src/utils/docs-validator.d.ts.map +1 -0
  150. package/dist/src/utils/docs-validator.js +529 -0
  151. package/dist/src/utils/docs-validator.js.map +1 -0
  152. package/dist/src/utils/feature-id-collision.js +1 -1
  153. package/dist/src/utils/feature-id-collision.js.map +1 -1
  154. package/dist/src/utils/html-to-mdx.d.ts +1 -0
  155. package/dist/src/utils/html-to-mdx.d.ts.map +1 -1
  156. package/dist/src/utils/html-to-mdx.js +43 -5
  157. package/dist/src/utils/html-to-mdx.js.map +1 -1
  158. package/package.json +1 -5
  159. package/plugins/specweave/agents/pm/AGENT.md +10 -7
  160. package/plugins/specweave/commands/specweave-archive-features.md +5 -7
  161. package/plugins/specweave/commands/specweave-archive.md +2 -1
  162. package/plugins/specweave/commands/specweave-do.md +35 -1
  163. package/plugins/specweave/commands/specweave-done.md +96 -0
  164. package/plugins/specweave/commands/specweave-external.md +150 -0
  165. package/plugins/specweave/commands/specweave-import-external.md +45 -18
  166. package/plugins/specweave/commands/specweave-increment.md +331 -33
  167. package/plugins/specweave/commands/specweave-jobs.md +2 -2
  168. package/plugins/specweave/commands/specweave-progress.md +4 -4
  169. package/plugins/specweave/commands/specweave-restore-feature.md +5 -4
  170. package/plugins/specweave/commands/specweave-sync-docs.md +1 -1
  171. package/plugins/specweave/commands/specweave-sync-specs.md +216 -322
  172. package/plugins/specweave/commands/specweave-validate-features.md +13 -8
  173. package/plugins/specweave/hooks/docs-changed.sh.backup +79 -0
  174. package/plugins/specweave/hooks/hooks.json +33 -4
  175. package/plugins/specweave/hooks/human-input-required.sh.backup +75 -0
  176. package/plugins/specweave/hooks/lib/common-setup.sh +375 -0
  177. package/plugins/specweave/hooks/lib/crash-prevention.sh +336 -0
  178. package/plugins/specweave/hooks/post-first-increment.sh.backup +61 -0
  179. package/plugins/specweave/hooks/post-increment-change.sh.backup +98 -0
  180. package/plugins/specweave/hooks/post-increment-completion.sh.backup +231 -0
  181. package/plugins/specweave/hooks/post-increment-planning.sh.backup +1048 -0
  182. package/plugins/specweave/hooks/post-increment-status-change.sh.backup +147 -0
  183. package/plugins/specweave/hooks/post-spec-update.sh.backup +158 -0
  184. package/plugins/specweave/hooks/post-task-completion.sh +4 -23
  185. package/plugins/specweave/hooks/post-user-story-complete.sh.backup +179 -0
  186. package/plugins/specweave/hooks/pre-command-deduplication.sh +1 -6
  187. package/plugins/specweave/hooks/pre-command-deduplication.sh.backup +83 -0
  188. package/plugins/specweave/hooks/pre-implementation.sh.backup +67 -0
  189. package/plugins/specweave/hooks/pre-task-completion.sh +8 -37
  190. package/plugins/specweave/hooks/pre-task-completion.sh.backup +194 -0
  191. package/plugins/specweave/hooks/pre-tool-use.sh +2 -11
  192. package/plugins/specweave/hooks/pre-tool-use.sh.backup +133 -0
  193. package/plugins/specweave/hooks/universal/dispatcher.mjs +135 -42
  194. package/plugins/specweave/hooks/universal/fail-fast-wrapper.sh +183 -0
  195. package/plugins/specweave/hooks/universal/hook-wrapper.cmd +26 -26
  196. package/plugins/specweave/hooks/universal/session-start.cmd +16 -16
  197. package/plugins/specweave/hooks/universal/session-start.ps1 +16 -16
  198. package/plugins/specweave/hooks/user-prompt-submit.sh +140 -38
  199. package/plugins/specweave/hooks/user-prompt-submit.sh.backup +386 -0
  200. package/plugins/specweave/hooks/v2/dispatchers/post-tool-use.sh +12 -0
  201. package/plugins/specweave/hooks/v2/dispatchers/session-start.sh +89 -0
  202. package/plugins/specweave/hooks/v2/guards/bash-file-guard.sh +211 -0
  203. package/plugins/specweave/hooks/v2/guards/bash-file-guard.test.sh +163 -0
  204. package/plugins/specweave/hooks/v2/guards/completion-guard.sh +26 -28
  205. package/plugins/specweave/hooks/v2/guards/features-folder-guard.sh +50 -0
  206. package/plugins/specweave/lib/vendor/core/increment/duplicate-detector.js +2 -2
  207. package/plugins/specweave/lib/vendor/core/increment/duplicate-detector.js.map +1 -1
  208. package/plugins/specweave/scripts/README.md +166 -0
  209. package/plugins/specweave/scripts/cleanup-state.sh +142 -0
  210. package/plugins/specweave/scripts/force-kill.sh +142 -0
  211. package/plugins/specweave/scripts/jobs.js +171 -0
  212. package/plugins/specweave/scripts/progress.js +170 -0
  213. package/plugins/specweave/scripts/read-costs.sh +132 -0
  214. package/plugins/specweave/scripts/read-jobs.sh +324 -0
  215. package/plugins/specweave/scripts/read-progress.sh +185 -0
  216. package/plugins/specweave/scripts/read-status.sh +146 -0
  217. package/plugins/specweave/scripts/read-workflow.sh +173 -0
  218. package/plugins/specweave/scripts/rebuild-dashboard-cache.sh +327 -0
  219. package/plugins/specweave/scripts/session-watchdog.sh +192 -0
  220. package/plugins/specweave/scripts/status.js +154 -0
  221. package/plugins/specweave/scripts/update-dashboard-cache.sh +281 -0
  222. package/plugins/specweave/skills/increment-planner/SKILL.md +333 -24
  223. package/plugins/specweave/skills/increment-planner/templates/spec-multi-project.md +17 -9
  224. package/plugins/specweave/skills/increment-planner/templates/spec-single-project.md +6 -2
  225. package/plugins/specweave/skills/instant-status/SKILL.md +70 -0
  226. package/plugins/specweave-ado/hooks/post-living-docs-update.sh.backup +353 -0
  227. package/plugins/specweave-ado/hooks/post-task-completion.sh.backup +172 -0
  228. package/plugins/specweave-ado/lib/enhanced-ado-sync.js +170 -0
  229. package/plugins/specweave-docs/commands/build.md +32 -4
  230. package/plugins/specweave-docs/commands/preview.md +43 -1
  231. package/plugins/specweave-docs/commands/validate.md +250 -0
  232. package/plugins/specweave-github/hooks/.specweave/logs/hooks-debug.log +1262 -626
  233. package/plugins/specweave-github/hooks/post-task-completion.sh.backup +258 -0
  234. package/plugins/specweave-github/lib/enhanced-github-sync.js +220 -0
  235. package/plugins/specweave-jira/hooks/post-task-completion.sh.backup +172 -0
  236. package/plugins/specweave-jira/lib/enhanced-jira-sync.js +134 -0
  237. package/plugins/specweave-release/hooks/.specweave/logs/dora-tracking.log +1254 -939
  238. package/plugins/specweave-release/hooks/post-task-completion.sh.backup +110 -0
  239. package/plugins/specweave/hooks/post-edit-spec.sh +0 -265
  240. package/plugins/specweave/hooks/post-write-spec.sh +0 -267
  241. package/plugins/specweave/hooks/pre-edit-spec.sh +0 -151
  242. package/plugins/specweave/hooks/pre-write-spec.sh +0 -151
@@ -0,0 +1,110 @@
1
+ #!/bin/bash
2
+ # Post-Increment-Completion Hook - DORA Metrics Tracking
3
+ #
4
+ # Fires after: /specweave:done completes
5
+ # Purpose: Automatically track DORA metrics and update living docs dashboard
6
+ #
7
+ # Integration: plugins/specweave-release/hooks/hooks.json
8
+
9
+ set -euo pipefail
10
+
11
+ # Constants
12
+ SPECWEAVE_ROOT="${SPECWEAVE_ROOT:-$(pwd)}"
13
+ METRICS_DIR="${SPECWEAVE_ROOT}/.specweave/metrics"
14
+ HISTORY_FILE="${METRICS_DIR}/dora-history.jsonl"
15
+ DASHBOARD_FILE="${SPECWEAVE_ROOT}/.specweave/docs/internal/delivery/dora-dashboard.md"
16
+ DORA_CALCULATOR="${SPECWEAVE_ROOT}/dist/src/metrics/dora-calculator.js"
17
+ LATEST_FILE="${METRICS_DIR}/dora-latest.json"
18
+
19
+ # Logging
20
+ LOG_FILE="${SPECWEAVE_ROOT}/.specweave/logs/dora-tracking.log"
21
+ mkdir -p "$(dirname "$LOG_FILE")"
22
+
23
+ log() {
24
+ echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG_FILE"
25
+ }
26
+
27
+ log "🎯 Post-Increment-Completion Hook Triggered"
28
+
29
+ # Check if DORA calculator exists
30
+ if [[ ! -f "$DORA_CALCULATOR" ]]; then
31
+ log "⚠️ DORA calculator not found at $DORA_CALCULATOR"
32
+ log " Run: npm run build"
33
+ exit 0 # Non-blocking
34
+ fi
35
+
36
+ # Check if GitHub token is available
37
+ if [[ -z "${GITHUB_TOKEN:-}" ]]; then
38
+ log "⚠️ GITHUB_TOKEN not set. DORA metrics require GitHub API access."
39
+ log " Set GITHUB_TOKEN in environment or .env file"
40
+ exit 0 # Non-blocking
41
+ fi
42
+
43
+ # Step 1: Calculate DORA metrics
44
+ log "📊 Calculating DORA metrics..."
45
+ if ! node "$DORA_CALCULATOR"; then
46
+ log "❌ Failed to calculate DORA metrics"
47
+ exit 0 # Non-blocking
48
+ fi
49
+
50
+ # Step 2: Append to history (JSONL format)
51
+ log "💾 Appending metrics to history..."
52
+ mkdir -p "$METRICS_DIR"
53
+
54
+ if [[ -f "$LATEST_FILE" ]]; then
55
+ cat "$LATEST_FILE" >> "$HISTORY_FILE"
56
+ log " ✓ Appended to $HISTORY_FILE"
57
+ else
58
+ log "⚠️ Latest metrics file not found: $LATEST_FILE"
59
+ fi
60
+
61
+ # Step 3: Update living docs dashboard
62
+ log "📝 Updating DORA dashboard..."
63
+ DASHBOARD_GENERATOR="${SPECWEAVE_ROOT}/dist/plugins/specweave-release/lib/dashboard-generator.js"
64
+
65
+ if [[ -f "$DASHBOARD_GENERATOR" ]]; then
66
+ if node "$DASHBOARD_GENERATOR"; then
67
+ log " ✓ Dashboard updated: $DASHBOARD_FILE"
68
+ else
69
+ log "⚠️ Failed to update dashboard"
70
+ fi
71
+ else
72
+ log "⚠️ Dashboard generator not found: $DASHBOARD_GENERATOR"
73
+ log " Manual dashboard update required"
74
+ fi
75
+
76
+ # Step 4: Check for degradation (optional)
77
+ log "🔍 Checking for metric degradation..."
78
+
79
+ # Calculate 30-day average and compare with current
80
+ # (This would be implemented in a TypeScript utility)
81
+ # For now, we'll just log a reminder
82
+ log " ℹ️ Degradation detection: Manual review recommended"
83
+ log " See: $DASHBOARD_FILE for trends"
84
+
85
+ # Step 5: Update main DORA metrics doc
86
+ DORA_METRICS_DOC="${SPECWEAVE_ROOT}/.specweave/docs/internal/delivery/dora-metrics.md"
87
+ if [[ -f "$DORA_METRICS_DOC" && -f "$LATEST_FILE" ]]; then
88
+ log "📄 Updating dora-metrics.md with latest values..."
89
+
90
+ # Extract current values from latest metrics
91
+ # (This is a simplified version - production would use jq for proper parsing)
92
+ TIMESTAMP=$(date '+%Y-%m-%d %H:%M UTC')
93
+
94
+ # Update "Last Calculated" timestamp
95
+ if command -v sed &> /dev/null; then
96
+ sed -i.bak "s/Last Calculated: .*/Last Calculated: $TIMESTAMP/" "$DORA_METRICS_DOC" 2>/dev/null || true
97
+ rm -f "${DORA_METRICS_DOC}.bak" 2>/dev/null || true
98
+ log " ✓ Updated timestamp in dora-metrics.md"
99
+ fi
100
+ fi
101
+
102
+ log "✅ DORA metrics tracking complete!"
103
+ log ""
104
+ log "📊 Next steps:"
105
+ log " 1. Review dashboard: $DASHBOARD_FILE"
106
+ log " 2. Check trends: Are metrics improving?"
107
+ log " 3. Take action: Address any degradation"
108
+ log ""
109
+
110
+ exit 0
@@ -1,265 +0,0 @@
1
- #!/bin/bash
2
- #
3
- # Post-Edit Hook: Update Status Line After spec.md or tasks.md Edits
4
- #
5
- # Triggers: After Edit tool modifies spec.md (AC updates) or tasks.md (task completion)
6
- # Action: Updates status line cache to reflect latest AC/task progress
7
- #
8
- # This ensures status line stays in sync when ACs are marked complete via Edit tool
9
- # (not just TodoWrite, which only tracks internal todo lists)
10
- #
11
- # EMERGENCY FIXES (v0.24.3):
12
- # - Kill switch: Set SPECWEAVE_DISABLE_HOOKS=1 to disable ALL hooks
13
- # - Circuit breaker: Auto-disable after 3 consecutive failures
14
- # - File locking: Prevent concurrent executions (max 1 at a time)
15
- # - Aggressive debouncing: Increased from 1s to 5s
16
- # - Complete error isolation: Never let errors reach Claude Code
17
- #
18
- # TIER 1 IMPROVEMENTS (v0.24.2):
19
- # - Debouncing: Skip if updated less than 1 second ago (90% overhead reduction)
20
- # - File mtime detection: Check recently modified spec.md/tasks.md as fallback
21
- # - Non-blocking: Run update-status-line.sh in background
22
- # - Smart detection: Only update if spec/tasks files actually changed
23
- #
24
- # Previous fix (v0.24.1): Enhanced file detection for increment completion
25
- # - Detects edits via TOOL_USE_CONTENT, TOOL_RESULT, and argument parsing
26
- # - Always updates status line for ANY spec.md/tasks.md edit in increments folder
27
-
28
- # CRITICAL: Remove set -e to prevent hook errors from crashing Claude Code
29
- set +e
30
-
31
- # EMERGENCY KILL SWITCH: Disable all hooks if env variable set
32
- if [[ "${SPECWEAVE_DISABLE_HOOKS:-0}" == "1" ]]; then
33
- exit 0
34
- fi
35
-
36
- # Find project root
37
- find_project_root() {
38
- local dir="$PWD"
39
- while [[ "$dir" != "/" ]]; do
40
- if [[ -d "$dir/.specweave" ]]; then
41
- echo "$dir"
42
- return 0
43
- fi
44
- dir=$(dirname "$dir")
45
- done
46
- echo "$PWD"
47
- }
48
-
49
- PROJECT_ROOT=$(find_project_root)
50
- LOGS_DIR="$PROJECT_ROOT/.specweave/logs"
51
- DEBUG_LOG="$LOGS_DIR/hooks-debug.log"
52
-
53
- # Ensure state and logs directories exist
54
- mkdir -p "$PROJECT_ROOT/.specweave/state" "$LOGS_DIR" 2>/dev/null || true
55
-
56
- # EMERGENCY CIRCUIT BREAKER: Track consecutive failures
57
- CIRCUIT_BREAKER_FILE="$PROJECT_ROOT/.specweave/state/.hook-circuit-breaker"
58
- CIRCUIT_BREAKER_THRESHOLD=3
59
-
60
- if [[ -f "$CIRCUIT_BREAKER_FILE" ]]; then
61
- FAILURE_COUNT=$(cat "$CIRCUIT_BREAKER_FILE" 2>/dev/null || echo 0)
62
- if (( FAILURE_COUNT >= CIRCUIT_BREAKER_THRESHOLD )); then
63
- echo "[$(date)] CIRCUIT BREAKER OPEN: Hooks disabled after $FAILURE_COUNT failures. Run: rm $CIRCUIT_BREAKER_FILE" >> "$DEBUG_LOG" 2>/dev/null || true
64
- exit 0
65
- fi
66
- fi
67
-
68
- # EMERGENCY FILE LOCK: Prevent concurrent executions
69
- LOCK_FILE="$PROJECT_ROOT/.specweave/state/.hook-post-edit.lock"
70
- LOCK_TIMEOUT=5 # seconds
71
-
72
- # Try to acquire lock with timeout
73
- LOCK_ACQUIRED=false
74
- for i in {1..5}; do
75
- if mkdir "$LOCK_FILE" 2>/dev/null; then
76
- LOCK_ACQUIRED=true
77
- trap 'rmdir "$LOCK_FILE" 2>/dev/null || true' EXIT
78
- break
79
- fi
80
-
81
- # Check if lock is stale (older than LOCK_TIMEOUT seconds)
82
- if [[ -d "$LOCK_FILE" ]]; then
83
- LOCK_AGE=$(($(date +%s) - $(stat -f "%m" "$LOCK_FILE" 2>/dev/null || echo 0)))
84
- if (( LOCK_AGE > LOCK_TIMEOUT )); then
85
- rmdir "$LOCK_FILE" 2>/dev/null || true
86
- continue
87
- fi
88
- fi
89
-
90
- sleep 0.2
91
- done
92
-
93
- if [[ "$LOCK_ACQUIRED" == "false" ]]; then
94
- echo "[$(date)] post-edit-spec: Could not acquire lock, skipping" >> "$DEBUG_LOG" 2>/dev/null || true
95
- exit 0
96
- fi
97
-
98
- # Log rotation: Keep debug log under 100KB
99
- if [[ -f "$DEBUG_LOG" ]] && [[ $(wc -c < "$DEBUG_LOG" 2>/dev/null || echo 0) -gt 102400 ]]; then
100
- tail -100 "$DEBUG_LOG" > "$DEBUG_LOG.tmp" 2>/dev/null || true
101
- mv "$DEBUG_LOG.tmp" "$DEBUG_LOG" 2>/dev/null || true
102
- echo "[$(date)] Log rotated" >> "$DEBUG_LOG" 2>/dev/null || true
103
- fi
104
-
105
- # ============================================================================
106
- # TIER 1 FIX: Debouncing (Prevent Redundant Updates)
107
- # ============================================================================
108
- # Skip update if we updated less than 5 seconds ago (INCREASED FROM 1s)
109
- # This handles rapid consecutive edits (e.g., 10 tasks marked complete quickly)
110
- LAST_UPDATE_FILE="$PROJECT_ROOT/.specweave/state/.last-status-update"
111
- DEBOUNCE_SECONDS=5
112
-
113
- if [[ -f "$LAST_UPDATE_FILE" ]]; then
114
- LAST_UPDATE=$(cat "$LAST_UPDATE_FILE" 2>/dev/null || echo 0)
115
- NOW=$(date +%s)
116
- TIME_SINCE_UPDATE=$((NOW - LAST_UPDATE))
117
-
118
- if (( TIME_SINCE_UPDATE < DEBOUNCE_SECONDS )); then
119
- echo "[$(date)] post-edit-spec: Debounced (${TIME_SINCE_UPDATE}s since last update)" >> "$DEBUG_LOG" 2>/dev/null || true
120
- exit 0 # Skip this update
121
- fi
122
- fi
123
-
124
- # ============================================================================
125
- # TIER 2: Check for PreToolUse Signal (Primary Detection Method)
126
- # ============================================================================
127
- PENDING_FILE="$PROJECT_ROOT/.specweave/state/.pending-status-update"
128
- METRICS_FILE="$PROJECT_ROOT/.specweave/state/hook-metrics.jsonl"
129
- EDITED_FILE=""
130
- DETECTION_METHOD="none"
131
-
132
- # First, check if PreToolUse hook left a signal
133
- if [[ -f "$PENDING_FILE" ]]; then
134
- EDITED_FILE=$(cat "$PENDING_FILE" 2>/dev/null || echo "")
135
- # Delete pending file immediately (consume signal)
136
- rm "$PENDING_FILE" 2>/dev/null || true
137
-
138
- if [[ -n "$EDITED_FILE" ]]; then
139
- DETECTION_METHOD="pretooluse"
140
- echo "[$(date)] post-edit-spec: File from PreToolUse signal: $EDITED_FILE" >> "$DEBUG_LOG" 2>/dev/null || true
141
-
142
- # Record Tier 2 success metric
143
- TIMESTAMP=$(date -u +%Y-%m-%dT%H:%M:%SZ)
144
- echo "{\"timestamp\":\"$TIMESTAMP\",\"hook\":\"post-edit-spec\",\"event\":\"tier2_success\",\"method\":\"pretooluse\"}" >> "$METRICS_FILE" 2>/dev/null || true
145
- fi
146
- fi
147
-
148
- # ============================================================================
149
- # TIER 1 FALLBACK: Environment Variable Detection
150
- # ============================================================================
151
- # If PreToolUse didn't provide signal, fall back to Tier 1 methods
152
- if [[ -z "$EDITED_FILE" ]]; then
153
- # Method 1: TOOL_USE_CONTENT environment variable
154
- if [[ -n "${TOOL_USE_CONTENT:-}" ]]; then
155
- EDITED_FILE="$TOOL_USE_CONTENT"
156
- DETECTION_METHOD="env_content"
157
- fi
158
-
159
- # Method 2: TOOL_RESULT environment variable
160
- if [[ -z "$EDITED_FILE" ]] && [[ -n "${TOOL_RESULT:-}" ]]; then
161
- EDITED_FILE=$(echo "$TOOL_RESULT" | grep -o '"file_path"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*"\([^"]*\)".*/\1/' || echo "")
162
- DETECTION_METHOD="env_result"
163
- fi
164
-
165
- # Method 3: TOOL_USE_ARGS
166
- if [[ -z "$EDITED_FILE" ]] && [[ -n "${TOOL_USE_ARGS:-}" ]]; then
167
- EDITED_FILE=$(echo "$TOOL_USE_ARGS" | grep -o '"file_path"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*"\([^"]*\)".*/\1/' || echo "")
168
- DETECTION_METHOD="env_args"
169
- fi
170
-
171
- # Log env var detection (for metrics)
172
- if [[ -n "$EDITED_FILE" ]]; then
173
- echo "[$(date)] post-edit-spec: File from env vars ($DETECTION_METHOD): $EDITED_FILE" >> "$DEBUG_LOG" 2>/dev/null || true
174
- fi
175
- fi
176
-
177
- # Check if we detected a spec.md or tasks.md edit in increments folder
178
- SHOULD_UPDATE=false
179
-
180
- if [[ -n "$EDITED_FILE" ]]; then
181
- # Check if the file is spec.md or tasks.md
182
- if [[ "$EDITED_FILE" == *"/spec.md" ]] || [[ "$EDITED_FILE" == *"/tasks.md" ]]; then
183
- # Check if it's in an increment folder
184
- if [[ "$EDITED_FILE" == *"/.specweave/increments/"* ]]; then
185
- SHOULD_UPDATE=true
186
- echo "[$(date)] post-edit-spec: Increment file edited - will update status line" >> "$DEBUG_LOG" 2>/dev/null || true
187
- fi
188
- fi
189
- fi
190
-
191
- # ============================================================================
192
- # TIER 1 FIX: File Modification Time Detection (Fallback)
193
- # ============================================================================
194
- # If we couldn't detect the file via environment variables, check which files
195
- # were modified recently (within last 2 seconds) instead of blindly updating
196
- if [[ -z "$EDITED_FILE" ]]; then
197
- echo "[$(date)] post-edit-spec: Env vars empty - checking file mtimes" >> "$DEBUG_LOG" 2>/dev/null || true
198
-
199
- NOW=$(date +%s)
200
- INCREMENTS_DIR="$PROJECT_ROOT/.specweave/increments"
201
-
202
- # Check for recently modified spec.md or tasks.md files
203
- if [[ -d "$INCREMENTS_DIR" ]]; then
204
- for file in "$INCREMENTS_DIR"/*/spec.md "$INCREMENTS_DIR"/*/tasks.md; do
205
- if [[ -f "$file" ]]; then
206
- # Get file modification time (platform-specific)
207
- if [[ "$(uname)" == "Darwin" ]]; then
208
- MTIME=$(stat -f "%m" "$file" 2>/dev/null || echo 0)
209
- else
210
- MTIME=$(stat -c "%Y" "$file" 2>/dev/null || echo 0)
211
- fi
212
-
213
- # If file was modified in last 2 seconds, consider it the edited file
214
- TIME_DIFF=$((NOW - MTIME))
215
- if (( TIME_DIFF <= 2 )); then
216
- EDITED_FILE="$file"
217
- echo "[$(date)] post-edit-spec: Detected recent modification: $file (${TIME_DIFF}s ago)" >> "$DEBUG_LOG" 2>/dev/null || true
218
- SHOULD_UPDATE=true
219
- break
220
- fi
221
- fi
222
- done
223
- fi
224
-
225
- # If still no file detected, skip update (not a spec/tasks edit)
226
- if [[ -z "$EDITED_FILE" ]]; then
227
- echo "[$(date)] post-edit-spec: No spec/tasks modifications detected - skipping" >> "$DEBUG_LOG" 2>/dev/null || true
228
- exit 0
229
- fi
230
- fi
231
-
232
- # ============================================================================
233
- # TIER 1 FIX: Non-Blocking Background Update with COMPLETE ERROR ISOLATION
234
- # ============================================================================
235
- # Update status line if needed
236
- if [[ "$SHOULD_UPDATE" == "true" ]]; then
237
- echo "[$(date)] post-edit-spec: Running update-status-line.sh (background)" >> "$DEBUG_LOG" 2>/dev/null || true
238
-
239
- # Record update time BEFORE spawning background process
240
- # This ensures debouncing works even if update hasn't completed yet
241
- echo "$(date +%s)" > "$LAST_UPDATE_FILE"
242
-
243
- # Run status line update in background with COMPLETE error isolation
244
- # This prevents Edit tool from waiting for status line computation
245
- (
246
- set +e # Disable error propagation
247
-
248
- if "$PROJECT_ROOT/plugins/specweave/hooks/lib/update-status-line.sh" 2>&1 | tee -a "$DEBUG_LOG" >/dev/null; then
249
- echo "[$(date)] post-edit-spec: Status line updated successfully" >> "$DEBUG_LOG" 2>/dev/null || true
250
- # Reset circuit breaker on success
251
- echo "0" > "$CIRCUIT_BREAKER_FILE" 2>/dev/null || true
252
- else
253
- echo "[$(date)] post-edit-spec: Warning - status line update failed (non-blocking)" >> "$DEBUG_LOG" 2>/dev/null || true
254
- # Increment circuit breaker
255
- CURRENT_FAILURES=$(cat "$CIRCUIT_BREAKER_FILE" 2>/dev/null || echo 0)
256
- echo "$((CURRENT_FAILURES + 1))" > "$CIRCUIT_BREAKER_FILE" 2>/dev/null || true
257
- fi
258
- ) &
259
-
260
- # Disown the background process so it's not killed when hook exits
261
- disown 2>/dev/null || true
262
- fi
263
-
264
- # Always exit 0 to prevent hook errors from crashing Claude Code
265
- exit 0
@@ -1,267 +0,0 @@
1
- #!/bin/bash
2
- #
3
- # Post-Write Hook: Update Status Line After spec.md or tasks.md Writes
4
- #
5
- # Triggers: After Write tool creates/replaces spec.md or tasks.md
6
- # Action: Updates status line cache to reflect latest AC/task progress
7
- #
8
- # EMERGENCY FIXES (v0.24.3):
9
- # - Kill switch: Set SPECWEAVE_DISABLE_HOOKS=1 to disable ALL hooks
10
- # - Circuit breaker: Auto-disable after 3 consecutive failures
11
- # - File locking: Prevent concurrent executions (max 1 at a time)
12
- # - Aggressive debouncing: Increased from 1s to 5s
13
- # - Complete error isolation: Never let errors reach Claude Code
14
- #
15
- # TIER 1 IMPROVEMENTS (v0.24.2):
16
- # - Debouncing: Skip if updated less than 1 second ago (90% overhead reduction)
17
- # - File mtime detection: Check recently modified spec.md/tasks.md as fallback
18
- # - Non-blocking: Run update-status-line.sh in background
19
- # - Smart detection: Only update if spec/tasks files actually changed
20
- #
21
- # Previous fix (v0.24.1): Enhanced file detection for increment completion
22
- # - Detects writes via TOOL_USE_CONTENT, TOOL_RESULT, and argument parsing
23
- # - Always updates status line for ANY spec.md/tasks.md write in increments folder
24
-
25
- # CRITICAL: Remove set -e to prevent hook errors from crashing Claude Code
26
- set +e
27
-
28
- # EMERGENCY KILL SWITCH: Disable all hooks if env variable set
29
- if [[ "${SPECWEAVE_DISABLE_HOOKS:-0}" == "1" ]]; then
30
- exit 0
31
- fi
32
-
33
- # Find project root
34
- find_project_root() {
35
- local dir="$PWD"
36
- while [[ "$dir" != "/" ]]; do
37
- if [[ -d "$dir/.specweave" ]]; then
38
- echo "$dir"
39
- return 0
40
- fi
41
- dir=$(dirname "$dir")
42
- done
43
- echo "$PWD"
44
- }
45
-
46
- PROJECT_ROOT=$(find_project_root)
47
- LOGS_DIR="$PROJECT_ROOT/.specweave/logs"
48
- DEBUG_LOG="$LOGS_DIR/hooks-debug.log"
49
-
50
- # Ensure state and logs directories exist
51
- mkdir -p "$PROJECT_ROOT/.specweave/state" "$LOGS_DIR" 2>/dev/null || true
52
-
53
- # EMERGENCY CIRCUIT BREAKER: Track consecutive failures
54
- CIRCUIT_BREAKER_FILE="$PROJECT_ROOT/.specweave/state/.hook-circuit-breaker"
55
- CIRCUIT_BREAKER_THRESHOLD=3
56
-
57
- if [[ -f "$CIRCUIT_BREAKER_FILE" ]]; then
58
- FAILURE_COUNT=$(cat "$CIRCUIT_BREAKER_FILE" 2>/dev/null || echo 0)
59
- if (( FAILURE_COUNT >= CIRCUIT_BREAKER_THRESHOLD )); then
60
- echo "[$(date)] CIRCUIT BREAKER OPEN: Hooks disabled after $FAILURE_COUNT failures. Run: rm $CIRCUIT_BREAKER_FILE" >> "$DEBUG_LOG" 2>/dev/null || true
61
- exit 0
62
- fi
63
- fi
64
-
65
- # EMERGENCY FILE LOCK: Prevent concurrent executions
66
- LOCK_FILE="$PROJECT_ROOT/.specweave/state/.hook-post-write.lock"
67
- LOCK_TIMEOUT=5 # seconds
68
-
69
- # Try to acquire lock with timeout
70
- LOCK_ACQUIRED=false
71
- for i in {1..5}; do
72
- if mkdir "$LOCK_FILE" 2>/dev/null; then
73
- LOCK_ACQUIRED=true
74
- trap 'rmdir "$LOCK_FILE" 2>/dev/null || true' EXIT
75
- break
76
- fi
77
-
78
- # Check if lock is stale (older than LOCK_TIMEOUT seconds)
79
- if [[ -d "$LOCK_FILE" ]]; then
80
- LOCK_AGE=$(($(date +%s) - $(stat -f "%m" "$LOCK_FILE" 2>/dev/null || echo 0)))
81
- if (( LOCK_AGE > LOCK_TIMEOUT )); then
82
- rmdir "$LOCK_FILE" 2>/dev/null || true
83
- continue
84
- fi
85
- fi
86
-
87
- sleep 0.2
88
- done
89
-
90
- if [[ "$LOCK_ACQUIRED" == "false" ]]; then
91
- echo "[$(date)] post-write-spec: Could not acquire lock, skipping" >> "$DEBUG_LOG" 2>/dev/null || true
92
- exit 0
93
- fi
94
-
95
- # Log rotation: Keep debug log under 100KB
96
- if [[ -f "$DEBUG_LOG" ]] && [[ $(wc -c < "$DEBUG_LOG" 2>/dev/null || echo 0) -gt 102400 ]]; then
97
- tail -100 "$DEBUG_LOG" > "$DEBUG_LOG.tmp" 2>/dev/null || true
98
- mv "$DEBUG_LOG.tmp" "$DEBUG_LOG" 2>/dev/null || true
99
- echo "[$(date)] Log rotated" >> "$DEBUG_LOG" 2>/dev/null || true
100
- fi
101
-
102
- # ============================================================================
103
- # TIER 1 FIX: Debouncing (Prevent Redundant Updates)
104
- # ============================================================================
105
- # Skip update if we updated less than 5 seconds ago (INCREASED FROM 1s)
106
- # This handles rapid consecutive writes (e.g., spec.md regeneration)
107
- LAST_UPDATE_FILE="$PROJECT_ROOT/.specweave/state/.last-status-update"
108
- DEBOUNCE_SECONDS=5
109
-
110
- if [[ -f "$LAST_UPDATE_FILE" ]]; then
111
- LAST_UPDATE=$(cat "$LAST_UPDATE_FILE" 2>/dev/null || echo 0)
112
- NOW=$(date +%s)
113
- TIME_SINCE_UPDATE=$((NOW - LAST_UPDATE))
114
-
115
- if (( TIME_SINCE_UPDATE < DEBOUNCE_SECONDS )); then
116
- echo "[$(date)] post-write-spec: Debounced (${TIME_SINCE_UPDATE}s since last update)" >> "$DEBUG_LOG" 2>/dev/null || true
117
- exit 0 # Skip this update
118
- fi
119
- fi
120
-
121
- # ============================================================================
122
- # TIER 2: Check for PreToolUse Signal (Primary Detection Method)
123
- # ============================================================================
124
- PENDING_FILE="$PROJECT_ROOT/.specweave/state/.pending-status-update"
125
- METRICS_FILE="$PROJECT_ROOT/.specweave/state/hook-metrics.jsonl"
126
- WRITTEN_FILE=""
127
- DETECTION_METHOD="none"
128
-
129
- # First, check if PreToolUse hook left a signal
130
- if [[ -f "$PENDING_FILE" ]]; then
131
- WRITTEN_FILE=$(cat "$PENDING_FILE" 2>/dev/null || echo "")
132
- # Delete pending file immediately (consume signal)
133
- rm "$PENDING_FILE" 2>/dev/null || true
134
-
135
- if [[ -n "$WRITTEN_FILE" ]]; then
136
- DETECTION_METHOD="pretooluse"
137
- echo "[$(date)] post-write-spec: File from PreToolUse signal: $WRITTEN_FILE" >> "$DEBUG_LOG" 2>/dev/null || true
138
-
139
- # Record Tier 2 success metric
140
- TIMESTAMP=$(date -u +%Y-%m-%dT%H:%M:%SZ)
141
- echo "{\"timestamp\":\"$TIMESTAMP\",\"hook\":\"post-write-spec\",\"event\":\"tier2_success\",\"method\":\"pretooluse\"}" >> "$METRICS_FILE" 2>/dev/null || true
142
- fi
143
- fi
144
-
145
- # ============================================================================
146
- # TIER 1 FALLBACK: Environment Variable Detection
147
- # ============================================================================
148
- # If PreToolUse didn't provide signal, fall back to Tier 1 methods
149
- if [[ -z "$WRITTEN_FILE" ]]; then
150
- # Method 1: TOOL_USE_CONTENT environment variable
151
- if [[ -n "${TOOL_USE_CONTENT:-}" ]]; then
152
- WRITTEN_FILE="$TOOL_USE_CONTENT"
153
- DETECTION_METHOD="env_content"
154
- fi
155
-
156
- # Method 2: TOOL_RESULT environment variable
157
- if [[ -z "$WRITTEN_FILE" ]] && [[ -n "${TOOL_RESULT:-}" ]]; then
158
- WRITTEN_FILE=$(echo "$TOOL_RESULT" | grep -o '"file_path"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*"\([^"]*\)".*/\1/' || echo "")
159
- DETECTION_METHOD="env_result"
160
- fi
161
-
162
- # Method 3: TOOL_USE_ARGS
163
- if [[ -z "$WRITTEN_FILE" ]] && [[ -n "${TOOL_USE_ARGS:-}" ]]; then
164
- WRITTEN_FILE=$(echo "$TOOL_USE_ARGS" | grep -o '"file_path"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*"\([^"]*\)".*/\1/' || echo "")
165
- DETECTION_METHOD="env_args"
166
- fi
167
-
168
- # Log env var detection (for metrics)
169
- if [[ -n "$WRITTEN_FILE" ]]; then
170
- echo "[$(date)] post-write-spec: File from env vars ($DETECTION_METHOD): $WRITTEN_FILE" >> "$DEBUG_LOG" 2>/dev/null || true
171
- fi
172
- fi
173
-
174
- # Log detection attempt (only log if we actually detected a file, to reduce noise)
175
- if [[ -n "$WRITTEN_FILE" ]]; then
176
- echo "[$(date)] post-write-spec: Detected file: $WRITTEN_FILE" >> "$DEBUG_LOG" 2>/dev/null || true
177
- fi
178
-
179
- # Check if we detected a spec.md or tasks.md write in increments folder
180
- SHOULD_UPDATE=false
181
-
182
- if [[ -n "$WRITTEN_FILE" ]]; then
183
- # Check if the file is spec.md or tasks.md
184
- if [[ "$WRITTEN_FILE" == *"/spec.md" ]] || [[ "$WRITTEN_FILE" == *"/tasks.md" ]]; then
185
- # Check if it's in an increment folder
186
- if [[ "$WRITTEN_FILE" == *"/.specweave/increments/"* ]]; then
187
- SHOULD_UPDATE=true
188
- echo "[$(date)] post-write-spec: Increment file written - will update status line" >> "$DEBUG_LOG" 2>/dev/null || true
189
- fi
190
- fi
191
- fi
192
-
193
- # ============================================================================
194
- # TIER 1 FIX: File Modification Time Detection (Fallback)
195
- # ============================================================================
196
- # If we couldn't detect the file via environment variables, check which files
197
- # were modified recently (within last 2 seconds) instead of blindly updating
198
- if [[ -z "$WRITTEN_FILE" ]]; then
199
- echo "[$(date)] post-write-spec: Env vars empty - checking file mtimes" >> "$DEBUG_LOG" 2>/dev/null || true
200
-
201
- NOW=$(date +%s)
202
- INCREMENTS_DIR="$PROJECT_ROOT/.specweave/increments"
203
-
204
- # Check for recently modified spec.md or tasks.md files
205
- if [[ -d "$INCREMENTS_DIR" ]]; then
206
- for file in "$INCREMENTS_DIR"/*/spec.md "$INCREMENTS_DIR"/*/tasks.md; do
207
- if [[ -f "$file" ]]; then
208
- # Get file modification time (platform-specific)
209
- if [[ "$(uname)" == "Darwin" ]]; then
210
- MTIME=$(stat -f "%m" "$file" 2>/dev/null || echo 0)
211
- else
212
- MTIME=$(stat -c "%Y" "$file" 2>/dev/null || echo 0)
213
- fi
214
-
215
- # If file was modified in last 2 seconds, consider it the written file
216
- TIME_DIFF=$((NOW - MTIME))
217
- if (( TIME_DIFF <= 2 )); then
218
- WRITTEN_FILE="$file"
219
- echo "[$(date)] post-write-spec: Detected recent modification: $file (${TIME_DIFF}s ago)" >> "$DEBUG_LOG" 2>/dev/null || true
220
- SHOULD_UPDATE=true
221
- break
222
- fi
223
- fi
224
- done
225
- fi
226
-
227
- # If still no file detected, skip update (not a spec/tasks write)
228
- if [[ -z "$WRITTEN_FILE" ]]; then
229
- echo "[$(date)] post-write-spec: No spec/tasks modifications detected - skipping" >> "$DEBUG_LOG" 2>/dev/null || true
230
- exit 0
231
- fi
232
- fi
233
-
234
- # ============================================================================
235
- # TIER 1 FIX: Non-Blocking Background Update with COMPLETE ERROR ISOLATION
236
- # ============================================================================
237
- # Update status line if needed
238
- if [[ "$SHOULD_UPDATE" == "true" ]]; then
239
- echo "[$(date)] post-write-spec: Running update-status-line.sh (background)" >> "$DEBUG_LOG" 2>/dev/null || true
240
-
241
- # Record update time BEFORE spawning background process
242
- # This ensures debouncing works even if update hasn't completed yet
243
- echo "$(date +%s)" > "$LAST_UPDATE_FILE"
244
-
245
- # Run status line update in background with COMPLETE error isolation
246
- # This prevents Write tool from waiting for status line computation
247
- (
248
- set +e # Disable error propagation
249
-
250
- if "$PROJECT_ROOT/plugins/specweave/hooks/lib/update-status-line.sh" 2>&1 | tee -a "$DEBUG_LOG" >/dev/null; then
251
- echo "[$(date)] post-write-spec: Status line updated successfully" >> "$DEBUG_LOG" 2>/dev/null || true
252
- # Reset circuit breaker on success
253
- echo "0" > "$CIRCUIT_BREAKER_FILE" 2>/dev/null || true
254
- else
255
- echo "[$(date)] post-write-spec: Warning - status line update failed (non-blocking)" >> "$DEBUG_LOG" 2>/dev/null || true
256
- # Increment circuit breaker
257
- CURRENT_FAILURES=$(cat "$CIRCUIT_BREAKER_FILE" 2>/dev/null || echo 0)
258
- echo "$((CURRENT_FAILURES + 1))" > "$CIRCUIT_BREAKER_FILE" 2>/dev/null || true
259
- fi
260
- ) &
261
-
262
- # Disown the background process so it's not killed when hook exits
263
- disown 2>/dev/null || true
264
- fi
265
-
266
- # Always exit 0 to prevent hook errors from crashing Claude Code
267
- exit 0