agent-coord-mcp 0.4.0 → 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.
- package/package.json +1 -1
- package/scripts/coord-chat.mjs +85 -22
package/package.json
CHANGED
package/scripts/coord-chat.mjs
CHANGED
|
@@ -429,23 +429,92 @@ async function postStatus(status) {
|
|
|
429
429
|
async function pruneOld(days) {
|
|
430
430
|
const cutoff = Date.now() - days * 24 * 60 * 60 * 1000;
|
|
431
431
|
let total = 0;
|
|
432
|
-
|
|
432
|
+
// Per-file removal counts so we can shift the corresponding cursor
|
|
433
|
+
// offsets — without this, every other agent's roomOffset/statusOffset/
|
|
434
|
+
// inboxOffset would point past the now-shorter file and they'd silently
|
|
435
|
+
// miss messages until enough new ones piled up to overtake the stale offset.
|
|
436
|
+
let roomRemoved = 0;
|
|
437
|
+
let statusRemoved = 0;
|
|
438
|
+
const inboxRemoved = {}; // agentId → count
|
|
439
|
+
|
|
440
|
+
const files = [
|
|
441
|
+
{ path: ROOM_FILE, kind: "room" },
|
|
442
|
+
{ path: STATUS_FILE_PATH, kind: "status" },
|
|
443
|
+
];
|
|
433
444
|
if (existsSync(INBOX_DIR)) {
|
|
434
445
|
for (const n of readdirSync(INBOX_DIR)) {
|
|
435
|
-
if (n.endsWith(".jsonl"))
|
|
446
|
+
if (n.endsWith(".jsonl")) {
|
|
447
|
+
files.push({ path: path.join(INBOX_DIR, n), kind: "inbox", agentId: n.replace(/\.jsonl$/, "") });
|
|
448
|
+
}
|
|
436
449
|
}
|
|
437
450
|
}
|
|
438
|
-
for (const
|
|
439
|
-
if (!existsSync(
|
|
440
|
-
const all = readJsonl(
|
|
451
|
+
for (const f of files) {
|
|
452
|
+
if (!existsSync(f.path)) continue;
|
|
453
|
+
const all = readJsonl(f.path);
|
|
441
454
|
const kept = all.filter((e) => e && e.ts > cutoff);
|
|
442
|
-
|
|
455
|
+
const removed = all.length - kept.length;
|
|
456
|
+
if (removed > 0) {
|
|
443
457
|
const body = kept.length ? kept.map((e) => JSON.stringify(e)).join("\n") + "\n" : "";
|
|
444
|
-
writeFileSync(
|
|
445
|
-
total +=
|
|
458
|
+
writeFileSync(f.path, body);
|
|
459
|
+
total += removed;
|
|
460
|
+
if (f.kind === "room") roomRemoved += removed;
|
|
461
|
+
else if (f.kind === "status") statusRemoved += removed;
|
|
462
|
+
else inboxRemoved[f.agentId] = (inboxRemoved[f.agentId] ?? 0) + removed;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
if (roomRemoved || statusRemoved || Object.keys(inboxRemoved).length) {
|
|
466
|
+
shiftAllCursors({ roomRemoved, statusRemoved, inboxRemoved });
|
|
467
|
+
}
|
|
468
|
+
say(A.dim(`→ pruned ${total} entries older than ${days}d (cursors adjusted)`));
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
async function wipeRoom() {
|
|
472
|
+
await ensureFile(ROOM_FILE);
|
|
473
|
+
writeFileSync(ROOM_FILE, "");
|
|
474
|
+
// Reset every agent's roomOffset to 0 so they start reading the (now empty)
|
|
475
|
+
// file from the beginning. Otherwise their stale offsets point past EOF.
|
|
476
|
+
resetAllRoomOffsets();
|
|
477
|
+
say(A.dim("→ room wiped (all room cursors reset)"));
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
// Walk every cursor file and shift offsets down by the per-channel removed
|
|
481
|
+
// counts. Mirrors what the MCP prune tool does server-side.
|
|
482
|
+
function shiftAllCursors({ roomRemoved = 0, statusRemoved = 0, inboxRemoved = {} }) {
|
|
483
|
+
if (!existsSync(CURSOR_DIR)) return;
|
|
484
|
+
for (const name of readdirSync(CURSOR_DIR)) {
|
|
485
|
+
if (!name.endsWith(".json")) continue;
|
|
486
|
+
const cursorPath = path.join(CURSOR_DIR, name);
|
|
487
|
+
const cur = readJsonSafe(cursorPath, {});
|
|
488
|
+
const id = name.replace(/\.json$/, "");
|
|
489
|
+
let touched = false;
|
|
490
|
+
if (cur.roomOffset !== undefined && roomRemoved > 0) {
|
|
491
|
+
cur.roomOffset = Math.max(0, cur.roomOffset - roomRemoved);
|
|
492
|
+
touched = true;
|
|
493
|
+
}
|
|
494
|
+
if (cur.statusOffset !== undefined && statusRemoved > 0) {
|
|
495
|
+
cur.statusOffset = Math.max(0, cur.statusOffset - statusRemoved);
|
|
496
|
+
touched = true;
|
|
497
|
+
}
|
|
498
|
+
const myInbox = inboxRemoved[id] ?? 0;
|
|
499
|
+
if (cur.inboxOffset !== undefined && myInbox > 0) {
|
|
500
|
+
cur.inboxOffset = Math.max(0, cur.inboxOffset - myInbox);
|
|
501
|
+
touched = true;
|
|
502
|
+
}
|
|
503
|
+
if (touched) writeJsonAtomic(cursorPath, cur);
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
function resetAllRoomOffsets() {
|
|
508
|
+
if (!existsSync(CURSOR_DIR)) return;
|
|
509
|
+
for (const name of readdirSync(CURSOR_DIR)) {
|
|
510
|
+
if (!name.endsWith(".json")) continue;
|
|
511
|
+
const cursorPath = path.join(CURSOR_DIR, name);
|
|
512
|
+
const cur = readJsonSafe(cursorPath, {});
|
|
513
|
+
if (cur.roomOffset !== undefined && cur.roomOffset !== 0) {
|
|
514
|
+
cur.roomOffset = 0;
|
|
515
|
+
writeJsonAtomic(cursorPath, cur);
|
|
446
516
|
}
|
|
447
517
|
}
|
|
448
|
-
say(A.dim(`→ pruned ${total} entries older than ${days}d`));
|
|
449
518
|
}
|
|
450
519
|
|
|
451
520
|
async function kickAgent(target) {
|
|
@@ -471,19 +540,13 @@ async function kickAgent(target) {
|
|
|
471
540
|
try { process.kill(marker.pid, "SIGTERM"); } catch {}
|
|
472
541
|
}
|
|
473
542
|
try { if (existsSync(markerPath)) unlinkSync(markerPath); } catch {}
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
const cur = readJsonSafe(CURSOR_FILE, {});
|
|
482
|
-
if (cur.roomOffset !== undefined) {
|
|
483
|
-
delete cur.roomOffset;
|
|
484
|
-
writeJsonAtomic(CURSOR_FILE, cur);
|
|
485
|
-
}
|
|
486
|
-
say(A.dim("→ room wiped"));
|
|
543
|
+
// Remove the kicked agent's inbox + cursor so they don't sit orphaned in
|
|
544
|
+
// ~/agent-coord/ taking up listing space and confusing future bookkeeping.
|
|
545
|
+
const inboxPath = path.join(INBOX_DIR, `${sanitize(target)}.jsonl`);
|
|
546
|
+
const cursorPath = path.join(CURSOR_DIR, `${sanitize(target)}.json`);
|
|
547
|
+
try { if (existsSync(inboxPath)) unlinkSync(inboxPath); } catch {}
|
|
548
|
+
try { if (existsSync(cursorPath)) unlinkSync(cursorPath); } catch {}
|
|
549
|
+
say(A.dim(`→ kicked ${target} (registry, transport, inbox, cursor all cleared)`));
|
|
487
550
|
}
|
|
488
551
|
|
|
489
552
|
async function findInHistory(term) {
|