@coreplane/switchboard 1.235.0 → 1.237.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/Dockerfile +11 -0
- package/dist/assets/config/config.example.yaml +9 -4
- package/dist/assets/deploy/cloudflare-memory/worker.ts +12 -0
- package/dist/assets/deploy/cloudflare-resident/Dockerfile +18 -0
- package/dist/assets/deploy/cloudflare-resident/worker.ts +290 -118
- package/dist/assets/deploy/cloudflare-sandbox/Dockerfile +11 -0
- package/dist/assets/deploy/cloudflare-sandbox/worker.ts +104 -17
- package/dist/assets/package-lock.json +212 -3
- package/dist/assets/package.json +4 -1
- package/dist/assets/source.json +3 -3
- package/dist/assets/src/core/authz/authorize.ts +25 -6
- package/dist/assets/src/core/authz/policy.ts +9 -0
- package/dist/assets/src/core/authz/types.ts +15 -1
- package/dist/assets/src/core/coordinator/contract.ts +24 -4
- package/dist/assets/src/core/coordinator/driver.ts +36 -4
- package/dist/assets/src/core/runEvents.ts +46 -7
- package/dist/assets/src/core/runFriction.ts +1 -0
- package/dist/assets/src/core/ship/contract.ts +3 -1
- package/dist/assets/src/core/ship/coordinator.ts +236 -30
- package/dist/assets/src/core/trace/types.ts +5 -0
- package/dist/assets/src/execution/residentDepsStore.ts +14 -2
- package/dist/assets/src/execution/residentDisk.ts +21 -10
- package/dist/assets/src/execution/residentDiskBudget.ts +45 -11
- package/dist/assets/src/execution/residentHead.ts +34 -8
- package/dist/assets/src/execution/residentRebind.ts +88 -31
- package/dist/assets/src/execution/sandboxErrors.ts +72 -0
- package/dist/assets/src/execution/sandboxLifecycle.ts +33 -0
- package/dist/assets/src/execution/sandboxStart.ts +90 -0
- package/dist/assets/web/dist/.vite/manifest.json +437 -423
- package/dist/assets/web/dist/assets/AppShell-MYHNxJks.js +1 -0
- package/dist/assets/web/dist/assets/{CostsPage-D-v8am88.js → CostsPage-DKk9OjB0.js} +1 -1
- package/dist/assets/web/dist/assets/{DeliveryPage-CvlWP7Eq.js → DeliveryPage-Kz6js49i.js} +1 -1
- package/dist/assets/web/dist/assets/{NotFoundPage-BzWS4Ca1.js → NotFoundPage-BXLrQQzy.js} +1 -1
- package/dist/assets/web/dist/assets/ResidentDetailPage-Dc23v_8v.js +1 -0
- package/dist/assets/web/dist/assets/ResidentsIndexPage-TR5D1TRR.js +1 -0
- package/dist/assets/web/dist/assets/RunFoldRow-mkUj7WEN.js +9 -0
- package/dist/assets/web/dist/assets/{RunRoutePage-oN9GkVEA.js → RunRoutePage-CQI17__g.js} +3 -3
- package/dist/assets/web/dist/assets/RunsIndexPage-yIP4PlKP.js +1 -0
- package/dist/assets/web/dist/assets/{RunsTabs-DEICQ4FY.js → RunsTabs-XpCqeWu4.js} +1 -1
- package/dist/assets/web/dist/assets/ScheduledPage-CdCVyNbh.js +1 -0
- package/dist/assets/web/dist/assets/SettingsPage-DuA8JpLU.js +1 -0
- package/dist/assets/web/dist/assets/{StatusDot-D14iJMy7.js → StatusDot-DmNHX6am.js} +1 -1
- package/dist/assets/web/dist/assets/{Tooltip-B0Ob5MQ4.js → Tooltip-qVnJTgSt.js} +1 -1
- package/dist/assets/web/dist/assets/UnitRoutePage-BcTeH7m2.js +1 -0
- package/dist/assets/web/dist/assets/{angular-html-Cw130Zyi.js → angular-html-DYtV9uIN.js} +1 -1
- package/dist/assets/web/dist/assets/{angular-ts-DY1m4C2s.js → angular-ts-DF2P25Zp.js} +1 -1
- package/dist/assets/web/dist/assets/{apl-W6Ty7v05.js → apl-Ff96wxko.js} +1 -1
- package/dist/assets/web/dist/assets/{astro-DlLVHwVk.js → astro-LbBnZna-.js} +1 -1
- package/dist/assets/web/dist/assets/{blade-Bco3tDh4.js → blade-DltuxeBW.js} +1 -1
- package/dist/assets/web/dist/assets/{c-1LaFY_cj.js → c-DBg7yuPx.js} +1 -1
- package/dist/assets/web/dist/assets/{chapel-B-OvrOL5.js → chapel-C83hUAds.js} +1 -1
- package/dist/assets/web/dist/assets/{cobol-Ch3EPlHu.js → cobol-DB0yV_2D.js} +1 -1
- package/dist/assets/web/dist/assets/{coffee-hZuITnto.js → coffee-Bpih6Kzl.js} +1 -1
- package/dist/assets/web/dist/assets/{cpp-B8iRVo8m.js → cpp-CU00ZeRn.js} +1 -1
- package/dist/assets/web/dist/assets/{crystal-DKveI7lr.js → crystal-f8ImJkux.js} +1 -1
- package/dist/assets/web/dist/assets/{css-_2_CD-rr.js → css-4VrC4ISo.js} +1 -1
- package/dist/assets/web/dist/assets/{dist-pOdUzj6D.js → dist-TAGawIfM.js} +2 -2
- package/dist/assets/web/dist/assets/durationTone-CYMux25J.js +1 -0
- package/dist/assets/web/dist/assets/{edge-BenMDPct.js → edge-BwFDzfS_.js} +1 -1
- package/dist/assets/web/dist/assets/{elixir-CBbdEqG6.js → elixir-wwIYIpJm.js} +1 -1
- package/dist/assets/web/dist/assets/{elm-DMub_2lY.js → elm-DyDuM3v3.js} +1 -1
- package/dist/assets/web/dist/assets/{erb-CI9He_Up.js → erb-DFJBEVrh.js} +1 -1
- package/dist/assets/web/dist/assets/{favicon-BQsePYv5.js → favicon-CSt-qDvc.js} +1 -1
- package/dist/assets/web/dist/assets/{git-rebase-BBfhnyF8.js → git-rebase-CuDv-44X.js} +1 -1
- package/dist/assets/web/dist/assets/{glimmer-js-CR9Fxrau.js → glimmer-js-ZFnrm4J3.js} +1 -1
- package/dist/assets/web/dist/assets/{glimmer-ts-CwFwX_XS.js → glimmer-ts-XY4Yqshp.js} +1 -1
- package/dist/assets/web/dist/assets/{glsl-Daiodp1r.js → glsl-xnR8efx0.js} +1 -1
- package/dist/assets/web/dist/assets/{graphql-DZvrsEkB.js → graphql-D-gO5tnP.js} +1 -1
- package/dist/assets/web/dist/assets/{hack-BaXOzdg7.js → hack-CSxbW4ax.js} +1 -1
- package/dist/assets/web/dist/assets/{haml-CMskq_VA.js → haml-D4ar42QT.js} +1 -1
- package/dist/assets/web/dist/assets/{handlebars-Dhw_f7jD.js → handlebars-CMLbDE7o.js} +1 -1
- package/dist/assets/web/dist/assets/{html-C9k99z0z.js → html-CVekU4Fs.js} +1 -1
- package/dist/assets/web/dist/assets/{html-derivative-VckPItXN.js → html-derivative-St3HHw_N.js} +1 -1
- package/dist/assets/web/dist/assets/{http-DXU_3h9v.js → http-Mon0DWHS.js} +1 -1
- package/dist/assets/web/dist/assets/{hurl-KU24JNdp.js → hurl-Cbl5IvBs.js} +1 -1
- package/dist/assets/web/dist/assets/indexRow-FLJu5mR9.js +1 -0
- package/dist/assets/web/dist/assets/{java-BbZjTNgf.js → java-Bprck1l-.js} +1 -1
- package/dist/assets/web/dist/assets/{javascript-DXCdqcZZ.js → javascript-C73G1-UR.js} +1 -1
- package/dist/assets/web/dist/assets/{jinja-pDlsjTVp.js → jinja-C4DuRxYJ.js} +1 -1
- package/dist/assets/web/dist/assets/{jison-DsXDk66e.js → jison-B2U03GEC.js} +1 -1
- package/dist/assets/web/dist/assets/{json-tCxXfRgG.js → json-CvTZUDzx.js} +1 -1
- package/dist/assets/web/dist/assets/{jsx-B0ZYkCmi.js → jsx-DMWKCzwo.js} +1 -1
- package/dist/assets/web/dist/assets/{julia-BLzzeI6x.js → julia-Czn7bV_3.js} +1 -1
- package/dist/assets/web/dist/assets/{just-DvD2_60c.js → just-BBxpNfvC.js} +1 -1
- package/dist/assets/web/dist/assets/{latex-511zn3h7.js → latex-Bw9yg5mr.js} +1 -1
- package/dist/assets/web/dist/assets/{liquid-BD0BkMox.js → liquid-BRCjaydE.js} +1 -1
- package/dist/assets/web/dist/assets/{indexFormat-B-pd4r7Y.js → localIso-CNA-bhS-.js} +1 -1
- package/dist/assets/web/dist/assets/{lua-NFicKm6N.js → lua-DUu2KIC0.js} +1 -1
- package/dist/assets/web/dist/assets/main-csihqEj5.css +1 -0
- package/dist/assets/web/dist/assets/main-mUd_TJjH.js +28 -0
- package/dist/assets/web/dist/assets/{marko-1-G_nEXK.js → marko-CZJZIlSQ.js} +1 -1
- package/dist/assets/web/dist/assets/{mdc-DUe3AQLp.js → mdc-BmClq6fd.js} +1 -1
- package/dist/assets/web/dist/assets/{nginx-Dg379_bA.js → nginx-Bmt3xSEm.js} +1 -1
- package/dist/assets/web/dist/assets/{nim-BnFq97ZO.js → nim-Da-i0utK.js} +1 -1
- package/dist/assets/web/dist/assets/{org-F0uiwGvq.js → org-BvAre2qP.js} +1 -1
- package/dist/assets/web/dist/assets/{perl-B0euczkl.js → perl-v9WwFFtB.js} +1 -1
- package/dist/assets/web/dist/assets/{php-DkL3k_n7.js → php-DTU4Zyze.js} +1 -1
- package/dist/assets/web/dist/assets/{pug-L_OjjZP4.js → pug-DhTwEqTO.js} +1 -1
- package/dist/assets/web/dist/assets/{qml-BMjB00Zz.js → qml-BUD9AC_c.js} +1 -1
- package/dist/assets/web/dist/assets/{r-DoeLdnqR.js → r-CAnu56n7.js} +1 -1
- package/dist/assets/web/dist/assets/{razor-BzYNkAWy.js → razor-Dn0P4gAq.js} +1 -1
- package/dist/assets/web/dist/assets/{regexp-CPmElMk3.js → regexp-CZyBRaVW.js} +1 -1
- package/dist/assets/web/dist/assets/residentsModel-By1fThvk.js +1 -0
- package/dist/assets/web/dist/assets/{rst-DrsjgfI7.js → rst-Ckyd5UsY.js} +1 -1
- package/dist/assets/web/dist/assets/{ruby-cB42ppvx.js → ruby-BBQ62fsx.js} +1 -1
- package/dist/assets/web/dist/assets/{sas-R5Y3NM_I.js → sas-CW35hMxG.js} +1 -1
- package/dist/assets/web/dist/assets/{scss-C-zWxV9s.js → scss-CpV8pF4J.js} +1 -1
- package/dist/assets/web/dist/assets/{shellscript-oJF96aAU.js → shellscript-CRJvsmE1.js} +1 -1
- package/dist/assets/web/dist/assets/{shellsession-CznECKyi.js → shellsession-CyriUZxf.js} +1 -1
- package/dist/assets/web/dist/assets/{soy-wjHLSRag.js → soy-D5QzYUeg.js} +1 -1
- package/dist/assets/web/dist/assets/{sql-C_BM8IOW.js → sql-CUBf_Mse.js} +1 -1
- package/dist/assets/web/dist/assets/{stata-D31HO8aQ.js → stata-B-4n4ITz.js} +1 -1
- package/dist/assets/web/dist/assets/{surrealql-CKCLyplA.js → surrealql-RuWZBLtr.js} +1 -1
- package/dist/assets/web/dist/assets/{svelte-3geWk2iu.js → svelte-CO5YzCsK.js} +1 -1
- package/dist/assets/web/dist/assets/{templ-DiJr_hTD.js → templ-DbkWVaBF.js} +1 -1
- package/dist/assets/web/dist/assets/{tex-BEJGWyeF.js → tex-IuxoEcId.js} +1 -1
- package/dist/assets/web/dist/assets/{ts-tags-C8Mzdpxx.js → ts-tags-g6dGQPjd.js} +1 -1
- package/dist/assets/web/dist/assets/{tsx-UQiSm_p3.js → tsx-WnXwiyH2.js} +1 -1
- package/dist/assets/web/dist/assets/{twig-_Pvzkeo9.js → twig-Lx1G7PnY.js} +1 -1
- package/dist/assets/web/dist/assets/{typescript-BWMkINKK.js → typescript-BQd7biLF.js} +1 -1
- package/dist/assets/web/dist/assets/{typst-Bdg9m-e7.js → typst-D2lXPHK7.js} +1 -1
- package/dist/assets/web/dist/assets/{vue-CDZrrAZ8.js → vue-4wVQD9y9.js} +1 -1
- package/dist/assets/web/dist/assets/{vue-html-tAlpNhfN.js → vue-html-DZPaRte4.js} +1 -1
- package/dist/assets/web/dist/assets/{vue-vine-C27UF_rh.js → vue-vine-DbmZCmu-.js} +1 -1
- package/dist/assets/web/dist/assets/{xml-CxeDr9Zh.js → xml-DV16szyo.js} +1 -1
- package/dist/assets/web/dist/assets/{xsl-Bpi0uUnM.js → xsl-eo5-1sk0.js} +1 -1
- package/dist/assets/web/dist/assets/{yaml-BtUgZ1GN.js → yaml-BXdX8HZf.js} +1 -1
- package/dist/cli.js +3329 -1804
- package/package.json +1 -1
- package/dist/assets/web/dist/assets/AppShell-lYVcj-k7.js +0 -1
- package/dist/assets/web/dist/assets/ResidentDetailPage-DSpsye5e.js +0 -1
- package/dist/assets/web/dist/assets/ResidentsIndexPage-CT8fI1M3.js +0 -1
- package/dist/assets/web/dist/assets/RunFoldRow-Cqh8pTXC.js +0 -9
- package/dist/assets/web/dist/assets/RunsIndexPage-sjXr8iCV.js +0 -1
- package/dist/assets/web/dist/assets/ScheduledPage-Tz__zLzi.js +0 -1
- package/dist/assets/web/dist/assets/UnitRoutePage-CbKCL58v.js +0 -1
- package/dist/assets/web/dist/assets/indexRow-Bnj883ii.js +0 -1
- package/dist/assets/web/dist/assets/localIso-L06jV29p.js +0 -1
- package/dist/assets/web/dist/assets/main-D3lG-yQ9.js +0 -28
- package/dist/assets/web/dist/assets/main-Dm11o0hc.css +0 -1
- package/dist/assets/web/dist/assets/residentDiskBudget-BMBKlYRH.js +0 -1
|
@@ -47,6 +47,16 @@ export interface Actor {
|
|
|
47
47
|
readonly onBehalfOf?: Actor;
|
|
48
48
|
/** Where a chat actor is speaking from — context, never authority. */
|
|
49
49
|
readonly origin?: { readonly channelId: string; readonly threadKey: string };
|
|
50
|
+
/**
|
|
51
|
+
* The ids that mean "me" for this actor (record 0042): its own `id` first,
|
|
52
|
+
* then the person it is linked to — a dashboard session whose Access email
|
|
53
|
+
* names one Slack user carries that `slack:U…` id here. Read by `is-self`,
|
|
54
|
+
* `acts-as-person`, the `me` tier and the "mine" filters; NEVER by a grant
|
|
55
|
+
* check — the link is identity, not authority. Absent → `[id]`.
|
|
56
|
+
*/
|
|
57
|
+
readonly self?: readonly string[];
|
|
58
|
+
/** The linked person, for display and the audit line (`asUser`); absent when unlinked. */
|
|
59
|
+
readonly asUser?: { readonly id: string; readonly name?: string };
|
|
50
60
|
}
|
|
51
61
|
|
|
52
62
|
/** `<group>:<read|write|exec>` plus the non-command actions. A plain
|
|
@@ -103,8 +113,12 @@ export type Condition =
|
|
|
103
113
|
* resource's channel is `public` (a run's stamped `channelVisibility`;
|
|
104
114
|
* `unknown` is never public). One definition for both evaluators. */
|
|
105
115
|
| { readonly kind: "member-of" }
|
|
106
|
-
/** resource.userId
|
|
116
|
+
/** resource.userId is one of the principal's `self` ids (its own id, or the person it is linked to). */
|
|
107
117
|
| { readonly kind: "is-self" }
|
|
118
|
+
/** The principal's `self` names a chat identity (`slack:U…`): every chat
|
|
119
|
+
* actor, and a dashboard session linked to its person (record 0042) — never
|
|
120
|
+
* an unlinked browser session or a credential. */
|
|
121
|
+
| { readonly kind: "acts-as-person" }
|
|
108
122
|
/** actor.grants.repos contains the resource's repo (or is "all"). */
|
|
109
123
|
| { readonly kind: "owner-of" }
|
|
110
124
|
/** actor.grants.channels === "all". */
|
|
@@ -55,6 +55,18 @@ export function parseUnitKey(key: string): { instanceId: string; unit: string }
|
|
|
55
55
|
return { instanceId: key.slice(0, at), unit: key.slice(at + 1) };
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
+
/** The unit an idempotency key names — the head of its step
|
|
59
|
+
* (`<instance>:<unit>/<round>/<kind>` for the plan runner), or undefined for
|
|
60
|
+
* a key whose step carries no unit prefix the unit pattern accepts. What the
|
|
61
|
+
* `coordinator_tag` run event stamps as `unit`, so a run's stream names the
|
|
62
|
+
* unit it ran for without parsing the key back. */
|
|
63
|
+
export function unitOfIdempotencyKey(key: string): string | undefined {
|
|
64
|
+
if (!IDEMPOTENCY_KEY_PATTERN.test(key)) return undefined;
|
|
65
|
+
const step = key.slice(key.indexOf(":") + 1);
|
|
66
|
+
const head = step.split("/")[0];
|
|
67
|
+
return UNIT_PATTERN.test(head) ? head : undefined;
|
|
68
|
+
}
|
|
69
|
+
|
|
58
70
|
/** The event a child's terminal record sends its parent: the type carries the
|
|
59
71
|
* run id, so each `waitForEvent` matches its own child and a duplicate is
|
|
60
72
|
* buffered harmlessly. An event type is the platform's alphabet — letters,
|
|
@@ -85,10 +97,12 @@ export interface CoordinatorTag {
|
|
|
85
97
|
* (`CoordinatorInstance.base`), set by the spawn when the instance knows it.
|
|
86
98
|
* A coordinator's child is dispatched AT its unit branch so the resident
|
|
87
99
|
* attaches there, which makes the binding ref the branch itself — no base
|
|
88
|
-
* the post-step could resolve from the thread — so the spawn says it.
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
100
|
+
* the post-step could resolve from the thread — so the spawn says it.
|
|
101
|
+
* Published as the run's own `coordinator_tag` event at dispatch
|
|
102
|
+
* (run-history item 48a), so a run re-attached after a bot roll — whose
|
|
103
|
+
* dispatch options are gone with the process that spawned it — reads it
|
|
104
|
+
* back off its ledger events; `coordinatorFields` still leaves it off the
|
|
105
|
+
* rows, so rows and records keep the shape written before it existed. */
|
|
92
106
|
base?: string;
|
|
93
107
|
}
|
|
94
108
|
|
|
@@ -182,6 +196,11 @@ export interface CoordinatorUnit {
|
|
|
182
196
|
* — no pre-check, no branch, no round 0. A task string's row only; written by
|
|
183
197
|
* the hand-off, read by the driver into the machine's input. */
|
|
184
198
|
resume?: { pr: number; headSha?: string; url?: string };
|
|
199
|
+
/** The head the unit's own coding child last pushed, recorded when the unit
|
|
200
|
+
* ended `review_pending` (the wall clock capped after the pull request was
|
|
201
|
+
* opened or updated): the next attempt's pre-check starts at the review
|
|
202
|
+
* round when the open pull request still heads exactly here. */
|
|
203
|
+
lastPush?: string;
|
|
185
204
|
/** The round boundaries the coordinator reported, oldest first (the `ship_round` vocabulary). */
|
|
186
205
|
rounds: Array<{ index: number; agent: string; outcome: string; at: number }>;
|
|
187
206
|
/** How the unit ended: the ending's kind and the thread's report, when it has. */
|
|
@@ -244,6 +263,7 @@ export function isCoordinatorUnit(v: unknown): v is CoordinatorUnit {
|
|
|
244
263
|
if (r.issue !== undefined && !isFinite(r.issue)) return false;
|
|
245
264
|
if (r.pr !== undefined && !isPr(r.pr)) return false;
|
|
246
265
|
if (r.resume !== undefined && !isResume(r.resume)) return false;
|
|
266
|
+
if (r.lastPush !== undefined && !isText(r.lastPush)) return false;
|
|
247
267
|
if (
|
|
248
268
|
!Array.isArray(r.rounds) ||
|
|
249
269
|
r.rounds.length > MAX_ROUNDS ||
|
|
@@ -274,7 +274,18 @@ function readRecordReturn(step: string, a: BotAnswer): StepReturn {
|
|
|
274
274
|
|
|
275
275
|
function prCheckReturn(step: string, a: BotAnswer): StepReturn {
|
|
276
276
|
const { ok, state, prNumber, url, headSha, sha, mergedAt, at } = a.body;
|
|
277
|
-
if (ok === true && state === "none")
|
|
277
|
+
if (ok === true && state === "none") {
|
|
278
|
+
const { unrecovered } = a.body;
|
|
279
|
+
return {
|
|
280
|
+
type: "pr-check",
|
|
281
|
+
step,
|
|
282
|
+
pr: {
|
|
283
|
+
state: "none",
|
|
284
|
+
...(unrecovered === "no_commits" || unrecovered === "no_base" ? { unrecovered } : {}),
|
|
285
|
+
},
|
|
286
|
+
at,
|
|
287
|
+
};
|
|
288
|
+
}
|
|
278
289
|
if (ok === true && state === "open" && typeof prNumber === "number" && typeof url === "string")
|
|
279
290
|
return {
|
|
280
291
|
type: "pr-check",
|
|
@@ -303,7 +314,11 @@ function prCheckReturn(step: string, a: BotAnswer): StepReturn {
|
|
|
303
314
|
}
|
|
304
315
|
|
|
305
316
|
function mergeReturn(step: string, a: BotAnswer): StepReturn {
|
|
306
|
-
const { ok, outcome, sha, reason, at } = a.body;
|
|
317
|
+
const { ok, outcome, by, sha, mergedAt, reason, at } = a.body;
|
|
318
|
+
// The door found the pull request already merged after the approval: the
|
|
319
|
+
// merge commit and the time ride the answer, and the unit ends `by: other`.
|
|
320
|
+
if (ok === true && outcome === "merged" && by === "other" && typeof sha === "string" && typeof mergedAt === "string")
|
|
321
|
+
return { type: "merge", step, outcome: "merged", by: "other", sha, mergedAt, at };
|
|
307
322
|
if (ok === true && outcome === "merged" && typeof sha === "string")
|
|
308
323
|
return { type: "merge", step, outcome: "merged", sha, at };
|
|
309
324
|
if (ok === true && (outcome === "pending" || outcome === "refused") && typeof reason === "string")
|
|
@@ -389,9 +404,16 @@ async function perform(
|
|
|
389
404
|
),
|
|
390
405
|
);
|
|
391
406
|
case "pr-check":
|
|
407
|
+
// `recover` rides only after a dead coding child: the bot opens the pull
|
|
408
|
+
// request from the pushed branch itself instead of answering `none`.
|
|
392
409
|
return prCheckReturn(
|
|
393
410
|
action.step,
|
|
394
|
-
answerOf(
|
|
411
|
+
answerOf(
|
|
412
|
+
"pr-check",
|
|
413
|
+
await step.do(action.step, STEP_CONFIG, () =>
|
|
414
|
+
call(bot, "pr-check", { ...tag, ...(action.recover !== undefined ? { recover: action.recover } : {}) }),
|
|
415
|
+
),
|
|
416
|
+
),
|
|
395
417
|
);
|
|
396
418
|
case "sleep":
|
|
397
419
|
await step.sleep(action.step, action.ms);
|
|
@@ -426,7 +448,11 @@ async function runUnit(
|
|
|
426
448
|
// A resume at review (agent-ship item 10) rides the unit's row: the pull
|
|
427
449
|
// request of ship's own the requester named opens the pipeline at its first
|
|
428
450
|
// review round, with no pre-check, no branch and no round 0.
|
|
429
|
-
const
|
|
451
|
+
const row = plan.units.find((u) => u.unit === unit);
|
|
452
|
+
const resume = row?.resume;
|
|
453
|
+
// A previous attempt's `review_pending` head: the machine's pre-check starts
|
|
454
|
+
// at the review round when the open pull request still heads exactly there.
|
|
455
|
+
const lastPush = row?.lastPush;
|
|
430
456
|
let state: UnitPipelineState = openUnitPipeline(
|
|
431
457
|
{
|
|
432
458
|
unit: { id: unit, branch: node.branch },
|
|
@@ -441,6 +467,7 @@ async function runUnit(
|
|
|
441
467
|
merge: plan.merge,
|
|
442
468
|
generated: plan.generated,
|
|
443
469
|
...(resume !== undefined ? { resume } : {}),
|
|
470
|
+
...(lastPush !== undefined ? { lastPush } : {}),
|
|
444
471
|
},
|
|
445
472
|
start.at,
|
|
446
473
|
);
|
|
@@ -486,6 +513,11 @@ async function runUnit(
|
|
|
486
513
|
...tag,
|
|
487
514
|
ending: { kind: note.ending.kind, report: renderUnitReport(state, endFacts) },
|
|
488
515
|
...(state.pr !== undefined ? { pr: state.pr } : {}),
|
|
516
|
+
// A review_pending ending names the child's own last push so the next
|
|
517
|
+
// attempt's pre-check can start at the review round (the row's lastPush).
|
|
518
|
+
...(note.ending.kind === "review_pending" && note.ending.headSha !== undefined
|
|
519
|
+
? { headSha: note.ending.headSha }
|
|
520
|
+
: {}),
|
|
489
521
|
...(state.lastCodingRunId !== undefined ? { codingRunId: state.lastCodingRunId } : {}),
|
|
490
522
|
};
|
|
491
523
|
await step.do(`${unit}/end`, STEP_CONFIG, () => call(bot, "unit-end", body));
|
|
@@ -76,13 +76,17 @@ export type RunNoteKind =
|
|
|
76
76
|
* wait had refused; on pi the container is provisioned before pi starts, so
|
|
77
77
|
* the note is a record fact from before the loop's deletion. */
|
|
78
78
|
| "fleet_busy"
|
|
79
|
-
/** The container the run's
|
|
79
|
+
/** The container the run's process ran in was replaced under the live run
|
|
80
80
|
* (docs/reference/specs/harness-pi.md item 16; the resident's roll,
|
|
81
|
-
* resident-repos.md item 65)
|
|
82
|
-
* the restart note, the summary
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
81
|
+
* resident-repos.md item 65). The harness's note is the verdict: the call
|
|
82
|
+
* in flight settled with the restart note, the summary naming both
|
|
83
|
+
* containers. The run loop then decides between two outcomes (harness.md
|
|
84
|
+
* item 6): a relaunch in the replacement, said in a `resumed` note, or —
|
|
85
|
+
* the relaunch refused by name, the ceiling among them — a second note of
|
|
86
|
+
* this kind saying why and that the run closes `interrupted` for a restart
|
|
87
|
+
* from its request. On a record from before the native loop's deletion the
|
|
88
|
+
* note says that loop's settlement instead: the executor waited for the
|
|
89
|
+
* wake and the run went on. */
|
|
86
90
|
| "sandbox_restarted"
|
|
87
91
|
| "stop_requested"
|
|
88
92
|
| "stopped"
|
|
@@ -356,6 +360,21 @@ export interface SpanEndEvent {
|
|
|
356
360
|
at?: number;
|
|
357
361
|
}
|
|
358
362
|
|
|
363
|
+
/** A value a `route` event may carry in a bound command input: JSON, nested
|
|
364
|
+
* at most three objects deep under `options`, and nothing else. The record
|
|
365
|
+
* crosses the run store's RPC boundary, whose typing walks every field: a
|
|
366
|
+
* field of `unknown` types the whole record `never`, and a recursive alias is
|
|
367
|
+
* "excessively deep" to it, so the nesting is spelled out level by level. The
|
|
368
|
+
* model's tool call is JSON to begin with; the registry's option schemas nest
|
|
369
|
+
* one object deep (`models.coding`); a deeper value is stored as its JSON
|
|
370
|
+
* text, still redacted and capped. */
|
|
371
|
+
export type RouteInputLeaf = string | number | boolean | null;
|
|
372
|
+
export type RouteInputLeafOrList = RouteInputLeaf | ReadonlyArray<RouteInputLeaf>;
|
|
373
|
+
export type RouteInputObject1 = { readonly [key: string]: RouteInputLeafOrList };
|
|
374
|
+
export type RouteInputObject2 = { readonly [key: string]: RouteInputLeafOrList | RouteInputObject1 };
|
|
375
|
+
export type RouteInputObject3 = { readonly [key: string]: RouteInputLeafOrList | RouteInputObject2 };
|
|
376
|
+
export type RouteInputValue = RouteInputLeafOrList | RouteInputObject3;
|
|
377
|
+
|
|
359
378
|
export type RunEvent =
|
|
360
379
|
/** `callId` is the provider's tool_use id — the explicit pair key between a
|
|
361
380
|
* call and its result (live-view item 13); the runner stamps it on both. */
|
|
@@ -635,6 +654,16 @@ export type RunEvent =
|
|
|
635
654
|
seq?: number;
|
|
636
655
|
at?: number;
|
|
637
656
|
}
|
|
657
|
+
/** The coordinator tag as a fact of the run (docs/reference/specs/run-history.md
|
|
658
|
+
* item 48a): the instance the run is a child of, the unit its idempotency
|
|
659
|
+
* key named, and the base branch its pull request targets — published by
|
|
660
|
+
* the dispatcher once at dispatch, from `DispatchOptions.coordinator`, so
|
|
661
|
+
* a run re-attached or restarted after a bot roll (whose spawn options are
|
|
662
|
+
* gone with the process) reads the plan's base back off its own events
|
|
663
|
+
* instead of letting the binding ref — the unit branch itself — stand in.
|
|
664
|
+
* `base` is absent when the spawn knew none; the post-step then falls to
|
|
665
|
+
* the coordinator store's `instance.base`. Additive: unknown → ignored. */
|
|
666
|
+
| { type: "coordinator_tag"; parentInstanceId: string; unit?: string; base?: string; seq?: number; at?: number }
|
|
638
667
|
/** The review post-step's outcome when the verdict landed
|
|
639
668
|
* (docs/reference/specs/agent-review.md item 18): the pull request it was
|
|
640
669
|
* posted to, the head it was pinned to (the carried head after a rebase,
|
|
@@ -679,7 +708,14 @@ export type RunEvent =
|
|
|
679
708
|
* `run_meta.agentSource` stays `default`). Published by the dispatcher
|
|
680
709
|
* straight to the registry right after `run_meta`, once per run the router
|
|
681
710
|
* answered; absent on every run a directive, a sticky preset or a scope
|
|
682
|
-
* chose. Head material, like `run_meta`. Additive: unknown → ignored.
|
|
711
|
+
* chose. Head material, like `run_meta`. Additive: unknown → ignored.
|
|
712
|
+
* A command the router bound from prose (record 0036: the door offers every
|
|
713
|
+
* chat command as a tool beside `route`) rides the command run's record
|
|
714
|
+
* instead, right after its `run_meta`: `preset` is the command run's agent
|
|
715
|
+
* (`command`), `command` the id the model called, `input` the bound input
|
|
716
|
+
* (redacted, each value capped) and `receipt` the chat form the reply led
|
|
717
|
+
* with (`routed: <chat form>`, redacted and capped at `ROUTE_RECEIPT_CAP`);
|
|
718
|
+
* how the invoke ended is the run's own status and `answer`. */
|
|
683
719
|
| {
|
|
684
720
|
type: "route";
|
|
685
721
|
preset: string;
|
|
@@ -687,6 +723,9 @@ export type RunEvent =
|
|
|
687
723
|
model: string;
|
|
688
724
|
parts?: ReadonlyArray<{ preset: string; text: string }>;
|
|
689
725
|
collapsed?: { presets: ReadonlyArray<string> };
|
|
726
|
+
command?: string;
|
|
727
|
+
input?: { readonly [key: string]: RouteInputValue };
|
|
728
|
+
receipt?: string;
|
|
690
729
|
seq?: number;
|
|
691
730
|
at?: number;
|
|
692
731
|
}
|
|
@@ -421,6 +421,7 @@ export function analyzeRunFriction(events: readonly RunEvent[], opts: FrictionOp
|
|
|
421
421
|
ev.type === "review_artifact" ||
|
|
422
422
|
ev.type === "pr_description" ||
|
|
423
423
|
ev.type === "pr_opened" ||
|
|
424
|
+
ev.type === "coordinator_tag" ||
|
|
424
425
|
ev.type === "review_posted" ||
|
|
425
426
|
ev.type === "ship_round" ||
|
|
426
427
|
ev.type === "route" ||
|
|
@@ -427,7 +427,9 @@ function renderFirstInstruction(rebase: ChildContract["rebase"]): string {
|
|
|
427
427
|
const onto = rebase.onto ? `\`${rebase.onto}\`` : "the merged parent";
|
|
428
428
|
return (
|
|
429
429
|
`Rebase ${branch} onto ${onto} before any other work — the parent unit has merged and the base has moved; ` +
|
|
430
|
-
`the only writes are your own on that branch. A conflict ends the unit: report it as the handoff and stop
|
|
430
|
+
`the only writes are your own on that branch. A conflict ends the unit: report it as the handoff and stop. ` +
|
|
431
|
+
`Right before the push, fetch ${onto} again and rebase once more if it moved during verify, ` +
|
|
432
|
+
`so the pull request is not born conflicting.`
|
|
431
433
|
);
|
|
432
434
|
}
|
|
433
435
|
|