@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.
@@ -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. Defaults shown; `maxRounds` must be an integer >= 1; any other key under
439
- # `ship` fails the load by name.
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
- bytes = await readPrImage({ ...object, contentType: object.httpMetadata?.contentType ?? "" });
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.263.0",
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.263.0",
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.263.0",
21063
+ "version": "1.264.0",
21064
21064
  "license": "Apache-2.0",
21065
21065
  "dependencies": {
21066
21066
  "@earendil-works/pi-ai": "0.85.1",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "switchboard",
3
- "version": "1.263.0",
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",
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.263.0",
3
- "commit": "45ff7fda11fb77898cd9677f0c6e42efd4f9ffbf",
4
- "builtAt": "2026-09-26T01:33:01.056Z"
2
+ "version": "1.264.0",
3
+ "commit": "3f965ac7812604e62bd3e7df613ccf72ee665615",
4
+ "builtAt": "2026-09-26T02:38:42.181Z"
5
5
  }
@@ -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.instanceId !== void 0 ? { kind: "live" } : { kind: "live", runId: pageOwner.run.id }
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.instanceId !== void 0) {
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.263.0",
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",