specweave 0.32.10 → 0.33.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 (172) hide show
  1. package/CLAUDE.md +106 -1
  2. package/dist/src/cli/add-child-pid.d.ts +11 -0
  3. package/dist/src/cli/add-child-pid.d.ts.map +1 -0
  4. package/dist/src/cli/add-child-pid.js +42 -0
  5. package/dist/src/cli/add-child-pid.js.map +1 -0
  6. package/dist/src/cli/add-child-process.d.ts +15 -0
  7. package/dist/src/cli/add-child-process.d.ts.map +1 -0
  8. package/dist/src/cli/add-child-process.js +40 -0
  9. package/dist/src/cli/add-child-process.js.map +1 -0
  10. package/dist/src/cli/check-watchdog.d.ts +15 -0
  11. package/dist/src/cli/check-watchdog.d.ts.map +1 -0
  12. package/dist/src/cli/check-watchdog.js +47 -0
  13. package/dist/src/cli/check-watchdog.js.map +1 -0
  14. package/dist/src/cli/cleanup-zombies.d.ts +14 -0
  15. package/dist/src/cli/cleanup-zombies.d.ts.map +1 -0
  16. package/dist/src/cli/cleanup-zombies.js +268 -0
  17. package/dist/src/cli/cleanup-zombies.js.map +1 -0
  18. package/dist/src/cli/find-session-by-pid.d.ts +14 -0
  19. package/dist/src/cli/find-session-by-pid.d.ts.map +1 -0
  20. package/dist/src/cli/find-session-by-pid.js +45 -0
  21. package/dist/src/cli/find-session-by-pid.js.map +1 -0
  22. package/dist/src/cli/get-stale-sessions.d.ts +17 -0
  23. package/dist/src/cli/get-stale-sessions.d.ts.map +1 -0
  24. package/dist/src/cli/get-stale-sessions.js +36 -0
  25. package/dist/src/cli/get-stale-sessions.js.map +1 -0
  26. package/dist/src/cli/register-session.d.ts +16 -0
  27. package/dist/src/cli/register-session.d.ts.map +1 -0
  28. package/dist/src/cli/register-session.js +48 -0
  29. package/dist/src/cli/register-session.js.map +1 -0
  30. package/dist/src/cli/remove-session.d.ts +11 -0
  31. package/dist/src/cli/remove-session.d.ts.map +1 -0
  32. package/dist/src/cli/remove-session.js +36 -0
  33. package/dist/src/cli/remove-session.js.map +1 -0
  34. package/dist/src/cli/update-heartbeat.d.ts +11 -0
  35. package/dist/src/cli/update-heartbeat.d.ts.map +1 -0
  36. package/dist/src/cli/update-heartbeat.js +36 -0
  37. package/dist/src/cli/update-heartbeat.js.map +1 -0
  38. package/dist/src/config/types.d.ts +1208 -203
  39. package/dist/src/config/types.d.ts.map +1 -1
  40. package/dist/src/core/background/job-manager.d.ts +16 -0
  41. package/dist/src/core/background/job-manager.d.ts.map +1 -1
  42. package/dist/src/core/background/job-manager.js +110 -15
  43. package/dist/src/core/background/job-manager.js.map +1 -1
  44. package/dist/src/core/increment/increment-utils.d.ts +26 -1
  45. package/dist/src/core/increment/increment-utils.d.ts.map +1 -1
  46. package/dist/src/core/increment/increment-utils.js +66 -4
  47. package/dist/src/core/increment/increment-utils.js.map +1 -1
  48. package/dist/src/core/increment/status-change-sync-trigger.d.ts +3 -1
  49. package/dist/src/core/increment/status-change-sync-trigger.d.ts.map +1 -1
  50. package/dist/src/core/increment/status-change-sync-trigger.js +5 -2
  51. package/dist/src/core/increment/status-change-sync-trigger.js.map +1 -1
  52. package/dist/src/core/living-docs/intelligent-analyzer/architecture-generator.d.ts.map +1 -1
  53. package/dist/src/core/living-docs/intelligent-analyzer/architecture-generator.js +48 -12
  54. package/dist/src/core/living-docs/intelligent-analyzer/architecture-generator.js.map +1 -1
  55. package/dist/src/core/living-docs/intelligent-analyzer/cache-manager.d.ts +70 -0
  56. package/dist/src/core/living-docs/intelligent-analyzer/cache-manager.d.ts.map +1 -0
  57. package/dist/src/core/living-docs/intelligent-analyzer/cache-manager.js +188 -0
  58. package/dist/src/core/living-docs/intelligent-analyzer/cache-manager.js.map +1 -0
  59. package/dist/src/core/living-docs/intelligent-analyzer/dashboard-generator.d.ts +33 -0
  60. package/dist/src/core/living-docs/intelligent-analyzer/dashboard-generator.d.ts.map +1 -0
  61. package/dist/src/core/living-docs/intelligent-analyzer/dashboard-generator.js +290 -0
  62. package/dist/src/core/living-docs/intelligent-analyzer/dashboard-generator.js.map +1 -0
  63. package/dist/src/core/living-docs/intelligent-analyzer/deep-repo-analyzer.d.ts.map +1 -1
  64. package/dist/src/core/living-docs/intelligent-analyzer/deep-repo-analyzer.js +114 -11
  65. package/dist/src/core/living-docs/intelligent-analyzer/deep-repo-analyzer.js.map +1 -1
  66. package/dist/src/core/living-docs/intelligent-analyzer/graph-visualizer.d.ts +23 -0
  67. package/dist/src/core/living-docs/intelligent-analyzer/graph-visualizer.d.ts.map +1 -0
  68. package/dist/src/core/living-docs/intelligent-analyzer/graph-visualizer.js +283 -0
  69. package/dist/src/core/living-docs/intelligent-analyzer/graph-visualizer.js.map +1 -0
  70. package/dist/src/core/living-docs/intelligent-analyzer/mermaid-generator.d.ts +44 -0
  71. package/dist/src/core/living-docs/intelligent-analyzer/mermaid-generator.d.ts.map +1 -0
  72. package/dist/src/core/living-docs/intelligent-analyzer/mermaid-generator.js +61 -0
  73. package/dist/src/core/living-docs/intelligent-analyzer/mermaid-generator.js.map +1 -0
  74. package/dist/src/core/living-docs/intelligent-analyzer/orchestrator.d.ts +126 -0
  75. package/dist/src/core/living-docs/intelligent-analyzer/orchestrator.d.ts.map +1 -0
  76. package/dist/src/core/living-docs/intelligent-analyzer/orchestrator.js +378 -0
  77. package/dist/src/core/living-docs/intelligent-analyzer/orchestrator.js.map +1 -0
  78. package/dist/src/core/living-docs/intelligent-analyzer/organization-synthesizer.d.ts.map +1 -1
  79. package/dist/src/core/living-docs/intelligent-analyzer/organization-synthesizer.js +57 -0
  80. package/dist/src/core/living-docs/intelligent-analyzer/organization-synthesizer.js.map +1 -1
  81. package/dist/src/core/living-docs/intelligent-analyzer/pattern-analyzer.d.ts +82 -0
  82. package/dist/src/core/living-docs/intelligent-analyzer/pattern-analyzer.d.ts.map +1 -0
  83. package/dist/src/core/living-docs/intelligent-analyzer/pattern-analyzer.js +430 -0
  84. package/dist/src/core/living-docs/intelligent-analyzer/pattern-analyzer.js.map +1 -0
  85. package/dist/src/core/living-docs/intelligent-analyzer/repo-scanner.d.ts +84 -0
  86. package/dist/src/core/living-docs/intelligent-analyzer/repo-scanner.d.ts.map +1 -0
  87. package/dist/src/core/living-docs/intelligent-analyzer/repo-scanner.js +387 -0
  88. package/dist/src/core/living-docs/intelligent-analyzer/repo-scanner.js.map +1 -0
  89. package/dist/src/core/living-docs/intelligent-analyzer/report-writer.d.ts +61 -0
  90. package/dist/src/core/living-docs/intelligent-analyzer/report-writer.d.ts.map +1 -0
  91. package/dist/src/core/living-docs/intelligent-analyzer/report-writer.js +174 -0
  92. package/dist/src/core/living-docs/intelligent-analyzer/report-writer.js.map +1 -0
  93. package/dist/src/core/living-docs/intelligent-analyzer/types.d.ts +1 -1
  94. package/dist/src/core/living-docs/intelligent-analyzer/types.d.ts.map +1 -1
  95. package/dist/src/core/living-docs/module-analyzer.d.ts +3 -0
  96. package/dist/src/core/living-docs/module-analyzer.d.ts.map +1 -1
  97. package/dist/src/core/living-docs/module-analyzer.js +40 -1
  98. package/dist/src/core/living-docs/module-analyzer.js.map +1 -1
  99. package/dist/src/core/qa/qa-runner.js +1 -1
  100. package/dist/src/core/qa/qa-runner.js.map +1 -1
  101. package/dist/src/core/scheduler/session-sync-executor.js +1 -1
  102. package/dist/src/core/scheduler/session-sync-executor.js.map +1 -1
  103. package/dist/src/core/status-line/status-line-updater.d.ts +1 -1
  104. package/dist/src/core/status-line/status-line-updater.d.ts.map +1 -1
  105. package/dist/src/core/status-line/status-line-updater.js +4 -3
  106. package/dist/src/core/status-line/status-line-updater.js.map +1 -1
  107. package/dist/src/importers/jira-importer.d.ts.map +1 -1
  108. package/dist/src/importers/jira-importer.js +18 -9
  109. package/dist/src/importers/jira-importer.js.map +1 -1
  110. package/dist/src/init/architecture/types.d.ts +140 -33
  111. package/dist/src/init/architecture/types.d.ts.map +1 -1
  112. package/dist/src/init/compliance/types.d.ts +27 -30
  113. package/dist/src/init/compliance/types.d.ts.map +1 -1
  114. package/dist/src/init/repo/types.d.ts +34 -11
  115. package/dist/src/init/repo/types.d.ts.map +1 -1
  116. package/dist/src/init/research/src/config/types.d.ts +82 -15
  117. package/dist/src/init/research/src/config/types.d.ts.map +1 -1
  118. package/dist/src/init/research/types.d.ts +93 -38
  119. package/dist/src/init/research/types.d.ts.map +1 -1
  120. package/dist/src/init/team/types.d.ts +42 -4
  121. package/dist/src/init/team/types.d.ts.map +1 -1
  122. package/dist/src/sync/ado-reconciler.js +1 -1
  123. package/dist/src/sync/ado-reconciler.js.map +1 -1
  124. package/dist/src/sync/github-reconciler.js +1 -1
  125. package/dist/src/sync/github-reconciler.js.map +1 -1
  126. package/dist/src/sync/jira-reconciler.js +1 -1
  127. package/dist/src/sync/jira-reconciler.js.map +1 -1
  128. package/dist/src/types/session.d.ts +65 -0
  129. package/dist/src/types/session.d.ts.map +1 -0
  130. package/dist/src/types/session.js +8 -0
  131. package/dist/src/types/session.js.map +1 -0
  132. package/dist/src/utils/lock-manager.d.ts +48 -0
  133. package/dist/src/utils/lock-manager.d.ts.map +1 -0
  134. package/dist/src/utils/lock-manager.js +195 -0
  135. package/dist/src/utils/lock-manager.js.map +1 -0
  136. package/dist/src/utils/notification-manager.d.ts +45 -0
  137. package/dist/src/utils/notification-manager.d.ts.map +1 -0
  138. package/dist/src/utils/notification-manager.js +130 -0
  139. package/dist/src/utils/notification-manager.js.map +1 -0
  140. package/dist/src/utils/platform-utils.d.ts +136 -0
  141. package/dist/src/utils/platform-utils.d.ts.map +1 -0
  142. package/dist/src/utils/platform-utils.js +366 -0
  143. package/dist/src/utils/platform-utils.js.map +1 -0
  144. package/dist/src/utils/session-registry.d.ts +142 -0
  145. package/dist/src/utils/session-registry.d.ts.map +1 -0
  146. package/dist/src/utils/session-registry.js +480 -0
  147. package/dist/src/utils/session-registry.js.map +1 -0
  148. package/package.json +5 -2
  149. package/plugins/specweave/commands/specweave-living-docs.md +42 -0
  150. package/plugins/specweave/hooks/hooks.json +10 -0
  151. package/plugins/specweave/hooks/lib/update-active-increment.sh +2 -2
  152. package/plugins/specweave/hooks/lib/update-status-line.sh +1 -1
  153. package/plugins/specweave/hooks/post-increment-status-change.sh +3 -3
  154. package/plugins/specweave/hooks/post-metadata-change.sh +1 -1
  155. package/plugins/specweave/hooks/universal/hook-wrapper.cmd +26 -26
  156. package/plugins/specweave/hooks/universal/session-start.cmd +16 -16
  157. package/plugins/specweave/hooks/universal/session-start.ps1 +16 -16
  158. package/plugins/specweave/hooks/user-prompt-submit.sh +2 -2
  159. package/plugins/specweave/hooks/v2/guards/increment-root-guard.sh +61 -0
  160. package/plugins/specweave/hooks/v2/session-end.sh +69 -0
  161. package/plugins/specweave/hooks/v2/session-start.sh +81 -0
  162. package/plugins/specweave/lib/vendor/sync/github-reconciler.js +1 -1
  163. package/plugins/specweave/lib/vendor/sync/github-reconciler.js.map +1 -1
  164. package/plugins/specweave/scripts/heartbeat.sh +110 -0
  165. package/plugins/specweave/scripts/progress.js +34 -4
  166. package/plugins/specweave/scripts/read-jobs.sh +1 -1
  167. package/plugins/specweave/scripts/read-progress.sh +50 -5
  168. package/plugins/specweave/scripts/read-workflow.sh +1 -1
  169. package/plugins/specweave/scripts/session-watchdog.sh +65 -0
  170. package/plugins/specweave/scripts/status.js +28 -11
  171. package/plugins/specweave-github/hooks/.specweave/logs/hooks-debug.log +738 -0
  172. package/plugins/specweave-release/hooks/.specweave/logs/dora-tracking.log +1107 -0
@@ -0,0 +1,366 @@
1
+ /**
2
+ * Platform Utilities - Cross-platform OS operations
3
+ *
4
+ * Abstracts platform-specific operations for macOS, Linux, and Windows
5
+ * Enhanced for process lifecycle management with async API, logger injection,
6
+ * and system notifications
7
+ */
8
+ import { execSync } from 'child_process';
9
+ import { stat, mkdir, rmdir } from 'fs/promises';
10
+ import { consoleLogger } from './logger.js';
11
+ /**
12
+ * Gets the current platform
13
+ */
14
+ export function getCurrentPlatform() {
15
+ return process.platform;
16
+ }
17
+ /**
18
+ * Checks if a process exists (cross-platform)
19
+ *
20
+ * @param pid - Process ID to check
21
+ * @returns true if process exists
22
+ */
23
+ export function checkProcessExists(pid) {
24
+ try {
25
+ if (process.platform === 'win32') {
26
+ const output = execSync(`tasklist /FI "PID eq ${pid}" /NH`, {
27
+ encoding: 'utf-8',
28
+ stdio: ['ignore', 'pipe', 'ignore'],
29
+ });
30
+ return output.includes(String(pid));
31
+ }
32
+ else {
33
+ execSync(`kill -0 ${pid}`, { stdio: 'ignore' });
34
+ return true;
35
+ }
36
+ }
37
+ catch {
38
+ return false;
39
+ }
40
+ }
41
+ /**
42
+ * Gets file modification time in seconds since epoch (cross-platform)
43
+ *
44
+ * @param filePath - Path to file
45
+ * @returns Modification time in seconds since epoch
46
+ */
47
+ export function getFileMtime(filePath) {
48
+ try {
49
+ if (process.platform === 'darwin') {
50
+ const output = execSync(`stat -f %m "${filePath}"`, { encoding: 'utf-8' });
51
+ return parseInt(output.trim(), 10);
52
+ }
53
+ else if (process.platform === 'win32') {
54
+ const output = execSync(`powershell -Command "(Get-Item '${filePath}').LastWriteTime.ToFileTimeUtc()"`, { encoding: 'utf-8' });
55
+ const fileTime = parseInt(output.trim(), 10);
56
+ return Math.floor((fileTime - 116444736000000000) / 10000000);
57
+ }
58
+ else {
59
+ const output = execSync(`stat -c %Y "${filePath}"`, { encoding: 'utf-8' });
60
+ return parseInt(output.trim(), 10);
61
+ }
62
+ }
63
+ catch {
64
+ return 0;
65
+ }
66
+ }
67
+ /**
68
+ * Kills a process (cross-platform)
69
+ *
70
+ * @param pid - Process ID to kill
71
+ * @param signal - Signal to send (default: SIGTERM)
72
+ */
73
+ export function killProcess(pid, signal = 'SIGTERM') {
74
+ try {
75
+ if (process.platform === 'win32') {
76
+ execSync(`taskkill /F /PID ${pid}`, { stdio: 'ignore' });
77
+ }
78
+ else {
79
+ process.kill(pid, signal);
80
+ }
81
+ }
82
+ catch {
83
+ // Process may not exist, ignore
84
+ }
85
+ }
86
+ /**
87
+ * Acquires a file lock using atomic directory creation (cross-platform)
88
+ *
89
+ * @param lockPath - Path to lock directory
90
+ * @returns true if lock acquired
91
+ */
92
+ export function acquireFileLock(lockPath) {
93
+ const fs = require('fs');
94
+ try {
95
+ fs.mkdirSync(lockPath, { recursive: false });
96
+ return true;
97
+ }
98
+ catch (err) {
99
+ if (err.code === 'EEXIST') {
100
+ return false; // Lock already exists
101
+ }
102
+ throw err;
103
+ }
104
+ }
105
+ /**
106
+ * Enhanced cross-platform utility functions with async API and logger injection
107
+ */
108
+ export class PlatformUtils {
109
+ constructor(options = {}) {
110
+ this.platform = process.platform;
111
+ this.logger = options.logger ?? consoleLogger;
112
+ }
113
+ /**
114
+ * Get current platform
115
+ */
116
+ getPlatform() {
117
+ return this.platform;
118
+ }
119
+ /**
120
+ * Check if current platform is Windows
121
+ */
122
+ isWindows() {
123
+ return this.platform === 'win32';
124
+ }
125
+ /**
126
+ * Check if current platform is POSIX (macOS or Linux)
127
+ */
128
+ isPosix() {
129
+ return this.platform === 'darwin' || this.platform === 'linux';
130
+ }
131
+ /**
132
+ * Check if a process exists by PID (async)
133
+ *
134
+ * - macOS/Linux: kill -0 $pid (signal 0 = existence check)
135
+ * - Windows: tasklist /FI "PID eq $pid"
136
+ *
137
+ * @param pid Process ID to check
138
+ * @returns true if process exists, false otherwise
139
+ */
140
+ async checkProcessExistsAsync(pid) {
141
+ try {
142
+ if (this.isWindows()) {
143
+ const output = execSync(`tasklist /FI "PID eq ${pid}" /NH`, {
144
+ encoding: 'utf-8',
145
+ stdio: ['pipe', 'pipe', 'ignore'],
146
+ windowsHide: true
147
+ });
148
+ return output.includes(pid.toString());
149
+ }
150
+ else {
151
+ // Signal 0 = check existence without actually sending a signal
152
+ process.kill(pid, 0);
153
+ return true;
154
+ }
155
+ }
156
+ catch (err) {
157
+ if (err.code === 'ESRCH') {
158
+ // No such process
159
+ return false;
160
+ }
161
+ if (err.code === 'EPERM') {
162
+ // Process exists but we don't have permission to signal it
163
+ return true;
164
+ }
165
+ this.logger.error(`Error checking process ${pid}:`, err);
166
+ return false;
167
+ }
168
+ }
169
+ /**
170
+ * Get file modification time (async, uses fs.stat for cross-platform)
171
+ *
172
+ * @param path File path
173
+ * @returns Modification time in seconds since epoch
174
+ */
175
+ async getFileMtimeAsync(path) {
176
+ try {
177
+ const stats = await stat(path);
178
+ return Math.floor(stats.mtimeMs / 1000);
179
+ }
180
+ catch (err) {
181
+ this.logger.error(`Error getting mtime for ${path}:`, err);
182
+ throw err;
183
+ }
184
+ }
185
+ /**
186
+ * Acquire file lock using atomic mkdir (async)
187
+ *
188
+ * @param lockPath Path to lock directory
189
+ * @param timeoutMs Maximum time to wait for lock (default: 5000ms)
190
+ * @returns true if lock acquired, false if timeout
191
+ */
192
+ async acquireFileLockAsync(lockPath, timeoutMs = 5000) {
193
+ const startTime = Date.now();
194
+ while (Date.now() - startTime < timeoutMs) {
195
+ try {
196
+ await mkdir(lockPath, { recursive: false });
197
+ return true; // Lock acquired
198
+ }
199
+ catch (err) {
200
+ if (err.code === 'EEXIST') {
201
+ // Lock exists, wait and retry
202
+ await new Promise(resolve => setTimeout(resolve, 100));
203
+ continue;
204
+ }
205
+ this.logger.error(`Error acquiring lock at ${lockPath}:`, err);
206
+ throw err;
207
+ }
208
+ }
209
+ this.logger.warn(`Lock acquisition timeout after ${timeoutMs}ms: ${lockPath}`);
210
+ return false;
211
+ }
212
+ /**
213
+ * Release file lock (async)
214
+ *
215
+ * @param lockPath Path to lock directory
216
+ */
217
+ async releaseFileLockAsync(lockPath) {
218
+ try {
219
+ await rmdir(lockPath);
220
+ }
221
+ catch (err) {
222
+ if (err.code !== 'ENOENT') {
223
+ this.logger.error(`Error releasing lock at ${lockPath}:`, err);
224
+ throw err;
225
+ }
226
+ }
227
+ }
228
+ /**
229
+ * Kill process with signal (async)
230
+ *
231
+ * @param pid Process ID to kill
232
+ * @param signal Signal to send (default: SIGTERM)
233
+ */
234
+ async killProcessAsync(pid, signal = 'SIGTERM') {
235
+ try {
236
+ if (this.isWindows()) {
237
+ execSync(`taskkill /PID ${pid} /F`, {
238
+ stdio: 'ignore',
239
+ windowsHide: true
240
+ });
241
+ this.logger.debug(`Killed process ${pid} (Windows taskkill /F)`);
242
+ }
243
+ else {
244
+ process.kill(pid, signal);
245
+ this.logger.debug(`Killed process ${pid} with signal ${signal}`);
246
+ }
247
+ }
248
+ catch (err) {
249
+ if (err.code === 'ESRCH') {
250
+ this.logger.debug(`Process ${pid} doesn't exist (already terminated)`);
251
+ return;
252
+ }
253
+ this.logger.error(`Error killing process ${pid}:`, err);
254
+ throw err;
255
+ }
256
+ }
257
+ /**
258
+ * Kill process with graceful fallback (SIGTERM → SIGKILL)
259
+ *
260
+ * @param pid Process ID to kill
261
+ * @param gracePeriodMs Time to wait after SIGTERM before SIGKILL (default: 2000ms)
262
+ */
263
+ async killProcessGracefully(pid, gracePeriodMs = 2000) {
264
+ const exists = await this.checkProcessExistsAsync(pid);
265
+ if (!exists) {
266
+ this.logger.debug(`Process ${pid} doesn't exist, skipping kill`);
267
+ return;
268
+ }
269
+ try {
270
+ // Step 1: Send SIGTERM (graceful shutdown)
271
+ await this.killProcessAsync(pid, 'SIGTERM');
272
+ this.logger.debug(`Sent SIGTERM to process ${pid}, waiting ${gracePeriodMs}ms`);
273
+ // Step 2: Wait for grace period
274
+ await new Promise(resolve => setTimeout(resolve, gracePeriodMs));
275
+ // Step 3: Check if process still exists
276
+ const stillExists = await this.checkProcessExistsAsync(pid);
277
+ if (!stillExists) {
278
+ this.logger.debug(`Process ${pid} terminated gracefully after SIGTERM`);
279
+ return;
280
+ }
281
+ // Step 4: Force kill with SIGKILL
282
+ this.logger.warn(`Process ${pid} didn't terminate after SIGTERM, sending SIGKILL`);
283
+ await this.killProcessAsync(pid, 'SIGKILL');
284
+ this.logger.debug(`Sent SIGKILL to process ${pid}`);
285
+ }
286
+ catch (err) {
287
+ this.logger.error(`Error during graceful kill of process ${pid}:`, err);
288
+ throw err;
289
+ }
290
+ }
291
+ /**
292
+ * Send system notification
293
+ *
294
+ * - macOS: osascript (AppleScript)
295
+ * - Linux: notify-send (if available)
296
+ * - Windows: PowerShell toast notification
297
+ *
298
+ * Fails gracefully if notification system is unavailable
299
+ *
300
+ * @param title Notification title
301
+ * @param body Notification body text
302
+ */
303
+ async sendNotification(title, body) {
304
+ try {
305
+ if (this.platform === 'darwin') {
306
+ await this.sendNotificationMacOS(title, body);
307
+ }
308
+ else if (this.platform === 'linux') {
309
+ await this.sendNotificationLinux(title, body);
310
+ }
311
+ else if (this.platform === 'win32') {
312
+ await this.sendNotificationWindows(title, body);
313
+ }
314
+ this.logger.debug(`Sent notification: ${title}`);
315
+ }
316
+ catch (err) {
317
+ this.logger.warn(`Failed to send notification "${title}": ${err}`);
318
+ }
319
+ }
320
+ /**
321
+ * macOS notification using osascript
322
+ */
323
+ async sendNotificationMacOS(title, body) {
324
+ const escapedTitle = title.replace(/"/g, '\\"');
325
+ const escapedBody = body.replace(/"/g, '\\"');
326
+ const cmd = `osascript -e 'display notification "${escapedBody}" with title "${escapedTitle}"'`;
327
+ execSync(cmd, { stdio: 'ignore' });
328
+ }
329
+ /**
330
+ * Linux notification using notify-send
331
+ */
332
+ async sendNotificationLinux(title, body) {
333
+ try {
334
+ execSync('command -v notify-send', { stdio: 'ignore' });
335
+ const escapedTitle = title.replace(/"/g, '\\"');
336
+ const escapedBody = body.replace(/"/g, '\\"');
337
+ execSync(`notify-send "${escapedTitle}" "${escapedBody}"`, { stdio: 'ignore' });
338
+ }
339
+ catch (err) {
340
+ throw new Error('notify-send not available on this system');
341
+ }
342
+ }
343
+ /**
344
+ * Windows notification using PowerShell toast
345
+ */
346
+ async sendNotificationWindows(title, body) {
347
+ const escapedTitle = title.replace(/'/g, "''");
348
+ const escapedBody = body.replace(/'/g, "''");
349
+ const psScript = `
350
+ [Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime] | Out-Null;
351
+ $template = [Windows.UI.Notifications.ToastNotificationManager]::GetTemplateContent([Windows.UI.Notifications.ToastTemplateType]::ToastText02);
352
+ $xml = [xml]$template.GetXml();
353
+ $xml.GetElementsByTagName('text')[0].AppendChild($xml.CreateTextNode('${escapedTitle}')) | Out-Null;
354
+ $xml.GetElementsByTagName('text')[1].AppendChild($xml.CreateTextNode('${escapedBody}')) | Out-Null;
355
+ $toast = [Windows.UI.Notifications.ToastNotification]::new($xml);
356
+ [Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier('SpecWeave').Show($toast);
357
+ `;
358
+ execSync(`powershell -Command "${psScript}"`, {
359
+ stdio: 'ignore',
360
+ windowsHide: true
361
+ });
362
+ }
363
+ }
364
+ // Export singleton instance for convenience
365
+ export const platformUtils = new PlatformUtils();
366
+ //# sourceMappingURL=platform-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform-utils.js","sourceRoot":"","sources":["../../../src/utils/platform-utils.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,142 @@
1
+ /**
2
+ * Session Registry - Central tracking for all Claude Code sessions and child processes
3
+ *
4
+ * Provides atomic file-based operations for tracking active sessions, detecting
5
+ * stale/zombie processes, and coordinating cleanup across multiple sessions.
6
+ *
7
+ * Key Features:
8
+ * - Atomic operations using temp file + rename pattern
9
+ * - File locking via mkdir (cross-platform atomic operation)
10
+ * - Automatic corruption recovery with JSON validation
11
+ * - Concurrent-safe updates from multiple processes
12
+ *
13
+ * Registry Location: `.specweave/state/.session-registry.json`
14
+ */
15
+ import { SessionInfo, RegisterSessionOptions, StaleSessionInfo, SessionStatus } from '../types/session.js';
16
+ import { Logger } from './logger.js';
17
+ export declare class SessionRegistry {
18
+ private registryPath;
19
+ private lockPath;
20
+ private logger;
21
+ constructor(projectRoot: string, options?: {
22
+ logger?: Logger;
23
+ });
24
+ /**
25
+ * Acquires an exclusive lock on the registry file
26
+ *
27
+ * Uses mkdir as an atomic operation (works cross-platform)
28
+ * Waits up to LOCK_TIMEOUT_MS before failing
29
+ *
30
+ * @returns true if lock acquired, false if timeout
31
+ */
32
+ private acquireLock;
33
+ /**
34
+ * Releases the lock on the registry file
35
+ */
36
+ private releaseLock;
37
+ /**
38
+ * Reads the registry file with corruption recovery
39
+ *
40
+ * If registry doesn't exist, creates a new empty one
41
+ * If registry is corrupted (invalid JSON), creates backup and reinitializes
42
+ *
43
+ * @returns The current registry state
44
+ */
45
+ private readRegistry;
46
+ /**
47
+ * Writes registry to disk atomically
48
+ *
49
+ * Uses temp file + rename pattern for atomic write
50
+ * This ensures registry is never left in a corrupted state
51
+ *
52
+ * @param registry - The registry state to write
53
+ */
54
+ private writeRegistry;
55
+ /**
56
+ * Creates a new empty registry
57
+ */
58
+ private createEmptyRegistry;
59
+ /**
60
+ * Registers a new session in the registry
61
+ *
62
+ * @param sessionId - Unique session identifier
63
+ * @param pid - Process ID of the session
64
+ * @param options - Optional configuration
65
+ * @returns true if registration successful
66
+ */
67
+ registerSession(sessionId: string, pid: number, options?: RegisterSessionOptions): Promise<boolean>;
68
+ /**
69
+ * Updates the heartbeat timestamp for a session
70
+ *
71
+ * @param sessionId - Session to update
72
+ * @returns true if update successful
73
+ */
74
+ updateHeartbeat(sessionId: string): Promise<boolean>;
75
+ /**
76
+ * Adds a child process PID to a session
77
+ *
78
+ * @param sessionId - Parent session ID
79
+ * @param childPid - Child process PID to add
80
+ * @returns true if successful
81
+ */
82
+ addChildProcess(sessionId: string, childPid: number): Promise<boolean>;
83
+ /**
84
+ * Removes a session from the registry
85
+ *
86
+ * @param sessionId - Session to remove
87
+ * @returns true if successful
88
+ */
89
+ removeSession(sessionId: string): Promise<boolean>;
90
+ /**
91
+ * Gets a session by ID
92
+ *
93
+ * @param sessionId - Session to retrieve
94
+ * @returns Session info or undefined
95
+ */
96
+ getSession(sessionId: string): Promise<SessionInfo | undefined>;
97
+ /**
98
+ * Gets all sessions
99
+ *
100
+ * @returns Array of all session info
101
+ */
102
+ getAllSessions(): Promise<SessionInfo[]>;
103
+ /**
104
+ * Updates the status of a session
105
+ *
106
+ * @param sessionId - Session to update
107
+ * @param status - New status
108
+ * @returns true if successful
109
+ */
110
+ updateStatus(sessionId: string, status: SessionStatus): Promise<boolean>;
111
+ /**
112
+ * Gets all stale sessions based on heartbeat threshold
113
+ *
114
+ * A session is considered stale if its last_heartbeat is older than
115
+ * the specified threshold.
116
+ *
117
+ * @param thresholdSeconds - Max age of last heartbeat before considered stale
118
+ * @returns Array of stale session info with staleness details
119
+ */
120
+ getStaleSessions(thresholdSeconds: number): Promise<StaleSessionInfo[]>;
121
+ /**
122
+ * Cleans up old sessions based on retention period
123
+ *
124
+ * Removes sessions that have been completed or stale for longer
125
+ * than the retention period.
126
+ *
127
+ * @param retentionHours - How long to keep old sessions (in hours)
128
+ * @returns Number of sessions removed
129
+ */
130
+ cleanupOldSessions(retentionHours: number): Promise<number>;
131
+ /**
132
+ * Checks if a PID exists (cross-platform)
133
+ *
134
+ * Uses kill -0 on Unix-like systems, which doesn't actually send a signal
135
+ * but checks if the process exists.
136
+ *
137
+ * @param pid - Process ID to check
138
+ * @returns true if process exists
139
+ */
140
+ private checkPidExists;
141
+ }
142
+ //# sourceMappingURL=session-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-registry.d.ts","sourceRoot":"","sources":["../../../src/utils/session-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,OAAO,EACL,WAAW,EAEX,sBAAsB,EACtB,gBAAgB,EAChB,aAAa,EACd,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,MAAM,EAAiB,MAAM,aAAa,CAAC;AAOpD,qBAAa,eAAe;IAC1B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,MAAM,CAAS;gBAEX,WAAW,EAAE,MAAM,EAAE,OAAO,GAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAO;IAclE;;;;;;;OAOG;YACW,WAAW;IA4BzB;;OAEG;IACH,OAAO,CAAC,WAAW;IAenB;;;;;;;OAOG;IACH,OAAO,CAAC,YAAY;IAsCpB;;;;;;;OAOG;IACH,OAAO,CAAC,aAAa;IAyBrB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAQ3B;;;;;;;OAOG;IACG,eAAe,CACnB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,OAAO,CAAC;IAuCnB;;;;;OAKG;IACG,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAyB1D;;;;;;OAMG;IACG,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAgC5E;;;;;OAKG;IACG,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAwBxD;;;;;OAKG;IACG,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC;IAcrE;;;;OAIG;IACG,cAAc,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;IAc9C;;;;;;OAMG;IACG,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC;IAwB9E;;;;;;;;OAQG;IACG,gBAAgB,CAAC,gBAAgB,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAyC7E;;;;;;;;OAQG;IACG,kBAAkB,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAgDjE;;;;;;;;OAQG;YACW,cAAc;CAuB7B"}