@stackmemoryai/stackmemory 0.3.26 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/commands/ralph.js +12 -152
- package/dist/cli/commands/ralph.js.map +2 -2
- package/dist/features/tui/swarm-monitor.js +488 -0
- package/dist/features/tui/swarm-monitor.js.map +7 -0
- package/dist/integrations/ralph/bridge/ralph-stackmemory-bridge.js +2 -20
- package/dist/integrations/ralph/bridge/ralph-stackmemory-bridge.js.map +2 -2
- package/dist/integrations/ralph/coordination/enhanced-coordination.js +406 -0
- package/dist/integrations/ralph/coordination/enhanced-coordination.js.map +7 -0
- package/dist/integrations/ralph/monitoring/swarm-dashboard.js +290 -0
- package/dist/integrations/ralph/monitoring/swarm-dashboard.js.map +7 -0
- package/dist/integrations/ralph/monitoring/swarm-registry.js +95 -0
- package/dist/integrations/ralph/monitoring/swarm-registry.js.map +7 -0
- package/dist/integrations/ralph/recovery/crash-recovery.js +458 -0
- package/dist/integrations/ralph/recovery/crash-recovery.js.map +7 -0
- package/dist/integrations/ralph/swarm/git-workflow-manager.js +6 -67
- package/dist/integrations/ralph/swarm/git-workflow-manager.js.map +2 -2
- package/dist/integrations/ralph/swarm/swarm-coordinator.js +5 -139
- package/dist/integrations/ralph/swarm/swarm-coordinator.js.map +2 -2
- package/package.json +2 -1
- package/scripts/test-swarm-tui.ts +34 -0
|
@@ -0,0 +1,488 @@
|
|
|
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
|
+
this.screen = blessed.screen({
|
|
19
|
+
smartCSR: true,
|
|
20
|
+
title: "Ralph Swarm Monitor"
|
|
21
|
+
});
|
|
22
|
+
this.createUI();
|
|
23
|
+
this.setupKeyHandlers();
|
|
24
|
+
logger.info("SwarmTUI initialized");
|
|
25
|
+
}
|
|
26
|
+
createUI() {
|
|
27
|
+
const container = blessed.box({
|
|
28
|
+
parent: this.screen,
|
|
29
|
+
top: 0,
|
|
30
|
+
left: 0,
|
|
31
|
+
width: "100%",
|
|
32
|
+
height: "100%",
|
|
33
|
+
style: {
|
|
34
|
+
bg: "black"
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
blessed.box({
|
|
38
|
+
parent: container,
|
|
39
|
+
top: 0,
|
|
40
|
+
left: 0,
|
|
41
|
+
width: "100%",
|
|
42
|
+
height: 3,
|
|
43
|
+
content: "\u{1F9BE} Ralph Swarm Monitor - Real-time Swarm Operations",
|
|
44
|
+
style: {
|
|
45
|
+
bg: "blue",
|
|
46
|
+
fg: "white",
|
|
47
|
+
bold: true
|
|
48
|
+
},
|
|
49
|
+
border: {
|
|
50
|
+
type: "line"
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
this.statusBox = blessed.box({
|
|
54
|
+
parent: container,
|
|
55
|
+
top: 3,
|
|
56
|
+
left: "50%",
|
|
57
|
+
width: "50%",
|
|
58
|
+
height: 8,
|
|
59
|
+
label: " Swarm Status ",
|
|
60
|
+
content: "No active swarm",
|
|
61
|
+
style: {
|
|
62
|
+
bg: "black",
|
|
63
|
+
fg: "white"
|
|
64
|
+
},
|
|
65
|
+
border: {
|
|
66
|
+
type: "line",
|
|
67
|
+
fg: "cyan"
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
this.metricsBox = blessed.box({
|
|
71
|
+
parent: container,
|
|
72
|
+
top: 3,
|
|
73
|
+
left: 0,
|
|
74
|
+
width: "50%",
|
|
75
|
+
height: 8,
|
|
76
|
+
label: " Performance Metrics ",
|
|
77
|
+
content: "Waiting for data...",
|
|
78
|
+
style: {
|
|
79
|
+
bg: "black",
|
|
80
|
+
fg: "white"
|
|
81
|
+
},
|
|
82
|
+
border: {
|
|
83
|
+
type: "line",
|
|
84
|
+
fg: "green"
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
this.agentsTable = blessed.table({
|
|
88
|
+
parent: container,
|
|
89
|
+
top: 11,
|
|
90
|
+
left: 0,
|
|
91
|
+
width: "50%",
|
|
92
|
+
height: 12,
|
|
93
|
+
label: " Active Agents ",
|
|
94
|
+
style: {
|
|
95
|
+
bg: "black",
|
|
96
|
+
fg: "white",
|
|
97
|
+
header: {
|
|
98
|
+
bg: "blue",
|
|
99
|
+
fg: "white",
|
|
100
|
+
bold: true
|
|
101
|
+
},
|
|
102
|
+
cell: {
|
|
103
|
+
selected: {
|
|
104
|
+
bg: "blue",
|
|
105
|
+
fg: "white"
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
border: {
|
|
110
|
+
type: "line",
|
|
111
|
+
fg: "yellow"
|
|
112
|
+
},
|
|
113
|
+
data: [
|
|
114
|
+
["Role", "Status", "Iteration", "Task", "Last Active"]
|
|
115
|
+
]
|
|
116
|
+
});
|
|
117
|
+
this.commitsTable = blessed.table({
|
|
118
|
+
parent: container,
|
|
119
|
+
top: 11,
|
|
120
|
+
left: "50%",
|
|
121
|
+
width: "50%",
|
|
122
|
+
height: 12,
|
|
123
|
+
label: " Recent Commits ",
|
|
124
|
+
style: {
|
|
125
|
+
bg: "black",
|
|
126
|
+
fg: "white",
|
|
127
|
+
header: {
|
|
128
|
+
bg: "blue",
|
|
129
|
+
fg: "white",
|
|
130
|
+
bold: true
|
|
131
|
+
},
|
|
132
|
+
cell: {
|
|
133
|
+
selected: {
|
|
134
|
+
bg: "blue",
|
|
135
|
+
fg: "white"
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
border: {
|
|
140
|
+
type: "line",
|
|
141
|
+
fg: "magenta"
|
|
142
|
+
},
|
|
143
|
+
data: [
|
|
144
|
+
["Agent", "Message", "Lines +/-", "Time"]
|
|
145
|
+
]
|
|
146
|
+
});
|
|
147
|
+
this.logBox = blessed.log({
|
|
148
|
+
parent: container,
|
|
149
|
+
top: 23,
|
|
150
|
+
left: 0,
|
|
151
|
+
width: "100%",
|
|
152
|
+
height: "100%-23",
|
|
153
|
+
label: " Swarm Logs ",
|
|
154
|
+
style: {
|
|
155
|
+
bg: "black",
|
|
156
|
+
fg: "white"
|
|
157
|
+
},
|
|
158
|
+
border: {
|
|
159
|
+
type: "line",
|
|
160
|
+
fg: "white"
|
|
161
|
+
},
|
|
162
|
+
scrollable: true,
|
|
163
|
+
alwaysScroll: true,
|
|
164
|
+
mouse: true
|
|
165
|
+
});
|
|
166
|
+
blessed.box({
|
|
167
|
+
parent: container,
|
|
168
|
+
bottom: 0,
|
|
169
|
+
left: 0,
|
|
170
|
+
width: "100%",
|
|
171
|
+
height: 1,
|
|
172
|
+
content: "Press q to quit, r to refresh, s to start swarm, t to stop swarm",
|
|
173
|
+
style: {
|
|
174
|
+
bg: "white",
|
|
175
|
+
fg: "black"
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
setupKeyHandlers() {
|
|
180
|
+
this.screen.key(["escape", "q", "C-c"], () => {
|
|
181
|
+
this.cleanup();
|
|
182
|
+
process.exit(0);
|
|
183
|
+
});
|
|
184
|
+
this.screen.key(["r"], () => {
|
|
185
|
+
this.refreshData();
|
|
186
|
+
this.logBox.log("Manual refresh triggered");
|
|
187
|
+
});
|
|
188
|
+
this.screen.key(["s"], () => {
|
|
189
|
+
this.logBox.log("Start swarm command - feature coming soon");
|
|
190
|
+
});
|
|
191
|
+
this.screen.key(["t"], () => {
|
|
192
|
+
this.logBox.log("Stop swarm command - feature coming soon");
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Initialize swarm monitoring
|
|
197
|
+
*/
|
|
198
|
+
async initialize(swarmCoordinator, swarmId) {
|
|
199
|
+
try {
|
|
200
|
+
if (swarmId) {
|
|
201
|
+
const registry = SwarmRegistry.getInstance();
|
|
202
|
+
const swarm = registry.getSwarm(swarmId);
|
|
203
|
+
if (swarm) {
|
|
204
|
+
this.swarmCoordinator = swarm.coordinator;
|
|
205
|
+
this.logBox.log(`Connected to swarm: ${swarmId}`);
|
|
206
|
+
} else {
|
|
207
|
+
this.logBox.log(`Swarm not found: ${swarmId}`);
|
|
208
|
+
}
|
|
209
|
+
} else if (swarmCoordinator) {
|
|
210
|
+
this.swarmCoordinator = swarmCoordinator;
|
|
211
|
+
} else {
|
|
212
|
+
const registry = SwarmRegistry.getInstance();
|
|
213
|
+
const activeSwarms = registry.listActiveSwarms();
|
|
214
|
+
if (activeSwarms.length > 0) {
|
|
215
|
+
this.swarmCoordinator = activeSwarms[0].coordinator;
|
|
216
|
+
this.logBox.log(`Auto-connected to swarm: ${activeSwarms[0].id}`);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
if (this.swarmCoordinator) {
|
|
220
|
+
this.swarmDashboard = new SwarmDashboard(this.swarmCoordinator);
|
|
221
|
+
this.swarmDashboard.startMonitoring(2e3);
|
|
222
|
+
this.swarmDashboard.on("metricsUpdated", (metrics) => {
|
|
223
|
+
this.updateUI(metrics);
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
this.refreshInterval = setInterval(() => {
|
|
227
|
+
this.refreshData();
|
|
228
|
+
}, 3e3);
|
|
229
|
+
this.logBox.log("SwarmTUI monitoring initialized");
|
|
230
|
+
} catch (error) {
|
|
231
|
+
logger.error("Failed to initialize SwarmTUI", error);
|
|
232
|
+
this.logBox.log(`Error: ${error.message}`);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Start the TUI display
|
|
237
|
+
*/
|
|
238
|
+
start() {
|
|
239
|
+
this.screen.render();
|
|
240
|
+
this.logBox.log("Ralph Swarm Monitor started");
|
|
241
|
+
this.logBox.log("Monitoring for active swarms...");
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Refresh all data
|
|
245
|
+
*/
|
|
246
|
+
async refreshData() {
|
|
247
|
+
try {
|
|
248
|
+
await this.updateCommitMetrics();
|
|
249
|
+
if (this.swarmCoordinator) {
|
|
250
|
+
const status = this.getSwarmStatus();
|
|
251
|
+
this.updateStatusDisplay(status);
|
|
252
|
+
} else {
|
|
253
|
+
await this.detectActiveSwarms();
|
|
254
|
+
}
|
|
255
|
+
this.screen.render();
|
|
256
|
+
} catch (error) {
|
|
257
|
+
logger.error("Failed to refresh TUI data", error);
|
|
258
|
+
this.logBox.log(`Refresh error: ${error.message}`);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Update commit metrics for all agents
|
|
263
|
+
*/
|
|
264
|
+
async updateCommitMetrics() {
|
|
265
|
+
try {
|
|
266
|
+
const gitLog = execSync(
|
|
267
|
+
'git log --oneline --since="1 hour ago" --pretty=format:"%H|%an|%s|%ct" --numstat',
|
|
268
|
+
{ encoding: "utf8", cwd: process.cwd() }
|
|
269
|
+
);
|
|
270
|
+
const commits = this.parseGitCommits(gitLog);
|
|
271
|
+
this.updateCommitsTable(commits);
|
|
272
|
+
} catch (error) {
|
|
273
|
+
this.logBox.log("No recent commits found");
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Parse git log output into commit data
|
|
278
|
+
*/
|
|
279
|
+
parseGitCommits(gitLog) {
|
|
280
|
+
const commits = [];
|
|
281
|
+
const lines = gitLog.split("\n").filter(Boolean);
|
|
282
|
+
let currentCommit = null;
|
|
283
|
+
for (const line of lines) {
|
|
284
|
+
if (line.includes("|")) {
|
|
285
|
+
const [hash, author, message, timestamp] = line.split("|");
|
|
286
|
+
currentCommit = {
|
|
287
|
+
hash: hash.substring(0, 8),
|
|
288
|
+
agent: this.extractAgentFromAuthor(author),
|
|
289
|
+
message: message.substring(0, 50),
|
|
290
|
+
timestamp: parseInt(timestamp),
|
|
291
|
+
linesAdded: 0,
|
|
292
|
+
linesDeleted: 0
|
|
293
|
+
};
|
|
294
|
+
} else if (currentCommit && line.match(/^\d+\s+\d+/)) {
|
|
295
|
+
const [added, deleted] = line.split(" ")[0].split(" ");
|
|
296
|
+
currentCommit.linesAdded += parseInt(added) || 0;
|
|
297
|
+
currentCommit.linesDeleted += parseInt(deleted) || 0;
|
|
298
|
+
commits.push({ ...currentCommit });
|
|
299
|
+
currentCommit = null;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
return commits.slice(0, 10);
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Extract agent info from git author
|
|
306
|
+
*/
|
|
307
|
+
extractAgentFromAuthor(author) {
|
|
308
|
+
const agentMatch = author.match(/\[(\w+)\]/);
|
|
309
|
+
if (agentMatch) {
|
|
310
|
+
return agentMatch[1];
|
|
311
|
+
}
|
|
312
|
+
const roles = ["developer", "tester", "optimizer", "documenter", "architect"];
|
|
313
|
+
for (const role of roles) {
|
|
314
|
+
if (author.toLowerCase().includes(role)) {
|
|
315
|
+
return role;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
return "user";
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Update commits table display
|
|
322
|
+
*/
|
|
323
|
+
updateCommitsTable(commits) {
|
|
324
|
+
const tableData = [
|
|
325
|
+
["Agent", "Message", "Lines +/-", "Time"]
|
|
326
|
+
];
|
|
327
|
+
for (const commit of commits) {
|
|
328
|
+
const timeAgo = this.formatTimeAgo(commit.timestamp * 1e3);
|
|
329
|
+
const linesChange = `+${commit.linesAdded}/-${commit.linesDeleted}`;
|
|
330
|
+
tableData.push([
|
|
331
|
+
commit.agent,
|
|
332
|
+
commit.message,
|
|
333
|
+
linesChange,
|
|
334
|
+
timeAgo
|
|
335
|
+
]);
|
|
336
|
+
}
|
|
337
|
+
this.commitsTable.setData(tableData);
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Get current swarm status
|
|
341
|
+
*/
|
|
342
|
+
getSwarmStatus() {
|
|
343
|
+
if (!this.swarmCoordinator) return null;
|
|
344
|
+
const usage = this.swarmCoordinator.getResourceUsage();
|
|
345
|
+
const swarmState = this.swarmCoordinator.swarmState;
|
|
346
|
+
if (!swarmState) return null;
|
|
347
|
+
return {
|
|
348
|
+
swarmId: swarmState.id,
|
|
349
|
+
status: swarmState.status,
|
|
350
|
+
startTime: swarmState.startTime,
|
|
351
|
+
uptime: Date.now() - swarmState.startTime,
|
|
352
|
+
agents: usage.activeAgents ? Array.from(this.swarmCoordinator.activeAgents?.values() || []).map((agent) => ({
|
|
353
|
+
id: agent.id,
|
|
354
|
+
role: agent.role,
|
|
355
|
+
status: agent.status,
|
|
356
|
+
currentTask: agent.currentTask,
|
|
357
|
+
iteration: agent.performance?.tasksCompleted || 0,
|
|
358
|
+
lastActivity: agent.performance?.lastFreshStart || Date.now()
|
|
359
|
+
})) : [],
|
|
360
|
+
performance: {
|
|
361
|
+
throughput: swarmState.performance?.throughput || 0,
|
|
362
|
+
efficiency: swarmState.performance?.efficiency || 0,
|
|
363
|
+
totalTasks: swarmState.totalTaskCount || 0,
|
|
364
|
+
completedTasks: swarmState.completedTaskCount || 0
|
|
365
|
+
}
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* Update status display
|
|
370
|
+
*/
|
|
371
|
+
updateStatusDisplay(status) {
|
|
372
|
+
if (!status) {
|
|
373
|
+
this.statusBox.setContent("No active swarm detected");
|
|
374
|
+
this.agentsTable.setData([["Role", "Status", "Iteration", "Task", "Last Active"]]);
|
|
375
|
+
this.metricsBox.setContent("Waiting for swarm data...");
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
const uptimeStr = this.formatDuration(status.uptime);
|
|
379
|
+
const statusContent = `Swarm: ${status.swarmId.substring(0, 8)}
|
|
380
|
+
Status: ${status.status.toUpperCase()}
|
|
381
|
+
Uptime: ${uptimeStr}
|
|
382
|
+
Agents: ${status.agents.length}`;
|
|
383
|
+
this.statusBox.setContent(statusContent);
|
|
384
|
+
const agentData = [["Role", "Status", "Iteration", "Task", "Last Active"]];
|
|
385
|
+
for (const agent of status.agents) {
|
|
386
|
+
const lastActivity = this.formatTimeAgo(agent.lastActivity);
|
|
387
|
+
const task = agent.currentTask ? agent.currentTask.substring(0, 20) : "idle";
|
|
388
|
+
agentData.push([
|
|
389
|
+
agent.role,
|
|
390
|
+
agent.status,
|
|
391
|
+
agent.iteration.toString(),
|
|
392
|
+
task,
|
|
393
|
+
lastActivity
|
|
394
|
+
]);
|
|
395
|
+
}
|
|
396
|
+
this.agentsTable.setData(agentData);
|
|
397
|
+
const metricsContent = `Throughput: ${status.performance.throughput.toFixed(2)} tasks/min
|
|
398
|
+
Efficiency: ${(status.performance.efficiency * 100).toFixed(1)}%
|
|
399
|
+
Tasks: ${status.performance.completedTasks}/${status.performance.totalTasks}
|
|
400
|
+
Success Rate: ${status.performance.efficiency > 0 ? (status.performance.efficiency * 100).toFixed(1) : "N/A"}%`;
|
|
401
|
+
this.metricsBox.setContent(metricsContent);
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* Update UI with metrics from dashboard
|
|
405
|
+
*/
|
|
406
|
+
updateUI(metrics) {
|
|
407
|
+
this.logBox.log(`Metrics updated: ${metrics.status} - ${metrics.activeAgents} agents`);
|
|
408
|
+
}
|
|
409
|
+
/**
|
|
410
|
+
* Detect active swarms in the system
|
|
411
|
+
*/
|
|
412
|
+
async detectActiveSwarms() {
|
|
413
|
+
try {
|
|
414
|
+
const registry = SwarmRegistry.getInstance();
|
|
415
|
+
const activeSwarms = registry.listActiveSwarms();
|
|
416
|
+
const stats = registry.getStatistics();
|
|
417
|
+
if (activeSwarms.length > 0) {
|
|
418
|
+
let statusContent = `Available Swarms (${activeSwarms.length}):
|
|
419
|
+
`;
|
|
420
|
+
for (const swarm of activeSwarms.slice(0, 3)) {
|
|
421
|
+
const uptime = this.formatDuration(Date.now() - swarm.startTime);
|
|
422
|
+
statusContent += `\u2022 ${swarm.id.substring(0, 8)}: ${swarm.status} (${uptime})
|
|
423
|
+
`;
|
|
424
|
+
}
|
|
425
|
+
if (activeSwarms.length > 3) {
|
|
426
|
+
statusContent += `... and ${activeSwarms.length - 3} more`;
|
|
427
|
+
}
|
|
428
|
+
this.statusBox.setContent(statusContent);
|
|
429
|
+
this.logBox.log(`Found ${activeSwarms.length} active swarms in registry`);
|
|
430
|
+
} else {
|
|
431
|
+
const ralphProcesses = execSync('ps aux | grep "ralph" | grep -v grep', { encoding: "utf8" });
|
|
432
|
+
if (ralphProcesses.trim()) {
|
|
433
|
+
this.logBox.log("Detected Ralph processes running");
|
|
434
|
+
this.statusBox.setContent("External Ralph processes detected\n(Use swarm coordinator for full monitoring)");
|
|
435
|
+
} else {
|
|
436
|
+
this.statusBox.setContent(`No active swarms detected
|
|
437
|
+
Total swarms: ${stats.totalSwarms}
|
|
438
|
+
Completed: ${stats.completedSwarms}
|
|
439
|
+
|
|
440
|
+
Run: stackmemory ralph swarm <task>`);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
} catch {
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* Format time ago string
|
|
448
|
+
*/
|
|
449
|
+
formatTimeAgo(timestamp) {
|
|
450
|
+
const diff = Date.now() - timestamp;
|
|
451
|
+
const minutes = Math.floor(diff / 6e4);
|
|
452
|
+
const hours = Math.floor(minutes / 60);
|
|
453
|
+
const days = Math.floor(hours / 24);
|
|
454
|
+
if (days > 0) return `${days}d ago`;
|
|
455
|
+
if (hours > 0) return `${hours}h ago`;
|
|
456
|
+
if (minutes > 0) return `${minutes}m ago`;
|
|
457
|
+
return "just now";
|
|
458
|
+
}
|
|
459
|
+
/**
|
|
460
|
+
* Format duration string
|
|
461
|
+
*/
|
|
462
|
+
formatDuration(ms) {
|
|
463
|
+
const seconds = Math.floor(ms / 1e3);
|
|
464
|
+
const minutes = Math.floor(seconds / 60);
|
|
465
|
+
const hours = Math.floor(minutes / 60);
|
|
466
|
+
if (hours > 0) return `${hours}h ${minutes % 60}m`;
|
|
467
|
+
if (minutes > 0) return `${minutes}m ${seconds % 60}s`;
|
|
468
|
+
return `${seconds}s`;
|
|
469
|
+
}
|
|
470
|
+
/**
|
|
471
|
+
* Cleanup resources
|
|
472
|
+
*/
|
|
473
|
+
cleanup() {
|
|
474
|
+
if (this.refreshInterval) {
|
|
475
|
+
clearInterval(this.refreshInterval);
|
|
476
|
+
}
|
|
477
|
+
if (this.swarmDashboard) {
|
|
478
|
+
this.swarmDashboard.stopMonitoring();
|
|
479
|
+
}
|
|
480
|
+
logger.info("SwarmTUI cleaned up");
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
var swarm_monitor_default = SwarmTUI;
|
|
484
|
+
export {
|
|
485
|
+
SwarmTUI,
|
|
486
|
+
swarm_monitor_default as default
|
|
487
|
+
};
|
|
488
|
+
//# sourceMappingURL=swarm-monitor.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/features/tui/swarm-monitor.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Real-time TUI for monitoring Ralph Swarm operations\n * Tracks commits, status, agents, and lines edited per agent\n */\n\nimport blessed from 'blessed';\nimport { logger } from '../../core/monitoring/logger.js';\nimport { SwarmCoordinator } from '../../integrations/ralph/swarm/swarm-coordinator.js';\nimport { SwarmDashboard } from '../../integrations/ralph/monitoring/swarm-dashboard.js';\nimport { SwarmRegistry } from '../../integrations/ralph/monitoring/swarm-registry.js';\nimport { execSync } from 'child_process';\n\nexport interface SwarmCommitMetrics {\n agentId: string;\n role: string;\n commits: Array<{\n hash: string;\n message: string;\n timestamp: number;\n linesAdded: number;\n linesDeleted: number;\n filesChanged: number;\n }>;\n totalCommits: number;\n totalLinesAdded: number;\n totalLinesDeleted: number;\n lastActivity: number;\n}\n\nexport interface SwarmStatus {\n swarmId: string;\n status: 'active' | 'idle' | 'completed' | 'error';\n startTime: number;\n uptime: number;\n agents: Array<{\n id: string;\n role: string;\n status: string;\n currentTask?: string;\n iteration: number;\n lastActivity: number;\n }>;\n performance: {\n throughput: number;\n efficiency: number;\n totalTasks: number;\n completedTasks: number;\n };\n}\n\nexport class SwarmTUI {\n private screen: blessed.Widgets.Screen;\n private commitsTable: blessed.Widgets.TableElement;\n private statusBox: blessed.Widgets.BoxElement;\n private agentsTable: blessed.Widgets.TableElement;\n private metricsBox: blessed.Widgets.BoxElement;\n private logBox: blessed.Widgets.LogElement;\n \n private swarmCoordinator: SwarmCoordinator | null = null;\n private swarmDashboard: SwarmDashboard | null = null;\n private refreshInterval: NodeJS.Timeout | null = null;\n private commitMetrics: Map<string, SwarmCommitMetrics> = new Map();\n \n constructor() {\n this.screen = blessed.screen({\n smartCSR: true,\n title: 'Ralph Swarm Monitor'\n });\n \n this.createUI();\n this.setupKeyHandlers();\n \n logger.info('SwarmTUI initialized');\n }\n\n private createUI(): void {\n // Main layout container\n const container = blessed.box({\n parent: this.screen,\n top: 0,\n left: 0,\n width: '100%',\n height: '100%',\n style: {\n bg: 'black'\n }\n });\n\n // Title bar\n blessed.box({\n parent: container,\n top: 0,\n left: 0,\n width: '100%',\n height: 3,\n content: '\uD83E\uDDBE Ralph Swarm Monitor - Real-time Swarm Operations',\n style: {\n bg: 'blue',\n fg: 'white',\n bold: true\n },\n border: {\n type: 'line'\n }\n });\n\n // Status box (top right)\n this.statusBox = blessed.box({\n parent: container,\n top: 3,\n left: '50%',\n width: '50%',\n height: 8,\n label: ' Swarm Status ',\n content: 'No active swarm',\n style: {\n bg: 'black',\n fg: 'white'\n },\n border: {\n type: 'line',\n fg: 'cyan'\n }\n });\n\n // Metrics box (top left)\n this.metricsBox = blessed.box({\n parent: container,\n top: 3,\n left: 0,\n width: '50%',\n height: 8,\n label: ' Performance Metrics ',\n content: 'Waiting for data...',\n style: {\n bg: 'black',\n fg: 'white'\n },\n border: {\n type: 'line',\n fg: 'green'\n }\n });\n\n // Agents table (middle left)\n this.agentsTable = blessed.table({\n parent: container,\n top: 11,\n left: 0,\n width: '50%',\n height: 12,\n label: ' Active Agents ',\n style: {\n bg: 'black',\n fg: 'white',\n header: {\n bg: 'blue',\n fg: 'white',\n bold: true\n },\n cell: {\n selected: {\n bg: 'blue',\n fg: 'white'\n }\n }\n },\n border: {\n type: 'line',\n fg: 'yellow'\n },\n data: [\n ['Role', 'Status', 'Iteration', 'Task', 'Last Active']\n ]\n });\n\n // Commits table (middle right)\n this.commitsTable = blessed.table({\n parent: container,\n top: 11,\n left: '50%',\n width: '50%',\n height: 12,\n label: ' Recent Commits ',\n style: {\n bg: 'black',\n fg: 'white',\n header: {\n bg: 'blue',\n fg: 'white',\n bold: true\n },\n cell: {\n selected: {\n bg: 'blue',\n fg: 'white'\n }\n }\n },\n border: {\n type: 'line',\n fg: 'magenta'\n },\n data: [\n ['Agent', 'Message', 'Lines +/-', 'Time']\n ]\n });\n\n // Log output (bottom)\n this.logBox = blessed.log({\n parent: container,\n top: 23,\n left: 0,\n width: '100%',\n height: '100%-23',\n label: ' Swarm Logs ',\n style: {\n bg: 'black',\n fg: 'white'\n },\n border: {\n type: 'line',\n fg: 'white'\n },\n scrollable: true,\n alwaysScroll: true,\n mouse: true\n });\n\n // Help text\n blessed.box({\n parent: container,\n bottom: 0,\n left: 0,\n width: '100%',\n height: 1,\n content: 'Press q to quit, r to refresh, s to start swarm, t to stop swarm',\n style: {\n bg: 'white',\n fg: 'black'\n }\n });\n }\n\n private setupKeyHandlers(): void {\n this.screen.key(['escape', 'q', 'C-c'], () => {\n this.cleanup();\n process.exit(0);\n });\n\n this.screen.key(['r'], () => {\n this.refreshData();\n this.logBox.log('Manual refresh triggered');\n });\n\n this.screen.key(['s'], () => {\n this.logBox.log('Start swarm command - feature coming soon');\n });\n\n this.screen.key(['t'], () => {\n this.logBox.log('Stop swarm command - feature coming soon');\n });\n }\n\n /**\n * Initialize swarm monitoring\n */\n async initialize(swarmCoordinator?: SwarmCoordinator, swarmId?: string): Promise<void> {\n try {\n // Connect to existing swarm if ID provided\n if (swarmId) {\n const registry = SwarmRegistry.getInstance();\n const swarm = registry.getSwarm(swarmId);\n if (swarm) {\n this.swarmCoordinator = swarm.coordinator;\n this.logBox.log(`Connected to swarm: ${swarmId}`);\n } else {\n this.logBox.log(`Swarm not found: ${swarmId}`);\n }\n } else if (swarmCoordinator) {\n this.swarmCoordinator = swarmCoordinator;\n } else {\n // Auto-detect active swarms\n const registry = SwarmRegistry.getInstance();\n const activeSwarms = registry.listActiveSwarms();\n if (activeSwarms.length > 0) {\n this.swarmCoordinator = activeSwarms[0].coordinator;\n this.logBox.log(`Auto-connected to swarm: ${activeSwarms[0].id}`);\n }\n }\n\n if (this.swarmCoordinator) {\n this.swarmDashboard = new SwarmDashboard(this.swarmCoordinator);\n this.swarmDashboard.startMonitoring(2000); // 2 second refresh\n \n // Listen to swarm events\n this.swarmDashboard.on('metricsUpdated', (metrics) => {\n this.updateUI(metrics);\n });\n }\n\n // Start refresh interval\n this.refreshInterval = setInterval(() => {\n this.refreshData();\n }, 3000);\n\n this.logBox.log('SwarmTUI monitoring initialized');\n } catch (error: unknown) {\n logger.error('Failed to initialize SwarmTUI', error as Error);\n this.logBox.log(`Error: ${(error as Error).message}`);\n }\n }\n\n /**\n * Start the TUI display\n */\n start(): void {\n this.screen.render();\n this.logBox.log('Ralph Swarm Monitor started');\n this.logBox.log('Monitoring for active swarms...');\n }\n\n /**\n * Refresh all data\n */\n private async refreshData(): Promise<void> {\n try {\n // Update commit metrics\n await this.updateCommitMetrics();\n \n // Update swarm status if coordinator available\n if (this.swarmCoordinator) {\n const status = this.getSwarmStatus();\n this.updateStatusDisplay(status);\n } else {\n // Try to detect active swarms\n await this.detectActiveSwarms();\n }\n \n this.screen.render();\n } catch (error: unknown) {\n logger.error('Failed to refresh TUI data', error as Error);\n this.logBox.log(`Refresh error: ${(error as Error).message}`);\n }\n }\n\n /**\n * Update commit metrics for all agents\n */\n private async updateCommitMetrics(): Promise<void> {\n try {\n // Get recent commits from git log\n const gitLog = execSync(\n 'git log --oneline --since=\"1 hour ago\" --pretty=format:\"%H|%an|%s|%ct\" --numstat',\n { encoding: 'utf8', cwd: process.cwd() }\n );\n\n const commits = this.parseGitCommits(gitLog);\n this.updateCommitsTable(commits);\n \n } catch (error: unknown) {\n // Git might fail if no commits, that's okay\n this.logBox.log('No recent commits found');\n }\n }\n\n /**\n * Parse git log output into commit data\n */\n private parseGitCommits(gitLog: string): Array<{\n hash: string;\n agent: string;\n message: string;\n timestamp: number;\n linesAdded: number;\n linesDeleted: number;\n }> {\n const commits = [];\n const lines = gitLog.split('\\n').filter(Boolean);\n \n let currentCommit: any = null;\n \n for (const line of lines) {\n if (line.includes('|')) {\n // Commit info line\n const [hash, author, message, timestamp] = line.split('|');\n currentCommit = {\n hash: hash.substring(0, 8),\n agent: this.extractAgentFromAuthor(author),\n message: message.substring(0, 50),\n timestamp: parseInt(timestamp),\n linesAdded: 0,\n linesDeleted: 0\n };\n } else if (currentCommit && line.match(/^\\d+\\s+\\d+/)) {\n // Stat line (added/deleted)\n const [added, deleted] = line.split('\\t')[0].split(' ');\n currentCommit.linesAdded += parseInt(added) || 0;\n currentCommit.linesDeleted += parseInt(deleted) || 0;\n \n commits.push({ ...currentCommit });\n currentCommit = null;\n }\n }\n \n return commits.slice(0, 10); // Show last 10 commits\n }\n\n /**\n * Extract agent info from git author\n */\n private extractAgentFromAuthor(author: string): string {\n // Look for [agent_role] pattern in commit author or message\n const agentMatch = author.match(/\\[(\\w+)\\]/);\n if (agentMatch) {\n return agentMatch[1];\n }\n \n // Fallback to checking if author contains known agent roles\n const roles = ['developer', 'tester', 'optimizer', 'documenter', 'architect'];\n for (const role of roles) {\n if (author.toLowerCase().includes(role)) {\n return role;\n }\n }\n \n return 'user';\n }\n\n /**\n * Update commits table display\n */\n private updateCommitsTable(commits: any[]): void {\n const tableData = [\n ['Agent', 'Message', 'Lines +/-', 'Time']\n ];\n\n for (const commit of commits) {\n const timeAgo = this.formatTimeAgo(commit.timestamp * 1000);\n const linesChange = `+${commit.linesAdded}/-${commit.linesDeleted}`;\n \n tableData.push([\n commit.agent,\n commit.message,\n linesChange,\n timeAgo\n ]);\n }\n\n this.commitsTable.setData(tableData);\n }\n\n /**\n * Get current swarm status\n */\n private getSwarmStatus(): SwarmStatus | null {\n if (!this.swarmCoordinator) return null;\n\n const usage = this.swarmCoordinator.getResourceUsage();\n const swarmState = (this.swarmCoordinator as any).swarmState;\n \n if (!swarmState) return null;\n\n return {\n swarmId: swarmState.id,\n status: swarmState.status,\n startTime: swarmState.startTime,\n uptime: Date.now() - swarmState.startTime,\n agents: usage.activeAgents ? Array.from((this.swarmCoordinator as any).activeAgents?.values() || []).map((agent: any) => ({\n id: agent.id,\n role: agent.role,\n status: agent.status,\n currentTask: agent.currentTask,\n iteration: agent.performance?.tasksCompleted || 0,\n lastActivity: agent.performance?.lastFreshStart || Date.now()\n })) : [],\n performance: {\n throughput: swarmState.performance?.throughput || 0,\n efficiency: swarmState.performance?.efficiency || 0,\n totalTasks: swarmState.totalTaskCount || 0,\n completedTasks: swarmState.completedTaskCount || 0\n }\n };\n }\n\n /**\n * Update status display\n */\n private updateStatusDisplay(status: SwarmStatus | null): void {\n if (!status) {\n this.statusBox.setContent('No active swarm detected');\n this.agentsTable.setData([['Role', 'Status', 'Iteration', 'Task', 'Last Active']]);\n this.metricsBox.setContent('Waiting for swarm data...');\n return;\n }\n\n // Update status box\n const uptimeStr = this.formatDuration(status.uptime);\n const statusContent = `Swarm: ${status.swarmId.substring(0, 8)}\nStatus: ${status.status.toUpperCase()}\nUptime: ${uptimeStr}\nAgents: ${status.agents.length}`;\n \n this.statusBox.setContent(statusContent);\n\n // Update agents table\n const agentData = [['Role', 'Status', 'Iteration', 'Task', 'Last Active']];\n for (const agent of status.agents) {\n const lastActivity = this.formatTimeAgo(agent.lastActivity);\n const task = agent.currentTask ? agent.currentTask.substring(0, 20) : 'idle';\n \n agentData.push([\n agent.role,\n agent.status,\n agent.iteration.toString(),\n task,\n lastActivity\n ]);\n }\n this.agentsTable.setData(agentData);\n\n // Update metrics box\n const metricsContent = `Throughput: ${status.performance.throughput.toFixed(2)} tasks/min\nEfficiency: ${(status.performance.efficiency * 100).toFixed(1)}%\nTasks: ${status.performance.completedTasks}/${status.performance.totalTasks}\nSuccess Rate: ${status.performance.efficiency > 0 ? (status.performance.efficiency * 100).toFixed(1) : 'N/A'}%`;\n \n this.metricsBox.setContent(metricsContent);\n }\n\n /**\n * Update UI with metrics from dashboard\n */\n private updateUI(metrics: any): void {\n this.logBox.log(`Metrics updated: ${metrics.status} - ${metrics.activeAgents} agents`);\n }\n\n /**\n * Detect active swarms in the system\n */\n private async detectActiveSwarms(): Promise<void> {\n try {\n const registry = SwarmRegistry.getInstance();\n const activeSwarms = registry.listActiveSwarms();\n const stats = registry.getStatistics();\n \n if (activeSwarms.length > 0) {\n let statusContent = `Available Swarms (${activeSwarms.length}):\\n`;\n for (const swarm of activeSwarms.slice(0, 3)) {\n const uptime = this.formatDuration(Date.now() - swarm.startTime);\n statusContent += `\u2022 ${swarm.id.substring(0, 8)}: ${swarm.status} (${uptime})\\n`;\n }\n if (activeSwarms.length > 3) {\n statusContent += `... and ${activeSwarms.length - 3} more`;\n }\n this.statusBox.setContent(statusContent);\n this.logBox.log(`Found ${activeSwarms.length} active swarms in registry`);\n } else {\n // Check for Ralph processes as fallback\n const ralphProcesses = execSync('ps aux | grep \"ralph\" | grep -v grep', { encoding: 'utf8' });\n \n if (ralphProcesses.trim()) {\n this.logBox.log('Detected Ralph processes running');\n this.statusBox.setContent('External Ralph processes detected\\n(Use swarm coordinator for full monitoring)');\n } else {\n this.statusBox.setContent(`No active swarms detected\nTotal swarms: ${stats.totalSwarms}\nCompleted: ${stats.completedSwarms}\n\nRun: stackmemory ralph swarm <task>`);\n }\n }\n } catch {\n // No processes found, that's fine\n }\n }\n\n /**\n * Format time ago string\n */\n private formatTimeAgo(timestamp: number): string {\n const diff = Date.now() - timestamp;\n const minutes = Math.floor(diff / 60000);\n const hours = Math.floor(minutes / 60);\n const days = Math.floor(hours / 24);\n\n if (days > 0) return `${days}d ago`;\n if (hours > 0) return `${hours}h ago`;\n if (minutes > 0) return `${minutes}m ago`;\n return 'just now';\n }\n\n /**\n * Format duration string\n */\n private formatDuration(ms: number): string {\n const seconds = Math.floor(ms / 1000);\n const minutes = Math.floor(seconds / 60);\n const hours = Math.floor(minutes / 60);\n\n if (hours > 0) return `${hours}h ${minutes % 60}m`;\n if (minutes > 0) return `${minutes}m ${seconds % 60}s`;\n return `${seconds}s`;\n }\n\n /**\n * Cleanup resources\n */\n private cleanup(): void {\n if (this.refreshInterval) {\n clearInterval(this.refreshInterval);\n }\n \n if (this.swarmDashboard) {\n this.swarmDashboard.stopMonitoring();\n }\n \n logger.info('SwarmTUI cleaned up');\n }\n}\n\nexport default SwarmTUI;"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -5,7 +5,6 @@ import { execSync } from "child_process";
|
|
|
5
5
|
import { logger } from "../../../core/monitoring/logger.js";
|
|
6
6
|
import { FrameManager } from "../../../core/context/frame-manager.js";
|
|
7
7
|
import { SessionManager } from "../../../core/session/session-manager.js";
|
|
8
|
-
import { SQLiteAdapter } from "../../../core/database/sqlite-adapter.js";
|
|
9
8
|
import { ContextBudgetManager } from "../context/context-budget-manager.js";
|
|
10
9
|
import { StateReconciler } from "../state/state-reconciler.js";
|
|
11
10
|
import { IterationLifecycle } from "../lifecycle/iteration-lifecycle.js";
|
|
@@ -46,11 +45,7 @@ class RalphStackMemoryBridge {
|
|
|
46
45
|
sessionId: options?.sessionId
|
|
47
46
|
});
|
|
48
47
|
this.state.currentSession = session;
|
|
49
|
-
|
|
50
|
-
await dbAdapter.connect();
|
|
51
|
-
const db = dbAdapter.db;
|
|
52
|
-
const projectId = path.basename(this.ralphDir);
|
|
53
|
-
this.frameManager = new FrameManager(db, projectId, { skipContextBridge: true });
|
|
48
|
+
this.frameManager = new FrameManager();
|
|
54
49
|
if (options?.loopId) {
|
|
55
50
|
await this.resumeLoop(options.loopId);
|
|
56
51
|
} else if (options?.task && options?.criteria) {
|
|
@@ -385,12 +380,7 @@ class RalphStackMemoryBridge {
|
|
|
385
380
|
status: "started"
|
|
386
381
|
}
|
|
387
382
|
};
|
|
388
|
-
return await this.frameManager.
|
|
389
|
-
name: frame.name,
|
|
390
|
-
type: frame.type,
|
|
391
|
-
content: frame.content || "",
|
|
392
|
-
metadata: frame.metadata
|
|
393
|
-
});
|
|
383
|
+
return await this.frameManager.pushFrame(frame);
|
|
394
384
|
}
|
|
395
385
|
/**
|
|
396
386
|
* Load iteration context from StackMemory
|
|
@@ -490,14 +480,6 @@ class RalphStackMemoryBridge {
|
|
|
490
480
|
};
|
|
491
481
|
await this.state.performanceOptimizer.saveFrame(frame);
|
|
492
482
|
}
|
|
493
|
-
/**
|
|
494
|
-
* Get database adapter for FrameManager
|
|
495
|
-
*/
|
|
496
|
-
async getDatabaseAdapter() {
|
|
497
|
-
const dbPath = path.join(this.ralphDir, "stackmemory.db");
|
|
498
|
-
const projectId = path.basename(this.ralphDir);
|
|
499
|
-
return new SQLiteAdapter(projectId, { dbPath });
|
|
500
|
-
}
|
|
501
483
|
/**
|
|
502
484
|
* Additional helper methods
|
|
503
485
|
*/
|