agent-coord-mcp 0.19.0 → 0.19.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/README.md +11 -1
- package/dist/server.js +127 -9
- package/dist/server.js.map +1 -1
- package/dist/store.js +33 -1
- package/dist/store.js.map +1 -1
- package/dist/tools/admin.js +24 -5
- package/dist/tools/admin.js.map +1 -1
- package/dist/tools/registry.js +69 -1
- package/dist/tools/registry.js.map +1 -1
- package/dist/tools/transport.js +97 -7
- package/dist/tools/transport.js.map +1 -1
- package/dist/tools/work.js +28 -8
- package/dist/tools/work.js.map +1 -1
- package/dist/work.js +36 -4
- package/dist/work.js.map +1 -1
- package/hooks/tmux-pusher.mjs +6 -0
- package/package.json +1 -1
- package/scripts/check-test-count.mjs +1 -1
- package/scripts/coord-pusher.mjs +39 -9
- package/src/server.ts +131 -9
- package/src/store.ts +45 -1
- package/src/tools/admin.ts +22 -5
- package/src/tools/registry.ts +96 -0
- package/src/tools/transport.ts +116 -6
- package/src/tools/work.ts +28 -7
- package/src/work.ts +64 -7
package/dist/tools/work.js
CHANGED
|
@@ -3,7 +3,7 @@ import { promises as fsp } from "node:fs";
|
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { z } from "zod";
|
|
5
5
|
import { WORK_DIR, workFile, readJson } from "../store.js";
|
|
6
|
-
import { boardRowsOf, doneEntriesOf, parseWorkDoc, queueItemsOf, renderWorkDoc, } from "../work.js";
|
|
6
|
+
import { boardRowsOf, doneEntriesOf, parseWorkDoc, queueItemsOf, renderWorkDoc, workDocIssues, } from "../work.js";
|
|
7
7
|
import { loadScopes, ownsDocument } from "./scopes.js";
|
|
8
8
|
import { AGENTS_FILE } from "../store.js";
|
|
9
9
|
// ---------- work state as data (Phase 8 Task 5) ----------
|
|
@@ -76,18 +76,28 @@ export async function importWorkTool(args) {
|
|
|
76
76
|
}
|
|
77
77
|
const state = { project: args.project, repo, importedAt: Date.now(), docs };
|
|
78
78
|
await saveState(state);
|
|
79
|
+
const allIssues = docs.flatMap((d) => workDocIssues(d.doc).map((issue) => `${d.path}: ${issue}`));
|
|
79
80
|
return {
|
|
80
81
|
ok: true,
|
|
81
82
|
project: args.project,
|
|
82
83
|
repo,
|
|
83
84
|
file: workFile(args.project),
|
|
84
|
-
imported: docs.map((d) =>
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
85
|
+
imported: docs.map((d) => {
|
|
86
|
+
const issues = workDocIssues(d.doc);
|
|
87
|
+
return {
|
|
88
|
+
path: d.path,
|
|
89
|
+
kind: d.kind,
|
|
90
|
+
queue: queueItemsOf(d.doc).length,
|
|
91
|
+
done: doneEntriesOf(d.doc).length,
|
|
92
|
+
board: boardRowsOf(d.doc).length,
|
|
93
|
+
...(issues.length ? { issues } : {}),
|
|
94
|
+
};
|
|
95
|
+
}),
|
|
96
|
+
...(allIssues.length
|
|
97
|
+
? {
|
|
98
|
+
warning: `${allIssues.length} table row(s) were refused a record (wrong column count) and kept verbatim — the documents round-trip unchanged, but these rows are invisible to board consumers until fixed. See imported[].issues.`,
|
|
99
|
+
}
|
|
100
|
+
: {}),
|
|
91
101
|
note: "the markdown remains authoritative — this store is a derived index",
|
|
92
102
|
};
|
|
93
103
|
}
|
|
@@ -117,10 +127,12 @@ export async function listWorkTool(args) {
|
|
|
117
127
|
const queue = [];
|
|
118
128
|
const done = [];
|
|
119
129
|
const board = [];
|
|
130
|
+
const issues = [];
|
|
120
131
|
for (const d of state.docs) {
|
|
121
132
|
queue.push(...queueItemsOf(d.doc));
|
|
122
133
|
done.push(...doneEntriesOf(d.doc));
|
|
123
134
|
board.push(...boardRowsOf(d.doc));
|
|
135
|
+
issues.push(...workDocIssues(d.doc).map((issue) => `${d.path}: ${issue}`));
|
|
124
136
|
}
|
|
125
137
|
const openQueue = args.includeDone ? queue : queue.filter((q) => !q.done);
|
|
126
138
|
const filtered = args.priority ? openQueue.filter((q) => q.priority === args.priority) : openQueue;
|
|
@@ -132,6 +144,9 @@ export async function listWorkTool(args) {
|
|
|
132
144
|
...(args.kind === "queue" || args.kind === undefined ? { queue: filtered } : {}),
|
|
133
145
|
...(args.kind === "done" || args.kind === undefined ? { done } : {}),
|
|
134
146
|
...(args.kind === "board" || args.kind === undefined ? { board } : {}),
|
|
147
|
+
// A row refused for wrong arity is absent from `board` — say so rather
|
|
148
|
+
// than let the absence read as "that lane doesn't exist".
|
|
149
|
+
...(issues.length ? { issues } : {}),
|
|
135
150
|
};
|
|
136
151
|
}
|
|
137
152
|
// Parse the documents without persisting — used by the list fallback so a
|
|
@@ -189,11 +204,16 @@ export async function exportWorkTool(args) {
|
|
|
189
204
|
: undefined;
|
|
190
205
|
if (write && rendered !== current)
|
|
191
206
|
await fsp.writeFile(target, rendered, "utf8");
|
|
207
|
+
const issues = workDocIssues(d.doc);
|
|
192
208
|
files.push({
|
|
193
209
|
path: d.path,
|
|
194
210
|
bytes: Buffer.byteLength(rendered, "utf8"),
|
|
195
211
|
identical: rendered === current,
|
|
196
212
|
written: write && rendered !== current,
|
|
213
|
+
// Refused rows replay verbatim — the write is byte-faithful — but a
|
|
214
|
+
// caller rewriting a document should hear that some rows carry no
|
|
215
|
+
// record, rather than infer health from `identical:true`.
|
|
216
|
+
...(issues.length ? { issues } : {}),
|
|
197
217
|
...(scope ? { scope } : {}),
|
|
198
218
|
});
|
|
199
219
|
}
|
package/dist/tools/work.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"work.js","sourceRoot":"","sources":["../../src/tools/work.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"work.js","sourceRoot":"","sources":["../../src/tools/work.ts"],"names":[],"mappings":"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"}
|
package/dist/work.js
CHANGED
|
@@ -20,6 +20,13 @@
|
|
|
20
20
|
// replayed in place. Only lines it genuinely understands are re-rendered, so
|
|
21
21
|
// an unmodelled construct can never be silently dropped.
|
|
22
22
|
import { createHash } from "node:crypto";
|
|
23
|
+
// The one arity BoardRow can hold. boardCells() and the parser's arity guard
|
|
24
|
+
// both reference this constant so the two sides cannot drift; a test pins
|
|
25
|
+
// boardCells().length === BOARD_ARITY.
|
|
26
|
+
export const BOARD_ARITY = 5;
|
|
27
|
+
export function isMalformedRow(r) {
|
|
28
|
+
return r.malformed === true;
|
|
29
|
+
}
|
|
23
30
|
// ---------- the glyph contract ----------
|
|
24
31
|
//
|
|
25
32
|
// Pinned in docs/DONE.md and consumed by external parsers: the ref splits on
|
|
@@ -116,11 +123,14 @@ function boardCells(r) {
|
|
|
116
123
|
return [r.lane, r.owner, r.state, r.currentSlice, r.nextGo];
|
|
117
124
|
}
|
|
118
125
|
// Replay the original line when the fields still say what it said; re-render
|
|
119
|
-
// once anything actually changed.
|
|
126
|
+
// once anything actually changed. A malformed row has no fields to have
|
|
127
|
+
// changed — it replays its bytes, always.
|
|
120
128
|
export function renderBoardRow(r) {
|
|
129
|
+
if (isMalformedRow(r))
|
|
130
|
+
return r.verbatim;
|
|
121
131
|
if (r.raw !== undefined) {
|
|
122
132
|
const cells = splitRow(r.raw);
|
|
123
|
-
if (cells.length ===
|
|
133
|
+
if (cells.length === BOARD_ARITY && cells.every((c, i) => c === boardCells(r)[i]))
|
|
124
134
|
return r.raw;
|
|
125
135
|
}
|
|
126
136
|
return renderRow(boardCells(r));
|
|
@@ -216,7 +226,23 @@ export function parseWorkDoc(source) {
|
|
|
216
226
|
let j = i + 2;
|
|
217
227
|
for (; j < lines.length && TABLE_ROW.test(lines[j] ?? ""); j++) {
|
|
218
228
|
const raw = lines[j] ?? "";
|
|
219
|
-
const
|
|
229
|
+
const cells = splitRow(raw);
|
|
230
|
+
// Arity guard: a row BoardRow cannot hold is refused a record, kept
|
|
231
|
+
// verbatim, and named loudly — destructuring it into the 5-tuple is
|
|
232
|
+
// exactly the silent narrow/widen this exists to prevent. An empty
|
|
233
|
+
// trailing cell (`| a | b | c | d | |`) is still five columns and
|
|
234
|
+
// still a legitimate row.
|
|
235
|
+
if (cells.length !== BOARD_ARITY) {
|
|
236
|
+
rows.push({
|
|
237
|
+
malformed: true,
|
|
238
|
+
verbatim: raw,
|
|
239
|
+
issue: `board row at line ${j + 1} has ${cells.length} column(s), expected ${BOARD_ARITY} — ` +
|
|
240
|
+
`refused (kept verbatim, excluded from board records). Fix the row, or widen BoardRow ` +
|
|
241
|
+
`deliberately (BOARD_ARITY + boardCells + this guard together). Row: ${raw}`,
|
|
242
|
+
});
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
245
|
+
const [lane = "", owner = "", state = "", currentSlice = "", nextGo = ""] = cells;
|
|
220
246
|
rows.push({ id: idFor("b", lane), lane, owner, state, currentSlice, nextGo, raw });
|
|
221
247
|
}
|
|
222
248
|
flushText();
|
|
@@ -255,6 +281,12 @@ export function doneEntriesOf(doc) {
|
|
|
255
281
|
return doc.blocks.flatMap((b) => (b.kind === "done" ? b.entries : []));
|
|
256
282
|
}
|
|
257
283
|
export function boardRowsOf(doc) {
|
|
258
|
-
return doc.blocks.flatMap((b) =>
|
|
284
|
+
return doc.blocks.flatMap((b) => b.kind === "board" ? b.rows.filter((r) => !isMalformedRow(r)) : []);
|
|
285
|
+
}
|
|
286
|
+
// Every refused row's issue, in document order — what makes the parse-time
|
|
287
|
+
// rejection LOUD at the tool layer (import_work/list_work/export_work all
|
|
288
|
+
// surface it) instead of a filtered-out record nobody notices.
|
|
289
|
+
export function workDocIssues(doc) {
|
|
290
|
+
return doc.blocks.flatMap((b) => b.kind === "board" ? b.rows.filter(isMalformedRow).map((r) => r.issue) : []);
|
|
259
291
|
}
|
|
260
292
|
//# sourceMappingURL=work.js.map
|
package/dist/work.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"work.js","sourceRoot":"","sources":["../src/work.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"work.js","sourceRoot":"","sources":["../src/work.ts"],"names":[],"mappings":"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"}
|
package/hooks/tmux-pusher.mjs
CHANGED
|
@@ -461,6 +461,12 @@ function writeReceipts(msgs, outcome) {
|
|
|
461
461
|
ts: Date.now(),
|
|
462
462
|
from: m.from,
|
|
463
463
|
control: m.control === true,
|
|
464
|
+
// Build identity of the pusher that did the typing/verifying — the
|
|
465
|
+
// same module-graph stamp the transport marker carries (SCRIPT_MTIME
|
|
466
|
+
// covers hooks/*.mjs, not just this file). Lets deliveryOutcome note
|
|
467
|
+
// a "confirmed" issued by pre-upgrade verification logic. Omitted
|
|
468
|
+
// when unknown: absence reads as UNKNOWN downstream, never as fresh.
|
|
469
|
+
...(SCRIPT_MTIME !== undefined ? { scriptMtime: SCRIPT_MTIME } : {}),
|
|
464
470
|
...(outcome
|
|
465
471
|
? {
|
|
466
472
|
submitted: outcome.submitted === true,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-coord-mcp",
|
|
3
|
-
"version": "0.19.
|
|
3
|
+
"version": "0.19.1",
|
|
4
4
|
"description": "File-backed MCP server for coordinating multiple AI coding agents (Claude Code, Cursor, Cline, etc.). Local stdio or networked over Streamable HTTP.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
|
|
23
23
|
import { spawn } from "node:child_process";
|
|
24
24
|
|
|
25
|
-
const EXPECTED_TESTS =
|
|
25
|
+
const EXPECTED_TESTS = 262;
|
|
26
26
|
|
|
27
27
|
const expected = Number(process.env.AGENT_COORD_EXPECTED_TESTS ?? EXPECTED_TESTS);
|
|
28
28
|
// Same glob the suite always used — `--test test/` would recurse differently
|
package/scripts/coord-pusher.mjs
CHANGED
|
@@ -114,15 +114,41 @@ try {
|
|
|
114
114
|
} catch (e) {
|
|
115
115
|
die(`register failed: ${e?.message ?? e}`);
|
|
116
116
|
}
|
|
117
|
-
//
|
|
118
|
-
//
|
|
119
|
-
//
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
117
|
+
// Build identity of THIS pusher process: newest mtime across the entry file
|
|
118
|
+
// AND its ../hooks/*.mjs imports, sampled once at startup. The entry file
|
|
119
|
+
// alone is not enough — the paste/submit pipeline lives in hooks/submit.mjs,
|
|
120
|
+
// so a fix landing there alone would leave a single-file stamp unchanged and
|
|
121
|
+
// a still-running pusher on the old code would read as fresh (#28's lesson,
|
|
122
|
+
// carried across the wire). Over-covering hooks siblings we don't import is
|
|
123
|
+
// the safe direction: a spurious stale flag is loud and cheap, a false fresh
|
|
124
|
+
// silently invalidates rollout verification. Stamped on the transport marker
|
|
125
|
+
// AND on every receipt this process reports; undefined on failure — an
|
|
126
|
+
// absent stamp reads as UNKNOWN downstream, never as fresh, and a partial
|
|
127
|
+
// (entry-only) value could read fresh while submit.mjs is exactly the stale
|
|
128
|
+
// part.
|
|
129
|
+
const scriptMtime = await (async () => {
|
|
130
|
+
try {
|
|
131
|
+
const { statSync, readdirSync } = await import("node:fs");
|
|
132
|
+
const { fileURLToPath } = await import("node:url");
|
|
133
|
+
const path = await import("node:path");
|
|
134
|
+
const self = fileURLToPath(import.meta.url);
|
|
135
|
+
let newest = statSync(self).mtimeMs;
|
|
136
|
+
const hooksDir = path.join(path.dirname(self), "..", "hooks");
|
|
137
|
+
for (const f of readdirSync(hooksDir)) {
|
|
138
|
+
if (!f.endsWith(".mjs")) continue;
|
|
139
|
+
let m;
|
|
140
|
+
try {
|
|
141
|
+
m = statSync(path.join(hooksDir, f)).mtimeMs;
|
|
142
|
+
} catch {
|
|
143
|
+
continue; // deleted mid-scan
|
|
144
|
+
}
|
|
145
|
+
if (m > newest) newest = m;
|
|
146
|
+
}
|
|
147
|
+
return newest;
|
|
148
|
+
} catch {
|
|
149
|
+
return undefined; // non-fatal — absence stays honest
|
|
150
|
+
}
|
|
151
|
+
})();
|
|
126
152
|
try {
|
|
127
153
|
await call(
|
|
128
154
|
"report_transport",
|
|
@@ -323,6 +349,10 @@ async function reportReceipts(msgs, outcome) {
|
|
|
323
349
|
id: m.id,
|
|
324
350
|
...(m.from !== undefined ? { from: m.from } : {}),
|
|
325
351
|
control: m.control === true,
|
|
352
|
+
// Our build identity (module-graph mtime, see the startup stamp) —
|
|
353
|
+
// ties this receipt to the code that typed/verified the delivery.
|
|
354
|
+
// Omitted when unknown; the server must not default it.
|
|
355
|
+
...(scriptMtime !== undefined ? { scriptMtime } : {}),
|
|
326
356
|
...(outcome
|
|
327
357
|
? {
|
|
328
358
|
submitted: outcome.submitted === true,
|
package/src/server.ts
CHANGED
|
@@ -4,8 +4,16 @@ import { createServer, IncomingMessage, ServerResponse } from "node:http";
|
|
|
4
4
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5
5
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
6
|
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
7
|
-
import {
|
|
7
|
+
import { unlinkSync, writeFileSync } from "node:fs";
|
|
8
8
|
import {
|
|
9
|
+
ensureDirs,
|
|
10
|
+
getTokenMap,
|
|
11
|
+
reloadTokenMapSync,
|
|
12
|
+
sessionFile,
|
|
13
|
+
type SessionBinding,
|
|
14
|
+
} from "./store.js";
|
|
15
|
+
import {
|
|
16
|
+
liveClaimEvidence,
|
|
9
17
|
attachAgentSchema,
|
|
10
18
|
attachAgentTool,
|
|
11
19
|
clearTransportSchema,
|
|
@@ -95,8 +103,103 @@ function jsonResult(data: unknown) {
|
|
|
95
103
|
// switching (the PR #45 spoof shape) is rejected.
|
|
96
104
|
// - rename_agent updates the binding to the new id on success so the
|
|
97
105
|
// renamed session keeps working.
|
|
98
|
-
|
|
106
|
+
// - First-claim guard (v0.20.0): TOFU no longer lets a fresh session claim
|
|
107
|
+
// an id that is currently LIVE on the bus (fresh heartbeat, live
|
|
108
|
+
// transport, or another live bound session) — that silently created a
|
|
109
|
+
// second session acting as an already-running agent (hit live 2026-07-06:
|
|
110
|
+
// a dev session bound itself to `disavow-liaison`). A live-id claim needs
|
|
111
|
+
// the agent's token or an explicit force (join/register params). See
|
|
112
|
+
// guardFirstClaim for how absent vs unreadable evidence is decided.
|
|
113
|
+
// - `trackSession` (stdio only): each successful bind writes a
|
|
114
|
+
// sessions/<id>.<pid>.<nonce>.json marker so doctor can SEE two live
|
|
115
|
+
// sessions bound to one id — closure state alone cannot be inspected
|
|
116
|
+
// from outside the process. Not tracked for HTTP sessions: tokens.json
|
|
117
|
+
// already enforces their identity and many share one pid, which would
|
|
118
|
+
// make pid-liveness meaningless.
|
|
119
|
+
function buildServer(initialBound?: string, opts: { trackSession?: boolean } = {}): McpServer {
|
|
99
120
|
let bound = initialBound;
|
|
121
|
+
const trackSession = opts.trackSession ?? false;
|
|
122
|
+
let sessionMarker: string | undefined;
|
|
123
|
+
let exitHooksInstalled = false;
|
|
124
|
+
|
|
125
|
+
// Best-effort: a marker left behind by SIGKILL has a dead pid, which both
|
|
126
|
+
// the guard's evidence read and doctor's duplicate-session-binding check
|
|
127
|
+
// treat as garbage (doctor fix deletes it).
|
|
128
|
+
function recordSessionBinding(agentId: string, via: string): void {
|
|
129
|
+
if (!trackSession) return;
|
|
130
|
+
try {
|
|
131
|
+
const file = sessionFile(agentId, process.pid, randomUUID().slice(0, 8));
|
|
132
|
+
const marker: SessionBinding = {
|
|
133
|
+
agentId,
|
|
134
|
+
pid: process.pid,
|
|
135
|
+
boundAt: Date.now(),
|
|
136
|
+
via,
|
|
137
|
+
...(process.env.TMUX_PANE ? { tmuxPane: process.env.TMUX_PANE } : {}),
|
|
138
|
+
};
|
|
139
|
+
writeFileSync(file, JSON.stringify(marker, null, 2) + "\n");
|
|
140
|
+
if (sessionMarker) {
|
|
141
|
+
try { unlinkSync(sessionMarker); } catch { /* already gone */ }
|
|
142
|
+
}
|
|
143
|
+
sessionMarker = file;
|
|
144
|
+
if (!exitHooksInstalled) {
|
|
145
|
+
exitHooksInstalled = true;
|
|
146
|
+
const cleanup = () => {
|
|
147
|
+
try { if (sessionMarker) unlinkSync(sessionMarker); } catch { /* already gone */ }
|
|
148
|
+
};
|
|
149
|
+
process.on("exit", cleanup);
|
|
150
|
+
// Default signal death skips 'exit' handlers; SIGHUP stays reserved
|
|
151
|
+
// for the token-map reload in loadTokenMap.
|
|
152
|
+
for (const sig of ["SIGTERM", "SIGINT"] as const) {
|
|
153
|
+
process.on(sig, () => { cleanup(); process.exit(0); });
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
} catch { /* marker is observability, never worth failing the bind */ }
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Decide whether a fresh session may claim `claimed` as its identity, and
|
|
160
|
+
// how. Returns the bind provenance ("tofu" | "token" | "force" |
|
|
161
|
+
// "same-pane") or throws. Ordering is deliberate:
|
|
162
|
+
// - a presented token must MATCH or the claim fails loudly, even when the
|
|
163
|
+
// id is not live — a wrong credential silently succeeding via the
|
|
164
|
+
// not-live path would teach callers that garbage tokens work;
|
|
165
|
+
// - force is an explicit human/agent decision, honored before evidence;
|
|
166
|
+
// - evidence that exists but cannot be read REFUSES (cannot-verify ≠
|
|
167
|
+
// verified-absent; unreadable state must not disable the guard);
|
|
168
|
+
// - a live id refuses, except when its live pusher types into THIS
|
|
169
|
+
// process's own tmux pane — two sessions cannot share a pane, so that
|
|
170
|
+
// is the same seat restarting (the routine fleet-restart case), not a
|
|
171
|
+
// second session. The exception never applies when another live
|
|
172
|
+
// session is already bound to the id.
|
|
173
|
+
// - verified-not-live binds freely: refusing absent evidence would break
|
|
174
|
+
// every first onboarding, and the guard exists to protect LIVE ids.
|
|
175
|
+
async function guardFirstClaim(claimed: string, args: Record<string, unknown>): Promise<string> {
|
|
176
|
+
const token = typeof args["token"] === "string" ? (args["token"] as string) : undefined;
|
|
177
|
+
if (token !== undefined) {
|
|
178
|
+
if (getTokenMap()?.get(token) === claimed) return "token";
|
|
179
|
+
throw new Error(
|
|
180
|
+
`token presented for '${claimed}' does not match tokens.json (or no token map is loaded). ` +
|
|
181
|
+
`Mint one with scripts/coord-token.mjs add ${claimed} (then SIGHUP the bus), or pass force:true if you are certain.`,
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
if (args["force"] === true) return "force";
|
|
185
|
+
const ev = await liveClaimEvidence(claimed, Date.now());
|
|
186
|
+
if (!ev.verifiable) {
|
|
187
|
+
throw new Error(
|
|
188
|
+
`cannot verify whether '${claimed}' is live: ${ev.reasons.join("; ")}. ` +
|
|
189
|
+
`Refusing to bind rather than treating unreadable evidence as absence. ` +
|
|
190
|
+
`Repair the state (doctor), or pass the agent's token or force:true (join/register).`,
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
if (ev.live) {
|
|
194
|
+
if (ev.samePane && ev.boundElsewhere === 0) return "same-pane";
|
|
195
|
+
throw new Error(
|
|
196
|
+
`agent '${claimed}' is live on this bus (${ev.reasons.join("; ")}) — refusing to bind this fresh session to it. ` +
|
|
197
|
+
`If you ARE '${claimed}' restarting, re-join from its tmux pane, or pass its token or force:true (join/register). ` +
|
|
198
|
+
`If you are diagnosing, use status/ping (read-only, they never bind) or your own id.`,
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
return "tofu";
|
|
202
|
+
}
|
|
100
203
|
|
|
101
204
|
// Gate every tool that takes a caller identity. `field: null` (list_agents,
|
|
102
205
|
// list_rooms, prune) bypasses the check entirely.
|
|
@@ -117,7 +220,12 @@ function buildServer(initialBound?: string): McpServer {
|
|
|
117
220
|
if (typeof claimed === "string") {
|
|
118
221
|
if (bound === undefined) {
|
|
119
222
|
if (bindOnClaim) {
|
|
120
|
-
|
|
223
|
+
// TOFU: first claim wins, then sticky — but only after the
|
|
224
|
+
// first-claim guard agrees the id isn't someone else's live
|
|
225
|
+
// session (see guardFirstClaim).
|
|
226
|
+
const via = await guardFirstClaim(claimed, args);
|
|
227
|
+
bound = claimed;
|
|
228
|
+
recordSessionBinding(claimed, via);
|
|
121
229
|
}
|
|
122
230
|
} else if (bound !== claimed) {
|
|
123
231
|
throw new Error(
|
|
@@ -137,7 +245,7 @@ function buildServer(initialBound?: string): McpServer {
|
|
|
137
245
|
|
|
138
246
|
server.tool(
|
|
139
247
|
"join",
|
|
140
|
-
"Recommended session-start call. Does register + auto-attach (if running inside tmux) + read inbox in one round-trip. Pass attach=false to skip the transport, attach={...overrides} to customize, or omit it to let the server auto-detect $TMUX_PANE. Returns the registration, attach result, any unread inbox messages, and the default channel's topic + MOTD (room rules) so you see them on connect. Calling join binds this MCP process's identity to agentId for the lifetime of the session — no env var or config needed. Each Claude Code session runs its own stdio process so bindings are naturally isolated.",
|
|
248
|
+
"Recommended session-start call. Does register + auto-attach (if running inside tmux) + read inbox in one round-trip. Pass attach=false to skip the transport, attach={...overrides} to customize, or omit it to let the server auto-detect $TMUX_PANE. Returns the registration, attach result, any unread inbox messages, and the default channel's topic + MOTD (room rules) so you see them on connect. Calling join binds this MCP process's identity to agentId for the lifetime of the session — no env var or config needed. Each Claude Code session runs its own stdio process so bindings are naturally isolated. Claiming an id that is currently LIVE on the bus (fresh heartbeat, live pusher, or another bound session) is refused unless the claim comes from that agent's own tmux pane or carries the agent's token or force:true — diagnosing someone else's agent is what status/ping are for.",
|
|
141
249
|
joinSchema,
|
|
142
250
|
// join explicitly sets the session binding when unset, so each agent can
|
|
143
251
|
// declare its identity via join rather than relying on env vars.
|
|
@@ -145,7 +253,9 @@ function buildServer(initialBound?: string): McpServer {
|
|
|
145
253
|
const claimed = args["agentId"];
|
|
146
254
|
if (typeof claimed === "string") {
|
|
147
255
|
if (bound === undefined) {
|
|
256
|
+
const via = await guardFirstClaim(claimed, args);
|
|
148
257
|
bound = claimed;
|
|
258
|
+
recordSessionBinding(claimed, via);
|
|
149
259
|
} else if (bound !== claimed) {
|
|
150
260
|
throw new Error(
|
|
151
261
|
`identity bound to '${bound}'; rejected attempt to act as '${claimed}'`,
|
|
@@ -249,7 +359,7 @@ function buildServer(initialBound?: string): McpServer {
|
|
|
249
359
|
|
|
250
360
|
server.tool(
|
|
251
361
|
"prune",
|
|
252
|
-
"Trim room/status/inbox JSONL to entries newer than `olderThanDays` (default 7); kind='decision' posts keep a longer `decisionDays` retention (default 30). Nothing is lost: aged-out entries are archived under archive/ (rooms/<chan>.jsonl, status.jsonl, inbox/<agent>.jsonl) — only receipts are truly deleted.
|
|
362
|
+
"Trim room/status/inbox JSONL to entries newer than `olderThanDays` (default 7); kind='decision' posts keep a longer `decisionDays` retention (default 30). Nothing is lost: aged-out entries are archived under archive/ (rooms/<chan>.jsonl, status.jsonl, inbox/<agent>.jsonl) — only receipts are truly deleted. `room` and `targets` compose: `room` scopes every sweep to that channel (and, alone, defaults the sweep to `rooms` only), while `targets` (rooms|status|inbox|receipts|members) selects which sweeps run and always wins over that default — so `{room, targets:['members']}` sweeps membership in that one channel. Sweeps room members that are unregistered or haven't heartbeated since the cutoff, and archives+removes non-default rooms left empty and inactive (disable via archiveEmptyRooms=false). Removes inbox files for agents no longer in the registry unless removeOrphanInboxes=false. Pass dryRun=true to preview.",
|
|
253
363
|
pruneSchema,
|
|
254
364
|
gate(null, pruneTool as (a: Record<string, unknown>) => Promise<unknown>),
|
|
255
365
|
);
|
|
@@ -306,15 +416,23 @@ function buildServer(initialBound?: string): McpServer {
|
|
|
306
416
|
async (args: Record<string, unknown>) => {
|
|
307
417
|
const claimed = args.agentId;
|
|
308
418
|
if (typeof claimed === "string") {
|
|
309
|
-
if (bound === undefined)
|
|
310
|
-
|
|
419
|
+
if (bound === undefined) {
|
|
420
|
+
// Renaming a live agent from a fresh session is still a first
|
|
421
|
+
// claim of that agent's identity — same guard as any other.
|
|
422
|
+
const via = await guardFirstClaim(claimed, args);
|
|
423
|
+
bound = claimed;
|
|
424
|
+
recordSessionBinding(claimed, via);
|
|
425
|
+
} else if (bound !== claimed) {
|
|
311
426
|
throw new Error(`identity bound to '${bound}'; rejected attempt to act as '${claimed}'`);
|
|
312
427
|
}
|
|
313
428
|
}
|
|
314
429
|
const result = await renameAgentTool(args as { agentId: string; newAgentId: string });
|
|
315
430
|
if (result && typeof result === "object" && (result as { ok?: unknown }).ok === true) {
|
|
316
431
|
const to = (result as { to?: unknown }).to;
|
|
317
|
-
if (typeof to === "string")
|
|
432
|
+
if (typeof to === "string") {
|
|
433
|
+
bound = to;
|
|
434
|
+
recordSessionBinding(to, "rename");
|
|
435
|
+
}
|
|
318
436
|
}
|
|
319
437
|
return jsonResult(result);
|
|
320
438
|
},
|
|
@@ -404,6 +522,10 @@ function buildServer(initialBound?: string): McpServer {
|
|
|
404
522
|
gate(null, forceUnregisterTool as (a: Record<string, unknown>) => Promise<unknown>),
|
|
405
523
|
);
|
|
406
524
|
|
|
525
|
+
// An env pre-bound session is just as live as a TOFU-bound one — record it
|
|
526
|
+
// so doctor's duplicate check sees it too. (No-op unless trackSession.)
|
|
527
|
+
if (initialBound) recordSessionBinding(initialBound, "env");
|
|
528
|
+
|
|
407
529
|
return server;
|
|
408
530
|
}
|
|
409
531
|
|
|
@@ -452,7 +574,7 @@ async function main() {
|
|
|
452
574
|
" unregister before restarting so the new name starts fresh.",
|
|
453
575
|
);
|
|
454
576
|
}
|
|
455
|
-
const server = buildServer(boundAgent);
|
|
577
|
+
const server = buildServer(boundAgent, { trackSession: true });
|
|
456
578
|
const transport = new StdioServerTransport();
|
|
457
579
|
await server.connect(transport);
|
|
458
580
|
}
|
package/src/store.ts
CHANGED
|
@@ -55,6 +55,37 @@ export const ARCHIVE_ROOMS_DIR = path.join(ARCHIVE_DIR, "rooms");
|
|
|
55
55
|
export const ARCHIVE_INBOX_DIR = path.join(ARCHIVE_DIR, "inbox");
|
|
56
56
|
export const ARCHIVE_STATUS_FILE = path.join(ARCHIVE_DIR, "status.jsonl");
|
|
57
57
|
|
|
58
|
+
// Live session-binding markers (v0.20.0). One small file per *bound* stdio MCP
|
|
59
|
+
// session: which agentId the session claimed, which pid holds it, and how the
|
|
60
|
+
// bind was established. Written at bind time, removed on clean exit; a file
|
|
61
|
+
// whose pid is dead is garbage doctor can clean. This is what makes two live
|
|
62
|
+
// sessions bound to the same id VISIBLE (doctor `duplicate-session-binding`)
|
|
63
|
+
// — in-process closure state can't be, by definition. HTTP sessions are not
|
|
64
|
+
// tracked here: with tokens.json they are already identity-enforced, and many
|
|
65
|
+
// share one pid, so pid-liveness would be meaningless for them.
|
|
66
|
+
export const SESSIONS_DIR = path.join(ROOT, "sessions");
|
|
67
|
+
|
|
68
|
+
export type SessionBinding = {
|
|
69
|
+
agentId: string;
|
|
70
|
+
pid: number;
|
|
71
|
+
boundAt: number;
|
|
72
|
+
// How the bind was established: "tofu" (first claim, id verified not live),
|
|
73
|
+
// "env" (AGENT_COORD_BOUND_AGENT), "token", "force", "same-pane" (live
|
|
74
|
+
// marker types into this session's own tmux pane), "rename".
|
|
75
|
+
via: string;
|
|
76
|
+
tmuxPane?: string;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export function sessionFile(agentId: string, pid: number, nonce: string): string {
|
|
80
|
+
return path.join(SESSIONS_DIR, `${sanitize(agentId)}.${pid}.${nonce}.json`);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export async function listSessionFiles(): Promise<string[]> {
|
|
84
|
+
if (!existsSync(SESSIONS_DIR)) return [];
|
|
85
|
+
const names = await fs.readdir(SESSIONS_DIR);
|
|
86
|
+
return names.filter((n) => n.endsWith(".json")).map((n) => path.join(SESSIONS_DIR, n));
|
|
87
|
+
}
|
|
88
|
+
|
|
58
89
|
// Per-agent token map for identity-bound bus auth (v0.7.0). Shape on disk:
|
|
59
90
|
// { "alice": "tk_<random-secret>", "bob": "tk_<another-secret>" }
|
|
60
91
|
// HTTP transport reverse-looks-up the bearer to bind the session to an
|
|
@@ -82,7 +113,7 @@ export function workFile(project: string): string {
|
|
|
82
113
|
}
|
|
83
114
|
|
|
84
115
|
export function ensureDirs(): void {
|
|
85
|
-
for (const d of [ROOT, INBOX_DIR, CURSOR_DIR, TRANSPORT_DIR, PID_DIR, LOG_DIR, ROOMS_DIR, RECEIPTS_DIR, HISTORY_DIR, WORK_DIR]) {
|
|
116
|
+
for (const d of [ROOT, INBOX_DIR, CURSOR_DIR, TRANSPORT_DIR, PID_DIR, LOG_DIR, ROOMS_DIR, RECEIPTS_DIR, HISTORY_DIR, WORK_DIR, SESSIONS_DIR]) {
|
|
86
117
|
if (!existsSync(d)) mkdirSync(d, { recursive: true });
|
|
87
118
|
}
|
|
88
119
|
for (const f of [ROOM_FILE, STATUS_FILE]) {
|
|
@@ -330,6 +361,19 @@ export async function readJson<T>(file: string, fallback: T): Promise<T> {
|
|
|
330
361
|
}
|
|
331
362
|
}
|
|
332
363
|
|
|
364
|
+
// Like readJson, but a file that EXISTS and cannot be parsed THROWS instead of
|
|
365
|
+
// silently returning the fallback. For callers whose decision flips on
|
|
366
|
+
// "verified absent" vs "cannot verify": the first-claim binding guard must
|
|
367
|
+
// refuse when evidence is unreadable, because a guard that treats unreadable
|
|
368
|
+
// evidence as absent is disabled by the very corruption it should be
|
|
369
|
+
// reporting (the absence-is-not-exemption class, #36).
|
|
370
|
+
export async function readJsonStrict<T>(file: string, fallback: T): Promise<T> {
|
|
371
|
+
if (!existsSync(file)) return fallback;
|
|
372
|
+
const raw = await fs.readFile(file, "utf8");
|
|
373
|
+
if (!raw.trim()) return fallback;
|
|
374
|
+
return JSON.parse(raw) as T;
|
|
375
|
+
}
|
|
376
|
+
|
|
333
377
|
export async function writeJson(file: string, data: unknown): Promise<void> {
|
|
334
378
|
await withLock(file, async () => {
|
|
335
379
|
await fs.writeFile(file, JSON.stringify(data, null, 2), "utf8");
|