consensus-cli 0.1.0 → 0.1.4
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/CHANGELOG.md +21 -0
- package/README.md +7 -2
- package/dist/activity.js +20 -3
- package/dist/cli.js +12 -0
- package/dist/codexLogs.js +73 -1
- package/dist/opencodeApi.js +84 -0
- package/dist/opencodeEvents.js +359 -0
- package/dist/opencodeServer.js +91 -0
- package/dist/opencodeStorage.js +127 -0
- package/dist/scan.js +333 -13
- package/package.json +3 -2
- package/public/app.js +162 -25
- package/public/index.html +3 -0
- package/public/style.css +29 -0
package/public/app.js
CHANGED
|
@@ -9,8 +9,10 @@ const panelClose = document.getElementById("panel-close");
|
|
|
9
9
|
const statusEl = document.getElementById("status");
|
|
10
10
|
const countEl = document.getElementById("count");
|
|
11
11
|
const activeList = document.getElementById("active-list");
|
|
12
|
+
const serverList = document.getElementById("server-list");
|
|
12
13
|
const searchInput = document.getElementById("search");
|
|
13
14
|
const laneTitle = document.querySelector(".lane-title");
|
|
15
|
+
const serverTitle = document.querySelector(".server-title");
|
|
14
16
|
|
|
15
17
|
const tileW = 96;
|
|
16
18
|
const tileH = 48;
|
|
@@ -24,6 +26,11 @@ const statePalette = {
|
|
|
24
26
|
idle: { top: "#384a57", left: "#2b3943", right: "#25323b", stroke: "#4f6b7a" },
|
|
25
27
|
error: { top: "#82443c", left: "#6d3530", right: "#5a2c28", stroke: "#d1584b" },
|
|
26
28
|
};
|
|
29
|
+
const serverPalette = {
|
|
30
|
+
active: { top: "#7d6a2b", left: "#665725", right: "#54481f", stroke: "#f5c453" },
|
|
31
|
+
idle: { top: "#353b42", left: "#272c33", right: "#1f242a", stroke: "#6b7380" },
|
|
32
|
+
error: statePalette.error,
|
|
33
|
+
};
|
|
27
34
|
const stateOpacity = {
|
|
28
35
|
active: 1,
|
|
29
36
|
idle: 0.35,
|
|
@@ -49,6 +56,53 @@ let searchMatches = new Set();
|
|
|
49
56
|
const layout = new Map();
|
|
50
57
|
const occupied = new Map();
|
|
51
58
|
|
|
59
|
+
function ensureSelectedVisible(agent) {
|
|
60
|
+
if (!agent || !panel.classList.contains("open")) return;
|
|
61
|
+
if (view.dragging) return;
|
|
62
|
+
const panelRect = panel.getBoundingClientRect();
|
|
63
|
+
if (panelRect.width >= window.innerWidth * 0.8) return;
|
|
64
|
+
const key = keyForAgent(agent);
|
|
65
|
+
const coord = layout.get(key);
|
|
66
|
+
if (!coord) return;
|
|
67
|
+
|
|
68
|
+
const screen = isoToScreen(coord.x, coord.y, tileW, tileH);
|
|
69
|
+
const memMB = (agent.mem || 0) / (1024 * 1024);
|
|
70
|
+
const heightBase = Math.min(120, Math.max(18, memMB * 0.4));
|
|
71
|
+
const idleScale = agent.state === "idle" ? 0.6 : 1;
|
|
72
|
+
const height = heightBase * idleScale;
|
|
73
|
+
|
|
74
|
+
const targetX = view.x + screen.x * view.scale;
|
|
75
|
+
const targetY = view.y + screen.y * view.scale;
|
|
76
|
+
const halfW = (tileW / 2) * view.scale;
|
|
77
|
+
const halfH = (tileH / 2) * view.scale;
|
|
78
|
+
const padding = 36;
|
|
79
|
+
const viewportWidth = window.innerWidth - panelRect.width;
|
|
80
|
+
const viewportHeight = window.innerHeight;
|
|
81
|
+
|
|
82
|
+
const left = targetX - halfW;
|
|
83
|
+
const right = targetX + halfW;
|
|
84
|
+
const top = targetY - (height + tileH * 0.6) * view.scale;
|
|
85
|
+
const bottom = targetY + (halfH + tileH * 0.6) * view.scale;
|
|
86
|
+
|
|
87
|
+
let dx = 0;
|
|
88
|
+
let dy = 0;
|
|
89
|
+
if (right > viewportWidth - padding) {
|
|
90
|
+
dx = viewportWidth - padding - right;
|
|
91
|
+
} else if (left < padding) {
|
|
92
|
+
dx = padding - left;
|
|
93
|
+
}
|
|
94
|
+
if (top < padding) {
|
|
95
|
+
dy = padding - top;
|
|
96
|
+
} else if (bottom > viewportHeight - padding) {
|
|
97
|
+
dy = viewportHeight - padding - bottom;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (dx !== 0 || dy !== 0) {
|
|
101
|
+
view.x += dx;
|
|
102
|
+
view.y += dy;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
52
106
|
function resize() {
|
|
53
107
|
deviceScale = window.devicePixelRatio || 1;
|
|
54
108
|
canvas.width = window.innerWidth * deviceScale;
|
|
@@ -72,12 +126,16 @@ function hashString(input) {
|
|
|
72
126
|
return Math.abs(hash);
|
|
73
127
|
}
|
|
74
128
|
|
|
75
|
-
function
|
|
129
|
+
function groupKeyForAgent(agent) {
|
|
76
130
|
return agent.repo || agent.cwd || agent.cmd || agent.id;
|
|
77
131
|
}
|
|
78
132
|
|
|
79
|
-
function
|
|
80
|
-
|
|
133
|
+
function keyForAgent(agent) {
|
|
134
|
+
return `${groupKeyForAgent(agent)}::${agent.id}`;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function assignCoordinate(key, baseKey) {
|
|
138
|
+
const hash = hashString(baseKey || key);
|
|
81
139
|
const baseX = (hash % 16) - 8;
|
|
82
140
|
const baseY = ((hash >> 4) % 16) - 8;
|
|
83
141
|
const maxRadius = 20;
|
|
@@ -105,9 +163,10 @@ function updateLayout(newAgents) {
|
|
|
105
163
|
const activeKeys = new Set();
|
|
106
164
|
for (const agent of newAgents) {
|
|
107
165
|
const key = keyForAgent(agent);
|
|
166
|
+
const baseKey = groupKeyForAgent(agent);
|
|
108
167
|
activeKeys.add(key);
|
|
109
168
|
if (!layout.has(key)) {
|
|
110
|
-
assignCoordinate(key);
|
|
169
|
+
assignCoordinate(key, baseKey);
|
|
111
170
|
}
|
|
112
171
|
}
|
|
113
172
|
|
|
@@ -123,8 +182,14 @@ function setStatus(text) {
|
|
|
123
182
|
statusEl.textContent = text;
|
|
124
183
|
}
|
|
125
184
|
|
|
126
|
-
function setCount(
|
|
127
|
-
|
|
185
|
+
function setCount(agentCount, serverCount) {
|
|
186
|
+
const agentLabel = `${agentCount} agent${agentCount === 1 ? "" : "s"}`;
|
|
187
|
+
if (typeof serverCount === "number") {
|
|
188
|
+
const serverLabel = `${serverCount} server${serverCount === 1 ? "" : "s"}`;
|
|
189
|
+
countEl.textContent = `${agentLabel} • ${serverLabel}`;
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
countEl.textContent = agentLabel;
|
|
128
193
|
}
|
|
129
194
|
|
|
130
195
|
function formatBytes(bytes) {
|
|
@@ -153,6 +218,26 @@ function escapeHtml(value) {
|
|
|
153
218
|
.replace(/'/g, "'");
|
|
154
219
|
}
|
|
155
220
|
|
|
221
|
+
function isServerKind(kind) {
|
|
222
|
+
return kind === "app-server" || kind === "opencode-server";
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function paletteFor(agent) {
|
|
226
|
+
if (isServerKind(agent.kind)) {
|
|
227
|
+
return serverPalette[agent.state] || serverPalette.idle;
|
|
228
|
+
}
|
|
229
|
+
return statePalette[agent.state] || statePalette.idle;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function accentFor(agent) {
|
|
233
|
+
return isServerKind(agent.kind) ? "#f5c453" : "#57f2c6";
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function accentGlow(agent, alpha) {
|
|
237
|
+
const tint = isServerKind(agent.kind) ? "245, 196, 83" : "87, 242, 198";
|
|
238
|
+
return `rgba(${tint}, ${alpha})`;
|
|
239
|
+
}
|
|
240
|
+
|
|
156
241
|
function labelFor(agent) {
|
|
157
242
|
if (agent.title) return agent.title;
|
|
158
243
|
if (agent.repo) return agent.repo;
|
|
@@ -220,10 +305,10 @@ function drawTag(ctx, x, y, text, accent) {
|
|
|
220
305
|
ctx.restore();
|
|
221
306
|
}
|
|
222
307
|
|
|
223
|
-
function
|
|
224
|
-
if (!
|
|
308
|
+
function renderLaneList(items, container, emptyLabel) {
|
|
309
|
+
if (!container) return;
|
|
225
310
|
if (!items.length) {
|
|
226
|
-
|
|
311
|
+
container.innerHTML = `<div class="lane-meta">${emptyLabel}</div>`;
|
|
227
312
|
return;
|
|
228
313
|
}
|
|
229
314
|
const sorted = [...items].sort((a, b) => {
|
|
@@ -234,7 +319,7 @@ function renderActiveList(items) {
|
|
|
234
319
|
return b.cpu - a.cpu;
|
|
235
320
|
});
|
|
236
321
|
|
|
237
|
-
|
|
322
|
+
container.innerHTML = sorted
|
|
238
323
|
.map((agent) => {
|
|
239
324
|
const doingRaw = agent.summary?.current || agent.doing || agent.cmdShort || "";
|
|
240
325
|
const doing = escapeHtml(truncate(doingRaw, 80));
|
|
@@ -252,7 +337,7 @@ function renderActiveList(items) {
|
|
|
252
337
|
})
|
|
253
338
|
.join("");
|
|
254
339
|
|
|
255
|
-
Array.from(
|
|
340
|
+
Array.from(container.querySelectorAll(".lane-item")).forEach((item) => {
|
|
256
341
|
item.addEventListener("click", () => {
|
|
257
342
|
const id = item.getAttribute("data-id");
|
|
258
343
|
selected = sorted.find((agent) => agent.id === id) || null;
|
|
@@ -369,13 +454,16 @@ function draw() {
|
|
|
369
454
|
ctx.fillStyle = "rgba(228, 230, 235, 0.6)";
|
|
370
455
|
ctx.font = "16px Space Grotesk";
|
|
371
456
|
ctx.textAlign = "center";
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
457
|
+
ctx.fillText("No codex processes found", 0, 0);
|
|
458
|
+
ctx.restore();
|
|
459
|
+
requestAnimationFrame(draw);
|
|
460
|
+
return;
|
|
376
461
|
}
|
|
377
462
|
|
|
378
463
|
updateLayout(agents);
|
|
464
|
+
if (selected) {
|
|
465
|
+
ensureSelectedVisible(selected);
|
|
466
|
+
}
|
|
379
467
|
|
|
380
468
|
const drawList = agents
|
|
381
469
|
.map((agent) => {
|
|
@@ -396,13 +484,22 @@ function draw() {
|
|
|
396
484
|
const reducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
397
485
|
|
|
398
486
|
for (const item of drawList) {
|
|
399
|
-
const palette =
|
|
487
|
+
const palette = paletteFor(item.agent);
|
|
400
488
|
const memMB = item.agent.mem / (1024 * 1024);
|
|
401
489
|
const heightBase = Math.min(120, Math.max(18, memMB * 0.4));
|
|
490
|
+
const isActive = item.agent.state === "active";
|
|
491
|
+
const isServer = isServerKind(item.agent.kind);
|
|
492
|
+
const accent = accentFor(item.agent);
|
|
493
|
+
const accentStrong = isServer ? "rgba(245, 196, 83, 0.6)" : "rgba(87, 242, 198, 0.6)";
|
|
494
|
+
const accentSoft = isServer ? "rgba(245, 196, 83, 0.35)" : "rgba(87, 242, 198, 0.35)";
|
|
402
495
|
const pulse =
|
|
403
|
-
|
|
496
|
+
isActive && !reducedMotion
|
|
404
497
|
? 4 + Math.sin(time / 200) * 3
|
|
405
498
|
: 0;
|
|
499
|
+
const pulsePhase =
|
|
500
|
+
isActive && !reducedMotion
|
|
501
|
+
? (Math.sin(time / 240) + 1) / 2
|
|
502
|
+
: 0;
|
|
406
503
|
const idleScale = item.agent.state === "idle" ? 0.6 : 1;
|
|
407
504
|
const height = heightBase * idleScale + pulse;
|
|
408
505
|
|
|
@@ -425,8 +522,33 @@ function draw() {
|
|
|
425
522
|
null
|
|
426
523
|
);
|
|
427
524
|
|
|
525
|
+
if (isActive) {
|
|
526
|
+
const glowAlpha = 0.12 + pulsePhase * 0.22;
|
|
527
|
+
const capAlpha = 0.16 + pulsePhase * 0.28;
|
|
528
|
+
ctx.save();
|
|
529
|
+
drawDiamond(
|
|
530
|
+
ctx,
|
|
531
|
+
x,
|
|
532
|
+
y + tileH * 0.02,
|
|
533
|
+
tileW * 0.92,
|
|
534
|
+
tileH * 0.46,
|
|
535
|
+
accentGlow(item.agent, glowAlpha),
|
|
536
|
+
null
|
|
537
|
+
);
|
|
538
|
+
drawDiamond(
|
|
539
|
+
ctx,
|
|
540
|
+
x,
|
|
541
|
+
y - height - tileH * 0.18,
|
|
542
|
+
roofSize * 0.82,
|
|
543
|
+
roofSize * 0.42,
|
|
544
|
+
accentGlow(item.agent, capAlpha),
|
|
545
|
+
null
|
|
546
|
+
);
|
|
547
|
+
ctx.restore();
|
|
548
|
+
}
|
|
549
|
+
|
|
428
550
|
if (selected && selected.id === item.agent.id) {
|
|
429
|
-
drawDiamond(ctx, x, y, tileW + 10, tileH + 6, "rgba(0,0,0,0)",
|
|
551
|
+
drawDiamond(ctx, x, y, tileW + 10, tileH + 6, "rgba(0,0,0,0)", accent);
|
|
430
552
|
}
|
|
431
553
|
|
|
432
554
|
ctx.fillStyle = "rgba(10, 12, 15, 0.6)";
|
|
@@ -439,15 +561,21 @@ function draw() {
|
|
|
439
561
|
const showActiveTag = topActiveIds.has(item.agent.id);
|
|
440
562
|
if (isHovered || isSelected) {
|
|
441
563
|
const label = truncate(labelFor(item.agent), 20);
|
|
442
|
-
drawTag(ctx, x, y - height - tileH * 0.6, label,
|
|
564
|
+
drawTag(ctx, x, y - height - tileH * 0.6, label, accentStrong);
|
|
443
565
|
const doing = truncate(item.agent.summary?.current || item.agent.doing || "", 36);
|
|
444
|
-
drawTag(ctx, x, y - height - tileH * 0.9, doing,
|
|
566
|
+
drawTag(ctx, x, y - height - tileH * 0.9, doing, accentSoft);
|
|
567
|
+
if (isServer) {
|
|
568
|
+
drawTag(ctx, x, y + tileH * 0.2, "server", "rgba(79, 107, 122, 0.6)");
|
|
569
|
+
}
|
|
445
570
|
} else if (showActiveTag) {
|
|
446
571
|
const doing = truncate(
|
|
447
572
|
item.agent.summary?.current || item.agent.doing || labelFor(item.agent),
|
|
448
573
|
32
|
|
449
574
|
);
|
|
450
|
-
drawTag(ctx, x, y - height - tileH * 0.7, doing,
|
|
575
|
+
drawTag(ctx, x, y - height - tileH * 0.7, doing, accentSoft);
|
|
576
|
+
if (isServer) {
|
|
577
|
+
drawTag(ctx, x, y + tileH * 0.2, "server", "rgba(79, 107, 122, 0.6)");
|
|
578
|
+
}
|
|
451
579
|
}
|
|
452
580
|
|
|
453
581
|
hitList.push({
|
|
@@ -600,7 +728,9 @@ function connect() {
|
|
|
600
728
|
|
|
601
729
|
function applySnapshot(payload) {
|
|
602
730
|
agents = payload.agents || [];
|
|
603
|
-
|
|
731
|
+
const serverAgents = agents.filter((agent) => isServerKind(agent.kind));
|
|
732
|
+
const agentNodes = agents.filter((agent) => !isServerKind(agent.kind));
|
|
733
|
+
setCount(agentNodes.length, serverAgents.length);
|
|
604
734
|
const query = searchQuery.trim().toLowerCase();
|
|
605
735
|
searchMatches = new Set(
|
|
606
736
|
query ? agents.filter((agent) => matchesQuery(agent, query)).map((agent) => agent.id) : []
|
|
@@ -609,12 +739,19 @@ function applySnapshot(payload) {
|
|
|
609
739
|
? agents.filter((agent) => searchMatches.has(agent.id))
|
|
610
740
|
: agents;
|
|
611
741
|
const listAgents = query
|
|
612
|
-
? visibleAgents
|
|
613
|
-
: visibleAgents.filter((agent) => agent.state !== "idle");
|
|
742
|
+
? visibleAgents.filter((agent) => !isServerKind(agent.kind))
|
|
743
|
+
: visibleAgents.filter((agent) => agent.state !== "idle" && !isServerKind(agent.kind));
|
|
744
|
+
const listServers = query
|
|
745
|
+
? visibleAgents.filter((agent) => isServerKind(agent.kind))
|
|
746
|
+
: visibleAgents.filter((agent) => isServerKind(agent.kind));
|
|
614
747
|
if (laneTitle) {
|
|
615
748
|
laneTitle.textContent = query ? "search results" : "active agents";
|
|
616
749
|
}
|
|
617
|
-
|
|
750
|
+
if (serverTitle) {
|
|
751
|
+
serverTitle.textContent = query ? "server results" : "servers";
|
|
752
|
+
}
|
|
753
|
+
renderLaneList(listAgents, activeList, "No active agents.");
|
|
754
|
+
renderLaneList(listServers, serverList, "No servers detected.");
|
|
618
755
|
if (selected) {
|
|
619
756
|
selected = agents.find((agent) => agent.id === selected.id) || selected;
|
|
620
757
|
renderPanel(selected);
|
package/public/index.html
CHANGED
|
@@ -41,6 +41,9 @@
|
|
|
41
41
|
aria-label="Search metadata"
|
|
42
42
|
/>
|
|
43
43
|
<div id="active-list"></div>
|
|
44
|
+
<div class="lane-divider" aria-hidden="true"></div>
|
|
45
|
+
<div class="lane-title server-title">servers</div>
|
|
46
|
+
<div id="server-list"></div>
|
|
44
47
|
</div>
|
|
45
48
|
<div id="tooltip" class="hidden"></div>
|
|
46
49
|
<aside id="panel" class="collapsed" aria-label="Agent details">
|
package/public/style.css
CHANGED
|
@@ -282,6 +282,18 @@ body {
|
|
|
282
282
|
gap: 8px;
|
|
283
283
|
}
|
|
284
284
|
|
|
285
|
+
#server-list {
|
|
286
|
+
display: flex;
|
|
287
|
+
flex-direction: column;
|
|
288
|
+
gap: 8px;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
.lane-divider {
|
|
292
|
+
height: 1px;
|
|
293
|
+
margin: 12px 0;
|
|
294
|
+
background: rgba(62, 78, 89, 0.6);
|
|
295
|
+
}
|
|
296
|
+
|
|
285
297
|
.lane-item {
|
|
286
298
|
display: flex;
|
|
287
299
|
align-items: flex-start;
|
|
@@ -320,11 +332,13 @@ body {
|
|
|
320
332
|
margin-top: 6px;
|
|
321
333
|
background: var(--idle);
|
|
322
334
|
box-shadow: 0 0 10px transparent;
|
|
335
|
+
transform-origin: center;
|
|
323
336
|
}
|
|
324
337
|
|
|
325
338
|
.lane-pill.active {
|
|
326
339
|
background: var(--active);
|
|
327
340
|
box-shadow: 0 0 12px rgba(81, 195, 165, 0.5);
|
|
341
|
+
animation: lanePulse 1.3s ease-in-out infinite;
|
|
328
342
|
}
|
|
329
343
|
|
|
330
344
|
.lane-pill.error {
|
|
@@ -332,6 +346,21 @@ body {
|
|
|
332
346
|
box-shadow: 0 0 12px rgba(209, 88, 75, 0.5);
|
|
333
347
|
}
|
|
334
348
|
|
|
349
|
+
@keyframes lanePulse {
|
|
350
|
+
0% {
|
|
351
|
+
transform: scale(1);
|
|
352
|
+
box-shadow: 0 0 10px rgba(81, 195, 165, 0.35);
|
|
353
|
+
}
|
|
354
|
+
50% {
|
|
355
|
+
transform: scale(1.35);
|
|
356
|
+
box-shadow: 0 0 16px rgba(81, 195, 165, 0.6);
|
|
357
|
+
}
|
|
358
|
+
100% {
|
|
359
|
+
transform: scale(1);
|
|
360
|
+
box-shadow: 0 0 10px rgba(81, 195, 165, 0.35);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
335
364
|
.lane-copy {
|
|
336
365
|
display: flex;
|
|
337
366
|
flex-direction: column;
|