specweave 0.28.68 → 0.29.0

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 (234) hide show
  1. package/CLAUDE.md +3 -2
  2. package/README.md +19 -2
  3. package/dist/src/cli/commands/discrepancies.d.ts +89 -0
  4. package/dist/src/cli/commands/discrepancies.d.ts.map +1 -0
  5. package/dist/src/cli/commands/discrepancies.js +385 -0
  6. package/dist/src/cli/commands/discrepancies.js.map +1 -0
  7. package/dist/src/cli/commands/notifications.d.ts +70 -0
  8. package/dist/src/cli/commands/notifications.d.ts.map +1 -0
  9. package/dist/src/cli/commands/notifications.js +236 -0
  10. package/dist/src/cli/commands/notifications.js.map +1 -0
  11. package/dist/src/cli/commands/sync-logs.d.ts +54 -0
  12. package/dist/src/cli/commands/sync-logs.d.ts.map +1 -0
  13. package/dist/src/cli/commands/sync-logs.js +240 -0
  14. package/dist/src/cli/commands/sync-logs.js.map +1 -0
  15. package/dist/src/cli/commands/sync-monitor.d.ts +42 -0
  16. package/dist/src/cli/commands/sync-monitor.d.ts.map +1 -0
  17. package/dist/src/cli/commands/sync-monitor.js +191 -0
  18. package/dist/src/cli/commands/sync-monitor.js.map +1 -0
  19. package/dist/src/cli/helpers/init/brownfield-analysis.d.ts +45 -0
  20. package/dist/src/cli/helpers/init/brownfield-analysis.d.ts.map +1 -0
  21. package/dist/src/cli/helpers/init/brownfield-analysis.js +431 -0
  22. package/dist/src/cli/helpers/init/brownfield-analysis.js.map +1 -0
  23. package/dist/src/cli/helpers/init/index.d.ts +1 -0
  24. package/dist/src/cli/helpers/init/index.d.ts.map +1 -1
  25. package/dist/src/cli/helpers/init/index.js +2 -0
  26. package/dist/src/cli/helpers/init/index.js.map +1 -1
  27. package/dist/src/cli/workers/brownfield-worker.d.ts +66 -0
  28. package/dist/src/cli/workers/brownfield-worker.d.ts.map +1 -0
  29. package/dist/src/cli/workers/brownfield-worker.js +417 -0
  30. package/dist/src/cli/workers/brownfield-worker.js.map +1 -0
  31. package/dist/src/core/background/brownfield-launcher.d.ts +86 -0
  32. package/dist/src/core/background/brownfield-launcher.d.ts.map +1 -0
  33. package/dist/src/core/background/brownfield-launcher.js +295 -0
  34. package/dist/src/core/background/brownfield-launcher.js.map +1 -0
  35. package/dist/src/core/background/index.d.ts +2 -0
  36. package/dist/src/core/background/index.d.ts.map +1 -1
  37. package/dist/src/core/background/index.js +2 -0
  38. package/dist/src/core/background/index.js.map +1 -1
  39. package/dist/src/core/background/types.d.ts +23 -2
  40. package/dist/src/core/background/types.d.ts.map +1 -1
  41. package/dist/src/core/config/index.d.ts +1 -0
  42. package/dist/src/core/config/index.d.ts.map +1 -1
  43. package/dist/src/core/config/index.js +1 -0
  44. package/dist/src/core/config/index.js.map +1 -1
  45. package/dist/src/core/config/types.d.ts +6 -0
  46. package/dist/src/core/config/types.d.ts.map +1 -1
  47. package/dist/src/core/config/types.js.map +1 -1
  48. package/dist/src/core/dashboard/dashboard-data.d.ts +156 -0
  49. package/dist/src/core/dashboard/dashboard-data.d.ts.map +1 -0
  50. package/dist/src/core/dashboard/dashboard-data.js +191 -0
  51. package/dist/src/core/dashboard/dashboard-data.js.map +1 -0
  52. package/dist/src/core/dashboard/index.d.ts +9 -0
  53. package/dist/src/core/dashboard/index.d.ts.map +1 -0
  54. package/dist/src/core/dashboard/index.js +9 -0
  55. package/dist/src/core/dashboard/index.js.map +1 -0
  56. package/dist/src/core/discrepancy/analyzers/api-route-analyzer.d.ts +77 -0
  57. package/dist/src/core/discrepancy/analyzers/api-route-analyzer.d.ts.map +1 -0
  58. package/dist/src/core/discrepancy/analyzers/api-route-analyzer.js +286 -0
  59. package/dist/src/core/discrepancy/analyzers/api-route-analyzer.js.map +1 -0
  60. package/dist/src/core/discrepancy/analyzers/index.d.ts +8 -0
  61. package/dist/src/core/discrepancy/analyzers/index.d.ts.map +1 -0
  62. package/dist/src/core/discrepancy/analyzers/index.js +8 -0
  63. package/dist/src/core/discrepancy/analyzers/index.js.map +1 -0
  64. package/dist/src/core/discrepancy/analyzers/typescript-analyzer.d.ts +96 -0
  65. package/dist/src/core/discrepancy/analyzers/typescript-analyzer.d.ts.map +1 -0
  66. package/dist/src/core/discrepancy/analyzers/typescript-analyzer.js +247 -0
  67. package/dist/src/core/discrepancy/analyzers/typescript-analyzer.js.map +1 -0
  68. package/dist/src/core/discrepancy/brownfield-manager.d.ts +88 -0
  69. package/dist/src/core/discrepancy/brownfield-manager.d.ts.map +1 -0
  70. package/dist/src/core/discrepancy/brownfield-manager.js +520 -0
  71. package/dist/src/core/discrepancy/brownfield-manager.js.map +1 -0
  72. package/dist/src/core/discrepancy/brownfield-types.d.ts +174 -0
  73. package/dist/src/core/discrepancy/brownfield-types.d.ts.map +1 -0
  74. package/dist/src/core/discrepancy/brownfield-types.js +11 -0
  75. package/dist/src/core/discrepancy/brownfield-types.js.map +1 -0
  76. package/dist/src/core/discrepancy/detector.d.ts +92 -0
  77. package/dist/src/core/discrepancy/detector.d.ts.map +1 -0
  78. package/dist/src/core/discrepancy/detector.js +346 -0
  79. package/dist/src/core/discrepancy/detector.js.map +1 -0
  80. package/dist/src/core/discrepancy/increment-generator.d.ts +51 -0
  81. package/dist/src/core/discrepancy/increment-generator.d.ts.map +1 -0
  82. package/dist/src/core/discrepancy/increment-generator.js +234 -0
  83. package/dist/src/core/discrepancy/increment-generator.js.map +1 -0
  84. package/dist/src/core/discrepancy/index.d.ts +18 -0
  85. package/dist/src/core/discrepancy/index.d.ts.map +1 -0
  86. package/dist/src/core/discrepancy/index.js +24 -0
  87. package/dist/src/core/discrepancy/index.js.map +1 -0
  88. package/dist/src/core/discrepancy/severity-classifier.d.ts +81 -0
  89. package/dist/src/core/discrepancy/severity-classifier.d.ts.map +1 -0
  90. package/dist/src/core/discrepancy/severity-classifier.js +289 -0
  91. package/dist/src/core/discrepancy/severity-classifier.js.map +1 -0
  92. package/dist/src/core/discrepancy/spec-parser.d.ts +74 -0
  93. package/dist/src/core/discrepancy/spec-parser.d.ts.map +1 -0
  94. package/dist/src/core/discrepancy/spec-parser.js +213 -0
  95. package/dist/src/core/discrepancy/spec-parser.js.map +1 -0
  96. package/dist/src/core/discrepancy/update-recommender.d.ts +77 -0
  97. package/dist/src/core/discrepancy/update-recommender.d.ts.map +1 -0
  98. package/dist/src/core/discrepancy/update-recommender.js +323 -0
  99. package/dist/src/core/discrepancy/update-recommender.js.map +1 -0
  100. package/dist/src/core/living-docs/living-docs-sync.d.ts +13 -16
  101. package/dist/src/core/living-docs/living-docs-sync.d.ts.map +1 -1
  102. package/dist/src/core/living-docs/living-docs-sync.js +31 -112
  103. package/dist/src/core/living-docs/living-docs-sync.js.map +1 -1
  104. package/dist/src/core/logs/index.d.ts +10 -0
  105. package/dist/src/core/logs/index.d.ts.map +1 -0
  106. package/dist/src/core/logs/index.js +10 -0
  107. package/dist/src/core/logs/index.js.map +1 -0
  108. package/dist/src/core/logs/log-aggregator.d.ts +130 -0
  109. package/dist/src/core/logs/log-aggregator.d.ts.map +1 -0
  110. package/dist/src/core/logs/log-aggregator.js +206 -0
  111. package/dist/src/core/logs/log-aggregator.js.map +1 -0
  112. package/dist/src/core/logs/log-exporter.d.ts +81 -0
  113. package/dist/src/core/logs/log-exporter.d.ts.map +1 -0
  114. package/dist/src/core/logs/log-exporter.js +141 -0
  115. package/dist/src/core/logs/log-exporter.js.map +1 -0
  116. package/dist/src/core/notifications/command-integration.d.ts +82 -0
  117. package/dist/src/core/notifications/command-integration.d.ts.map +1 -0
  118. package/dist/src/core/notifications/command-integration.js +80 -0
  119. package/dist/src/core/notifications/command-integration.js.map +1 -0
  120. package/dist/src/core/notifications/index.d.ts +12 -0
  121. package/dist/src/core/notifications/index.d.ts.map +1 -0
  122. package/dist/src/core/notifications/index.js +12 -0
  123. package/dist/src/core/notifications/index.js.map +1 -0
  124. package/dist/src/core/notifications/notification-display.d.ts +70 -0
  125. package/dist/src/core/notifications/notification-display.d.ts.map +1 -0
  126. package/dist/src/core/notifications/notification-display.js +177 -0
  127. package/dist/src/core/notifications/notification-display.js.map +1 -0
  128. package/dist/src/core/notifications/notification-manager.d.ts +126 -0
  129. package/dist/src/core/notifications/notification-manager.d.ts.map +1 -0
  130. package/dist/src/core/notifications/notification-manager.js +287 -0
  131. package/dist/src/core/notifications/notification-manager.js.map +1 -0
  132. package/dist/src/core/notifications/notification-types.d.ts +159 -0
  133. package/dist/src/core/notifications/notification-types.d.ts.map +1 -0
  134. package/dist/src/core/notifications/notification-types.js +93 -0
  135. package/dist/src/core/notifications/notification-types.js.map +1 -0
  136. package/dist/src/core/scheduler/index.d.ts +11 -0
  137. package/dist/src/core/scheduler/index.d.ts.map +1 -0
  138. package/dist/src/core/scheduler/index.js +11 -0
  139. package/dist/src/core/scheduler/index.js.map +1 -0
  140. package/dist/src/core/scheduler/job-scheduler.d.ts +179 -0
  141. package/dist/src/core/scheduler/job-scheduler.d.ts.map +1 -0
  142. package/dist/src/core/scheduler/job-scheduler.js +282 -0
  143. package/dist/src/core/scheduler/job-scheduler.js.map +1 -0
  144. package/dist/src/core/scheduler/schedule-persistence.d.ts +83 -0
  145. package/dist/src/core/scheduler/schedule-persistence.d.ts.map +1 -0
  146. package/dist/src/core/scheduler/schedule-persistence.js +180 -0
  147. package/dist/src/core/scheduler/schedule-persistence.js.map +1 -0
  148. package/dist/src/core/scheduler/scheduled-job.d.ts +188 -0
  149. package/dist/src/core/scheduler/scheduled-job.d.ts.map +1 -0
  150. package/dist/src/core/scheduler/scheduled-job.js +182 -0
  151. package/dist/src/core/scheduler/scheduled-job.js.map +1 -0
  152. package/dist/src/core/sync/permission-enforcer.d.ts +206 -0
  153. package/dist/src/core/sync/permission-enforcer.d.ts.map +1 -0
  154. package/dist/src/core/sync/permission-enforcer.js +268 -0
  155. package/dist/src/core/sync/permission-enforcer.js.map +1 -0
  156. package/dist/src/core/sync/sync-audit-logger.d.ts +217 -0
  157. package/dist/src/core/sync/sync-audit-logger.d.ts.map +1 -0
  158. package/dist/src/core/sync/sync-audit-logger.js +327 -0
  159. package/dist/src/core/sync/sync-audit-logger.js.map +1 -0
  160. package/dist/src/core/sync/sync-interceptor.d.ts +190 -0
  161. package/dist/src/core/sync/sync-interceptor.d.ts.map +1 -0
  162. package/dist/src/core/sync/sync-interceptor.js +224 -0
  163. package/dist/src/core/sync/sync-interceptor.js.map +1 -0
  164. package/dist/src/core/types/increment-metadata.d.ts +5 -2
  165. package/dist/src/core/types/increment-metadata.d.ts.map +1 -1
  166. package/dist/src/core/types/sync-config.d.ts +267 -0
  167. package/dist/src/core/types/sync-config.d.ts.map +1 -0
  168. package/dist/src/core/types/sync-config.js +304 -0
  169. package/dist/src/core/types/sync-config.js.map +1 -0
  170. package/dist/src/hooks/index.d.ts +11 -0
  171. package/dist/src/hooks/index.d.ts.map +1 -0
  172. package/dist/src/hooks/index.js +11 -0
  173. package/dist/src/hooks/index.js.map +1 -0
  174. package/dist/src/hooks/platform.d.ts +125 -0
  175. package/dist/src/hooks/platform.d.ts.map +1 -0
  176. package/dist/src/hooks/platform.js +325 -0
  177. package/dist/src/hooks/platform.js.map +1 -0
  178. package/dist/src/hooks/processor.d.ts +20 -0
  179. package/dist/src/hooks/processor.d.ts.map +1 -0
  180. package/dist/src/hooks/processor.js +317 -0
  181. package/dist/src/hooks/processor.js.map +1 -0
  182. package/dist/src/hooks/scheduler-startup.d.ts +19 -0
  183. package/dist/src/hooks/scheduler-startup.d.ts.map +1 -0
  184. package/dist/src/hooks/scheduler-startup.js +92 -0
  185. package/dist/src/hooks/scheduler-startup.js.map +1 -0
  186. package/dist/src/hooks/session-start.d.ts +16 -0
  187. package/dist/src/hooks/session-start.d.ts.map +1 -0
  188. package/dist/src/hooks/session-start.js +92 -0
  189. package/dist/src/hooks/session-start.js.map +1 -0
  190. package/dist/src/importers/duplicate-detector.d.ts +13 -2
  191. package/dist/src/importers/duplicate-detector.d.ts.map +1 -1
  192. package/dist/src/importers/duplicate-detector.js +21 -2
  193. package/dist/src/importers/duplicate-detector.js.map +1 -1
  194. package/dist/src/importers/item-converter.d.ts +41 -2
  195. package/dist/src/importers/item-converter.d.ts.map +1 -1
  196. package/dist/src/importers/item-converter.js +225 -38
  197. package/dist/src/importers/item-converter.js.map +1 -1
  198. package/dist/src/living-docs/fs-id-allocator.d.ts +7 -0
  199. package/dist/src/living-docs/fs-id-allocator.d.ts.map +1 -1
  200. package/dist/src/living-docs/fs-id-allocator.js +30 -4
  201. package/dist/src/living-docs/fs-id-allocator.js.map +1 -1
  202. package/dist/src/sync/ado-sync-wrapper.d.ts +137 -0
  203. package/dist/src/sync/ado-sync-wrapper.d.ts.map +1 -0
  204. package/dist/src/sync/ado-sync-wrapper.js +148 -0
  205. package/dist/src/sync/ado-sync-wrapper.js.map +1 -0
  206. package/dist/src/sync/github-sync-wrapper.d.ts +195 -0
  207. package/dist/src/sync/github-sync-wrapper.d.ts.map +1 -0
  208. package/dist/src/sync/github-sync-wrapper.js +220 -0
  209. package/dist/src/sync/github-sync-wrapper.js.map +1 -0
  210. package/dist/src/sync/jira-sync-wrapper.d.ts +155 -0
  211. package/dist/src/sync/jira-sync-wrapper.d.ts.map +1 -0
  212. package/dist/src/sync/jira-sync-wrapper.js +175 -0
  213. package/dist/src/sync/jira-sync-wrapper.js.map +1 -0
  214. package/dist/src/utils/feature-id-derivation.d.ts +58 -0
  215. package/dist/src/utils/feature-id-derivation.d.ts.map +1 -0
  216. package/dist/src/utils/feature-id-derivation.js +77 -0
  217. package/dist/src/utils/feature-id-derivation.js.map +1 -0
  218. package/package.json +1 -1
  219. package/plugins/specweave/commands/specweave-discrepancies.md +141 -0
  220. package/plugins/specweave/commands/specweave-discrepancy-to-increment.md +160 -0
  221. package/plugins/specweave/commands/specweave-jobs.md +45 -2
  222. package/plugins/specweave/commands/specweave-notifications.md +92 -0
  223. package/plugins/specweave/commands/specweave-sync-logs.md +131 -0
  224. package/plugins/specweave/commands/specweave-sync-monitor.md +57 -0
  225. package/plugins/specweave/hooks/hooks.json +3 -3
  226. package/plugins/specweave/hooks/lib/scheduler-startup.sh +72 -0
  227. package/plugins/specweave/hooks/universal/dispatcher.mjs +246 -0
  228. package/plugins/specweave/hooks/universal/session-start.cmd +16 -0
  229. package/plugins/specweave/hooks/universal/session-start.ps1 +16 -0
  230. package/plugins/specweave/hooks/v2/dispatchers/session-start.sh +14 -5
  231. package/plugins/specweave/lib/vendor/core/types/increment-metadata.d.ts +5 -2
  232. package/plugins/specweave/skills/discrepancy-viewer.md +154 -0
  233. package/plugins/specweave-github/hooks/.specweave/logs/hooks-debug.log +34 -0
  234. package/plugins/specweave-release/hooks/.specweave/logs/dora-tracking.log +51 -0
@@ -0,0 +1,57 @@
1
+ # Sync Monitor Dashboard
2
+
3
+ Show sync orchestration status at a glance - jobs, notifications, and recent activity.
4
+
5
+ ## Usage
6
+
7
+ ```bash
8
+ /specweave:sync-monitor # Show dashboard
9
+ /specweave:sync-monitor --json # JSON output for scripting
10
+ ```
11
+
12
+ ## Arguments
13
+
14
+ - `--json`: Output machine-readable JSON instead of formatted dashboard
15
+
16
+ ## Workflow
17
+
18
+ 1. **Fetch dashboard data** from DashboardDataProvider:
19
+ - Get all scheduled job statuses (real-time)
20
+ - Get notification summary (5s cache)
21
+ - Get last 24h sync activity (1m cache)
22
+
23
+ 2. **Display formatted dashboard**:
24
+ ```
25
+ ╔══════════════════════════════════════════════════════════════╗
26
+ ║ SYNC MONITOR DASHBOARD ║
27
+ ╠══════════════════════════════════════════════════════════════╣
28
+ ║ SCHEDULED JOBS ║
29
+ ╟──────────────────────────────────────────────────────────────╢
30
+ ║ external-sync │ ✅ idle │ Last: 5m ago │ Next: 10m ║
31
+ ║ discrepancy-check │ 🔄 running │ Started: 2m ago ║
32
+ ║ living-docs-sync │ ⏸️ disabled ║
33
+ ╠══════════════════════════════════════════════════════════════╣
34
+ ║ PENDING NOTIFICATIONS (3) ║
35
+ ╟──────────────────────────────────────────────────────────────╢
36
+ ║ ❗ CRITICAL: GitHub sync failed (rate limited) ║
37
+ ║ ⚠️ WARNING: 2 discrepancies detected in FS-045 ║
38
+ ║ ℹ️ INFO: 107 items imported from JIRA (project CORE) ║
39
+ ╠══════════════════════════════════════════════════════════════╣
40
+ ║ RECENT SYNC ACTIVITY (last 24h) ║
41
+ ╟──────────────────────────────────────────────────────────────╢
42
+ ║ GitHub: 45 synced │ JIRA: 12 synced │ ADO: 0 synced ║
43
+ ║ Success: 55 │ Failed: 2 │ Skipped (no permission): 8 ║
44
+ ╚══════════════════════════════════════════════════════════════╝
45
+ ```
46
+
47
+ ## Output
48
+
49
+ - **Jobs Section**: Shows each scheduled job with status emoji, last run, next run
50
+ - **Notifications Section**: Shows pending notification count and recent items
51
+ - **Activity Section**: Shows last 24h sync stats by platform and result
52
+
53
+ ## Related
54
+
55
+ - `/specweave:notifications`: Manage notifications
56
+ - `/specweave:discrepancies`: View and act on discrepancies
57
+ - `/specweave:sync-logs`: Query sync audit logs
@@ -5,7 +5,7 @@
5
5
  "hooks": [
6
6
  {
7
7
  "type": "command",
8
- "command": "${CLAUDE_PLUGIN_ROOT}/hooks/v2/dispatchers/session-start.sh"
8
+ "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/universal/dispatcher.mjs\" session-start"
9
9
  }
10
10
  ]
11
11
  }
@@ -17,7 +17,7 @@
17
17
  "hooks": [
18
18
  {
19
19
  "type": "command",
20
- "command": "${CLAUDE_PLUGIN_ROOT}/hooks/v2/guards/completion-guard.sh"
20
+ "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/universal/dispatcher.mjs\" completion-guard"
21
21
  }
22
22
  ]
23
23
  }
@@ -29,7 +29,7 @@
29
29
  "hooks": [
30
30
  {
31
31
  "type": "command",
32
- "command": "${CLAUDE_PLUGIN_ROOT}/hooks/v2/dispatchers/post-tool-use.sh"
32
+ "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/universal/dispatcher.mjs\" post-tool-use"
33
33
  }
34
34
  ]
35
35
  }
@@ -0,0 +1,72 @@
1
+ #!/bin/bash
2
+ # scheduler-startup.sh - Check for due jobs on session start
3
+ # Called from session-start hook to initialize scheduler
4
+ set -e
5
+
6
+ # Skip if hooks disabled
7
+ [[ "${SPECWEAVE_DISABLE_HOOKS:-0}" == "1" ]] && exit 0
8
+
9
+ # Find project root
10
+ PROJECT_ROOT="$PWD"
11
+ while [[ "$PROJECT_ROOT" != "/" ]] && [[ ! -d "$PROJECT_ROOT/.specweave" ]]; do
12
+ PROJECT_ROOT=$(dirname "$PROJECT_ROOT")
13
+ done
14
+
15
+ # Exit if no .specweave directory
16
+ [[ ! -d "$PROJECT_ROOT/.specweave" ]] && exit 0
17
+
18
+ # Paths
19
+ SCHEDULED_JOBS_FILE="$PROJECT_ROOT/.specweave/state/scheduled-jobs.json"
20
+ CONFIG_FILE="$PROJECT_ROOT/.specweave/config.json"
21
+
22
+ # Check if scheduler is enabled
23
+ if [[ -f "$CONFIG_FILE" ]]; then
24
+ # Check if sync.orchestration.scheduler.enabled is true
25
+ # Use node for reliable JSON parsing
26
+ SCHEDULER_ENABLED=$(node -e "
27
+ try {
28
+ const config = require('$CONFIG_FILE');
29
+ const enabled = config?.sync?.orchestration?.scheduler?.enabled ?? false;
30
+ console.log(enabled ? 'true' : 'false');
31
+ } catch(e) {
32
+ console.log('false');
33
+ }
34
+ " 2>/dev/null || echo "false")
35
+
36
+ if [[ "$SCHEDULER_ENABLED" != "true" ]]; then
37
+ exit 0
38
+ fi
39
+ fi
40
+
41
+ # Check if scheduled jobs file exists
42
+ if [[ ! -f "$SCHEDULED_JOBS_FILE" ]]; then
43
+ exit 0
44
+ fi
45
+
46
+ # Use node to check for due jobs (robust JSON parsing)
47
+ DUE_JOBS=$(node -e "
48
+ const fs = require('fs');
49
+ try {
50
+ const data = JSON.parse(fs.readFileSync('$SCHEDULED_JOBS_FILE', 'utf-8'));
51
+ const now = Date.now();
52
+ const dueJobs = (data.jobs || []).filter(job => {
53
+ if (!job.schedule.enabled || job.status !== 'idle') return false;
54
+ if (!job.schedule.nextRun) return true;
55
+ return new Date(job.schedule.nextRun).getTime() <= now;
56
+ });
57
+ console.log(JSON.stringify(dueJobs.map(j => j.id)));
58
+ } catch(e) {
59
+ console.log('[]');
60
+ }
61
+ " 2>/dev/null || echo "[]")
62
+
63
+ # Exit if no due jobs
64
+ if [[ "$DUE_JOBS" == "[]" ]]; then
65
+ exit 0
66
+ fi
67
+
68
+ # Log due jobs (for debugging)
69
+ echo "📅 Due sync jobs: $DUE_JOBS" >> "$PROJECT_ROOT/.specweave/logs/scheduler.log" 2>/dev/null || true
70
+
71
+ # Output status (will be captured by hook system)
72
+ echo "{\"continue\": true, \"systemMessage\": \"📅 Scheduled sync jobs ready to run. Use /specweave:sync-now to execute.\"}"
@@ -0,0 +1,246 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Universal Hook Dispatcher (Cross-Platform)
4
+ *
5
+ * Routes hook calls to the appropriate TypeScript implementation.
6
+ * Works on Windows, macOS, and Linux.
7
+ *
8
+ * Usage:
9
+ * node dispatcher.mjs <hook-type>
10
+ *
11
+ * Where hook-type is one of:
12
+ * - session-start
13
+ * - post-tool-use
14
+ * - completion-guard
15
+ *
16
+ * @module hooks/universal/dispatcher
17
+ */
18
+
19
+ import { spawn } from 'child_process';
20
+ import { fileURLToPath } from 'url';
21
+ import { dirname, join, resolve } from 'path';
22
+ import { existsSync } from 'fs';
23
+
24
+ const __filename = fileURLToPath(import.meta.url);
25
+ const __dirname = dirname(__filename);
26
+
27
+ // Hook type from arguments
28
+ const hookType = process.argv[2] || 'unknown';
29
+
30
+ /**
31
+ * Find the dist/hooks directory
32
+ */
33
+ function findHooksDir() {
34
+ // Try multiple locations
35
+ const candidates = [
36
+ // Production: node_modules/specweave/dist/hooks
37
+ join(__dirname, '..', '..', '..', '..', 'node_modules', 'specweave', 'dist', 'hooks'),
38
+ // Development: project root dist/hooks
39
+ join(__dirname, '..', '..', '..', '..', 'dist', 'hooks'),
40
+ // Relative to this file
41
+ join(__dirname, '..', '..', '..', '..', 'src', 'hooks'),
42
+ ];
43
+
44
+ for (const candidate of candidates) {
45
+ const resolved = resolve(candidate);
46
+ if (existsSync(resolved)) {
47
+ return resolved;
48
+ }
49
+ }
50
+
51
+ return null;
52
+ }
53
+
54
+ /**
55
+ * Run a hook script
56
+ */
57
+ async function runHook(scriptName) {
58
+ const hooksDir = findHooksDir();
59
+ if (!hooksDir) {
60
+ // No hooks directory - just continue
61
+ console.log(JSON.stringify({ continue: true }));
62
+ return;
63
+ }
64
+
65
+ const scriptPath = join(hooksDir, scriptName);
66
+ if (!existsSync(scriptPath) && !existsSync(scriptPath + '.js')) {
67
+ console.log(JSON.stringify({ continue: true }));
68
+ return;
69
+ }
70
+
71
+ // Spawn node to run the script
72
+ const child = spawn(process.execPath, [scriptPath], {
73
+ stdio: ['inherit', 'inherit', 'inherit'],
74
+ windowsHide: true,
75
+ });
76
+
77
+ return new Promise((resolve) => {
78
+ child.on('exit', (code) => resolve(code || 0));
79
+ child.on('error', () => {
80
+ console.log(JSON.stringify({ continue: true }));
81
+ resolve(1);
82
+ });
83
+ });
84
+ }
85
+
86
+ /**
87
+ * Cached Git Bash path (computed once per session)
88
+ * undefined = not yet checked, null = checked and not found, string = path found
89
+ */
90
+ let gitBashCache = undefined;
91
+
92
+ /**
93
+ * Find Git Bash on Windows (with caching)
94
+ *
95
+ * Checks common Git for Windows installation paths.
96
+ * Caches result to avoid repeated filesystem checks.
97
+ */
98
+ function findGitBash() {
99
+ // Return cached result if available
100
+ if (gitBashCache !== undefined) {
101
+ return gitBashCache;
102
+ }
103
+
104
+ const gitBashPaths = [
105
+ // Environment variable paths with proper fallbacks
106
+ join(process.env.PROGRAMFILES || 'C:\\Program Files', 'Git', 'bin', 'bash.exe'),
107
+ join(process.env['PROGRAMFILES(X86)'] || 'C:\\Program Files (x86)', 'Git', 'bin', 'bash.exe'),
108
+ join(process.env.LOCALAPPDATA || '', 'Programs', 'Git', 'bin', 'bash.exe'),
109
+ // Hardcoded fallbacks for edge cases where env vars are missing
110
+ 'C:\\Program Files\\Git\\bin\\bash.exe',
111
+ 'C:\\Program Files (x86)\\Git\\bin\\bash.exe',
112
+ 'C:\\Git\\bin\\bash.exe',
113
+ ];
114
+
115
+ for (const p of gitBashPaths) {
116
+ if (p && existsSync(p)) {
117
+ gitBashCache = p;
118
+ return p;
119
+ }
120
+ }
121
+
122
+ gitBashCache = null;
123
+ return null;
124
+ }
125
+
126
+ /**
127
+ * Fallback to bash script if TypeScript not built
128
+ *
129
+ * @param bashScript - Name of the bash script (e.g., 'post-tool-use.sh')
130
+ * @param subdir - Subdirectory under v2 (e.g., 'dispatchers', 'guards')
131
+ */
132
+ async function fallbackToBash(bashScript, subdir = 'dispatchers') {
133
+ const isWindows = process.platform === 'win32';
134
+ const bashDir = join(__dirname, '..', 'v2', subdir);
135
+ const scriptPath = join(bashDir, bashScript);
136
+
137
+ if (!existsSync(scriptPath)) {
138
+ console.log(JSON.stringify({ continue: true }));
139
+ return;
140
+ }
141
+
142
+ if (isWindows) {
143
+ // Strategy 1: Git Bash (preferred - most common)
144
+ const bashExe = findGitBash();
145
+ if (bashExe) {
146
+ const child = spawn(bashExe, [scriptPath], {
147
+ stdio: ['inherit', 'inherit', 'inherit'],
148
+ windowsHide: true,
149
+ });
150
+ return new Promise((resolve) => {
151
+ child.on('exit', (code) => resolve(code || 0));
152
+ child.on('error', () => {
153
+ console.log(JSON.stringify({ continue: true }));
154
+ resolve(1);
155
+ });
156
+ });
157
+ }
158
+
159
+ // Strategy 2: WSL (if Git Bash not available) - FALLBACK only
160
+ const wslPath = join(process.env.SYSTEMROOT || 'C:\\Windows', 'System32', 'wsl.exe');
161
+ if (existsSync(wslPath)) {
162
+ // Convert Windows path to WSL path:
163
+ // 1. Backslashes to forward slashes: C:\path\file -> C:/path/file
164
+ // 2. Drive letter to /mnt/: C:/path/file -> /mnt/c/path/file
165
+ // NOTE: Handle BOTH uppercase and lowercase drive letters (C: and c:)
166
+ const wslScriptPath = scriptPath
167
+ .replace(/\\/g, '/')
168
+ .replace(/^([A-Za-z]):/, (_, d) => `/mnt/${d.toLowerCase()}`);
169
+ const child = spawn('wsl', ['bash', wslScriptPath], {
170
+ stdio: ['inherit', 'inherit', 'inherit'],
171
+ windowsHide: true,
172
+ });
173
+ return new Promise((resolve) => {
174
+ child.on('exit', (code) => resolve(code || 0));
175
+ child.on('error', () => {
176
+ console.log(JSON.stringify({ continue: true }));
177
+ resolve(1);
178
+ });
179
+ });
180
+ }
181
+
182
+ // Strategy 3: No bash available - output warning and continue
183
+ // Hooks should not block Claude Code operation
184
+ console.log(JSON.stringify({
185
+ continue: true,
186
+ systemMessage: 'SpecWeave hooks require Git Bash on Windows. Install from https://git-scm.com'
187
+ }));
188
+ return;
189
+ }
190
+
191
+ // POSIX (macOS, Linux) - run directly
192
+ const child = spawn('bash', [scriptPath], {
193
+ stdio: ['inherit', 'inherit', 'inherit'],
194
+ });
195
+ return new Promise((resolve) => {
196
+ child.on('exit', (code) => resolve(code || 0));
197
+ child.on('error', () => {
198
+ console.log(JSON.stringify({ continue: true }));
199
+ resolve(1);
200
+ });
201
+ });
202
+ }
203
+
204
+ // Main routing
205
+ async function main() {
206
+ const isWindows = process.platform === 'win32';
207
+
208
+ try {
209
+ switch (hookType) {
210
+ case 'session-start':
211
+ // CRITICAL: On Windows, ALWAYS use TypeScript implementation
212
+ // Bash nohup/disown is unreliable in Git Bash (process may terminate early)
213
+ // TypeScript uses proper Windows detached spawn with windowsHide
214
+ if (isWindows) {
215
+ await runHook('session-start.js');
216
+ } else {
217
+ // POSIX: try TypeScript first (preferred), fallback to bash for compatibility
218
+ try {
219
+ await runHook('session-start.js');
220
+ } catch {
221
+ await fallbackToBash('session-start.sh', 'dispatchers');
222
+ }
223
+ }
224
+ break;
225
+
226
+ case 'post-tool-use':
227
+ // Currently only bash implementation
228
+ // On Windows without Git Bash, will gracefully skip
229
+ await fallbackToBash('post-tool-use.sh', 'dispatchers');
230
+ break;
231
+
232
+ case 'completion-guard':
233
+ // Guards are in a different subdirectory
234
+ // On Windows without Git Bash, will gracefully skip
235
+ await fallbackToBash('completion-guard.sh', 'guards');
236
+ break;
237
+
238
+ default:
239
+ console.log(JSON.stringify({ continue: true, error: `Unknown hook type: ${hookType}` }));
240
+ }
241
+ } catch (err) {
242
+ console.log(JSON.stringify({ continue: true, error: String(err) }));
243
+ }
244
+ }
245
+
246
+ main();
@@ -0,0 +1,16 @@
1
+ @echo off
2
+ :: Universal Session Start Hook for Windows
3
+ :: Calls the Node.js dispatcher
4
+
5
+ :: Find node.exe
6
+ where node >nul 2>&1
7
+ if %ERRORLEVEL% neq 0 (
8
+ echo {"continue": true, "error": "Node.js not found"}
9
+ exit /b 0
10
+ )
11
+
12
+ :: Get the directory of this script
13
+ set "SCRIPT_DIR=%~dp0"
14
+
15
+ :: Run the dispatcher
16
+ node "%SCRIPT_DIR%dispatcher.mjs" session-start
@@ -0,0 +1,16 @@
1
+ # Universal Session Start Hook for Windows PowerShell
2
+ # Calls the Node.js dispatcher for cross-platform compatibility
3
+
4
+ # Find node.exe
5
+ $nodePath = Get-Command node -ErrorAction SilentlyContinue
6
+
7
+ if (-not $nodePath) {
8
+ Write-Host '{"continue": true, "error": "Node.js not found"}'
9
+ exit 0
10
+ }
11
+
12
+ # Get script directory
13
+ $scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
14
+
15
+ # Run the dispatcher
16
+ & node "$scriptDir\dispatcher.mjs" session-start
@@ -15,10 +15,19 @@ done
15
15
  # Consume stdin
16
16
  cat > /dev/null
17
17
 
18
- PROCESSOR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../queue" && pwd)/processor.sh"
19
- [[ ! -f "$PROCESSOR" ]] && exit 0
18
+ HOOK_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
19
+ PROCESSOR="$HOOK_DIR/../queue/processor.sh"
20
+ SCHEDULER_STARTUP="$HOOK_DIR/../../lib/scheduler-startup.sh"
21
+
22
+ # Launch queue processor in background (daemon mode)
23
+ if [[ -f "$PROCESSOR" ]]; then
24
+ nohup bash "$PROCESSOR" --daemon > /dev/null 2>&1 &
25
+ disown 2>/dev/null
26
+ fi
27
+
28
+ # Check for due scheduled jobs (non-blocking)
29
+ if [[ -f "$SCHEDULER_STARTUP" ]]; then
30
+ bash "$SCHEDULER_STARTUP" 2>/dev/null || true
31
+ fi
20
32
 
21
- # Launch processor in background (daemon mode)
22
- nohup bash "$PROCESSOR" --daemon > /dev/null 2>&1 &
23
- disown 2>/dev/null
24
33
  exit 0
@@ -247,6 +247,11 @@ export interface ExternalContainerContext {
247
247
  }
248
248
  /**
249
249
  * Extended increment metadata with multi-project support (v0.29.0+)
250
+ *
251
+ * NOTE (v0.29.0): featureId field was REMOVED
252
+ * Feature ID is derived from increment number: 0081 → FS-081
253
+ * Use deriveFeatureId() from src/utils/feature-id-derivation.ts
254
+ * See ADR-0140 for rationale
250
255
  */
251
256
  export interface IncrementMetadataV2 extends IncrementMetadata {
252
257
  /** Single project ID (backward compatible) */
@@ -255,8 +260,6 @@ export interface IncrementMetadataV2 extends IncrementMetadata {
255
260
  multiProject?: MultiProjectUserStory;
256
261
  /** External container context for 2-level directory structure */
257
262
  externalContainer?: ExternalContainerContext;
258
- /** Feature ID this increment belongs to */
259
- featureId?: string;
260
263
  /** Epic ID if part of an epic */
261
264
  epicId?: string;
262
265
  }
@@ -0,0 +1,154 @@
1
+ # Discrepancy Viewer Skill
2
+
3
+ View and manage brownfield documentation discrepancies.
4
+
5
+ **Activates for**: discrepancies, documentation gaps, missing docs, stale docs, knowledge gaps, brownfield analysis results, DISC-0001, view discrepancy, list discrepancies
6
+
7
+ ## Context
8
+
9
+ Brownfield discrepancies are documentation gaps detected during brownfield analysis:
10
+
11
+ | Type | Description |
12
+ |------|-------------|
13
+ | `missing-docs` | Code exists but has no documentation |
14
+ | `stale-docs` | Code changed but docs weren't updated |
15
+ | `knowledge-gap` | Module only one person has committed to |
16
+ | `orphan-doc` | Documentation for deleted code |
17
+ | `missing-adr` | Significant pattern without ADR |
18
+
19
+ ## How to View Discrepancies
20
+
21
+ ### List All Pending
22
+
23
+ ```typescript
24
+ import { BrownfieldDiscrepancyManager } from 'specweave/core/discrepancy';
25
+
26
+ const manager = new BrownfieldDiscrepancyManager(projectPath);
27
+ const discrepancies = await manager.listDiscrepancies();
28
+
29
+ // Display in table format
30
+ console.log('📋 BROWNFIELD DISCREPANCIES');
31
+ console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
32
+ console.log('ID Type Priority Module Summary');
33
+ console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
34
+
35
+ for (const disc of discrepancies) {
36
+ const priorityIcon = {
37
+ critical: '🔴',
38
+ high: '🟠',
39
+ medium: '🟡',
40
+ low: '🟢'
41
+ }[disc.priority];
42
+
43
+ console.log(`${disc.id} ${disc.type.padEnd(15)} ${priorityIcon} ${disc.priority.padEnd(8)} ${disc.module.padEnd(16)} ${disc.summary.slice(0, 30)}...`);
44
+ }
45
+ ```
46
+
47
+ ### Filter by Module
48
+
49
+ ```typescript
50
+ const discrepancies = await manager.listDiscrepancies({
51
+ module: 'payment-service'
52
+ });
53
+ ```
54
+
55
+ ### Filter by Type
56
+
57
+ ```typescript
58
+ const discrepancies = await manager.listDiscrepancies({
59
+ type: 'missing-docs'
60
+ });
61
+ ```
62
+
63
+ ### Filter by Priority
64
+
65
+ ```typescript
66
+ const discrepancies = await manager.listDiscrepancies({
67
+ priority: 'critical'
68
+ });
69
+ ```
70
+
71
+ ### View Single Discrepancy
72
+
73
+ ```typescript
74
+ const disc = await manager.getDiscrepancy('DISC-0001');
75
+
76
+ console.log(`
77
+ 🔍 DISCREPANCY DETAILS
78
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
79
+
80
+ ID: ${disc.id}
81
+ Type: ${disc.type}
82
+ Priority: ${disc.priority}
83
+ Module: ${disc.module}
84
+ Status: ${disc.status}
85
+ Confidence: ${disc.confidence}%
86
+
87
+ Summary: ${disc.summary}
88
+ Details: ${disc.details}
89
+
90
+ Code Location: ${disc.codeLocation || 'N/A'}
91
+ Doc Location: ${disc.docLocation || 'N/A'}
92
+
93
+ Detected: ${disc.detectedAt}
94
+ Last Check: ${disc.lastChecked}
95
+ `);
96
+ ```
97
+
98
+ ### Ignore a Discrepancy
99
+
100
+ ```typescript
101
+ await manager.ignoreDiscrepancy('DISC-0001', 'False positive - test code');
102
+ ```
103
+
104
+ ## Output Format
105
+
106
+ ### Table Format (Default)
107
+
108
+ ```
109
+ 📋 BROWNFIELD DISCREPANCIES (15 pending)
110
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
111
+
112
+ ID Type Priority Module Summary
113
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
114
+ DISC-0001 missing-docs 🔴 critical payment-service 12 undocumented exports
115
+ DISC-0002 stale-docs 🟠 high auth Login flow docs outdated
116
+ DISC-0003 knowledge-gap 🟡 medium legacy-adapter Single contributor module
117
+ DISC-0004 missing-adr 🟢 low cache No ADR for caching strategy
118
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
119
+
120
+ Use '/specweave:discrepancies show <ID>' for details
121
+ Use '/specweave:discrepancy-to-increment <ID> <ID>...' to create an increment
122
+ ```
123
+
124
+ ### Statistics
125
+
126
+ ```
127
+ 📊 DISCREPANCY STATS
128
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
129
+
130
+ Total: 47
131
+ Pending: 15
132
+ In Progress: 5
133
+ Resolved: 25
134
+ Ignored: 2
135
+
136
+ By Type:
137
+ missing-docs: 22 (47%)
138
+ stale-docs: 8 (17%)
139
+ knowledge-gap: 7 (15%)
140
+ orphan-doc: 5 (11%)
141
+ missing-adr: 5 (11%)
142
+
143
+ By Priority:
144
+ Critical: 3
145
+ High: 8
146
+ Medium: 12
147
+ Low: 24
148
+ ```
149
+
150
+ ## Related
151
+
152
+ - `/specweave:discrepancy-to-increment` - Convert discrepancies to increments
153
+ - `/specweave:jobs` - Monitor brownfield analysis jobs
154
+ - `brownfield-analyzer` skill - Run new analysis
@@ -24,3 +24,37 @@
24
24
  [Mon Dec 1 15:44:14 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
25
25
  [Mon Dec 1 15:44:15 EST 2025] [GitHub] 🔗 GitHub sync hook fired
26
26
  [Mon Dec 1 15:44:15 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
27
+ [Mon Dec 1 20:26:17 EST 2025] [GitHub] 🔗 GitHub sync hook fired
28
+ [Mon Dec 1 20:26:17 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
29
+ [Mon Dec 1 20:26:17 EST 2025] [GitHub] 🔗 GitHub sync hook fired
30
+ [Mon Dec 1 20:26:17 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
31
+ [Mon Dec 1 20:26:17 EST 2025] [GitHub] 🔗 GitHub sync hook fired
32
+ [Mon Dec 1 20:26:17 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
33
+ [Mon Dec 1 20:26:17 EST 2025] [GitHub] 🔗 GitHub sync hook fired
34
+ [Mon Dec 1 20:26:17 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
35
+ [Mon Dec 1 20:26:17 EST 2025] [GitHub] 🔗 GitHub sync hook fired
36
+ [Mon Dec 1 20:26:17 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
37
+ [Mon Dec 1 20:26:18 EST 2025] [GitHub] 🔗 GitHub sync hook fired
38
+ [Mon Dec 1 20:26:18 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
39
+ [Mon Dec 1 20:26:18 EST 2025] [GitHub] 🔗 GitHub sync hook fired
40
+ [Mon Dec 1 20:26:18 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
41
+ [Mon Dec 1 20:26:18 EST 2025] [GitHub] 🔗 GitHub sync hook fired
42
+ [Mon Dec 1 20:26:18 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
43
+ [Mon Dec 1 20:26:27 EST 2025] [GitHub] 🔗 GitHub sync hook fired
44
+ [Mon Dec 1 20:26:27 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
45
+ [Mon Dec 1 20:26:27 EST 2025] [GitHub] 🔗 GitHub sync hook fired
46
+ [Mon Dec 1 20:26:27 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
47
+ [Mon Dec 1 20:26:27 EST 2025] [GitHub] 🔗 GitHub sync hook fired
48
+ [Mon Dec 1 20:26:27 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
49
+ [Mon Dec 1 20:37:58 EST 2025] [GitHub] 🔗 GitHub sync hook fired
50
+ [Mon Dec 1 20:37:58 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
51
+ [Mon Dec 1 20:37:58 EST 2025] [GitHub] 🔗 GitHub sync hook fired
52
+ [Mon Dec 1 20:37:58 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
53
+ [Mon Dec 1 20:37:58 EST 2025] [GitHub] 🔗 GitHub sync hook fired
54
+ [Mon Dec 1 20:37:58 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
55
+ [Mon Dec 1 20:40:32 EST 2025] [GitHub] 🔗 GitHub sync hook fired
56
+ [Mon Dec 1 20:40:32 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
57
+ [Mon Dec 1 20:40:32 EST 2025] [GitHub] 🔗 GitHub sync hook fired
58
+ [Mon Dec 1 20:40:32 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
59
+ [Mon Dec 1 20:40:33 EST 2025] [GitHub] 🔗 GitHub sync hook fired
60
+ [Mon Dec 1 20:40:33 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Documents/Projects/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync