agent-coord-mcp 0.17.0 → 0.18.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/README.md +34 -5
- package/dist/build.js +113 -0
- package/dist/build.js.map +1 -0
- package/dist/roles.js +92 -0
- package/dist/roles.js.map +1 -0
- package/dist/server.js +30 -14
- package/dist/server.js.map +1 -1
- package/dist/store.js +54 -1
- package/dist/store.js.map +1 -1
- package/dist/tools/admin.js +5 -3
- package/dist/tools/admin.js.map +1 -1
- package/dist/tools/index.js +2 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/messaging.js +187 -8
- package/dist/tools/messaging.js.map +1 -1
- package/dist/tools/registry.js +54 -3
- package/dist/tools/registry.js.map +1 -1
- package/dist/tools/render.js +84 -0
- package/dist/tools/render.js.map +1 -0
- package/dist/tools/scopes.js +126 -0
- package/dist/tools/scopes.js.map +1 -0
- package/dist/tools/shared.js +18 -0
- package/dist/tools/shared.js.map +1 -1
- package/dist/tools/transport.js +367 -33
- package/dist/tools/transport.js.map +1 -1
- package/dist/tools/work.js +209 -0
- package/dist/tools/work.js.map +1 -0
- package/dist/work.js +260 -0
- package/dist/work.js.map +1 -0
- package/hooks/marker.mjs +18 -0
- package/hooks/roles.mjs +79 -0
- package/hooks/submit.mjs +271 -0
- package/hooks/tier.mjs +104 -11
- package/hooks/tmux-pusher.mjs +137 -51
- package/package.json +5 -4
- package/scripts/check-self-dependency.mjs +42 -0
- package/scripts/check-test-count.mjs +83 -0
- package/scripts/coord-pusher.mjs +150 -33
- package/src/build.ts +111 -0
- package/src/roles.ts +111 -0
- package/src/server.ts +79 -14
- package/src/store.ts +60 -1
- package/src/tools/admin.ts +10 -4
- package/src/tools/index.ts +2 -0
- package/src/tools/messaging.ts +206 -7
- package/src/tools/registry.ts +63 -4
- package/src/tools/render.ts +80 -0
- package/src/tools/scopes.ts +177 -0
- package/src/tools/shared.ts +120 -0
- package/src/tools/transport.ts +386 -34
- package/src/tools/work.ts +265 -0
- package/src/work.ts +329 -0
package/README.md
CHANGED
|
@@ -84,7 +84,11 @@ If you're building an agent with the official MCP SDKs (`@modelcontextprotocol/s
|
|
|
84
84
|
| `report_transport({agentId, transport, host?, tmuxTarget?, since?})` | Publish a transport marker for an agent. Used by the **remote** pusher (`coord-pusher`, see [Remote agents](#remote-agents-streamable-http)) to surface itself in `list_agents`. Local tmux push uses `attach_agent` instead. |
|
|
85
85
|
| `clear_transport({agentId})` | Idempotent delete of an agent's transport marker — wire-callable counterpart to `detach_agent` for the remote pusher. Removes the marker only; nothing local to kill. |
|
|
86
86
|
| `prune({olderThanDays?, decisionDays?, room?, targets?, archiveEmptyRooms?, removeOrphanInboxes?, dryRun?})` | Archive room/status/inbox entries older than N days (default 7; decisions 30) to `archive/` — nothing is deleted except receipts. Scope with `room` or `targets`. Sweeps unregistered *and* heartbeat-stale members, archives empty inactive rooms. Pass `dryRun:true` to preview. |
|
|
87
|
-
| `
|
|
87
|
+
| `list_scopes({path?, agentId?})` | Read the declared write scopes for managed documents (`~/agent-coord/scopes.json`). With `path` (+ your `agentId`) it answers *"may I write this?"* before you edit a shared doc; bare, it lists every declared document and its owning role. **Advisory** — the bus does not mediate file writes, so this reports ownership and `doctor` detects drift after the fact; nothing is prevented. Absent `scopes.json` → nothing owned, nothing warns (opt-in). |
|
|
88
|
+
| `import_work({project, repo?})` | Read a project's work documents (`docs/QUEUE.md` + `docs/DONE.md`, or the legacy `docs/BACKLOG.md`, plus `docs/WORKSTREAMS.md`) into typed records — queue items `{priority,text,done}`, done entries `{text,ref,date}`, board rows. The markdown stays authoritative; the store is a derived index. |
|
|
89
|
+
| `list_work({project, kind?, priority?, includeDone?, repo?})` | Query work state as records instead of parsing markdown. Falls back to reading the documents directly when nothing has been imported, so it works with no store at all. |
|
|
90
|
+
| `export_work({project, write?, repo?, agentId?})` | Render the documents back out of the store, reproducing the pinned glyph contract exactly (ref after the last ` — `, date after a trailing ` · `). Reports by default; `write:true` rewrites the files. Refuses to export from an empty store rather than blanking a document. A declared write scope is **reported, never enforced**. |
|
|
91
|
+
| `doctor({fix?, maxFileBytes?})` | Bus-wide health check — inspects the whole state dir for drift/leaks/corruption (orphan transport markers, **stale pusher daemons whose loaded code predates the on-disk script**, **a server process running pre-rebuild code and markers stamped by such a server — merging is not deploying**, orphan memberships, orphan inbox/cursor files, cursor offsets past EOF, malformed JSONL, stale agents, oversized files, stale locks, channel/registry mismatches, **documents whose last writer disagrees with their declared scope**, environment). Read-only by default; `fix:true` applies the safe, reversible repairs (malformed-line rewrites are backed up to `.bak`). `healthy:true` means the bus is internally consistent. |
|
|
88
92
|
|
|
89
93
|
## First session checklist
|
|
90
94
|
|
|
@@ -311,6 +315,7 @@ Under the hood: [`hooks/tmux-pusher.mjs`](./hooks/tmux-pusher.mjs) is the daemon
|
|
|
311
315
|
- The pusher pastes into the pane unconditionally. If you're typing in the same pane it will corrupt your buffer; if the agent is showing a `[y/n]` permission prompt, the message becomes the answer. Run the receiving agent in a pane you don't normally edit in.
|
|
312
316
|
- Untrusted peer messages become real prompts with full agent privileges. Use `--allowlist` to restrict who can talk to a given agent; the pusher also refuses anything starting with `/` to block injected slash commands — the sole exception being the locked `/clear` + `/compact` control commands sent via [`send_command`](#clearing-sub-agent-context-send_command).
|
|
313
317
|
- Bursts get coalesced (1s default) into a single paste so 5 rapid DMs become one prompt rather than five.
|
|
318
|
+
- **Never `pkill -f tmux-pusher.mjs`.** The pattern matches **every** pusher on the bus, not just yours — one agent's test-rig cleanup doing exactly that silently detached all four live agents at once (the panes stay alive; delivery just stops until each agent re-attaches). The pusher is spawned with its agentId in argv (`tmux-pusher.mjs --agent <id>`) precisely so a pattern kill can be scoped to one agent: `pkill -f "tmux-pusher.mjs --agent <id>"`. Better still, use `detach_agent({agentId})` — it SIGTERMs the exact pid from the transport marker.
|
|
314
319
|
|
|
315
320
|
### Clearing sub-agent context (`send_command`)
|
|
316
321
|
|
|
@@ -359,7 +364,7 @@ AGENT_COORD_DIR=~/agent-coord \
|
|
|
359
364
|
agent-coord-mcp
|
|
360
365
|
```
|
|
361
366
|
|
|
362
|
-
Defaults to `127.0.0.1`. To bind to a LAN address (Tailscale, WireGuard, etc.) set `AGENT_COORD_BIND=10.x.y.z`; the
|
|
367
|
+
Defaults to `127.0.0.1`. To bind to a LAN / overlay address (Tailscale, WireGuard, etc.) set `AGENT_COORD_BIND=10.x.y.z`; a non-loopback bind trips the fail-closed gate below — the server **refuses to start** (rather than warns) unless identity and transport are both secured. `GET /healthz` is unauthenticated (for reverse-proxy / orchestrator probes); everything else requires `Authorization: Bearer <token>`. TLS is out of scope — front with Caddy/nginx, or skip TLS entirely on a private overlay network.
|
|
363
368
|
|
|
364
369
|
The server can run as a long-lived daemon on one machine (the "host") while local agents on that host keep using stdio per-session; the two modes don't conflict — they're separate processes.
|
|
365
370
|
|
|
@@ -370,9 +375,31 @@ The server can run as a long-lived daemon on one machine (the "host") while loca
|
|
|
370
375
|
|
|
371
376
|
Mint the per-agent tokens with `coord-token` (below). Loopback binds are exempt from both checks, so single-host use needs no extra setup.
|
|
372
377
|
|
|
378
|
+
**Example — bind to a Tailscale IP.** Tailscale/WireGuard *is* the secured transport (WireGuard-encrypted), so `AGENT_COORD_INSECURE=1` is the correct acknowledgement here, not a hack. On the host, after minting at least one token (see [Identity binding](#identity-binding-v070)):
|
|
379
|
+
|
|
380
|
+
```bash
|
|
381
|
+
node scripts/coord-token.mjs add worker-2 # creates ~/agent-coord/tokens.json, prints the token
|
|
382
|
+
AGENT_COORD_HTTP_PORT=8765 \
|
|
383
|
+
AGENT_COORD_BIND=100.x.y.z \ # this host's Tailscale IP (`tailscale ip -4`)
|
|
384
|
+
AGENT_COORD_INSECURE=1 \ # ack: WireGuard is the encryption layer
|
|
385
|
+
node dist/server.js
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
Remote nodes then reach it at `http://100.x.y.z:8765/mcp`. Add or rotate tokens later without a restart: `coord-token add <id>` then `kill -HUP <bus-pid>` reloads the map. `GET http://100.x.y.z:8765/healthz` (no auth) is a quick reachability check from another tailnet device.
|
|
389
|
+
|
|
390
|
+
### Joining from another machine
|
|
391
|
+
|
|
392
|
+
A remote participant is just an **MCP client with a bearer token** — there is nothing to build or clone. What you need depends on how you connect:
|
|
393
|
+
|
|
394
|
+
- **Claude Code (or any MCP client that speaks HTTP): nothing to install.** The client already speaks MCP; a config entry (below) is the entire setup. You do *not* need this package on the client to use the tools.
|
|
395
|
+
- **Optional real-time push into a tmux pane:** install the package globally (`npm i -g agent-coord-mcp`) for the `coord-pusher` bin (the MCP SDK ships with it — no repo needed). See [`coord-pusher`](#coord-pusher--real-time-push-cross-machine) below. Without it you simply poll with `read_messages` / `wait_for_message`.
|
|
396
|
+
- **Operator-side tools** (`coord-token`, `coord-node.sh`) live in the repo and run on the **bus host**, not on a pure client. `coord-node.sh` is not a published bin, so a client without the repo can't (and needn't) run it.
|
|
397
|
+
|
|
398
|
+
> ⚠️ **Installing the package globally does not connect you to a remote bus.** The `agent-coord-mcp` bin is the *stdio server* — pointing a Claude config at it spins up a **separate, local, file-backed bus on your own machine**, not a connection to anyone else's. To join a networked bus you must add the **HTTP** entry below (with `"type": "http"` and a URL), never the stdio server.
|
|
399
|
+
|
|
373
400
|
### Point a Claude Code session at the remote server
|
|
374
401
|
|
|
375
|
-
In `~/.claude.json
|
|
402
|
+
In `~/.claude.json` (or a project `.mcp.json`) — the token must be the one minted for *this* agent's id; the bus enforces that the id you `join` as matches the token:
|
|
376
403
|
|
|
377
404
|
```json
|
|
378
405
|
{
|
|
@@ -380,12 +407,14 @@ In `~/.claude.json`:
|
|
|
380
407
|
"agent-coord": {
|
|
381
408
|
"type": "http",
|
|
382
409
|
"url": "http://host:8765/mcp",
|
|
383
|
-
"headers": { "Authorization": "Bearer <
|
|
410
|
+
"headers": { "Authorization": "Bearer <this-agent's-token>" }
|
|
384
411
|
}
|
|
385
412
|
}
|
|
386
413
|
}
|
|
387
414
|
```
|
|
388
415
|
|
|
416
|
+
Or via the CLI (no hand-editing): `claude mcp add --transport http --scope user agent-coord http://host:8765/mcp --header "Authorization: Bearer <token>"`.
|
|
417
|
+
|
|
389
418
|
Then `join({agentId:"me"})` and call any tool exactly as you would locally. `send_message`, `read_messages`, `wait_for_message`, `list_rooms`, `join_room`, etc. all work identically.
|
|
390
419
|
|
|
391
420
|
### `coord-node` — one-command onboarding (recommended)
|
|
@@ -464,7 +493,7 @@ Backward-compat: if `tokens.json` is absent, the legacy single shared `AGENT_COO
|
|
|
464
493
|
### Auth posture, briefly
|
|
465
494
|
|
|
466
495
|
- Threat model: misbehaving / buggy / compromised same-LAN cooperator can no longer assert another agent's identity. Not a hostile-attacker model (TLS + per-message signing is a separate, larger task).
|
|
467
|
-
- Don't bind to a public address without TLS.
|
|
496
|
+
- Don't bind to a public address without TLS. A non-loopback bind is refused outright unless per-agent tokens are configured **and** `AGENT_COORD_INSECURE=1` is set — and that acknowledgement is meant for a private overlay (Tailscale/WireGuard) or a TLS reverse proxy, not the open internet.
|
|
468
497
|
|
|
469
498
|
### Other clients
|
|
470
499
|
|
package/dist/build.js
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
// Build identity of the RUNNING server process.
|
|
2
|
+
//
|
|
3
|
+
// The principle is the #28 pusher-freshness fix carried one layer up: stamp
|
|
4
|
+
// what you LOADED at init, compare against what's on disk NOW, and resolve the
|
|
5
|
+
// measured artifact from the code that is actually executing
|
|
6
|
+
// (import.meta.url), never from configuration — the thing that measures must
|
|
7
|
+
// be the thing that ran. A server process outlives `npm run build`; without a
|
|
8
|
+
// load-time sample there is nothing truthful to compare the on-disk build to,
|
|
9
|
+
// and a server running pre-rebuild code stamps transport markers with logic
|
|
10
|
+
// the rebuild replaced (observed live 2026-07-29: post-#28 attach spawned a
|
|
11
|
+
// pusher with no `--agent` argv and a single-file freshness stamp, agreeing
|
|
12
|
+
// with the new on-disk check only by coincidence).
|
|
13
|
+
import { readdirSync, statSync, readFileSync } from "node:fs";
|
|
14
|
+
import path from "node:path";
|
|
15
|
+
import { fileURLToPath } from "node:url";
|
|
16
|
+
// Newest mtime (epoch ms) across every file under `dir` (recursive) whose
|
|
17
|
+
// name ends with one of `exts`. Returns undefined when the dir is missing or
|
|
18
|
+
// unreadable — callers skip their check rather than guess. Pure over its
|
|
19
|
+
// arguments so tests exercise it on temp trees instead of touching real
|
|
20
|
+
// sources (a utimes on a shared checkout flips every live pusher's freshness
|
|
21
|
+
// while the suite runs files in parallel).
|
|
22
|
+
export function newestMtimeUnder(dir, exts) {
|
|
23
|
+
try {
|
|
24
|
+
let newest;
|
|
25
|
+
for (const rel of readdirSync(dir, { recursive: true })) {
|
|
26
|
+
const name = String(rel);
|
|
27
|
+
if (!exts.some((e) => name.endsWith(e)))
|
|
28
|
+
continue;
|
|
29
|
+
let m;
|
|
30
|
+
try {
|
|
31
|
+
m = statSync(path.join(dir, name)).mtimeMs;
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
continue; // deleted mid-scan
|
|
35
|
+
}
|
|
36
|
+
if (newest === undefined || m > newest)
|
|
37
|
+
newest = m;
|
|
38
|
+
}
|
|
39
|
+
return newest;
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
// The dir this module was loaded FROM: dist/ in production, src/ under tsx.
|
|
46
|
+
// Either way it is the code actually running, which is the point.
|
|
47
|
+
export const BUILD_DIR = path.dirname(fileURLToPath(import.meta.url));
|
|
48
|
+
// .js for the compiled build, .ts for dev-mode (tsx src/server.ts) — both
|
|
49
|
+
// sides of every comparison use the same list, so the two modes are each
|
|
50
|
+
// self-consistent and can never be compared across.
|
|
51
|
+
const BUILD_EXTS = [".js", ".ts"];
|
|
52
|
+
// Sampled ONCE at module load: the newest mtime across the build this server
|
|
53
|
+
// process actually imported. A later `npm run build` rewrites dist/ under a
|
|
54
|
+
// still-running server; this value stays behind, which is exactly what
|
|
55
|
+
// doctor's server-build-drift check compares against.
|
|
56
|
+
export const SERVER_BUILD_MTIME = newestMtimeUnder(BUILD_DIR, BUILD_EXTS);
|
|
57
|
+
// The on-disk side of the comparison, statted fresh per call.
|
|
58
|
+
// AGENT_COORD_DIST_DIR is a test seam only: it redirects what doctor
|
|
59
|
+
// MEASURES so tests can stage a newer/older build in a temp dir — it never
|
|
60
|
+
// changes what the server loads.
|
|
61
|
+
export function onDiskBuildMtime() {
|
|
62
|
+
const dir = process.env.AGENT_COORD_DIST_DIR ?? BUILD_DIR;
|
|
63
|
+
return newestMtimeUnder(dir, BUILD_EXTS);
|
|
64
|
+
}
|
|
65
|
+
// The uncompiled side of the dist-behind-source comparison: newest mtime
|
|
66
|
+
// across src/**/*.ts, resolved as BUILD_DIR's sibling. undefined on a
|
|
67
|
+
// packaged install with no src/ (callers report "nothing to compare", never
|
|
68
|
+
// warn). Under tsx dev-mode BUILD_DIR *is* src/, so the comparison degrades
|
|
69
|
+
// to src-vs-src and reads ok — dev-mode has no build to fall behind.
|
|
70
|
+
// AGENT_COORD_SRC_DIR is the same test seam as AGENT_COORD_DIST_DIR:
|
|
71
|
+
// it redirects measurement only.
|
|
72
|
+
export function onDiskSourceMtime() {
|
|
73
|
+
const dir = process.env.AGENT_COORD_SRC_DIR ?? path.resolve(BUILD_DIR, "..", "src");
|
|
74
|
+
return newestMtimeUnder(dir, [".ts"]);
|
|
75
|
+
}
|
|
76
|
+
// Best-effort checkout identity, report-only: lets doctor NAME the build
|
|
77
|
+
// (`branch@sha` would be nicer, but HEAD's sha alone already makes
|
|
78
|
+
// mutable-checkout drift visible, which is all this claims). undefined when
|
|
79
|
+
// not a git checkout (npm install) — never an error.
|
|
80
|
+
export const SERVER_BUILD_SHA = (() => {
|
|
81
|
+
try {
|
|
82
|
+
let gitDir = path.resolve(BUILD_DIR, "..", ".git");
|
|
83
|
+
const st = statSync(gitDir);
|
|
84
|
+
if (st.isFile()) {
|
|
85
|
+
// A worktree's .git is a pointer file: "gitdir: <real dir>".
|
|
86
|
+
const ptr = readFileSync(gitDir, "utf8").trim();
|
|
87
|
+
if (!ptr.startsWith("gitdir:"))
|
|
88
|
+
return undefined;
|
|
89
|
+
gitDir = ptr.slice("gitdir:".length).trim();
|
|
90
|
+
}
|
|
91
|
+
const head = readFileSync(path.join(gitDir, "HEAD"), "utf8").trim();
|
|
92
|
+
if (!head.startsWith("ref:"))
|
|
93
|
+
return head.slice(0, 12); // detached
|
|
94
|
+
const ref = head.slice(4).trim();
|
|
95
|
+
try {
|
|
96
|
+
return readFileSync(path.join(gitDir, ref), "utf8").trim().slice(0, 12);
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
// Ref may be packed. commondir handling is deliberately out of scope —
|
|
100
|
+
// best-effort means undefined beats wrong.
|
|
101
|
+
const packed = readFileSync(path.join(gitDir, "packed-refs"), "utf8");
|
|
102
|
+
for (const line of packed.split("\n")) {
|
|
103
|
+
if (line.endsWith(` ${ref}`))
|
|
104
|
+
return line.slice(0, 12);
|
|
105
|
+
}
|
|
106
|
+
return undefined;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
return undefined;
|
|
111
|
+
}
|
|
112
|
+
})();
|
|
113
|
+
//# sourceMappingURL=build.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build.js","sourceRoot":"","sources":["../src/build.ts"],"names":[],"mappings":"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"}
|
package/dist/roles.js
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
// Canonical role identity, server side (Phase 8 Task 4).
|
|
2
|
+
//
|
|
3
|
+
// MIRROR of hooks/roles.mjs — tsconfig's rootDir is `src`, so this cannot
|
|
4
|
+
// import the hook copy, and the hook copy must stay build-free (the pusher
|
|
5
|
+
// loads it from a bare checkout). test/roles.test.mjs asserts the two agree;
|
|
6
|
+
// change one, change the other.
|
|
7
|
+
//
|
|
8
|
+
// See hooks/roles.mjs for the rationale behind `explicit` and the word-match
|
|
9
|
+
// fallback.
|
|
10
|
+
import { z } from "zod";
|
|
11
|
+
export function slugifyRole(role) {
|
|
12
|
+
return String(role ?? "")
|
|
13
|
+
.trim()
|
|
14
|
+
.toLowerCase()
|
|
15
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
16
|
+
.replace(/^-+|-+$/g, "");
|
|
17
|
+
}
|
|
18
|
+
export const GATE_RUNNER_ROLE_IDS = new Set(["qa", "quality", "coordinator", "gate"]);
|
|
19
|
+
export const COORDINATOR_ROLE_IDS = new Set(["coordinator"]);
|
|
20
|
+
export function resolveRole(role) {
|
|
21
|
+
if (role === null || role === undefined)
|
|
22
|
+
return undefined;
|
|
23
|
+
if (typeof role === "string") {
|
|
24
|
+
const roleId = slugifyRole(role);
|
|
25
|
+
return roleId ? { roleId, displayName: role, explicit: false } : undefined;
|
|
26
|
+
}
|
|
27
|
+
if (typeof role === "object") {
|
|
28
|
+
const declared = typeof role.roleId === "string" ? slugifyRole(role.roleId) : "";
|
|
29
|
+
const name = typeof role.displayName === "string" && role.displayName
|
|
30
|
+
? role.displayName
|
|
31
|
+
: typeof role.role === "string" && role.role
|
|
32
|
+
? role.role
|
|
33
|
+
: undefined;
|
|
34
|
+
if (declared)
|
|
35
|
+
return { roleId: declared, displayName: name ?? declared, explicit: true };
|
|
36
|
+
if (name)
|
|
37
|
+
return resolveRole(name);
|
|
38
|
+
}
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
export function roleMatches(role, allowedIds) {
|
|
42
|
+
const resolved = resolveRole(role);
|
|
43
|
+
if (!resolved)
|
|
44
|
+
return false;
|
|
45
|
+
if (allowedIds.has(resolved.roleId))
|
|
46
|
+
return true;
|
|
47
|
+
if (resolved.explicit)
|
|
48
|
+
return false;
|
|
49
|
+
return resolved.roleId.split("-").some((word) => allowedIds.has(word));
|
|
50
|
+
}
|
|
51
|
+
export function isGateRunner(role) {
|
|
52
|
+
return roleMatches(role, GATE_RUNNER_ROLE_IDS);
|
|
53
|
+
}
|
|
54
|
+
export function isCoordinator(role) {
|
|
55
|
+
return roleMatches(role, COORDINATOR_ROLE_IDS);
|
|
56
|
+
}
|
|
57
|
+
// Which roles may emit which record.type at the send path. Enforcement lives
|
|
58
|
+
// in messaging.ts (checkRecordAuthority); the table lives here so register/join
|
|
59
|
+
// can ECHO the consequence back at onboarding — a role that cannot emit `go`
|
|
60
|
+
// should learn it when it registers, not when it sends its first work order.
|
|
61
|
+
//
|
|
62
|
+
// NOT A TRUST BOUNDARY — roles are self-declared. See checkRecordAuthority.
|
|
63
|
+
export const RECORD_AUTHORITY = {
|
|
64
|
+
verdict: { roles: GATE_RUNNER_ROLE_IDS, label: "gate-runner" },
|
|
65
|
+
go: { roles: COORDINATOR_ROLE_IDS, label: "coordinator" },
|
|
66
|
+
scope: { roles: COORDINATOR_ROLE_IDS, label: "coordinator" },
|
|
67
|
+
};
|
|
68
|
+
// Split the restricted record types into what this role may and may not emit.
|
|
69
|
+
// Unrestricted types are omitted from both lists — they are nobody's business.
|
|
70
|
+
export function recordAuthorityFor(role) {
|
|
71
|
+
const mayEmit = [];
|
|
72
|
+
const mayNotEmit = [];
|
|
73
|
+
for (const [type, rule] of Object.entries(RECORD_AUTHORITY)) {
|
|
74
|
+
(roleMatches(role, rule.roles) ? mayEmit : mayNotEmit).push(type);
|
|
75
|
+
}
|
|
76
|
+
return { mayEmit, mayNotEmit };
|
|
77
|
+
}
|
|
78
|
+
// Wire shape for `role` on register/join. Either free text (v1: `role: "qa
|
|
79
|
+
// lead"`) or a declared identity (`{roleId: "qa", displayName: "QA gate"}`).
|
|
80
|
+
// Both are supported forever — the string form is not deprecated, it just
|
|
81
|
+
// leaves the id derived rather than frozen.
|
|
82
|
+
//
|
|
83
|
+
// Lives here rather than in tools/ because registry.ts and transport.ts import
|
|
84
|
+
// each other; a schema in either would be a temporal-dead-zone hazard.
|
|
85
|
+
export const roleInputSchema = z.union([
|
|
86
|
+
z.string(),
|
|
87
|
+
z.object({
|
|
88
|
+
roleId: z.string().min(1).optional(),
|
|
89
|
+
displayName: z.string().min(1).optional(),
|
|
90
|
+
}),
|
|
91
|
+
]);
|
|
92
|
+
//# sourceMappingURL=roles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"roles.js","sourceRoot":"","sources":["../src/roles.ts"],"names":[],"mappings":"AAAA,yDAAyD;AACzD,EAAE;AACF,0EAA0E;AAC1E,2EAA2E;AAC3E,6EAA6E;AAC7E,gCAAgC;AAChC,EAAE;AACF,6EAA6E;AAC7E,YAAY;AAEZ,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAexB,MAAM,UAAU,WAAW,CAAC,IAAa;IACvC,OAAO,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;SACtB,IAAI,EAAE;SACN,WAAW,EAAE;SACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;SAC3B,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;AAC7B,CAAC;AAED,MAAM,CAAC,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAAC,CAAC,IAAI,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,CAAC,CAAC,CAAC;AACtF,MAAM,CAAC,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC;AAE7D,MAAM,UAAU,WAAW,CAAC,IAAe;IACzC,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC1D,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC7B,MAAM,MAAM,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;QACjC,OAAO,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;IAC7E,CAAC;IACD,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC7B,MAAM,QAAQ,GAAG,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACjF,MAAM,IAAI,GACR,OAAO,IAAI,CAAC,WAAW,KAAK,QAAQ,IAAI,IAAI,CAAC,WAAW;YACtD,CAAC,CAAC,IAAI,CAAC,WAAW;YAClB,CAAC,CAAC,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,IAAI;gBAC1C,CAAC,CAAC,IAAI,CAAC,IAAI;gBACX,CAAC,CAAC,SAAS,CAAC;QAClB,IAAI,QAAQ;YAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,IAAI,IAAI,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;QACzF,IAAI,IAAI;YAAE,OAAO,WAAW,CAAC,IAAI,CAAC,CAAC;IACrC,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,IAAe,EAAE,UAAuB;IAClE,MAAM,QAAQ,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;IACnC,IAAI,CAAC,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC5B,IAAI,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IACjD,IAAI,QAAQ,CAAC,QAAQ;QAAE,OAAO,KAAK,CAAC;IACpC,OAAO,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;AACzE,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,IAAe;IAC1C,OAAO,WAAW,CAAC,IAAI,EAAE,oBAAoB,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAAe;IAC3C,OAAO,WAAW,CAAC,IAAI,EAAE,oBAAoB,CAAC,CAAC;AACjD,CAAC;AAED,6EAA6E;AAC7E,gFAAgF;AAChF,6EAA6E;AAC7E,6EAA6E;AAC7E,EAAE;AACF,4EAA4E;AAC5E,MAAM,CAAC,MAAM,gBAAgB,GAA0D;IACrF,OAAO,EAAE,EAAE,KAAK,EAAE,oBAAoB,EAAE,KAAK,EAAE,aAAa,EAAE;IAC9D,EAAE,EAAE,EAAE,KAAK,EAAE,oBAAoB,EAAE,KAAK,EAAE,aAAa,EAAE;IACzD,KAAK,EAAE,EAAE,KAAK,EAAE,oBAAoB,EAAE,KAAK,EAAE,aAAa,EAAE;CAC7D,CAAC;AAEF,8EAA8E;AAC9E,+EAA+E;AAC/E,MAAM,UAAU,kBAAkB,CAAC,IAAe;IAChD,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,MAAM,UAAU,GAAa,EAAE,CAAC;IAChC,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,gBAAgB,CAAC,EAAE,CAAC;QAC5D,CAAC,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACpE,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC;AACjC,CAAC;AAED,2EAA2E;AAC3E,6EAA6E;AAC7E,0EAA0E;AAC1E,4CAA4C;AAC5C,EAAE;AACF,+EAA+E;AAC/E,uEAAuE;AACvE,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC;IACrC,CAAC,CAAC,MAAM,EAAE;IACV,CAAC,CAAC,MAAM,CAAC;QACP,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;QACpC,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;KAC1C,CAAC;CACH,CAAC,CAAC"}
|
package/dist/server.js
CHANGED
|
@@ -4,8 +4,8 @@ import { createServer } 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 { ensureDirs,
|
|
8
|
-
import { attachAgentSchema, attachAgentTool, clearTransportSchema, clearTransportTool, deleteRoomSchema, deleteRoomTool, detachAgentSchema, detachAgentTool, doctorSchema, doctorTool, forceUnregisterSchema, forceUnregisterTool, heartbeatSchema, heartbeatTool, joinRoomSchema, joinRoomTool, joinSchema, joinTool, leaveRoomSchema, leaveRoomTool, listAgentsSchema, listAgentsTool, pingSchema, pingTool, listRoomsSchema, listRoomsTool, postStatusSchema, postStatusTool, pruneSchema, pruneTool, readMessagesSchema, readMessagesTool, retrieveRoomHistorySchema, retrieveRoomHistoryTool, registerSchema, registerTool, renameAgentSchema, renameAgentTool, reportTransportSchema, reportTransportTool, sendCommandSchema, sendCommandTool, sendMessageSchema, sendMessageTool, setRoomMotdSchema, setRoomMotdTool, setRoomTopicSchema, setRoomTopicTool, statusSchema, statusTool, unregisterSchema, unregisterTool, quitSchema, quitTool, waitForMessageSchema, waitForMessageTool, } from "./tools/index.js";
|
|
7
|
+
import { ensureDirs, getTokenMap, reloadTokenMapSync } from "./store.js";
|
|
8
|
+
import { attachAgentSchema, attachAgentTool, clearTransportSchema, clearTransportTool, deleteRoomSchema, deleteRoomTool, detachAgentSchema, detachAgentTool, doctorSchema, doctorTool, forceUnregisterSchema, forceUnregisterTool, heartbeatSchema, heartbeatTool, joinRoomSchema, joinRoomTool, joinSchema, joinTool, leaveRoomSchema, leaveRoomTool, listAgentsSchema, listAgentsTool, pingSchema, pingTool, listRoomsSchema, listRoomsTool, postStatusSchema, postStatusTool, pruneSchema, pruneTool, readMessagesSchema, readMessagesTool, retrieveMessageSchema, retrieveMessageTool, retrieveRoomHistorySchema, retrieveRoomHistoryTool, registerSchema, registerTool, renameAgentSchema, renameAgentTool, reportReceiptSchema, reportReceiptTool, reportTransportSchema, reportTransportTool, sendCommandSchema, sendCommandTool, sendMessageSchema, sendMessageTool, setRoomMotdSchema, setRoomMotdTool, setRoomTopicSchema, setRoomTopicTool, statusSchema, statusTool, unregisterSchema, unregisterTool, quitSchema, quitTool, waitForMessageSchema, waitForMessageTool, listScopesSchema, listScopesTool, importWorkSchema, importWorkTool, listWorkSchema, listWorkTool, exportWorkSchema, exportWorkTool, } from "./tools/index.js";
|
|
9
9
|
function jsonResult(data) {
|
|
10
10
|
return {
|
|
11
11
|
content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
|
|
@@ -28,13 +28,21 @@ function buildServer(initialBound) {
|
|
|
28
28
|
let bound = initialBound;
|
|
29
29
|
// Gate every tool that takes a caller identity. `field: null` (list_agents,
|
|
30
30
|
// list_rooms, prune) bypasses the check entirely.
|
|
31
|
-
|
|
31
|
+
//
|
|
32
|
+
// `bindOnClaim: false` (status, ping) means the tool still enforces a
|
|
33
|
+
// mismatch against an *existing* binding, but a fresh (unbound) session
|
|
34
|
+
// never claims one just by naming an agentId — a diagnostic status/ping
|
|
35
|
+
// call must not be able to silently TOFU-bind a session to some other,
|
|
36
|
+
// already-live agent's identity.
|
|
37
|
+
function gate(field, handler, { bindOnClaim = true } = {}) {
|
|
32
38
|
return async (args) => {
|
|
33
39
|
if (field) {
|
|
34
40
|
const claimed = args[field];
|
|
35
41
|
if (typeof claimed === "string") {
|
|
36
42
|
if (bound === undefined) {
|
|
37
|
-
|
|
43
|
+
if (bindOnClaim) {
|
|
44
|
+
bound = claimed; // TOFU: first claim wins, then sticky.
|
|
45
|
+
}
|
|
38
46
|
}
|
|
39
47
|
else if (bound !== claimed) {
|
|
40
48
|
throw new Error(`identity bound to '${bound}'; rejected attempt to act as '${claimed}'`);
|
|
@@ -66,14 +74,15 @@ function buildServer(initialBound) {
|
|
|
66
74
|
server.tool("register", "Register this agent in the shared registry. Lower-level than `join` — does not attach a transport or drain the inbox. Prefer `join` unless you need explicit control.", registerSchema, gate("agentId", registerTool));
|
|
67
75
|
server.tool("unregister", "Tear down this agent: detach any attached transport (kills the pusher) and remove the registry entry. Clean shutdown counterpart to `join`.", unregisterSchema, gate("agentId", unregisterTool));
|
|
68
76
|
server.tool("quit", "Clean shutdown: unregister this agent (detach transport, leave rooms, remove registry entry) then exit the MCP process. Only callable by the session's bound identity. Use this to cleanly hand off before a restart with a new name.", quitSchema, gate("agentId", quitTool));
|
|
69
|
-
server.tool("status", "Introspect this agent's coord state: registration, attached transport, inbox depth and unread count, and whether this MCP server is running inside tmux. Useful for debugging 'why isn't my DM landing'.", statusSchema, gate("agentId", statusTool));
|
|
77
|
+
server.tool("status", "Introspect this agent's coord state: registration, attached transport, inbox depth and unread count, and whether this MCP server is running inside tmux. Useful for debugging 'why isn't my DM landing'. Read-only — naming an agentId here never binds this session's identity.", statusSchema, gate("agentId", statusTool, { bindOnClaim: false }));
|
|
70
78
|
server.tool("heartbeat", "Refresh this agent's lastHeartbeat timestamp.", heartbeatSchema, gate("agentId", heartbeatTool));
|
|
71
|
-
server.tool("ping", "Liveness probe for another agent, answered entirely from server-side state (registry entry, transport marker, pusher pid, tmux pane) — it never touches the target's session, so a fleet-wide sweep costs zero model tokens on the targets. Returns alive (fresh heartbeat or live transport), reachable (a DM pushed now would land), granular checks, and latencyMs. Distinct from heartbeat, which is an agent refreshing its OWN activity timestamp. Pass echo:true (default off) to additionally drop a PING DM into the target's inbox — that wakes the target's model, so use it sparingly and only when you need an agent-level acknowledgement. 'from' is enforced against the session's bound identity.", pingSchema, gate("from", pingTool));
|
|
79
|
+
server.tool("ping", "Liveness probe for another agent, answered entirely from server-side state (registry entry, transport marker, pusher pid, tmux pane) — it never touches the target's session, so a fleet-wide sweep costs zero model tokens on the targets. Returns alive (fresh heartbeat or live transport), reachable (a DM pushed now would land), granular checks, and latencyMs. Distinct from heartbeat, which is an agent refreshing its OWN activity timestamp. Pass echo:true (default off) to additionally drop a PING DM into the target's inbox — that wakes the target's model, so use it sparingly and only when you need an agent-level acknowledgement. 'from' is enforced against the session's bound identity, but read-only — naming 'from' here never binds this session's identity.", pingSchema, gate("from", pingTool, { bindOnClaim: false }));
|
|
72
80
|
server.tool("list_agents", "List all known agents and whether they appear online (heartbeat <5min).", listAgentsSchema, gate(null, listAgentsTool));
|
|
73
81
|
server.tool("send_message", "Send a message. If 'to' is set, goes to that agent's inbox (DM); otherwise to a channel — pass 'room' (e.g. 'seo' or '#seo') to target a specific channel, or omit it for the default 'general' channel. For channel posts, tag 'kind': 'decision' for GOs/verdicts/agreements that must outlive routine cleanup (kept ~30 days, quoted verbatim in digests), 'status' for progress notes, omit for ordinary chatter. The 'from' field is enforced against the session's bound identity when binding is configured.", sendMessageSchema, gate("from", sendMessageTool));
|
|
74
82
|
server.tool("send_command", "Inject a context-management slash command (/clear or /compact) directly into a sub-agent's live tmux session — delivered RAW with no banner or prefix, so the agent's CLI runs it as a real slash command. Target one agent with 'to' or broadcast to a channel's tmux-attached members with 'room' (never the sender). Hard-gated to tmux: returns ok:false if the target has no live tmux-push(-remote) transport. By default BLOCKS until the receiving pusher confirms it actually typed the command into the pane (out-of-band delivery receipt, no added agent context) and returns delivery:'confirmed' with deliveredAt, or delivery:'pending'+warning if no receipt arrived within deliveryTimeoutMs (default 8000) — a stale/wedged pusher. Pass waitForDelivery:false for fire-and-forget. Intended for a lead agent to clear/compact sub-agent context and save tokens. The command allowlist is locked to /clear and /compact; nothing else is accepted. 'from' is enforced against the session's bound identity.", sendCommandSchema, gate("from", sendCommandTool));
|
|
75
83
|
server.tool("read_messages", "Read new messages from inbox|room|status. For source='room', pass 'room' to read a specific channel (default 'general'). Room and status reads return the most recent 50 entries per call — pass limit to override (max 500). When the backlog exceeds the window, the older overflow is replaced by a compact `history` digest carrying a retrieval hash; call retrieve_room_history(hash) to expand it. Inbox drains fully by default. Advances the per-channel cursor unless peek=true.", readMessagesSchema, gate("agentId", readMessagesTool));
|
|
76
84
|
server.tool("retrieve_room_history", "Expand a compressed channel-history digest returned by read_messages. Pass the `hash` from the `history` field; optionally pass `query` to return only matching messages (case-insensitive substring). Entries are scoped to the agent that produced them and expire after 30 minutes — if expired, re-read the channel with a higher limit instead.", retrieveRoomHistorySchema, gate("agentId", retrieveRoomHistoryTool));
|
|
85
|
+
server.tool("retrieve_message", "Expand a `retrieve_message id=<uuid>` handle from a pane digest into the full message and its typed `record`. A record whose text rendering spans multiple lines (a DAVID_DECISION packet) is delivered to a pane as ONE attributed line plus this handle; call it to get the structured record back. Reads the message by id from the channels you can read (your inbox and rooms you belong to), falling through to the append-only archive if compaction moved it — so unlike retrieve_room_history there is no TTL and nothing to expire. A handle for a message never delivered to you is simply not found.", retrieveMessageSchema, gate("agentId", retrieveMessageTool));
|
|
77
86
|
server.tool("post_status", "Append a status broadcast to the shared status stream.", postStatusSchema, gate("agentId", postStatusTool));
|
|
78
87
|
server.tool("prune", "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. Pass `room` to prune a single channel, or `targets` (rooms|status|inbox|receipts|members) to narrow the sweep. 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.", pruneSchema, gate(null, pruneTool));
|
|
79
88
|
server.tool("wait_for_message", "Block (max 60s) until a new message appears on the given source, then return it. For source='room', pass 'room' to wait on a specific channel (default 'general').", waitForMessageSchema, gate("agentId", waitForMessageTool));
|
|
@@ -107,17 +116,23 @@ function buildServer(initialBound) {
|
|
|
107
116
|
server.tool("detach_agent", "Stop the tmux-push transport for an agent: kills the pusher process and clears the transport marker.", detachAgentSchema, gate("agentId", detachAgentTool));
|
|
108
117
|
server.tool("report_transport", "Publish a transport marker for an agent (used by the remote tmux pusher, scripts/coord-pusher.mjs, to surface itself in list_agents). Set transport='tmux-push-remote' and optionally host/tmuxTarget. Liveness for remote markers is heartbeat-based — keep calling heartbeat or this marker gets GC'd after staleness.", reportTransportSchema, gate("agentId", reportTransportTool));
|
|
109
118
|
server.tool("clear_transport", "Idempotent delete of an agent's transport marker. The wire-callable counterpart to detach_agent for remote pushers: it only removes the marker — there's no local process to kill.", clearTransportSchema, gate("agentId", clearTransportTool));
|
|
119
|
+
server.tool("report_receipt", "Append a delivery receipt for a message this agent's pusher just typed into its pane — the wire-callable counterpart to the local pusher's receipts/<id>.jsonl stamp, for remote pushers (scripts/coord-pusher.mjs) that cannot write this host's filesystem. This is what lets send_command to a tmux-push-remote agent return delivery:'confirmed'. For control commands pass exactly what submit verification observed (submitted/verified/reason); omitting 'submitted' means 'typed but unverified' and is reported as delivery:'pending', never 'confirmed'. 'agentId' (the receiving agent) is enforced against the session's bound identity, so a pusher can only stamp its own agent's receipt file.", reportReceiptSchema, gate("agentId", reportReceiptTool));
|
|
110
120
|
server.tool("doctor", "Bus-wide health check: inspects the whole state dir and reports drift, leaks, and corruption (orphan transport markers / memberships / inboxes, cursor offsets past EOF, malformed JSONL, stale agents, oversized files, stale locks, channel/registry mismatches, environment). Read-only by default; pass fix=true to apply the safe, reversible repairs (malformed-line rewrites are backed up to .bak first). A clean report (healthy=true) means the bus is internally consistent.", doctorSchema, gate(null, doctorTool));
|
|
121
|
+
server.tool("list_scopes", "Read the declared write scopes for managed documents (~/agent-coord/scopes.json). Call it with 'path' (and your 'agentId') to ask \"may I write this?\" BEFORE editing a shared doc like docs/QUEUE.md; call it bare to list every declared document and its owning role. ADVISORY ONLY: the bus does not mediate file writes, so this answers who owns a document, it does not stop anyone — enforcement arrives when work state moves into the store. Absent scopes.json means nothing is owned and nothing warns (opt-in).", listScopesSchema, gate(null, listScopesTool));
|
|
122
|
+
server.tool("import_work", "Read a project's work documents (docs/QUEUE.md + docs/DONE.md, or the legacy docs/BACKLOG.md, plus docs/WORKSTREAMS.md) into typed records: queue items {priority,text,done}, done entries {text,ref,date} and board rows. The markdown stays authoritative — this store is a derived index, and export_work renders it back byte-identically.", importWorkSchema, gate(null, importWorkTool));
|
|
123
|
+
server.tool("list_work", "Query a project's work state as records instead of parsing markdown: open queue items (filter by priority), done entries with their ref and date as separate fields, and the board's lane rows. Falls back to reading the documents directly when nothing has been imported, so it works with no store at all.", listWorkSchema, gate(null, listWorkTool));
|
|
124
|
+
server.tool("export_work", "Render a project's work documents back out of the store, reproducing the pinned glyph contract exactly (ref after the last ' \u2014 ', date after a trailing ' \u00b7 '). Reports by default; pass write:true to rewrite the files. Refuses to export from an empty store rather than blanking a document. Any declared Task 4 write scope is REPORTED alongside the write, never enforced.", exportWorkSchema, gate(null, exportWorkTool));
|
|
111
125
|
server.tool("delete_room", "Permanently delete a channel: removes it from the registry, deletes its JSONL file, and clears all agent cursor offsets for that channel. Refuses if agents are still joined unless force=true. Cannot delete the default 'general' channel. Posts a system notice to #general on success.", deleteRoomSchema, gate("agentId", deleteRoomTool));
|
|
112
126
|
server.tool("force_unregister", "Admin eviction: unregisters any agent by targetAgentId regardless of the caller's identity. Detaches the agent's transport, removes it from all channel memberships, and drops its registry entry. Use after a reboot to clean up stale agents that can no longer unregister themselves.", forceUnregisterSchema, gate(null, forceUnregisterTool));
|
|
113
127
|
return server;
|
|
114
128
|
}
|
|
115
|
-
//
|
|
116
|
-
// operators can rotate / add agents
|
|
117
|
-
|
|
129
|
+
// Token map for HTTP identity binding, held in-process via store.ts's
|
|
130
|
+
// shared cache. Hot-reloaded on SIGHUP so operators can rotate / add agents
|
|
131
|
+
// without a server restart; also refreshed automatically by rename_agent
|
|
132
|
+
// (see rotateAgentToken) so a live rename doesn't need one.
|
|
118
133
|
function loadTokenMap(initial) {
|
|
119
134
|
try {
|
|
120
|
-
|
|
135
|
+
reloadTokenMapSync();
|
|
121
136
|
}
|
|
122
137
|
catch (e) {
|
|
123
138
|
// On initial load a bad file is fatal — refuse to start in a known-bad
|
|
@@ -130,7 +145,7 @@ function loadTokenMap(initial) {
|
|
|
130
145
|
return;
|
|
131
146
|
}
|
|
132
147
|
if (!initial) {
|
|
133
|
-
console.error(`[agent-coord-mcp] SIGHUP: token map reloaded (${
|
|
148
|
+
console.error(`[agent-coord-mcp] SIGHUP: token map reloaded (${getTokenMap()?.size ?? 0} agents)`);
|
|
134
149
|
}
|
|
135
150
|
}
|
|
136
151
|
async function main() {
|
|
@@ -161,7 +176,7 @@ async function main() {
|
|
|
161
176
|
}
|
|
162
177
|
async function startHttp(port) {
|
|
163
178
|
const sharedToken = process.env.AGENT_COORD_TOKEN;
|
|
164
|
-
const bound =
|
|
179
|
+
const bound = getTokenMap() !== null;
|
|
165
180
|
if (!bound && !sharedToken) {
|
|
166
181
|
console.error("[agent-coord-mcp] HTTP mode needs auth: either set AGENT_COORD_TOKEN (legacy " +
|
|
167
182
|
"shared bearer, advisory identity) or create ~/agent-coord/tokens.json (per-agent " +
|
|
@@ -237,6 +252,7 @@ async function startHttp(port) {
|
|
|
237
252
|
if (!authHeader || !authHeader.startsWith("Bearer "))
|
|
238
253
|
return { ok: false };
|
|
239
254
|
const bearer = authHeader.slice("Bearer ".length);
|
|
255
|
+
const tokenMap = getTokenMap();
|
|
240
256
|
if (tokenMap) {
|
|
241
257
|
const agent = tokenMap.get(bearer);
|
|
242
258
|
return agent ? { ok: true, agent } : { ok: false };
|
|
@@ -275,7 +291,7 @@ async function startHttp(port) {
|
|
|
275
291
|
// agent than the session was created for — otherwise any valid token plus
|
|
276
292
|
// a leaked session id could drive that session's identity (session hijack).
|
|
277
293
|
if (transport &&
|
|
278
|
-
|
|
294
|
+
getTokenMap() &&
|
|
279
295
|
typeof sid === "string" &&
|
|
280
296
|
sessionAgents.get(sid) !== resolved.agent) {
|
|
281
297
|
res.writeHead(403, { "Content-Type": "text/plain" });
|
|
@@ -301,7 +317,7 @@ async function startHttp(port) {
|
|
|
301
317
|
}
|
|
302
318
|
});
|
|
303
319
|
http.listen(port, bindAddr, () => {
|
|
304
|
-
const mode = bound ? `pre-bound (${
|
|
320
|
+
const mode = bound ? `pre-bound (${getTokenMap()?.size ?? 0} agents)` : "TOFU";
|
|
305
321
|
console.error(`[agent-coord-mcp] http listening on ${bindAddr}:${port} — identity ${mode}`);
|
|
306
322
|
if (bindAddr !== "127.0.0.1" && bindAddr !== "localhost") {
|
|
307
323
|
console.error(`[agent-coord-mcp] WARNING: bound to ${bindAddr} without TLS. Front with a TLS reverse proxy ` +
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
package/dist/store.js
CHANGED
|
@@ -56,8 +56,24 @@ export const ARCHIVE_STATUS_FILE = path.join(ARCHIVE_DIR, "status.jsonl");
|
|
|
56
56
|
// from/agentId field. Absent → advisory mode (legacy behaviour, with a
|
|
57
57
|
// startup warning). Should be mode 600; operator-managed.
|
|
58
58
|
export const TOKENS_FILE = path.join(ROOT, "tokens.json");
|
|
59
|
+
// Declared write scopes for managed documents (v0.18.0, Phase 8 Task 4).
|
|
60
|
+
// Opt-in and operator-managed: absent → nothing is owned and nothing warns.
|
|
61
|
+
// ADVISORY. The bus does not mediate writes to docs/QUEUE.md & friends —
|
|
62
|
+
// agents edit them with ordinary file tools, so there is no interception
|
|
63
|
+
// point. This file lets an agent ASK who owns a document (list_scopes) and
|
|
64
|
+
// lets `doctor` DETECT drift after the fact. Pre-emptive enforcement waits
|
|
65
|
+
// for Phase 8 Task 5, when work state moves into the store.
|
|
66
|
+
export const SCOPES_FILE = path.join(ROOT, "scopes.json");
|
|
67
|
+
// Work state as data (v0.18.0, Phase 8 Task 5). One file per project holding
|
|
68
|
+
// the parsed QUEUE/DONE/board documents. DERIVED, not authoritative: the
|
|
69
|
+
// markdown in the repo remains the source of truth, and deleting this
|
|
70
|
+
// directory costs an `import_work`, never data (see src/work.ts).
|
|
71
|
+
export const WORK_DIR = path.join(ROOT, "work");
|
|
72
|
+
export function workFile(project) {
|
|
73
|
+
return path.join(WORK_DIR, `${sanitize(project)}.json`);
|
|
74
|
+
}
|
|
59
75
|
export function ensureDirs() {
|
|
60
|
-
for (const d of [ROOT, INBOX_DIR, CURSOR_DIR, TRANSPORT_DIR, PID_DIR, LOG_DIR, ROOMS_DIR, RECEIPTS_DIR, HISTORY_DIR]) {
|
|
76
|
+
for (const d of [ROOT, INBOX_DIR, CURSOR_DIR, TRANSPORT_DIR, PID_DIR, LOG_DIR, ROOMS_DIR, RECEIPTS_DIR, HISTORY_DIR, WORK_DIR]) {
|
|
61
77
|
if (!existsSync(d))
|
|
62
78
|
mkdirSync(d, { recursive: true });
|
|
63
79
|
}
|
|
@@ -94,19 +110,56 @@ export function readTokenMapSync() {
|
|
|
94
110
|
}
|
|
95
111
|
return out;
|
|
96
112
|
}
|
|
113
|
+
// In-process cache of the token map, shared by the HTTP identity-binding
|
|
114
|
+
// layer (server.ts) and rotateAgentToken below. A module-level cache (rather
|
|
115
|
+
// than each caller re-reading the file) is what lets a rename refresh the
|
|
116
|
+
// live server's view without an operator SIGHUP.
|
|
117
|
+
let tokenMapCache = null;
|
|
118
|
+
let tokenMapInitialized = false;
|
|
119
|
+
// Current in-process token map (bearer -> agentId), or null if unbound (no
|
|
120
|
+
// tokens.json). Lazily loads from disk on first call.
|
|
121
|
+
export function getTokenMap() {
|
|
122
|
+
if (!tokenMapInitialized) {
|
|
123
|
+
tokenMapCache = readTokenMapSync();
|
|
124
|
+
tokenMapInitialized = true;
|
|
125
|
+
}
|
|
126
|
+
return tokenMapCache;
|
|
127
|
+
}
|
|
128
|
+
// Re-read tokens.json from disk and replace the in-process cache. Throws on
|
|
129
|
+
// a malformed file — callers decide whether that's fatal (startup) or
|
|
130
|
+
// recoverable (SIGHUP, post-rotate refresh).
|
|
131
|
+
export function reloadTokenMapSync() {
|
|
132
|
+
tokenMapCache = readTokenMapSync();
|
|
133
|
+
tokenMapInitialized = true;
|
|
134
|
+
return tokenMapCache;
|
|
135
|
+
}
|
|
97
136
|
// Atomically rotate the token entry for an agent rename (used by
|
|
98
137
|
// rename_agent so the same bearer continues to authenticate the renamed
|
|
99
138
|
// identity). No-op if the file is absent or the old id isn't in the map.
|
|
100
139
|
export async function rotateAgentToken(oldAgentId, newAgentId) {
|
|
101
140
|
if (!existsSync(TOKENS_FILE))
|
|
102
141
|
return;
|
|
142
|
+
let rotated = false;
|
|
103
143
|
await updateJson(TOKENS_FILE, {}, (current) => {
|
|
104
144
|
if (current[oldAgentId] !== undefined) {
|
|
105
145
|
current[newAgentId] = current[oldAgentId];
|
|
106
146
|
delete current[oldAgentId];
|
|
147
|
+
rotated = true;
|
|
107
148
|
}
|
|
108
149
|
return current;
|
|
109
150
|
});
|
|
151
|
+
if (rotated) {
|
|
152
|
+
// Refresh the in-process cache immediately: without this, the renamed
|
|
153
|
+
// agent's bearer keeps resolving to the OLD id in this process until an
|
|
154
|
+
// operator sends SIGHUP, silently misattributing its calls.
|
|
155
|
+
try {
|
|
156
|
+
reloadTokenMapSync();
|
|
157
|
+
}
|
|
158
|
+
catch (e) {
|
|
159
|
+
console.error(`[agent-coord-mcp] rename_agent: token map reload after rotate failed: ${e.message} ` +
|
|
160
|
+
`(keeping previous in-process map; send SIGHUP to retry)`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
110
163
|
}
|
|
111
164
|
// Normalize a channel name: strip leading '#', lowercase, restrict to a safe
|
|
112
165
|
// charset, empty → the default channel. Display layers re-add the '#'.
|