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.
- package/dist/capabilities.js +20 -0
- package/dist/capabilities.js.map +1 -1
- package/dist/tools/event-kinds.js.map +1 -1
- package/dist/tools/events.js +9 -2
- package/dist/tools/events.js.map +1 -1
- package/dist/tools/herdr-delivery.js +99 -0
- package/dist/tools/herdr-delivery.js.map +1 -0
- package/dist/tools/messaging.js +8 -0
- package/dist/tools/messaging.js.map +1 -1
- package/dist/tools/records.js +79 -6
- package/dist/tools/records.js.map +1 -1
- package/dist/tools/registry.js +15 -1
- package/dist/tools/registry.js.map +1 -1
- package/dist/tools/seat-build.js +10 -1
- package/dist/tools/seat-build.js.map +1 -1
- package/dist/tools/transport.js +50 -1
- package/dist/tools/transport.js.map +1 -1
- package/dist/transports/herdr.js +297 -0
- package/dist/transports/herdr.js.map +1 -0
- package/dist/transports/index.js +10 -4
- package/dist/transports/index.js.map +1 -1
- package/package.json +1 -1
- package/src/capabilities.ts +20 -0
- package/src/tools/event-kinds.ts +2 -1
- package/src/tools/events.ts +9 -2
- package/src/tools/herdr-delivery.ts +87 -0
- package/src/tools/messaging.ts +8 -0
- package/src/tools/records.ts +68 -6
- package/src/tools/registry.ts +14 -1
- package/src/tools/seat-build.ts +8 -1
- package/src/tools/transport.ts +48 -0
- package/src/transports/herdr.ts +311 -0
- package/src/transports/index.ts +10 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"herdr.js","sourceRoot":"","sources":["../../src/transports/herdr.ts"],"names":[],"mappings":"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"}
|
package/dist/transports/index.js
CHANGED
|
@@ -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
|
|
31
|
-
//
|
|
32
|
-
|
|
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":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAAsC,MAAM,YAAY,CAAC;
|
|
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.
|
|
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": {
|
package/src/capabilities.ts
CHANGED
|
@@ -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",
|
package/src/tools/event-kinds.ts
CHANGED
|
@@ -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
|
-
|
|
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.
|
package/src/tools/events.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
+
}
|
package/src/tools/messaging.ts
CHANGED
|
@@ -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 } : {}) };
|
package/src/tools/records.ts
CHANGED
|
@@ -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
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
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:
|
|
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
|
-
|
|
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);
|
package/src/tools/registry.ts
CHANGED
|
@@ -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
|
|
package/src/tools/seat-build.ts
CHANGED
|
@@ -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 (
|
|
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}).`;
|
package/src/tools/transport.ts
CHANGED
|
@@ -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
|
//
|