agent-coord-mcp 0.26.4 → 0.26.6

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,545 @@
1
+ /*
2
+ * Record verbs: `next_unblocked` · `claim` · `land`.
3
+ *
4
+ * These turn coordinator RECIPES into bus VERBS, so a forgotten step fails closed
5
+ * instead of looking healthy. The measured cost of the recipe: twelve merges went
6
+ * 23 hours unlogged, and the queue/DONE loop failed three times in nine hours with
7
+ * the rule written down each time.
8
+ *
9
+ * THE MARKDOWN IS AUTHORITATIVE (ADR-003). These read and write the documents
10
+ * directly rather than the derived store: a store import is a second source of
11
+ * truth, and the failure this phase exists to remove is exactly a second source
12
+ * that drifts.
13
+ */
14
+ import { execFileSync } from "node:child_process";
15
+ import { existsSync, readFileSync, writeFileSync } from "node:fs";
16
+ import path from "node:path";
17
+ import { z } from "zod";
18
+ import { parseWorkDoc, renderWorkDoc, queueItemsOf, doneEntriesOf, phaseCitationsIn, newlyTickedInDiff, } from "@davidbalzan/groundwork-seam";
19
+ import { ensureWorktreeTool } from "./worktrees.js";
20
+ import { haltState } from "./stall.js";
21
+ const QUEUE_DOC = "docs/QUEUE.md";
22
+ const DONE_DOC = "docs/DONE.md";
23
+ const BOARD_DOC = "docs/WORKSTREAMS.md";
24
+ const PRIORITY_ORDER = { P1: 0, P2: 1, P3: 2 };
25
+ const readDoc = (repo, rel) => {
26
+ const p = path.join(repo, rel);
27
+ if (!existsSync(p))
28
+ return null;
29
+ const text = readFileSync(p, "utf8");
30
+ return { text, doc: parseWorkDoc(text) };
31
+ };
32
+ /**
33
+ * Write a document back HUNK-FAITHFULLY: everything the seam did not model is
34
+ * replayed verbatim, and an UNCHANGED file is not written at all.
35
+ *
36
+ * The round trip is byte-exact on all three live documents (measured before this
37
+ * was built, not assumed). Re-rendering an untouched file would still be a write,
38
+ * and a write is a diff someone has to review — so the no-op case returns false.
39
+ */
40
+ function writeDoc(repo, rel, doc, original) {
41
+ const out = renderWorkDoc(doc);
42
+ if (out === original)
43
+ return false;
44
+ writeFileSync(path.join(repo, rel), out);
45
+ return true;
46
+ }
47
+ const git = (repo, args) => execFileSync("git", args, { cwd: repo, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
48
+ /** `#123` / `owner/repo#123` → "123". */
49
+ function prNumber(pr) {
50
+ const m = /#(\d+)\b/.exec(String(pr)) ?? /^(\d+)$/.exec(String(pr).trim());
51
+ return m ? m[1] : null;
52
+ }
53
+ // ---------- blocked / no-downstream ----------
54
+ const BLOCKED_RE = /\bblocked (?:by|on)\b[:\s]*([^\s·,.;]+)/i;
55
+ /** The blocker an item names, if it names one. */
56
+ export function blockedBy(item) {
57
+ const m = BLOCKED_RE.exec(String(item.text));
58
+ return m ? m[1].replace(/[`*]/g, "") : null;
59
+ }
60
+ const keyOf = (i) => String(i.text).replace(/\s+/g, " ").slice(0, 60);
61
+ /**
62
+ * A DONE summary a human would have written.
63
+ *
64
+ * The first `write:true` run produced
65
+ * `- [x] Kit: **THE ROOT GATE HAND-LISTS ITS FOUR PACKAGES BY NAME WH — …`:
66
+ * truncated MID-WORD at 60 characters, leaving an unbalanced `**`. It parses, so
67
+ * the glyph contract accepts it, and it reads as a line someone abandoned
68
+ * half-way. Cut on a word boundary and drop emphasis markers rather than leaving
69
+ * half of one.
70
+ */
71
+ export function summarize(text, max = 96) {
72
+ const flat = String(text).replace(/\s+/g, " ").replace(/\*\*/g, "").trim();
73
+ if (flat.length <= max)
74
+ return flat;
75
+ const cut = flat.slice(0, max);
76
+ const at = cut.lastIndexOf(" ");
77
+ return `${(at > max * 0.6 ? cut.slice(0, at) : cut).replace(/[\s\-—·,;:]+$/, "")}…`;
78
+ }
79
+ /**
80
+ * Items nothing else waits on.
81
+ *
82
+ * "BLOCKS NOTHING" IS NOT "COSTS NOTHING TO DEFER" — and an item that blocks
83
+ * nothing also ANNOUNCES nothing when it stalls. Everything else surfaces through
84
+ * the thing waiting on it; these have no such witness, so they go missing silently
85
+ * and their absence is found by someone re-reading the plan. That is why they are
86
+ * a SEPARATE AXIS here and not folded into the skipped-because-blocked list: those
87
+ * are two different states with two different remedies, and one list covering both
88
+ * leaves the reader to infer which.
89
+ *
90
+ * LIMIT, stated because it bounds the claim: dependency is detected from the TEXT.
91
+ * An unstated dependency is invisible to this, so "no downstream" means "nothing in
92
+ * the queue SAYS it waits on this", never "nothing waits on this".
93
+ */
94
+ export function noDownstream(items) {
95
+ const open = items.filter((i) => !i.done);
96
+ const named = new Set();
97
+ for (const i of open) {
98
+ const b = blockedBy(i);
99
+ if (b)
100
+ named.add(b.toLowerCase());
101
+ }
102
+ return open.filter((i) => {
103
+ if (blockedBy(i))
104
+ return false; // it waits on something: not this axis
105
+ const key = keyOf(i).toLowerCase();
106
+ for (const n of named)
107
+ if (n.length > 3 && key.includes(n))
108
+ return false;
109
+ return true;
110
+ });
111
+ }
112
+ // ---------- next_unblocked ----------
113
+ export const nextUnblockedSchema = { project: z.string().min(1), repo: z.string().optional() };
114
+ export async function nextUnblockedTool(args) {
115
+ // A HALT IS A NAMED STATE AND IT BLOCKS THE LANE, not a suggestion. Handing out
116
+ // the next item during a board cutover or a cited BLOCKER is how work lands on
117
+ // a base nobody meant to be building on.
118
+ const halt = haltState();
119
+ if (halt.halted) {
120
+ return {
121
+ ok: false,
122
+ error: `HALTED by ${halt.by}: ${halt.reason}. No item is handed out while a halt is set — clear it with set_halt{clear:true} when the named condition is gone.`,
123
+ halted: true,
124
+ };
125
+ }
126
+ const repo = args.repo ?? process.cwd();
127
+ const q = readDoc(repo, QUEUE_DOC);
128
+ if (!q)
129
+ return { ok: false, error: `no ${QUEUE_DOC} under '${repo}'` };
130
+ const items = queueItemsOf(q.doc);
131
+ const open = items.filter((i) => !i.done);
132
+ const ranked = open
133
+ .map((i, idx) => ({ i, idx }))
134
+ .sort((a, b) => (PRIORITY_ORDER[a.i.priority ?? "P3"] ?? 3) - (PRIORITY_ORDER[b.i.priority ?? "P3"] ?? 3) || a.idx - b.idx);
135
+ const skipped = [];
136
+ let pick = null;
137
+ for (const { i } of ranked) {
138
+ const b = blockedBy(i);
139
+ // NEVER STALL THE LANE waiting on a reorder: a blocked top item is skipped,
140
+ // visibly, and the next unblocked one is taken.
141
+ if (b) {
142
+ skipped.push({ item: keyOf(i), blockedBy: b });
143
+ continue;
144
+ }
145
+ pick = i;
146
+ break;
147
+ }
148
+ const silent = noDownstream(open);
149
+ // AN AXIS THAT FIRES ON EVERYTHING IS NOISE. If no item in the queue declares a
150
+ // dependency, then "nothing waits on this" is true of every item and the axis
151
+ // cannot discriminate — listing all of them trains the reader to skim, which is
152
+ // the severity finding one file over. Say the axis is uninformative instead.
153
+ const undiscriminating = silent.length === open.length && open.length > 1;
154
+ return {
155
+ ok: true,
156
+ project: args.project,
157
+ open: open.length,
158
+ next: pick ? { id: pick.id, priority: pick.priority, text: pick.text } : null,
159
+ skipped,
160
+ boardHunks: skipped.map((s) => `⏭ skipped — blocked by ${s.blockedBy}`),
161
+ // A SEPARATE AXIS, deliberately. See noDownstream().
162
+ noDownstream: undiscriminating
163
+ ? {
164
+ count: silent.length,
165
+ items: [],
166
+ why: `NO ITEM IN THIS QUEUE DECLARES A DEPENDENCY, so "nothing waits on this" is true of all ${open.length} and this axis ` +
167
+ "cannot discriminate. Reporting every item would train you to skim it. Every item's absence here is equally silent, " +
168
+ "which is a fact about the QUEUE rather than about any item — declare dependencies (`blocked by <id>`) and this becomes useful.",
169
+ }
170
+ : {
171
+ count: silent.length,
172
+ items: silent.slice(0, 10).map((i) => ({ id: i.id, priority: i.priority, key: keyOf(i) })),
173
+ why: "nothing in the queue says it waits on these, so their absence is SILENT — they need an explicit check at each stage boundary. " +
174
+ "Detected from item text: an unstated dependency is invisible here.",
175
+ },
176
+ };
177
+ }
178
+ // ---------- claim ----------
179
+ export const claimSchema = {
180
+ project: z.string().min(1),
181
+ agentId: z.string().min(1),
182
+ itemId: z.string().optional(),
183
+ repo: z.string().optional(),
184
+ base: z.string().optional(),
185
+ task: z.string().optional(),
186
+ };
187
+ export async function claimTool(args) {
188
+ const halt = haltState();
189
+ if (halt.halted) {
190
+ return {
191
+ ok: false,
192
+ error: `HALTED by ${halt.by}: ${halt.reason}. Claiming is refused while a halt is set.`,
193
+ halted: true,
194
+ };
195
+ }
196
+ const repo = args.repo ?? process.cwd();
197
+ const q = readDoc(repo, QUEUE_DOC);
198
+ if (!q)
199
+ return { ok: false, error: `no ${QUEUE_DOC} under '${repo}'` };
200
+ const items = queueItemsOf(q.doc);
201
+ let item = args.itemId ? items.find((i) => i.id === args.itemId) : null;
202
+ if (args.itemId && !item)
203
+ return { ok: false, error: `no queue item with id '${args.itemId}'` };
204
+ if (!item) {
205
+ const next = await nextUnblockedTool({ project: args.project, repo });
206
+ if (!next.ok || !next.next)
207
+ return { ok: false, error: "no unblocked item to claim" };
208
+ item = items.find((i) => i.id === next.next.id) ?? null;
209
+ }
210
+ if (!item)
211
+ return { ok: false, error: "no unblocked item to claim" };
212
+ // TASK 1 LANDED, SO THE PLACEHOLDER IS GONE RATHER THAN LEFT SWITCHED OFF.
213
+ //
214
+ // While `ensure_worktree` did not exist this returned a loud warning that the
215
+ // worktree was NOT ensured — conditional on the verb's absence, because a
216
+ // warning that never clears stops being read. The verb exists now, so `claim`
217
+ // CALLS it: the interface is unchanged and the gap is closed rather than
218
+ // annotated. An interface with a placeholder nobody removes is how a temporary
219
+ // state becomes canon.
220
+ //
221
+ // A worktree that cannot be ensured is a REFUSAL, not a warning. Binding an
222
+ // item to an agent with nowhere isolated to work is the shared-checkout failure
223
+ // this pair exists to prevent.
224
+ const wt = await ensureWorktreeTool({
225
+ agentId: args.agentId,
226
+ repo,
227
+ base: args.base ?? "main",
228
+ task: args.task,
229
+ });
230
+ if (!wt.ok) {
231
+ return {
232
+ ok: false,
233
+ error: `cannot claim: no isolated worktree — ${wt.error}`,
234
+ item: { id: item.id, priority: item.priority },
235
+ };
236
+ }
237
+ return {
238
+ ok: true,
239
+ project: args.project,
240
+ agentId: args.agentId,
241
+ item: { id: item.id, priority: item.priority, text: item.text },
242
+ boardHunk: `| ${keyOf(item)} | ${args.agentId} | \`${wt.branch}\` · ${wt.path} | 🚧 In Progress | — | claimed |`,
243
+ worktreeEnsured: true,
244
+ worktree: { path: wt.path, sha: wt.sha, branch: wt.branch, created: wt.created, base: wt.base },
245
+ };
246
+ }
247
+ // ---------- land ----------
248
+ export const landSchema = {
249
+ project: z.string().min(1),
250
+ pr: z.string().min(1),
251
+ queueItemId: z.string().optional(),
252
+ repo: z.string().optional(),
253
+ base: z.string().optional(),
254
+ write: z.boolean().optional(),
255
+ };
256
+ export async function landTool(args) {
257
+ const repo = args.repo ?? process.cwd();
258
+ const base = args.base ?? "main";
259
+ const n = prNumber(args.pr);
260
+ // A CITED PR OR REFUSE. A `DONE:` without a ref cannot be tied to anything by
261
+ // anyone, ever — which is its own finding, not a formatting preference.
262
+ if (!n) {
263
+ return { ok: false, error: `'${args.pr}' names no PR number — a DONE entry with no ref can never be tied to the work. Cite owner/repo#N.` };
264
+ }
265
+ // MERGED ON THE TARGET'S TIP, NOT THE MERGE BASE.
266
+ //
267
+ // "What does the thing I am merging INTO have that I do not?" is answered only
268
+ // by the target's tip: the merge base is the point the branch DIVERGED from, so
269
+ // anything landed after the cut is missing from it too — comparing against it is
270
+ // exactly as blind as comparing against the branch (kit#102/#103). Squash merges
271
+ // leave no ancestor either, so the citation in the merge SUBJECT is the tie.
272
+ const ref = `origin/${base}`;
273
+ let landedIn = null;
274
+ let reason = null;
275
+ try {
276
+ const subjects = git(repo, ["log", "-n", "400", "--format=%H %s", ref]);
277
+ const hit = subjects.split("\n").find((l) => new RegExp(`\\(#${n}\\)|#${n}\\b`).test(l));
278
+ landedIn = hit ? hit.split(" ")[0] : null;
279
+ }
280
+ catch (e) {
281
+ reason = `could not read ${ref} (${String(e.message).split("\n")[0]}) — NOT checked, which is not the same as checked and absent`;
282
+ }
283
+ if (reason)
284
+ return { ok: false, error: reason };
285
+ if (!landedIn) {
286
+ return {
287
+ ok: false,
288
+ 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.`,
289
+ comparedAgainst: ref,
290
+ };
291
+ }
292
+ const q = readDoc(repo, QUEUE_DOC);
293
+ const d = readDoc(repo, DONE_DOC);
294
+ if (!q || !d)
295
+ return { ok: false, error: `need both ${QUEUE_DOC} and ${DONE_DOC} under '${repo}'` };
296
+ const items = queueItemsOf(q.doc);
297
+ // WHICH ITEM A PR CLOSES IS A JUDGEMENT, AND GUESSING IT CLOSED THE WRONG ONE.
298
+ //
299
+ // The first real use of this verb matched `#116` against an item that merely
300
+ // MENTIONED #116 in its body — an item about seam ids — and reported it closed.
301
+ // With write:true it would have closed unrelated, still-open work. That is the
302
+ // occurrence-vs-position defect I fixed for sweep tags, reintroduced here in a
303
+ // different matcher hours later: a citation IN an item's text is not a claim
304
+ // that the item is closed BY it.
305
+ //
306
+ // There is no positional convention to anchor on, so the honest fix is not a
307
+ // better guess: `land` CLOSES ONLY WHAT IT IS TOLD TO CLOSE. Without an explicit
308
+ // `queueItemId` it closes nothing and reports the candidates for the caller to
309
+ // pick, saying so.
310
+ const candidates = items.filter((i) => !i.done && new RegExp(`#${n}\\b`).test(String(i.text)));
311
+ const target = args.queueItemId ? items.find((i) => i.id === args.queueItemId) : null;
312
+ if (args.queueItemId && !target)
313
+ return { ok: false, error: `no queue item with id '${args.queueItemId}'` };
314
+ // CLOSE = STATUS ONLY. The item's priority and body BYTES are untouched: the
315
+ // seam re-renders `- [x] (P2) <text>` from the same text it parsed, so closing
316
+ // cannot reword an item. That is asserted by a fixture, not by inspection.
317
+ let queueChanged = false;
318
+ if (target) {
319
+ target.done = true;
320
+ queueChanged = true;
321
+ }
322
+ const already = doneEntriesOf(d.doc).some((e) => new RegExp(`#${n}\\b`).test(String(e.ref ?? "")));
323
+ // A DONE LINE A HUMAN WOULD NOT HAVE WRITTEN IS NOT A DONE LINE.
324
+ //
325
+ // First real use produced `- [x] PR #117 — #117 · 2026-08-28`: no description of
326
+ // the work, and a BARE ref where every existing entry carries `owner/repo#N`.
327
+ // The glyph contract parses it, so a shape check would pass it — and it tells a
328
+ // reader nothing, which is the whole job of the file.
329
+ //
330
+ // So: the summary comes from the item being closed, and a bare `#N` is reported
331
+ // as UNDER-QUALIFIED rather than silently written.
332
+ const bareRef = !/[\w.-]+\/[\w.-]+#\d+/.test(String(args.pr));
333
+ const summary = target ? summarize(target.text) : null;
334
+ const doneLine = already || !summary ? null : `- [x] ${summary} — ${args.pr} · ${new Date().toISOString().slice(0, 10)}`;
335
+ // APPEND TO DONE.md — the half this verb exists for.
336
+ //
337
+ // The first `write:true` run closed the queue item and wrote NOTHING to
338
+ // DONE.md: it did half the loop, and the half it skipped is the one that failed
339
+ // three times in nine hours and left twelve merges unlogged for 23 hours. A verb
340
+ // built to close that gap that does not write DONE is the gap with a tool in
341
+ // front of it.
342
+ //
343
+ // Appended as TEXT to the last done block so the rest of the file is replayed
344
+ // byte-for-byte: `renderWorkDoc` reproduces every unmodelled line verbatim, and
345
+ // an entry added to the record model renders through the pinned glyph contract.
346
+ const wrote = [];
347
+ if (args.write) {
348
+ if (queueChanged && writeDoc(repo, QUEUE_DOC, q.doc, q.text))
349
+ wrote.push(QUEUE_DOC);
350
+ if (doneLine) {
351
+ const blocks = d.doc.blocks;
352
+ let last = -1;
353
+ for (let i = 0; i < blocks.length; i++)
354
+ if (blocks[i]?.kind === "done")
355
+ last = i;
356
+ if (last === -1) {
357
+ return {
358
+ ok: false,
359
+ error: `${DONE_DOC} has no parsed done block to append to — refusing to guess where the entry goes. A DONE.md that parses to zero entries is a defect in the log, not an empty log.`,
360
+ };
361
+ }
362
+ const block = blocks[last];
363
+ const parsed = parseWorkDoc(`## Done\n${doneLine}\n`);
364
+ const entry = doneEntriesOf(parsed)[0];
365
+ if (!entry) {
366
+ return { ok: false, error: `the composed DONE line does not parse as done.v1: ${doneLine}` };
367
+ }
368
+ block.entries.push(entry);
369
+ if (writeDoc(repo, DONE_DOC, d.doc, d.text))
370
+ wrote.push(DONE_DOC);
371
+ }
372
+ }
373
+ return {
374
+ ok: true,
375
+ project: args.project,
376
+ pr: `#${n}`,
377
+ comparedAgainst: ref,
378
+ landedIn: landedIn.slice(0, 8),
379
+ queueItem: target ? { id: target.id, closed: true, textUnchanged: true } : null,
380
+ candidates: target
381
+ ? undefined
382
+ : candidates.map((i) => ({ id: i.id, priority: i.priority, key: keyOf(i) })),
383
+ ...(target || !candidates.length
384
+ ? {}
385
+ : {
386
+ note_candidates: `${candidates.length} open item(s) MENTION #${n}; none was closed. A citation in an item's text is not a claim ` +
387
+ `that the item is closed by it — pass queueItemId to close one deliberately.`,
388
+ }),
389
+ doneEntry: doneLine,
390
+ ...(bareRef
391
+ ? {
392
+ refWarning: `'${args.pr}' is an UNDER-QUALIFIED ref — every entry in DONE.md carries owner/repo#N, and a bare #N does not ` +
393
+ `identify a repository. Pass the full ref; the glyph contract would parse the bare one and it would tell a reader nothing.`,
394
+ }
395
+ : {}),
396
+ ...(summary || already ? {} : { doneEntryWithheld: "no queue item named, so there is no description to write — a DONE line reading only 'PR #N' is not one a human would write" }),
397
+ alreadyLogged: already,
398
+ written: wrote,
399
+ note: args.write ? undefined : "reporting only — pass write:true to apply. The markdown is authoritative; a report is not a write.",
400
+ };
401
+ }
402
+ /**
403
+ * gh reports CheckRun as status+conclusion and StatusContext as a bare state,
404
+ * and a rollup routinely contains BOTH. Reading only one shape silently scores
405
+ * the other as unknown — so normalise explicitly and let anything unrecognised
406
+ * fall to `pending`, which refuses. An unreadable check is not a passing one.
407
+ */
408
+ export function normalizeChecks(rollup) {
409
+ return (rollup ?? []).map((r) => {
410
+ const c = (r ?? {});
411
+ const name = String(c.name ?? c.context ?? "(unnamed)");
412
+ const status = String(c.status ?? "").toUpperCase();
413
+ const raw = String(c.conclusion ?? c.state ?? "").toUpperCase();
414
+ if (status && status !== "COMPLETED")
415
+ return { name, state: status, verdict: "pending" };
416
+ if (raw === "SUCCESS")
417
+ return { name, state: raw, verdict: "pass" };
418
+ // NEUTRAL and SKIPPED are deliberately NOT passes. A check that declined to
419
+ // run has not evidenced anything, and scoring it green is the unread-input
420
+ // defect: reporting clean on something never read.
421
+ if (raw === "FAILURE" || raw === "ERROR" || raw === "TIMED_OUT" || raw === "CANCELLED" || raw === "ACTION_REQUIRED")
422
+ return { name, state: raw, verdict: "fail" };
423
+ return { name, state: raw || status || "UNKNOWN", verdict: "pending" };
424
+ });
425
+ }
426
+ export const mergeSchema = {
427
+ project: z.string().min(1),
428
+ pr: z.string().min(1),
429
+ repo: z.string().optional(),
430
+ method: z.enum(["squash", "merge", "rebase"]).optional(),
431
+ write: z.boolean().optional(),
432
+ };
433
+ const ghFacts = (repo, n) => {
434
+ const out = execFileSync("gh", ["pr", "view", n, "--json", "state,mergeable,statusCheckRollup"], {
435
+ cwd: repo,
436
+ encoding: "utf8",
437
+ stdio: ["ignore", "pipe", "ignore"],
438
+ });
439
+ const j = JSON.parse(out);
440
+ const gh = (args) => {
441
+ try {
442
+ return execFileSync("gh", args, { cwd: repo, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
443
+ }
444
+ catch {
445
+ return "";
446
+ }
447
+ };
448
+ // The citation must survive the MERGE, so what counts is what lands in
449
+ // history: the PR title (which becomes the squash subject) and the commit
450
+ // subjects. The body is included because a reviewer reads it, but a claim
451
+ // that lives only in a comment thread is not a record.
452
+ const meta = JSON.parse(gh(["pr", "view", n, "--json", "title,body,commits"]) || "{}");
453
+ const subjects = (meta.commits ?? [])
454
+ .map((c) => c.messageHeadline ?? "")
455
+ .join("\n");
456
+ return {
457
+ state: String(j.state ?? ""),
458
+ mergeable: String(j.mergeable ?? ""),
459
+ checks: j.statusCheckRollup ?? [],
460
+ diff: gh(["pr", "diff", n]),
461
+ citationText: [String(meta.title ?? ""), subjects, String(meta.body ?? "")].join("\n"),
462
+ };
463
+ };
464
+ const ghMerge = (repo, n, method) => {
465
+ execFileSync("gh", ["pr", "merge", n, `--${method}`, "--delete-branch"], {
466
+ cwd: repo,
467
+ encoding: "utf8",
468
+ stdio: ["ignore", "pipe", "ignore"],
469
+ });
470
+ };
471
+ export async function mergeTool(args, facts = ghFacts, doMerge = ghMerge) {
472
+ const repo = args.repo ?? process.cwd();
473
+ const n = prNumber(args.pr);
474
+ if (!n)
475
+ return { ok: false, error: `'${args.pr}' names no PR number. Cite owner/repo#N.` };
476
+ let f;
477
+ try {
478
+ f = facts(repo, n);
479
+ }
480
+ catch (e) {
481
+ // NOT CHECKED IS NOT CHECKED-AND-GREEN. If we cannot read the verdict we
482
+ // cannot have consumed it, and this verb's whole claim is that it did.
483
+ return {
484
+ ok: false,
485
+ error: `could not read the checks for #${n} (${String(e.message).split("\n")[0]}) — NOT read, which is not the same as read and passing.`,
486
+ };
487
+ }
488
+ const checks = normalizeChecks(f.checks);
489
+ const failed = checks.filter((c) => c.verdict === "fail");
490
+ const pending = checks.filter((c) => c.verdict === "pending");
491
+ // EVERY RETURN CARRIES THE POPULATION IT JUDGED. "All passed" over an empty
492
+ // set is the sentence this verb exists to make unsayable.
493
+ const verdict = { population: checks.length, checks, failed: failed.map((c) => c.name), pending: pending.map((c) => c.name) };
494
+ if (f.state !== "OPEN")
495
+ return { ok: false, error: `#${n} is ${f.state || "not OPEN"} — nothing to merge.`, verdict };
496
+ // NO CHECKS IS NOT PASSING CHECKS.
497
+ //
498
+ // Same invariant as the stall clock: no alerts is not no stalls, and a clock
499
+ // that stopped reads quiet exactly like a system that is fine. An empty
500
+ // rollup is the strongest-looking green there is — zero failures — and it is
501
+ // evidence of nothing at all.
502
+ if (checks.length === 0)
503
+ return { ok: false, error: `#${n} reports ZERO checks. No checks is not passing checks — an empty rollup has zero failures and evidences nothing.`, verdict };
504
+ if (failed.length)
505
+ return { ok: false, error: `#${n} has ${failed.length} of ${checks.length} check(s) FAILING: ${failed.map((c) => c.name).join(", ")}. Refusing to merge.`, verdict };
506
+ if (pending.length)
507
+ return { ok: false, error: `#${n} has ${pending.length} of ${checks.length} check(s) not yet terminal: ${pending.map((c) => c.name).join(", ")}. A check still running has not returned a verdict to consume.`, verdict };
508
+ // EVERY NEWLY-TICKED CHECKBOX MUST BE CITED, CHECKED AT THE MERGE.
509
+ //
510
+ // Twice in one day a PR carried two things and left one unrecorded: kit#126
511
+ // ticked 4.4 and named it nowhere, and all five of Task 5's boxes shipped
512
+ // inside kit#127 alongside a CI fix. The pattern is not carelessness — a PR
513
+ // that fixes an incident AND delivers planned work gets the incident
514
+ // remembered and the work forgotten, because the incident is what everyone
515
+ // is talking about. Review caught neither; the coordinator found both after
516
+ // the fact.
517
+ //
518
+ // So it is checked where the record is actually made. `doctor`'s
519
+ // `phase-checkbox` finds this too, but only AFTER the merge, against DONE.md
520
+ // and merged subjects — by which time the claim is already in history
521
+ // unevidenced. The citation grammar is shared through seam rather than
522
+ // copied, because a copied grammar is two grammars the moment one is fixed.
523
+ const ticked = newlyTickedInDiff(f.diff ?? "");
524
+ if (ticked.size) {
525
+ const cited = phaseCitationsIn(f.citationText ?? "");
526
+ const uncited = [...ticked].filter((k) => !cited.has(k));
527
+ if (uncited.length) {
528
+ const names = uncited.map((k) => { const [p, id] = k.split(":"); return `Phase ${p} Task ${id}`; });
529
+ return {
530
+ ok: false,
531
+ error: `#${n} ticks ${ticked.size} phase checkbox(es) and ${uncited.length} of them are UNCITED: ${names.join(", ")}. ` +
532
+ `Once this merges, the tick claims progress that nothing in history evidences. Name them in the PR title or a commit subject (e.g. "${names[0]}") — the subject is what survives a squash merge.`,
533
+ verdict,
534
+ uncited: names,
535
+ };
536
+ }
537
+ }
538
+ if (f.mergeable === "CONFLICTING")
539
+ return { ok: false, error: `#${n} is CONFLICTING with its base.`, verdict };
540
+ if (!args.write)
541
+ return { ok: true, merged: false, verdict, note: `#${n} would merge: all ${checks.length} check(s) pass. Pass write:true to apply.` };
542
+ doMerge(repo, n, args.method ?? "squash");
543
+ return { ok: true, merged: true, verdict };
544
+ }
545
+ //# sourceMappingURL=records.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"records.js","sourceRoot":"","sources":["../../src/tools/records.ts"],"names":[],"mappings":"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"}
@@ -1,9 +1,10 @@
1
1
  import { detachAgentTool } from "./transport.js";
2
+ import { readAway, secondCoordinatorRefusal } from "./away.js";
2
3
  import { z } from "zod";
3
4
  import path from "node:path";
4
5
  import { AGENTS_FILE, ROOMS_FILE, appendJsonl, cursorFile, deleteFile, inboxFile, listTransportFiles, memberRooms, readJson, roomFile, rotateAgentToken, transportFile, TRANSPORT_DIR, updateJson, listSessionFiles, readJsonStrict, } from "../store.js";
5
6
  import { recordAuthorityFor, resolveRole, CANONICAL_ROLE_IDS, roleInputSchema } from "../roles.js";
6
- import { sysMsg, moveFile, STALE_MS, EVICT_MS, } from "./shared.js";
7
+ import { roomFeedOf, sysMsg, moveFile, STALE_MS, EVICT_MS, } from "./shared.js";
7
8
  // ---------- register ----------
8
9
  export const registerSchema = {
9
10
  agentId: z.string().min(1),
@@ -47,6 +48,13 @@ export async function registerTool(args) {
47
48
  const roleUpdate = resolveRoleUpdate(args.agentId, before[args.agentId], args.role);
48
49
  if (!roleUpdate.ok)
49
50
  return { ok: false, error: roleUpdate.error };
51
+ // 4.2 — a SECOND coordinator may not register while the first is away.
52
+ // Checked on the RESOLVED role, not the string the caller passed: the refusal
53
+ // has to see what the registry will actually record, or a spelling slips past
54
+ // the guard and lands as `coordinator` anyway.
55
+ const second = secondCoordinatorRefusal(readAway(), args.agentId, roleUpdate.roleId);
56
+ if (second)
57
+ return { ok: false, error: second };
50
58
  const reg = await updateJson(AGENTS_FILE, {}, (current) => {
51
59
  const now = Date.now();
52
60
  const existing = current[args.agentId];
@@ -207,7 +215,19 @@ export async function listAgentsTool() {
207
215
  ...heartbeatFields,
208
216
  capabilities: merged.length > 0 ? merged : undefined,
209
217
  transport: transport
210
- ? { kind: transport.transport, tmuxTarget: transport.tmuxTarget, pid: transport.pid }
218
+ ? {
219
+ kind: transport.transport,
220
+ tmuxTarget: transport.tmuxTarget,
221
+ pid: transport.pid,
222
+ // `attached` alone said nothing about WHAT is attached. A pusher
223
+ // started `--no-room` delivers DMs only, and its marker used to be
224
+ // indistinguishable from a full one — so an agent could sit with
225
+ // its room feed off while status read healthy (worker-2).
226
+ //
227
+ // Absent is UNKNOWN, never "on": an older pusher's marker cannot
228
+ // answer, and answering for it is how the original defect worked.
229
+ rooms: roomFeedOf(transport),
230
+ }
211
231
  : undefined,
212
232
  };
213
233
  });