specweave 0.32.10 → 0.33.3

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 (224) hide show
  1. package/CLAUDE.md +162 -1
  2. package/dist/plugins/specweave-ado/lib/per-us-sync.d.ts +120 -0
  3. package/dist/plugins/specweave-ado/lib/per-us-sync.d.ts.map +1 -0
  4. package/dist/plugins/specweave-ado/lib/per-us-sync.js +276 -0
  5. package/dist/plugins/specweave-ado/lib/per-us-sync.js.map +1 -0
  6. package/dist/plugins/specweave-github/lib/github-client-v2.d.ts +4 -1
  7. package/dist/plugins/specweave-github/lib/github-client-v2.d.ts.map +1 -1
  8. package/dist/plugins/specweave-github/lib/github-client-v2.js +13 -3
  9. package/dist/plugins/specweave-github/lib/github-client-v2.js.map +1 -1
  10. package/dist/plugins/specweave-github/lib/per-us-sync.d.ts +97 -0
  11. package/dist/plugins/specweave-github/lib/per-us-sync.d.ts.map +1 -0
  12. package/dist/plugins/specweave-github/lib/per-us-sync.js +274 -0
  13. package/dist/plugins/specweave-github/lib/per-us-sync.js.map +1 -0
  14. package/dist/plugins/specweave-jira/lib/per-us-sync.d.ts +113 -0
  15. package/dist/plugins/specweave-jira/lib/per-us-sync.d.ts.map +1 -0
  16. package/dist/plugins/specweave-jira/lib/per-us-sync.js +254 -0
  17. package/dist/plugins/specweave-jira/lib/per-us-sync.js.map +1 -0
  18. package/dist/src/cli/add-child-pid.d.ts +11 -0
  19. package/dist/src/cli/add-child-pid.d.ts.map +1 -0
  20. package/dist/src/cli/add-child-pid.js +42 -0
  21. package/dist/src/cli/add-child-pid.js.map +1 -0
  22. package/dist/src/cli/add-child-process.d.ts +15 -0
  23. package/dist/src/cli/add-child-process.d.ts.map +1 -0
  24. package/dist/src/cli/add-child-process.js +40 -0
  25. package/dist/src/cli/add-child-process.js.map +1 -0
  26. package/dist/src/cli/check-watchdog.d.ts +15 -0
  27. package/dist/src/cli/check-watchdog.d.ts.map +1 -0
  28. package/dist/src/cli/check-watchdog.js +47 -0
  29. package/dist/src/cli/check-watchdog.js.map +1 -0
  30. package/dist/src/cli/cleanup-zombies.d.ts +14 -0
  31. package/dist/src/cli/cleanup-zombies.d.ts.map +1 -0
  32. package/dist/src/cli/cleanup-zombies.js +268 -0
  33. package/dist/src/cli/cleanup-zombies.js.map +1 -0
  34. package/dist/src/cli/find-session-by-pid.d.ts +14 -0
  35. package/dist/src/cli/find-session-by-pid.d.ts.map +1 -0
  36. package/dist/src/cli/find-session-by-pid.js +45 -0
  37. package/dist/src/cli/find-session-by-pid.js.map +1 -0
  38. package/dist/src/cli/get-stale-sessions.d.ts +17 -0
  39. package/dist/src/cli/get-stale-sessions.d.ts.map +1 -0
  40. package/dist/src/cli/get-stale-sessions.js +36 -0
  41. package/dist/src/cli/get-stale-sessions.js.map +1 -0
  42. package/dist/src/cli/register-session.d.ts +16 -0
  43. package/dist/src/cli/register-session.d.ts.map +1 -0
  44. package/dist/src/cli/register-session.js +48 -0
  45. package/dist/src/cli/register-session.js.map +1 -0
  46. package/dist/src/cli/remove-session.d.ts +11 -0
  47. package/dist/src/cli/remove-session.d.ts.map +1 -0
  48. package/dist/src/cli/remove-session.js +36 -0
  49. package/dist/src/cli/remove-session.js.map +1 -0
  50. package/dist/src/cli/update-heartbeat.d.ts +11 -0
  51. package/dist/src/cli/update-heartbeat.d.ts.map +1 -0
  52. package/dist/src/cli/update-heartbeat.js +36 -0
  53. package/dist/src/cli/update-heartbeat.js.map +1 -0
  54. package/dist/src/config/types.d.ts +1208 -203
  55. package/dist/src/config/types.d.ts.map +1 -1
  56. package/dist/src/core/background/job-manager.d.ts +16 -0
  57. package/dist/src/core/background/job-manager.d.ts.map +1 -1
  58. package/dist/src/core/background/job-manager.js +110 -15
  59. package/dist/src/core/background/job-manager.js.map +1 -1
  60. package/dist/src/core/config/config-manager.d.ts.map +1 -1
  61. package/dist/src/core/config/config-manager.js +58 -0
  62. package/dist/src/core/config/config-manager.js.map +1 -1
  63. package/dist/src/core/config/types.d.ts +80 -0
  64. package/dist/src/core/config/types.d.ts.map +1 -1
  65. package/dist/src/core/config/types.js.map +1 -1
  66. package/dist/src/core/increment/increment-utils.d.ts +26 -1
  67. package/dist/src/core/increment/increment-utils.d.ts.map +1 -1
  68. package/dist/src/core/increment/increment-utils.js +66 -4
  69. package/dist/src/core/increment/increment-utils.js.map +1 -1
  70. package/dist/src/core/increment/status-change-sync-trigger.d.ts +3 -1
  71. package/dist/src/core/increment/status-change-sync-trigger.d.ts.map +1 -1
  72. package/dist/src/core/increment/status-change-sync-trigger.js +5 -2
  73. package/dist/src/core/increment/status-change-sync-trigger.js.map +1 -1
  74. package/dist/src/core/living-docs/cross-project-sync.d.ts +87 -15
  75. package/dist/src/core/living-docs/cross-project-sync.d.ts.map +1 -1
  76. package/dist/src/core/living-docs/cross-project-sync.js +147 -28
  77. package/dist/src/core/living-docs/cross-project-sync.js.map +1 -1
  78. package/dist/src/core/living-docs/intelligent-analyzer/architecture-generator.d.ts.map +1 -1
  79. package/dist/src/core/living-docs/intelligent-analyzer/architecture-generator.js +48 -12
  80. package/dist/src/core/living-docs/intelligent-analyzer/architecture-generator.js.map +1 -1
  81. package/dist/src/core/living-docs/intelligent-analyzer/cache-manager.d.ts +70 -0
  82. package/dist/src/core/living-docs/intelligent-analyzer/cache-manager.d.ts.map +1 -0
  83. package/dist/src/core/living-docs/intelligent-analyzer/cache-manager.js +188 -0
  84. package/dist/src/core/living-docs/intelligent-analyzer/cache-manager.js.map +1 -0
  85. package/dist/src/core/living-docs/intelligent-analyzer/dashboard-generator.d.ts +33 -0
  86. package/dist/src/core/living-docs/intelligent-analyzer/dashboard-generator.d.ts.map +1 -0
  87. package/dist/src/core/living-docs/intelligent-analyzer/dashboard-generator.js +290 -0
  88. package/dist/src/core/living-docs/intelligent-analyzer/dashboard-generator.js.map +1 -0
  89. package/dist/src/core/living-docs/intelligent-analyzer/deep-repo-analyzer.d.ts.map +1 -1
  90. package/dist/src/core/living-docs/intelligent-analyzer/deep-repo-analyzer.js +114 -11
  91. package/dist/src/core/living-docs/intelligent-analyzer/deep-repo-analyzer.js.map +1 -1
  92. package/dist/src/core/living-docs/intelligent-analyzer/graph-visualizer.d.ts +23 -0
  93. package/dist/src/core/living-docs/intelligent-analyzer/graph-visualizer.d.ts.map +1 -0
  94. package/dist/src/core/living-docs/intelligent-analyzer/graph-visualizer.js +283 -0
  95. package/dist/src/core/living-docs/intelligent-analyzer/graph-visualizer.js.map +1 -0
  96. package/dist/src/core/living-docs/intelligent-analyzer/mermaid-generator.d.ts +44 -0
  97. package/dist/src/core/living-docs/intelligent-analyzer/mermaid-generator.d.ts.map +1 -0
  98. package/dist/src/core/living-docs/intelligent-analyzer/mermaid-generator.js +61 -0
  99. package/dist/src/core/living-docs/intelligent-analyzer/mermaid-generator.js.map +1 -0
  100. package/dist/src/core/living-docs/intelligent-analyzer/orchestrator.d.ts +126 -0
  101. package/dist/src/core/living-docs/intelligent-analyzer/orchestrator.d.ts.map +1 -0
  102. package/dist/src/core/living-docs/intelligent-analyzer/orchestrator.js +378 -0
  103. package/dist/src/core/living-docs/intelligent-analyzer/orchestrator.js.map +1 -0
  104. package/dist/src/core/living-docs/intelligent-analyzer/organization-synthesizer.d.ts.map +1 -1
  105. package/dist/src/core/living-docs/intelligent-analyzer/organization-synthesizer.js +57 -0
  106. package/dist/src/core/living-docs/intelligent-analyzer/organization-synthesizer.js.map +1 -1
  107. package/dist/src/core/living-docs/intelligent-analyzer/pattern-analyzer.d.ts +82 -0
  108. package/dist/src/core/living-docs/intelligent-analyzer/pattern-analyzer.d.ts.map +1 -0
  109. package/dist/src/core/living-docs/intelligent-analyzer/pattern-analyzer.js +430 -0
  110. package/dist/src/core/living-docs/intelligent-analyzer/pattern-analyzer.js.map +1 -0
  111. package/dist/src/core/living-docs/intelligent-analyzer/repo-scanner.d.ts +84 -0
  112. package/dist/src/core/living-docs/intelligent-analyzer/repo-scanner.d.ts.map +1 -0
  113. package/dist/src/core/living-docs/intelligent-analyzer/repo-scanner.js +387 -0
  114. package/dist/src/core/living-docs/intelligent-analyzer/repo-scanner.js.map +1 -0
  115. package/dist/src/core/living-docs/intelligent-analyzer/report-writer.d.ts +61 -0
  116. package/dist/src/core/living-docs/intelligent-analyzer/report-writer.d.ts.map +1 -0
  117. package/dist/src/core/living-docs/intelligent-analyzer/report-writer.js +174 -0
  118. package/dist/src/core/living-docs/intelligent-analyzer/report-writer.js.map +1 -0
  119. package/dist/src/core/living-docs/intelligent-analyzer/types.d.ts +1 -1
  120. package/dist/src/core/living-docs/intelligent-analyzer/types.d.ts.map +1 -1
  121. package/dist/src/core/living-docs/living-docs-sync.d.ts.map +1 -1
  122. package/dist/src/core/living-docs/living-docs-sync.js +26 -22
  123. package/dist/src/core/living-docs/living-docs-sync.js.map +1 -1
  124. package/dist/src/core/living-docs/module-analyzer.d.ts +3 -0
  125. package/dist/src/core/living-docs/module-analyzer.d.ts.map +1 -1
  126. package/dist/src/core/living-docs/module-analyzer.js +40 -1
  127. package/dist/src/core/living-docs/module-analyzer.js.map +1 -1
  128. package/dist/src/core/living-docs/types.d.ts +24 -3
  129. package/dist/src/core/living-docs/types.d.ts.map +1 -1
  130. package/dist/src/core/qa/qa-runner.js +1 -1
  131. package/dist/src/core/qa/qa-runner.js.map +1 -1
  132. package/dist/src/core/scheduler/session-sync-executor.js +1 -1
  133. package/dist/src/core/scheduler/session-sync-executor.js.map +1 -1
  134. package/dist/src/core/status-line/status-line-updater.d.ts +1 -1
  135. package/dist/src/core/status-line/status-line-updater.d.ts.map +1 -1
  136. package/dist/src/core/status-line/status-line-updater.js +4 -3
  137. package/dist/src/core/status-line/status-line-updater.js.map +1 -1
  138. package/dist/src/core/types/config.d.ts +79 -0
  139. package/dist/src/core/types/config.d.ts.map +1 -1
  140. package/dist/src/core/types/config.js.map +1 -1
  141. package/dist/src/importers/jira-importer.d.ts.map +1 -1
  142. package/dist/src/importers/jira-importer.js +18 -9
  143. package/dist/src/importers/jira-importer.js.map +1 -1
  144. package/dist/src/init/architecture/types.d.ts +140 -33
  145. package/dist/src/init/architecture/types.d.ts.map +1 -1
  146. package/dist/src/init/compliance/types.d.ts +27 -30
  147. package/dist/src/init/compliance/types.d.ts.map +1 -1
  148. package/dist/src/init/repo/types.d.ts +34 -11
  149. package/dist/src/init/repo/types.d.ts.map +1 -1
  150. package/dist/src/init/research/src/config/types.d.ts +82 -15
  151. package/dist/src/init/research/src/config/types.d.ts.map +1 -1
  152. package/dist/src/init/research/types.d.ts +93 -38
  153. package/dist/src/init/research/types.d.ts.map +1 -1
  154. package/dist/src/init/team/types.d.ts +42 -4
  155. package/dist/src/init/team/types.d.ts.map +1 -1
  156. package/dist/src/sync/ado-reconciler.js +1 -1
  157. package/dist/src/sync/ado-reconciler.js.map +1 -1
  158. package/dist/src/sync/github-reconciler.js +1 -1
  159. package/dist/src/sync/github-reconciler.js.map +1 -1
  160. package/dist/src/sync/jira-reconciler.js +1 -1
  161. package/dist/src/sync/jira-reconciler.js.map +1 -1
  162. package/dist/src/sync/sync-coordinator.d.ts +20 -0
  163. package/dist/src/sync/sync-coordinator.d.ts.map +1 -1
  164. package/dist/src/sync/sync-coordinator.js +258 -33
  165. package/dist/src/sync/sync-coordinator.js.map +1 -1
  166. package/dist/src/types/session.d.ts +65 -0
  167. package/dist/src/types/session.d.ts.map +1 -0
  168. package/dist/src/types/session.js +8 -0
  169. package/dist/src/types/session.js.map +1 -0
  170. package/dist/src/utils/lock-manager.d.ts +48 -0
  171. package/dist/src/utils/lock-manager.d.ts.map +1 -0
  172. package/dist/src/utils/lock-manager.js +195 -0
  173. package/dist/src/utils/lock-manager.js.map +1 -0
  174. package/dist/src/utils/notification-manager.d.ts +45 -0
  175. package/dist/src/utils/notification-manager.d.ts.map +1 -0
  176. package/dist/src/utils/notification-manager.js +130 -0
  177. package/dist/src/utils/notification-manager.js.map +1 -0
  178. package/dist/src/utils/platform-utils.d.ts +136 -0
  179. package/dist/src/utils/platform-utils.d.ts.map +1 -0
  180. package/dist/src/utils/platform-utils.js +366 -0
  181. package/dist/src/utils/platform-utils.js.map +1 -0
  182. package/dist/src/utils/project-resolver.d.ts +156 -0
  183. package/dist/src/utils/project-resolver.d.ts.map +1 -0
  184. package/dist/src/utils/project-resolver.js +587 -0
  185. package/dist/src/utils/project-resolver.js.map +1 -0
  186. package/dist/src/utils/session-registry.d.ts +142 -0
  187. package/dist/src/utils/session-registry.d.ts.map +1 -0
  188. package/dist/src/utils/session-registry.js +480 -0
  189. package/dist/src/utils/session-registry.js.map +1 -0
  190. package/package.json +5 -2
  191. package/plugins/specweave/commands/specweave-living-docs.md +42 -0
  192. package/plugins/specweave/hooks/hooks.json +20 -0
  193. package/plugins/specweave/hooks/lib/update-active-increment.sh +2 -2
  194. package/plugins/specweave/hooks/lib/update-status-line.sh +1 -1
  195. package/plugins/specweave/hooks/post-increment-status-change.sh +3 -3
  196. package/plugins/specweave/hooks/post-metadata-change.sh +1 -1
  197. package/plugins/specweave/hooks/universal/hook-wrapper.cmd +26 -26
  198. package/plugins/specweave/hooks/universal/session-start.cmd +16 -16
  199. package/plugins/specweave/hooks/universal/session-start.ps1 +16 -16
  200. package/plugins/specweave/hooks/user-prompt-submit.sh +107 -5
  201. package/plugins/specweave/hooks/v2/guards/increment-root-guard.sh +61 -0
  202. package/plugins/specweave/hooks/v2/guards/per-us-project-validator.sh +281 -0
  203. package/plugins/specweave/hooks/v2/handlers/living-specs-handler.sh +29 -0
  204. package/plugins/specweave/hooks/v2/session-end.sh +69 -0
  205. package/plugins/specweave/hooks/v2/session-start.sh +81 -0
  206. package/plugins/specweave/lib/vendor/sync/github-reconciler.js +1 -1
  207. package/plugins/specweave/lib/vendor/sync/github-reconciler.js.map +1 -1
  208. package/plugins/specweave/scripts/heartbeat.sh +110 -0
  209. package/plugins/specweave/scripts/progress.js +34 -4
  210. package/plugins/specweave/scripts/read-jobs.sh +1 -1
  211. package/plugins/specweave/scripts/read-progress.sh +50 -5
  212. package/plugins/specweave/scripts/read-workflow.sh +1 -1
  213. package/plugins/specweave/scripts/session-watchdog.sh +65 -0
  214. package/plugins/specweave/scripts/status.js +28 -11
  215. package/plugins/specweave-ado/lib/per-us-sync.js +247 -0
  216. package/plugins/specweave-ado/lib/per-us-sync.ts +410 -0
  217. package/plugins/specweave-github/hooks/.specweave/logs/hooks-debug.log +738 -0
  218. package/plugins/specweave-github/lib/github-client-v2.js +10 -3
  219. package/plugins/specweave-github/lib/github-client-v2.ts +15 -3
  220. package/plugins/specweave-github/lib/per-us-sync.js +241 -0
  221. package/plugins/specweave-github/lib/per-us-sync.ts +375 -0
  222. package/plugins/specweave-jira/lib/per-us-sync.js +224 -0
  223. package/plugins/specweave-jira/lib/per-us-sync.ts +366 -0
  224. package/plugins/specweave-release/hooks/.specweave/logs/dora-tracking.log +1107 -0
@@ -0,0 +1,268 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Cleanup Zombies CLI
4
+ *
5
+ * Detects and cleans up zombie/stale processes
6
+ *
7
+ * Usage:
8
+ * node dist/src/cli/cleanup-zombies.js [threshold-seconds]
9
+ *
10
+ * Arguments:
11
+ * threshold-seconds: Heartbeat age threshold (default: 60)
12
+ */
13
+ import { SessionRegistry } from '../utils/session-registry.js';
14
+ import { consoleLogger } from '../utils/logger.js';
15
+ import * as childProcess from 'child_process';
16
+ import * as util from 'util';
17
+ import * as fs from 'fs';
18
+ import * as path from 'path';
19
+ const exec = util.promisify(childProcess.exec);
20
+ // Cleanup logging
21
+ function logCleanupAction(level, action, details) {
22
+ const logDir = path.join(process.cwd(), '.specweave', 'logs');
23
+ const logFile = path.join(logDir, 'cleanup.log');
24
+ // Ensure log directory exists
25
+ if (!fs.existsSync(logDir)) {
26
+ fs.mkdirSync(logDir, { recursive: true });
27
+ }
28
+ const timestamp = new Date().toISOString();
29
+ const logEntry = `[${timestamp}] [${level}] [${action}] ${details}\n`;
30
+ try {
31
+ fs.appendFileSync(logFile, logEntry, 'utf-8');
32
+ }
33
+ catch (err) {
34
+ // If we can't log, just continue
35
+ console.error('Failed to write cleanup log:', err);
36
+ }
37
+ }
38
+ async function killProcess(pid, signal = 'SIGTERM') {
39
+ try {
40
+ process.kill(pid, signal);
41
+ }
42
+ catch (err) {
43
+ // Process may not exist, ignore
44
+ }
45
+ }
46
+ async function validatePidIsSpecWeave(pid) {
47
+ try {
48
+ const { stdout } = await exec(`ps -p ${pid} -o command= || true`);
49
+ const command = stdout.trim().toLowerCase();
50
+ // Valid SpecWeave/Claude processes
51
+ const validPatterns = [
52
+ 'claude',
53
+ 'specweave',
54
+ 'cat.*eof',
55
+ 'esbuild',
56
+ 'processor.sh',
57
+ 'session-watchdog',
58
+ 'heartbeat.sh',
59
+ 'node.*specweave',
60
+ 'bash.*specweave',
61
+ ];
62
+ return validPatterns.some((pattern) => {
63
+ const regex = new RegExp(pattern, 'i');
64
+ return regex.test(command);
65
+ });
66
+ }
67
+ catch {
68
+ // If we can't determine, err on the side of caution
69
+ return false;
70
+ }
71
+ }
72
+ async function killZombieProcesses(registry) {
73
+ let killedCount = 0;
74
+ let skippedCount = 0;
75
+ // Pattern 1: Heredoc zombies
76
+ try {
77
+ const { stdout } = await exec("pgrep -f 'cat.*EOF' || true");
78
+ const pids = stdout
79
+ .trim()
80
+ .split('\n')
81
+ .filter((p) => p);
82
+ for (const pidStr of pids) {
83
+ const pid = parseInt(pidStr, 10);
84
+ if (!isNaN(pid)) {
85
+ await killProcess(pid, 'SIGKILL');
86
+ const msg = `Killed heredoc zombie: PID ${pid}`;
87
+ console.log(msg);
88
+ logCleanupAction('INFO', 'KILL_ZOMBIE', `heredoc cat EOF process - PID ${pid}`);
89
+ killedCount++;
90
+ }
91
+ }
92
+ }
93
+ catch (err) {
94
+ // Ignore errors
95
+ }
96
+ // Pattern 2: Stale esbuild services (>1 hour old)
97
+ try {
98
+ const { stdout } = await exec("pgrep -f 'esbuild.*--service' || true");
99
+ const pids = stdout
100
+ .trim()
101
+ .split('\n')
102
+ .filter((p) => p);
103
+ for (const pidStr of pids) {
104
+ const pid = parseInt(pidStr, 10);
105
+ if (!isNaN(pid)) {
106
+ // Check age using ps
107
+ try {
108
+ const { stdout: psOut } = await exec(`ps -o etime= -p ${pid}`);
109
+ const etime = psOut.trim();
110
+ // Parse elapsed time (format: [[dd-]hh:]mm:ss)
111
+ const parts = etime.split(/[-:]/);
112
+ let totalSeconds = 0;
113
+ if (parts.length >= 2) {
114
+ const seconds = parseInt(parts[parts.length - 1], 10);
115
+ const minutes = parseInt(parts[parts.length - 2], 10);
116
+ totalSeconds = minutes * 60 + seconds;
117
+ if (parts.length >= 3) {
118
+ const hours = parseInt(parts[parts.length - 3], 10);
119
+ totalSeconds += hours * 3600;
120
+ }
121
+ if (parts.length >= 4) {
122
+ const days = parseInt(parts[parts.length - 4], 10);
123
+ totalSeconds += days * 86400;
124
+ }
125
+ }
126
+ // Kill if older than 1 hour
127
+ if (totalSeconds > 3600) {
128
+ await killProcess(pid, 'SIGKILL');
129
+ const ageMinutes = Math.floor(totalSeconds / 60);
130
+ console.log(`Killed stale esbuild: PID ${pid} (age: ${ageMinutes}m)`);
131
+ logCleanupAction('INFO', 'KILL_ZOMBIE', `stale esbuild service - PID ${pid} - age ${ageMinutes}m`);
132
+ killedCount++;
133
+ }
134
+ }
135
+ catch (err) {
136
+ // Ignore errors
137
+ }
138
+ }
139
+ }
140
+ }
141
+ catch (err) {
142
+ // Ignore errors
143
+ }
144
+ // Pattern 3: Orphaned processor.sh daemons (not in registry)
145
+ try {
146
+ const { stdout } = await exec("pgrep -f 'processor\\.sh.*--daemon' || true");
147
+ const pids = stdout
148
+ .trim()
149
+ .split('\n')
150
+ .filter((p) => p);
151
+ for (const pidStr of pids) {
152
+ const pid = parseInt(pidStr, 10);
153
+ if (!isNaN(pid)) {
154
+ // Check if this processor is registered in any session
155
+ const sessions = await registry.getAllSessions();
156
+ const isRegistered = sessions.some((s) => s.child_pids?.includes(pid) || s.pid === pid);
157
+ if (!isRegistered) {
158
+ // Orphaned processor daemon - kill it
159
+ await killProcess(pid, 'SIGTERM');
160
+ await new Promise((resolve) => setTimeout(resolve, 1000));
161
+ await killProcess(pid, 'SIGKILL');
162
+ console.log(`Killed orphaned processor daemon: PID ${pid}`);
163
+ logCleanupAction('INFO', 'KILL_ZOMBIE', `orphaned processor.sh daemon - PID ${pid} - not in registry`);
164
+ killedCount++;
165
+ }
166
+ }
167
+ }
168
+ }
169
+ catch (err) {
170
+ // Ignore errors
171
+ }
172
+ return { killed: killedCount, skipped: skippedCount };
173
+ }
174
+ async function main() {
175
+ const thresholdArg = process.argv[2];
176
+ const threshold = thresholdArg ? parseInt(thresholdArg, 10) : 60;
177
+ if (isNaN(threshold)) {
178
+ console.error('Invalid threshold:', thresholdArg);
179
+ process.exit(1);
180
+ }
181
+ const registry = new SessionRegistry(process.cwd(), { logger: consoleLogger });
182
+ try {
183
+ // Get stale sessions
184
+ const staleSessions = await registry.getStaleSessions(threshold);
185
+ let totalKilled = 0;
186
+ // Kill stale session processes
187
+ for (const staleInfo of staleSessions) {
188
+ const { session, pid_exists } = staleInfo;
189
+ const staleAge = Math.floor(staleInfo.stale_duration_seconds);
190
+ console.log(`Found stale session: ${session.session_id} (PID: ${session.pid}, ${staleAge}s old)`);
191
+ logCleanupAction('INFO', 'DETECT_STALE', `session ${session.session_id} - PID ${session.pid} - age ${staleAge}s`);
192
+ // PID validation: ensure process is SpecWeave-related
193
+ if (pid_exists) {
194
+ const isValid = await validatePidIsSpecWeave(session.pid);
195
+ if (!isValid) {
196
+ console.log(` ⚠️ Skipping PID ${session.pid} - not a SpecWeave process`);
197
+ logCleanupAction('WARN', 'SKIP_PID', `PID ${session.pid} not a SpecWeave process - removed from registry only`);
198
+ // Remove from registry but don't kill
199
+ await registry.removeSession(session.session_id);
200
+ continue;
201
+ }
202
+ }
203
+ // Kill parent process
204
+ if (pid_exists) {
205
+ await killProcess(session.pid, 'SIGTERM');
206
+ // Wait 2 seconds, then SIGKILL if still exists
207
+ await new Promise((resolve) => setTimeout(resolve, 2000));
208
+ await killProcess(session.pid, 'SIGKILL');
209
+ console.log(` Killed parent PID: ${session.pid}`);
210
+ logCleanupAction('INFO', 'KILL_PARENT', `session ${session.session_id} - PID ${session.pid} - SIGTERM -> SIGKILL`);
211
+ totalKilled++;
212
+ }
213
+ // Kill child processes
214
+ if (session.child_pids && session.child_pids.length > 0) {
215
+ for (const childPid of session.child_pids) {
216
+ await killProcess(childPid, 'SIGTERM');
217
+ await new Promise((resolve) => setTimeout(resolve, 1000));
218
+ await killProcess(childPid, 'SIGKILL');
219
+ console.log(` Killed child PID: ${childPid}`);
220
+ logCleanupAction('INFO', 'KILL_CHILD', `session ${session.session_id} - child PID ${childPid}`);
221
+ totalKilled++;
222
+ }
223
+ }
224
+ // Remove from registry
225
+ await registry.removeSession(session.session_id);
226
+ logCleanupAction('INFO', 'REMOVE_SESSION', `session ${session.session_id} removed from registry`);
227
+ }
228
+ // Kill zombie processes by pattern
229
+ const zombieResults = await killZombieProcesses(registry);
230
+ totalKilled += zombieResults.killed;
231
+ if (totalKilled > 0) {
232
+ console.log(`\nTotal processes cleaned up: ${totalKilled}`);
233
+ logCleanupAction('INFO', 'SUMMARY', `Total processes cleaned: ${totalKilled}`);
234
+ // Send notification if >3 processes cleaned
235
+ if (totalKilled > 3) {
236
+ const title = '🚨 Zombie Cleanup';
237
+ const message = `Cleaned up ${totalKilled} zombie processes`;
238
+ try {
239
+ if (process.platform === 'darwin') {
240
+ // macOS notification
241
+ await exec(`osascript -e 'display notification "${message}" with title "${title}" sound name "Glass"'`);
242
+ }
243
+ else if (process.platform === 'linux') {
244
+ // Linux notification
245
+ await exec(`notify-send "${title}" "${message}" --urgency=normal`);
246
+ }
247
+ else if (process.platform === 'win32') {
248
+ // Windows notification (PowerShell)
249
+ const psScript = `[Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime] > $null; $null`;
250
+ await exec(`powershell -Command "${psScript}"`);
251
+ }
252
+ logCleanupAction('INFO', 'NOTIFICATION', `Sent notification - ${totalKilled} processes cleaned`);
253
+ }
254
+ catch (err) {
255
+ // Ignore notification errors
256
+ logCleanupAction('WARN', 'NOTIFICATION', `Failed to send notification: ${err}`);
257
+ }
258
+ }
259
+ }
260
+ process.exit(0);
261
+ }
262
+ catch (err) {
263
+ console.error('Error during cleanup:', err);
264
+ process.exit(1);
265
+ }
266
+ }
267
+ main();
268
+ //# sourceMappingURL=cleanup-zombies.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cleanup-zombies.js","sourceRoot":"","sources":["../../../src/cli/cleanup-zombies.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Find Session By PID CLI
4
+ *
5
+ * Finds a session in the registry by its PID
6
+ *
7
+ * Usage:
8
+ * node dist/src/cli/find-session-by-pid.js <pid>
9
+ *
10
+ * Output:
11
+ * JSON session info or empty string
12
+ */
13
+ export {};
14
+ //# sourceMappingURL=find-session-by-pid.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"find-session-by-pid.d.ts","sourceRoot":"","sources":["../../../src/cli/find-session-by-pid.ts"],"names":[],"mappings":";AACA;;;;;;;;;;GAUG"}
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Find Session By PID CLI
4
+ *
5
+ * Finds a session in the registry by its PID
6
+ *
7
+ * Usage:
8
+ * node dist/src/cli/find-session-by-pid.js <pid>
9
+ *
10
+ * Output:
11
+ * JSON session info or empty string
12
+ */
13
+ import { SessionRegistry } from '../utils/session-registry.js';
14
+ import { consoleLogger } from '../utils/logger.js';
15
+ async function main() {
16
+ const pidStr = process.argv[2];
17
+ if (!pidStr) {
18
+ console.error('Usage: node find-session-by-pid.js <pid>');
19
+ process.exit(1);
20
+ }
21
+ const pid = parseInt(pidStr, 10);
22
+ if (isNaN(pid)) {
23
+ console.error(`Invalid PID: ${pidStr}`);
24
+ process.exit(1);
25
+ }
26
+ const registry = new SessionRegistry(process.cwd(), { logger: consoleLogger });
27
+ try {
28
+ const sessions = await registry.getAllSessions();
29
+ const session = sessions.find((s) => s.pid === pid);
30
+ if (session) {
31
+ console.log(JSON.stringify(session));
32
+ process.exit(0);
33
+ }
34
+ else {
35
+ // No session found
36
+ process.exit(0);
37
+ }
38
+ }
39
+ catch (err) {
40
+ console.error('Error finding session:', err);
41
+ process.exit(1);
42
+ }
43
+ }
44
+ main();
45
+ //# sourceMappingURL=find-session-by-pid.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"find-session-by-pid.js","sourceRoot":"","sources":["../../../src/cli/find-session-by-pid.ts"],"names":[],"mappings":";AACA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD,KAAK,UAAU,IAAI;IACjB,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAE/B,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,CAAC,KAAK,CAAC,0CAA0C,CAAC,CAAC;QAC1D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,GAAG,GAAG,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACjC,IAAI,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,gBAAgB,MAAM,EAAE,CAAC,CAAC;QACxC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,eAAe,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC,CAAC;IAE/E,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,cAAc,EAAE,CAAC;QACjD,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,CAAC;QAEpD,IAAI,OAAO,EAAE,CAAC;YACZ,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;YACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;aAAM,CAAC;YACN,mBAAmB;YACnB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,wBAAwB,EAAE,GAAG,CAAC,CAAC;QAC7C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC"}
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Get Stale Sessions CLI
4
+ *
5
+ * Returns all stale sessions from the registry based on heartbeat threshold.
6
+ *
7
+ * Usage:
8
+ * node dist/src/cli/get-stale-sessions.js [threshold_seconds]
9
+ *
10
+ * Arguments:
11
+ * threshold_seconds - Max age of heartbeat before considered stale (default: 60)
12
+ *
13
+ * Output:
14
+ * JSON array of stale session info
15
+ */
16
+ export {};
17
+ //# sourceMappingURL=get-stale-sessions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-stale-sessions.d.ts","sourceRoot":"","sources":["../../../src/cli/get-stale-sessions.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;GAaG"}
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Get Stale Sessions CLI
4
+ *
5
+ * Returns all stale sessions from the registry based on heartbeat threshold.
6
+ *
7
+ * Usage:
8
+ * node dist/src/cli/get-stale-sessions.js [threshold_seconds]
9
+ *
10
+ * Arguments:
11
+ * threshold_seconds - Max age of heartbeat before considered stale (default: 60)
12
+ *
13
+ * Output:
14
+ * JSON array of stale session info
15
+ */
16
+ import { SessionRegistry } from '../utils/session-registry.js';
17
+ const thresholdStr = process.argv[2] || '60';
18
+ const threshold = parseInt(thresholdStr, 10);
19
+ if (isNaN(threshold)) {
20
+ console.error('Error: threshold must be a number');
21
+ process.exit(1);
22
+ }
23
+ const registry = new SessionRegistry(process.cwd());
24
+ (async () => {
25
+ try {
26
+ const staleSessions = await registry.getStaleSessions(threshold);
27
+ // Output as JSON for easy parsing in bash
28
+ console.log(JSON.stringify(staleSessions, null, 2));
29
+ process.exit(0);
30
+ }
31
+ catch (err) {
32
+ console.error(`Error getting stale sessions: ${err}`);
33
+ process.exit(1);
34
+ }
35
+ })();
36
+ //# sourceMappingURL=get-stale-sessions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-stale-sessions.js","sourceRoot":"","sources":["../../../src/cli/get-stale-sessions.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAE/D,MAAM,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;AAC7C,MAAM,SAAS,GAAG,QAAQ,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;AAE7C,IAAI,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC;IACrB,OAAO,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAC;IACnD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,QAAQ,GAAG,IAAI,eAAe,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;AAEpD,CAAC,KAAK,IAAI,EAAE;IACV,IAAI,CAAC;QACH,MAAM,aAAa,GAAG,MAAM,QAAQ,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC;QAEjE,0CAA0C;QAC1C,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAEpD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,iCAAiC,GAAG,EAAE,CAAC,CAAC;QACtD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,EAAE,CAAC"}
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Register Session CLI
4
+ *
5
+ * Registers a new session in the registry
6
+ *
7
+ * Usage:
8
+ * node dist/src/cli/register-session.js <session-id> <pid> <type>
9
+ *
10
+ * Arguments:
11
+ * session-id: Unique session identifier
12
+ * pid: Process ID
13
+ * type: Session type (claude-code | watchdog | heartbeat | processor)
14
+ */
15
+ export {};
16
+ //# sourceMappingURL=register-session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register-session.d.ts","sourceRoot":"","sources":["../../../src/cli/register-session.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;GAYG"}
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Register Session CLI
4
+ *
5
+ * Registers a new session in the registry
6
+ *
7
+ * Usage:
8
+ * node dist/src/cli/register-session.js <session-id> <pid> <type>
9
+ *
10
+ * Arguments:
11
+ * session-id: Unique session identifier
12
+ * pid: Process ID
13
+ * type: Session type (claude-code | watchdog | heartbeat | processor)
14
+ */
15
+ import { SessionRegistry } from '../utils/session-registry.js';
16
+ import { consoleLogger } from '../utils/logger.js';
17
+ async function main() {
18
+ const sessionId = process.argv[2];
19
+ const pidStr = process.argv[3];
20
+ const type = (process.argv[4] || 'claude-code');
21
+ if (!sessionId || !pidStr) {
22
+ console.error('Usage: node register-session.js <session-id> <pid> [type]');
23
+ process.exit(1);
24
+ }
25
+ const pid = parseInt(pidStr, 10);
26
+ if (isNaN(pid)) {
27
+ console.error(`Invalid PID: ${pidStr}`);
28
+ process.exit(1);
29
+ }
30
+ const registry = new SessionRegistry(process.cwd(), { logger: consoleLogger });
31
+ try {
32
+ const success = await registry.registerSession(sessionId, pid, { type });
33
+ if (success) {
34
+ console.log(`Session registered: ${sessionId} (PID: ${pid}, Type: ${type})`);
35
+ process.exit(0);
36
+ }
37
+ else {
38
+ console.error('Failed to register session');
39
+ process.exit(1);
40
+ }
41
+ }
42
+ catch (err) {
43
+ console.error('Error registering session:', err);
44
+ process.exit(1);
45
+ }
46
+ }
47
+ main();
48
+ //# sourceMappingURL=register-session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register-session.js","sourceRoot":"","sources":["../../../src/cli/register-session.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAE/D,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD,KAAK,UAAU,IAAI;IACjB,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClC,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC/B,MAAM,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,aAAa,CAAgB,CAAC;IAE/D,IAAI,CAAC,SAAS,IAAI,CAAC,MAAM,EAAE,CAAC;QAC1B,OAAO,CAAC,KAAK,CAAC,2DAA2D,CAAC,CAAC;QAC3E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,GAAG,GAAG,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACjC,IAAI,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,gBAAgB,MAAM,EAAE,CAAC,CAAC;QACxC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,eAAe,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC,CAAC;IAE/E,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,eAAe,CAAC,SAAS,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;QAEzE,IAAI,OAAO,EAAE,CAAC;YACZ,OAAO,CAAC,GAAG,CAAC,uBAAuB,SAAS,UAAU,GAAG,WAAW,IAAI,GAAG,CAAC,CAAC;YAC7E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,KAAK,CAAC,4BAA4B,CAAC,CAAC;YAC5C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,4BAA4B,EAAE,GAAG,CAAC,CAAC;QACjD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC"}
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Remove Session CLI
4
+ *
5
+ * Removes a session from the registry
6
+ *
7
+ * Usage:
8
+ * node dist/src/cli/remove-session.js <session-id>
9
+ */
10
+ export {};
11
+ //# sourceMappingURL=remove-session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remove-session.d.ts","sourceRoot":"","sources":["../../../src/cli/remove-session.ts"],"names":[],"mappings":";AACA;;;;;;;GAOG"}
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Remove Session CLI
4
+ *
5
+ * Removes a session from the registry
6
+ *
7
+ * Usage:
8
+ * node dist/src/cli/remove-session.js <session-id>
9
+ */
10
+ import { SessionRegistry } from '../utils/session-registry.js';
11
+ import { consoleLogger } from '../utils/logger.js';
12
+ async function main() {
13
+ const sessionId = process.argv[2];
14
+ if (!sessionId) {
15
+ console.error('Usage: node remove-session.js <session-id>');
16
+ process.exit(1);
17
+ }
18
+ const registry = new SessionRegistry(process.cwd(), { logger: consoleLogger });
19
+ try {
20
+ const success = await registry.removeSession(sessionId);
21
+ if (success) {
22
+ console.log(`Session removed: ${sessionId}`);
23
+ process.exit(0);
24
+ }
25
+ else {
26
+ console.error(`Session not found: ${sessionId}`);
27
+ process.exit(1);
28
+ }
29
+ }
30
+ catch (err) {
31
+ console.error('Error removing session:', err);
32
+ process.exit(1);
33
+ }
34
+ }
35
+ main();
36
+ //# sourceMappingURL=remove-session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remove-session.js","sourceRoot":"","sources":["../../../src/cli/remove-session.ts"],"names":[],"mappings":";AACA;;;;;;;GAOG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD,KAAK,UAAU,IAAI;IACjB,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAElC,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,4CAA4C,CAAC,CAAC;QAC5D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,eAAe,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC,CAAC;IAE/E,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;QAExD,IAAI,OAAO,EAAE,CAAC;YACZ,OAAO,CAAC,GAAG,CAAC,oBAAoB,SAAS,EAAE,CAAC,CAAC;YAC7C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,KAAK,CAAC,sBAAsB,SAAS,EAAE,CAAC,CAAC;YACjD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,yBAAyB,EAAE,GAAG,CAAC,CAAC;QAC9C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC"}
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Update Heartbeat CLI
4
+ *
5
+ * Updates the heartbeat timestamp for a session in the registry
6
+ *
7
+ * Usage:
8
+ * node dist/src/cli/update-heartbeat.js <session-id>
9
+ */
10
+ export {};
11
+ //# sourceMappingURL=update-heartbeat.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-heartbeat.d.ts","sourceRoot":"","sources":["../../../src/cli/update-heartbeat.ts"],"names":[],"mappings":";AACA;;;;;;;GAOG"}
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Update Heartbeat CLI
4
+ *
5
+ * Updates the heartbeat timestamp for a session in the registry
6
+ *
7
+ * Usage:
8
+ * node dist/src/cli/update-heartbeat.js <session-id>
9
+ */
10
+ import { SessionRegistry } from '../utils/session-registry.js';
11
+ import { consoleLogger } from '../utils/logger.js';
12
+ async function main() {
13
+ const sessionId = process.argv[2];
14
+ if (!sessionId) {
15
+ console.error('Usage: node update-heartbeat.js <session-id>');
16
+ process.exit(1);
17
+ }
18
+ const registry = new SessionRegistry(process.cwd(), { logger: consoleLogger });
19
+ try {
20
+ const success = await registry.updateHeartbeat(sessionId);
21
+ if (success) {
22
+ // Silent success (no output to avoid log spam)
23
+ process.exit(0);
24
+ }
25
+ else {
26
+ console.error(`Failed to update heartbeat for session: ${sessionId}`);
27
+ process.exit(1);
28
+ }
29
+ }
30
+ catch (err) {
31
+ console.error('Error updating heartbeat:', err);
32
+ process.exit(1);
33
+ }
34
+ }
35
+ main();
36
+ //# sourceMappingURL=update-heartbeat.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-heartbeat.js","sourceRoot":"","sources":["../../../src/cli/update-heartbeat.ts"],"names":[],"mappings":";AACA;;;;;;;GAOG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD,KAAK,UAAU,IAAI;IACjB,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAElC,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,8CAA8C,CAAC,CAAC;QAC9D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,eAAe,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC,CAAC;IAE/E,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC;QAE1D,IAAI,OAAO,EAAE,CAAC;YACZ,+CAA+C;YAC/C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,KAAK,CAAC,2CAA2C,SAAS,EAAE,CAAC,CAAC;YACtE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,2BAA2B,EAAE,GAAG,CAAC,CAAC;QAChD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC"}