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,317 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Background Event Processor (Cross-Platform)
4
+ *
5
+ * Processes queued events asynchronously, routes to specialized handlers.
6
+ * Works on Windows, macOS, and Linux without WSL requirement.
7
+ *
8
+ * Usage: node processor.js [--daemon]
9
+ *
10
+ * Event routing:
11
+ * - increment.created/done/archived/reopened -> living-specs-handler
12
+ * - user-story.completed/reopened -> status-line-handler
13
+ * - task.updated/spec.updated -> living-docs-handler (legacy)
14
+ *
15
+ * Self-terminates after 60s of idle
16
+ *
17
+ * @module hooks/processor
18
+ */
19
+ import * as path from 'path';
20
+ import * as fs from 'fs';
21
+ import { spawn } from 'child_process';
22
+ import { findProjectRoot, FileLock, appendLog, isWindows, } from './platform.js';
23
+ // Configuration
24
+ const IDLE_TIMEOUT = 60; // seconds before self-termination
25
+ const HANDLER_TIMEOUT = 30000; // ms per handler call
26
+ const STALE_LOCK_SECONDS = 300; // 5 minutes
27
+ /**
28
+ * Initialize processor state
29
+ */
30
+ function initState(projectRoot, daemonMode) {
31
+ const specweavePath = path.join(projectRoot, '.specweave');
32
+ return {
33
+ projectRoot,
34
+ queueDir: path.join(specweavePath, 'state', 'event-queue'),
35
+ handlerDir: path.join(projectRoot, 'plugins', 'specweave', 'hooks', 'v2', 'handlers'),
36
+ logFile: path.join(specweavePath, 'logs', 'processor.log'),
37
+ pidFile: path.join(specweavePath, 'state', '.processor.pid'),
38
+ lock: new FileLock(path.join(specweavePath, 'state', '.processor')),
39
+ daemonMode,
40
+ idleCount: 0,
41
+ };
42
+ }
43
+ /**
44
+ * Dequeue an event from the queue directory
45
+ */
46
+ function dequeue(state) {
47
+ try {
48
+ if (!fs.existsSync(state.queueDir)) {
49
+ return null;
50
+ }
51
+ // Get oldest event file
52
+ const files = fs.readdirSync(state.queueDir)
53
+ .filter((f) => f.endsWith('.json'))
54
+ .sort(); // Oldest first (timestamp-based naming)
55
+ if (files.length === 0) {
56
+ return null;
57
+ }
58
+ const eventFile = path.join(state.queueDir, files[0]);
59
+ const content = fs.readFileSync(eventFile, 'utf-8');
60
+ // Delete after reading
61
+ fs.unlinkSync(eventFile);
62
+ return JSON.parse(content);
63
+ }
64
+ catch {
65
+ return null;
66
+ }
67
+ }
68
+ /**
69
+ * Run a handler script with timeout
70
+ */
71
+ async function runHandler(handlerPath, eventType, eventData, state) {
72
+ if (!fs.existsSync(handlerPath)) {
73
+ return;
74
+ }
75
+ return new Promise((resolve) => {
76
+ let child;
77
+ let timeoutId;
78
+ const cleanup = () => {
79
+ clearTimeout(timeoutId);
80
+ try {
81
+ child?.kill();
82
+ }
83
+ catch {
84
+ // Ignore kill errors
85
+ }
86
+ resolve();
87
+ };
88
+ try {
89
+ if (isWindows()) {
90
+ // On Windows, run bash scripts via Git Bash if available, or skip
91
+ const gitBashPath = findGitBash();
92
+ if (gitBashPath) {
93
+ child = spawn(gitBashPath, [handlerPath, eventType, eventData], {
94
+ cwd: state.projectRoot,
95
+ stdio: 'ignore',
96
+ windowsHide: true,
97
+ });
98
+ }
99
+ else {
100
+ // No Git Bash - try to run via WSL if available (FALLBACK only)
101
+ const wslPath = path.join(process.env.SYSTEMROOT || 'C:\\Windows', 'System32', 'wsl.exe');
102
+ if (fs.existsSync(wslPath)) {
103
+ // Convert Windows path to WSL path:
104
+ // 1. Backslashes to forward slashes: C:\path\file -> C:/path/file
105
+ // 2. Drive letter to /mnt/: C:/path/file -> /mnt/c/path/file
106
+ // NOTE: Handle BOTH uppercase and lowercase drive letters (C: and c:)
107
+ const wslHandlerPath = handlerPath
108
+ .replace(/\\/g, '/')
109
+ .replace(/^([A-Za-z]):/, (_, drive) => `/mnt/${drive.toLowerCase()}`);
110
+ child = spawn('wsl', ['bash', wslHandlerPath, eventType, eventData], {
111
+ cwd: state.projectRoot,
112
+ stdio: 'ignore',
113
+ windowsHide: true,
114
+ });
115
+ }
116
+ else {
117
+ // No bash available - skip handler
118
+ appendLog(state.logFile, `Skipped handler (no bash): ${path.basename(handlerPath)}`);
119
+ resolve();
120
+ return;
121
+ }
122
+ }
123
+ }
124
+ else {
125
+ // POSIX - run directly
126
+ child = spawn('bash', [handlerPath, eventType, eventData], {
127
+ cwd: state.projectRoot,
128
+ stdio: 'ignore',
129
+ });
130
+ }
131
+ // Set timeout
132
+ timeoutId = setTimeout(() => {
133
+ appendLog(state.logFile, `Handler timeout: ${path.basename(handlerPath)}`);
134
+ cleanup();
135
+ }, HANDLER_TIMEOUT);
136
+ child.on('exit', cleanup);
137
+ child.on('error', cleanup);
138
+ }
139
+ catch (err) {
140
+ appendLog(state.logFile, `Handler error: ${err}`);
141
+ resolve();
142
+ }
143
+ });
144
+ }
145
+ /**
146
+ * Cached Git Bash path (computed once at module load)
147
+ * undefined = not yet checked, null = checked and not found, string = path found
148
+ */
149
+ let gitBashPathCache = undefined;
150
+ /**
151
+ * Find Git Bash on Windows (with caching)
152
+ *
153
+ * Caches the result to avoid repeated filesystem checks.
154
+ * On Windows, checks common Git installation locations.
155
+ */
156
+ function findGitBash() {
157
+ // Return cached result if available
158
+ if (gitBashPathCache !== undefined) {
159
+ return gitBashPathCache;
160
+ }
161
+ if (!isWindows()) {
162
+ gitBashPathCache = null;
163
+ return null;
164
+ }
165
+ const possiblePaths = [
166
+ // Standard Git for Windows installation paths
167
+ path.join(process.env.PROGRAMFILES || 'C:\\Program Files', 'Git', 'bin', 'bash.exe'),
168
+ path.join(process.env['PROGRAMFILES(X86)'] || 'C:\\Program Files (x86)', 'Git', 'bin', 'bash.exe'),
169
+ // User-specific installation
170
+ path.join(process.env.LOCALAPPDATA || '', 'Programs', 'Git', 'bin', 'bash.exe'),
171
+ // Portable Git / custom installation
172
+ 'C:\\Git\\bin\\bash.exe',
173
+ ];
174
+ for (const bashPath of possiblePaths) {
175
+ if (bashPath && fs.existsSync(bashPath)) {
176
+ gitBashPathCache = bashPath;
177
+ return bashPath;
178
+ }
179
+ }
180
+ gitBashPathCache = null;
181
+ return null;
182
+ }
183
+ /**
184
+ * Process a single event
185
+ */
186
+ async function processEvent(event, state) {
187
+ const { type, data } = event;
188
+ appendLog(state.logFile, `Processing: ${type} (${data})`);
189
+ const handlers = [
190
+ // EDA Event Routing (new architecture)
191
+ {
192
+ pattern: /^increment\.(created|done|archived|reopened)$/,
193
+ handlers: ['living-specs-handler.sh', 'status-line-handler.sh'],
194
+ },
195
+ {
196
+ pattern: /^user-story\.(completed|reopened)$/,
197
+ handlers: ['status-line-handler.sh'],
198
+ },
199
+ // Legacy event routing (backward compat)
200
+ {
201
+ pattern: /^(task|spec)\.updated$/,
202
+ handlers: ['living-docs-handler.sh', 'ac-validation-handler.sh'],
203
+ },
204
+ {
205
+ pattern: /^metadata\.changed$/,
206
+ handlers: ['github-sync-handler.sh'],
207
+ },
208
+ ];
209
+ for (const route of handlers) {
210
+ if (route.pattern.test(type)) {
211
+ for (const handlerName of route.handlers) {
212
+ const handlerPath = path.join(state.handlerDir, handlerName);
213
+ await runHandler(handlerPath, type, data, state);
214
+ }
215
+ return;
216
+ }
217
+ }
218
+ appendLog(state.logFile, `Unknown event type: ${type}`);
219
+ }
220
+ /**
221
+ * Main processing loop
222
+ */
223
+ async function mainLoop(state) {
224
+ appendLog(state.logFile, `Processor started (PID: ${process.pid}, timeout: ${IDLE_TIMEOUT}s)`);
225
+ // Write PID file
226
+ fs.mkdirSync(path.dirname(state.pidFile), { recursive: true });
227
+ fs.writeFileSync(state.pidFile, String(process.pid), 'utf-8');
228
+ // Ensure queue directory exists
229
+ fs.mkdirSync(state.queueDir, { recursive: true });
230
+ while (true) {
231
+ const event = dequeue(state);
232
+ if (event) {
233
+ state.idleCount = 0;
234
+ await processEvent(event, state);
235
+ }
236
+ else {
237
+ state.idleCount++;
238
+ if (state.idleCount >= IDLE_TIMEOUT) {
239
+ appendLog(state.logFile, `Idle timeout (${IDLE_TIMEOUT}s), exiting`);
240
+ break;
241
+ }
242
+ // In non-daemon mode, exit after 3s of idle
243
+ if (!state.daemonMode && state.idleCount >= 3) {
244
+ break;
245
+ }
246
+ // Wait 1 second before checking again
247
+ await new Promise((resolve) => setTimeout(resolve, 1000));
248
+ }
249
+ }
250
+ // Cleanup
251
+ state.lock.release();
252
+ try {
253
+ fs.unlinkSync(state.pidFile);
254
+ }
255
+ catch {
256
+ // Ignore cleanup errors
257
+ }
258
+ }
259
+ /**
260
+ * Main entry point
261
+ */
262
+ async function main() {
263
+ // Check if hooks disabled
264
+ if (process.env.SPECWEAVE_DISABLE_HOOKS === '1') {
265
+ return;
266
+ }
267
+ // Parse arguments
268
+ const daemonMode = process.argv.includes('--daemon');
269
+ // Find project root
270
+ const projectRoot = findProjectRoot();
271
+ if (!projectRoot) {
272
+ return;
273
+ }
274
+ // Initialize state
275
+ const state = initState(projectRoot, daemonMode);
276
+ // Try to acquire lock
277
+ if (!state.lock.acquire(STALE_LOCK_SECONDS)) {
278
+ // Another processor is running
279
+ return;
280
+ }
281
+ // Check PID file for extra safety
282
+ if (fs.existsSync(state.pidFile)) {
283
+ try {
284
+ const oldPid = parseInt(fs.readFileSync(state.pidFile, 'utf-8').trim(), 10);
285
+ if (!isNaN(oldPid)) {
286
+ try {
287
+ process.kill(oldPid, 0);
288
+ // Process is running - exit
289
+ state.lock.release();
290
+ return;
291
+ }
292
+ catch {
293
+ // Process not running - continue
294
+ }
295
+ }
296
+ }
297
+ catch {
298
+ // Ignore PID file errors
299
+ }
300
+ }
301
+ // Run main loop
302
+ try {
303
+ await mainLoop(state);
304
+ }
305
+ catch (err) {
306
+ appendLog(state.logFile, `Processor error: ${err}`);
307
+ }
308
+ finally {
309
+ state.lock.release();
310
+ }
311
+ }
312
+ // Run if executed directly
313
+ main().catch((err) => {
314
+ console.error('Processor fatal error:', err);
315
+ process.exit(1);
316
+ });
317
+ //# sourceMappingURL=processor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"processor.js","sourceRoot":"","sources":["../../../src/hooks/processor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Scheduler Startup Check (Cross-Platform)
4
+ *
5
+ * Checks for due scheduled jobs on session start.
6
+ * Returns system message if jobs are ready to run.
7
+ *
8
+ * @module hooks/scheduler-startup
9
+ */
10
+ /**
11
+ * Check for due scheduled jobs
12
+ *
13
+ * @param projectRoot - Project root directory
14
+ * @returns Object with systemMessage if jobs are due
15
+ */
16
+ export declare function checkScheduledJobs(projectRoot?: string): Promise<{
17
+ systemMessage?: string;
18
+ } | null>;
19
+ //# sourceMappingURL=scheduler-startup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scheduler-startup.d.ts","sourceRoot":"","sources":["../../../src/hooks/scheduler-startup.ts"],"names":[],"mappings":";AACA;;;;;;;GAOG;AA4CH;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC;IAAE,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CA0D5C"}
@@ -0,0 +1,92 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Scheduler Startup Check (Cross-Platform)
4
+ *
5
+ * Checks for due scheduled jobs on session start.
6
+ * Returns system message if jobs are ready to run.
7
+ *
8
+ * @module hooks/scheduler-startup
9
+ */
10
+ import * as path from 'path';
11
+ import * as fs from 'fs';
12
+ import { findProjectRoot, readJsonSafe, appendLog, outputHookResult } from './platform.js';
13
+ /**
14
+ * Check for due scheduled jobs
15
+ *
16
+ * @param projectRoot - Project root directory
17
+ * @returns Object with systemMessage if jobs are due
18
+ */
19
+ export async function checkScheduledJobs(projectRoot) {
20
+ const root = projectRoot || findProjectRoot();
21
+ if (!root) {
22
+ return null;
23
+ }
24
+ const configFile = path.join(root, '.specweave', 'config.json');
25
+ const scheduledJobsFile = path.join(root, '.specweave', 'state', 'scheduled-jobs.json');
26
+ const logFile = path.join(root, '.specweave', 'logs', 'scheduler.log');
27
+ // Check if scheduler is enabled
28
+ const config = readJsonSafe(configFile);
29
+ const schedulerEnabled = config?.sync?.orchestration?.scheduler?.enabled ?? false;
30
+ if (!schedulerEnabled) {
31
+ return null;
32
+ }
33
+ // Check if scheduled jobs file exists
34
+ if (!fs.existsSync(scheduledJobsFile)) {
35
+ return null;
36
+ }
37
+ // Read and parse scheduled jobs
38
+ const jobsData = readJsonSafe(scheduledJobsFile);
39
+ if (!jobsData?.jobs || !Array.isArray(jobsData.jobs)) {
40
+ return null;
41
+ }
42
+ // Find due jobs
43
+ const now = Date.now();
44
+ const dueJobs = jobsData.jobs.filter((job) => {
45
+ // Job must be enabled and idle
46
+ if (!job.schedule.enabled || job.status !== 'idle') {
47
+ return false;
48
+ }
49
+ // No nextRun means it should run now
50
+ if (!job.schedule.nextRun) {
51
+ return true;
52
+ }
53
+ // Check if nextRun has passed
54
+ const nextRunTime = new Date(job.schedule.nextRun).getTime();
55
+ return nextRunTime <= now;
56
+ });
57
+ if (dueJobs.length === 0) {
58
+ return null;
59
+ }
60
+ // Log due jobs
61
+ const dueJobIds = dueJobs.map((j) => j.id);
62
+ appendLog(logFile, `Due sync jobs: ${JSON.stringify(dueJobIds)}`);
63
+ return {
64
+ systemMessage: `Scheduled sync jobs ready to run. Use /specweave:sync-now to execute.`,
65
+ };
66
+ }
67
+ /**
68
+ * Main entry point (when run directly)
69
+ */
70
+ async function main() {
71
+ // Check if hooks disabled
72
+ if (process.env.SPECWEAVE_DISABLE_HOOKS === '1') {
73
+ outputHookResult({ continue: true });
74
+ return;
75
+ }
76
+ const result = await checkScheduledJobs();
77
+ if (result?.systemMessage) {
78
+ outputHookResult({ continue: true, systemMessage: result.systemMessage });
79
+ }
80
+ else {
81
+ outputHookResult({ continue: true });
82
+ }
83
+ }
84
+ // Run if executed directly
85
+ const isMainModule = import.meta.url === `file://${process.argv[1]}`;
86
+ if (isMainModule) {
87
+ main().catch((err) => {
88
+ console.error(JSON.stringify({ continue: true, error: String(err) }));
89
+ process.exit(0);
90
+ });
91
+ }
92
+ //# sourceMappingURL=scheduler-startup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scheduler-startup.js","sourceRoot":"","sources":["../../../src/hooks/scheduler-startup.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Session Start Hook (Cross-Platform)
4
+ *
5
+ * Launches background processor on session start.
6
+ * Works on Windows, macOS, and Linux without WSL requirement.
7
+ *
8
+ * Windows Support Strategy:
9
+ * 1. Git Bash (PRIMARY - required for production use)
10
+ * 2. WSL (FALLBACK - for development/emergency only)
11
+ * 3. Graceful degradation (skip bash handlers if neither available)
12
+ *
13
+ * @module hooks/session-start
14
+ */
15
+ export {};
16
+ //# sourceMappingURL=session-start.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-start.d.ts","sourceRoot":"","sources":["../../../src/hooks/session-start.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;GAYG"}
@@ -0,0 +1,92 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Session Start Hook (Cross-Platform)
4
+ *
5
+ * Launches background processor on session start.
6
+ * Works on Windows, macOS, and Linux without WSL requirement.
7
+ *
8
+ * Windows Support Strategy:
9
+ * 1. Git Bash (PRIMARY - required for production use)
10
+ * 2. WSL (FALLBACK - for development/emergency only)
11
+ * 3. Graceful degradation (skip bash handlers if neither available)
12
+ *
13
+ * @module hooks/session-start
14
+ */
15
+ import * as path from 'path';
16
+ import * as fs from 'fs';
17
+ import { fileURLToPath } from 'url';
18
+ import { findProjectRoot, spawnNodeBackground, outputHookResult, consumeStdin, appendLog, } from './platform.js';
19
+ // Proper cross-platform URL-to-path conversion
20
+ const __filename = fileURLToPath(import.meta.url);
21
+ const __dirname = path.dirname(__filename);
22
+ /**
23
+ * Check if hooks are disabled
24
+ */
25
+ function isHooksDisabled() {
26
+ return process.env.SPECWEAVE_DISABLE_HOOKS === '1';
27
+ }
28
+ /**
29
+ * Main entry point
30
+ */
31
+ async function main() {
32
+ // Check if hooks disabled
33
+ if (isHooksDisabled()) {
34
+ outputHookResult({ continue: true });
35
+ return;
36
+ }
37
+ // Find project root
38
+ const projectRoot = findProjectRoot();
39
+ if (!projectRoot) {
40
+ outputHookResult({ continue: true });
41
+ return;
42
+ }
43
+ // Consume stdin (required by hook protocol)
44
+ await consumeStdin();
45
+ const logFile = path.join(projectRoot, '.specweave', 'logs', 'session-start.log');
46
+ const distHooksDir = path.join(projectRoot, 'node_modules', 'specweave', 'dist', 'hooks');
47
+ // Check for processor script
48
+ // First try: built hooks in dist (production)
49
+ // Fallback: development mode - hooks relative to this file
50
+ let processorScript = path.join(distHooksDir, 'processor.js');
51
+ if (!fs.existsSync(processorScript)) {
52
+ // Development mode - use fileURLToPath for correct cross-platform path
53
+ processorScript = path.join(__dirname, 'processor.js');
54
+ }
55
+ // Launch processor in background (daemon mode)
56
+ if (fs.existsSync(processorScript)) {
57
+ const child = spawnNodeBackground(processorScript, ['--daemon'], projectRoot);
58
+ if (child) {
59
+ appendLog(logFile, `Processor started (PID: ${child.pid})`);
60
+ }
61
+ }
62
+ // Check for scheduler startup
63
+ let schedulerScript = path.join(distHooksDir, 'scheduler-startup.js');
64
+ if (!fs.existsSync(schedulerScript)) {
65
+ // Development mode - use fileURLToPath for correct cross-platform path
66
+ schedulerScript = path.join(__dirname, 'scheduler-startup.js');
67
+ }
68
+ // Run scheduler check (synchronously for hook response)
69
+ if (fs.existsSync(schedulerScript)) {
70
+ try {
71
+ // Dynamic import to run scheduler check
72
+ const schedulerModule = await import(schedulerScript);
73
+ if (typeof schedulerModule.checkScheduledJobs === 'function') {
74
+ const result = await schedulerModule.checkScheduledJobs(projectRoot);
75
+ if (result && result.systemMessage) {
76
+ outputHookResult({ continue: true, systemMessage: result.systemMessage });
77
+ return;
78
+ }
79
+ }
80
+ }
81
+ catch (err) {
82
+ appendLog(logFile, `Scheduler check failed: ${err}`);
83
+ }
84
+ }
85
+ outputHookResult({ continue: true });
86
+ }
87
+ // Run main
88
+ main().catch((err) => {
89
+ console.error(JSON.stringify({ continue: true, error: String(err) }));
90
+ process.exit(0); // Don't block Claude Code on hook errors
91
+ });
92
+ //# sourceMappingURL=session-start.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-start.js","sourceRoot":"","sources":["../../../src/hooks/session-start.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,gBAAgB,EAChB,YAAY,EACZ,SAAS,GACV,MAAM,eAAe,CAAC;AAEvB,+CAA+C;AAC/C,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;AAE3C;;GAEG;AACH,SAAS,eAAe;IACtB,OAAO,OAAO,CAAC,GAAG,CAAC,uBAAuB,KAAK,GAAG,CAAC;AACrD,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,IAAI;IACjB,0BAA0B;IAC1B,IAAI,eAAe,EAAE,EAAE,CAAC;QACtB,gBAAgB,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QACrC,OAAO;IACT,CAAC;IAED,oBAAoB;IACpB,MAAM,WAAW,GAAG,eAAe,EAAE,CAAC;IACtC,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,gBAAgB,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QACrC,OAAO;IACT,CAAC;IAED,4CAA4C;IAC5C,MAAM,YAAY,EAAE,CAAC;IAErB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,YAAY,EAAE,MAAM,EAAE,mBAAmB,CAAC,CAAC;IAClF,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;IAE1F,6BAA6B;IAC7B,8CAA8C;IAC9C,2DAA2D;IAC3D,IAAI,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,cAAc,CAAC,CAAC;IAC9D,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,eAAe,CAAC,EAAE,CAAC;QACpC,uEAAuE;QACvE,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;IACzD,CAAC;IAED,+CAA+C;IAC/C,IAAI,EAAE,CAAC,UAAU,CAAC,eAAe,CAAC,EAAE,CAAC;QACnC,MAAM,KAAK,GAAG,mBAAmB,CAAC,eAAe,EAAE,CAAC,UAAU,CAAC,EAAE,WAAW,CAAC,CAAC;QAC9E,IAAI,KAAK,EAAE,CAAC;YACV,SAAS,CAAC,OAAO,EAAE,2BAA2B,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC;IAED,8BAA8B;IAC9B,IAAI,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,sBAAsB,CAAC,CAAC;IACtE,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,eAAe,CAAC,EAAE,CAAC;QACpC,uEAAuE;QACvE,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,sBAAsB,CAAC,CAAC;IACjE,CAAC;IAED,wDAAwD;IACxD,IAAI,EAAE,CAAC,UAAU,CAAC,eAAe,CAAC,EAAE,CAAC;QACnC,IAAI,CAAC;YACH,wCAAwC;YACxC,MAAM,eAAe,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,CAAC;YACtD,IAAI,OAAO,eAAe,CAAC,kBAAkB,KAAK,UAAU,EAAE,CAAC;gBAC7D,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,kBAAkB,CAAC,WAAW,CAAC,CAAC;gBACrE,IAAI,MAAM,IAAI,MAAM,CAAC,aAAa,EAAE,CAAC;oBACnC,gBAAgB,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,CAAC,aAAa,EAAE,CAAC,CAAC;oBAC1E,OAAO;gBACT,CAAC;YACH,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,SAAS,CAAC,OAAO,EAAE,2BAA2B,GAAG,EAAE,CAAC,CAAC;QACvD,CAAC;IACH,CAAC;IAED,gBAAgB,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;AACvC,CAAC;AAED,WAAW;AACX,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IACtE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,yCAAyC;AAC5D,CAAC,CAAC,CAAC"}
@@ -6,6 +6,7 @@
6
6
  */
7
7
  /**
8
8
  * External ID reference found in living docs
9
+ * CRITICAL (2025-12-01): Includes parent tracking for re-import hierarchy updates
9
10
  */
10
11
  export interface ExternalIdReference {
11
12
  /** User Story ID (e.g., US-001E) */
@@ -16,6 +17,14 @@ export interface ExternalIdReference {
16
17
  externalId: string;
17
18
  /** External platform (github, jira, ado) */
18
19
  platform?: string;
20
+ /** Feature ID this item belongs to (e.g., FS-001E) */
21
+ featureId?: string;
22
+ /** Parent work item ID in external tool (e.g., ADO-123) */
23
+ parentId?: string;
24
+ /** Whether this item was imported as orphan (no parent) */
25
+ isOrphan?: boolean;
26
+ /** ADO work item type (e.g., User Story, Bug) */
27
+ adoWorkItemType?: string;
19
28
  }
20
29
  /**
21
30
  * Options for duplicate detection
@@ -71,10 +80,12 @@ export declare class DuplicateDetector {
71
80
  */
72
81
  private findUserStoryFiles;
73
82
  /**
74
- * Extract external_id from a User Story file
83
+ * Extract external_id and parent tracking info from a User Story file
84
+ *
85
+ * CRITICAL (2025-12-01): Also extracts parent info for re-import hierarchy updates
75
86
  *
76
87
  * @param filePath - Path to User Story markdown file
77
- * @returns External ID reference if found, null otherwise
88
+ * @returns External ID reference with parent info if found, null otherwise
78
89
  */
79
90
  private extractExternalIdFromFile;
80
91
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"duplicate-detector.d.ts","sourceRoot":"","sources":["../../../src/importers/duplicate-detector.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,oCAAoC;IACpC,IAAI,EAAE,MAAM,CAAC;IAEb,4CAA4C;IAC5C,QAAQ,EAAE,MAAM,CAAC;IAEjB,wBAAwB;IACxB,UAAU,EAAE,MAAM,CAAC;IAEnB,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,0CAA0C;IAC1C,QAAQ,EAAE,MAAM,CAAC;IAEjB,yCAAyC;IACzC,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;;;;GAKG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,OAAO,CAA2B;IAC1C,OAAO,CAAC,KAAK,CAAiD;gBAElD,OAAO,EAAE,wBAAwB;IAO7C;;;;;OAKG;IACG,uBAAuB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAKnE;;;;;OAKG;IACG,uBAAuB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC;IAUtF;;;;OAIG;IACG,iBAAiB,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;IAIpE;;OAEG;YACW,kBAAkB;IA4BhC;;;;;;;;OAQG;YACW,kBAAkB;IAYhC;;;;;OAKG;YACW,yBAAyB;IAkCvC;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAiB3B;;;;;;;;;;OAUG;IACH,OAAO,CAAC,mBAAmB;IAY3B;;OAEG;IACH,UAAU,IAAI,IAAI;IAIlB;;OAEG;IACH,aAAa,IAAI;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE;CAMpD;AAED;;;;;;GAMG;AACH,wBAAsB,uBAAuB,CAC3C,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,OAAO,CAAC,CAGlB"}
1
+ {"version":3,"file":"duplicate-detector.d.ts","sourceRoot":"","sources":["../../../src/importers/duplicate-detector.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC,oCAAoC;IACpC,IAAI,EAAE,MAAM,CAAC;IAEb,4CAA4C;IAC5C,QAAQ,EAAE,MAAM,CAAC;IAEjB,wBAAwB;IACxB,UAAU,EAAE,MAAM,CAAC;IAEnB,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAGlB,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,iDAAiD;IACjD,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,0CAA0C;IAC1C,QAAQ,EAAE,MAAM,CAAC;IAEjB,yCAAyC;IACzC,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;;;;GAKG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,OAAO,CAA2B;IAC1C,OAAO,CAAC,KAAK,CAAiD;gBAElD,OAAO,EAAE,wBAAwB;IAO7C;;;;;OAKG;IACG,uBAAuB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAKnE;;;;;OAKG;IACG,uBAAuB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC;IAUtF;;;;OAIG;IACG,iBAAiB,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;IAIpE;;OAEG;YACW,kBAAkB;IA4BhC;;;;;;;;OAQG;YACW,kBAAkB;IAYhC;;;;;;;OAOG;YACW,yBAAyB;IAoDvC;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAiB3B;;;;;;;;;;OAUG;IACH,OAAO,CAAC,mBAAmB;IAY3B;;OAEG;IACH,UAAU,IAAI,IAAI;IAIlB;;OAEG;IACH,aAAa,IAAI;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE;CAMpD;AAED;;;;;;GAMG;AACH,wBAAsB,uBAAuB,CAC3C,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,OAAO,CAAC,CAGlB"}
@@ -97,10 +97,12 @@ export class DuplicateDetector {
97
97
  return files;
98
98
  }
99
99
  /**
100
- * Extract external_id from a User Story file
100
+ * Extract external_id and parent tracking info from a User Story file
101
+ *
102
+ * CRITICAL (2025-12-01): Also extracts parent info for re-import hierarchy updates
101
103
  *
102
104
  * @param filePath - Path to User Story markdown file
103
- * @returns External ID reference if found, null otherwise
105
+ * @returns External ID reference with parent info if found, null otherwise
104
106
  */
105
107
  async extractExternalIdFromFile(filePath) {
106
108
  try {
@@ -114,15 +116,32 @@ export class DuplicateDetector {
114
116
  filePath,
115
117
  externalId: String(parsed.data.external_id),
116
118
  platform: parsed.data.external_platform,
119
+ // Parent tracking from frontmatter
120
+ featureId: parsed.data.feature_id,
121
+ parentId: parsed.data.parent_id,
122
+ isOrphan: parsed.data.is_orphan,
123
+ adoWorkItemType: parsed.data.ado_work_item_type,
117
124
  };
118
125
  }
119
126
  // Fallback: Parse external metadata section in content
120
127
  const externalIdMatch = content.match(/^-\s+\*\*External ID\*\*:\s+(.+)$/m);
121
128
  if (externalIdMatch) {
129
+ // Extract parent tracking info from content body
130
+ const featureIdMatch = content.match(/^-\s+\*\*Feature ID\*\*:\s+(.+)$/m);
131
+ const parentIdMatch = content.match(/^-\s+\*\*Parent ID\*\*:\s+(.+)$/m);
132
+ const orphanMatch = content.match(/^-\s+\*\*Orphan\*\*:\s+true/m);
133
+ const adoTypeMatch = content.match(/^-\s+\*\*ADO Work Item Type\*\*:\s+(.+)$/m);
134
+ const platformMatch = content.match(/^-\s+\*\*Platform\*\*:\s+(.+)$/m);
122
135
  return {
123
136
  usId: this.extractUsIdFromFile(filePath, content),
124
137
  filePath,
125
138
  externalId: externalIdMatch[1].trim(),
139
+ platform: platformMatch?.[1]?.trim()?.toLowerCase(),
140
+ // Parent tracking from content body
141
+ featureId: featureIdMatch?.[1]?.trim(),
142
+ parentId: parentIdMatch?.[1]?.trim(),
143
+ isOrphan: !!orphanMatch,
144
+ adoWorkItemType: adoTypeMatch?.[1]?.trim(),
126
145
  };
127
146
  }
128
147
  return null;