@coreplane/switchboard 1.263.0 → 1.264.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/assets/config/config.example.yaml +4 -2
- package/dist/assets/deploy/cloudflare/prImages.ts +6 -1
- 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/driver.ts +1 -0
- package/dist/assets/src/core/ship/coordinator.ts +11 -0
- package/dist/cli.js +10 -5
- package/package.json +1 -1
|
@@ -435,8 +435,10 @@ workspaceDir: ./workspaces
|
|
|
435
435
|
# integer >= 14 (the loop's reserve plus one round). `maxMinutes` is the ship
|
|
436
436
|
# preset's declared budget: a channel or user `boundary.maxMinutes` and a
|
|
437
437
|
# per-message `budget:` directive clip it like any preset's, and the card says
|
|
438
|
-
# so.
|
|
439
|
-
#
|
|
438
|
+
# so. An unfinished pipeline keeps only its remaining rounds and minutes on
|
|
439
|
+
# continuation. A new task after merge-ready starts with fresh caps, even when
|
|
440
|
+
# it adopts that pull request. Defaults shown; `maxRounds` must be an integer
|
|
441
|
+
# >= 1; any other key under `ship` fails the load by name.
|
|
440
442
|
# ship:
|
|
441
443
|
# maxRounds: 3 # review rounds per unit
|
|
442
444
|
# maxMinutes: 240 # the ship preset's wall-clock budget in minutes (the registry's default)
|
|
@@ -57,7 +57,12 @@ export async function publishPrImage(
|
|
|
57
57
|
if (!object) return json(404, { error: "artifact not found" });
|
|
58
58
|
let bytes: Uint8Array;
|
|
59
59
|
try {
|
|
60
|
-
|
|
60
|
+
// R2ObjectBody is a runtime object; its size and body need not be enumerable.
|
|
61
|
+
bytes = await readPrImage({
|
|
62
|
+
size: object.size,
|
|
63
|
+
body: object.body,
|
|
64
|
+
contentType: object.httpMetadata?.contentType ?? "",
|
|
65
|
+
});
|
|
61
66
|
} catch {
|
|
62
67
|
// A storage stream can fail with internal paths or stack details; the caller
|
|
63
68
|
// needs only the stable validation result.
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "switchboard",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.264.0",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "switchboard",
|
|
9
|
-
"version": "1.
|
|
9
|
+
"version": "1.264.0",
|
|
10
10
|
"license": "Apache-2.0",
|
|
11
11
|
"workspaces": [
|
|
12
12
|
"web",
|
|
@@ -21060,7 +21060,7 @@
|
|
|
21060
21060
|
},
|
|
21061
21061
|
"packages/switchboard": {
|
|
21062
21062
|
"name": "@coreplane/switchboard",
|
|
21063
|
-
"version": "1.
|
|
21063
|
+
"version": "1.264.0",
|
|
21064
21064
|
"license": "Apache-2.0",
|
|
21065
21065
|
"dependencies": {
|
|
21066
21066
|
"@earendil-works/pi-ai": "0.85.1",
|
package/dist/assets/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "switchboard",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.264.0",
|
|
4
4
|
"private": true,
|
|
5
5
|
"description": "Mention it in Slack and an agent reviews the PR, ships the fix, or answers the question — on the model you choose, with its tools running where you decide.",
|
|
6
6
|
"license": "Apache-2.0",
|
package/dist/assets/source.json
CHANGED
|
@@ -1050,6 +1050,7 @@ async function runUnit(
|
|
|
1050
1050
|
generated: plan.generated,
|
|
1051
1051
|
...(plan.runPageBase !== undefined ? { runPageBase: plan.runPageBase } : {}),
|
|
1052
1052
|
...(resume !== undefined ? { resume } : {}),
|
|
1053
|
+
...(row?.publication !== undefined && resume === undefined && lastPush === undefined ? { freshAdopt: true } : {}),
|
|
1053
1054
|
...(lastPush !== undefined ? { lastPush } : {}),
|
|
1054
1055
|
...(session !== undefined ? { session } : {}),
|
|
1055
1056
|
...(row?.recovery !== undefined
|
|
@@ -1167,6 +1167,9 @@ export interface UnitPipelineInput {
|
|
|
1167
1167
|
idleDays?: number;
|
|
1168
1168
|
/** Resume at review: an open pull request of ship's own the requester named. */
|
|
1169
1169
|
resume?: { pr: number; headSha?: string; url?: string };
|
|
1170
|
+
/** A task adopted an existing PR without a prior coding push. Its old
|
|
1171
|
+
* approval and checks cannot answer this task, so pre-check starts coding. */
|
|
1172
|
+
freshAdopt?: boolean;
|
|
1170
1173
|
/** The head the previous attempt's coding child last pushed (a
|
|
1171
1174
|
* `review_pending` ending's `headSha`, carried on the unit's row): when the
|
|
1172
1175
|
* pre-check finds the open pull request still at exactly this head, there is
|
|
@@ -3083,6 +3086,8 @@ export function applyReturn(s: UnitPipelineState, ret: StepReturn): Transition {
|
|
|
3083
3086
|
};
|
|
3084
3087
|
return nextReview(adopted);
|
|
3085
3088
|
}
|
|
3089
|
+
if (s.input.freshAdopt === true)
|
|
3090
|
+
return enterRound({ ...clocked, pr: { number: r.pr.prNumber, url: r.pr.url } }, { index: 0, kind: "coding" });
|
|
3086
3091
|
const branchHead = normalizeHead(r.pr.branchHead);
|
|
3087
3092
|
const lastPush = normalizeHead(s.input.lastPush);
|
|
3088
3093
|
const atBranchHead = head !== undefined && branchHead !== undefined && sameCommit(head, branchHead);
|
|
@@ -3121,6 +3126,12 @@ export function applyReturn(s: UnitPipelineState, ret: StepReturn): Transition {
|
|
|
3121
3126
|
return nextReview(adopted);
|
|
3122
3127
|
}
|
|
3123
3128
|
}
|
|
3129
|
+
if (s.input.freshAdopt === true)
|
|
3130
|
+
return end(clocked, {
|
|
3131
|
+
kind: "aborted",
|
|
3132
|
+
reason: `⚠️ The adopted pull request on ${s.input.repo} is no longer open, so coding did not start.`,
|
|
3133
|
+
reviewRounds: s.reviewRounds,
|
|
3134
|
+
});
|
|
3124
3135
|
return { state: { ...clocked, phase: { at: "branch" } }, notes: [] };
|
|
3125
3136
|
}
|
|
3126
3137
|
case "branch": {
|
package/dist/cli.js
CHANGED
|
@@ -40789,21 +40789,26 @@ function instanceOf(runs) {
|
|
|
40789
40789
|
return void 0;
|
|
40790
40790
|
}
|
|
40791
40791
|
async function ownerOf2(runs, unitsOf, threadKey) {
|
|
40792
|
-
const live = runs.find((r) => !r.finished);
|
|
40792
|
+
const live = runs.find((r) => !r.finished && r.hosted !== true);
|
|
40793
40793
|
if (live !== void 0) return { kind: "live", run: live };
|
|
40794
|
+
const hosted = runs.find((r) => !r.finished && r.hosted === true);
|
|
40794
40795
|
const instanceId = instanceOf(runs);
|
|
40795
40796
|
if (instanceId !== void 0) {
|
|
40796
40797
|
const units = await unitsOf(instanceId).catch(() => []);
|
|
40797
40798
|
const unit = units.find((u) => u.threadKey === threadKey && u.ending === void 0);
|
|
40798
40799
|
if (unit !== void 0) return { kind: "unit", instanceId, unit };
|
|
40800
|
+
if (hosted !== void 0) return { kind: "live", run: hosted };
|
|
40799
40801
|
const ended = units.filter(
|
|
40800
|
-
(u) => u.threadKey === threadKey && u.ending !== void 0 && u.ending.kind !== "merged" && u.ending.kind !== "already_landed"
|
|
40802
|
+
(u) => u.threadKey === threadKey && u.ending !== void 0 && u.ending.kind !== "merged" && u.ending.kind !== "already_landed" && // A completed, publication-bound PR is new work on the next reply.
|
|
40803
|
+
// Keep older rows without that binding on the guarded recovery path.
|
|
40804
|
+
(u.ending.kind !== "merge_ready" || u.publication === void 0)
|
|
40801
40805
|
);
|
|
40802
40806
|
const ship = runs.find((r) => r.instanceId === instanceId && r.finished);
|
|
40803
40807
|
if (ended.length === 1 && ship !== void 0) return { kind: "pipeline", instanceId, run: ship, unit: ended[0] };
|
|
40804
40808
|
if (ended.length > 1 && ship !== void 0)
|
|
40805
40809
|
return { kind: "pipeline_ambiguous", instanceId, run: ship, units: ended };
|
|
40806
40810
|
}
|
|
40811
|
+
if (hosted !== void 0) return { kind: "live", run: hosted };
|
|
40807
40812
|
const agent = stickyAgentOf(runs);
|
|
40808
40813
|
if (agent !== void 0) return { kind: "session", agent };
|
|
40809
40814
|
return { kind: "none" };
|
|
@@ -56711,7 +56716,7 @@ async function dispatch(deps, msg, io, opts = {}) {
|
|
|
56711
56716
|
// offers no steer line, the executor folds a steer bind like any
|
|
56712
56717
|
// other, and the fold runs on to the seed refusal below, which
|
|
56713
56718
|
// names the unit threads to reply in.
|
|
56714
|
-
pageOwner.run.
|
|
56719
|
+
pageOwner.run.hosted === true ? { kind: "live" } : { kind: "live", runId: pageOwner.run.id }
|
|
56715
56720
|
) : pageOwner?.kind === "unit" ? { kind: "unit", unit: pageOwner.unit.unit } : pageOwner?.kind === "pipeline" ? { kind: "pipeline", unit: pageOwner.unit.unit } : pageOwner?.kind === "pipeline_ambiguous" ? { kind: "pipeline", unit: pageOwner.units.map((unit) => unit.unit).join(", ") } : void 0;
|
|
56716
56721
|
operatorEvent = await root.span(
|
|
56717
56722
|
"dispatch.operator",
|
|
@@ -56798,8 +56803,8 @@ async function dispatch(deps, msg, io, opts = {}) {
|
|
|
56798
56803
|
const threadLive = admission.get(msg.threadKey) !== void 0 || !resume && !restart && deps.threadsElsewhere.get(msg.threadKey) !== void 0;
|
|
56799
56804
|
if (thread && !threadLive && deps.coordinatorInstances !== void 0) {
|
|
56800
56805
|
const owner = pageOwner ?? await ownerOf2(thread, (id) => deps.coordinatorInstances.listUnits(id), msg.threadKey);
|
|
56801
|
-
if (owner.kind === "live" && owner.run.
|
|
56802
|
-
const units = await deps.coordinatorInstances.listUnits(owner.run.instanceId).catch(() => []);
|
|
56806
|
+
if (owner.kind === "live" && owner.run.hosted === true) {
|
|
56807
|
+
const units = owner.run.instanceId === void 0 ? [] : await deps.coordinatorInstances.listUnits(owner.run.instanceId).catch(() => []);
|
|
56803
56808
|
const open2 = units.filter((u) => u.ending === void 0);
|
|
56804
56809
|
await refuse3(
|
|
56805
56810
|
refusalOf(
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coreplane/switchboard",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.264.0",
|
|
4
4
|
"description": "Mention it in Slack and an agent reviews the PR, ships the fix, or answers the question — on the model you choose, with its tools running where you decide.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://openswitchboard.dev",
|