@coreplane/switchboard 1.260.2 → 1.260.4
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-memory/backgroundTasks.ts +27 -3
- package/dist/assets/deploy/cloudflare-memory/testDiagnostics.ts +227 -0
- package/dist/assets/deploy/cloudflare-memory/testDiagnosticsProtocol.ts +22 -0
- package/dist/assets/deploy/cloudflare-memory/testDiagnosticsReporter.ts +88 -0
- package/dist/assets/deploy/cloudflare-memory/tsconfig.json +14 -2
- package/dist/assets/deploy/cloudflare-resident/Dockerfile +11 -2
- package/dist/assets/package-lock.json +3 -3
- package/dist/assets/package.json +4 -3
- package/dist/assets/project.json +4 -0
- package/dist/assets/source.json +3 -3
- package/dist/assets/src/agents/registry.ts +6 -5
- package/dist/assets/src/core/coordinator/contract.ts +48 -2
- package/dist/assets/src/core/coordinator/driver.ts +40 -5
- package/dist/assets/src/core/reviewVerdict.ts +15 -5
- package/dist/assets/src/core/runFriction.ts +1 -1
- package/dist/assets/src/core/ship/contract.ts +2 -2
- package/dist/assets/src/core/ship/coordinator.ts +236 -108
- package/dist/assets/src/core/ship/renewal.ts +3 -1
- package/dist/assets/src/execution/bashTimeout.ts +1 -1
- package/dist/assets/src/execution/sandboxErrors.ts +6 -6
- package/dist/assets/web/dist/.vite/manifest.json +488 -488
- package/dist/assets/web/dist/assets/{AppShell-CSXDCV4x.js → AppShell-DPJVhUGP.js} +1 -1
- package/dist/assets/web/dist/assets/{CostChart-DsuPS2g7.js → CostChart-4TeDdbvJ.js} +1 -1
- package/dist/assets/web/dist/assets/CostsPage-8HDgvuWB.js +1 -0
- package/dist/assets/web/dist/assets/{DeliveryPage-62qCSLvk.js → DeliveryPage-BaemWKW8.js} +1 -1
- package/dist/assets/web/dist/assets/{HomePage-Dk3HRBc3.js → HomePage-fgKQHLaO.js} +1 -1
- package/dist/assets/web/dist/assets/{InputMenu-BdZXnibG.js → InputMenu-BRV35UWP.js} +1 -1
- package/dist/assets/web/dist/assets/{MetricsPage-o5fSaCTe.js → MetricsPage-BQBuIuYU.js} +1 -1
- package/dist/assets/web/dist/assets/{NotFoundPage-DHuWyjlq.js → NotFoundPage-CDjMfCcj.js} +1 -1
- package/dist/assets/web/dist/assets/{PendingTurnRow-CeTGOXUy.js → PendingTurnRow-vuWiDzvz.js} +1 -1
- package/dist/assets/web/dist/assets/{PlanePage-RD0M6O6W.js → PlanePage-DXMJf8FB.js} +1 -1
- package/dist/assets/web/dist/assets/{ResidentDetailPage-Dl2KId95.js → ResidentDetailPage-DdC8yU_S.js} +1 -1
- package/dist/assets/web/dist/assets/{ResidentsIndexPage-DBy43I1R.js → ResidentsIndexPage-CSM-KODv.js} +1 -1
- package/dist/assets/web/dist/assets/{RunFoldRow-CwHDL-Mo.js → RunFoldRow-Csik3wD6.js} +1 -1
- package/dist/assets/web/dist/assets/{RunRoutePage-Du1HqLZs.js → RunRoutePage-jo6NZxsP.js} +3 -3
- package/dist/assets/web/dist/assets/{RunsIndexPage-BZphy3Hr.js → RunsIndexPage-Dx1Y4sSq.js} +1 -1
- package/dist/assets/web/dist/assets/{RunsTabs-kHbbxVHx.js → RunsTabs-C7Ua3XX5.js} +1 -1
- package/dist/assets/web/dist/assets/{ScheduledPage-B7jh898t.js → ScheduledPage-BuB_NZyR.js} +1 -1
- package/dist/assets/web/dist/assets/{SettingSelect-BfID5nF4.js → SettingSelect-CEeA4iuC.js} +1 -1
- package/dist/assets/web/dist/assets/{SettingsPage-3uLEsiiE.js → SettingsPage-Cn96jB6Q.js} +1 -1
- package/dist/assets/web/dist/assets/{SilentTurn-CKxSxnQC.js → SilentTurn-D2cJfpEq.js} +1 -1
- package/dist/assets/web/dist/assets/{SlackMark-CtiHrNjr.js → SlackMark-DB0MGiF5.js} +1 -1
- package/dist/assets/web/dist/assets/{StatusDot-x7vcK0iE.js → StatusDot-DDHUCPVJ.js} +1 -1
- package/dist/assets/web/dist/assets/{Tooltip-wVXCWhMp.js → Tooltip-B4VIHkAI.js} +1 -1
- package/dist/assets/web/dist/assets/{UnitRoutePage-V5BXK7FH.js → UnitRoutePage-C-2DfjLI.js} +1 -1
- package/dist/assets/web/dist/assets/{angular-html-C8b5YTHf.js → angular-html-BRRhsdQE.js} +1 -1
- package/dist/assets/web/dist/assets/{angular-ts-C3f4WYNe.js → angular-ts-BFj-mqCm.js} +1 -1
- package/dist/assets/web/dist/assets/{apl-DSHxUJc3.js → apl-CsBuy1IL.js} +1 -1
- package/dist/assets/web/dist/assets/{astro-BSGCCBP6.js → astro-cVaqxBZq.js} +1 -1
- package/dist/assets/web/dist/assets/{blade-DFeYrMKk.js → blade-MEP5mWha.js} +1 -1
- package/dist/assets/web/dist/assets/{browser-B6T5hjfR.js → browser-CCImen5O.js} +1 -1
- package/dist/assets/web/dist/assets/{c-L_QOnFVv.js → c-D4NGQ_Pd.js} +1 -1
- package/dist/assets/web/dist/assets/{chapel-DLQWUwhu.js → chapel-BkWImsIy.js} +1 -1
- package/dist/assets/web/dist/assets/{cobol-1DlMmrEO.js → cobol-RPDSPSET.js} +1 -1
- package/dist/assets/web/dist/assets/{coffee-BTB6os6N.js → coffee-DZ5z7oVX.js} +1 -1
- package/dist/assets/web/dist/assets/{cpp-BvJI2z3u.js → cpp-CrBtIaRZ.js} +1 -1
- package/dist/assets/web/dist/assets/{crystal-B11wGW_h.js → crystal-DJesYi6f.js} +1 -1
- package/dist/assets/web/dist/assets/{css-BiIWx5Pw.js → css-DO9mjau-.js} +1 -1
- package/dist/assets/web/dist/assets/{dist-C-XGnvM4.js → dist-Cf1CmCSK.js} +2 -2
- package/dist/assets/web/dist/assets/{edge-nSglEXaD.js → edge-C3VzbSW0.js} +1 -1
- package/dist/assets/web/dist/assets/{elixir-x7o8qMl8.js → elixir-BkD_Vhfe.js} +1 -1
- package/dist/assets/web/dist/assets/{elm-DGrRyqTQ.js → elm-KIM0mFPk.js} +1 -1
- package/dist/assets/web/dist/assets/{erb--_dh58Nw.js → erb-D2ruCqb2.js} +1 -1
- package/dist/assets/web/dist/assets/{eventSource-Bj_dZf6M.js → eventSource-Cv0AFlMi.js} +1 -1
- package/dist/assets/web/dist/assets/{git-rebase-DbpUXwyg.js → git-rebase-CnfbQTxA.js} +1 -1
- package/dist/assets/web/dist/assets/{glimmer-js-BG0CuZG5.js → glimmer-js-CbiwFXWH.js} +1 -1
- package/dist/assets/web/dist/assets/{glimmer-ts-CQIl5qyR.js → glimmer-ts-DV8ii0Pv.js} +1 -1
- package/dist/assets/web/dist/assets/{glsl-9PJNQTcw.js → glsl-CgmznWkA.js} +1 -1
- package/dist/assets/web/dist/assets/{graphql-CzVTzjEI.js → graphql-BK-bBYfH.js} +1 -1
- package/dist/assets/web/dist/assets/{hack-BhCmAz3Q.js → hack-DnwTTP5n.js} +1 -1
- package/dist/assets/web/dist/assets/{haml-BmI12COR.js → haml-DAVJsWwT.js} +1 -1
- package/dist/assets/web/dist/assets/{handlebars-Cib-ISTS.js → handlebars-voOVfxFL.js} +1 -1
- package/dist/assets/web/dist/assets/{html-D3lDapvI.js → html-3FTqwaPk.js} +1 -1
- package/dist/assets/web/dist/assets/{html-derivative-DRPY8vOK.js → html-derivative-CSlhLDQn.js} +1 -1
- package/dist/assets/web/dist/assets/{http-B9VttK6m.js → http-Vx4ilPfS.js} +1 -1
- package/dist/assets/web/dist/assets/{hurl-C0saNJYj.js → hurl-DxyZDE3R.js} +1 -1
- package/dist/assets/web/dist/assets/{java-BCFbtYAj.js → java-nWqdjNJG.js} +1 -1
- package/dist/assets/web/dist/assets/{javascript-nwBjnrhh.js → javascript-Dr82HOwp.js} +1 -1
- package/dist/assets/web/dist/assets/{jinja-CMYO9byN.js → jinja-BhjLrPOt.js} +1 -1
- package/dist/assets/web/dist/assets/{jison-Cko8HnE_.js → jison-DilGIUa8.js} +1 -1
- package/dist/assets/web/dist/assets/{json-Dzv__YsX.js → json-CrOcvmhJ.js} +1 -1
- package/dist/assets/web/dist/assets/{jsx-CTFxagih.js → jsx-BW_RX-fo.js} +1 -1
- package/dist/assets/web/dist/assets/{julia-_Xvten1-.js → julia-CWH071DB.js} +1 -1
- package/dist/assets/web/dist/assets/{just-bLps4qOu.js → just-DkhhoWBy.js} +1 -1
- package/dist/assets/web/dist/assets/{latex-D6UaYsUP.js → latex-cuHJ4TUT.js} +1 -1
- package/dist/assets/web/dist/assets/{liquid-CoDIeULa.js → liquid-DG6afYQN.js} +1 -1
- package/dist/assets/web/dist/assets/{lua-D1KFRnVf.js → lua-C5CMnCPS.js} +1 -1
- package/dist/assets/web/dist/assets/{main-DAL--hyj.js → main-DxPqaFu9.js} +3 -3
- package/dist/assets/web/dist/assets/{marko-B5N5XcOw.js → marko-Dy2_DuC4.js} +1 -1
- package/dist/assets/web/dist/assets/{mdc-uxzjQO3q.js → mdc-BMKb_EeA.js} +1 -1
- package/dist/assets/web/dist/assets/{nginx-BMJxs2TK.js → nginx-og0RgMKf.js} +1 -1
- package/dist/assets/web/dist/assets/{nim-DqQ3-8p1.js → nim-CQxTQQP0.js} +1 -1
- package/dist/assets/web/dist/assets/{org-DsY6LK59.js → org-b5lkq_Pl.js} +1 -1
- package/dist/assets/web/dist/assets/{perl--pq9iJFp.js → perl-D9X5_i_J.js} +1 -1
- package/dist/assets/web/dist/assets/{php-RHCMbsM2.js → php-CwUxvLX0.js} +1 -1
- package/dist/assets/web/dist/assets/{pug-CFNq_FCp.js → pug-uOIOExr0.js} +1 -1
- package/dist/assets/web/dist/assets/{qml-C9Acx9E8.js → qml-g5RoADf-.js} +1 -1
- package/dist/assets/web/dist/assets/{r-DxlU8FBd.js → r-5LdAopD3.js} +1 -1
- package/dist/assets/web/dist/assets/{razor-CLJ2kKih.js → razor-DwrvFLYQ.js} +1 -1
- package/dist/assets/web/dist/assets/{regexp-CzmdGoEp.js → regexp-dGtAaxC-.js} +1 -1
- package/dist/assets/web/dist/assets/{rst-D9yuxBET.js → rst-wFdW0brr.js} +1 -1
- package/dist/assets/web/dist/assets/{ruby-CIRcEvnD.js → ruby-DPglN6I9.js} +1 -1
- package/dist/assets/web/dist/assets/{sas-LOl-uUPh.js → sas-CUbCs40d.js} +1 -1
- package/dist/assets/web/dist/assets/{scss-BX2_sZHY.js → scss-B-DUiI1c.js} +1 -1
- package/dist/assets/web/dist/assets/{shellscript-4d-QvKkY.js → shellscript-lGOV7Ram.js} +1 -1
- package/dist/assets/web/dist/assets/{shellsession-DhB16UGy.js → shellsession-BDWtAAjr.js} +1 -1
- package/dist/assets/web/dist/assets/{soy-Cm1xTUBr.js → soy-zod_dcOy.js} +1 -1
- package/dist/assets/web/dist/assets/{sql-BsfcBJdu.js → sql-BG0HSSoM.js} +1 -1
- package/dist/assets/web/dist/assets/{sseReplay-BqgOggyQ.js → sseReplay-BzoeVxZB.js} +1 -1
- package/dist/assets/web/dist/assets/{stata-Dwat3BSw.js → stata-BVUMLp1W.js} +1 -1
- package/dist/assets/web/dist/assets/{surrealql-P4rtxzAW.js → surrealql-DiSUbHKF.js} +1 -1
- package/dist/assets/web/dist/assets/{svelte-DTcsi8S8.js → svelte-DZenT45Y.js} +1 -1
- package/dist/assets/web/dist/assets/{templ-D-kP0Tg5.js → templ-BWKRNM0-.js} +1 -1
- package/dist/assets/web/dist/assets/{tex-D-4vuedK.js → tex-CbMzBlkK.js} +1 -1
- package/dist/assets/web/dist/assets/{ts-tags-jEEWYxsu.js → ts-tags-CZsVorDN.js} +1 -1
- package/dist/assets/web/dist/assets/{tsx-CFnlrVzT.js → tsx-R1r3mH4W.js} +1 -1
- package/dist/assets/web/dist/assets/{twig-D5rGrPjs.js → twig-BjPMyjKH.js} +1 -1
- package/dist/assets/web/dist/assets/{typescript-nYIQ35or.js → typescript-Bx-66VN_.js} +1 -1
- package/dist/assets/web/dist/assets/{typst-3-UX8dna.js → typst-fW037Eo6.js} +1 -1
- package/dist/assets/web/dist/assets/{vue-CLIPIX03.js → vue-D1V_GNxW.js} +1 -1
- package/dist/assets/web/dist/assets/{vue-html-Ci9CpkHU.js → vue-html-C-4pTZ-s.js} +1 -1
- package/dist/assets/web/dist/assets/{vue-vine-DL5pEYYk.js → vue-vine-C-QsX3hR.js} +1 -1
- package/dist/assets/web/dist/assets/{wallClock-DmaC1sKA.js → wallClock-x0hjr0J_.js} +1 -1
- package/dist/assets/web/dist/assets/{xml-bO80qikC.js → xml-BJTJXPgC.js} +1 -1
- package/dist/assets/web/dist/assets/{xsl-BPze60Ej.js → xsl-Xc9lukqe.js} +1 -1
- package/dist/assets/web/dist/assets/{yaml-BQUSon_o.js → yaml-Dw-FMsQa.js} +1 -1
- package/dist/cli.js +505 -253
- package/package.json +1 -1
- package/dist/assets/web/dist/assets/CostsPage-BaeWnm-o.js +0 -1
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
// the shim Worker imports this by relative path.
|
|
41
41
|
|
|
42
42
|
import { DAY_MS, DEFAULT_GRANT, GRANT_RENEWALS_MAX, IDLE_DAYS_MAX, type Grant, type GrantSource } from "../budgets.js";
|
|
43
|
+
import { isFindingShape, type Finding } from "../reviewVerdict.js";
|
|
43
44
|
import { DEFAULT_VERBOSITY, isVerbosity, type Verbosity } from "../verbosity.js";
|
|
44
45
|
import {
|
|
45
46
|
applyReturn,
|
|
@@ -343,6 +344,8 @@ function readRecordReturn(step: string, a: BotAnswer): StepReturn {
|
|
|
343
344
|
// they were written (the run record's validator), read here as they are.
|
|
344
345
|
const facts = run as unknown as Omit<Extract<ChildFacts, { finished: true }>, "finished" | "status">;
|
|
345
346
|
const {
|
|
347
|
+
finishedAt,
|
|
348
|
+
reviewAskedAt,
|
|
346
349
|
finalReply,
|
|
347
350
|
pr,
|
|
348
351
|
headSha,
|
|
@@ -367,6 +370,8 @@ function readRecordReturn(step: string, a: BotAnswer): StepReturn {
|
|
|
367
370
|
run: {
|
|
368
371
|
finished: true,
|
|
369
372
|
status: run.status as Extract<ChildFacts, { finished: true }>["status"],
|
|
373
|
+
...(typeof finishedAt === "number" ? { finishedAt } : {}),
|
|
374
|
+
...(typeof reviewAskedAt === "number" ? { reviewAskedAt } : {}),
|
|
370
375
|
...(finalReply !== undefined ? { finalReply } : {}),
|
|
371
376
|
...(pr !== undefined ? { pr } : {}),
|
|
372
377
|
...(headSha !== undefined ? { headSha } : {}),
|
|
@@ -403,6 +408,33 @@ function isCommitChecks(v: unknown): v is { total: number; pending: string[]; fa
|
|
|
403
408
|
return typeof c.total === "number" && names(c.pending) && names(c.failed);
|
|
404
409
|
}
|
|
405
410
|
|
|
411
|
+
function entryHumanGate(v: unknown):
|
|
412
|
+
| {
|
|
413
|
+
round: number;
|
|
414
|
+
findings: Finding[];
|
|
415
|
+
verdict: "approve" | "request_changes";
|
|
416
|
+
answer: string;
|
|
417
|
+
author: string;
|
|
418
|
+
commentId: string;
|
|
419
|
+
}
|
|
420
|
+
| undefined {
|
|
421
|
+
if (typeof v !== "object" || v === null) return undefined;
|
|
422
|
+
const row = v as Record<string, unknown>;
|
|
423
|
+
if (typeof row.round !== "number" || !Number.isInteger(row.round) || row.round < 1) return undefined;
|
|
424
|
+
if (!Array.isArray(row.findings) || !row.findings.every(isFindingShape)) return undefined;
|
|
425
|
+
if (row.verdict !== "approve" && row.verdict !== "request_changes") return undefined;
|
|
426
|
+
if (typeof row.answer !== "string" || typeof row.author !== "string" || typeof row.commentId !== "string")
|
|
427
|
+
return undefined;
|
|
428
|
+
return {
|
|
429
|
+
round: row.round,
|
|
430
|
+
findings: row.findings,
|
|
431
|
+
verdict: row.verdict,
|
|
432
|
+
answer: row.answer,
|
|
433
|
+
author: row.author,
|
|
434
|
+
commentId: row.commentId,
|
|
435
|
+
};
|
|
436
|
+
}
|
|
437
|
+
|
|
406
438
|
function prCheckReturn(step: string, a: BotAnswer): StepReturn {
|
|
407
439
|
const { ok, state, prNumber, url, headSha, sha, mergedAt, at } = a.body;
|
|
408
440
|
if (ok === true && state === "none") {
|
|
@@ -448,6 +480,7 @@ function prCheckReturn(step: string, a: BotAnswer): StepReturn {
|
|
|
448
480
|
// The base's merge-queue rule beside the checks (issue 2011): the
|
|
449
481
|
// merge:person report says the person's merge is queued.
|
|
450
482
|
...(typeof a.body.baseHasMergeQueue === "boolean" ? { baseHasMergeQueue: a.body.baseHasMergeQueue } : {}),
|
|
483
|
+
...(entryHumanGate(a.body.humanGate) !== undefined ? { humanGate: entryHumanGate(a.body.humanGate)! } : {}),
|
|
451
484
|
},
|
|
452
485
|
at,
|
|
453
486
|
};
|
|
@@ -773,7 +806,7 @@ async function tellStepThrew(
|
|
|
773
806
|
: `in round ${at.round.index} (\`${at.step}\`)`;
|
|
774
807
|
const report =
|
|
775
808
|
`⚠️ The runner failed ${where}: ${line}\n\n` +
|
|
776
|
-
"
|
|
809
|
+
"The unit remains bound to this thread; the next reply continues it, and a pull request already approved with green checks resumes at the checks step, never at a fresh coding round.";
|
|
777
810
|
const body = {
|
|
778
811
|
...tag,
|
|
779
812
|
ending: {
|
|
@@ -961,6 +994,7 @@ async function runUnit(
|
|
|
961
994
|
...(note.ending.from !== undefined ? { from: note.ending.from } : {}),
|
|
962
995
|
spendUsd: note.ending.spendUsd,
|
|
963
996
|
...(note.ending.handoff !== undefined ? { handoff: note.ending.handoff } : {}),
|
|
997
|
+
...(note.ending.humanGate !== undefined ? { humanGate: note.ending.humanGate } : {}),
|
|
964
998
|
}
|
|
965
999
|
: {}),
|
|
966
1000
|
},
|
|
@@ -1007,14 +1041,14 @@ async function runUnit(
|
|
|
1007
1041
|
|
|
1008
1042
|
/** The report of a unit the hard stop ended before it ran (record 0060; issue 1924). */
|
|
1009
1043
|
function stoppedReport(unit: string): string {
|
|
1010
|
-
return `⏹ Stopped: the pipeline's hosted parent was hard-stopped, so ${unit} was ended without running.
|
|
1044
|
+
return `⏹ Stopped: the pipeline's hosted parent was hard-stopped, so ${unit} was ended without running. The original plan remains the durable task for any later pipeline.`;
|
|
1011
1045
|
}
|
|
1012
1046
|
|
|
1013
1047
|
function blockedReport(unit: string, dep: string, depEnding: string): string {
|
|
1014
1048
|
if (depEnding === "blocked")
|
|
1015
|
-
return `⛔ Blocked: ${unit} waits on ${dep}, which is blocked itself.
|
|
1049
|
+
return `⛔ Blocked: ${unit} waits on ${dep}, which is blocked itself. A later pipeline recognizes both units once the dependency is resolved.`;
|
|
1016
1050
|
const person = depEnding === "merge_ready";
|
|
1017
|
-
return `⛔ Blocked: ${unit} waits on ${dep}, which ended ${depEnding}${person ? " — a person's merge" : ""}.
|
|
1051
|
+
return `⛔ Blocked: ${unit} waits on ${dep}, which ended ${depEnding}${person ? " — a person's merge" : ""}. A later pipeline recognizes the dependency once it is ${person ? "merged" : "resolved"}.`;
|
|
1018
1052
|
}
|
|
1019
1053
|
|
|
1020
1054
|
/** End a unit that never entered `runUnit` under the same failure net. */
|
|
@@ -1171,6 +1205,7 @@ async function waitOnIdle(
|
|
|
1171
1205
|
...(answer.runId !== undefined ? { previousRunId: answer.runId } : {}),
|
|
1172
1206
|
...(answer.handoff !== undefined ? { previousHandoff: answer.handoff } : {}),
|
|
1173
1207
|
...(answer.texts.length > 0 ? { texts: answer.texts } : {}),
|
|
1208
|
+
...(answer.humanGate !== undefined ? { humanGate: answer.humanGate } : {}),
|
|
1174
1209
|
...(answer.leaseMs !== undefined
|
|
1175
1210
|
? { resume: { leaseMs: answer.leaseMs, attempt: (currentSession?.resume?.attempt ?? 0) + 1 } }
|
|
1176
1211
|
: {}),
|
|
@@ -1240,7 +1275,7 @@ async function walk(step: StepRunner, bot: CoordinatorBot, instanceId: string):
|
|
|
1240
1275
|
next,
|
|
1241
1276
|
stepPrefixOf(next, session),
|
|
1242
1277
|
ending,
|
|
1243
|
-
plan.idleDays,
|
|
1278
|
+
ending.parkDays ?? plan.idleDays,
|
|
1244
1279
|
session,
|
|
1245
1280
|
);
|
|
1246
1281
|
if (parked.kind === "ending") {
|
|
@@ -328,8 +328,14 @@ function findingCounts(findings: readonly Finding[] | undefined): string {
|
|
|
328
328
|
return `${findings.length} finding${findings.length === 1 ? "" : "s"}: ${by}`;
|
|
329
329
|
}
|
|
330
330
|
|
|
331
|
-
/** A table cell
|
|
332
|
-
|
|
331
|
+
/** A one-line Markdown table cell. Backslashes are escaped before pipes so
|
|
332
|
+
* input cannot consume the pipe escape and split the row. */
|
|
333
|
+
export const escapeMarkdownTableCell = (text: string): string =>
|
|
334
|
+
oneLine(text).replace(/\\/g, "\\\\").replace(/\|/g, "\\|");
|
|
335
|
+
|
|
336
|
+
/** Decode the two escapes emitted by `escapeMarkdownTableCell`. This also
|
|
337
|
+
* accepts the legacy form that escaped pipes without first escaping slashes. */
|
|
338
|
+
export const unescapeMarkdownTableCell = (text: string): string => text.replace(/\\([\\|])/g, "$1");
|
|
333
339
|
|
|
334
340
|
/** Whether a finding's `file` is a path a blob URL can point at: no
|
|
335
341
|
* whitespace, no backtick, not a URL. */
|
|
@@ -339,7 +345,7 @@ const isRepoPath = (file: string): boolean => /^[^\s`]+$/.test(file) && !/^[a-z]
|
|
|
339
345
|
* file is a path and a target is known. */
|
|
340
346
|
function whereCell(f: Finding, target: ReviewBodyTarget | undefined): string {
|
|
341
347
|
const location = f.line !== undefined ? `${f.file}:${f.line}` : f.file;
|
|
342
|
-
const label = `\`${
|
|
348
|
+
const label = `\`${escapeMarkdownTableCell(location)}\``;
|
|
343
349
|
if (!target || !isRepoPath(f.file)) return label;
|
|
344
350
|
const path = encodeURI(f.file).replace(/#/g, "%23").replace(/\?/g, "%3F");
|
|
345
351
|
const url = `https://github.com/${target.repo}/blob/${target.head}/${path}${f.line !== undefined ? `#L${f.line}` : ""}`;
|
|
@@ -360,6 +366,7 @@ function verdictMarker(verdict: ReviewVerdict | undefined, target: ReviewBodyTar
|
|
|
360
366
|
id: f.id,
|
|
361
367
|
severity: f.severity,
|
|
362
368
|
file: f.file,
|
|
369
|
+
title: f.title,
|
|
363
370
|
...(f.line !== undefined ? { line: f.line } : {}),
|
|
364
371
|
...(f.humanGated ? { humanGated: true } : {}),
|
|
365
372
|
})),
|
|
@@ -395,7 +402,10 @@ export function buildReviewPostBody(
|
|
|
395
402
|
[
|
|
396
403
|
"| Severity | Finding | Where |",
|
|
397
404
|
"| --- | --- | --- |",
|
|
398
|
-
...findings.map(
|
|
405
|
+
...findings.map(
|
|
406
|
+
(f) =>
|
|
407
|
+
`| ${f.severity} | **${escapeMarkdownTableCell(f.id)}** ${escapeMarkdownTableCell(f.title)} | ${whereCell(f, target)} |`,
|
|
408
|
+
),
|
|
399
409
|
].join("\n"),
|
|
400
410
|
);
|
|
401
411
|
}
|
|
@@ -517,7 +527,7 @@ const DISPOSITION_KINDS: readonly string[] = ["fixed", "declined"];
|
|
|
517
527
|
|
|
518
528
|
const isRecordLike = (v: unknown): v is Record<string, unknown> => typeof v === "object" && v !== null;
|
|
519
529
|
|
|
520
|
-
function isFindingShape(v: unknown): v is Finding {
|
|
530
|
+
export function isFindingShape(v: unknown): v is Finding {
|
|
521
531
|
if (!isRecordLike(v)) return false;
|
|
522
532
|
return (
|
|
523
533
|
typeof v.id === "string" &&
|
|
@@ -621,7 +621,7 @@ export function analyzeRunFriction(events: readonly RunEvent[], opts: FrictionOp
|
|
|
621
621
|
findings.push({
|
|
622
622
|
category: "infra_failure",
|
|
623
623
|
severity: "high",
|
|
624
|
-
summary: `no result for tool call (run ended mid-tool): ${event.summary}`,
|
|
624
|
+
summary: `no result for tool call (the run ended mid-tool): ${event.summary}`,
|
|
625
625
|
tool: event.tool,
|
|
626
626
|
eventIndex: index,
|
|
627
627
|
...(durationMs !== undefined ? { durationMs } : {}),
|
|
@@ -480,9 +480,9 @@ function renderFirstInstruction(rebase: ChildContract["rebase"]): string {
|
|
|
480
480
|
const gates = `${FAST_GATES_POINTER} ${GATE_RECEIPTS}`;
|
|
481
481
|
return (
|
|
482
482
|
`Rebase ${branch} onto ${onto} before any other work — the parent unit has merged and the base has moved; ` +
|
|
483
|
-
`the only writes are your own on that branch.
|
|
483
|
+
`the only writes are your own on that branch. ` +
|
|
484
484
|
`Push the branch as soon as the change exists and the fast gates pass — the project's full verification ` +
|
|
485
|
-
`is CI's gate
|
|
485
|
+
`is CI's gate and runs there after the push, with any fix as a further commit; an unpushed tree does not ` +
|
|
486
486
|
`survive the run's end. ${gates} ${REBASE_POINTER} At the wind-down note, ` +
|
|
487
487
|
`commit and push what compiles, say what does not, then answer. ${TIMEOUT_ON_LONG_COMMANDS}`
|
|
488
488
|
);
|