@coreplane/switchboard 1.230.0 → 1.231.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/dist/cli.js CHANGED
@@ -443,8 +443,10 @@ var init_store = __esm({
443
443
  const contentType = res.headers.get("content-type") ?? "application/octet-stream";
444
444
  if (res.status === 416) {
445
445
  const total = /\/(\d+)\s*$/.exec(res.headers.get("content-range") ?? "");
446
- if (!total) throw new Error(`artifact store: GET ${key} answered HTTP 416 without the object's size`);
447
- return { unsatisfiable: true, size: Number(total[1]), contentType };
446
+ if (total) return { unsatisfiable: true, size: Number(total[1]), contentType };
447
+ const head = await this.head(key);
448
+ if (!head) return null;
449
+ return { unsatisfiable: true, size: head.size, contentType: head.contentType };
448
450
  }
449
451
  if (!res.ok || !res.body) throw new Error(`artifact store: GET ${key} answered HTTP ${res.status}`);
450
452
  if (res.status === 206) {
@@ -1616,7 +1618,18 @@ function resolveSpecRow(ref, specMarkdown) {
1616
1618
  validation: parseValidationRows(specMarkdown).filter((row) => itemNumbersNamed(row.criterion).has(ref.item))
1617
1619
  };
1618
1620
  }
1621
+ function unitTitleOf(text) {
1622
+ const firstLine2 = text.split("\n").find((l) => l.trim() !== "")?.trim() ?? "";
1623
+ return firstLine2.length > TITLE_MAX ? `${firstLine2.slice(0, TITLE_MAX - 1).trimEnd()}\u2026` : firstLine2;
1624
+ }
1625
+ function generatedUnit(id, text) {
1626
+ const title = unitTitleOf(text);
1627
+ return { id, title, section: `### ${id}. ${title}
1628
+
1629
+ ${text}`, bullets: {} };
1630
+ }
1619
1631
  function contractFromPlan(input) {
1632
+ if ("unit" in input) return contractOf(input.unit, input);
1620
1633
  const unit = parsePlanUnit(input.planMarkdown, input.unitId);
1621
1634
  if (!unit) {
1622
1635
  const ids = planUnitIds(input.planMarkdown);
@@ -1624,6 +1637,9 @@ function contractFromPlan(input) {
1624
1637
  `the plan has no unit ${input.unitId} (its units: ${ids.length > 0 ? ids.join(", ") : "none \u2014 no `### U<n>.` heading"})`
1625
1638
  );
1626
1639
  }
1640
+ return contractOf(unit, input);
1641
+ }
1642
+ function contractOf(unit, input) {
1627
1643
  return {
1628
1644
  unit,
1629
1645
  specRows: specItemRefs(unit.section).map((ref) => resolveSpecRow(ref, input.readSpec(ref.spec))),
@@ -1633,18 +1649,6 @@ function contractFromPlan(input) {
1633
1649
  issue: input.issue
1634
1650
  };
1635
1651
  }
1636
- function contractFromTask(input) {
1637
- const firstLine2 = input.task.split("\n").find((l) => l.trim() !== "")?.trim() ?? "";
1638
- const title = firstLine2.length > TITLE_MAX ? `${firstLine2.slice(0, TITLE_MAX - 1).trimEnd()}\u2026` : firstLine2;
1639
- return {
1640
- unit: { id: "task", title, section: input.task, bullets: {} },
1641
- specRows: [],
1642
- agentRules: input.agentRules,
1643
- guards: GUARDS,
1644
- rebase: { branch: input.rebase?.branch, onto: input.rebase?.onto },
1645
- issue: input.issue
1646
- };
1647
- }
1648
1652
  function unitBody(unit, dropApproach) {
1649
1653
  const lines = unit.section.split("\n");
1650
1654
  if (dropApproach) {
@@ -12192,7 +12196,8 @@ function isCoordinatorInstance(v) {
12192
12196
  if (typeof r.repo !== "string" || !REPO_SLUG2.test(r.repo)) return false;
12193
12197
  if (!isText(r.branch) || !isOptionalText(r.base)) return false;
12194
12198
  if (!isFinite(r.createdAt)) return false;
12195
- if (r.plan !== void 0 && !(isObject(r.plan) && isText(r.plan.id) && isText(r.plan.path, 1024))) return false;
12199
+ if (r.plan !== void 0 && !(isObject(r.plan) && isText(r.plan.id) && (r.plan.path === void 0 || isText(r.plan.path, 1024))))
12200
+ return false;
12196
12201
  if (r.merge !== void 0 && r.merge !== "runner" && r.merge !== "person") return false;
12197
12202
  if (r.caps !== void 0 && !(isObject(r.caps) && isFinite(r.caps.maxRounds) && isFinite(r.caps.maxMinutes)))
12198
12203
  return false;
@@ -14159,11 +14164,10 @@ async function viewerRunUserIds(userIds, viewer, emailOfSlackUser, cache2) {
14159
14164
  const out = [];
14160
14165
  for (const id of new Set(userIds)) {
14161
14166
  if (!id.startsWith("slack:") || id.startsWith("slack:bot:")) continue;
14162
- const slackId = id.slice("slack:".length);
14163
- let known = cache2.get(slackId);
14167
+ let known = cache2.get(id);
14164
14168
  if (known === void 0) {
14165
- known = (await emailOfSlackUser(slackId))?.toLowerCase();
14166
- if (known !== void 0) cache2.set(slackId, known);
14169
+ known = (await emailOfSlackUser(id))?.toLowerCase();
14170
+ if (known !== void 0) cache2.set(id, known);
14167
14171
  }
14168
14172
  if (known === email) out.push(id);
14169
14173
  }
@@ -29741,7 +29745,7 @@ var init_statusCardFrame = __esm({
29741
29745
  SPINNER_GLYPHS = ["\u25D0", "\u25D3", "\u25D1", "\u25D2"];
29742
29746
  LIVE_CARD_PREFIXES = [...SPINNER_GLYPHS, "\u{1F440}"];
29743
29747
  ROUTED_LABEL_PREFIX = "routed:";
29744
- ROUTED_CARD_FOOTER = "reply agent:<preset> to run it another way";
29748
+ ROUTED_CARD_FOOTER = "wrong preset? reply agent:<preset> to run it another way";
29745
29749
  }
29746
29750
  });
29747
29751
 
@@ -35674,7 +35678,6 @@ var init_runLoop = __esm({
35674
35678
  });
35675
35679
 
35676
35680
  // ../../src/core/ship/preflight.ts
35677
- import { createHash as createHash5 } from "node:crypto";
35678
35681
  function shipTaskText(requestText, repo) {
35679
35682
  let t = requestText.replace(/<((?:https?):\/\/[^|>\s]+)(?:\|[^>]*)?>/gi, " $1 ");
35680
35683
  t = t.replace(/https?:\/\/\S+/gi, " ");
@@ -35684,11 +35687,6 @@ function shipTaskText(requestText, repo) {
35684
35687
  t = t.replace(/\b[a-z0-9][\w.-]*\/[\w.-]+#\d+\b/gi, " ");
35685
35688
  return t.replace(/\s+/g, " ").trim().replace(/^[:,\-—.\s]+/, "").trim();
35686
35689
  }
35687
- function shipBranchName(task, threadKey) {
35688
- const slug = task.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 24).replace(/-+$/, "") || "task";
35689
- const hash = createHash5("sha256").update(threadKey).digest("hex").slice(0, 6);
35690
- return `ship/${slug}-${hash}`;
35691
- }
35692
35690
  async function shipPreflight(input) {
35693
35691
  const { repoCtx } = input;
35694
35692
  if (!input.channelId.startsWith("slack:") && !input.channelId.startsWith("cli:")) {
@@ -35812,7 +35810,7 @@ async function shipPreflight(input) {
35812
35810
  const ref = repoCtx.ref && !repoCtx.refFromPr && repoCtx.ref.toLowerCase() !== repo.toLowerCase() ? repoCtx.ref : void 0;
35813
35811
  return {
35814
35812
  ok: true,
35815
- entry: { repo, branch: shipBranchName(task, input.threadKey), base: resolveBaseRef([ref], info.defaultBranch) }
35813
+ entry: { repo, base: resolveBaseRef([ref], info.defaultBranch) }
35816
35814
  };
35817
35815
  }
35818
35816
  var refuse2;
@@ -35855,6 +35853,133 @@ function planInstanceId(planId, attempt = 1) {
35855
35853
  const suffix = `-${attempt}`;
35856
35854
  return `${base.slice(0, INSTANCE_ID_MAX - suffix.length)}${suffix}`;
35857
35855
  }
35856
+ function sha256Hex2(text) {
35857
+ const K = new Uint32Array([
35858
+ 1116352408,
35859
+ 1899447441,
35860
+ 3049323471,
35861
+ 3921009573,
35862
+ 961987163,
35863
+ 1508970993,
35864
+ 2453635748,
35865
+ 2870763221,
35866
+ 3624381080,
35867
+ 310598401,
35868
+ 607225278,
35869
+ 1426881987,
35870
+ 1925078388,
35871
+ 2162078206,
35872
+ 2614888103,
35873
+ 3248222580,
35874
+ 3835390401,
35875
+ 4022224774,
35876
+ 264347078,
35877
+ 604807628,
35878
+ 770255983,
35879
+ 1249150122,
35880
+ 1555081692,
35881
+ 1996064986,
35882
+ 2554220882,
35883
+ 2821834349,
35884
+ 2952996808,
35885
+ 3210313671,
35886
+ 3336571891,
35887
+ 3584528711,
35888
+ 113926993,
35889
+ 338241895,
35890
+ 666307205,
35891
+ 773529912,
35892
+ 1294757372,
35893
+ 1396182291,
35894
+ 1695183700,
35895
+ 1986661051,
35896
+ 2177026350,
35897
+ 2456956037,
35898
+ 2730485921,
35899
+ 2820302411,
35900
+ 3259730800,
35901
+ 3345764771,
35902
+ 3516065817,
35903
+ 3600352804,
35904
+ 4094571909,
35905
+ 275423344,
35906
+ 430227734,
35907
+ 506948616,
35908
+ 659060556,
35909
+ 883997877,
35910
+ 958139571,
35911
+ 1322822218,
35912
+ 1537002063,
35913
+ 1747873779,
35914
+ 1955562222,
35915
+ 2024104815,
35916
+ 2227730452,
35917
+ 2361852424,
35918
+ 2428436474,
35919
+ 2756734187,
35920
+ 3204031479,
35921
+ 3329325298
35922
+ ]);
35923
+ const h = new Uint32Array([
35924
+ 1779033703,
35925
+ 3144134277,
35926
+ 1013904242,
35927
+ 2773480762,
35928
+ 1359893119,
35929
+ 2600822924,
35930
+ 528734635,
35931
+ 1541459225
35932
+ ]);
35933
+ const bytes = new TextEncoder().encode(text);
35934
+ const padded = new Uint8Array((bytes.length + 8 >> 6 << 6) + 64);
35935
+ padded.set(bytes);
35936
+ padded[bytes.length] = 128;
35937
+ new DataView(padded.buffer).setBigUint64(padded.length - 8, BigInt(bytes.length) * 8n);
35938
+ const w = new Uint32Array(64);
35939
+ const rotr = (x, n2) => x >>> n2 | x << 32 - n2;
35940
+ const view = new DataView(padded.buffer);
35941
+ for (let i = 0; i < padded.length; i += 64) {
35942
+ for (let t = 0; t < 16; t++) w[t] = view.getUint32(i + t * 4);
35943
+ for (let t = 16; t < 64; t++) {
35944
+ const s0 = rotr(w[t - 15], 7) ^ rotr(w[t - 15], 18) ^ w[t - 15] >>> 3;
35945
+ const s1 = rotr(w[t - 2], 17) ^ rotr(w[t - 2], 19) ^ w[t - 2] >>> 10;
35946
+ w[t] = w[t - 16] + s0 + w[t - 7] + s1 >>> 0;
35947
+ }
35948
+ let [a, b, c, d, e, f, g, hh] = [h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7]];
35949
+ for (let t = 0; t < 64; t++) {
35950
+ const S1 = rotr(e, 6) ^ rotr(e, 11) ^ rotr(e, 25);
35951
+ const ch = e & f ^ ~e & g;
35952
+ const t1 = hh + S1 + ch + K[t] + w[t] >>> 0;
35953
+ const S0 = rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22);
35954
+ const maj = a & b ^ a & c ^ b & c;
35955
+ const t2 = S0 + maj >>> 0;
35956
+ hh = g;
35957
+ g = f;
35958
+ f = e;
35959
+ e = d + t1 >>> 0;
35960
+ d = c;
35961
+ c = b;
35962
+ b = a;
35963
+ a = t1 + t2 >>> 0;
35964
+ }
35965
+ h[0] = h[0] + a >>> 0;
35966
+ h[1] = h[1] + b >>> 0;
35967
+ h[2] = h[2] + c >>> 0;
35968
+ h[3] = h[3] + d >>> 0;
35969
+ h[4] = h[4] + e >>> 0;
35970
+ h[5] = h[5] + f >>> 0;
35971
+ h[6] = h[6] + g >>> 0;
35972
+ h[7] = h[7] + hh >>> 0;
35973
+ }
35974
+ return [...h].map((x) => x.toString(16).padStart(8, "0")).join("");
35975
+ }
35976
+ function generatedPlanId(text, threadKey) {
35977
+ const normalised = text.toLowerCase().replace(/\s+/g, " ").trim();
35978
+ const slug = normalised.replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, SLUG_MAX).replace(/-+$/, "") || "task";
35979
+ const hash = sha256Hex2(`${threadKey}
35980
+ ${normalised}`).slice(0, 6);
35981
+ return `${slug}-${hash}`;
35982
+ }
35858
35983
  function dependenciesOf(text, self) {
35859
35984
  const out = [];
35860
35985
  const add = (id) => {
@@ -35947,141 +36072,6 @@ var init_coordinator = __esm({
35947
36072
  }
35948
36073
  });
35949
36074
 
35950
- // ../../src/core/ship/reviewChild.ts
35951
- function buildShipReviewTurn(input) {
35952
- const at = input.headSha ? ` at head \`${input.headSha}\`` : "";
35953
- if (input.round <= 1 || !input.prior) {
35954
- return `Review pull request ${input.where}${at}. Submit your verdict with findings via submit_verdict before your final message.`;
35955
- }
35956
- const findings = input.prior.findings.map(formatFinding).join("\n") || "(none recorded)";
35957
- const dispositions = input.prior.dispositions.map((d) => `${d.findingId}: ${d.disposition}${d.note ? ` \u2014 ${d.note}` : ""}`).join("\n") || "(none recorded)";
35958
- const dropped = input.prior.dropped !== void 0 && input.prior.dropped.length > 0 ? `
35959
- Dispositions naming no finding of the previous round (dropped): ${input.prior.dropped.join(", ")}` : "";
35960
- return `Re-review pull request ${input.where}${at} \u2014 review round ${input.round} of this ship pipeline. Load the \`re-review-delta\` skill: narrow your READING to the delta since the previously reviewed head and verify each prior finding's disposition, but your verdict still covers the full diff against base. Carry every unresolved prior finding forward under its existing id.
35961
-
35962
- Previous round's findings:
35963
- ${findings}
35964
-
35965
- Fix round's dispositions:
35966
- ${dispositions}${dropped}`;
35967
- }
35968
- var init_reviewChild = __esm({
35969
- "../../src/core/ship/reviewChild.ts"() {
35970
- "use strict";
35971
- init_reviewVerdict();
35972
- }
35973
- });
35974
-
35975
- // ../../src/core/coordinator/briefs.ts
35976
- async function contractFor(instance, unit, readers) {
35977
- const rebase = { branch: unit.branch, onto: instance.base ?? "main" };
35978
- const issue = unit.issue !== void 0 ? { repo: instance.repo, number: unit.issue } : void 0;
35979
- if (unit.unit === TASK_UNIT || instance.plan === void 0) {
35980
- const request = await readers.readShipRequest();
35981
- const task = request !== void 0 ? shipTaskText(parseDirectives(request).text, instance.repo) : "";
35982
- return contractFromTask({
35983
- task: task || "Implement the task this thread's ship request describes.",
35984
- rebase,
35985
- ...issue ? { issue } : {}
35986
- });
35987
- }
35988
- const planMarkdown = await readers.readRepoFile(instance.plan.path);
35989
- if (planMarkdown === void 0)
35990
- throw new Error(`the plan ${instance.plan.path} is not readable at ${rebase.onto} in ${instance.repo}`);
35991
- const section = parsePlanUnit(planMarkdown, unit.unit)?.section ?? "";
35992
- const specs = /* @__PURE__ */ new Map();
35993
- for (const spec of new Set(specItemRefs(section).map((r) => r.spec)))
35994
- specs.set(spec, await readers.readRepoFile(`${SPECS_DIR2}/${spec}`));
35995
- let agentRules;
35996
- for (const file of RULES_FILES2) {
35997
- const text = await readers.readRepoFile(file);
35998
- if (text !== void 0) {
35999
- agentRules = { file, text };
36000
- break;
36001
- }
36002
- }
36003
- return contractFromPlan({
36004
- planMarkdown,
36005
- unitId: unit.unit,
36006
- readSpec: (spec) => specs.get(spec),
36007
- ...agentRules ? { agentRules } : {},
36008
- rebase,
36009
- ...issue ? { issue } : {}
36010
- });
36011
- }
36012
- function findingsRequest(input) {
36013
- const findings = input.findings.map(formatFinding).join("\n") || "(the review listed no structured findings, address its prose)";
36014
- return `The review of ${input.where} requested changes. Load the \`address-review-findings\` skill and address every finding below, nits included: record one disposition per finding with submit_dispositions (fixed or declined, with a note), squash to coherent commits, resubmit the pull request description with submit_pr_description, and push the branch. Never merge and never approve.
36015
-
36016
- Findings:
36017
- ${findings}
36018
-
36019
- Review:
36020
- ${input.review}`;
36021
- }
36022
- async function composeChild(brief, instance, unit, readers) {
36023
- const where = `${instance.repo}#${"pr" in brief ? brief.pr : ""}`;
36024
- switch (brief.kind) {
36025
- case "contract": {
36026
- const contract = await contractFor(instance, unit, readers);
36027
- const prompt = contract.unit.id === TASK_UNIT ? contract.unit.section : `Implement unit ${contract.unit.id} \u2014 ${contract.unit.title} \u2014 of ${instance.plan?.path ?? "the plan"}: the contract below is the unit. Do its first instruction first, then add every test scenario it lists, update every spec row it names and weaken no guard.`;
36028
- return { preset: "coding", prompt, ref: unit.branch, contract };
36029
- }
36030
- case "review": {
36031
- let prior;
36032
- if (brief.prior !== void 0) {
36033
- const findings = (await facts(readers, brief.prior.reviewRunId)).findings ?? [];
36034
- const recorded = brief.prior.codingRunId !== void 0 ? (await facts(readers, brief.prior.codingRunId)).dispositions ?? [] : [];
36035
- const { matched, dropped } = matchDispositions(findings, recorded);
36036
- prior = { findings, dispositions: matched, dropped };
36037
- }
36038
- const turn = buildShipReviewTurn({
36039
- where,
36040
- round: brief.round,
36041
- ...brief.headSha !== void 0 ? { headSha: brief.headSha } : {},
36042
- ...prior ? { prior } : {}
36043
- });
36044
- const contract = await contractFor(instance, unit, readers);
36045
- return { preset: "review", prompt: `${prUrl(instance.repo, brief.pr)}
36046
-
36047
- ${turn}`, contract };
36048
- }
36049
- case "findings": {
36050
- const review = await facts(readers, brief.reviewRunId);
36051
- return {
36052
- preset: "coding",
36053
- prompt: findingsRequest({ where, findings: review.findings ?? [], review: review.finalReply ?? "" }),
36054
- ref: unit.branch
36055
- };
36056
- }
36057
- default: {
36058
- const unknown = brief;
36059
- throw new Error(`unknown brief kind ${JSON.stringify(unknown.kind)}`);
36060
- }
36061
- }
36062
- }
36063
- async function facts(readers, runId3) {
36064
- const read = await readers.readRunFacts(runId3);
36065
- if (!read) throw new Error(`run ${runId3} is not in the run history`);
36066
- return read;
36067
- }
36068
- var SPECS_DIR2, RULES_FILES2, TASK_UNIT, prUrl;
36069
- var init_briefs = __esm({
36070
- "../../src/core/coordinator/briefs.ts"() {
36071
- "use strict";
36072
- init_directives();
36073
- init_reviewVerdict();
36074
- init_coordinator();
36075
- init_contract();
36076
- init_preflight();
36077
- init_reviewChild();
36078
- SPECS_DIR2 = "docs/reference/specs";
36079
- RULES_FILES2 = ["AGENTS.md", "CLAUDE.md"];
36080
- TASK_UNIT = "task";
36081
- prUrl = (repo, pr) => `https://github.com/${repo}/pull/${pr}`;
36082
- }
36083
- });
36084
-
36085
36075
  // ../../src/core/coordinator/handOff.ts
36086
36076
  async function plan(deps, input) {
36087
36077
  const { entry, msg } = input;
@@ -36107,29 +36097,26 @@ async function plan(deps, input) {
36107
36097
  runId: input.runId,
36108
36098
  label: input.label
36109
36099
  };
36110
- const request = parseShipPlanRequest(shipTaskText(input.requestText, entry.repo));
36100
+ const taskText = shipTaskText(input.requestText, entry.repo);
36101
+ const request = parseShipPlanRequest(taskText);
36111
36102
  if (request === void 0) {
36112
- const id = `ship-${input.runId}`;
36113
- const resume = entry.resume;
36114
- const prUrl2 = resume?.url ?? (resume !== void 0 ? `https://github.com/${entry.repo}/pull/${resume.pr}` : void 0);
36103
+ const text2 = taskText || "Implement the task this thread's ship request describes.";
36104
+ const planId2 = generatedPlanId(text2, msg.threadKey);
36105
+ const graph2 = {
36106
+ planId: planId2,
36107
+ units: [{ id: "U1", title: unitTitleOf(text2), slug: "u1", branch: unitBranch(planId2, "u1"), dependsOn: [] }]
36108
+ };
36115
36109
  return {
36116
36110
  ok: true,
36117
36111
  planned: {
36118
- kind: "task",
36119
- // A task's merge is a person's, whatever the request's words say.
36120
- instance: { id, ...identity2, branch: entry.branch, merge: "person" },
36121
- units: [
36122
- {
36123
- instanceId: id,
36124
- unit: TASK_UNIT,
36125
- slug: TASK_UNIT,
36126
- branch: entry.branch,
36127
- dependsOn: [],
36128
- rounds: [],
36129
- ...resume !== void 0 ? { resume } : {}
36130
- }
36131
- ],
36132
- where: resume !== void 0 ? `the review loop of ${prUrl2} resumes at its next review round on \`${entry.branch}\` in this thread under your grants \u2014 no new coding round first; this card follows it and the report lands here.` : `the task runs on \`${entry.branch}\` in this thread under your grants; this card follows it and the report lands here.`
36112
+ planId: planId2,
36113
+ base,
36114
+ graph: graph2,
36115
+ selected: ["U1"],
36116
+ identity: identity2,
36117
+ merge: "person",
36118
+ ...entry.resume !== void 0 ? { resume: entry.resume } : {},
36119
+ ...entry.branch !== void 0 ? { entryBranch: entry.branch } : {}
36133
36120
  }
36134
36121
  };
36135
36122
  }
@@ -36160,42 +36147,55 @@ async function plan(deps, input) {
36160
36147
  } catch (err2) {
36161
36148
  return { ok: false, reply: `\u{1F6AB} ${describe6(err2)}` };
36162
36149
  }
36163
- return { ok: true, planned: { kind: "plan", planId, path: request.planPath, base, graph, selected, identity: identity2 } };
36150
+ return {
36151
+ ok: true,
36152
+ planned: { planId, path: request.planPath, base, graph, selected, identity: identity2, merge: "runner" }
36153
+ };
36164
36154
  }
36165
- function rowsFor(graph, selected, instanceId) {
36166
- return graph.units.filter((u) => selected.includes(u.id)).map((u) => ({
36155
+ function rowsFor(p, selected, instanceId) {
36156
+ return p.graph.units.filter((u) => selected.includes(u.id)).map((u) => ({
36167
36157
  instanceId,
36168
36158
  unit: u.id,
36169
36159
  slug: u.slug,
36170
36160
  title: u.title,
36171
- branch: u.branch,
36161
+ branch: p.entryBranch ?? u.branch,
36172
36162
  dependsOn: u.dependsOn,
36173
- rounds: []
36163
+ rounds: [],
36164
+ ...p.resume !== void 0 ? { resume: p.resume } : {}
36174
36165
  }));
36175
36166
  }
36176
36167
  function planWhere(p, units, mergedBefore) {
36168
+ const at = p.path !== void 0 ? ` (\`${p.path}\` at \`${p.base}\`)` : "";
36177
36169
  const count = `${units.length} unit${units.length === 1 ? "" : "s"}`;
36178
36170
  const left = mergedBefore.length > 0 ? ` left` : "";
36179
36171
  const merged = mergedBefore.length > 0 ? `; merged before: ${mergedBefore.join(", ")}` : "";
36180
- return `plan \`${p.planId}\` (\`${p.path}\` at \`${p.base}\`), ${count}${left} in dependency order \u2014 ${units.map((u) => u.unit).join(", ")}${merged}. Each unit runs in a thread of its own in this channel under your grants; this card follows the plan and its summary lands in this thread.`;
36172
+ const head = `plan \`${p.planId}\`${at}, ${count}${left} in dependency order \u2014 ${units.map((u) => u.unit).join(", ")}${merged}.`;
36173
+ if (p.path !== void 0)
36174
+ return `${head} Each unit runs in a thread of its own in this channel under your grants; this card follows the plan and its summary lands in this thread.`;
36175
+ const branch2 = units[0]?.branch ?? "";
36176
+ const prUrl2 = p.resume?.url ?? (p.resume !== void 0 ? `https://github.com/${p.identity.repo}/pull/${p.resume.pr}` : void 0);
36177
+ const runs = p.resume !== void 0 ? `the review loop of ${prUrl2} resumes at its next review round on \`${branch2}\` in this thread under your grants \u2014 no new coding round first` : `the unit runs on \`${branch2}\` in this thread under your grants`;
36178
+ return `${head} ${runs}; this card follows it and the report lands here.`;
36181
36179
  }
36182
36180
  async function handOffToCoordinator(deps, input) {
36183
36181
  const log = deps.log ?? console.log;
36184
36182
  const planned = await plan(deps, input);
36185
36183
  if (!planned.ok) return refused3(planned.reply);
36186
36184
  const p = planned.planned;
36187
- if (p.kind === "task") return start(deps, input, p.instance, p.units, p.where, "put");
36185
+ const planOf = () => ({
36186
+ id: p.planId,
36187
+ ...p.path !== void 0 ? { path: p.path } : {}
36188
+ });
36188
36189
  const firstId = planInstanceId(p.planId);
36189
36190
  const first = await deps.instances.get(firstId);
36190
36191
  if (first === null) {
36191
- const units2 = rowsFor(p.graph, p.selected, firstId);
36192
+ const units2 = rowsFor(p, p.selected, firstId);
36192
36193
  const instance2 = {
36193
36194
  id: firstId,
36194
36195
  ...p.identity,
36195
36196
  branch: units2[0].branch,
36196
- plan: { id: p.planId, path: p.path },
36197
- // A seeded plan's units are the runner's to merge (record 0031's merge grant).
36198
- merge: "runner"
36197
+ plan: planOf(),
36198
+ merge: p.merge
36199
36199
  };
36200
36200
  return start(deps, input, instance2, units2, planWhere(p, units2, []), "put");
36201
36201
  }
@@ -36232,13 +36232,13 @@ async function handOffToCoordinator(deps, input) {
36232
36232
  );
36233
36233
  const mergedBefore = p.selected.filter((u) => merged.has(u));
36234
36234
  if (status3.kind === "absent") {
36235
- const units2 = rowsFor(p.graph, remaining, latest.id);
36235
+ const units2 = rowsFor(p, remaining, latest.id);
36236
36236
  const instance2 = {
36237
36237
  id: latest.id,
36238
36238
  ...p.identity,
36239
36239
  branch: units2[0].branch,
36240
- plan: { id: p.planId, path: p.path },
36241
- merge: "runner",
36240
+ plan: planOf(),
36241
+ merge: p.merge,
36242
36242
  ...attempt > 1 ? { attempt } : {}
36243
36243
  };
36244
36244
  log(`[ship] ${input.msg.threadKey}: ${latest.id} has records but no instance \u2014 replacing the earlier attempt's`);
@@ -36246,13 +36246,13 @@ async function handOffToCoordinator(deps, input) {
36246
36246
  return start(deps, input, instance2, units2, `${prefix}${planWhere(p, units2, mergedBefore)}`, "replace");
36247
36247
  }
36248
36248
  const nextId = planInstanceId(p.planId, attempt + 1);
36249
- const units = rowsFor(p.graph, remaining, nextId);
36249
+ const units = rowsFor(p, remaining, nextId);
36250
36250
  const instance = {
36251
36251
  id: nextId,
36252
36252
  ...p.identity,
36253
36253
  branch: units[0].branch,
36254
- plan: { id: p.planId, path: p.path },
36255
- merge: "runner",
36254
+ plan: planOf(),
36255
+ merge: p.merge,
36256
36256
  attempt: attempt + 1
36257
36257
  };
36258
36258
  return start(deps, input, instance, units, `attempt ${attempt + 1} of ${planWhere(p, units, mergedBefore)}`, "put");
@@ -36304,9 +36304,9 @@ var refused3, describe6, RUNNING, ENDED;
36304
36304
  var init_handOff = __esm({
36305
36305
  "../../src/core/coordinator/handOff.ts"() {
36306
36306
  "use strict";
36307
+ init_contract();
36307
36308
  init_preflight();
36308
36309
  init_coordinator();
36309
- init_briefs();
36310
36310
  refused3 = (reply) => ({ status: "aborted", reply });
36311
36311
  describe6 = (err2) => err2 instanceof Error ? err2.message : String(err2);
36312
36312
  RUNNING = /* @__PURE__ */ new Set(["queued", "running", "paused", "waiting", "waitingForPause"]);
@@ -43751,7 +43751,7 @@ var init_accessAuth = __esm({
43751
43751
  });
43752
43752
 
43753
43753
  // ../../src/channels/dashboardAuth.ts
43754
- import { createHash as createHash6, timingSafeEqual as timingSafeEqual4 } from "node:crypto";
43754
+ import { createHash as createHash5, timingSafeEqual as timingSafeEqual4 } from "node:crypto";
43755
43755
  function header2(headers, name) {
43756
43756
  const raw = headers[name];
43757
43757
  return Array.isArray(raw) ? raw[0] : raw;
@@ -43769,8 +43769,8 @@ function accessVerifier(config, deps) {
43769
43769
  };
43770
43770
  }
43771
43771
  function secretsEqual(a, b) {
43772
- const ha = createHash6("sha256").update(a).digest();
43773
- const hb = createHash6("sha256").update(b).digest();
43772
+ const ha = createHash5("sha256").update(a).digest();
43773
+ const hb = createHash5("sha256").update(b).digest();
43774
43774
  return timingSafeEqual4(ha, hb);
43775
43775
  }
43776
43776
  function tokenVerifier(opts) {
@@ -44799,6 +44799,147 @@ var init_adminRestartAuthorize = __esm({
44799
44799
  }
44800
44800
  });
44801
44801
 
44802
+ // ../../src/core/ship/reviewChild.ts
44803
+ function buildShipReviewTurn(input) {
44804
+ const at = input.headSha ? ` at head \`${input.headSha}\`` : "";
44805
+ if (input.round <= 1 || !input.prior) {
44806
+ return `Review pull request ${input.where}${at}. Submit your verdict with findings via submit_verdict before your final message.`;
44807
+ }
44808
+ const findings = input.prior.findings.map(formatFinding).join("\n") || "(none recorded)";
44809
+ const dispositions = input.prior.dispositions.map((d) => `${d.findingId}: ${d.disposition}${d.note ? ` \u2014 ${d.note}` : ""}`).join("\n") || "(none recorded)";
44810
+ const dropped = input.prior.dropped !== void 0 && input.prior.dropped.length > 0 ? `
44811
+ Dispositions naming no finding of the previous round (dropped): ${input.prior.dropped.join(", ")}` : "";
44812
+ return `Re-review pull request ${input.where}${at} \u2014 review round ${input.round} of this ship pipeline. Load the \`re-review-delta\` skill: narrow your READING to the delta since the previously reviewed head and verify each prior finding's disposition, but your verdict still covers the full diff against base. Carry every unresolved prior finding forward under its existing id.
44813
+
44814
+ Previous round's findings:
44815
+ ${findings}
44816
+
44817
+ Fix round's dispositions:
44818
+ ${dispositions}${dropped}`;
44819
+ }
44820
+ var init_reviewChild = __esm({
44821
+ "../../src/core/ship/reviewChild.ts"() {
44822
+ "use strict";
44823
+ init_reviewVerdict();
44824
+ }
44825
+ });
44826
+
44827
+ // ../../src/core/coordinator/briefs.ts
44828
+ async function generatedUnitOf(instance, unit, readers) {
44829
+ const resume = unit.resume;
44830
+ if (resume !== void 0) {
44831
+ const url = resume.url ?? `https://github.com/${instance.repo}/pull/${resume.pr}`;
44832
+ return generatedUnit(unit.unit, `Resume the review loop of ${url}`);
44833
+ }
44834
+ const request = await readers.readShipRequest();
44835
+ const task = request !== void 0 ? shipTaskText(parseDirectives(request).text, instance.repo) : "";
44836
+ return generatedUnit(unit.unit, task || "Implement the task this thread's ship request describes.");
44837
+ }
44838
+ async function contractFor(instance, unit, readers) {
44839
+ const rebase = { branch: unit.branch, onto: instance.base ?? "main" };
44840
+ const issue = unit.issue !== void 0 ? { repo: instance.repo, number: unit.issue } : void 0;
44841
+ let source2;
44842
+ if (isGenerated(instance)) {
44843
+ source2 = { unit: await generatedUnitOf(instance, unit, readers) };
44844
+ } else {
44845
+ const planMarkdown = await readers.readRepoFile(instance.plan.path);
44846
+ if (planMarkdown === void 0)
44847
+ throw new Error(`the plan ${instance.plan.path} is not readable at ${rebase.onto} in ${instance.repo}`);
44848
+ source2 = { planMarkdown, unitId: unit.unit };
44849
+ }
44850
+ const section = ("unit" in source2 ? source2.unit : parsePlanUnit(source2.planMarkdown, unit.unit))?.section ?? "";
44851
+ const specs = /* @__PURE__ */ new Map();
44852
+ for (const spec of new Set(specItemRefs(section).map((r) => r.spec)))
44853
+ specs.set(spec, await readers.readRepoFile(`${SPECS_DIR2}/${spec}`));
44854
+ let agentRules;
44855
+ for (const file of RULES_FILES2) {
44856
+ const text = await readers.readRepoFile(file);
44857
+ if (text !== void 0) {
44858
+ agentRules = { file, text };
44859
+ break;
44860
+ }
44861
+ }
44862
+ return contractFromPlan({
44863
+ ...source2,
44864
+ readSpec: (spec) => specs.get(spec),
44865
+ ...agentRules ? { agentRules } : {},
44866
+ rebase,
44867
+ ...issue ? { issue } : {}
44868
+ });
44869
+ }
44870
+ function findingsRequest(input) {
44871
+ const findings = input.findings.map(formatFinding).join("\n") || "(the review listed no structured findings, address its prose)";
44872
+ return `The review of ${input.where} requested changes. Load the \`address-review-findings\` skill and address every finding below, nits included: record one disposition per finding with submit_dispositions (fixed or declined, with a note), squash to coherent commits, resubmit the pull request description with submit_pr_description, and push the branch. Never merge and never approve.
44873
+
44874
+ Findings:
44875
+ ${findings}
44876
+
44877
+ Review:
44878
+ ${input.review}`;
44879
+ }
44880
+ async function composeChild(brief, instance, unit, readers) {
44881
+ const where = `${instance.repo}#${"pr" in brief ? brief.pr : ""}`;
44882
+ switch (brief.kind) {
44883
+ case "contract": {
44884
+ const contract = await contractFor(instance, unit, readers);
44885
+ const prompt = isGenerated(instance) ? contract.unit.section.split("\n").slice(1).join("\n").trim() : `Implement unit ${contract.unit.id} \u2014 ${contract.unit.title} \u2014 of ${instance.plan?.path ?? "the plan"}: the contract below is the unit. Do its first instruction first, then add every test scenario it lists, update every spec row it names and weaken no guard.`;
44886
+ return { preset: "coding", prompt, ref: unit.branch, contract };
44887
+ }
44888
+ case "review": {
44889
+ let prior;
44890
+ if (brief.prior !== void 0) {
44891
+ const findings = (await facts(readers, brief.prior.reviewRunId)).findings ?? [];
44892
+ const recorded = brief.prior.codingRunId !== void 0 ? (await facts(readers, brief.prior.codingRunId)).dispositions ?? [] : [];
44893
+ const { matched, dropped } = matchDispositions(findings, recorded);
44894
+ prior = { findings, dispositions: matched, dropped };
44895
+ }
44896
+ const turn = buildShipReviewTurn({
44897
+ where,
44898
+ round: brief.round,
44899
+ ...brief.headSha !== void 0 ? { headSha: brief.headSha } : {},
44900
+ ...prior ? { prior } : {}
44901
+ });
44902
+ const contract = await contractFor(instance, unit, readers);
44903
+ return { preset: "review", prompt: `${prUrl(instance.repo, brief.pr)}
44904
+
44905
+ ${turn}`, contract };
44906
+ }
44907
+ case "findings": {
44908
+ const review = await facts(readers, brief.reviewRunId);
44909
+ return {
44910
+ preset: "coding",
44911
+ prompt: findingsRequest({ where, findings: review.findings ?? [], review: review.finalReply ?? "" }),
44912
+ ref: unit.branch
44913
+ };
44914
+ }
44915
+ default: {
44916
+ const unknown = brief;
44917
+ throw new Error(`unknown brief kind ${JSON.stringify(unknown.kind)}`);
44918
+ }
44919
+ }
44920
+ }
44921
+ async function facts(readers, runId3) {
44922
+ const read = await readers.readRunFacts(runId3);
44923
+ if (!read) throw new Error(`run ${runId3} is not in the run history`);
44924
+ return read;
44925
+ }
44926
+ var SPECS_DIR2, RULES_FILES2, isGenerated, prUrl;
44927
+ var init_briefs = __esm({
44928
+ "../../src/core/coordinator/briefs.ts"() {
44929
+ "use strict";
44930
+ init_directives();
44931
+ init_reviewVerdict();
44932
+ init_coordinator();
44933
+ init_contract();
44934
+ init_preflight();
44935
+ init_reviewChild();
44936
+ SPECS_DIR2 = "docs/reference/specs";
44937
+ RULES_FILES2 = ["AGENTS.md", "CLAUDE.md"];
44938
+ isGenerated = (instance) => instance.plan?.path === void 0;
44939
+ prUrl = (repo, pr) => `https://github.com/${repo}/pull/${pr}`;
44940
+ }
44941
+ });
44942
+
44802
44943
  // ../../src/channels/adminCoordinator.ts
44803
44944
  function isCoordinatorAdminPath(path) {
44804
44945
  return path.startsWith(COORDINATOR_ADMIN_PREFIX) && path.length > COORDINATOR_ADMIN_PREFIX.length;
@@ -44913,7 +45054,7 @@ async function unitRowOf(deps, instance, unit) {
44913
45054
  return { ok: true, row };
44914
45055
  }
44915
45056
  function unitThread(instance, row) {
44916
- const threadKey = row?.threadKey ?? (row === void 0 || row.unit === TASK_UNIT ? instance.threadKey : void 0);
45057
+ const threadKey = row?.threadKey ?? (row === void 0 || isGenerated2(instance) ? instance.threadKey : void 0);
44917
45058
  const sourceUrl = row?.sourceUrl ?? (threadKey === instance.threadKey ? instance.sourceUrl : void 0);
44918
45059
  return { threadKey, sourceUrl };
44919
45060
  }
@@ -45054,7 +45195,7 @@ async function spawn6(body, deps) {
45054
45195
  if (req.brief !== void 0) {
45055
45196
  if (row === void 0) return json(400, { ok: false, error: "a brief needs the unit it runs for" });
45056
45197
  try {
45057
- turn = await composeChild(req.brief, instance, row, briefReaders(deps, instance, io));
45198
+ turn = await composeChild(req.brief, instance, row, briefReaders(deps, instance));
45058
45199
  } catch (err2) {
45059
45200
  log(`[coordinator] ${instance.id} ${req.step}: the brief could not be composed: ${describe11(err2)}`);
45060
45201
  return json(502, { ok: false, error: "brief_failed", message: describe11(err2), at });
@@ -45283,6 +45424,8 @@ async function plan2(body, deps) {
45283
45424
  ...instance.plan !== void 0 ? { planId: instance.plan.id } : {},
45284
45425
  // Who merges: the instance's field; a record written before it existed is a person's merge.
45285
45426
  merge: instance.merge ?? "person",
45427
+ // The mark (item 16): the machine's report keys its re-issue line on it.
45428
+ generated: isGenerated2(instance),
45286
45429
  repo: instance.repo,
45287
45430
  base: instance.base ?? "main",
45288
45431
  caps: instance.caps ?? resolveShipCaps(void 0),
@@ -45312,7 +45455,7 @@ async function unitStart(body, deps) {
45312
45455
  if (!unit.ok) return unit.response;
45313
45456
  let row = unit.row;
45314
45457
  if (row.threadKey === void 0) {
45315
- if (row.unit === TASK_UNIT) {
45458
+ if (isGenerated2(instance)) {
45316
45459
  row = {
45317
45460
  ...row,
45318
45461
  threadKey: instance.threadKey,
@@ -45332,7 +45475,7 @@ async function unitStart(body, deps) {
45332
45475
  }
45333
45476
  row = review.row;
45334
45477
  }
45335
- if (row.issue === void 0 && row.unit !== TASK_UNIT) {
45478
+ if (row.issue === void 0 && !isGenerated2(instance)) {
45336
45479
  const issue = await unitIssueOf(deps, instance.repo, row.unit);
45337
45480
  if (issue !== void 0) row = { ...row, issue };
45338
45481
  }
@@ -45359,7 +45502,7 @@ function unitLead(instance, row) {
45359
45502
  function reviewLead(instance, row) {
45360
45503
  const who2 = instance.userName ?? instance.userId;
45361
45504
  const from = instance.sourceUrl !== void 0 ? `[the *ship* run](${instance.sourceUrl})` : "the *ship* run";
45362
- const what = row.unit === TASK_UNIT ? "the task" : `unit ${row.unit}${row.title ? ` \u2014 ${row.title}` : ""}`;
45505
+ const what = isGenerated2(instance) ? "the task" : `unit ${row.unit}${row.title ? ` \u2014 ${row.title}` : ""}`;
45363
45506
  return `\u21B3 *ship* review of ${what} for ${who2}, from ${from}: \`${row.branch}\` in ${instance.repo}`;
45364
45507
  }
45365
45508
  async function branch(body, deps) {
@@ -45382,11 +45525,11 @@ async function branch(body, deps) {
45382
45525
  return json(200, { ok: false, reason: describe11(err2), at });
45383
45526
  }
45384
45527
  }
45385
- function unitLines(units) {
45528
+ function unitLines(units, generated) {
45386
45529
  return units.map((u) => {
45387
45530
  const last = u.rounds.at(-1);
45388
45531
  const state = u.ending ? u.ending.kind : last ? `${shipRoundHeader({ index: last.index, agent: last.agent })} \xB7 ${last.outcome}` : u.threadKey ? "starting" : "waiting";
45389
- return u.unit === TASK_UNIT ? state : `${u.unit} \xB7 ${state}`;
45532
+ return generated ? state : `${u.unit} \xB7 ${state}`;
45390
45533
  });
45391
45534
  }
45392
45535
  async function drawCard(deps, instance, units, close) {
@@ -45395,7 +45538,7 @@ async function drawCard(deps, instance, units, close) {
45395
45538
  if (!io) return;
45396
45539
  const clock4 = deps.clock ?? systemClock;
45397
45540
  const shell = createCardShell({ label: instance.label ?? "*ship*", startedAt: instance.createdAt, now: clock4 });
45398
- const detail = unitLines(units);
45541
+ const detail = unitLines(units, isGenerated2(instance));
45399
45542
  if (!close) {
45400
45543
  await io.status(shell.live({ detail }));
45401
45544
  return;
@@ -45613,7 +45756,7 @@ function parentRunRecord(instance, units, outcome, channelVisibility, finishedAt
45613
45756
  at: r.at
45614
45757
  }))
45615
45758
  ),
45616
- { type: "answer", text: planSummary(units), at: finishedAt }
45759
+ { type: "answer", text: planSummary(units, isGenerated2(instance)), at: finishedAt }
45617
45760
  ];
45618
45761
  events.forEach((e, i) => {
45619
45762
  e.seq = i + 1;
@@ -45639,11 +45782,11 @@ function parentRunRecord(instance, units, outcome, channelVisibility, finishedAt
45639
45782
  ...instance.sourceUrl !== void 0 ? { sourceUrl: instance.sourceUrl } : {}
45640
45783
  };
45641
45784
  }
45642
- function planSummary(units) {
45785
+ function planSummary(units, generated = false) {
45643
45786
  const lines = units.map((u) => {
45644
45787
  const how = u.ending ? u.ending.kind : u.threadKey ? "unfinished" : "not started";
45645
45788
  const pr = u.pr ? ` \u2014 ${u.pr.url}` : "";
45646
- return u.unit === TASK_UNIT ? `${ENDING_ICON[how] ?? "\u2022"} ${how}${pr}` : `${ENDING_ICON[how] ?? "\u2022"} ${u.unit} \u2014 ${how}${pr}`;
45789
+ return generated ? `${ENDING_ICON[how] ?? "\u2022"} ${how}${pr}` : `${ENDING_ICON[how] ?? "\u2022"} ${u.unit} \u2014 ${how}${pr}`;
45647
45790
  });
45648
45791
  return lines.join("\n");
45649
45792
  }
@@ -45661,8 +45804,7 @@ async function finish(body, deps) {
45661
45804
  deps.runHistoryWriter.write(record2);
45662
45805
  await drawCard(deps, instance, units, { icon: body.outcome === "completed" ? "\u2705" : "\u26A0\uFE0F" }).catch(() => {
45663
45806
  });
45664
- const isPlan = units.some((u) => u.unit !== TASK_UNIT);
45665
- if (isPlan) {
45807
+ if (!isGenerated2(instance)) {
45666
45808
  const io = deps.ioFor({ threadKey: instance.threadKey, userId: instance.userId });
45667
45809
  await io?.reply(`Plan ${instance.plan?.id ?? ""} ended (${body.outcome}):
45668
45810
  ${planSummary(units)}`).catch(() => {
@@ -45671,7 +45813,7 @@ ${planSummary(units)}`).catch(() => {
45671
45813
  (deps.log ?? console.log)(`[coordinator] ${instance.id}: finished ${body.outcome} \u2014 record ${record2.id}`);
45672
45814
  return json(200, { ok: true, runId: record2.id, at });
45673
45815
  }
45674
- function briefReaders(deps, instance, io) {
45816
+ function briefReaders(deps, instance) {
45675
45817
  const ref = instance.base ?? "main";
45676
45818
  return {
45677
45819
  readRepoFile: async (path) => {
@@ -45691,9 +45833,16 @@ function briefReaders(deps, instance, io) {
45691
45833
  ...finalReplyOf2(r.events) !== void 0 ? { finalReply: finalReplyOf2(r.events) } : {}
45692
45834
  };
45693
45835
  },
45836
+ // The generated plan's request text: the ship run's own record
45837
+ // (`instance.runId`, its `input` event) — never a scan of the thread, so a
45838
+ // routed request with no `agent:ship` turn anywhere still reads back the
45839
+ // words the person typed (agent-ship item 13).
45694
45840
  readShipRequest: async () => {
45695
- const history = await io.history().catch(() => []);
45696
- return [...history].reverse().find((h) => h.role === "user" && /\bagent:ship\b/.test(h.text))?.text;
45841
+ if (instance.runId === void 0) return void 0;
45842
+ const res = await deps.runs.getRun(instance.runId, { include: "messages" }).catch(() => void 0);
45843
+ if (res === void 0 || !res.ok) return void 0;
45844
+ const input = (res.value.events ?? []).find((e) => e.type === "input");
45845
+ return input?.type === "input" ? input.text : void 0;
45697
45846
  }
45698
45847
  };
45699
45848
  }
@@ -45769,7 +45918,7 @@ function createAdminCoordinatorHandler(deps) {
45769
45918
  })();
45770
45919
  };
45771
45920
  }
45772
- var COORDINATOR_ADMIN_PREFIX, MAX_SPAWN_PROMPT_CHARS, FINISHED_LOOKBACK_PAGES, MAX_ADMIN_BODY_BYTES, UNIT_ID, PRESETS_OF_KIND, invalid, json, describe11, EVERY_RUN, REVIEW_POSTED_CHECKS, REVIEW_POSTED_RECHECK_MS, ROUND_OUTCOMES, ENDING_ICON, STEPS;
45921
+ var COORDINATOR_ADMIN_PREFIX, MAX_SPAWN_PROMPT_CHARS, FINISHED_LOOKBACK_PAGES, MAX_ADMIN_BODY_BYTES, UNIT_ID, PRESETS_OF_KIND, invalid, json, describe11, isGenerated2, EVERY_RUN, REVIEW_POSTED_CHECKS, REVIEW_POSTED_RECHECK_MS, ROUND_OUTCOMES, ENDING_ICON, STEPS;
45773
45922
  var init_adminCoordinator = __esm({
45774
45923
  "../../src/channels/adminCoordinator.ts"() {
45775
45924
  "use strict";
@@ -45803,6 +45952,7 @@ var init_adminCoordinator = __esm({
45803
45952
  invalid = (error) => ({ ok: false, error });
45804
45953
  json = (status3, body) => ({ status: status3, body });
45805
45954
  describe11 = (err2) => err2 instanceof Error ? err2.message : String(err2);
45955
+ isGenerated2 = (instance) => instance.plan?.path === void 0;
45806
45956
  EVERY_RUN = { kind: "all" };
45807
45957
  REVIEW_POSTED_CHECKS = 3;
45808
45958
  REVIEW_POSTED_RECHECK_MS = 2e3;