@coreplane/switchboard 1.230.0 → 1.231.1
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/assets/deploy/cloudflare/knownLength.ts +43 -0
- package/dist/assets/deploy/cloudflare/worker.ts +10 -2
- package/dist/assets/package-lock.json +3 -3
- package/dist/assets/package.json +1 -1
- package/dist/assets/source.json +3 -3
- package/dist/assets/src/core/coordinator/contract.ts +22 -14
- package/dist/assets/src/core/coordinator/driver.ts +4 -0
- package/dist/assets/src/core/ship/contract.ts +35 -29
- package/dist/assets/src/core/ship/coordinator.ts +89 -4
- package/dist/assets/web/dist/.vite/manifest.json +19 -19
- package/dist/assets/web/dist/assets/CostsPage-D-v8am88.js +2 -0
- package/dist/assets/web/dist/assets/{ResidentDetailPage-DYxDruS0.js → ResidentDetailPage-V4K35SYX.js} +1 -1
- package/dist/assets/web/dist/assets/{ResidentsIndexPage-DIBRBmuq.js → ResidentsIndexPage-3HuYaDwD.js} +1 -1
- package/dist/assets/web/dist/assets/{RunRoutePage-B4s8hJlW.js → RunRoutePage-Dr867-Ha.js} +4 -4
- package/dist/assets/web/dist/assets/{RunsIndexPage-CaW07KOf.js → RunsIndexPage-D_lpXsr8.js} +1 -1
- package/dist/assets/web/dist/assets/{ScheduledPage-Cr7269s9.js → ScheduledPage-dfrjQ5E9.js} +1 -1
- package/dist/assets/web/dist/assets/{StatusDot-lCLi16zY.js → StatusDot-DexKtvUC.js} +1 -1
- package/dist/assets/web/dist/assets/{Tooltip-DKMPwNyy.js → Tooltip-DGQ2gu9M.js} +1 -1
- package/dist/assets/web/dist/assets/{dist-DRkTB2rt.js → dist-boTdDLF4.js} +1 -1
- package/dist/assets/web/dist/assets/{main-CXKOiCOK.js → main-BHhLVMQh.js} +2 -2
- package/dist/cli.js +398 -224
- package/package.json +1 -1
- package/dist/assets/web/dist/assets/CostsPage-B08bdD-1.js +0 -2
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 (
|
|
447
|
-
|
|
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)))
|
|
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
|
-
|
|
14163
|
-
let known = cache2.get(slackId);
|
|
14167
|
+
let known = cache2.get(id);
|
|
14164
14168
|
if (known === void 0) {
|
|
14165
|
-
known = (await emailOfSlackUser(
|
|
14166
|
-
if (known !== void 0) cache2.set(
|
|
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,
|
|
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
|
|
36100
|
+
const taskText = shipTaskText(input.requestText, entry.repo);
|
|
36101
|
+
const request = parseShipPlanRequest(taskText);
|
|
36111
36102
|
if (request === void 0) {
|
|
36112
|
-
const
|
|
36113
|
-
const
|
|
36114
|
-
const
|
|
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
|
-
|
|
36119
|
-
|
|
36120
|
-
|
|
36121
|
-
|
|
36122
|
-
|
|
36123
|
-
|
|
36124
|
-
|
|
36125
|
-
|
|
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 {
|
|
36150
|
+
return {
|
|
36151
|
+
ok: true,
|
|
36152
|
+
planned: { planId, path: request.planPath, base, graph, selected, identity: identity2, merge: "runner" }
|
|
36153
|
+
};
|
|
36164
36154
|
}
|
|
36165
|
-
function rowsFor(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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:
|
|
36197
|
-
|
|
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
|
|
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:
|
|
36241
|
-
merge:
|
|
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
|
|
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:
|
|
36255
|
-
merge:
|
|
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"]);
|
|
@@ -40486,7 +40486,7 @@ var init_threadTurns = __esm({
|
|
|
40486
40486
|
"use strict";
|
|
40487
40487
|
init_reply();
|
|
40488
40488
|
APP_FOOTER_RE = /(?:^|\s)(?:\*Sent using\*|Sent using)\s+<@[A-Z0-9]+(?:\|[^>]*)?>(?:\s*\[[^\]\n]*\])?\s*$/;
|
|
40489
|
-
RELAY_FOOTER_RE = /(?:^|\s)Sent by Claude in <#([CGD][A-Z0-9_]+)(?:\|[^>]*)
|
|
40489
|
+
RELAY_FOOTER_RE = /(?:^|\s)Sent by Claude in <#([CGD][A-Z0-9_]+)(?:\|[^>]*)?>(?:\s+on behalf of <@([A-Z0-9]+)(?:\|[^>]*)?>)?\s*(?:·|•|-|—)\s*<(https?:\/\/[^|>\s]+)(?:\|[^>]*)?>\s*$/;
|
|
40490
40490
|
}
|
|
40491
40491
|
});
|
|
40492
40492
|
|
|
@@ -41257,12 +41257,35 @@ var init_lookups = __esm({
|
|
|
41257
41257
|
});
|
|
41258
41258
|
|
|
41259
41259
|
// ../../src/channels/slack/requester.ts
|
|
41260
|
+
function textOfBlocks(blocks) {
|
|
41261
|
+
if (!blocks) return "";
|
|
41262
|
+
const out = [];
|
|
41263
|
+
const walk2 = (b) => {
|
|
41264
|
+
if (typeof b.text === "string") out.push(b.text);
|
|
41265
|
+
else if (b.text && typeof b.text.text === "string") out.push(b.text.text);
|
|
41266
|
+
for (const e of b.elements ?? []) walk2(e);
|
|
41267
|
+
};
|
|
41268
|
+
for (const b of blocks) {
|
|
41269
|
+
const before = out.length;
|
|
41270
|
+
walk2(b);
|
|
41271
|
+
if (out.length > before) out.push("\n");
|
|
41272
|
+
}
|
|
41273
|
+
return out.join("").replace(/\n+$/, "");
|
|
41274
|
+
}
|
|
41275
|
+
function rawTextOf(text, blocks) {
|
|
41276
|
+
const base = text ?? "";
|
|
41277
|
+
const fromBlocks = textOfBlocks(blocks);
|
|
41278
|
+
if (!fromBlocks) return base;
|
|
41279
|
+
const extra = fromBlocks.split("\n").map((l) => l.trim()).filter((l) => l.length > 0 && !base.includes(l));
|
|
41280
|
+
return extra.length > 0 ? `${base}
|
|
41281
|
+
${extra.join("\n")}` : base;
|
|
41282
|
+
}
|
|
41260
41283
|
function parseRelayFooter(text) {
|
|
41261
41284
|
const m = RELAY_FOOTER_RE.exec(text);
|
|
41262
41285
|
if (!m) return void 0;
|
|
41263
41286
|
let url;
|
|
41264
41287
|
try {
|
|
41265
|
-
url = new URL(m[
|
|
41288
|
+
url = new URL(m[3].replaceAll("&", "&"));
|
|
41266
41289
|
} catch {
|
|
41267
41290
|
return void 0;
|
|
41268
41291
|
}
|
|
@@ -41272,7 +41295,7 @@ function parseRelayFooter(text) {
|
|
|
41272
41295
|
if (!ts) return void 0;
|
|
41273
41296
|
const threadTs = url.searchParams.get("thread_ts") ?? `${ts[1]}.${ts[2]}`;
|
|
41274
41297
|
if (!THREAD_TS.test(threadTs)) return void 0;
|
|
41275
|
-
return { channel: parts[1], threadTs };
|
|
41298
|
+
return { channel: parts[1], threadTs, ...m[2] ? { onBehalfOf: m[2] } : {} };
|
|
41276
41299
|
}
|
|
41277
41300
|
function rememberParent(key, user) {
|
|
41278
41301
|
relayParentCache.set(key, user);
|
|
@@ -41302,6 +41325,7 @@ async function resolveSlackRequester(client, ev) {
|
|
|
41302
41325
|
const poster = ev.poster ?? {};
|
|
41303
41326
|
const relay = parseRelayFooter(ev.text);
|
|
41304
41327
|
if (relay) {
|
|
41328
|
+
if (relay.onBehalfOf) return personRequester(relay.onBehalfOf, "relay-footer", poster);
|
|
41305
41329
|
const user = await threadParentUser(client, relay.channel, relay.threadTs);
|
|
41306
41330
|
if (user) return personRequester(user, "relay-footer", poster);
|
|
41307
41331
|
}
|
|
@@ -41552,7 +41576,7 @@ function createSlackApp(deps) {
|
|
|
41552
41576
|
channel: event.channel,
|
|
41553
41577
|
user: event.user,
|
|
41554
41578
|
poster: posterOf(posted),
|
|
41555
|
-
rawText: event.text
|
|
41579
|
+
rawText: rawTextOf(event.text, posted.blocks),
|
|
41556
41580
|
text: stripMention(event.text ?? "", botUserId),
|
|
41557
41581
|
ts: event.ts,
|
|
41558
41582
|
threadTs: event.thread_ts ?? event.ts,
|
|
@@ -41579,7 +41603,7 @@ function createSlackApp(deps) {
|
|
|
41579
41603
|
channel: m.channel,
|
|
41580
41604
|
user: m.user,
|
|
41581
41605
|
poster: posterOf(m),
|
|
41582
|
-
rawText: m.text
|
|
41606
|
+
rawText: rawTextOf(m.text, m.blocks),
|
|
41583
41607
|
text: stripMention(m.text ?? "", botUserId),
|
|
41584
41608
|
ts: m.ts,
|
|
41585
41609
|
threadTs: m.thread_ts ?? m.ts,
|
|
@@ -43751,7 +43775,7 @@ var init_accessAuth = __esm({
|
|
|
43751
43775
|
});
|
|
43752
43776
|
|
|
43753
43777
|
// ../../src/channels/dashboardAuth.ts
|
|
43754
|
-
import { createHash as
|
|
43778
|
+
import { createHash as createHash5, timingSafeEqual as timingSafeEqual4 } from "node:crypto";
|
|
43755
43779
|
function header2(headers, name) {
|
|
43756
43780
|
const raw = headers[name];
|
|
43757
43781
|
return Array.isArray(raw) ? raw[0] : raw;
|
|
@@ -43769,8 +43793,8 @@ function accessVerifier(config, deps) {
|
|
|
43769
43793
|
};
|
|
43770
43794
|
}
|
|
43771
43795
|
function secretsEqual(a, b) {
|
|
43772
|
-
const ha =
|
|
43773
|
-
const hb =
|
|
43796
|
+
const ha = createHash5("sha256").update(a).digest();
|
|
43797
|
+
const hb = createHash5("sha256").update(b).digest();
|
|
43774
43798
|
return timingSafeEqual4(ha, hb);
|
|
43775
43799
|
}
|
|
43776
43800
|
function tokenVerifier(opts) {
|
|
@@ -44799,6 +44823,147 @@ var init_adminRestartAuthorize = __esm({
|
|
|
44799
44823
|
}
|
|
44800
44824
|
});
|
|
44801
44825
|
|
|
44826
|
+
// ../../src/core/ship/reviewChild.ts
|
|
44827
|
+
function buildShipReviewTurn(input) {
|
|
44828
|
+
const at = input.headSha ? ` at head \`${input.headSha}\`` : "";
|
|
44829
|
+
if (input.round <= 1 || !input.prior) {
|
|
44830
|
+
return `Review pull request ${input.where}${at}. Submit your verdict with findings via submit_verdict before your final message.`;
|
|
44831
|
+
}
|
|
44832
|
+
const findings = input.prior.findings.map(formatFinding).join("\n") || "(none recorded)";
|
|
44833
|
+
const dispositions = input.prior.dispositions.map((d) => `${d.findingId}: ${d.disposition}${d.note ? ` \u2014 ${d.note}` : ""}`).join("\n") || "(none recorded)";
|
|
44834
|
+
const dropped = input.prior.dropped !== void 0 && input.prior.dropped.length > 0 ? `
|
|
44835
|
+
Dispositions naming no finding of the previous round (dropped): ${input.prior.dropped.join(", ")}` : "";
|
|
44836
|
+
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.
|
|
44837
|
+
|
|
44838
|
+
Previous round's findings:
|
|
44839
|
+
${findings}
|
|
44840
|
+
|
|
44841
|
+
Fix round's dispositions:
|
|
44842
|
+
${dispositions}${dropped}`;
|
|
44843
|
+
}
|
|
44844
|
+
var init_reviewChild = __esm({
|
|
44845
|
+
"../../src/core/ship/reviewChild.ts"() {
|
|
44846
|
+
"use strict";
|
|
44847
|
+
init_reviewVerdict();
|
|
44848
|
+
}
|
|
44849
|
+
});
|
|
44850
|
+
|
|
44851
|
+
// ../../src/core/coordinator/briefs.ts
|
|
44852
|
+
async function generatedUnitOf(instance, unit, readers) {
|
|
44853
|
+
const resume = unit.resume;
|
|
44854
|
+
if (resume !== void 0) {
|
|
44855
|
+
const url = resume.url ?? `https://github.com/${instance.repo}/pull/${resume.pr}`;
|
|
44856
|
+
return generatedUnit(unit.unit, `Resume the review loop of ${url}`);
|
|
44857
|
+
}
|
|
44858
|
+
const request = await readers.readShipRequest();
|
|
44859
|
+
const task = request !== void 0 ? shipTaskText(parseDirectives(request).text, instance.repo) : "";
|
|
44860
|
+
return generatedUnit(unit.unit, task || "Implement the task this thread's ship request describes.");
|
|
44861
|
+
}
|
|
44862
|
+
async function contractFor(instance, unit, readers) {
|
|
44863
|
+
const rebase = { branch: unit.branch, onto: instance.base ?? "main" };
|
|
44864
|
+
const issue = unit.issue !== void 0 ? { repo: instance.repo, number: unit.issue } : void 0;
|
|
44865
|
+
let source2;
|
|
44866
|
+
if (isGenerated(instance)) {
|
|
44867
|
+
source2 = { unit: await generatedUnitOf(instance, unit, readers) };
|
|
44868
|
+
} else {
|
|
44869
|
+
const planMarkdown = await readers.readRepoFile(instance.plan.path);
|
|
44870
|
+
if (planMarkdown === void 0)
|
|
44871
|
+
throw new Error(`the plan ${instance.plan.path} is not readable at ${rebase.onto} in ${instance.repo}`);
|
|
44872
|
+
source2 = { planMarkdown, unitId: unit.unit };
|
|
44873
|
+
}
|
|
44874
|
+
const section = ("unit" in source2 ? source2.unit : parsePlanUnit(source2.planMarkdown, unit.unit))?.section ?? "";
|
|
44875
|
+
const specs = /* @__PURE__ */ new Map();
|
|
44876
|
+
for (const spec of new Set(specItemRefs(section).map((r) => r.spec)))
|
|
44877
|
+
specs.set(spec, await readers.readRepoFile(`${SPECS_DIR2}/${spec}`));
|
|
44878
|
+
let agentRules;
|
|
44879
|
+
for (const file of RULES_FILES2) {
|
|
44880
|
+
const text = await readers.readRepoFile(file);
|
|
44881
|
+
if (text !== void 0) {
|
|
44882
|
+
agentRules = { file, text };
|
|
44883
|
+
break;
|
|
44884
|
+
}
|
|
44885
|
+
}
|
|
44886
|
+
return contractFromPlan({
|
|
44887
|
+
...source2,
|
|
44888
|
+
readSpec: (spec) => specs.get(spec),
|
|
44889
|
+
...agentRules ? { agentRules } : {},
|
|
44890
|
+
rebase,
|
|
44891
|
+
...issue ? { issue } : {}
|
|
44892
|
+
});
|
|
44893
|
+
}
|
|
44894
|
+
function findingsRequest(input) {
|
|
44895
|
+
const findings = input.findings.map(formatFinding).join("\n") || "(the review listed no structured findings, address its prose)";
|
|
44896
|
+
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.
|
|
44897
|
+
|
|
44898
|
+
Findings:
|
|
44899
|
+
${findings}
|
|
44900
|
+
|
|
44901
|
+
Review:
|
|
44902
|
+
${input.review}`;
|
|
44903
|
+
}
|
|
44904
|
+
async function composeChild(brief, instance, unit, readers) {
|
|
44905
|
+
const where = `${instance.repo}#${"pr" in brief ? brief.pr : ""}`;
|
|
44906
|
+
switch (brief.kind) {
|
|
44907
|
+
case "contract": {
|
|
44908
|
+
const contract = await contractFor(instance, unit, readers);
|
|
44909
|
+
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.`;
|
|
44910
|
+
return { preset: "coding", prompt, ref: unit.branch, contract };
|
|
44911
|
+
}
|
|
44912
|
+
case "review": {
|
|
44913
|
+
let prior;
|
|
44914
|
+
if (brief.prior !== void 0) {
|
|
44915
|
+
const findings = (await facts(readers, brief.prior.reviewRunId)).findings ?? [];
|
|
44916
|
+
const recorded = brief.prior.codingRunId !== void 0 ? (await facts(readers, brief.prior.codingRunId)).dispositions ?? [] : [];
|
|
44917
|
+
const { matched, dropped } = matchDispositions(findings, recorded);
|
|
44918
|
+
prior = { findings, dispositions: matched, dropped };
|
|
44919
|
+
}
|
|
44920
|
+
const turn = buildShipReviewTurn({
|
|
44921
|
+
where,
|
|
44922
|
+
round: brief.round,
|
|
44923
|
+
...brief.headSha !== void 0 ? { headSha: brief.headSha } : {},
|
|
44924
|
+
...prior ? { prior } : {}
|
|
44925
|
+
});
|
|
44926
|
+
const contract = await contractFor(instance, unit, readers);
|
|
44927
|
+
return { preset: "review", prompt: `${prUrl(instance.repo, brief.pr)}
|
|
44928
|
+
|
|
44929
|
+
${turn}`, contract };
|
|
44930
|
+
}
|
|
44931
|
+
case "findings": {
|
|
44932
|
+
const review = await facts(readers, brief.reviewRunId);
|
|
44933
|
+
return {
|
|
44934
|
+
preset: "coding",
|
|
44935
|
+
prompt: findingsRequest({ where, findings: review.findings ?? [], review: review.finalReply ?? "" }),
|
|
44936
|
+
ref: unit.branch
|
|
44937
|
+
};
|
|
44938
|
+
}
|
|
44939
|
+
default: {
|
|
44940
|
+
const unknown = brief;
|
|
44941
|
+
throw new Error(`unknown brief kind ${JSON.stringify(unknown.kind)}`);
|
|
44942
|
+
}
|
|
44943
|
+
}
|
|
44944
|
+
}
|
|
44945
|
+
async function facts(readers, runId3) {
|
|
44946
|
+
const read = await readers.readRunFacts(runId3);
|
|
44947
|
+
if (!read) throw new Error(`run ${runId3} is not in the run history`);
|
|
44948
|
+
return read;
|
|
44949
|
+
}
|
|
44950
|
+
var SPECS_DIR2, RULES_FILES2, isGenerated, prUrl;
|
|
44951
|
+
var init_briefs = __esm({
|
|
44952
|
+
"../../src/core/coordinator/briefs.ts"() {
|
|
44953
|
+
"use strict";
|
|
44954
|
+
init_directives();
|
|
44955
|
+
init_reviewVerdict();
|
|
44956
|
+
init_coordinator();
|
|
44957
|
+
init_contract();
|
|
44958
|
+
init_preflight();
|
|
44959
|
+
init_reviewChild();
|
|
44960
|
+
SPECS_DIR2 = "docs/reference/specs";
|
|
44961
|
+
RULES_FILES2 = ["AGENTS.md", "CLAUDE.md"];
|
|
44962
|
+
isGenerated = (instance) => instance.plan?.path === void 0;
|
|
44963
|
+
prUrl = (repo, pr) => `https://github.com/${repo}/pull/${pr}`;
|
|
44964
|
+
}
|
|
44965
|
+
});
|
|
44966
|
+
|
|
44802
44967
|
// ../../src/channels/adminCoordinator.ts
|
|
44803
44968
|
function isCoordinatorAdminPath(path) {
|
|
44804
44969
|
return path.startsWith(COORDINATOR_ADMIN_PREFIX) && path.length > COORDINATOR_ADMIN_PREFIX.length;
|
|
@@ -44913,7 +45078,7 @@ async function unitRowOf(deps, instance, unit) {
|
|
|
44913
45078
|
return { ok: true, row };
|
|
44914
45079
|
}
|
|
44915
45080
|
function unitThread(instance, row) {
|
|
44916
|
-
const threadKey = row?.threadKey ?? (row === void 0 ||
|
|
45081
|
+
const threadKey = row?.threadKey ?? (row === void 0 || isGenerated2(instance) ? instance.threadKey : void 0);
|
|
44917
45082
|
const sourceUrl = row?.sourceUrl ?? (threadKey === instance.threadKey ? instance.sourceUrl : void 0);
|
|
44918
45083
|
return { threadKey, sourceUrl };
|
|
44919
45084
|
}
|
|
@@ -45054,7 +45219,7 @@ async function spawn6(body, deps) {
|
|
|
45054
45219
|
if (req.brief !== void 0) {
|
|
45055
45220
|
if (row === void 0) return json(400, { ok: false, error: "a brief needs the unit it runs for" });
|
|
45056
45221
|
try {
|
|
45057
|
-
turn = await composeChild(req.brief, instance, row, briefReaders(deps, instance
|
|
45222
|
+
turn = await composeChild(req.brief, instance, row, briefReaders(deps, instance));
|
|
45058
45223
|
} catch (err2) {
|
|
45059
45224
|
log(`[coordinator] ${instance.id} ${req.step}: the brief could not be composed: ${describe11(err2)}`);
|
|
45060
45225
|
return json(502, { ok: false, error: "brief_failed", message: describe11(err2), at });
|
|
@@ -45283,6 +45448,8 @@ async function plan2(body, deps) {
|
|
|
45283
45448
|
...instance.plan !== void 0 ? { planId: instance.plan.id } : {},
|
|
45284
45449
|
// Who merges: the instance's field; a record written before it existed is a person's merge.
|
|
45285
45450
|
merge: instance.merge ?? "person",
|
|
45451
|
+
// The mark (item 16): the machine's report keys its re-issue line on it.
|
|
45452
|
+
generated: isGenerated2(instance),
|
|
45286
45453
|
repo: instance.repo,
|
|
45287
45454
|
base: instance.base ?? "main",
|
|
45288
45455
|
caps: instance.caps ?? resolveShipCaps(void 0),
|
|
@@ -45312,7 +45479,7 @@ async function unitStart(body, deps) {
|
|
|
45312
45479
|
if (!unit.ok) return unit.response;
|
|
45313
45480
|
let row = unit.row;
|
|
45314
45481
|
if (row.threadKey === void 0) {
|
|
45315
|
-
if (
|
|
45482
|
+
if (isGenerated2(instance)) {
|
|
45316
45483
|
row = {
|
|
45317
45484
|
...row,
|
|
45318
45485
|
threadKey: instance.threadKey,
|
|
@@ -45332,7 +45499,7 @@ async function unitStart(body, deps) {
|
|
|
45332
45499
|
}
|
|
45333
45500
|
row = review.row;
|
|
45334
45501
|
}
|
|
45335
|
-
if (row.issue === void 0 &&
|
|
45502
|
+
if (row.issue === void 0 && !isGenerated2(instance)) {
|
|
45336
45503
|
const issue = await unitIssueOf(deps, instance.repo, row.unit);
|
|
45337
45504
|
if (issue !== void 0) row = { ...row, issue };
|
|
45338
45505
|
}
|
|
@@ -45359,7 +45526,7 @@ function unitLead(instance, row) {
|
|
|
45359
45526
|
function reviewLead(instance, row) {
|
|
45360
45527
|
const who2 = instance.userName ?? instance.userId;
|
|
45361
45528
|
const from = instance.sourceUrl !== void 0 ? `[the *ship* run](${instance.sourceUrl})` : "the *ship* run";
|
|
45362
|
-
const what =
|
|
45529
|
+
const what = isGenerated2(instance) ? "the task" : `unit ${row.unit}${row.title ? ` \u2014 ${row.title}` : ""}`;
|
|
45363
45530
|
return `\u21B3 *ship* review of ${what} for ${who2}, from ${from}: \`${row.branch}\` in ${instance.repo}`;
|
|
45364
45531
|
}
|
|
45365
45532
|
async function branch(body, deps) {
|
|
@@ -45382,11 +45549,11 @@ async function branch(body, deps) {
|
|
|
45382
45549
|
return json(200, { ok: false, reason: describe11(err2), at });
|
|
45383
45550
|
}
|
|
45384
45551
|
}
|
|
45385
|
-
function unitLines(units) {
|
|
45552
|
+
function unitLines(units, generated) {
|
|
45386
45553
|
return units.map((u) => {
|
|
45387
45554
|
const last = u.rounds.at(-1);
|
|
45388
45555
|
const state = u.ending ? u.ending.kind : last ? `${shipRoundHeader({ index: last.index, agent: last.agent })} \xB7 ${last.outcome}` : u.threadKey ? "starting" : "waiting";
|
|
45389
|
-
return
|
|
45556
|
+
return generated ? state : `${u.unit} \xB7 ${state}`;
|
|
45390
45557
|
});
|
|
45391
45558
|
}
|
|
45392
45559
|
async function drawCard(deps, instance, units, close) {
|
|
@@ -45395,7 +45562,7 @@ async function drawCard(deps, instance, units, close) {
|
|
|
45395
45562
|
if (!io) return;
|
|
45396
45563
|
const clock4 = deps.clock ?? systemClock;
|
|
45397
45564
|
const shell = createCardShell({ label: instance.label ?? "*ship*", startedAt: instance.createdAt, now: clock4 });
|
|
45398
|
-
const detail = unitLines(units);
|
|
45565
|
+
const detail = unitLines(units, isGenerated2(instance));
|
|
45399
45566
|
if (!close) {
|
|
45400
45567
|
await io.status(shell.live({ detail }));
|
|
45401
45568
|
return;
|
|
@@ -45613,7 +45780,7 @@ function parentRunRecord(instance, units, outcome, channelVisibility, finishedAt
|
|
|
45613
45780
|
at: r.at
|
|
45614
45781
|
}))
|
|
45615
45782
|
),
|
|
45616
|
-
{ type: "answer", text: planSummary(units), at: finishedAt }
|
|
45783
|
+
{ type: "answer", text: planSummary(units, isGenerated2(instance)), at: finishedAt }
|
|
45617
45784
|
];
|
|
45618
45785
|
events.forEach((e, i) => {
|
|
45619
45786
|
e.seq = i + 1;
|
|
@@ -45639,11 +45806,11 @@ function parentRunRecord(instance, units, outcome, channelVisibility, finishedAt
|
|
|
45639
45806
|
...instance.sourceUrl !== void 0 ? { sourceUrl: instance.sourceUrl } : {}
|
|
45640
45807
|
};
|
|
45641
45808
|
}
|
|
45642
|
-
function planSummary(units) {
|
|
45809
|
+
function planSummary(units, generated = false) {
|
|
45643
45810
|
const lines = units.map((u) => {
|
|
45644
45811
|
const how = u.ending ? u.ending.kind : u.threadKey ? "unfinished" : "not started";
|
|
45645
45812
|
const pr = u.pr ? ` \u2014 ${u.pr.url}` : "";
|
|
45646
|
-
return
|
|
45813
|
+
return generated ? `${ENDING_ICON[how] ?? "\u2022"} ${how}${pr}` : `${ENDING_ICON[how] ?? "\u2022"} ${u.unit} \u2014 ${how}${pr}`;
|
|
45647
45814
|
});
|
|
45648
45815
|
return lines.join("\n");
|
|
45649
45816
|
}
|
|
@@ -45661,8 +45828,7 @@ async function finish(body, deps) {
|
|
|
45661
45828
|
deps.runHistoryWriter.write(record2);
|
|
45662
45829
|
await drawCard(deps, instance, units, { icon: body.outcome === "completed" ? "\u2705" : "\u26A0\uFE0F" }).catch(() => {
|
|
45663
45830
|
});
|
|
45664
|
-
|
|
45665
|
-
if (isPlan) {
|
|
45831
|
+
if (!isGenerated2(instance)) {
|
|
45666
45832
|
const io = deps.ioFor({ threadKey: instance.threadKey, userId: instance.userId });
|
|
45667
45833
|
await io?.reply(`Plan ${instance.plan?.id ?? ""} ended (${body.outcome}):
|
|
45668
45834
|
${planSummary(units)}`).catch(() => {
|
|
@@ -45671,7 +45837,7 @@ ${planSummary(units)}`).catch(() => {
|
|
|
45671
45837
|
(deps.log ?? console.log)(`[coordinator] ${instance.id}: finished ${body.outcome} \u2014 record ${record2.id}`);
|
|
45672
45838
|
return json(200, { ok: true, runId: record2.id, at });
|
|
45673
45839
|
}
|
|
45674
|
-
function briefReaders(deps, instance
|
|
45840
|
+
function briefReaders(deps, instance) {
|
|
45675
45841
|
const ref = instance.base ?? "main";
|
|
45676
45842
|
return {
|
|
45677
45843
|
readRepoFile: async (path) => {
|
|
@@ -45691,9 +45857,16 @@ function briefReaders(deps, instance, io) {
|
|
|
45691
45857
|
...finalReplyOf2(r.events) !== void 0 ? { finalReply: finalReplyOf2(r.events) } : {}
|
|
45692
45858
|
};
|
|
45693
45859
|
},
|
|
45860
|
+
// The generated plan's request text: the ship run's own record
|
|
45861
|
+
// (`instance.runId`, its `input` event) — never a scan of the thread, so a
|
|
45862
|
+
// routed request with no `agent:ship` turn anywhere still reads back the
|
|
45863
|
+
// words the person typed (agent-ship item 13).
|
|
45694
45864
|
readShipRequest: async () => {
|
|
45695
|
-
|
|
45696
|
-
|
|
45865
|
+
if (instance.runId === void 0) return void 0;
|
|
45866
|
+
const res = await deps.runs.getRun(instance.runId, { include: "messages" }).catch(() => void 0);
|
|
45867
|
+
if (res === void 0 || !res.ok) return void 0;
|
|
45868
|
+
const input = (res.value.events ?? []).find((e) => e.type === "input");
|
|
45869
|
+
return input?.type === "input" ? input.text : void 0;
|
|
45697
45870
|
}
|
|
45698
45871
|
};
|
|
45699
45872
|
}
|
|
@@ -45769,7 +45942,7 @@ function createAdminCoordinatorHandler(deps) {
|
|
|
45769
45942
|
})();
|
|
45770
45943
|
};
|
|
45771
45944
|
}
|
|
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;
|
|
45945
|
+
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
45946
|
var init_adminCoordinator = __esm({
|
|
45774
45947
|
"../../src/channels/adminCoordinator.ts"() {
|
|
45775
45948
|
"use strict";
|
|
@@ -45803,6 +45976,7 @@ var init_adminCoordinator = __esm({
|
|
|
45803
45976
|
invalid = (error) => ({ ok: false, error });
|
|
45804
45977
|
json = (status3, body) => ({ status: status3, body });
|
|
45805
45978
|
describe11 = (err2) => err2 instanceof Error ? err2.message : String(err2);
|
|
45979
|
+
isGenerated2 = (instance) => instance.plan?.path === void 0;
|
|
45806
45980
|
EVERY_RUN = { kind: "all" };
|
|
45807
45981
|
REVIEW_POSTED_CHECKS = 3;
|
|
45808
45982
|
REVIEW_POSTED_RECHECK_MS = 2e3;
|