@coreplane/switchboard 1.264.0 → 1.265.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.
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "switchboard",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.265.0",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "switchboard",
|
|
9
|
-
"version": "1.
|
|
9
|
+
"version": "1.265.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.265.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.265.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
|
@@ -1998,10 +1998,12 @@ function settleCoding(
|
|
|
1998
1998
|
// final observed head. Only then may a fresh remote read decide readiness.
|
|
1999
1999
|
if (round.kind === "findings" && facts.status === "completed") {
|
|
2000
2000
|
const issued = next.findingsByRound[round.index] ?? [];
|
|
2001
|
-
const matched = matchDispositions(issued, facts.dispositions ?? [])
|
|
2001
|
+
const { matched, dropped } = matchDispositions(issued, facts.dispositions ?? []);
|
|
2002
2002
|
const missingOutputs = issued
|
|
2003
2003
|
.filter((finding) => !matched.some((disposition) => disposition.findingId === finding.id))
|
|
2004
2004
|
.map((finding) => `missing disposition for ${finding.id}`);
|
|
2005
|
+
if (missingOutputs.length > 0 && dropped.length > 0)
|
|
2006
|
+
missingOutputs.push(`submitted IDs with no matching finding: ${dropped.join(", ")}`);
|
|
2005
2007
|
if (facts.description !== true) missingOutputs.push("missing updated pull request description");
|
|
2006
2008
|
const observedHead = fullHead(facts.headSha);
|
|
2007
2009
|
if (observedHead === undefined) missingOutputs.push("missing final observed commit");
|
package/dist/cli.js
CHANGED
|
@@ -36722,13 +36722,16 @@ async function resolveRepoContext(msg, history = [], probe, residentSlugs, recor
|
|
|
36722
36722
|
rejected = void 0;
|
|
36723
36723
|
unverified = void 0;
|
|
36724
36724
|
}
|
|
36725
|
+
const bareNumberText = !s.pr && repo === records?.pr?.repo ? /\b(?:PR|pull request)\s*#(\d+)\b/i.exec(unwrapSlack(msg.text).replace(CODE_SPAN, " "))?.[1] : void 0;
|
|
36726
|
+
const bareNumber = bareNumberText === void 0 ? void 0 : Number(bareNumberText);
|
|
36727
|
+
const namedPr = s.pr ?? (repo && bareNumber !== void 0 && Number.isSafeInteger(bareNumber) && bareNumber > 0 ? { repo, number: bareNumber } : void 0);
|
|
36725
36728
|
let headSha;
|
|
36726
36729
|
let baseRef;
|
|
36727
36730
|
let prSize;
|
|
36728
36731
|
let facts2;
|
|
36729
36732
|
let closedPr;
|
|
36730
|
-
if (
|
|
36731
|
-
const head = await prHead(
|
|
36733
|
+
if (namedPr && repo === namedPr.repo) {
|
|
36734
|
+
const head = await prHead(namedPr).catch(() => void 0);
|
|
36732
36735
|
if (head?.ref && head.state === "open") {
|
|
36733
36736
|
ref = head.ref;
|
|
36734
36737
|
refFromPr = true;
|
|
@@ -36739,7 +36742,7 @@ async function resolveRepoContext(msg, history = [], probe, residentSlugs, recor
|
|
|
36739
36742
|
facts2 = head?.facts;
|
|
36740
36743
|
if (head?.state === "closed")
|
|
36741
36744
|
closedPr = {
|
|
36742
|
-
number:
|
|
36745
|
+
number: namedPr.number,
|
|
36743
36746
|
merged: head.merged,
|
|
36744
36747
|
...head.mergedAt !== void 0 ? { mergedAt: head.mergedAt } : {}
|
|
36745
36748
|
};
|
|
@@ -36750,16 +36753,16 @@ async function resolveRepoContext(msg, history = [], probe, residentSlugs, recor
|
|
|
36750
36753
|
else if (rejected) out.rejectedRepo = rejected;
|
|
36751
36754
|
if (ref) out.ref = ref;
|
|
36752
36755
|
if (refFromPr) out.refFromPr = true;
|
|
36753
|
-
if (repo &&
|
|
36754
|
-
out.pr =
|
|
36756
|
+
if (repo && namedPr && repo === namedPr.repo) {
|
|
36757
|
+
out.pr = namedPr.number;
|
|
36755
36758
|
out.prFromMessage = true;
|
|
36756
|
-
if (isThreadOwnPr(records, repo,
|
|
36759
|
+
if (isThreadOwnPr(records, repo, namedPr.number)) out.prIsThreadOwn = true;
|
|
36757
36760
|
if (headSha) out.headSha = headSha;
|
|
36758
36761
|
if (baseRef) out.baseRef = baseRef;
|
|
36759
36762
|
if (prSize) out.prSize = prSize;
|
|
36760
36763
|
if (facts2) out.prDescription = facts2;
|
|
36761
36764
|
if (closedPr) out.closedPr = closedPr;
|
|
36762
|
-
} else if (repo && !
|
|
36765
|
+
} else if (repo && !namedPr) {
|
|
36763
36766
|
const inherited = inheritedPr(thread, records, repo);
|
|
36764
36767
|
if (inherited) {
|
|
36765
36768
|
const head = await openPrHeadSha(inherited);
|
|
@@ -40793,6 +40796,7 @@ async function ownerOf2(runs, unitsOf, threadKey) {
|
|
|
40793
40796
|
if (live !== void 0) return { kind: "live", run: live };
|
|
40794
40797
|
const hosted = runs.find((r) => !r.finished && r.hosted === true);
|
|
40795
40798
|
const instanceId = instanceOf(runs);
|
|
40799
|
+
let releasedPr;
|
|
40796
40800
|
if (instanceId !== void 0) {
|
|
40797
40801
|
const units = await unitsOf(instanceId).catch(() => []);
|
|
40798
40802
|
const unit = units.find((u) => u.threadKey === threadKey && u.ending === void 0);
|
|
@@ -40807,11 +40811,19 @@ async function ownerOf2(runs, unitsOf, threadKey) {
|
|
|
40807
40811
|
if (ended.length === 1 && ship !== void 0) return { kind: "pipeline", instanceId, run: ship, unit: ended[0] };
|
|
40808
40812
|
if (ended.length > 1 && ship !== void 0)
|
|
40809
40813
|
return { kind: "pipeline_ambiguous", instanceId, run: ship, units: ended };
|
|
40814
|
+
const released = units.filter((u) => {
|
|
40815
|
+
const binding = u.publication;
|
|
40816
|
+
return u.threadKey === threadKey && u.instanceId === instanceId && u.ending?.kind === "merge_ready" && binding !== void 0 && u.pr?.number === binding.pr && u.branch === binding.headRef && u.branch === binding.publicationRef && binding.owner.instanceId === instanceId && binding.owner.unit === u.unit && (u.lastPush === void 0 || u.lastPush === binding.expectedHeadSha);
|
|
40817
|
+
});
|
|
40818
|
+
if (released.length === 1) {
|
|
40819
|
+
const unit2 = released[0];
|
|
40820
|
+
releasedPr = { repo: unit2.publication.repo, number: unit2.publication.pr, at: unit2.ending.at };
|
|
40821
|
+
}
|
|
40810
40822
|
}
|
|
40811
40823
|
if (hosted !== void 0) return { kind: "live", run: hosted };
|
|
40812
40824
|
const agent = stickyAgentOf(runs);
|
|
40813
|
-
if (agent !== void 0) return { kind: "session", agent };
|
|
40814
|
-
return { kind: "none" };
|
|
40825
|
+
if (agent !== void 0) return { kind: "session", agent, ...releasedPr ? { releasedPr } : {} };
|
|
40826
|
+
return { kind: "none", ...releasedPr ? { releasedPr } : {} };
|
|
40815
40827
|
}
|
|
40816
40828
|
async function shipRequestOf(service, runId3) {
|
|
40817
40829
|
const result = await service.getRun(runId3, { include: "messages" }).catch(() => void 0);
|
|
@@ -46062,7 +46074,7 @@ var init_submit = __esm({
|
|
|
46062
46074
|
submitDispositionsTool = {
|
|
46063
46075
|
name: "submit_dispositions",
|
|
46064
46076
|
failsInText: true,
|
|
46065
|
-
description: "Record one disposition per review finding after addressing them: `fixed` (the finding is addressed in your pushed code) or `declined` (deliberately not doing it \u2014 the note says why). `findingId` is the finding's stable id
|
|
46077
|
+
description: "Record one disposition per review finding after addressing them: `fixed` (the finding is addressed in your pushed code) or `declined` (deliberately not doing it \u2014 the note says why). `findingId` is the finding's stable id printed in the findings. Copy it exactly, including check ids such as `check:CI / checks (test)`; do not replace a check id with `F1`. An id the review never issued answers nothing and is dropped when the plan runner reads your record. Every finding gets exactly one entry, every severity included (nits too). Call it once with the complete set after your last push; a later call replaces the earlier one. The set rides this run's record, where the plan runner reads it for the re-review.",
|
|
46066
46078
|
inputSchema: {
|
|
46067
46079
|
type: "object",
|
|
46068
46080
|
properties: {
|
|
@@ -46072,7 +46084,10 @@ var init_submit = __esm({
|
|
|
46072
46084
|
items: {
|
|
46073
46085
|
type: "object",
|
|
46074
46086
|
properties: {
|
|
46075
|
-
findingId: {
|
|
46087
|
+
findingId: {
|
|
46088
|
+
type: "string",
|
|
46089
|
+
description: 'Copy the exact id in the findings (e.g. "F1" or "check:CI / checks (test)")'
|
|
46090
|
+
},
|
|
46076
46091
|
disposition: { type: "string", enum: ["fixed", "declined"], description: "fixed | declined" },
|
|
46077
46092
|
note: { type: "string", description: "One line: what was done, or why it was declined" }
|
|
46078
46093
|
},
|
|
@@ -46088,7 +46103,7 @@ var init_submit = __esm({
|
|
|
46088
46103
|
if (!ctx.onDispositions) return "no run is recording dispositions here";
|
|
46089
46104
|
ctx.onDispositions(parsed.dispositions);
|
|
46090
46105
|
const drops = parsed.dropped.length ? ` (dropped: ${parsed.dropped.join("; ")})` : "";
|
|
46091
|
-
return `dispositions recorded: ${parsed.dispositions.length}${drops}; a later call replaces this one`;
|
|
46106
|
+
return `dispositions recorded: ${parsed.dispositions.length}${drops}; IDs are checked against the findings by the plan runner; a later call replaces this one`;
|
|
46092
46107
|
}
|
|
46093
46108
|
};
|
|
46094
46109
|
submitPrDescriptionTool = {
|
|
@@ -50278,19 +50293,36 @@ function judgeBashCommand(command2, ctx) {
|
|
|
50278
50293
|
if (MERGE_OR_APPROVE.test(command2)) {
|
|
50279
50294
|
return refused4("merge/approve \u2014 a coding run never merges or approves a pull request");
|
|
50280
50295
|
}
|
|
50296
|
+
const pushCommand = withoutShellContinuations(command2);
|
|
50281
50297
|
if (ctx.identity !== "write") {
|
|
50282
|
-
if (ANY_PUSH.test(
|
|
50298
|
+
if (ANY_PUSH.test(pushCommand)) return refused4("read-only \u2014 a read-identity run never pushes");
|
|
50283
50299
|
if (GH_WRITE_VERB.test(command2) || GH_API_WRITE.test(command2) || CURL_GITHUB_WRITE.test(command2)) {
|
|
50284
50300
|
return refused4("read-only \u2014 a read-identity run never writes to GitHub");
|
|
50285
50301
|
}
|
|
50286
50302
|
return allowed;
|
|
50287
50303
|
}
|
|
50288
|
-
for (const match of
|
|
50304
|
+
for (const match of pushCommand.matchAll(GIT_PUSH)) {
|
|
50289
50305
|
const verdict = judgePush(match[1], ctx);
|
|
50290
50306
|
if (verdict.verdict !== "allowed") return verdict;
|
|
50291
50307
|
}
|
|
50292
50308
|
return allowed;
|
|
50293
50309
|
}
|
|
50310
|
+
function withoutShellContinuations(command2) {
|
|
50311
|
+
let result = "";
|
|
50312
|
+
let quote3;
|
|
50313
|
+
for (let i = 0; i < command2.length; i++) {
|
|
50314
|
+
const char = command2[i];
|
|
50315
|
+
if (char === "\\" && quote3 !== "'" && i + 1 < command2.length) {
|
|
50316
|
+
const next = command2[++i];
|
|
50317
|
+
if (next !== "\n") result += char + next;
|
|
50318
|
+
continue;
|
|
50319
|
+
}
|
|
50320
|
+
if (char === quote3) quote3 = void 0;
|
|
50321
|
+
else if (quote3 === void 0 && (char === "'" || char === '"')) quote3 = char;
|
|
50322
|
+
result += char;
|
|
50323
|
+
}
|
|
50324
|
+
return result;
|
|
50325
|
+
}
|
|
50294
50326
|
function judgeBashTimeout(timeout, ctx) {
|
|
50295
50327
|
if (!ctx.loopEndsIn || typeof timeout !== "number" || !Number.isFinite(timeout) || timeout <= 0) return allowed;
|
|
50296
50328
|
const leftMs = ctx.loopEndsIn();
|
|
@@ -50401,8 +50433,11 @@ var init_toolRules = __esm({
|
|
|
50401
50433
|
ENV_DUMP = /(^|[;&|(]\s*)((printenv|env)(\s+-[A-Za-z0-9-]+)*|export\s+-p|declare\s+-[a-zA-Z]*[px][a-zA-Z]*|set)\s*($|[|;&>)])|\/proc\/(self|\d+)\/environ|process\.env(?![.[\w])/;
|
|
50402
50434
|
CREDENTIAL_VAR = /\$\{?[A-Z][A-Z0-9_]*(_API_KEY|_TOKEN|_SECRET|_BEARER|_PASSWORD)\b|printenv\s+[A-Z][A-Z0-9_]*(_API_KEY|_TOKEN|_SECRET|_BEARER|_PASSWORD)\b/;
|
|
50403
50435
|
MERGE_OR_APPROVE = /\bgh\s+pr\s+(merge|review)\b|\/pulls\/\d+\/(merge|reviews)\b/;
|
|
50404
|
-
GIT_THEN_PUSH = String.raw`\bgit(
|
|
50405
|
-
GIT_PUSH = new RegExp(
|
|
50436
|
+
GIT_THEN_PUSH = String.raw`\bgit(?:[ \t]+(?:-C[ \t]+\S+|--git-dir=\S+|--work-tree=\S+|-c[ \t]+\S+|--no-pager))*[ \t]+push\b`;
|
|
50437
|
+
GIT_PUSH = new RegExp(
|
|
50438
|
+
GIT_THEN_PUSH + String.raw`((?:"(?:\\[\s\S]|[^"\\])*"|'[^']*'|\\[^\n]|[^\n;&|'"\\]|(?<=[<>])&|&(?=>))*)`,
|
|
50439
|
+
"g"
|
|
50440
|
+
);
|
|
50406
50441
|
ANY_PUSH = new RegExp(GIT_THEN_PUSH);
|
|
50407
50442
|
GH_WRITE_VERB = /\bgh\s+(pr|issue)\s+(comment|create|edit|close|reopen|ready|lock|unlock|review|merge|delete|transfer|pin|unpin)\b/;
|
|
50408
50443
|
WRITE_METHOD = "(POST|post|PATCH|patch|PUT|put|DELETE|delete)";
|
|
@@ -56782,7 +56817,8 @@ async function dispatch(deps, msg, io, opts = {}) {
|
|
|
56782
56817
|
);
|
|
56783
56818
|
};
|
|
56784
56819
|
const stickyAgent = thread ? stickyAgentOf(thread) : void 0;
|
|
56785
|
-
const
|
|
56820
|
+
const laterPr = (runPr, releasedPr) => releasedPr !== void 0 && (runPr === void 0 || releasedPr.at > runPr.at) ? releasedPr : runPr;
|
|
56821
|
+
let threadPr = laterPr(thread ? threadPrOf(thread) : void 0, pageOwner?.releasedPr);
|
|
56786
56822
|
const inheritedRepo = operatorRepo ?? (thread ? newestFinishedRunOf(thread)?.repo : void 0) ?? deps.config.scopes(msg.channelId, msg.userId).channel.repo;
|
|
56787
56823
|
const historicalRoutePreset = restart?.row.meta.route?.preset;
|
|
56788
56824
|
const resolveCurrent = () => resolveRun(deps, {
|
|
@@ -56803,6 +56839,7 @@ async function dispatch(deps, msg, io, opts = {}) {
|
|
|
56803
56839
|
const threadLive = admission.get(msg.threadKey) !== void 0 || !resume && !restart && deps.threadsElsewhere.get(msg.threadKey) !== void 0;
|
|
56804
56840
|
if (thread && !threadLive && deps.coordinatorInstances !== void 0) {
|
|
56805
56841
|
const owner = pageOwner ?? await ownerOf2(thread, (id) => deps.coordinatorInstances.listUnits(id), msg.threadKey);
|
|
56842
|
+
threadPr = laterPr(threadPr, owner.releasedPr);
|
|
56806
56843
|
if (owner.kind === "live" && owner.run.hosted === true) {
|
|
56807
56844
|
const units = owner.run.instanceId === void 0 ? [] : await deps.coordinatorInstances.listUnits(owner.run.instanceId).catch(() => []);
|
|
56808
56845
|
const open2 = units.filter((u) => u.ending === void 0);
|
|
@@ -72943,7 +72980,7 @@ function findingsRequest(input) {
|
|
|
72943
72980
|
|
|
72944
72981
|
A person answered the human-gated finding. Treat the finding and this answer together as the fix brief:
|
|
72945
72982
|
${input.answers.join("\n\n")}` : "";
|
|
72946
|
-
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),
|
|
72983
|
+
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). Copy each finding ID exactly, including any \`check:\u2026\` ID; never substitute an \`F1\` ID for a check. Squash to coherent commits, resubmit the pull request description with submit_pr_description, and push the branch. Never merge and never approve.
|
|
72947
72984
|
|
|
72948
72985
|
Findings:
|
|
72949
72986
|
${findings}${answers}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coreplane/switchboard",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.265.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",
|