@stackmemoryai/stackmemory 0.3.26 → 0.4.1

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 (26) hide show
  1. package/dist/cli/commands/ralph.js +125 -188
  2. package/dist/cli/commands/ralph.js.map +2 -2
  3. package/dist/features/tui/simple-monitor.js +112 -0
  4. package/dist/features/tui/simple-monitor.js.map +7 -0
  5. package/dist/features/tui/swarm-monitor.js +644 -0
  6. package/dist/features/tui/swarm-monitor.js.map +7 -0
  7. package/dist/integrations/ralph/bridge/ralph-stackmemory-bridge.js +254 -43
  8. package/dist/integrations/ralph/bridge/ralph-stackmemory-bridge.js.map +3 -3
  9. package/dist/integrations/ralph/coordination/enhanced-coordination.js +406 -0
  10. package/dist/integrations/ralph/coordination/enhanced-coordination.js.map +7 -0
  11. package/dist/integrations/ralph/monitoring/swarm-dashboard.js +290 -0
  12. package/dist/integrations/ralph/monitoring/swarm-dashboard.js.map +7 -0
  13. package/dist/integrations/ralph/monitoring/swarm-registry.js +95 -0
  14. package/dist/integrations/ralph/monitoring/swarm-registry.js.map +7 -0
  15. package/dist/integrations/ralph/recovery/crash-recovery.js +458 -0
  16. package/dist/integrations/ralph/recovery/crash-recovery.js.map +7 -0
  17. package/dist/integrations/ralph/swarm/git-workflow-manager.js +6 -67
  18. package/dist/integrations/ralph/swarm/git-workflow-manager.js.map +2 -2
  19. package/dist/integrations/ralph/swarm/swarm-coordinator.js +5 -139
  20. package/dist/integrations/ralph/swarm/swarm-coordinator.js.map +2 -2
  21. package/package.json +2 -1
  22. package/scripts/test-ralph-iteration-fix.ts +118 -0
  23. package/scripts/test-simple-ralph-state-sync.ts +178 -0
  24. package/scripts/test-swarm-tui.ts +34 -0
  25. package/scripts/test-tui-shortcuts.ts +66 -0
  26. package/scripts/validate-tui-shortcuts.ts +83 -0
@@ -0,0 +1,644 @@
1
+ import blessed from "blessed";
2
+ import { logger } from "../../core/monitoring/logger.js";
3
+ import { SwarmDashboard } from "../../integrations/ralph/monitoring/swarm-dashboard.js";
4
+ import { SwarmRegistry } from "../../integrations/ralph/monitoring/swarm-registry.js";
5
+ import { execSync } from "child_process";
6
+ class SwarmTUI {
7
+ screen;
8
+ commitsTable;
9
+ statusBox;
10
+ agentsTable;
11
+ metricsBox;
12
+ logBox;
13
+ swarmCoordinator = null;
14
+ swarmDashboard = null;
15
+ refreshInterval = null;
16
+ commitMetrics = /* @__PURE__ */ new Map();
17
+ constructor() {
18
+ const isGhostty = process.env.TERM_PROGRAM === "ghostty" || process.env.TERM?.includes("ghostty");
19
+ const isBasicTerm = process.env.TERM === "dumb" || process.env.TERM === "unknown";
20
+ this.screen = blessed.screen({
21
+ smartCSR: !isGhostty,
22
+ // Disable smart CSR for ghostty
23
+ title: "Ralph Swarm Monitor",
24
+ terminal: isGhostty ? "xterm-256color" : void 0,
25
+ fullUnicode: !isBasicTerm,
26
+ dockBorders: false,
27
+ ignoreDockContrast: true,
28
+ useBCE: false,
29
+ // Disable background color erase for compatibility
30
+ forceUnicode: false,
31
+ debug: false
32
+ });
33
+ this.screen.on("error", (err) => {
34
+ logger.error("TUI screen error:", err);
35
+ console.log(
36
+ "\u26A0\uFE0F TUI display error detected. Try setting TERM=xterm-256color"
37
+ );
38
+ console.log(
39
+ " Alternative: Use stackmemory ralph status for text-based monitoring"
40
+ );
41
+ });
42
+ this.createUI();
43
+ this.setupKeyHandlers();
44
+ logger.info("SwarmTUI initialized");
45
+ }
46
+ createUI() {
47
+ const container = blessed.box({
48
+ parent: this.screen,
49
+ top: 0,
50
+ left: 0,
51
+ width: "100%",
52
+ height: "100%",
53
+ style: {
54
+ bg: "black"
55
+ }
56
+ });
57
+ const isGhostty = process.env.TERM_PROGRAM === "ghostty" || process.env.TERM?.includes("ghostty");
58
+ const safeColors = isGhostty;
59
+ blessed.box({
60
+ parent: container,
61
+ top: 0,
62
+ left: 0,
63
+ width: "100%",
64
+ height: 3,
65
+ content: "\u{1F9BE} Ralph Swarm Monitor - Real-time Swarm Operations",
66
+ style: safeColors ? {
67
+ fg: "white",
68
+ bold: false
69
+ } : {
70
+ bg: "blue",
71
+ fg: "white",
72
+ bold: true
73
+ },
74
+ border: {
75
+ type: "line"
76
+ }
77
+ });
78
+ this.statusBox = blessed.box({
79
+ parent: container,
80
+ top: 3,
81
+ left: "50%",
82
+ width: "50%",
83
+ height: 8,
84
+ label: " Swarm Status ",
85
+ content: "No active swarm",
86
+ style: {
87
+ bg: "black",
88
+ fg: "white"
89
+ },
90
+ border: {
91
+ type: "line",
92
+ fg: "cyan"
93
+ }
94
+ });
95
+ this.metricsBox = blessed.box({
96
+ parent: container,
97
+ top: 3,
98
+ left: 0,
99
+ width: "50%",
100
+ height: 8,
101
+ label: " Performance Metrics ",
102
+ content: "Waiting for data...",
103
+ style: {
104
+ bg: "black",
105
+ fg: "white"
106
+ },
107
+ border: {
108
+ type: "line",
109
+ fg: "green"
110
+ }
111
+ });
112
+ this.agentsTable = blessed.table({
113
+ parent: container,
114
+ top: 11,
115
+ left: 0,
116
+ width: "50%",
117
+ height: 12,
118
+ label: " Active Agents ",
119
+ style: {
120
+ bg: "black",
121
+ fg: "white",
122
+ header: {
123
+ bg: "blue",
124
+ fg: "white",
125
+ bold: true
126
+ },
127
+ cell: {
128
+ selected: {
129
+ bg: "blue",
130
+ fg: "white"
131
+ }
132
+ }
133
+ },
134
+ border: {
135
+ type: "line",
136
+ fg: "yellow"
137
+ },
138
+ data: [["Role", "Status", "Iteration", "Task", "Last Active"]]
139
+ });
140
+ this.commitsTable = blessed.table({
141
+ parent: container,
142
+ top: 11,
143
+ left: "50%",
144
+ width: "50%",
145
+ height: 12,
146
+ label: " Recent Commits ",
147
+ style: {
148
+ bg: "black",
149
+ fg: "white",
150
+ header: {
151
+ bg: "blue",
152
+ fg: "white",
153
+ bold: true
154
+ },
155
+ cell: {
156
+ selected: {
157
+ bg: "blue",
158
+ fg: "white"
159
+ }
160
+ }
161
+ },
162
+ border: {
163
+ type: "line",
164
+ fg: "magenta"
165
+ },
166
+ data: [["Agent", "Message", "Lines +/-", "Time"]]
167
+ });
168
+ this.logBox = blessed.log({
169
+ parent: container,
170
+ top: 23,
171
+ left: 0,
172
+ width: "100%",
173
+ height: "100%-23",
174
+ label: " Swarm Logs ",
175
+ style: {
176
+ bg: "black",
177
+ fg: "white"
178
+ },
179
+ border: {
180
+ type: "line",
181
+ fg: "white"
182
+ },
183
+ scrollable: true,
184
+ alwaysScroll: true,
185
+ mouse: true
186
+ });
187
+ blessed.box({
188
+ parent: container,
189
+ bottom: 0,
190
+ left: 0,
191
+ width: "100%",
192
+ height: 1,
193
+ content: "q=quit | r=refresh | s=start swarm | t=stop swarm | h=help | c=clear logs | d=detect swarms",
194
+ style: {
195
+ bg: "white",
196
+ fg: "black"
197
+ }
198
+ });
199
+ }
200
+ setupKeyHandlers() {
201
+ this.screen.key(["escape", "q", "C-c"], () => {
202
+ this.cleanup();
203
+ process.exit(0);
204
+ });
205
+ this.screen.key(["r"], () => {
206
+ this.refreshData();
207
+ this.logBox.log("Manual refresh triggered");
208
+ });
209
+ this.screen.key(["s"], () => {
210
+ this.startSwarmInteractive();
211
+ });
212
+ this.screen.key(["t"], () => {
213
+ this.stopSwarmInteractive();
214
+ });
215
+ this.screen.key(["h"], () => {
216
+ this.showHelp();
217
+ });
218
+ this.screen.key(["c"], () => {
219
+ this.clearLogs();
220
+ });
221
+ this.screen.key(["d"], () => {
222
+ this.showDetectedSwarms();
223
+ });
224
+ }
225
+ /**
226
+ * Initialize swarm monitoring
227
+ */
228
+ async initialize(swarmCoordinator, swarmId) {
229
+ try {
230
+ if (swarmId) {
231
+ const registry = SwarmRegistry.getInstance();
232
+ const swarm = registry.getSwarm(swarmId);
233
+ if (swarm) {
234
+ this.swarmCoordinator = swarm.coordinator;
235
+ this.logBox.log(`Connected to swarm: ${swarmId}`);
236
+ } else {
237
+ this.logBox.log(`Swarm not found: ${swarmId}`);
238
+ }
239
+ } else if (swarmCoordinator) {
240
+ this.swarmCoordinator = swarmCoordinator;
241
+ } else {
242
+ const registry = SwarmRegistry.getInstance();
243
+ const activeSwarms = registry.listActiveSwarms();
244
+ if (activeSwarms.length > 0) {
245
+ this.swarmCoordinator = activeSwarms[0].coordinator;
246
+ this.logBox.log(`Auto-connected to swarm: ${activeSwarms[0].id}`);
247
+ }
248
+ }
249
+ if (this.swarmCoordinator) {
250
+ this.swarmDashboard = new SwarmDashboard(this.swarmCoordinator);
251
+ this.swarmDashboard.startMonitoring(2e3);
252
+ this.swarmDashboard.on("metricsUpdated", (metrics) => {
253
+ this.updateUI(metrics);
254
+ });
255
+ }
256
+ this.refreshInterval = setInterval(() => {
257
+ this.refreshData();
258
+ }, 3e3);
259
+ this.logBox.log("SwarmTUI monitoring initialized");
260
+ } catch (error) {
261
+ logger.error("Failed to initialize SwarmTUI", error);
262
+ this.logBox.log(`Error: ${error.message}`);
263
+ }
264
+ }
265
+ /**
266
+ * Start the TUI display
267
+ */
268
+ start() {
269
+ this.screen.render();
270
+ this.logBox.log("Ralph Swarm Monitor started");
271
+ this.logBox.log("Monitoring for active swarms...");
272
+ }
273
+ /**
274
+ * Refresh all data
275
+ */
276
+ async refreshData() {
277
+ try {
278
+ await this.updateCommitMetrics();
279
+ if (this.swarmCoordinator) {
280
+ const status = this.getSwarmStatus();
281
+ this.updateStatusDisplay(status);
282
+ } else {
283
+ await this.detectActiveSwarms();
284
+ }
285
+ this.screen.render();
286
+ } catch (error) {
287
+ logger.error("Failed to refresh TUI data", error);
288
+ this.logBox.log(`Refresh error: ${error.message}`);
289
+ }
290
+ }
291
+ /**
292
+ * Update commit metrics for all agents
293
+ */
294
+ async updateCommitMetrics() {
295
+ try {
296
+ const gitLog = execSync(
297
+ 'git log --oneline --since="1 hour ago" --pretty=format:"%H|%an|%s|%ct" --numstat',
298
+ { encoding: "utf8", cwd: process.cwd() }
299
+ );
300
+ const commits = this.parseGitCommits(gitLog);
301
+ this.updateCommitsTable(commits);
302
+ } catch {
303
+ this.logBox.log("No recent commits found");
304
+ }
305
+ }
306
+ /**
307
+ * Parse git log output into commit data
308
+ */
309
+ parseGitCommits(gitLog) {
310
+ const commits = [];
311
+ const lines = gitLog.split("\n").filter(Boolean);
312
+ let currentCommit = null;
313
+ for (const line of lines) {
314
+ if (line.includes("|")) {
315
+ const [hash, author, message, timestamp] = line.split("|");
316
+ currentCommit = {
317
+ hash: hash.substring(0, 8),
318
+ agent: this.extractAgentFromAuthor(author),
319
+ message: message.substring(0, 50),
320
+ timestamp: parseInt(timestamp),
321
+ linesAdded: 0,
322
+ linesDeleted: 0
323
+ };
324
+ } else if (currentCommit && line.match(/^\d+\s+\d+/)) {
325
+ const [added, deleted] = line.split(" ")[0].split(" ");
326
+ currentCommit.linesAdded += parseInt(added) || 0;
327
+ currentCommit.linesDeleted += parseInt(deleted) || 0;
328
+ commits.push({ ...currentCommit });
329
+ currentCommit = null;
330
+ }
331
+ }
332
+ return commits.slice(0, 10);
333
+ }
334
+ /**
335
+ * Extract agent info from git author
336
+ */
337
+ extractAgentFromAuthor(author) {
338
+ const agentMatch = author.match(/\[(\w+)\]/);
339
+ if (agentMatch) {
340
+ return agentMatch[1];
341
+ }
342
+ const roles = [
343
+ "developer",
344
+ "tester",
345
+ "optimizer",
346
+ "documenter",
347
+ "architect"
348
+ ];
349
+ for (const role of roles) {
350
+ if (author.toLowerCase().includes(role)) {
351
+ return role;
352
+ }
353
+ }
354
+ return "user";
355
+ }
356
+ /**
357
+ * Update commits table display
358
+ */
359
+ updateCommitsTable(commits) {
360
+ const tableData = [["Agent", "Message", "Lines +/-", "Time"]];
361
+ for (const commit of commits) {
362
+ const timeAgo = this.formatTimeAgo(commit.timestamp * 1e3);
363
+ const linesChange = `+${commit.linesAdded}/-${commit.linesDeleted}`;
364
+ tableData.push([commit.agent, commit.message, linesChange, timeAgo]);
365
+ }
366
+ this.commitsTable.setData(tableData);
367
+ }
368
+ /**
369
+ * Get current swarm status
370
+ */
371
+ getSwarmStatus() {
372
+ if (!this.swarmCoordinator) return null;
373
+ const usage = this.swarmCoordinator.getResourceUsage();
374
+ const swarmState = this.swarmCoordinator.swarmState;
375
+ if (!swarmState) return null;
376
+ return {
377
+ swarmId: swarmState.id,
378
+ status: swarmState.status,
379
+ startTime: swarmState.startTime,
380
+ uptime: Date.now() - swarmState.startTime,
381
+ agents: usage.activeAgents ? Array.from(
382
+ this.swarmCoordinator.activeAgents?.values() || []
383
+ ).map((agent) => ({
384
+ id: agent.id,
385
+ role: agent.role,
386
+ status: agent.status,
387
+ currentTask: agent.currentTask,
388
+ iteration: agent.performance?.tasksCompleted || 0,
389
+ lastActivity: agent.performance?.lastFreshStart || Date.now()
390
+ })) : [],
391
+ performance: {
392
+ throughput: swarmState.performance?.throughput || 0,
393
+ efficiency: swarmState.performance?.efficiency || 0,
394
+ totalTasks: swarmState.totalTaskCount || 0,
395
+ completedTasks: swarmState.completedTaskCount || 0
396
+ }
397
+ };
398
+ }
399
+ /**
400
+ * Update status display
401
+ */
402
+ updateStatusDisplay(status) {
403
+ if (!status) {
404
+ this.statusBox.setContent("No active swarm detected");
405
+ this.agentsTable.setData([
406
+ ["Role", "Status", "Iteration", "Task", "Last Active"]
407
+ ]);
408
+ this.metricsBox.setContent("Waiting for swarm data...");
409
+ return;
410
+ }
411
+ const uptimeStr = this.formatDuration(status.uptime);
412
+ const statusContent = `Swarm: ${status.swarmId.substring(0, 8)}
413
+ Status: ${status.status.toUpperCase()}
414
+ Uptime: ${uptimeStr}
415
+ Agents: ${status.agents.length}`;
416
+ this.statusBox.setContent(statusContent);
417
+ const agentData = [["Role", "Status", "Iteration", "Task", "Last Active"]];
418
+ for (const agent of status.agents) {
419
+ const lastActivity = this.formatTimeAgo(agent.lastActivity);
420
+ const task = agent.currentTask ? agent.currentTask.substring(0, 20) : "idle";
421
+ agentData.push([
422
+ agent.role,
423
+ agent.status,
424
+ agent.iteration.toString(),
425
+ task,
426
+ lastActivity
427
+ ]);
428
+ }
429
+ this.agentsTable.setData(agentData);
430
+ const metricsContent = `Throughput: ${status.performance.throughput.toFixed(2)} tasks/min
431
+ Efficiency: ${(status.performance.efficiency * 100).toFixed(1)}%
432
+ Tasks: ${status.performance.completedTasks}/${status.performance.totalTasks}
433
+ Success Rate: ${status.performance.efficiency > 0 ? (status.performance.efficiency * 100).toFixed(1) : "N/A"}%`;
434
+ this.metricsBox.setContent(metricsContent);
435
+ }
436
+ /**
437
+ * Update UI with metrics from dashboard
438
+ */
439
+ updateUI(metrics) {
440
+ this.logBox.log(
441
+ `Metrics updated: ${metrics.status} - ${metrics.activeAgents} agents`
442
+ );
443
+ }
444
+ /**
445
+ * Detect active swarms in the system
446
+ */
447
+ async detectActiveSwarms() {
448
+ try {
449
+ const registry = SwarmRegistry.getInstance();
450
+ const activeSwarms = registry.listActiveSwarms();
451
+ const stats = registry.getStatistics();
452
+ if (activeSwarms.length > 0) {
453
+ let statusContent = `Available Swarms (${activeSwarms.length}):
454
+ `;
455
+ for (const swarm of activeSwarms.slice(0, 3)) {
456
+ const uptime = this.formatDuration(Date.now() - swarm.startTime);
457
+ statusContent += `\u2022 ${swarm.id.substring(0, 8)}: ${swarm.status} (${uptime})
458
+ `;
459
+ }
460
+ if (activeSwarms.length > 3) {
461
+ statusContent += `... and ${activeSwarms.length - 3} more`;
462
+ }
463
+ this.statusBox.setContent(statusContent);
464
+ this.logBox.log(
465
+ `Found ${activeSwarms.length} active swarms in registry`
466
+ );
467
+ } else {
468
+ const ralphProcesses = execSync(
469
+ 'ps aux | grep "ralph" | grep -v grep',
470
+ { encoding: "utf8" }
471
+ );
472
+ if (ralphProcesses.trim()) {
473
+ this.logBox.log("Detected Ralph processes running");
474
+ this.statusBox.setContent(
475
+ "External Ralph processes detected\n(Use swarm coordinator for full monitoring)"
476
+ );
477
+ } else {
478
+ this.statusBox.setContent(`No active swarms detected
479
+ Total swarms: ${stats.totalSwarms}
480
+ Completed: ${stats.completedSwarms}
481
+
482
+ Run: stackmemory ralph swarm <task>`);
483
+ }
484
+ }
485
+ } catch {
486
+ }
487
+ }
488
+ /**
489
+ * Format time ago string
490
+ */
491
+ formatTimeAgo(timestamp) {
492
+ const diff = Date.now() - timestamp;
493
+ const minutes = Math.floor(diff / 6e4);
494
+ const hours = Math.floor(minutes / 60);
495
+ const days = Math.floor(hours / 24);
496
+ if (days > 0) return `${days}d ago`;
497
+ if (hours > 0) return `${hours}h ago`;
498
+ if (minutes > 0) return `${minutes}m ago`;
499
+ return "just now";
500
+ }
501
+ /**
502
+ * Format duration string
503
+ */
504
+ formatDuration(ms) {
505
+ const seconds = Math.floor(ms / 1e3);
506
+ const minutes = Math.floor(seconds / 60);
507
+ const hours = Math.floor(minutes / 60);
508
+ if (hours > 0) return `${hours}h ${minutes % 60}m`;
509
+ if (minutes > 0) return `${minutes}m ${seconds % 60}s`;
510
+ return `${seconds}s`;
511
+ }
512
+ /**
513
+ * Start swarm interactively
514
+ */
515
+ startSwarmInteractive() {
516
+ this.logBox.log("\u{1F680} Start Swarm Interactive Mode:");
517
+ this.logBox.log(
518
+ 'Example: stackmemory ralph swarm "Implement feature" --agents developer,tester'
519
+ );
520
+ this.logBox.log(
521
+ 'Tip: Run the command in another terminal, then press "d" to detect it'
522
+ );
523
+ }
524
+ /**
525
+ * Stop swarm interactively
526
+ */
527
+ stopSwarmInteractive() {
528
+ if (this.swarmCoordinator) {
529
+ this.logBox.log("\u{1F6D1} Stopping current swarm...");
530
+ this.logBox.log(
531
+ "Note: Swarm stopping not yet implemented - use Ctrl+C in swarm terminal"
532
+ );
533
+ } else {
534
+ this.logBox.log("\u274C No active swarm coordinator to stop");
535
+ this.logBox.log("External Ralph processes must be stopped manually");
536
+ }
537
+ }
538
+ /**
539
+ * Show help dialog
540
+ */
541
+ showHelp() {
542
+ this.logBox.log("\u{1F9BE} Ralph Swarm Monitor - Help");
543
+ this.logBox.log("");
544
+ this.logBox.log("Keyboard Shortcuts:");
545
+ this.logBox.log(" q, Esc, Ctrl+C - Quit TUI");
546
+ this.logBox.log(" r - Refresh data manually");
547
+ this.logBox.log(" s - Show start swarm commands");
548
+ this.logBox.log(" t - Stop current swarm");
549
+ this.logBox.log(" h - Show this help");
550
+ this.logBox.log(" c - Clear log output");
551
+ this.logBox.log(" d - Detect and list available swarms");
552
+ this.logBox.log("");
553
+ this.logBox.log("Usage:");
554
+ this.logBox.log(
555
+ " stackmemory ralph tui # Auto-detect swarms"
556
+ );
557
+ this.logBox.log(
558
+ " stackmemory ralph tui --swarm-id <id> # Monitor specific swarm"
559
+ );
560
+ this.logBox.log("");
561
+ this.logBox.log("Starting Swarms:");
562
+ this.logBox.log(
563
+ ' stackmemory ralph swarm "Task description" --agents developer,tester'
564
+ );
565
+ this.logBox.log("");
566
+ }
567
+ /**
568
+ * Clear log output
569
+ */
570
+ clearLogs() {
571
+ this.logBox.setContent("");
572
+ this.logBox.log("\u{1F4DD} Logs cleared - monitoring continues...");
573
+ }
574
+ /**
575
+ * Show detected swarms
576
+ */
577
+ async showDetectedSwarms() {
578
+ this.logBox.log("\u{1F50D} Detecting active swarms...");
579
+ try {
580
+ const registry = SwarmRegistry.getInstance();
581
+ const activeSwarms = registry.listActiveSwarms();
582
+ const stats = registry.getStatistics();
583
+ this.logBox.log("");
584
+ this.logBox.log("\u{1F4CA} Swarm Registry Status:");
585
+ this.logBox.log(` Total swarms: ${stats.totalSwarms}`);
586
+ this.logBox.log(` Active swarms: ${stats.activeSwarms}`);
587
+ this.logBox.log(` Completed swarms: ${stats.completedSwarms}`);
588
+ if (activeSwarms.length > 0) {
589
+ this.logBox.log("");
590
+ this.logBox.log("\u{1F9BE} Active Swarms:");
591
+ for (const swarm of activeSwarms) {
592
+ const uptime = this.formatDuration(Date.now() - swarm.startTime);
593
+ this.logBox.log(` \u2022 ${swarm.id}: ${swarm.description} (${uptime})`);
594
+ }
595
+ this.logBox.log("");
596
+ this.logBox.log("\u{1F4A1} Use --swarm-id to connect to specific swarm");
597
+ } else {
598
+ this.logBox.log("");
599
+ this.logBox.log("\u274C No active swarms in registry");
600
+ try {
601
+ const ralphProcesses = execSync(
602
+ 'ps aux | grep "ralph" | grep -v grep',
603
+ { encoding: "utf8" }
604
+ );
605
+ if (ralphProcesses.trim()) {
606
+ this.logBox.log("\u{1F50D} External Ralph processes detected:");
607
+ ralphProcesses.split("\n").filter((line) => line.trim()).forEach((line) => {
608
+ const parts = line.split(/\s+/);
609
+ this.logBox.log(
610
+ ` PID ${parts[1]}: ${parts.slice(10).join(" ").slice(0, 60)}`
611
+ );
612
+ });
613
+ }
614
+ } catch {
615
+ this.logBox.log("\u{1F50D} No external Ralph processes found");
616
+ }
617
+ this.logBox.log("");
618
+ this.logBox.log(
619
+ '\u{1F4A1} Start a swarm: stackmemory ralph swarm "Task" --agents developer'
620
+ );
621
+ }
622
+ } catch (error) {
623
+ this.logBox.log(`\u274C Detection failed: ${error.message}`);
624
+ }
625
+ }
626
+ /**
627
+ * Cleanup resources
628
+ */
629
+ cleanup() {
630
+ if (this.refreshInterval) {
631
+ clearInterval(this.refreshInterval);
632
+ }
633
+ if (this.swarmDashboard) {
634
+ this.swarmDashboard.stopMonitoring();
635
+ }
636
+ logger.info("SwarmTUI cleaned up");
637
+ }
638
+ }
639
+ var swarm_monitor_default = SwarmTUI;
640
+ export {
641
+ SwarmTUI,
642
+ swarm_monitor_default as default
643
+ };
644
+ //# sourceMappingURL=swarm-monitor.js.map