@tekmidian/pai 0.60.0 → 0.61.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/{chain-DFlzAfDE.mjs → chain-C5oeyUg4.mjs} +4 -4
- package/dist/{chain-DFlzAfDE.mjs.map → chain-C5oeyUg4.mjs.map} +1 -1
- package/dist/cli/index.mjs +12 -12
- package/dist/cli/program.mjs +12 -12
- package/dist/{config-msER8xj_.mjs → config-CQCmH_gV.mjs} +2 -1
- package/dist/config-CQCmH_gV.mjs.map +1 -0
- package/dist/{config-GceCMUxa.mjs → config-DjXq_W42.mjs} +1 -1
- package/dist/{context-handover-cache-DF0xWVB0.mjs → context-handover-cache-BdtJZpgv.mjs} +4 -4
- package/dist/{context-handover-cache-DF0xWVB0.mjs.map → context-handover-cache-BdtJZpgv.mjs.map} +1 -1
- package/dist/daemon/index.mjs +11 -11
- package/dist/{daemon-DArRKBlk.mjs → daemon-DSsIEqzW.mjs} +26 -19
- package/dist/{daemon-DArRKBlk.mjs.map → daemon-DSsIEqzW.mjs.map} +1 -1
- package/dist/daemon-MoFF4oeg.mjs +19 -0
- package/dist/daemon-mcp/index.mjs +9 -11
- package/dist/daemon-mcp/index.mjs.map +1 -1
- package/dist/{factory-D6I2jmjQ.mjs → factory-DW7BCJJT.mjs} +1 -1
- package/dist/{factory-ChfAvCzO.mjs → factory-EUUhSSoq.mjs} +5 -6
- package/dist/factory-EUUhSSoq.mjs.map +1 -0
- package/dist/{fallback-B7VEMMRn.mjs → fallback-DDbJVaR8.mjs} +12 -14
- package/dist/{fallback-B7VEMMRn.mjs.map → fallback-DDbJVaR8.mjs.map} +1 -1
- package/dist/hooks/block-sleep-poll.mjs.map +2 -2
- package/dist/hooks/context-compression-hook.mjs.map +1 -1
- package/dist/hooks/post-compact-inject.mjs.map +1 -1
- package/dist/hooks/route-agents-to-worker.mjs +5 -5
- package/dist/hooks/route-agents-to-worker.mjs.map +3 -3
- package/dist/hooks/security-validator.mjs +60 -60
- package/dist/hooks/security-validator.mjs.map +3 -3
- package/dist/hooks/stop-hook.mjs +15 -15
- package/dist/hooks/stop-hook.mjs.map +3 -3
- package/dist/hooks/update-tab-on-action.mjs +14 -12
- package/dist/hooks/update-tab-on-action.mjs.map +3 -3
- package/dist/hooks/update-tab-titles.mjs +13 -9
- package/dist/hooks/update-tab-titles.mjs.map +3 -3
- package/dist/hooks/whisper-rules.mjs +2 -2
- package/dist/hooks/whisper-rules.mjs.map +3 -3
- package/dist/hooks/worker-proxy.mjs +5 -5
- package/dist/hooks/worker-proxy.mjs.map +3 -3
- package/dist/hooks/worker-status-line.mjs +5 -5
- package/dist/hooks/worker-status-line.mjs.map +3 -3
- package/dist/hooks/worker-supervision.mjs +5 -5
- package/dist/hooks/worker-supervision.mjs.map +3 -3
- package/dist/main-resolver-CxOsxtOr.mjs +7 -0
- package/dist/{main-resolver-BqTjt-GL.mjs → main-resolver-DIQ6m_RA.mjs} +4 -4
- package/dist/{main-resolver-BqTjt-GL.mjs.map → main-resolver-DIQ6m_RA.mjs.map} +1 -1
- package/dist/{planner-DbpsMZqY.mjs → planner-D8jAr_sx.mjs} +7 -7
- package/dist/{planner-DbpsMZqY.mjs.map → planner-D8jAr_sx.mjs.map} +1 -1
- package/dist/{program-QSuci3RH.mjs → program-BTdspOOa.mjs} +131 -81
- package/dist/program-BTdspOOa.mjs.map +1 -0
- package/dist/{run-BFxuNnIJ.mjs → run-CxxZKEZw.mjs} +336 -174
- package/dist/run-CxxZKEZw.mjs.map +1 -0
- package/dist/{run-env-kbWVwUvU.mjs → run-env-BE5xyCwy.mjs} +26 -7
- package/dist/run-env-BE5xyCwy.mjs.map +1 -0
- package/dist/{server-B0vBmfJt.mjs → server-BY6AedmC.mjs} +2 -2
- package/dist/{server-B0vBmfJt.mjs.map → server-BY6AedmC.mjs.map} +1 -1
- package/dist/{session-keepalive-CUcFa8ld.mjs → session-keepalive-urk--pfa.mjs} +5 -5
- package/dist/{session-keepalive-CUcFa8ld.mjs.map → session-keepalive-urk--pfa.mjs.map} +1 -1
- package/dist/{tools-CaTZnIau.mjs → tools-qXyHFwNj.mjs} +2 -2
- package/dist/{tools-CaTZnIau.mjs.map → tools-qXyHFwNj.mjs.map} +1 -1
- package/dist/{tools-_7MF8Ebb.mjs → tools-r-7ZG8B5.mjs} +3 -3
- package/dist/{wakeup-CTX3rlz-.mjs → wakeup-C48hcN6O.mjs} +2 -2
- package/dist/{wakeup-CTX3rlz-.mjs.map → wakeup-C48hcN6O.mjs.map} +1 -1
- package/dist/work-queue-worker-1_VBfI_k.mjs +11 -0
- package/dist/{work-queue-worker-B4eZGy5n.mjs → work-queue-worker-DUvPiwGO.mjs} +2 -2
- package/dist/{work-queue-worker-B4eZGy5n.mjs.map → work-queue-worker-DUvPiwGO.mjs.map} +1 -1
- package/docs/commands/worker.md +1 -0
- package/package.json +1 -1
- package/src/hooks/ts/lib/tab-title.ts +18 -0
- package/src/hooks/ts/post-tool-use/update-tab-on-action.ts +3 -20
- package/src/hooks/ts/stop/stop-hook.ts +4 -15
- package/src/hooks/ts/user-prompt/update-tab-titles.ts +2 -10
- package/dist/config-msER8xj_.mjs.map +0 -1
- package/dist/daemon-BppwJtrH.mjs +0 -19
- package/dist/factory-ChfAvCzO.mjs.map +0 -1
- package/dist/main-resolver-CCojcYr2.mjs +0 -7
- package/dist/program-QSuci3RH.mjs.map +0 -1
- package/dist/run-BFxuNnIJ.mjs.map +0 -1
- package/dist/run-env-kbWVwUvU.mjs.map +0 -1
- package/dist/work-queue-worker-DuhZmfDB.mjs +0 -11
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { i as getRegistryBackend } from "./factory-
|
|
2
|
-
import {
|
|
3
|
-
import { _ as statusPath, d as resolveTarget, f as setCooldown, g as panesDir, h as ledgerPath, i as capabilityForRun, m as eventsPath, n as ensureProxyRunning, o as isQuotaFailure, p as ensureNoMcpConfig, s as nextAutoProvider, t as DEFAULT_PROXY_PORT, u as resolveCapabilityRun, v as workersLogDir } from "./server-
|
|
4
|
-
import { appendFileSync, closeSync, existsSync, mkdirSync, mkdtempSync, openSync, readFileSync, readdirSync, renameSync, rmSync, statSync, unlinkSync, writeFileSync, writeSync } from "node:fs";
|
|
1
|
+
import { i as getRegistryBackend } from "./factory-EUUhSSoq.mjs";
|
|
2
|
+
import { E as readWorkersSection, O as resolveModelCapability, T as providerKeyPath, b as isModelCapability, d as NATIVE_ANTHROPIC_MODELS, g as classModelCapability, h as assertProviderRunnable, k as resolveProviderKey, m as WorkersConfigError, n as claudeCommand, t as buildRunEnv } from "./run-env-BE5xyCwy.mjs";
|
|
3
|
+
import { _ as statusPath, d as resolveTarget, f as setCooldown, g as panesDir, h as ledgerPath, i as capabilityForRun, m as eventsPath, n as ensureProxyRunning, o as isQuotaFailure, p as ensureNoMcpConfig, s as nextAutoProvider, t as DEFAULT_PROXY_PORT, u as resolveCapabilityRun, v as workersLogDir } from "./server-BY6AedmC.mjs";
|
|
4
|
+
import { appendFileSync, closeSync, existsSync, lstatSync, mkdirSync, mkdtempSync, openSync, readFileSync, readdirSync, readlinkSync, realpathSync, renameSync, rmSync, statSync, unlinkSync, writeFileSync, writeSync } from "node:fs";
|
|
5
5
|
import { homedir, tmpdir } from "node:os";
|
|
6
|
-
import { dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
6
|
+
import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
7
7
|
import { execFileSync, spawn } from "node:child_process";
|
|
8
8
|
import { connect, createServer } from "node:net";
|
|
9
9
|
import { createInterface } from "node:readline";
|
|
@@ -336,9 +336,10 @@ function saveStatus(logDir, status, d = /* @__PURE__ */ new Date()) {
|
|
|
336
336
|
const path = statusPath(logDir, status.id);
|
|
337
337
|
const baseline = firstWrittenLabel.get(status.id);
|
|
338
338
|
if (baseline === void 0) firstWrittenLabel.set(status.id, status.label);
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
if (
|
|
339
|
+
const onDisk = baseline === void 0 ? void 0 : loadStatus(logDir, status.id);
|
|
340
|
+
if (onDisk) {
|
|
341
|
+
if (status.label === baseline && onDisk.label !== status.label) status.label = onDisk.label;
|
|
342
|
+
if (onDisk.controlsHeld) status.controlsHeld = true;
|
|
342
343
|
}
|
|
343
344
|
const tmp = statusTmpPath(logDir, status.id);
|
|
344
345
|
if (!existsSync(logDir)) mkdirSync(logDir, { recursive: true });
|
|
@@ -639,7 +640,8 @@ function isGitRepo(cwd) {
|
|
|
639
640
|
function promptLooksReadonly(prompt) {
|
|
640
641
|
const p = prompt.trim();
|
|
641
642
|
if (!p) return true;
|
|
642
|
-
|
|
643
|
+
const firstLine = p.split("\n", 1)[0];
|
|
644
|
+
if (/\b(read[- ]only|do not (modify|change|edit|write)|don'?t (modify|change|edit|write)|no changes)\b/i.test(firstLine)) return true;
|
|
643
645
|
return /^(review|read|analy[sz]e|research|summar[iy]|inspect|investigate|spotcheck|report|find|list|check|verify|describe|explain|show)\b/i.test(p);
|
|
644
646
|
}
|
|
645
647
|
/** The classes whose runs write files and therefore default to a worktree. */
|
|
@@ -843,18 +845,58 @@ function uncommittedPaths(wtDir) {
|
|
|
843
845
|
return [...tracked, ...untracked];
|
|
844
846
|
}
|
|
845
847
|
/**
|
|
848
|
+
* True when `wtDir`/`relPath` is a symlink whose target resolves outside
|
|
849
|
+
* `wtDir` — e.g. a worker's `node_modules -> <main checkout>/node_modules`
|
|
850
|
+
* convenience link. A `.gitignore` using `dir/` (directories only) does not
|
|
851
|
+
* ignore such a link, so it turns up as untracked; staging and merging it
|
|
852
|
+
* lets git replace the real directory on the other side with a symlink to
|
|
853
|
+
* itself. Never a candidate for salvage.
|
|
854
|
+
*/
|
|
855
|
+
function symlinkEscapesWorktree(wtDir, relPath) {
|
|
856
|
+
const full = join(wtDir, relPath);
|
|
857
|
+
let stat;
|
|
858
|
+
try {
|
|
859
|
+
stat = lstatSync(full);
|
|
860
|
+
} catch {
|
|
861
|
+
return false;
|
|
862
|
+
}
|
|
863
|
+
if (!stat.isSymbolicLink()) return false;
|
|
864
|
+
const target = readlinkSync(full);
|
|
865
|
+
const resolvedTarget = isAbsolute(target) ? target : resolve(dirname(full), target);
|
|
866
|
+
const realTarget = existsSync(resolvedTarget) ? realpathSync(resolvedTarget) : resolvedTarget;
|
|
867
|
+
const realWtDir = realpathSync(wtDir);
|
|
868
|
+
return realTarget !== realWtDir && !realTarget.startsWith(realWtDir + sep);
|
|
869
|
+
}
|
|
870
|
+
/**
|
|
846
871
|
* Commit a worktree's uncommitted changes to its branch so the merge carries
|
|
847
872
|
* them. `git merge` only moves committed work, so a worker that stopped
|
|
848
873
|
* without committing would lose its edits to `worktree remove` — exactly
|
|
849
|
-
* what happened live on 2026-09-17. Returns the salvaged paths,
|
|
850
|
-
* worktree is clean. A
|
|
874
|
+
* what happened live on 2026-09-17. Returns the salvaged paths, empty when
|
|
875
|
+
* the worktree is clean. A symlink pointing outside the worktree (see
|
|
876
|
+
* `symlinkEscapesWorktree`) is never staged; it is left on disk and reported
|
|
877
|
+
* as skipped instead. A failed commit throws with the worktree untouched:
|
|
851
878
|
* its edits are still on disk, so nothing is lost.
|
|
852
879
|
*/
|
|
853
880
|
function salvageUncommitted(wtDir, label) {
|
|
854
881
|
const paths = uncommittedPaths(wtDir);
|
|
855
|
-
if (!paths.length) return
|
|
882
|
+
if (!paths.length) return {
|
|
883
|
+
committed: [],
|
|
884
|
+
skipped: []
|
|
885
|
+
};
|
|
886
|
+
const skipped = [];
|
|
887
|
+
const toStage = [];
|
|
888
|
+
for (const p of paths) if (symlinkEscapesWorktree(wtDir, p)) skipped.push(`symlink ${p} -> ${readlinkSync(join(wtDir, p))} (points outside the worktree)`);
|
|
889
|
+
else toStage.push(p);
|
|
890
|
+
if (!toStage.length) return {
|
|
891
|
+
committed: [],
|
|
892
|
+
skipped
|
|
893
|
+
};
|
|
856
894
|
try {
|
|
857
|
-
git(wtDir, [
|
|
895
|
+
git(wtDir, [
|
|
896
|
+
"add",
|
|
897
|
+
"--",
|
|
898
|
+
...toStage
|
|
899
|
+
]);
|
|
858
900
|
git(wtDir, [
|
|
859
901
|
"commit",
|
|
860
902
|
"-m",
|
|
@@ -863,7 +905,10 @@ function salvageUncommitted(wtDir, label) {
|
|
|
863
905
|
} catch (e) {
|
|
864
906
|
throw new Error(`cannot salvage the uncommitted changes in ${wtDir} — ${e.message}; nothing was lost: commit them there by hand, then re-run merge`);
|
|
865
907
|
}
|
|
866
|
-
return
|
|
908
|
+
return {
|
|
909
|
+
committed: toStage,
|
|
910
|
+
skipped
|
|
911
|
+
};
|
|
867
912
|
}
|
|
868
913
|
/**
|
|
869
914
|
* The dirty paths of a checkout, parsed from `git status --porcelain -z`:
|
|
@@ -914,9 +959,14 @@ function assertNoDirtyOverlap(cwd, incoming, id, branch) {
|
|
|
914
959
|
if (!overlap.length) return;
|
|
915
960
|
throw new Error(`worker ${id}: the checkout ${cwd} has uncommitted changes in paths ${branch} touches: ${overlap.join(", ")}. Commit or stash them in the checkout, then re-run: pai worker merge ${id}. No merge was made; the worktree was kept.`);
|
|
916
961
|
}
|
|
917
|
-
/**
|
|
962
|
+
/**
|
|
963
|
+
* Never remove a worktree that still holds uncommitted changes — except a
|
|
964
|
+
* symlink escaping the worktree (see `symlinkEscapesWorktree`): it was
|
|
965
|
+
* deliberately left uncommitted by `salvageUncommitted`, and deleting the
|
|
966
|
+
* link itself touches nothing outside the worktree.
|
|
967
|
+
*/
|
|
918
968
|
function assertWorktreeClean(wtDir, id) {
|
|
919
|
-
const leftover = uncommittedPaths(wtDir);
|
|
969
|
+
const leftover = uncommittedPaths(wtDir).filter((p) => !symlinkEscapesWorktree(wtDir, p));
|
|
920
970
|
if (leftover.length) throw new Error(`worker ${id}: the worktree ${wtDir} still holds uncommitted changes (${leftover.join(", ")}) — it was NOT removed; commit or copy them by hand, then re-run merge`);
|
|
921
971
|
}
|
|
922
972
|
/** Blob sha of `path` at `rev` in `cwd`, or null when it does not exist there. */
|
|
@@ -970,7 +1020,10 @@ function mergeSnapshotWorker(logDir, id, st) {
|
|
|
970
1020
|
const snapshot = st.worktreeBase;
|
|
971
1021
|
const branch = st.branch;
|
|
972
1022
|
const worktreeDir = st.worktreeDir;
|
|
973
|
-
const
|
|
1023
|
+
const salvage = existsSync(worktreeDir) ? salvageUncommitted(worktreeDir, st.label || UNLABELED) : {
|
|
1024
|
+
committed: [],
|
|
1025
|
+
skipped: []
|
|
1026
|
+
};
|
|
974
1027
|
if ((parseInt(git(st.cwd, [
|
|
975
1028
|
"rev-list",
|
|
976
1029
|
"--count",
|
|
@@ -1029,7 +1082,10 @@ function mergeSnapshotWorker(logDir, id, st) {
|
|
|
1029
1082
|
merged: true
|
|
1030
1083
|
});
|
|
1031
1084
|
const base = `applied worker ${id}'s changes (branch ${branch}) to ${st.cwd} as uncommitted changes: ${changedPaths.join(", ")} (worktree removed, branch deleted)`;
|
|
1032
|
-
|
|
1085
|
+
const notes = [];
|
|
1086
|
+
if (salvage.committed.length) notes.push(`salvaged ${salvage.committed.length} uncommitted change(s) onto the branch first: ${salvage.committed.join(", ")}`);
|
|
1087
|
+
if (salvage.skipped.length) notes.push(`skipped ${salvage.skipped.join(", ")}`);
|
|
1088
|
+
return notes.length ? `${base}; ${notes.join("; ")}` : base;
|
|
1033
1089
|
}
|
|
1034
1090
|
/**
|
|
1035
1091
|
* `pai worker merge <id>`: salvage whatever the worker left uncommitted onto
|
|
@@ -1044,7 +1100,10 @@ function mergeWorker(logDir, id) {
|
|
|
1044
1100
|
const st = mustHaveBranch(logDir, id);
|
|
1045
1101
|
if (st.merged) return `worker ${id}: branch ${st.branch} already merged`;
|
|
1046
1102
|
if (st.worktreeSnapshot) return mergeSnapshotWorker(logDir, id, st);
|
|
1047
|
-
const
|
|
1103
|
+
const salvage = existsSync(st.worktreeDir) ? salvageUncommitted(st.worktreeDir, st.label || UNLABELED) : {
|
|
1104
|
+
committed: [],
|
|
1105
|
+
skipped: []
|
|
1106
|
+
};
|
|
1048
1107
|
if ((parseInt(git(st.cwd, [
|
|
1049
1108
|
"rev-list",
|
|
1050
1109
|
"--count",
|
|
@@ -1074,7 +1133,7 @@ function mergeWorker(logDir, id) {
|
|
|
1074
1133
|
throw new Error(`worker ${id}: git refused the merge of ${st.branch} — ${e.message}. The worktree ${st.worktreeDir} was kept: resolve the conflict, then re-run merge`);
|
|
1075
1134
|
}
|
|
1076
1135
|
if (existsSync(st.worktreeDir)) assertWorktreeClean(st.worktreeDir, id);
|
|
1077
|
-
removeWorktree(st.cwd, st.worktreeDir,
|
|
1136
|
+
removeWorktree(st.cwd, st.worktreeDir, true);
|
|
1078
1137
|
let branchGone = true;
|
|
1079
1138
|
try {
|
|
1080
1139
|
git(st.cwd, [
|
|
@@ -1090,7 +1149,10 @@ function mergeWorker(logDir, id) {
|
|
|
1090
1149
|
merged: true
|
|
1091
1150
|
});
|
|
1092
1151
|
const base = `merged ${st.branch} into ${st.cwd} (worktree removed${branchGone ? ", branch deleted" : "; branch kept: git refused -d"})`;
|
|
1093
|
-
|
|
1152
|
+
const notes = [];
|
|
1153
|
+
if (salvage.committed.length) notes.push(`salvaged ${salvage.committed.length} uncommitted change(s): ${salvage.committed.join(", ")}`);
|
|
1154
|
+
if (salvage.skipped.length) notes.push(`skipped ${salvage.skipped.join(", ")}`);
|
|
1155
|
+
return notes.length ? `${base}; ${notes.join("; ")}` : base;
|
|
1094
1156
|
}
|
|
1095
1157
|
/** `pai worker discard <id>`: drop worktree and branch, keep nothing. */
|
|
1096
1158
|
function discardWorker(logDir, id) {
|
|
@@ -1172,9 +1234,10 @@ function inPlaceSystemPrompt() {
|
|
|
1172
1234
|
* If neither is available, viewers fall back to "all workers".
|
|
1173
1235
|
*
|
|
1174
1236
|
* A third case: workers spawned from a Claude Code Bash tool (the
|
|
1175
|
-
* orchestrator pattern)
|
|
1176
|
-
*
|
|
1177
|
-
*
|
|
1237
|
+
* orchestrator pattern) inherit the orchestrator's `ITERM_SESSION_ID`, which
|
|
1238
|
+
* identifies the orchestrator's own pane, not a pane for the sub-worker —
|
|
1239
|
+
* so it does not key the sub-worker's tab. Those record `spawnerSession`,
|
|
1240
|
+
* the orchestrator's claude session id bridged through the status line's
|
|
1178
1241
|
* session map (see below), so their tab still claims them.
|
|
1179
1242
|
*/
|
|
1180
1243
|
const AIBROKER_REGISTRY = join(homedir(), ".aibroker", "session-names.json");
|
|
@@ -1896,7 +1959,10 @@ function absoluteCliPath() {
|
|
|
1896
1959
|
}
|
|
1897
1960
|
/** Open (or only report on) the stacked follow pane of one worker. */
|
|
1898
1961
|
async function openPaneForWorker(logDir, config, wid, term) {
|
|
1899
|
-
if (workerPaneOpen(wid)) return
|
|
1962
|
+
if (workerPaneOpen(wid)) return {
|
|
1963
|
+
message: `pane for ${wid} already open`,
|
|
1964
|
+
session: null
|
|
1965
|
+
};
|
|
1900
1966
|
const uid = itermUuid(term);
|
|
1901
1967
|
const regPath = join(panesDir(logDir), `${scopeKey(term)}.json`);
|
|
1902
1968
|
const reg = loadRegistry(regPath);
|
|
@@ -1920,7 +1986,10 @@ async function openPaneForWorker(logDir, config, wid, term) {
|
|
|
1920
1986
|
opened: (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19)
|
|
1921
1987
|
});
|
|
1922
1988
|
saveRegistry(regPath, pruned);
|
|
1923
|
-
return
|
|
1989
|
+
return {
|
|
1990
|
+
message: `pane opened for ${wid}`,
|
|
1991
|
+
session: out.slice(bar + 1)
|
|
1992
|
+
};
|
|
1924
1993
|
}
|
|
1925
1994
|
/**
|
|
1926
1995
|
* One `--check` line with the bounds of the window hosting `term`'s iTerm
|
|
@@ -2040,6 +2109,34 @@ function launchParent(explicit, env = process.env) {
|
|
|
2040
2109
|
function isWorkerId(logDir, id) {
|
|
2041
2110
|
return loadStatus(logDir, id) !== null;
|
|
2042
2111
|
}
|
|
2112
|
+
/**
|
|
2113
|
+
* A worker owns its children's results (the worker contract says so): if
|
|
2114
|
+
* `parent` exits leaving sub-workers unaccounted for, its own run must not
|
|
2115
|
+
* report success. Two shapes count, both read off `runningChildren` and the
|
|
2116
|
+
* raw statuses, never a second live-child lookup:
|
|
2117
|
+
*
|
|
2118
|
+
* - still live: left running untouched (killing another process's work
|
|
2119
|
+
* here would be its own bug) but named in the reason.
|
|
2120
|
+
* - marked "running" with a dead pid (the child never got to write its own
|
|
2121
|
+
* terminal state before its parent vanished from under it): finalised
|
|
2122
|
+
* here as failed, so `ps` stops showing a corpse as live.
|
|
2123
|
+
*
|
|
2124
|
+
* Returns the reason string for the parent's own report, or null when every
|
|
2125
|
+
* child it started is accounted for.
|
|
2126
|
+
*/
|
|
2127
|
+
function checkOrphanedChildren(logDir, parent) {
|
|
2128
|
+
const statuses = loadStatuses(logDir);
|
|
2129
|
+
const live = runningChildren(statuses, parent);
|
|
2130
|
+
const abandoned = statuses.filter((s) => s.parent === parent && s.state === "running" && !isLive(s));
|
|
2131
|
+
for (const child of abandoned) saveStatus(logDir, {
|
|
2132
|
+
...child,
|
|
2133
|
+
state: "failed",
|
|
2134
|
+
last: `parent ${parent} exited`
|
|
2135
|
+
});
|
|
2136
|
+
const ids = [...live, ...abandoned].map((s) => s.id);
|
|
2137
|
+
if (!ids.length) return null;
|
|
2138
|
+
return `exited with ${ids.length} sub-worker${ids.length === 1 ? "" : "s"} still running (${ids.join(", ")}); they were not waited for — run children in the foreground or wait for them before finishing`;
|
|
2139
|
+
}
|
|
2043
2140
|
|
|
2044
2141
|
//#endregion
|
|
2045
2142
|
//#region src/workers/operator.ts
|
|
@@ -2282,6 +2379,16 @@ function ag2Spec() {
|
|
|
2282
2379
|
return cachedSpec;
|
|
2283
2380
|
}
|
|
2284
2381
|
/**
|
|
2382
|
+
* Strip what workers wrap around a report: one surrounding ``` fence (opening
|
|
2383
|
+
* line may carry a language tag) and a leading `[YYYY-MM-DD HH:MM]` stamp line.
|
|
2384
|
+
*/
|
|
2385
|
+
function unwrapAg2(text) {
|
|
2386
|
+
let t = (text ?? "").trim();
|
|
2387
|
+
const fenced = t.match(/^```[^\n]*\n([\s\S]*?)\n?```$/);
|
|
2388
|
+
if (fenced) t = fenced[1].trim();
|
|
2389
|
+
return t.replace(/^\[\d{4}-\d{2}-\d{2}[^\]\n]*\][ \t]*\n/, "").trim();
|
|
2390
|
+
}
|
|
2391
|
+
/**
|
|
2285
2392
|
* Parse one AG2 message: first non-empty line is the kind (T R S Q A X,
|
|
2286
2393
|
* optionally followed by trailing text — only the first character is the
|
|
2287
2394
|
* kind), later lines are `key=value` or `@n=path` symbol declarations.
|
|
@@ -2297,7 +2404,7 @@ function parseAg2Report(text) {
|
|
|
2297
2404
|
"A",
|
|
2298
2405
|
"X"
|
|
2299
2406
|
]);
|
|
2300
|
-
const lines = (text
|
|
2407
|
+
const lines = unwrapAg2(text).split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("```"));
|
|
2301
2408
|
if (!lines.length) return null;
|
|
2302
2409
|
const kind = lines[0][0];
|
|
2303
2410
|
if (!kinds.has(kind)) return null;
|
|
@@ -2341,11 +2448,17 @@ function ag2ToWorkerReport(parsed) {
|
|
|
2341
2448
|
summary: entry.slice(cut + 1).trim()
|
|
2342
2449
|
};
|
|
2343
2450
|
});
|
|
2344
|
-
if (f.t)
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2451
|
+
if (f.t) {
|
|
2452
|
+
const tokens = f.t.split(/\s+/).filter(Boolean);
|
|
2453
|
+
out.checks = tokens.length > 0 && tokens.every((tok) => /^\S+[+\-~?!]$/.test(tok)) ? tokens.map((entry) => ({
|
|
2454
|
+
name: entry.slice(0, -1),
|
|
2455
|
+
ok: passed(entry),
|
|
2456
|
+
detail: entry.slice(-1)
|
|
2457
|
+
})) : [{
|
|
2458
|
+
name: "tests",
|
|
2459
|
+
detail: f.t
|
|
2460
|
+
}];
|
|
2461
|
+
}
|
|
2349
2462
|
if (f.p) out.commands = f.p.split("|").map((s) => s.trim()).filter(Boolean);
|
|
2350
2463
|
const open = [];
|
|
2351
2464
|
if (f.x) open.push(f.x);
|
|
@@ -2371,7 +2484,7 @@ function validateAg2(text) {
|
|
|
2371
2484
|
"-",
|
|
2372
2485
|
"--json"
|
|
2373
2486
|
], {
|
|
2374
|
-
input: text,
|
|
2487
|
+
input: unwrapAg2(text),
|
|
2375
2488
|
timeout: 5e3,
|
|
2376
2489
|
stdio: [
|
|
2377
2490
|
"pipe",
|
|
@@ -2599,7 +2712,7 @@ function renderReport(c, prefix, r, cwd = "") {
|
|
|
2599
2712
|
if (has(r.checks)) {
|
|
2600
2713
|
out.push(`${prefix}${c("bold", "checks")}`);
|
|
2601
2714
|
for (const ck of r.checks) {
|
|
2602
|
-
const mark = ck.ok === false ? c("red", "✗") : c("green", "✓");
|
|
2715
|
+
const mark = ck.ok === false ? c("red", "✗") : ck.ok === true ? c("green", "✓") : c("dim", "·");
|
|
2603
2716
|
const detail = ck.detail ? c("dim", ` · ${shortText(ck.detail, 80)}`) : "";
|
|
2604
2717
|
out.push(`${prefix} ${mark} ${ck.name ?? "?"}${detail}`);
|
|
2605
2718
|
}
|
|
@@ -3011,16 +3124,22 @@ function toolResultFailed(block) {
|
|
|
3011
3124
|
const m = toolResultText(block.content).match(/Exit code (\d+)/);
|
|
3012
3125
|
return m !== null && Number(m[1]) !== 0;
|
|
3013
3126
|
}
|
|
3127
|
+
/** CLI aliases the built-in provider hands to `--model` (NATIVE_ANTHROPIC_MODELS'
|
|
3128
|
+
* values): a bare name like "sonnet", not a concrete id, so the init event's
|
|
3129
|
+
* resolved id is always the more useful thing to display. */
|
|
3130
|
+
const NATIVE_MODEL_ALIASES = new Set(Object.values(NATIVE_ANTHROPIC_MODELS));
|
|
3014
3131
|
/**
|
|
3015
3132
|
* The model the init event announces, adopted into the status when the spawn
|
|
3016
3133
|
* could not name one (a caller that passed `--model` itself in the claude
|
|
3017
|
-
* args, or a provider whose table has no entry for the capability)
|
|
3018
|
-
*
|
|
3019
|
-
*
|
|
3134
|
+
* args, or a provider whose table has no entry for the capability) or named
|
|
3135
|
+
* only a CLI alias (the built-in provider's "sonnet"/"haiku", which tracks
|
|
3136
|
+
* whatever release is current — the init event says which one actually ran).
|
|
3137
|
+
* The run's real model is then only knowable from the first event it sends.
|
|
3138
|
+
* Never overwrites a concrete resolved or pinned model — that stays the
|
|
3020
3139
|
* recorded truth.
|
|
3021
3140
|
*/
|
|
3022
3141
|
function adoptInitModel(status, e) {
|
|
3023
|
-
if (status.model) return;
|
|
3142
|
+
if (status.model && !NATIVE_MODEL_ALIASES.has(status.model)) return;
|
|
3024
3143
|
const m = (e.model ?? "").trim();
|
|
3025
3144
|
if (m) status.model = m;
|
|
3026
3145
|
}
|
|
@@ -3115,7 +3234,7 @@ async function runWorker(opts) {
|
|
|
3115
3234
|
const logDir = workersLogDir(config);
|
|
3116
3235
|
mkdirSync(logDir, { recursive: true });
|
|
3117
3236
|
if (opts.className === "plan" && !opts._planner) {
|
|
3118
|
-
const { runPlanner } = await import("./planner-
|
|
3237
|
+
const { runPlanner } = await import("./planner-D8jAr_sx.mjs");
|
|
3119
3238
|
return runPlanner(opts);
|
|
3120
3239
|
}
|
|
3121
3240
|
const parent = launchParent(opts.parent);
|
|
@@ -3319,6 +3438,64 @@ function interactiveMcpTools(explicitMcp, callerTools, projectLaunch) {
|
|
|
3319
3438
|
tools: !callerTools && projectLaunch?.tools?.length ? projectLaunch.tools : []
|
|
3320
3439
|
};
|
|
3321
3440
|
}
|
|
3441
|
+
/**
|
|
3442
|
+
* The finalisation every engine shares: orphaned-children check, state, the
|
|
3443
|
+
* WORKER-END ledger line, worktree outcome, parent handoff, final rc. A worker
|
|
3444
|
+
* owns its children's results (the worker contract says so): if it
|
|
3445
|
+
* backgrounded a sub-worker and exited without waiting, the run must not
|
|
3446
|
+
* report success, whatever the process returned.
|
|
3447
|
+
*/
|
|
3448
|
+
async function finaliseRun(f) {
|
|
3449
|
+
const { logDir, ledger, ok, rc } = f;
|
|
3450
|
+
let { status, report } = f;
|
|
3451
|
+
const wid = status.id;
|
|
3452
|
+
const orphanReason = checkOrphanedChildren(logDir, wid);
|
|
3453
|
+
const succeeded = ok && !orphanReason;
|
|
3454
|
+
status.state = succeeded ? "done" : "failed";
|
|
3455
|
+
status.rc = rc;
|
|
3456
|
+
status.secs = f.secs;
|
|
3457
|
+
if (orphanReason) {
|
|
3458
|
+
status.last = shortText(orphanReason, 90);
|
|
3459
|
+
report = {
|
|
3460
|
+
...report ?? {},
|
|
3461
|
+
notes: orphanReason,
|
|
3462
|
+
result: "-"
|
|
3463
|
+
};
|
|
3464
|
+
appendLedger(ledger, "WORKER-ORPHAN-CHILDREN", {
|
|
3465
|
+
id: wid,
|
|
3466
|
+
reason: orphanReason
|
|
3467
|
+
});
|
|
3468
|
+
}
|
|
3469
|
+
saveStatus(logDir, status);
|
|
3470
|
+
appendLedger(ledger, "WORKER-END", {
|
|
3471
|
+
id: wid,
|
|
3472
|
+
...f.end,
|
|
3473
|
+
rc,
|
|
3474
|
+
secs: f.secs
|
|
3475
|
+
});
|
|
3476
|
+
if (f.worktree) status = recordWorktree(logDir, status, f.worktree, ok);
|
|
3477
|
+
const early = await f.beforeHandoff?.(status, report);
|
|
3478
|
+
if (typeof early === "number") return early;
|
|
3479
|
+
const finalRc = rc !== 0 ? rc : succeeded ? 0 : 1;
|
|
3480
|
+
if (status.parent && isWorkerId(logDir, status.parent)) try {
|
|
3481
|
+
await deliverHandoff(logDir, {
|
|
3482
|
+
from: wid,
|
|
3483
|
+
to: status.parent,
|
|
3484
|
+
kind: "result",
|
|
3485
|
+
text: shortText(report?.notes ?? f.fallbackText ?? (succeeded ? "done" : "failed"), 400),
|
|
3486
|
+
data: {
|
|
3487
|
+
rc: finalRc,
|
|
3488
|
+
ok: succeeded,
|
|
3489
|
+
...status.branch ? {
|
|
3490
|
+
branch: status.branch,
|
|
3491
|
+
commits: status.commits ?? 0
|
|
3492
|
+
} : {},
|
|
3493
|
+
...report ? { report } : {}
|
|
3494
|
+
}
|
|
3495
|
+
});
|
|
3496
|
+
} catch {}
|
|
3497
|
+
return finalRc;
|
|
3498
|
+
}
|
|
3322
3499
|
async function executeImageRun(a) {
|
|
3323
3500
|
const { logDir, target, model, label, parsed } = a;
|
|
3324
3501
|
if (!parsed.headless || parsed.prompt === null) throw new Error(`provider "${target.providerName}" (engine image) supports headless runs only: pass the task with -p '<prompt>'`);
|
|
@@ -3365,6 +3542,14 @@ async function executeImageRun(a) {
|
|
|
3365
3542
|
capability: a.capability,
|
|
3366
3543
|
...a.specPath ? { spec: a.specPath } : {}
|
|
3367
3544
|
});
|
|
3545
|
+
const imageEnd = {
|
|
3546
|
+
provider: target.providerName,
|
|
3547
|
+
mode: "headless",
|
|
3548
|
+
engine: "image",
|
|
3549
|
+
model,
|
|
3550
|
+
label,
|
|
3551
|
+
capability: a.capability
|
|
3552
|
+
};
|
|
3368
3553
|
const t0 = Date.now();
|
|
3369
3554
|
try {
|
|
3370
3555
|
const result = await runImageCapability({
|
|
@@ -3377,46 +3562,61 @@ async function executeImageRun(a) {
|
|
|
3377
3562
|
timeoutMs: a.timeoutMs
|
|
3378
3563
|
});
|
|
3379
3564
|
const secs = Math.round((Date.now() - t0) / 1e3);
|
|
3380
|
-
status.state = "done";
|
|
3381
|
-
status.rc = 0;
|
|
3382
|
-
status.secs = secs;
|
|
3383
3565
|
status.last = `wrote ${result.path}`;
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
engine: "image",
|
|
3390
|
-
model,
|
|
3566
|
+
return await finaliseRun({
|
|
3567
|
+
logDir,
|
|
3568
|
+
ledger,
|
|
3569
|
+
status,
|
|
3570
|
+
ok: true,
|
|
3391
3571
|
rc: 0,
|
|
3392
3572
|
secs,
|
|
3393
|
-
|
|
3394
|
-
|
|
3573
|
+
end: imageEnd,
|
|
3574
|
+
report: null,
|
|
3575
|
+
beforeHandoff: () => {
|
|
3576
|
+
if (!a.quiet) process.stdout.write(JSON.stringify(result) + "\n");
|
|
3577
|
+
}
|
|
3395
3578
|
});
|
|
3396
|
-
if (!a.quiet) process.stdout.write(JSON.stringify(result) + "\n");
|
|
3397
|
-
return 0;
|
|
3398
3579
|
} catch (e) {
|
|
3399
3580
|
const secs = Math.round((Date.now() - t0) / 1e3);
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
appendLedger(ledger, "WORKER-END", {
|
|
3407
|
-
id: wid,
|
|
3408
|
-
provider: target.providerName,
|
|
3409
|
-
mode: "headless",
|
|
3410
|
-
engine: "image",
|
|
3411
|
-
model,
|
|
3581
|
+
status.last = e instanceof Error ? e.message : String(e);
|
|
3582
|
+
await finaliseRun({
|
|
3583
|
+
logDir,
|
|
3584
|
+
ledger,
|
|
3585
|
+
status,
|
|
3586
|
+
ok: false,
|
|
3412
3587
|
rc: 1,
|
|
3413
3588
|
secs,
|
|
3414
|
-
|
|
3415
|
-
|
|
3589
|
+
end: imageEnd,
|
|
3590
|
+
report: null
|
|
3416
3591
|
});
|
|
3417
3592
|
throw e;
|
|
3418
3593
|
}
|
|
3419
3594
|
}
|
|
3595
|
+
/**
|
|
3596
|
+
* Follow pane, made observable on stderr (stdout stays pure JSON for
|
|
3597
|
+
* `--output-format json`): one line naming the outcome — opened, skipped
|
|
3598
|
+
* (with reason), or failed (with reason, alongside the existing PANE-FAIL
|
|
3599
|
+
* ledger line). Fire-and-forget, never blocks the worker.
|
|
3600
|
+
*/
|
|
3601
|
+
async function announcePane(logDir, config, wid, term, noPane, ledger) {
|
|
3602
|
+
const skip = !noPane ? !config.pane.enabled ? "workers.pane.enabled is false" : process.env.PAI_WORKER_AUTOPANE === "0" ? "PAI_WORKER_AUTOPANE=0" : !term ? "not in iTerm2 (no ITERM_SESSION_ID)" : null : "--no-pane";
|
|
3603
|
+
if (skip) {
|
|
3604
|
+
process.stderr.write(`[pai worker] no pane for ${wid}: ${skip}\n`);
|
|
3605
|
+
return;
|
|
3606
|
+
}
|
|
3607
|
+
try {
|
|
3608
|
+
const r = await openPaneForWorker(logDir, config, wid, term);
|
|
3609
|
+
const suffix = r.session ? ` (iTerm session ${r.session})` : "";
|
|
3610
|
+
process.stderr.write(`[pai worker] pane opened for ${wid}${suffix}\n`);
|
|
3611
|
+
} catch (e) {
|
|
3612
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
3613
|
+
process.stderr.write(`[pai worker] no pane for ${wid}: ${message.slice(0, 200)}\n`);
|
|
3614
|
+
appendLedger(ledger, "PANE-FAIL", {
|
|
3615
|
+
id: wid,
|
|
3616
|
+
error: message.slice(0, 200)
|
|
3617
|
+
});
|
|
3618
|
+
}
|
|
3619
|
+
}
|
|
3420
3620
|
async function executeRun(a) {
|
|
3421
3621
|
const { config, logDir, target, model, label, parsed, noPane } = a;
|
|
3422
3622
|
const headless = parsed.headless;
|
|
@@ -3548,12 +3748,7 @@ async function executeRun(a) {
|
|
|
3548
3748
|
...a.capability ? { capability: a.capability } : {},
|
|
3549
3749
|
...a.specPath ? { spec: a.specPath } : {}
|
|
3550
3750
|
});
|
|
3551
|
-
if (headless
|
|
3552
|
-
appendLedger(ledger, "PANE-FAIL", {
|
|
3553
|
-
id: wid,
|
|
3554
|
-
error: (e instanceof Error ? e.message : String(e)).slice(0, 200)
|
|
3555
|
-
});
|
|
3556
|
-
});
|
|
3751
|
+
if (headless) announcePane(logDir, config, wid, term, noPane, ledger);
|
|
3557
3752
|
const t0 = Date.now();
|
|
3558
3753
|
const proc = spawn(cmd[0], cmd.slice(1), {
|
|
3559
3754
|
env,
|
|
@@ -3706,9 +3901,6 @@ async function executeRun(a) {
|
|
|
3706
3901
|
const secs = Math.floor((Date.now() - t0) / 1e3);
|
|
3707
3902
|
const resultEvent = ctx.resultEvent;
|
|
3708
3903
|
const ok = runSucceeded(headless, rc, resultEvent);
|
|
3709
|
-
status.state = ok ? "done" : "failed";
|
|
3710
|
-
status.rc = rc;
|
|
3711
|
-
status.secs = secs;
|
|
3712
3904
|
if (resultEvent) status.last = shortText(resultEvent.result ?? "", 90);
|
|
3713
3905
|
if (ctx.resultReport?.notes) status.last = shortText(ctx.resultReport.notes, 90);
|
|
3714
3906
|
if (headless && a.reportFormat === "ag2" && resultEvent?.result) {
|
|
@@ -3760,66 +3952,55 @@ async function executeRun(a) {
|
|
|
3760
3952
|
});
|
|
3761
3953
|
}
|
|
3762
3954
|
}
|
|
3763
|
-
|
|
3764
|
-
|
|
3765
|
-
|
|
3766
|
-
|
|
3767
|
-
|
|
3768
|
-
model,
|
|
3955
|
+
return finaliseRun({
|
|
3956
|
+
logDir,
|
|
3957
|
+
ledger,
|
|
3958
|
+
status,
|
|
3959
|
+
ok,
|
|
3769
3960
|
rc,
|
|
3770
3961
|
secs,
|
|
3771
|
-
|
|
3772
|
-
|
|
3773
|
-
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
|
|
3777
|
-
|
|
3778
|
-
|
|
3779
|
-
|
|
3780
|
-
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
|
|
3788
|
-
|
|
3789
|
-
|
|
3790
|
-
|
|
3791
|
-
|
|
3792
|
-
|
|
3793
|
-
|
|
3794
|
-
|
|
3795
|
-
|
|
3796
|
-
|
|
3797
|
-
|
|
3798
|
-
|
|
3799
|
-
|
|
3800
|
-
|
|
3801
|
-
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
|
|
3806
|
-
|
|
3807
|
-
|
|
3808
|
-
|
|
3809
|
-
|
|
3810
|
-
text: shortText(ctx.resultReport?.notes ?? resultEvent?.result ?? (ok ? "done" : "failed"), 400),
|
|
3811
|
-
data: {
|
|
3812
|
-
rc: finalRc,
|
|
3813
|
-
ok,
|
|
3814
|
-
...status.branch ? {
|
|
3815
|
-
branch: status.branch,
|
|
3816
|
-
commits: status.commits ?? 0
|
|
3817
|
-
} : {},
|
|
3818
|
-
...ctx.resultReport ? { report: ctx.resultReport } : {}
|
|
3962
|
+
end: {
|
|
3963
|
+
provider: target.providerName,
|
|
3964
|
+
mode: headless ? "headless" : "interactive",
|
|
3965
|
+
model,
|
|
3966
|
+
turns: status.turns,
|
|
3967
|
+
tools: status.tools,
|
|
3968
|
+
label
|
|
3969
|
+
},
|
|
3970
|
+
report: ctx.resultReport,
|
|
3971
|
+
fallbackText: resultEvent?.result,
|
|
3972
|
+
worktree,
|
|
3973
|
+
beforeHandoff: async (st, rep) => {
|
|
3974
|
+
if (headless && !a.quiet) printResult(parsed.outputFormat, resultEvent, rc, logDir, wid, rep, worktreeExtras(st));
|
|
3975
|
+
const resultText = resultEvent?.result ?? "";
|
|
3976
|
+
if (!ok && headless && a.target.via === "auto" && config.routing.retryOnQuota && status.turns <= 1 && status.tools === 0 && isQuotaFailure(resultText)) {
|
|
3977
|
+
setCooldown(logDir, target.providerName, config.routing.cooldownMinutes);
|
|
3978
|
+
const next = nextAutoProvider(config, logDir, target.providerName);
|
|
3979
|
+
if (next && a.reroutes < config.routing.order.length) {
|
|
3980
|
+
appendLedger(ledger, "WORKER-REROUTE", {
|
|
3981
|
+
from: target.providerName,
|
|
3982
|
+
to: next,
|
|
3983
|
+
reason: "quota"
|
|
3984
|
+
});
|
|
3985
|
+
return runWorker({
|
|
3986
|
+
providerFlag: next,
|
|
3987
|
+
label,
|
|
3988
|
+
noPane: a.noPane,
|
|
3989
|
+
mcpFlag: a.mcpFlag,
|
|
3990
|
+
cwd: a.cwd,
|
|
3991
|
+
specPath: a.specPath,
|
|
3992
|
+
parent: a.parent,
|
|
3993
|
+
stage: a.stage,
|
|
3994
|
+
claudeArgs: a.claudeArgs,
|
|
3995
|
+
onWorkerStart: a.onWorkerStart,
|
|
3996
|
+
worktreeFlag: a.worktreeFlag,
|
|
3997
|
+
className: a.className,
|
|
3998
|
+
_reroutes: a.reroutes + 1
|
|
3999
|
+
});
|
|
4000
|
+
}
|
|
3819
4001
|
}
|
|
3820
|
-
}
|
|
3821
|
-
}
|
|
3822
|
-
return finalRc;
|
|
4002
|
+
}
|
|
4003
|
+
});
|
|
3823
4004
|
}
|
|
3824
4005
|
/** The worktree fields printResult adds to a json payload, when there is one. */
|
|
3825
4006
|
function worktreeExtras(s) {
|
|
@@ -3944,12 +4125,7 @@ async function executeCodexRun(a) {
|
|
|
3944
4125
|
id: wid,
|
|
3945
4126
|
note: `dropped for codex: ${dropped.join(", ")}`
|
|
3946
4127
|
});
|
|
3947
|
-
|
|
3948
|
-
appendLedger(ledger, "PANE-FAIL", {
|
|
3949
|
-
id: wid,
|
|
3950
|
-
error: (e instanceof Error ? e.message : String(e)).slice(0, 200)
|
|
3951
|
-
});
|
|
3952
|
-
});
|
|
4128
|
+
announcePane(logDir, config, wid, term, noPane, ledger);
|
|
3953
4129
|
const t0 = Date.now();
|
|
3954
4130
|
const proc = spawn("codex", buildCodexArgs(prompt, parsed.callerModel ? void 0 : model), {
|
|
3955
4131
|
env,
|
|
@@ -4028,9 +4204,6 @@ async function executeCodexRun(a) {
|
|
|
4028
4204
|
};
|
|
4029
4205
|
writeEvent(resultEvent);
|
|
4030
4206
|
const ok = rc === 0 && !fold.isError;
|
|
4031
|
-
status.state = ok ? "done" : "failed";
|
|
4032
|
-
status.rc = rc;
|
|
4033
|
-
status.secs = secs;
|
|
4034
4207
|
status.last = shortText(report?.notes ?? finalText, 90) || (ok ? "done" : "failed");
|
|
4035
4208
|
if (report?.changed?.length) {
|
|
4036
4209
|
const verify = verifyReportChanges(report.changed, worktree?.dir ?? cwd, t0);
|
|
@@ -4046,40 +4219,29 @@ async function executeCodexRun(a) {
|
|
|
4046
4219
|
});
|
|
4047
4220
|
}
|
|
4048
4221
|
}
|
|
4049
|
-
|
|
4050
|
-
|
|
4051
|
-
|
|
4052
|
-
|
|
4053
|
-
|
|
4054
|
-
engine: "codex",
|
|
4055
|
-
model,
|
|
4222
|
+
return finaliseRun({
|
|
4223
|
+
logDir,
|
|
4224
|
+
ledger,
|
|
4225
|
+
status,
|
|
4226
|
+
ok,
|
|
4056
4227
|
rc,
|
|
4057
4228
|
secs,
|
|
4058
|
-
|
|
4059
|
-
|
|
4060
|
-
|
|
4229
|
+
end: {
|
|
4230
|
+
provider: target.providerName,
|
|
4231
|
+
mode: "headless",
|
|
4232
|
+
engine: "codex",
|
|
4233
|
+
model,
|
|
4234
|
+
turns: status.turns,
|
|
4235
|
+
tools: status.tools,
|
|
4236
|
+
label
|
|
4237
|
+
},
|
|
4238
|
+
report,
|
|
4239
|
+
fallbackText: finalText,
|
|
4240
|
+
worktree,
|
|
4241
|
+
beforeHandoff: (st, rep) => {
|
|
4242
|
+
if (!a.quiet) printResult(parsed.outputFormat, resultEvent, rc, logDir, wid, rep, worktreeExtras(st));
|
|
4243
|
+
}
|
|
4061
4244
|
});
|
|
4062
|
-
if (worktree) status = recordWorktree(logDir, status, worktree, ok);
|
|
4063
|
-
if (!a.quiet) printResult(parsed.outputFormat, resultEvent, rc, logDir, wid, report, worktreeExtras(status));
|
|
4064
|
-
const finalRc = rc !== 0 ? rc : ok ? 0 : 1;
|
|
4065
|
-
if (status.parent && isWorkerId(logDir, status.parent)) try {
|
|
4066
|
-
await deliverHandoff(logDir, {
|
|
4067
|
-
from: wid,
|
|
4068
|
-
to: status.parent,
|
|
4069
|
-
kind: "result",
|
|
4070
|
-
text: shortText(report?.notes ?? finalText ?? (ok ? "done" : "failed"), 400),
|
|
4071
|
-
data: {
|
|
4072
|
-
rc: finalRc,
|
|
4073
|
-
ok,
|
|
4074
|
-
...status.branch ? {
|
|
4075
|
-
branch: status.branch,
|
|
4076
|
-
commits: status.commits ?? 0
|
|
4077
|
-
} : {},
|
|
4078
|
-
...report ? { report } : {}
|
|
4079
|
-
}
|
|
4080
|
-
});
|
|
4081
|
-
} catch {}
|
|
4082
|
-
return finalRc;
|
|
4083
4245
|
}
|
|
4084
4246
|
function printResult(fmt, resultEvent, rc, logDir, wid, report, extras) {
|
|
4085
4247
|
if (fmt === "stream-json") return;
|
|
@@ -4213,4 +4375,4 @@ function resultFromOutput(out) {
|
|
|
4213
4375
|
|
|
4214
4376
|
//#endregion
|
|
4215
4377
|
export { UNLABELED as A, newWorkerId as B, workerInScope as C, worktreesDir as D, mergeWorker as E, elapsedOf as F, waitForTerminalStatus as G, ownsPid as H, isChatPane as I, shortText as J, longInlinePromptHint as K, isLive as L, alive as M, contextLabel as N, appendLedger as O, contextPercent as P, loadStatus as R, sessionTag as S, git as T, saveStatus as U, nowStamp as V, setWorkerLabel as W, expandMcpNames as X, describeMcp as Y, currentTabKey as _, projectLaunchConfig as a, resolveSession as b, handoffFromInside as c, workerDepth as d, checkPaneForWorker as f, markControlsHeld as g, clickrControlsArgv as h, usageContextTokens as i, ageOf as j, ledgerSummary as k, readInbox as l, openPaneForWorker as m, runWorker as n, parseWorkerReport as o, openFollowPane as p, parseRunnerArgs as q, testProvider as r, renderReport as s, printResult as t, sayToWorker as u, itermForClaudeSession as v, discardWorker as w, sessionMapPath as x, itermUuid as y, loadStatuses as z };
|
|
4216
|
-
//# sourceMappingURL=run-
|
|
4378
|
+
//# sourceMappingURL=run-CxxZKEZw.mjs.map
|