@tekmidian/pai 0.60.1 → 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-CGyAIHo4.mjs → chain-C5oeyUg4.mjs} +4 -4
- package/dist/{chain-CGyAIHo4.mjs.map → chain-C5oeyUg4.mjs.map} +1 -1
- package/dist/cli/index.mjs +9 -9
- package/dist/cli/program.mjs +9 -9
- package/dist/{context-handover-cache-BzM7Qudn.mjs → context-handover-cache-BdtJZpgv.mjs} +3 -3
- package/dist/{context-handover-cache-BzM7Qudn.mjs.map → context-handover-cache-BdtJZpgv.mjs.map} +1 -1
- package/dist/daemon/index.mjs +7 -7
- package/dist/{daemon-B_TodsIS.mjs → daemon-DSsIEqzW.mjs} +20 -13
- package/dist/{daemon-B_TodsIS.mjs.map → daemon-DSsIEqzW.mjs.map} +1 -1
- package/dist/{daemon-jviL3VVJ.mjs → daemon-MoFF4oeg.mjs} +7 -7
- package/dist/daemon-mcp/index.mjs +7 -9
- package/dist/daemon-mcp/index.mjs.map +1 -1
- package/dist/{fallback-CjdakQVu.mjs → fallback-DDbJVaR8.mjs} +11 -13
- package/dist/{fallback-CjdakQVu.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 +3 -3
- package/dist/hooks/route-agents-to-worker.mjs.map +2 -2
- package/dist/hooks/security-validator.mjs +58 -58
- 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/worker-proxy.mjs +3 -3
- package/dist/hooks/worker-proxy.mjs.map +2 -2
- package/dist/hooks/worker-status-line.mjs +3 -3
- package/dist/hooks/worker-status-line.mjs.map +2 -2
- package/dist/hooks/worker-supervision.mjs +3 -3
- package/dist/hooks/worker-supervision.mjs.map +2 -2
- package/dist/{main-resolver-VMBENifT.mjs → main-resolver-CxOsxtOr.mjs} +2 -2
- package/dist/{main-resolver-BFQfU5xo.mjs → main-resolver-DIQ6m_RA.mjs} +2 -2
- package/dist/{main-resolver-BFQfU5xo.mjs.map → main-resolver-DIQ6m_RA.mjs.map} +1 -1
- package/dist/{planner-DN967Lvm.mjs → planner-D8jAr_sx.mjs} +5 -5
- package/dist/{planner-DN967Lvm.mjs.map → planner-D8jAr_sx.mjs.map} +1 -1
- package/dist/{program-BnsjB57Q.mjs → program-BTdspOOa.mjs} +102 -52
- package/dist/program-BTdspOOa.mjs.map +1 -0
- package/dist/{run-FeM1_UVa.mjs → run-CxxZKEZw.mjs} +333 -172
- package/dist/run-CxxZKEZw.mjs.map +1 -0
- package/dist/{run-env-CEHTeIUM.mjs → run-env-BE5xyCwy.mjs} +25 -6
- package/dist/run-env-BE5xyCwy.mjs.map +1 -0
- package/dist/{server-CekGOJcp.mjs → server-BY6AedmC.mjs} +2 -2
- package/dist/{server-CekGOJcp.mjs.map → server-BY6AedmC.mjs.map} +1 -1
- package/dist/{session-keepalive-Bc9aT678.mjs → session-keepalive-urk--pfa.mjs} +4 -4
- package/dist/{session-keepalive-Bc9aT678.mjs.map → session-keepalive-urk--pfa.mjs.map} +1 -1
- package/dist/{work-queue-worker-DVOVcEnO.mjs → work-queue-worker-1_VBfI_k.mjs} +4 -4
- package/dist/{work-queue-worker-BL4dq5P7.mjs → work-queue-worker-DUvPiwGO.mjs} +2 -2
- package/dist/{work-queue-worker-BL4dq5P7.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/program-BnsjB57Q.mjs.map +0 -1
- package/dist/run-FeM1_UVa.mjs.map +0 -1
- package/dist/run-env-CEHTeIUM.mjs.map +0 -1
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { i as getRegistryBackend } from "./factory-EUUhSSoq.mjs";
|
|
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";
|
|
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 });
|
|
@@ -844,18 +845,58 @@ function uncommittedPaths(wtDir) {
|
|
|
844
845
|
return [...tracked, ...untracked];
|
|
845
846
|
}
|
|
846
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
|
+
/**
|
|
847
871
|
* Commit a worktree's uncommitted changes to its branch so the merge carries
|
|
848
872
|
* them. `git merge` only moves committed work, so a worker that stopped
|
|
849
873
|
* without committing would lose its edits to `worktree remove` — exactly
|
|
850
|
-
* what happened live on 2026-09-17. Returns the salvaged paths,
|
|
851
|
-
* 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:
|
|
852
878
|
* its edits are still on disk, so nothing is lost.
|
|
853
879
|
*/
|
|
854
880
|
function salvageUncommitted(wtDir, label) {
|
|
855
881
|
const paths = uncommittedPaths(wtDir);
|
|
856
|
-
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
|
+
};
|
|
857
894
|
try {
|
|
858
|
-
git(wtDir, [
|
|
895
|
+
git(wtDir, [
|
|
896
|
+
"add",
|
|
897
|
+
"--",
|
|
898
|
+
...toStage
|
|
899
|
+
]);
|
|
859
900
|
git(wtDir, [
|
|
860
901
|
"commit",
|
|
861
902
|
"-m",
|
|
@@ -864,7 +905,10 @@ function salvageUncommitted(wtDir, label) {
|
|
|
864
905
|
} catch (e) {
|
|
865
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`);
|
|
866
907
|
}
|
|
867
|
-
return
|
|
908
|
+
return {
|
|
909
|
+
committed: toStage,
|
|
910
|
+
skipped
|
|
911
|
+
};
|
|
868
912
|
}
|
|
869
913
|
/**
|
|
870
914
|
* The dirty paths of a checkout, parsed from `git status --porcelain -z`:
|
|
@@ -915,9 +959,14 @@ function assertNoDirtyOverlap(cwd, incoming, id, branch) {
|
|
|
915
959
|
if (!overlap.length) return;
|
|
916
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.`);
|
|
917
961
|
}
|
|
918
|
-
/**
|
|
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
|
+
*/
|
|
919
968
|
function assertWorktreeClean(wtDir, id) {
|
|
920
|
-
const leftover = uncommittedPaths(wtDir);
|
|
969
|
+
const leftover = uncommittedPaths(wtDir).filter((p) => !symlinkEscapesWorktree(wtDir, p));
|
|
921
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`);
|
|
922
971
|
}
|
|
923
972
|
/** Blob sha of `path` at `rev` in `cwd`, or null when it does not exist there. */
|
|
@@ -971,7 +1020,10 @@ function mergeSnapshotWorker(logDir, id, st) {
|
|
|
971
1020
|
const snapshot = st.worktreeBase;
|
|
972
1021
|
const branch = st.branch;
|
|
973
1022
|
const worktreeDir = st.worktreeDir;
|
|
974
|
-
const
|
|
1023
|
+
const salvage = existsSync(worktreeDir) ? salvageUncommitted(worktreeDir, st.label || UNLABELED) : {
|
|
1024
|
+
committed: [],
|
|
1025
|
+
skipped: []
|
|
1026
|
+
};
|
|
975
1027
|
if ((parseInt(git(st.cwd, [
|
|
976
1028
|
"rev-list",
|
|
977
1029
|
"--count",
|
|
@@ -1030,7 +1082,10 @@ function mergeSnapshotWorker(logDir, id, st) {
|
|
|
1030
1082
|
merged: true
|
|
1031
1083
|
});
|
|
1032
1084
|
const base = `applied worker ${id}'s changes (branch ${branch}) to ${st.cwd} as uncommitted changes: ${changedPaths.join(", ")} (worktree removed, branch deleted)`;
|
|
1033
|
-
|
|
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;
|
|
1034
1089
|
}
|
|
1035
1090
|
/**
|
|
1036
1091
|
* `pai worker merge <id>`: salvage whatever the worker left uncommitted onto
|
|
@@ -1045,7 +1100,10 @@ function mergeWorker(logDir, id) {
|
|
|
1045
1100
|
const st = mustHaveBranch(logDir, id);
|
|
1046
1101
|
if (st.merged) return `worker ${id}: branch ${st.branch} already merged`;
|
|
1047
1102
|
if (st.worktreeSnapshot) return mergeSnapshotWorker(logDir, id, st);
|
|
1048
|
-
const
|
|
1103
|
+
const salvage = existsSync(st.worktreeDir) ? salvageUncommitted(st.worktreeDir, st.label || UNLABELED) : {
|
|
1104
|
+
committed: [],
|
|
1105
|
+
skipped: []
|
|
1106
|
+
};
|
|
1049
1107
|
if ((parseInt(git(st.cwd, [
|
|
1050
1108
|
"rev-list",
|
|
1051
1109
|
"--count",
|
|
@@ -1075,7 +1133,7 @@ function mergeWorker(logDir, id) {
|
|
|
1075
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`);
|
|
1076
1134
|
}
|
|
1077
1135
|
if (existsSync(st.worktreeDir)) assertWorktreeClean(st.worktreeDir, id);
|
|
1078
|
-
removeWorktree(st.cwd, st.worktreeDir,
|
|
1136
|
+
removeWorktree(st.cwd, st.worktreeDir, true);
|
|
1079
1137
|
let branchGone = true;
|
|
1080
1138
|
try {
|
|
1081
1139
|
git(st.cwd, [
|
|
@@ -1091,7 +1149,10 @@ function mergeWorker(logDir, id) {
|
|
|
1091
1149
|
merged: true
|
|
1092
1150
|
});
|
|
1093
1151
|
const base = `merged ${st.branch} into ${st.cwd} (worktree removed${branchGone ? ", branch deleted" : "; branch kept: git refused -d"})`;
|
|
1094
|
-
|
|
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;
|
|
1095
1156
|
}
|
|
1096
1157
|
/** `pai worker discard <id>`: drop worktree and branch, keep nothing. */
|
|
1097
1158
|
function discardWorker(logDir, id) {
|
|
@@ -1173,9 +1234,10 @@ function inPlaceSystemPrompt() {
|
|
|
1173
1234
|
* If neither is available, viewers fall back to "all workers".
|
|
1174
1235
|
*
|
|
1175
1236
|
* A third case: workers spawned from a Claude Code Bash tool (the
|
|
1176
|
-
* orchestrator pattern)
|
|
1177
|
-
*
|
|
1178
|
-
*
|
|
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
|
|
1179
1241
|
* session map (see below), so their tab still claims them.
|
|
1180
1242
|
*/
|
|
1181
1243
|
const AIBROKER_REGISTRY = join(homedir(), ".aibroker", "session-names.json");
|
|
@@ -1897,7 +1959,10 @@ function absoluteCliPath() {
|
|
|
1897
1959
|
}
|
|
1898
1960
|
/** Open (or only report on) the stacked follow pane of one worker. */
|
|
1899
1961
|
async function openPaneForWorker(logDir, config, wid, term) {
|
|
1900
|
-
if (workerPaneOpen(wid)) return
|
|
1962
|
+
if (workerPaneOpen(wid)) return {
|
|
1963
|
+
message: `pane for ${wid} already open`,
|
|
1964
|
+
session: null
|
|
1965
|
+
};
|
|
1901
1966
|
const uid = itermUuid(term);
|
|
1902
1967
|
const regPath = join(panesDir(logDir), `${scopeKey(term)}.json`);
|
|
1903
1968
|
const reg = loadRegistry(regPath);
|
|
@@ -1921,7 +1986,10 @@ async function openPaneForWorker(logDir, config, wid, term) {
|
|
|
1921
1986
|
opened: (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19)
|
|
1922
1987
|
});
|
|
1923
1988
|
saveRegistry(regPath, pruned);
|
|
1924
|
-
return
|
|
1989
|
+
return {
|
|
1990
|
+
message: `pane opened for ${wid}`,
|
|
1991
|
+
session: out.slice(bar + 1)
|
|
1992
|
+
};
|
|
1925
1993
|
}
|
|
1926
1994
|
/**
|
|
1927
1995
|
* One `--check` line with the bounds of the window hosting `term`'s iTerm
|
|
@@ -2041,6 +2109,34 @@ function launchParent(explicit, env = process.env) {
|
|
|
2041
2109
|
function isWorkerId(logDir, id) {
|
|
2042
2110
|
return loadStatus(logDir, id) !== null;
|
|
2043
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
|
+
}
|
|
2044
2140
|
|
|
2045
2141
|
//#endregion
|
|
2046
2142
|
//#region src/workers/operator.ts
|
|
@@ -2283,6 +2379,16 @@ function ag2Spec() {
|
|
|
2283
2379
|
return cachedSpec;
|
|
2284
2380
|
}
|
|
2285
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
|
+
/**
|
|
2286
2392
|
* Parse one AG2 message: first non-empty line is the kind (T R S Q A X,
|
|
2287
2393
|
* optionally followed by trailing text — only the first character is the
|
|
2288
2394
|
* kind), later lines are `key=value` or `@n=path` symbol declarations.
|
|
@@ -2298,7 +2404,7 @@ function parseAg2Report(text) {
|
|
|
2298
2404
|
"A",
|
|
2299
2405
|
"X"
|
|
2300
2406
|
]);
|
|
2301
|
-
const lines = (text
|
|
2407
|
+
const lines = unwrapAg2(text).split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("```"));
|
|
2302
2408
|
if (!lines.length) return null;
|
|
2303
2409
|
const kind = lines[0][0];
|
|
2304
2410
|
if (!kinds.has(kind)) return null;
|
|
@@ -2342,11 +2448,17 @@ function ag2ToWorkerReport(parsed) {
|
|
|
2342
2448
|
summary: entry.slice(cut + 1).trim()
|
|
2343
2449
|
};
|
|
2344
2450
|
});
|
|
2345
|
-
if (f.t)
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
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
|
+
}
|
|
2350
2462
|
if (f.p) out.commands = f.p.split("|").map((s) => s.trim()).filter(Boolean);
|
|
2351
2463
|
const open = [];
|
|
2352
2464
|
if (f.x) open.push(f.x);
|
|
@@ -2372,7 +2484,7 @@ function validateAg2(text) {
|
|
|
2372
2484
|
"-",
|
|
2373
2485
|
"--json"
|
|
2374
2486
|
], {
|
|
2375
|
-
input: text,
|
|
2487
|
+
input: unwrapAg2(text),
|
|
2376
2488
|
timeout: 5e3,
|
|
2377
2489
|
stdio: [
|
|
2378
2490
|
"pipe",
|
|
@@ -2600,7 +2712,7 @@ function renderReport(c, prefix, r, cwd = "") {
|
|
|
2600
2712
|
if (has(r.checks)) {
|
|
2601
2713
|
out.push(`${prefix}${c("bold", "checks")}`);
|
|
2602
2714
|
for (const ck of r.checks) {
|
|
2603
|
-
const mark = ck.ok === false ? c("red", "✗") : c("green", "✓");
|
|
2715
|
+
const mark = ck.ok === false ? c("red", "✗") : ck.ok === true ? c("green", "✓") : c("dim", "·");
|
|
2604
2716
|
const detail = ck.detail ? c("dim", ` · ${shortText(ck.detail, 80)}`) : "";
|
|
2605
2717
|
out.push(`${prefix} ${mark} ${ck.name ?? "?"}${detail}`);
|
|
2606
2718
|
}
|
|
@@ -3012,16 +3124,22 @@ function toolResultFailed(block) {
|
|
|
3012
3124
|
const m = toolResultText(block.content).match(/Exit code (\d+)/);
|
|
3013
3125
|
return m !== null && Number(m[1]) !== 0;
|
|
3014
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));
|
|
3015
3131
|
/**
|
|
3016
3132
|
* The model the init event announces, adopted into the status when the spawn
|
|
3017
3133
|
* could not name one (a caller that passed `--model` itself in the claude
|
|
3018
|
-
* args, or a provider whose table has no entry for the capability)
|
|
3019
|
-
*
|
|
3020
|
-
*
|
|
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
|
|
3021
3139
|
* recorded truth.
|
|
3022
3140
|
*/
|
|
3023
3141
|
function adoptInitModel(status, e) {
|
|
3024
|
-
if (status.model) return;
|
|
3142
|
+
if (status.model && !NATIVE_MODEL_ALIASES.has(status.model)) return;
|
|
3025
3143
|
const m = (e.model ?? "").trim();
|
|
3026
3144
|
if (m) status.model = m;
|
|
3027
3145
|
}
|
|
@@ -3116,7 +3234,7 @@ async function runWorker(opts) {
|
|
|
3116
3234
|
const logDir = workersLogDir(config);
|
|
3117
3235
|
mkdirSync(logDir, { recursive: true });
|
|
3118
3236
|
if (opts.className === "plan" && !opts._planner) {
|
|
3119
|
-
const { runPlanner } = await import("./planner-
|
|
3237
|
+
const { runPlanner } = await import("./planner-D8jAr_sx.mjs");
|
|
3120
3238
|
return runPlanner(opts);
|
|
3121
3239
|
}
|
|
3122
3240
|
const parent = launchParent(opts.parent);
|
|
@@ -3320,6 +3438,64 @@ function interactiveMcpTools(explicitMcp, callerTools, projectLaunch) {
|
|
|
3320
3438
|
tools: !callerTools && projectLaunch?.tools?.length ? projectLaunch.tools : []
|
|
3321
3439
|
};
|
|
3322
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
|
+
}
|
|
3323
3499
|
async function executeImageRun(a) {
|
|
3324
3500
|
const { logDir, target, model, label, parsed } = a;
|
|
3325
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>'`);
|
|
@@ -3366,6 +3542,14 @@ async function executeImageRun(a) {
|
|
|
3366
3542
|
capability: a.capability,
|
|
3367
3543
|
...a.specPath ? { spec: a.specPath } : {}
|
|
3368
3544
|
});
|
|
3545
|
+
const imageEnd = {
|
|
3546
|
+
provider: target.providerName,
|
|
3547
|
+
mode: "headless",
|
|
3548
|
+
engine: "image",
|
|
3549
|
+
model,
|
|
3550
|
+
label,
|
|
3551
|
+
capability: a.capability
|
|
3552
|
+
};
|
|
3369
3553
|
const t0 = Date.now();
|
|
3370
3554
|
try {
|
|
3371
3555
|
const result = await runImageCapability({
|
|
@@ -3378,46 +3562,61 @@ async function executeImageRun(a) {
|
|
|
3378
3562
|
timeoutMs: a.timeoutMs
|
|
3379
3563
|
});
|
|
3380
3564
|
const secs = Math.round((Date.now() - t0) / 1e3);
|
|
3381
|
-
status.state = "done";
|
|
3382
|
-
status.rc = 0;
|
|
3383
|
-
status.secs = secs;
|
|
3384
3565
|
status.last = `wrote ${result.path}`;
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
engine: "image",
|
|
3391
|
-
model,
|
|
3566
|
+
return await finaliseRun({
|
|
3567
|
+
logDir,
|
|
3568
|
+
ledger,
|
|
3569
|
+
status,
|
|
3570
|
+
ok: true,
|
|
3392
3571
|
rc: 0,
|
|
3393
3572
|
secs,
|
|
3394
|
-
|
|
3395
|
-
|
|
3573
|
+
end: imageEnd,
|
|
3574
|
+
report: null,
|
|
3575
|
+
beforeHandoff: () => {
|
|
3576
|
+
if (!a.quiet) process.stdout.write(JSON.stringify(result) + "\n");
|
|
3577
|
+
}
|
|
3396
3578
|
});
|
|
3397
|
-
if (!a.quiet) process.stdout.write(JSON.stringify(result) + "\n");
|
|
3398
|
-
return 0;
|
|
3399
3579
|
} catch (e) {
|
|
3400
3580
|
const secs = Math.round((Date.now() - t0) / 1e3);
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
appendLedger(ledger, "WORKER-END", {
|
|
3408
|
-
id: wid,
|
|
3409
|
-
provider: target.providerName,
|
|
3410
|
-
mode: "headless",
|
|
3411
|
-
engine: "image",
|
|
3412
|
-
model,
|
|
3581
|
+
status.last = e instanceof Error ? e.message : String(e);
|
|
3582
|
+
await finaliseRun({
|
|
3583
|
+
logDir,
|
|
3584
|
+
ledger,
|
|
3585
|
+
status,
|
|
3586
|
+
ok: false,
|
|
3413
3587
|
rc: 1,
|
|
3414
3588
|
secs,
|
|
3415
|
-
|
|
3416
|
-
|
|
3589
|
+
end: imageEnd,
|
|
3590
|
+
report: null
|
|
3417
3591
|
});
|
|
3418
3592
|
throw e;
|
|
3419
3593
|
}
|
|
3420
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
|
+
}
|
|
3421
3620
|
async function executeRun(a) {
|
|
3422
3621
|
const { config, logDir, target, model, label, parsed, noPane } = a;
|
|
3423
3622
|
const headless = parsed.headless;
|
|
@@ -3549,12 +3748,7 @@ async function executeRun(a) {
|
|
|
3549
3748
|
...a.capability ? { capability: a.capability } : {},
|
|
3550
3749
|
...a.specPath ? { spec: a.specPath } : {}
|
|
3551
3750
|
});
|
|
3552
|
-
if (headless
|
|
3553
|
-
appendLedger(ledger, "PANE-FAIL", {
|
|
3554
|
-
id: wid,
|
|
3555
|
-
error: (e instanceof Error ? e.message : String(e)).slice(0, 200)
|
|
3556
|
-
});
|
|
3557
|
-
});
|
|
3751
|
+
if (headless) announcePane(logDir, config, wid, term, noPane, ledger);
|
|
3558
3752
|
const t0 = Date.now();
|
|
3559
3753
|
const proc = spawn(cmd[0], cmd.slice(1), {
|
|
3560
3754
|
env,
|
|
@@ -3707,9 +3901,6 @@ async function executeRun(a) {
|
|
|
3707
3901
|
const secs = Math.floor((Date.now() - t0) / 1e3);
|
|
3708
3902
|
const resultEvent = ctx.resultEvent;
|
|
3709
3903
|
const ok = runSucceeded(headless, rc, resultEvent);
|
|
3710
|
-
status.state = ok ? "done" : "failed";
|
|
3711
|
-
status.rc = rc;
|
|
3712
|
-
status.secs = secs;
|
|
3713
3904
|
if (resultEvent) status.last = shortText(resultEvent.result ?? "", 90);
|
|
3714
3905
|
if (ctx.resultReport?.notes) status.last = shortText(ctx.resultReport.notes, 90);
|
|
3715
3906
|
if (headless && a.reportFormat === "ag2" && resultEvent?.result) {
|
|
@@ -3761,66 +3952,55 @@ async function executeRun(a) {
|
|
|
3761
3952
|
});
|
|
3762
3953
|
}
|
|
3763
3954
|
}
|
|
3764
|
-
|
|
3765
|
-
|
|
3766
|
-
|
|
3767
|
-
|
|
3768
|
-
|
|
3769
|
-
model,
|
|
3955
|
+
return finaliseRun({
|
|
3956
|
+
logDir,
|
|
3957
|
+
ledger,
|
|
3958
|
+
status,
|
|
3959
|
+
ok,
|
|
3770
3960
|
rc,
|
|
3771
3961
|
secs,
|
|
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
|
-
|
|
3811
|
-
text: shortText(ctx.resultReport?.notes ?? resultEvent?.result ?? (ok ? "done" : "failed"), 400),
|
|
3812
|
-
data: {
|
|
3813
|
-
rc: finalRc,
|
|
3814
|
-
ok,
|
|
3815
|
-
...status.branch ? {
|
|
3816
|
-
branch: status.branch,
|
|
3817
|
-
commits: status.commits ?? 0
|
|
3818
|
-
} : {},
|
|
3819
|
-
...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
|
+
}
|
|
3820
4001
|
}
|
|
3821
|
-
}
|
|
3822
|
-
}
|
|
3823
|
-
return finalRc;
|
|
4002
|
+
}
|
|
4003
|
+
});
|
|
3824
4004
|
}
|
|
3825
4005
|
/** The worktree fields printResult adds to a json payload, when there is one. */
|
|
3826
4006
|
function worktreeExtras(s) {
|
|
@@ -3945,12 +4125,7 @@ async function executeCodexRun(a) {
|
|
|
3945
4125
|
id: wid,
|
|
3946
4126
|
note: `dropped for codex: ${dropped.join(", ")}`
|
|
3947
4127
|
});
|
|
3948
|
-
|
|
3949
|
-
appendLedger(ledger, "PANE-FAIL", {
|
|
3950
|
-
id: wid,
|
|
3951
|
-
error: (e instanceof Error ? e.message : String(e)).slice(0, 200)
|
|
3952
|
-
});
|
|
3953
|
-
});
|
|
4128
|
+
announcePane(logDir, config, wid, term, noPane, ledger);
|
|
3954
4129
|
const t0 = Date.now();
|
|
3955
4130
|
const proc = spawn("codex", buildCodexArgs(prompt, parsed.callerModel ? void 0 : model), {
|
|
3956
4131
|
env,
|
|
@@ -4029,9 +4204,6 @@ async function executeCodexRun(a) {
|
|
|
4029
4204
|
};
|
|
4030
4205
|
writeEvent(resultEvent);
|
|
4031
4206
|
const ok = rc === 0 && !fold.isError;
|
|
4032
|
-
status.state = ok ? "done" : "failed";
|
|
4033
|
-
status.rc = rc;
|
|
4034
|
-
status.secs = secs;
|
|
4035
4207
|
status.last = shortText(report?.notes ?? finalText, 90) || (ok ? "done" : "failed");
|
|
4036
4208
|
if (report?.changed?.length) {
|
|
4037
4209
|
const verify = verifyReportChanges(report.changed, worktree?.dir ?? cwd, t0);
|
|
@@ -4047,40 +4219,29 @@ async function executeCodexRun(a) {
|
|
|
4047
4219
|
});
|
|
4048
4220
|
}
|
|
4049
4221
|
}
|
|
4050
|
-
|
|
4051
|
-
|
|
4052
|
-
|
|
4053
|
-
|
|
4054
|
-
|
|
4055
|
-
engine: "codex",
|
|
4056
|
-
model,
|
|
4222
|
+
return finaliseRun({
|
|
4223
|
+
logDir,
|
|
4224
|
+
ledger,
|
|
4225
|
+
status,
|
|
4226
|
+
ok,
|
|
4057
4227
|
rc,
|
|
4058
4228
|
secs,
|
|
4059
|
-
|
|
4060
|
-
|
|
4061
|
-
|
|
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
|
+
}
|
|
4062
4244
|
});
|
|
4063
|
-
if (worktree) status = recordWorktree(logDir, status, worktree, ok);
|
|
4064
|
-
if (!a.quiet) printResult(parsed.outputFormat, resultEvent, rc, logDir, wid, report, worktreeExtras(status));
|
|
4065
|
-
const finalRc = rc !== 0 ? rc : ok ? 0 : 1;
|
|
4066
|
-
if (status.parent && isWorkerId(logDir, status.parent)) try {
|
|
4067
|
-
await deliverHandoff(logDir, {
|
|
4068
|
-
from: wid,
|
|
4069
|
-
to: status.parent,
|
|
4070
|
-
kind: "result",
|
|
4071
|
-
text: shortText(report?.notes ?? finalText ?? (ok ? "done" : "failed"), 400),
|
|
4072
|
-
data: {
|
|
4073
|
-
rc: finalRc,
|
|
4074
|
-
ok,
|
|
4075
|
-
...status.branch ? {
|
|
4076
|
-
branch: status.branch,
|
|
4077
|
-
commits: status.commits ?? 0
|
|
4078
|
-
} : {},
|
|
4079
|
-
...report ? { report } : {}
|
|
4080
|
-
}
|
|
4081
|
-
});
|
|
4082
|
-
} catch {}
|
|
4083
|
-
return finalRc;
|
|
4084
4245
|
}
|
|
4085
4246
|
function printResult(fmt, resultEvent, rc, logDir, wid, report, extras) {
|
|
4086
4247
|
if (fmt === "stream-json") return;
|
|
@@ -4214,4 +4375,4 @@ function resultFromOutput(out) {
|
|
|
4214
4375
|
|
|
4215
4376
|
//#endregion
|
|
4216
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 };
|
|
4217
|
-
//# sourceMappingURL=run-
|
|
4378
|
+
//# sourceMappingURL=run-CxxZKEZw.mjs.map
|