agent-coord-mcp 0.26.22 → 0.26.23

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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"herdr.js","sourceRoot":"","sources":["../../src/transports/herdr.ts"],"names":[],"mappings":"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"}
@@ -6,12 +6,14 @@
6
6
  * fall-through at a call site. Until Task 3, tmux is the only registered
7
7
  * implementation and that is the rollback plan — the seam lands behind no config.
8
8
  */
9
- import { HERDR, TMUX_PUSH, TMUX_PUSH_REMOTE } from "./types.js";
9
+ import { HERDR, TMUX_PUSH, TMUX_PUSH_REMOTE, TRANSPORT_KINDS } from "./types.js";
10
10
  import { TmuxTransport } from "./tmux.js";
11
+ import { HerdrTransport } from "./herdr.js";
11
12
  import { configuredTransport } from "./config.js";
12
13
  export * from "./types.js";
13
14
  export * from "./config.js";
14
15
  export { TmuxTransport, tmuxAvailable, paneExists, probePane, tmuxVersion } from "./tmux.js";
16
+ export { HerdrTransport, defaultHerdrRunner, interpretHerdrReply, herdrKeyName, herdrPaneExists, HERDR_KEYS, HERDR_ABSENT_MESSAGE } from "./herdr.js";
15
17
  let host;
16
18
  /** Wire the process-layer implementation in once, at module init. */
17
19
  export function registerTmuxHost(h) {
@@ -27,9 +29,13 @@ export function resolveTransport(kind) {
27
29
  case TMUX_PUSH_REMOTE:
28
30
  return new TmuxTransport(host, kind);
29
31
  case HERDR:
30
- // Task 4. Named so the union stays total and the gap is a stated absence
31
- // rather than a default that silently behaves like tmux.
32
- throw new Error('transport "herdr" is not implemented yet (Phase 5.4 Task 4)');
32
+ // Task 4: the socket transport. No host object — there is no pusher process to
33
+ // inject; every call is `herdr <subcommand>` through the transport's own runner.
34
+ return new HerdrTransport();
35
+ default:
36
+ // Unreachable for a TransportKind; reachable from JS with a string. A designed
37
+ // refusal, never a default that behaves like tmux.
38
+ throw new Error(`unknown transport kind ${JSON.stringify(kind)} — valid: ${TRANSPORT_KINDS.join(", ")}`);
33
39
  }
34
40
  }
35
41
  /* ── the ACTIVE transport, and why `running` is not read from config ────────── */
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/transports/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/transports/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-coord-mcp",
3
- "version": "0.26.22",
3
+ "version": "0.26.23",
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": {
@@ -50,6 +50,8 @@ import { readAllTransportMarkers } from "./tools/registry.js";
50
50
  import { queueWriteSchema } from "./tools/queue-write.js";
51
51
  import { treeProvenance } from "./tools/tree-provenance.js";
52
52
  import { detectSpread } from "./server-spread.js";
53
+ import { HerdrTransport, herdrKeyName } from "./transports/herdr.js";
54
+ import { HERDR } from "./transports/types.js";
53
55
 
54
56
  export type ProbeResult = {
55
57
  id: string;
@@ -270,6 +272,24 @@ const PROBES: Probe[] = [
270
272
  return { present, evidence: `"⛔ Blocked — was 🚧 …" in flight: ${blocked} (0.26.21 said true) · "🔍 In Review": ${review} -> present=${present}` };
271
273
  },
272
274
  },
275
+ {
276
+ // Phase 5.4 Task 4 (0.26.23) — the herdr transport exists and refuses by name: a scripted
277
+ // dead pane reads dead from herdr's own reply, and a tmux key name is refused, not typed.
278
+ id: "herdr-transport-registered",
279
+ since: "0.26.23",
280
+ run: () => {
281
+ const scripted = new HerdrTransport({
282
+ run: (a) => (a[0] === "status"
283
+ ? { ok: true, status: 0, stdout: "server:\n status: running\n", stderr: "" }
284
+ : { ok: false, status: 0, stdout: "", stderr: "", json: { error: { code: "pane_not_found", message: "pane w0:p0 not found" } }, error: { code: "pane_not_found", message: "pane w0:p0 not found" } }),
285
+ sleep: () => {},
286
+ });
287
+ const key = herdrKeyName("C-u");
288
+ const exists = scripted.paneExists("w0:p0");
289
+ const present = scripted.kind === HERDR && exists === false && key.ok === false;
290
+ return { present, evidence: `HerdrTransport.kind=${scripted.kind} · scripted pane_not_found -> paneExists=${exists} · herdrKeyName("C-u").ok=${key.ok} -> present=${present}` };
291
+ },
292
+ },
273
293
  {
274
294
  id: "record-authority",
275
295
  since: "0.24.0",
@@ -29,7 +29,8 @@ export type SubKind = keyof typeof EVENT_KINDS;
29
29
  * FIRE, whatever the emitter list and the scan clock say.
30
30
  */
31
31
  export type KindProbe = { diff: string; after?: { done?: string; phases?: Record<string, string> } };
32
- export type RecordEvent = { kind: SubKind; target: string; ref: string; summary: string };
32
+ /** `refs`: ⟨q-cbace757⟩ — a closure cited by N PRs carries all N, each checked against the record on its own; `ref` stays the joined form for the event key. */
33
+ export type RecordEvent = { kind: SubKind; target: string; ref: string; summary: string; refs?: string[] };
33
34
 
34
35
  /*
35
36
  * THE KIND REGISTRY IS THE SINGLE SOURCE, AND THAT IS TASK 9.2.
@@ -177,11 +177,18 @@ export const eventKey = (kind: SubKind, target: string, ref: string): string =>
177
177
  */
178
178
  export function eventIsDerived(recordText: string, ev: RecordEvent): { ok: true } | { ok: false; error: string } {
179
179
  if (!ev.ref) return { ok: false, error: `event for ${ev.kind} ${ev.target} carries no ref — nothing ties it to a record entry` };
180
- if (!String(recordText).includes(ev.ref))
180
+ // ⟨q-cbace757⟩ — a multi-PR closer is N citations, checked ONE BY ONE. The
181
+ // joined string ("a#1, a#2, a#3") is how the event is keyed, not how the record
182
+ // is read: a DONE line citing the same three PRs in another arrangement carries
183
+ // every ref and none of the joined form. The guard stays exactly as strict per
184
+ // ref — a citation absent from the record still refuses, and is named.
185
+ const refs = ev.refs?.length ? ev.refs : [ev.ref];
186
+ const missing = refs.filter((r) => !String(recordText).includes(r));
187
+ if (missing.length)
181
188
  return {
182
189
  ok: false,
183
190
  error:
184
- `refusing to emit ${ev.kind} ${ev.target}: its ref ${ev.ref} is NOT in the record. ` +
191
+ `refusing to emit ${ev.kind} ${ev.target}: ${missing.length === refs.length && refs.length === 1 ? `its ref ${ev.ref}` : `${missing.length} of its ${refs.length} cited ref(s) — ${missing.join(", ")} —`} is NOT in the record. ` +
185
192
  `An event that exists without the record change that caused it is a second source of truth — ` +
186
193
  `the stream would claim something the authoritative document does not.`,
187
194
  };
@@ -0,0 +1,87 @@
1
+ /**
2
+ * IN-PROCESS DELIVERY FOR HERDR SEATS (Phase 5.4 Task 4, box 4.4).
3
+ *
4
+ * A tmux seat has a pusher that tails its inbox and the rooms it joined, formats a batch,
5
+ * types it into the pane and advances the PUSH cursor once the paste is verified submitted
6
+ * (hooks/tmux-pusher.mjs + hooks/push-cursor.mjs). A herdr seat has no pusher, so the
7
+ * server does the same at SEND time: the message it just appended is formatted by the very
8
+ * same formatter the pusher uses (hooks/tier.mjs — one renderer, so the pane sees one
9
+ * shape on either transport), pushed through the transport, and ONLY on a verified
10
+ * delivery is the seat's push cursor advanced past it.
11
+ *
12
+ * THE CURSOR RULE IS THE PUSHER'S, UNCHANGED (⟨q-7be94b5e⟩): a paste that did not reach the
13
+ * pane must not mark the message consumed. The push cursor is advanced to the offset the
14
+ * append produced, and never touched when the transport reports not-delivered — the
15
+ * message stays where `read_messages` still serves it. The READ cursor is the agent's and
16
+ * is never written here.
17
+ *
18
+ * Simplification stated: the pusher batches routine room traffic into digests on a
19
+ * debounce; a herdr seat receives each message as it is sent, in the digest FORMAT (the
20
+ * `[agent-coord] …` banner and the attributed line) but one at a time. Tiers still decide
21
+ * the banner text. Batching for herdr is Task 5 territory if it is wanted.
22
+ */
23
+ import { statSync } from "node:fs";
24
+ import path from "node:path";
25
+ import { pathToFileURL } from "node:url";
26
+ import { activeTransport, HERDR, type TransportMarker } from "../transports/index.js";
27
+ import { ROOT, inboxFile, roomFile } from "../store.js";
28
+ import { loadLiveTransports } from "./registry.js";
29
+ import type { Message } from "./shared.js";
30
+
31
+ type Tier = { formatBatch: (batch: unknown[], agentId: string, rooms: string[]) => string; classifyTier: (m: unknown, opts?: unknown) => string };
32
+ type PushCursor = { readPushCursor: (root: string, safeId: string) => Record<string, unknown>; writePushCursor: (root: string, safeId: string, c: Record<string, unknown>) => void };
33
+ let hooks: Promise<{ tier: Tier; cursor: PushCursor }> | undefined;
34
+ function loadHooks(): Promise<{ tier: Tier; cursor: PushCursor }> {
35
+ hooks ??= (async () => {
36
+ const base = path.resolve(path.dirname(new URL(import.meta.url).pathname), "..", "..", "hooks");
37
+ const tier = (await import(pathToFileURL(path.join(base, "tier.mjs")).href)) as Tier;
38
+ const cursor = (await import(pathToFileURL(path.join(base, "push-cursor.mjs")).href)) as PushCursor;
39
+ return { tier, cursor };
40
+ })();
41
+ return hooks;
42
+ }
43
+ const safeId = (id: string) => id.replace(/[^A-Za-z0-9._-]/g, "_");
44
+
45
+ export type HerdrDeliveryOutcome = { agentId: string; delivered: boolean; enters?: number; error?: string; cursorAdvanced: boolean };
46
+
47
+ /** Deliver one just-appended message to every herdr-attached recipient among `recipients`. */
48
+ export async function deliverToHerdrSeats(msg: Message, recipients: string[], where: { kind: "dm" } | { kind: "room"; chan: string }): Promise<HerdrDeliveryOutcome[]> {
49
+ const t = activeTransport();
50
+ if (!t || t.kind !== HERDR) return [];
51
+ let markers: Map<string, TransportMarker>;
52
+ try { markers = await loadLiveTransports(); } catch { return []; }
53
+ const out: HerdrDeliveryOutcome[] = [];
54
+ for (const agentId of recipients) {
55
+ const marker = markers.get(agentId);
56
+ if (!marker || marker.transport !== HERDR) continue;
57
+ if (where.kind === "room" && marker.rooms === false) continue;
58
+ if (msg.from === agentId) continue;
59
+ const { tier, cursor } = await loadHooks();
60
+ const tagged = { ...msg, tag: where.kind === "dm" ? "DM" : `room #${where.chan}` };
61
+ const rendered = tier.formatBatch([{ ...tagged, tier: tier.classifyTier(tagged) }], agentId, where.kind === "room" ? [where.chan] : []);
62
+ // A control never comes through here: send_command hands a herdr seat's control to the
63
+ // transport's sendControl directly (a raw-vs-rendered branch here was dead and its
64
+ // mutation survived, so it is gone). Everything delivered here is a rendered message.
65
+ let r: { delivered: boolean; error?: string; enters?: number };
66
+ try { r = await t.push(marker, rendered); } catch (e) { r = { delivered: false, error: (e as Error).message }; }
67
+ let cursorAdvanced = false;
68
+ if (r.delivered) {
69
+ try {
70
+ const file = where.kind === "dm" ? inboxFile(agentId) : roomFile(where.chan);
71
+ const size = statSync(file).size;
72
+ const id = safeId(agentId);
73
+ const c = cursor.readPushCursor(ROOT, id) ?? {};
74
+ if (where.kind === "dm") c.inboxOffset = Math.max(Number(c.inboxOffset ?? 0), size);
75
+ else {
76
+ const offsets = ((c.roomOffsets as Record<string, number> | undefined) ?? {});
77
+ offsets[where.chan] = Math.max(Number(offsets[where.chan] ?? 0), size);
78
+ c.roomOffsets = offsets;
79
+ }
80
+ cursor.writePushCursor(ROOT, id, c);
81
+ cursorAdvanced = true;
82
+ } catch { cursorAdvanced = false; }
83
+ }
84
+ out.push({ agentId, delivered: r.delivered, enters: r.enters, error: r.error, cursorAdvanced });
85
+ }
86
+ return out;
87
+ }
@@ -84,6 +84,7 @@ import {
84
84
  isDecision,
85
85
  } from "./shared.js";
86
86
  import { isKnownHuman } from "../store.js";
87
+ import { deliverToHerdrSeats } from "./herdr-delivery.js";
87
88
  import { verifyCommitCite } from "../commit-cite.js";
88
89
 
89
90
  // ---------- send_message ----------
@@ -454,6 +455,9 @@ export async function sendMessageTool(args: {
454
455
  };
455
456
  const target = inboxFile(args.to);
456
457
  await appendJsonl(target, msg);
458
+ // Phase 5.4 Task 4 — a herdr-attached recipient has no pusher: deliver now, in-process.
459
+ const herdr = await deliverToHerdrSeats(msg, [args.to], { kind: "dm" });
460
+ void herdr;
457
461
  // Offline delivery is intentional (the inbox is created on demand), but a
458
462
  // typo'd recipient shouldn't vanish silently — surface a warning when the
459
463
  // target isn't a known agent so the caller can catch the mistake.
@@ -482,6 +486,10 @@ export async function sendMessageTool(args: {
482
486
  };
483
487
  const target = roomFile(chan);
484
488
  await appendJsonl(target, msg);
489
+ // Phase 5.4 Task 4 — herdr-attached members with rooms on receive the post now, in-process.
490
+ const roomMembers = (await getRooms())[chan]?.members ?? [];
491
+ const herdrRoom = await deliverToHerdrSeats(msg, roomMembers, { kind: "room", chan });
492
+ void herdrRoom;
485
493
  await maybeCompactRoom(chan);
486
494
  const roomWarning = [typedWarning, replyWarning, slashWarning].filter(Boolean).join("; ") || undefined;
487
495
  return { ok: true, id: msg.id, target, room: chan, ...(roomWarning ? { warning: roomWarning } : {}) };
@@ -45,6 +45,7 @@ import { verdictsFor, gatedBy, prVerdictsIn } from "../gated-head.js";
45
45
  import { boardRefFor, classifyBoardRef } from "./board-ref.js";
46
46
  import { haltState } from "./stall.js";
47
47
  import { readSubs, evaluate, commitEvaluation, eventIsDerived, type RecordEvent } from "./events.js";
48
+ import { prRefsIn } from "./record-events.js";
48
49
 
49
50
  const QUEUE_DOC = "docs/QUEUE.md";
50
51
  const DONE_DOC = "docs/DONE.md";
@@ -169,6 +170,53 @@ function prNumber(pr: string): string | null {
169
170
  const m = /#(\d+)\b/.exec(String(pr)) ?? /^(\d+)$/.exec(String(pr).trim());
170
171
  return m ? (m[1] as string) : null;
171
172
  }
173
+ /** ⟨q-cbace757⟩ — EVERY PR number a citation names, in order; a multi-PR closer is N citations. */
174
+ function prNumbersOf(pr: string): string[] {
175
+ const out: string[] = [];
176
+ for (const m of String(pr).matchAll(/#(\d+)\b/g)) if (!out.includes(m[1]!)) out.push(m[1]!);
177
+ if (!out.length) { const one = prNumber(pr); if (one) out.push(one); }
178
+ return out;
179
+ }
180
+ /*
181
+ * ⟨q-b7198479⟩ — THE LOOKUP IS NOT BOUNDED BY A WINDOW. `git log -n 400` missed
182
+ * #245's squash 777 commits back on an 1806-commit main and the verb then
183
+ * asserted "#245 is not on origin/main" as a fact — a truncated search reported
184
+ * as an absence, at the verb that writes the delivery record, and worded with a
185
+ * mechanism (target tip vs merge base) that had nothing to do with it. At the
186
+ * fleet's speed (~200 record commits a day) 400 is about two days, so it fires
187
+ * precisely on the oldest rows, the ones closed late.
188
+ *
189
+ * Now: `git log --grep` over the WHOLE of the ref, then the SUBJECT is judged
190
+ * BY IDENTITY, the rule #327's mergeOf and the closing-line grammar already use:
191
+ * the landing is the commit whose subject ENDS with the forge's `(#N)` marker.
192
+ * A bare `#N` anywhere is a mention, never a landing — qa measured the first
193
+ * cut of this (`\(#N\)|#N\b`, newest first) on live origin/main: 149 of 322
194
+ * squash-merged PRs resolved to their CLOSURE or board commit ("docs(record):
195
+ * close … by content on #245"), which carry the bare number in the subject and
196
+ * sit newer than the squash. Among trailing-(#N) subjects the OLDEST wins: a
197
+ * hand-written "docs: log Task 10 (#164)" copied the marker 36 s after #164's
198
+ * squash and would otherwise be taken for it. The one PR of 323 on this main
199
+ * that landed as a merge commit (#108, "Merge pull request #108 from …") is the
200
+ * second identity form — the forge's own, not a mention — and is the last
201
+ * resort, consulted only when no trailing form exists. A miss reports what was
202
+ * searched — every subject on the ref — never a mechanism it did not test.
203
+ */
204
+ export function landingCommitOf(repo: string, ref: string, n: string): { sha: string | null; searched: number } {
205
+ const searched = Number(git(repo, ["rev-list", "--count", ref])) || 0;
206
+ // git's --grep is a basic regex with no `\b`; identity is decided on the SUBJECT below.
207
+ const out = git(repo, ["log", ref, "--format=%H%x00%s", `--grep=#${n}`]);
208
+ const trailing = new RegExp(`\\(#${n}\\)\\s*$`);
209
+ const mergeForm = new RegExp(`^Merge pull request #${n}(?:\\s|$)`);
210
+ let landing: string | null = null;
211
+ let merge: string | null = null;
212
+ for (const line of out.split("\n")) {
213
+ const [sha, subject = ""] = line.split("\x00");
214
+ if (!sha) continue;
215
+ if (trailing.test(subject)) landing = sha; // newest first: the last hit is the OLDEST
216
+ else if (!merge && mergeForm.test(subject)) merge = sha;
217
+ }
218
+ return { sha: landing ?? merge, searched };
219
+ }
172
220
 
173
221
  /**
174
222
  * The `owner/repo` a BARE `#N` in this repo's docs should be read as naming —
@@ -1015,19 +1063,31 @@ export async function landTool(
1015
1063
  const ref = `origin/${base}`;
1016
1064
  let landedIn: string | null = null;
1017
1065
  let reason: string | null = null;
1066
+ // ⟨q-cbace757⟩ — every cited PR must be on the ref, not only the first.
1067
+ const numbers = prNumbersOf(args.pr);
1068
+ const landings: Record<string, string> = {};
1069
+ let searched = 0;
1070
+ const missing: string[] = [];
1018
1071
  try {
1019
- const subjects = git(repo, ["log", "-n", "400", "--format=%H %s", ref]);
1020
- const hit = subjects.split("\n").find((l) => new RegExp(`\\(#${n}\\)|#${n}\\b`).test(l));
1021
- landedIn = hit ? (hit.split(" ")[0] as string) : null;
1072
+ for (const num of numbers) {
1073
+ const found = landingCommitOf(repo, ref, num);
1074
+ searched = found.searched;
1075
+ if (found.sha) landings[num] = found.sha; else missing.push(num);
1076
+ }
1077
+ landedIn = landings[n] ?? null;
1022
1078
  } catch (e) {
1023
1079
  reason = `could not read ${ref} (${String((e as Error).message).split("\n")[0]}) — NOT checked, which is not the same as checked and absent`;
1024
1080
  }
1025
1081
  if (reason) return { ok: false as const, error: reason };
1026
- if (!landedIn) {
1082
+ if (!landedIn || missing.length) {
1027
1083
  return {
1028
1084
  ok: false as const,
1029
- error: `#${n} is not on ${ref} — refusing to record it as landed. Compared against the TARGET TIP (${ref}), not a merge base: an item merged after this branch was cut is missing from the base too.`,
1085
+ error:
1086
+ `${missing.map((m) => `#${m}`).join(", ")} not found on ${ref}: none of the ${searched} commit subject(s) on ${ref} carries ` +
1087
+ `${missing.map((m) => `"(#${m})"`).join(" or ")} — refusing to record it as landed. The whole of ${ref} was searched, not a window; ` +
1088
+ `a PR merged under another number or never merged reads the same here — check \`gh pr view\`.`,
1030
1089
  comparedAgainst: ref,
1090
+ searched,
1031
1091
  };
1032
1092
  }
1033
1093
 
@@ -1259,7 +1319,9 @@ export async function landTool(
1259
1319
  if (args.write && target) {
1260
1320
  const after = readDoc(repo, DONE_DOC);
1261
1321
  const recordText = after?.text ?? "";
1262
- const ev: RecordEvent = { kind: "item", target: target.id, ref: args.pr, summary: summarize(originalText ?? "") };
1322
+ // ⟨q-cbace757⟩ — one event, every cited ref; each checked against the record on its own.
1323
+ const refs = prRefsIn(args.pr);
1324
+ const ev: RecordEvent = { kind: "item", target: target.id, ref: refs.length ? refs.join(", ") : args.pr, summary: summarize(originalText ?? ""), ...(refs.length > 1 ? { refs } : {}) };
1263
1325
  const derived = eventIsDerived(recordText, ev);
1264
1326
  if (!derived.ok) {
1265
1327
  events.refused.push(derived.error);
@@ -1,5 +1,5 @@
1
1
  import { detachAgentTool } from "./transport.js";
2
- import { isLocallyProbeable, isRemoteTmuxKind, targetOf } from "../transports/index.js";
2
+ import { isLocallyProbeable, isRemoteTmuxKind, targetOf, HERDR, HerdrTransport, activeTransport } from "../transports/index.js";
3
3
  import { readAway, secondCoordinatorRefusal } from "./away.js";
4
4
  import { randomUUID } from "node:crypto";
5
5
  import { existsSync, openSync, statSync, watch } from "node:fs";
@@ -525,6 +525,19 @@ export function isMarkerLive(marker: TransportMarker, reg: AgentRegistry, now: n
525
525
  const entry = reg[marker.agentId];
526
526
  return !!entry && now - entry.lastHeartbeat < STALE_MS;
527
527
  }
528
+ // Phase 5.4 Task 4 — a herdr marker has no pid (0): liveness is the PANE, asked of
529
+ // herdr itself. "Could not ask" keeps the marker (unknown is not dead); only herdr
530
+ // saying pane_not_found lets the registry drop it.
531
+ if (marker.transport === HERDR) {
532
+ const t = targetOf(marker);
533
+ if (!t) return false;
534
+ // Ask through the WIRED herdr transport (its runner is what tests inject and what the
535
+ // fleet configured). A server with no herdr transport wired cannot ask, and "cannot
536
+ // ask" keeps the marker: the herdr-configured server reaps its own dead panes.
537
+ const active = activeTransport();
538
+ const exists = active?.kind === HERDR && active instanceof HerdrTransport ? active.paneExists(t) : null;
539
+ return exists !== false;
540
+ }
528
541
  return isPidAlive(marker.pid);
529
542
  }
530
543
 
@@ -104,7 +104,11 @@ export function seatBuildOf(input: { agentId: string; marker: TransportMarker |
104
104
  // ---- pusher half
105
105
  let pusher: SeatBuild["pusher"];
106
106
  const empty = { pid: null, alive: null, keyedByAgentArg: null, startedAt: null, hookPath: null, hookMtime: null, sameTreeAsServer: null, current: null };
107
- if (!marker || typeof marker.pid !== "number") {
107
+ if (marker && marker.transport === "herdr") {
108
+ // Phase 5.4 Task 4 — a herdr seat has NO pusher: delivery is in-process by the server,
109
+ // so the seat's build is the server half alone, and this says so instead of reading pid 0.
110
+ pusher = { ...empty, note: `herdr socket transport (pane ${marker.target ?? marker.tmuxTarget ?? "?"}): no pusher process — delivery is in-process by the answering server, so the server half is the whole seat` };
111
+ } else if (!marker || typeof marker.pid !== "number") {
108
112
  pusher = { ...empty, note: "no transport marker for this seat — no pusher pid to read" };
109
113
  } else {
110
114
  const facts = ps(marker.pid);
@@ -183,6 +187,9 @@ export function seatBuildOf(input: { agentId: string; marker: TransportMarker |
183
187
  } else if (s === false && p === true) {
184
188
  verdict = "half-restarted";
185
189
  statement = `${agentId}: HALF-RESTARTED the other way — pusher on the installed hook, server started before the ${day(server!.buildMtime!)} install. Reload the server (relaunch the MCP client for this seat).`;
190
+ } else if (marker?.transport === "herdr" && s !== null) {
191
+ verdict = s ? "current" : "stale";
192
+ statement = `${agentId}: ${s ? "current" : "stale"} — herdr socket transport, no pusher; the server ${s ? "started after" : "predates"} the ${day(server!.buildMtime!)} install and is the whole seat.`;
186
193
  } else if (s === null && p !== null) {
187
194
  verdict = "unknown";
188
195
  statement = `${agentId}: pusher ${p ? "current" : "STALE — started before the installed hook"}; server UNOBSERVABLE from here (${srv.note}).`;
@@ -2,6 +2,8 @@ import { loadLiveTransports, isMarkerLive, isPidAlive } from "./registry.js";
2
2
  import {
3
3
  TMUX_PUSH,
4
4
  registerTmuxHost,
5
+ activeTransport,
6
+ HERDR,
5
7
  type TmuxHost,
6
8
  isLocallyProbeable,
7
9
  isTmuxKind,
@@ -480,6 +482,20 @@ export async function sendCommandTool(args: {
480
482
  // DM: target must itself be tmux-attached.
481
483
  if (args.to) {
482
484
  const marker = liveTmux.get(args.to);
485
+ // Phase 5.4 Task 4 — a herdr seat takes the control IN-PROCESS: no inbox message, no
486
+ // pusher receipt; the transport types it, verifies it left the input, and answers.
487
+ const herdrMarker = marker ? undefined : (await loadLiveTransports()).get(args.to);
488
+ const activeT = activeTransport();
489
+ if (herdrMarker?.transport === HERDR) {
490
+ if (activeT?.kind !== HERDR) {
491
+ return { ok: false, error: `'${args.to}' is attached through herdr but this server's active transport is ${activeT?.kind ?? "none"} — a mixed fleet; the server configured for herdr must send this control` };
492
+ }
493
+ const r = await activeT.sendControl(herdrMarker, cmd as "clear" | "compact" | "reload-skills");
494
+ const reminderMs = cmd === "clear" ? args.reminderMs ?? 3000 : 0;
495
+ if (r.ok && reminderMs > 0) scheduleReminders(args.from, [args.to], reminderMs, args.reminderText);
496
+ const extra = r as { enters?: number; note?: string };
497
+ return { ok: r.ok, command: text, delivered: r.ok ? [args.to] : [], transport: HERDR, delivery: r.ok ? "confirmed" : "refused", ...(r.error ? { error: r.error } : {}), ...(extra.enters !== undefined ? { enters: extra.enters } : {}), ...(extra.note ? { note: extra.note } : {}) };
498
+ }
483
499
  if (!marker) {
484
500
  return {
485
501
  ok: false,
@@ -648,6 +664,32 @@ export async function attachAgentTool(args: {
648
664
  debounceMs?: number;
649
665
  }) {
650
666
  // Resolve target: explicit arg > MCP server's own TMUX_PANE env.
667
+ // Phase 5.4 Task 4 — a fleet configured for herdr attaches through the transport: no
668
+ // pusher is spawned, the marker carries pid 0 and a herdr pane id, and every refusal
669
+ // names herdr (an absent binary is never a silent fall-through to tmux).
670
+ const activeT = activeTransport();
671
+ if (activeT?.kind === HERDR) {
672
+ const existing = await readJson<TransportMarker | null>(transportFile(args.agentId), null);
673
+ if (existing) await deleteFile(transportFile(args.agentId));
674
+ let marker: TransportMarker;
675
+ try {
676
+ marker = await activeT.attach({ agentId: args.agentId, target: args.tmuxTarget, includeRoom: args.includeRoom, allowlist: args.allowlist, debounceMs: args.debounceMs });
677
+ } catch (e) {
678
+ return { ok: false, error: (e as Error).message };
679
+ }
680
+ marker = { ...marker, serverBuildMtime: SERVER_BUILD_MTIME };
681
+ await fsp.mkdir(path.dirname(transportFile(args.agentId)), { recursive: true });
682
+ await updateJson<TransportMarker>(transportFile(args.agentId), marker, () => marker);
683
+ return {
684
+ ok: true,
685
+ agentId: args.agentId,
686
+ transport: HERDR,
687
+ target: marker.target,
688
+ pid: 0,
689
+ rooms: marker.rooms,
690
+ note: "herdr socket transport: no pusher process — delivery is made in-process by this server through herdr's socket API; liveness is herdr's own pane status",
691
+ };
692
+ }
651
693
  const target = args.tmuxTarget ?? process.env.TMUX_PANE;
652
694
  if (!target) {
653
695
  return {
@@ -808,6 +850,12 @@ export async function detachAgentTool(args: { agentId: string }) {
808
850
  const marker = await readJson<TransportMarker | null>(transportFile(args.agentId), null);
809
851
  let killed = false;
810
852
  let unverified = false;
853
+ if (marker?.transport === HERDR) {
854
+ // No pusher to kill: the socket transport has no process of its own. The marker is
855
+ // the whole attachment, and removing it is the detach.
856
+ await deleteFile(transportFile(args.agentId));
857
+ return { ok: true, agentId: args.agentId, killed: false, hadMarker: true, transport: HERDR, note: "herdr socket transport: no pusher process to stop; marker removed" };
858
+ }
811
859
  if (marker && isPidAlive(marker.pid)) {
812
860
  // ALIVE IS NOT ENOUGH — VERIFY IT IS A PUSHER BEFORE SIGNALLING IT.
813
861
  //