pi-subagents 0.81.0 → 0.82.1
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/CHANGELOG.md +55 -0
- package/README.md +1 -1
- package/bundle/agents.js +3 -3
- package/bundle/child-tool-plan.js +2 -2
- package/bundle/{chunk-L5ZHE4L4.js → chunk-3JCDWF4V.js} +4 -4
- package/bundle/{chunk-LSRUTHT7.js → chunk-43SCHIMD.js} +1 -1
- package/bundle/{chunk-VJHOELQP.js → chunk-46XKCPJR.js} +193 -81
- package/bundle/{chunk-G5DKFLLI.js → chunk-4SDU2BZX.js} +15 -10
- package/bundle/{chunk-2ZSNH26H.js → chunk-4Y2ROR7L.js} +7 -7
- package/bundle/{chunk-V2JWDB5U.js → chunk-52UBALJL.js} +2 -2
- package/bundle/{chunk-3DC5KBVP.js → chunk-5TYMSZX3.js} +1 -1
- package/bundle/{chunk-NNLASTQE.js → chunk-6XJB7PIX.js} +20 -6
- package/bundle/{chunk-ZBC44JJ3.js → chunk-CIZQXJ5Q.js} +22 -9
- package/bundle/{chunk-KSWQVGDW.js → chunk-FXUXCX2K.js} +225 -18
- package/bundle/{chunk-563BHAZ5.js → chunk-G4GZD3OJ.js} +35 -26
- package/bundle/{chunk-ARRKBB2B.js → chunk-GJECHSAR.js} +2 -2
- package/bundle/{chunk-V3BIUPLU.js → chunk-IVAE5Z6Q.js} +256 -52
- package/bundle/{chunk-V6MR5TOQ.js → chunk-JYUKW2SY.js} +25 -19
- package/bundle/{chunk-BJN5LUQY.js → chunk-OYF6AFDY.js} +1 -1
- package/bundle/{chunk-CEKS3TFO.js → chunk-PBK2I7WY.js} +6 -6
- package/bundle/{chunk-TUWLXTAM.js → chunk-PDZWJCHD.js} +681 -320
- package/bundle/{chunk-EYNJ6VL6.js → chunk-PLCCBLPY.js} +2 -2
- package/bundle/{chunk-XMFLCKMQ.js → chunk-QE4AGIMG.js} +339 -132
- package/bundle/{chunk-74RT5YQE.js → chunk-RMQFMMAT.js} +123 -33
- package/bundle/{chunk-WSBNENFS.js → chunk-UCPP4GNU.js} +14 -4
- package/bundle/{chunk-2XYWN7QJ.js → chunk-UTT254JE.js} +2 -2
- package/bundle/{chunk-BPS2AGBZ.js → chunk-VSUSLDNW.js} +93 -52
- package/bundle/{chunk-ZP3HODFH.js → chunk-XSWOTIA3.js} +1 -1
- package/bundle/{chunk-3IF2PGW7.js → chunk-YKEWIB4M.js} +1 -1
- package/bundle/{chunk-26C3WLYQ.js → chunk-ZIV4J4HG.js} +498 -274
- package/bundle/control-channel.js +2 -2
- package/bundle/index.js +1 -1
- package/bundle/intercom-bridge.js +2 -2
- package/bundle/preflight.js +8 -8
- package/bundle/project-panes.js +3 -3
- package/docs/agents.md +37 -7
- package/docs/configuration.md +9 -1
- package/docs/tool-reference.md +3 -1
- package/docs/workflows.md +16 -0
- package/package.json +2 -2
- package/skills/council-mode/SKILL.md +1 -4
- package/skills/pi-subagents/SKILL.md +130 -107
- package/skills/pi-subagents/references/orchestration.md +124 -0
- package/skills/pi-subagents/references/prompting-and-roles.md +96 -295
- package/src/agents/agent-management.js +3 -3
- package/src/agents/agent-memory.js +3 -1
- package/src/agents/agents.js +6 -6
- package/src/agents/frontmatter.d.ts +2 -0
- package/src/agents/frontmatter.js +15 -1
- package/src/agents/skills.js +2 -1
- package/src/extension/config.js +3 -0
- package/src/extension/herdr-pi-bridge.js +17 -10
- package/src/extension/index.js +82 -2
- package/src/extension/reply-workflow-script.js +5 -2
- package/src/extension/schemas.js +3 -3
- package/src/extension/subagent-guide.js +1 -2
- package/src/intercom/native-supervisor-channel.js +20 -0
- package/src/missions/lifecycle.js +7 -1
- package/src/runs/background/active-async-capacity.d.ts +1 -0
- package/src/runs/background/active-async-capacity.js +9 -3
- package/src/runs/background/async-execution.js +20 -10
- package/src/runs/background/async-job-tracker.d.ts +6 -1
- package/src/runs/background/async-job-tracker.js +9 -4
- package/src/runs/background/async-status.d.ts +4 -0
- package/src/runs/background/async-status.js +22 -3
- package/src/runs/background/await-async-run.js +3 -7
- package/src/runs/background/boot-id.d.ts +12 -0
- package/src/runs/background/boot-id.js +47 -0
- package/src/runs/background/interrupted-elsewhere.d.ts +22 -0
- package/src/runs/background/interrupted-elsewhere.js +68 -0
- package/src/runs/background/notify.d.ts +2 -0
- package/src/runs/background/notify.js +13 -0
- package/src/runs/background/result-delivery-ownership.d.ts +6 -0
- package/src/runs/background/result-delivery-ownership.js +19 -1
- package/src/runs/background/result-watcher.d.ts +3 -1
- package/src/runs/background/result-watcher.js +24 -8
- package/src/runs/background/run-child-session.d.ts +1 -6
- package/src/runs/background/run-child-session.js +1 -1
- package/src/runs/background/run-status.js +2 -1
- package/src/runs/background/stale-run-reconciler.d.ts +25 -0
- package/src/runs/background/stale-run-reconciler.js +52 -13
- package/src/runs/background/subagent-runner-bootstrap.js +3 -0
- package/src/runs/background/subagent-runner.d.ts +4 -0
- package/src/runs/background/subagent-runner.js +13 -5
- package/src/runs/background/subagent-wait.d.ts +1 -1
- package/src/runs/background/subagent-wait.js +6 -1
- package/src/runs/background/terminal-run-index.d.ts +2 -0
- package/src/runs/background/terminal-run-index.js +44 -3
- package/src/runs/foreground/async-stop-action.js +3 -1
- package/src/runs/foreground/execution.js +6 -3
- package/src/runs/foreground/foreground-history.d.ts +16 -2
- package/src/runs/foreground/foreground-history.js +133 -31
- package/src/runs/foreground/subagent-executor.d.ts +11 -0
- package/src/runs/foreground/subagent-executor.js +277 -74
- package/src/runs/shared/child-launch.d.ts +2 -2
- package/src/runs/shared/child-session.d.ts +3 -2
- package/src/runs/shared/child-session.js +51 -8
- package/src/runs/shared/child-tool-plan.d.ts +7 -0
- package/src/runs/shared/child-tool-plan.js +21 -6
- package/src/runs/shared/herdr-connection.d.ts +17 -8
- package/src/runs/shared/herdr-connection.js +19 -7
- package/src/runs/shared/herdr-external-adapters.d.ts +3 -2
- package/src/runs/shared/herdr-external-adapters.js +1 -1
- package/src/runs/shared/herdr-machine.d.ts +12 -2
- package/src/runs/shared/herdr-machine.js +55 -9
- package/src/runs/shared/herdr-pane-host.d.ts +88 -0
- package/src/runs/shared/herdr-pane-host.js +155 -0
- package/src/runs/shared/herdr-placed-run.d.ts +27 -150
- package/src/runs/shared/herdr-placed-run.js +48 -395
- package/src/runs/shared/local-machine-access.d.ts +5 -0
- package/src/runs/shared/local-machine-access.js +28 -0
- package/src/runs/shared/orca-progress-tabs.d.ts +0 -1
- package/src/runs/shared/orca-progress-tabs.js +1 -24
- package/src/runs/shared/parallel-utils.d.ts +1 -1
- package/src/runs/shared/placed-run-owner.d.ts +49 -0
- package/src/runs/shared/placed-run-owner.js +93 -0
- package/src/runs/shared/placement-host.d.ts +99 -0
- package/src/runs/shared/placement-host.js +157 -0
- package/src/runs/shared/rex-machine.d.ts +25 -0
- package/src/runs/shared/rex-machine.js +83 -0
- package/src/runs/shared/rex-pane-host.d.ts +62 -0
- package/src/runs/shared/rex-pane-host.js +327 -0
- package/src/shared/completion-owner.d.ts +5 -0
- package/src/shared/completion-owner.js +5 -0
- package/src/shared/session-identity.d.ts +2 -0
- package/src/shared/session-identity.js +26 -0
- package/src/shared/types.d.ts +45 -6
- package/src/tui/fleet.d.ts +1 -0
- package/src/tui/fleet.js +25 -15
- package/src/tui/render.d.ts +6 -0
- package/src/tui/render.js +3 -3
- package/src/tui/subagent-messages.js +1 -0
- package/src/workflows/scripted-workflow.d.ts +1 -1
- package/src/workflows/workflow-auto-resume.d.ts +32 -0
- package/src/workflows/workflow-auto-resume.js +102 -0
- package/src/workflows/workflow-launch-record.d.ts +27 -0
- package/src/workflows/workflow-launch-record.js +48 -0
- package/src/workflows/workflow-resume-claim.d.ts +82 -0
- package/src/workflows/workflow-resume-claim.js +210 -0
- package/src/workflows/workflow-resume.d.ts +56 -0
- package/src/workflows/workflow-resume.js +106 -0
- package/src/workflows/workflow-reuse.d.ts +15 -9
- package/src/workflows/workflow-reuse.js +77 -14
- package/src/workflows/workflow-revival.d.ts +2 -0
- package/src/workflows/workflow-revival.js +2 -1
- package/src/workflows/workflow-stop-cause.d.ts +6 -0
- package/src/workflows/workflow-stop-cause.js +8 -0
- package/skills/pi-subagents/references/constraints-and-recipes.md +0 -74
- package/skills/pi-subagents/references/execution-controls.md +0 -563
- package/skills/pi-subagents/references/management-authoring-rpc.md +0 -165
- package/skills/pi-subagents/references/multi-lane-orchestration.md +0 -61
- package/skills/pi-subagents/references/review-and-validation.md +0 -73
|
@@ -4,6 +4,7 @@ import { writeAtomicJson } from "../../shared/atomic-json.js";
|
|
|
4
4
|
import { resultFilePath, resultPayloadPathForSessionRun, writeAsyncResultFile } from "./result-files.js";
|
|
5
5
|
import { updateActiveRunIndex } from "./active-run-index.js";
|
|
6
6
|
import { readProcessTerminal } from "./process-terminal.js";
|
|
7
|
+
import { OWNING_SESSION_COMPLETION_OWNER } from "../../shared/completion-owner.js";
|
|
7
8
|
import { readStatus } from "../../shared/utils.js";
|
|
8
9
|
import { DIRS } from "../../shared/types.js";
|
|
9
10
|
import { resolveEffectiveThinking } from "../../shared/model-info.js";
|
|
@@ -11,6 +12,8 @@ import { normalizeParallelGroups } from "./parallel-groups.js";
|
|
|
11
12
|
import { nestedSummaryFromAsyncStatus, projectNestedEvents, resolveNestedAsyncDir, writeNestedEvent } from "../shared/nested-events.js";
|
|
12
13
|
import { assertWorkflowGraphHostSteps } from "../shared/host-step-status.js";
|
|
13
14
|
import { currentPidNamespaceScope } from "./pid-namespace.js";
|
|
15
|
+
import { currentBootId } from "./boot-id.js";
|
|
16
|
+
import { WORKFLOW_STOP_CAUSE_OWNER_EXITED } from "../../workflows/workflow-stop-cause.js";
|
|
14
17
|
import { isTerminalAsyncState } from "./workflow-terminal-proof.js";
|
|
15
18
|
function getErrorMessage(error) {
|
|
16
19
|
return error instanceof Error ? error.message : String(error);
|
|
@@ -215,9 +218,14 @@ function settledWorkflowChildStatus(asyncDir, workflowRunId, step, now) {
|
|
|
215
218
|
delete settled.stopped;
|
|
216
219
|
return settled;
|
|
217
220
|
}
|
|
218
|
-
function buildFailedRepair(status, asyncDir, now, reason) {
|
|
221
|
+
function buildFailedRepair(status, asyncDir, now, reason, ownerExited = false, adoptCompletionOwnerId) {
|
|
219
222
|
const runId = status.runId || path.basename(asyncDir);
|
|
220
223
|
const pid = typeof status.pid === "number" ? status.pid : "unknown";
|
|
224
|
+
// A dead workflow host is the Pi process itself; its journal keeps the finished children for a relaunch.
|
|
225
|
+
const exitedWorkflow = ownerExited && status.mode === "workflow" ? status.workflow : undefined;
|
|
226
|
+
// Its owner process is dead, so nothing else can deliver its notice: an owning session that repairs it
|
|
227
|
+
// adopts it, and a repair elsewhere leaves it to whichever session owns the run.
|
|
228
|
+
const completionOwnerId = exitedWorkflow ? adoptCompletionOwnerId || OWNING_SESSION_COMPLETION_OWNER : status.completionOwnerId;
|
|
221
229
|
const terminal = readProcessTerminal(asyncDir, { runId }) ?? status.processTerminal;
|
|
222
230
|
const runnerExit = terminal?.state === "observed" || terminal?.state === "unknown"
|
|
223
231
|
? terminal.instances?.find((instance) => instance.kind === "runner" && instance.processInstanceId === terminal.runnerProcessInstanceId)
|
|
@@ -225,7 +233,9 @@ function buildFailedRepair(status, asyncDir, now, reason) {
|
|
|
225
233
|
const exitText = runnerExit?.kind === "runner"
|
|
226
234
|
? `exited with code ${runnerExit.exitCode ?? "none"}${runnerExit.signal ? ` (signal ${runnerExit.signal})` : ""}`
|
|
227
235
|
: "exited or disappeared";
|
|
228
|
-
const baseMessage = reason ??
|
|
236
|
+
const baseMessage = reason ?? (exitedWorkflow
|
|
237
|
+
? `The Pi process (PID ${pid}) that ran workflow ${runId} exited before the workflow finished. Marked run failed by stale-run reconciliation. Its finished children are kept.`
|
|
238
|
+
: `Async runner process ${pid} ${exitText} before writing a result. Marked run failed by stale-run reconciliation.`);
|
|
229
239
|
const diagnostics = readRunnerStartupDiagnostics(asyncDir);
|
|
230
240
|
const message = diagnostics ? `${baseMessage}\n\nRunner stderr tail:\n${diagnostics}` : baseMessage;
|
|
231
241
|
const steps = status.steps?.length ? status.steps : [{ agent: "subagent", status: "running" }];
|
|
@@ -263,6 +273,9 @@ function buildFailedRepair(status, asyncDir, now, reason) {
|
|
|
263
273
|
lastUpdate: now,
|
|
264
274
|
endedAt: now,
|
|
265
275
|
steps: repairedSteps,
|
|
276
|
+
// Read from the pre-repair status: the repair time would make an old crash look new.
|
|
277
|
+
...(exitedWorkflow ? { workflow: { ...exitedWorkflow, stopCause: WORKFLOW_STOP_CAUSE_OWNER_EXITED, ownerExitedAt: status.lastUpdate ?? status.startedAt } } : {}),
|
|
278
|
+
...(completionOwnerId ? { completionOwnerId } : {}),
|
|
266
279
|
};
|
|
267
280
|
const resultAgent = repairedSteps[status.currentStep ?? 0]?.agent ?? repairedSteps[0]?.agent ?? "subagent";
|
|
268
281
|
return {
|
|
@@ -272,7 +285,9 @@ function buildFailedRepair(status, asyncDir, now, reason) {
|
|
|
272
285
|
id: runId,
|
|
273
286
|
agent: resultAgent,
|
|
274
287
|
mode: status.mode,
|
|
275
|
-
...(
|
|
288
|
+
...(exitedWorkflow ? { workflow: { stopCause: WORKFLOW_STOP_CAUSE_OWNER_EXITED } } : {}),
|
|
289
|
+
...(completionOwnerId ? { completionOwnerId } : {}),
|
|
290
|
+
...(status.completionOwnerProcess ? { completionOwnerProcess: status.completionOwnerProcess } : {}),
|
|
276
291
|
...(status.parentWorkflowRunId ? { parentWorkflowRunId: status.parentWorkflowRunId } : {}),
|
|
277
292
|
...(status.workflowKey ? { workflowKey: status.workflowKey } : {}),
|
|
278
293
|
success: false,
|
|
@@ -298,8 +313,8 @@ function buildFailedRepair(status, asyncDir, now, reason) {
|
|
|
298
313
|
},
|
|
299
314
|
};
|
|
300
315
|
}
|
|
301
|
-
function writeFailedRepair(asyncDir, status, resultPath, now, reason) {
|
|
302
|
-
const repair = buildFailedRepair(status, asyncDir, now, reason);
|
|
316
|
+
function writeFailedRepair(asyncDir, status, resultPath, now, reason, ownerExited = false, adoptCompletionOwnerId) {
|
|
317
|
+
const repair = buildFailedRepair(status, asyncDir, now, reason, ownerExited, adoptCompletionOwnerId);
|
|
303
318
|
if (repair.result.sessionId)
|
|
304
319
|
writeAsyncResultFile(resultPath, repair.result);
|
|
305
320
|
writeAtomicJson(path.join(asyncDir, "status.json"), repair.status);
|
|
@@ -386,6 +401,32 @@ export function checkPidLiveness(pid, kill = process.kill, probeZombie = false)
|
|
|
386
401
|
return "unknown";
|
|
387
402
|
}
|
|
388
403
|
}
|
|
404
|
+
export function isRecordedPid(value) {
|
|
405
|
+
if (!value || typeof value !== "object")
|
|
406
|
+
return false;
|
|
407
|
+
const { pid, pidNamespaceScope, bootId } = value;
|
|
408
|
+
return typeof pid === "number" && Number.isSafeInteger(pid) && pid > 0
|
|
409
|
+
&& (pidNamespaceScope === undefined || typeof pidNamespaceScope === "string")
|
|
410
|
+
&& (bootId === undefined || typeof bootId === "string");
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* Liveness of a pid saved in a status file. A pid saved under another boot is dead without a
|
|
414
|
+
* probe, but only when both sides are in the same pid namespace or neither records one: a
|
|
415
|
+
* macOS host reading a Linux container's runs must not compare their boot ids.
|
|
416
|
+
*/
|
|
417
|
+
export function checkRecordedPidLiveness(recorded, observation = { observedScope: currentPidNamespaceScope(), observedBootId: currentBootId() }) {
|
|
418
|
+
const { observedScope, observedBootId } = observation;
|
|
419
|
+
if (recorded.pidNamespaceScope === observedScope && recorded.bootId && observedBootId && recorded.bootId !== observedBootId)
|
|
420
|
+
return "dead";
|
|
421
|
+
// An observer without a scope (macOS/Windows host sharing a container's temp root) cannot match a recorded one.
|
|
422
|
+
const scopeMismatch = recorded.pidNamespaceScope !== undefined && recorded.pidNamespaceScope !== observedScope;
|
|
423
|
+
// A local zombie is evidence about this pid only when its namespace is known to match.
|
|
424
|
+
const scopeVerified = recorded.pidNamespaceScope !== undefined && recorded.pidNamespaceScope === observedScope;
|
|
425
|
+
const liveness = observation.probe
|
|
426
|
+
? observation.probe(recorded.pid)
|
|
427
|
+
: checkPidLiveness(recorded.pid, observation.kill, scopeVerified);
|
|
428
|
+
return liveness === "dead" && scopeMismatch ? "unknown" : liveness;
|
|
429
|
+
}
|
|
389
430
|
export function reconcileAsyncRun(asyncDir, options = {}, observeStatus) {
|
|
390
431
|
const now = options.now?.() ?? Date.now();
|
|
391
432
|
const status = readStatus(asyncDir);
|
|
@@ -450,13 +491,11 @@ export function reconcileAsyncRun(asyncDir, options = {}, observeStatus) {
|
|
|
450
491
|
return { status: null, repaired: false, resultPath };
|
|
451
492
|
}
|
|
452
493
|
}
|
|
453
|
-
const
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
const observedLiveness = checkPidLiveness(effectiveStatus.pid, options.kill, pidScopeVerified);
|
|
459
|
-
const liveness = observedLiveness === "dead" && pidScopeMismatch ? "unknown" : observedLiveness;
|
|
494
|
+
const liveness = checkRecordedPidLiveness({ pid: effectiveStatus.pid, pidNamespaceScope: effectiveStatus.pidNamespaceScope, bootId: effectiveStatus.bootId }, {
|
|
495
|
+
kill: options.kill,
|
|
496
|
+
observedScope: options.pidNamespaceScope ? options.pidNamespaceScope() : currentPidNamespaceScope(),
|
|
497
|
+
observedBootId: options.bootId ? options.bootId() : currentBootId(),
|
|
498
|
+
});
|
|
460
499
|
if (liveness !== "dead") {
|
|
461
500
|
const staleAfterMs = options.staleAlivePidMs ?? 24 * 60 * 60 * 1000;
|
|
462
501
|
const lastUpdate = effectiveStatus.lastUpdate ?? effectiveStatus.startedAt;
|
|
@@ -466,5 +505,5 @@ export function reconcileAsyncRun(asyncDir, options = {}, observeStatus) {
|
|
|
466
505
|
const message = `Async runner PID ${effectiveStatus.pid} ${probe}; status has not updated for ${now - lastUpdate}ms, so stale-run reconciliation marked the run failed because PID ownership is unverified.`;
|
|
467
506
|
return writeFailedRepair(asyncDir, effectiveStatus, resultPath, now, message);
|
|
468
507
|
}
|
|
469
|
-
return writeFailedRepair(asyncDir, effectiveStatus, resultPath, now);
|
|
508
|
+
return writeFailedRepair(asyncDir, effectiveStatus, resultPath, now, undefined, true, options.adoptCompletionOwnerId);
|
|
470
509
|
}
|
|
@@ -14,6 +14,7 @@ import { acquireSessionLease } from "../shared/session-lease.js";
|
|
|
14
14
|
import { readProcessTerminalCandidate, writeProcessTerminalCandidate, markProcessTerminalCandidateLeaseRelease } from "./process-terminal-candidate.js";
|
|
15
15
|
import { persistRunnerStartupFailure } from "./runner-startup-failure.js";
|
|
16
16
|
import { currentPidNamespaceScope } from "./pid-namespace.js";
|
|
17
|
+
import { primeBootId } from "./boot-id.js";
|
|
17
18
|
function isRecord(value) {
|
|
18
19
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
19
20
|
}
|
|
@@ -103,6 +104,8 @@ async function waitForStartupControl(controlPath, token, action, timeoutMs = 30_
|
|
|
103
104
|
export async function runConfiguredSubagent(rawConfig, options = {}) {
|
|
104
105
|
validateSubagentRunConfig(rawConfig);
|
|
105
106
|
const config = rawConfig;
|
|
107
|
+
// The runner never reads the boot id from the OS (sysctl on macOS); Pi passes it to direct runners only.
|
|
108
|
+
primeBootId(typeof config.bootId === "string" && config.bootId ? config.bootId : undefined);
|
|
106
109
|
let lease;
|
|
107
110
|
let startupCommitted = config.revivalLease === undefined && config.launchBarrierToken === undefined;
|
|
108
111
|
let executionLoaded = false;
|
|
@@ -4,6 +4,7 @@ import { type RunnerSubagentStep as SubagentStep, type RunnerStep } from "../sha
|
|
|
4
4
|
import type { InheritedChildRuntime } from "../shared/child-launch.ts";
|
|
5
5
|
import type { ChildSessionFactory, DefaultChildSessionFactoryOptions } from "../shared/child-session.ts";
|
|
6
6
|
import { type ChildEvent, type SteerDelivery, type StepSteerHandler } from "./run-child-session.ts";
|
|
7
|
+
import type { RecordedPid } from "./stale-run-reconciler.ts";
|
|
7
8
|
import type { SessionLeaseRequest } from "../shared/session-lease.ts";
|
|
8
9
|
import { createHerdrExternalAdapter, type HerdrExternalAdapterId, type HerdrExternalResult } from "../shared/herdr-external-adapters.ts";
|
|
9
10
|
import { type OrcaProgressTab } from "../shared/orca-progress-tabs.ts";
|
|
@@ -25,6 +26,7 @@ export interface SubagentRunConfig {
|
|
|
25
26
|
asyncDir: string;
|
|
26
27
|
sessionId?: string | null;
|
|
27
28
|
completionOwnerId?: string;
|
|
29
|
+
completionOwnerProcess?: RecordedPid;
|
|
28
30
|
piPackageRoot?: string;
|
|
29
31
|
/** Test seam: module the runner imports its `ChildSessionFactory` from. */
|
|
30
32
|
childSessionFactoryModule?: string;
|
|
@@ -76,6 +78,8 @@ export interface SubagentRunConfig {
|
|
|
76
78
|
runtimeAcknowledgedExtensions?: RuntimeAcknowledgedChildExtensions;
|
|
77
79
|
runnerProcessInstanceId?: string;
|
|
78
80
|
launchBarrierToken?: string;
|
|
81
|
+
/** Pi's boot id, set only for a direct (non-launcher) runner; the runner never reads its own. */
|
|
82
|
+
bootId?: string;
|
|
79
83
|
parentWorkflowRunId?: string;
|
|
80
84
|
workflowKey?: string;
|
|
81
85
|
lane?: WorkflowLaneMetadata;
|
|
@@ -49,7 +49,7 @@ import { nestedSummaryFromAsyncStatus, projectNestedEvents, resolveNestedAsyncDi
|
|
|
49
49
|
import { isContextOverflow } from "../shared/model-resolution.js";
|
|
50
50
|
import { processTerminalPath, writeProcessTerminalCandidate } from "./process-terminal.js";
|
|
51
51
|
import { persistRunnerStartupFailure } from "./runner-startup-failure.js";
|
|
52
|
-
import {
|
|
52
|
+
import { currentRecordedPid } from "./boot-id.js";
|
|
53
53
|
import { createSteeringStatus, recordSteeringRequest, steeringStatus, terminalSteeringNoticeState, unconsumedSteerReason, updateSteeringTarget } from "./steering.js";
|
|
54
54
|
import { PROMPT_REDACTED, SUBAGENT_STOPPED_MESSAGE, SUBAGENT_TIMED_OUT_MESSAGE, detectSubagentError, extractTextFromContent, extractToolArgsPreview, formatEmptyTerminalAssistantResponseError, getAgentDir, hasEmptyTerminalAssistantResponse, readStatus } from "../../shared/utils.js";
|
|
55
55
|
import { planAbortRecovery } from "../shared/abort-recovery.js";
|
|
@@ -77,6 +77,7 @@ import { resolveCodexExecLaunch } from "../shared/codex-exec-adapter.js";
|
|
|
77
77
|
import { resolveCursorAgentLaunch } from "../shared/cursor-agent-adapter.js";
|
|
78
78
|
import { resolveExternalCliRunnerStatus } from "../shared/external-cli-contract.js";
|
|
79
79
|
import { formatHerdrMachineHint, prepareHerdrMachineExternalCliRun } from "../shared/herdr-machine.js";
|
|
80
|
+
import { isRexLocalMachine } from "../shared/rex-machine.js";
|
|
80
81
|
import { HerdrExternalNeedsAttentionError, createHerdrExternalAdapter, prepareInternalHerdrExternalAdapter } from "../shared/herdr-external-adapters.js";
|
|
81
82
|
import { runExternalJob } from "../shared/external-job-runner.js";
|
|
82
83
|
import { createOrcaProgressTab } from "../shared/orca-progress-tabs.js";
|
|
@@ -522,6 +523,7 @@ export async function runSingleStepInner(step, ctx) {
|
|
|
522
523
|
capabilityCeiling: step.capabilityCeiling ?? ctx.capabilityCeiling,
|
|
523
524
|
inheritedCapabilityCeiling: ctx.inheritedChildRuntime?.capabilityCeiling,
|
|
524
525
|
requiredExtensions: step.requiredExtensions ?? ctx.inheritedChildRuntime?.requiredExtensions,
|
|
526
|
+
agentName: step.agent,
|
|
525
527
|
permissionRules: step.permissionRules,
|
|
526
528
|
}));
|
|
527
529
|
}
|
|
@@ -608,6 +610,8 @@ export async function runSingleStepInner(step, ctx) {
|
|
|
608
610
|
return omitUndefinedProperties({ agent: step.agent, context: step.context, output: message, error: message, exitCode: 1, stopped: stopped || undefined, timedOut: stopped ? undefined : true });
|
|
609
611
|
}
|
|
610
612
|
if (step.machine) {
|
|
613
|
+
if (step.machine.provider !== "herdr")
|
|
614
|
+
throw new Error("Rex supports native Pi children only.");
|
|
611
615
|
const runner = resolveExternalCliRunnerStatus({ ...step.runner, machine: step.machine });
|
|
612
616
|
const outputSnapshot = captureSingleOutputSnapshot(step.outputPath);
|
|
613
617
|
const placedRunId = `${ctx.id}-${ctx.flatIndex}`;
|
|
@@ -781,7 +785,8 @@ export async function runSingleStepInner(step, ctx) {
|
|
|
781
785
|
let toolBudget = step.toolBudget ? initialToolBudgetState(step.toolBudget) : undefined;
|
|
782
786
|
let toolBudgetBlocked = false;
|
|
783
787
|
let actualLaunchContractDigest = step.launchContractDigest;
|
|
784
|
-
|
|
788
|
+
// A machine 'local' child edits this disk, so its local Git evidence is authoritative, as for an unplaced run.
|
|
789
|
+
const mutationSnapshot = step.machine && !isRexLocalMachine(step.machine) ? { source: "tracked-files", trackedOnly: true, cwd: step.cwd ?? ctx.cwd, dirtyFiles: [], fingerprints: {}, unavailable: "Local Git evidence is not authoritative for a pane-native remote run." } : snapshotTrackedMutations(step.cwd ?? ctx.cwd);
|
|
785
790
|
let finalMutationEvidence = collectTrackedMutationEvidence(mutationSnapshot, step.cwd ?? ctx.cwd);
|
|
786
791
|
let contextOverflow = false;
|
|
787
792
|
let launchWarningsEmitted = false;
|
|
@@ -1004,7 +1009,7 @@ export async function runSingleStepInner(step, ctx) {
|
|
|
1004
1009
|
? formatEmptyTerminalAssistantResponseError(run.messages)
|
|
1005
1010
|
: undefined;
|
|
1006
1011
|
const remoteGitChanged = run.nativeMachine?.initialGit && run.nativeMachine.finalGit ? run.nativeMachine.initialGit.head !== run.nativeMachine.finalGit.head || run.nativeMachine.initialGit.dirty !== run.nativeMachine.finalGit.dirty : undefined;
|
|
1007
|
-
const mutationEvidence = run.nativeMachine ? { source: "tracked-files", trackedOnly: true, changedFiles: [], attemptedMutation: remoteGitChanged === true, ...(remoteGitChanged === undefined ? { unavailable: "Remote Git before/after evidence was incomplete." } : {}) } : collectTrackedMutationEvidence(mutationSnapshot, step.cwd ?? ctx.cwd);
|
|
1012
|
+
const mutationEvidence = run.nativeMachine && !isRexLocalMachine(step.machine) ? { source: "tracked-files", trackedOnly: true, changedFiles: [], attemptedMutation: remoteGitChanged === true, ...(remoteGitChanged === undefined ? { unavailable: "Remote Git before/after evidence was incomplete." } : {}) } : collectTrackedMutationEvidence(mutationSnapshot, step.cwd ?? ctx.cwd);
|
|
1008
1013
|
finalMutationEvidence = mutationEvidence;
|
|
1009
1014
|
const mutationAttemptObserved = run.observedMutationAttempt === true || mutationEvidence.attemptedMutation === true;
|
|
1010
1015
|
// Validated structured output is persistable file content even when the final text is only
|
|
@@ -1669,6 +1674,7 @@ export async function runSubagent(config, childSessions) {
|
|
|
1669
1674
|
...(config.toolCallId ? { toolCallId: config.toolCallId } : {}),
|
|
1670
1675
|
...(config.sessionId ? { sessionId: config.sessionId } : {}),
|
|
1671
1676
|
...(config.completionOwnerId ? { completionOwnerId: config.completionOwnerId } : {}),
|
|
1677
|
+
...(config.completionOwnerProcess ? { completionOwnerProcess: config.completionOwnerProcess } : {}),
|
|
1672
1678
|
mode: config.resultMode ?? (flatSteps.length > 1 ? "chain" : "single"),
|
|
1673
1679
|
...(config.nestedSelf ? { isNested: true } : {}),
|
|
1674
1680
|
state: "running",
|
|
@@ -1680,8 +1686,7 @@ export async function runSubagent(config, childSessions) {
|
|
|
1680
1686
|
...(config.deadlineAt !== undefined ? { deadlineAt: config.deadlineAt } : {}),
|
|
1681
1687
|
...(config.toolBudget ? { toolBudget: initialToolBudgetState(config.toolBudget) } : {}),
|
|
1682
1688
|
...(config.usageBudget ? { usageBudget: usageBudgetState(config.usageBudget, undefined) } : {}),
|
|
1683
|
-
|
|
1684
|
-
pidNamespaceScope: currentPidNamespaceScope(),
|
|
1689
|
+
...currentRecordedPid(),
|
|
1685
1690
|
cwd,
|
|
1686
1691
|
currentStep: 0,
|
|
1687
1692
|
chainStepCount: steps.length,
|
|
@@ -1909,6 +1914,8 @@ export async function runSubagent(config, childSessions) {
|
|
|
1909
1914
|
cwd,
|
|
1910
1915
|
sessionId: config.sessionId,
|
|
1911
1916
|
completionOwnerId: config.completionOwnerId,
|
|
1917
|
+
completionOwnerProcess: config.completionOwnerProcess,
|
|
1918
|
+
parentWorkflowRunId: config.parentWorkflowRunId,
|
|
1912
1919
|
sessionFile: statusPayload.sessionFile ?? latestSessionFile,
|
|
1913
1920
|
}), (filePath, payload) => publishRunResult(filePath, () => writePendingAsyncResultFile(filePath, payload)));
|
|
1914
1921
|
};
|
|
@@ -4797,6 +4804,7 @@ export async function runSubagent(config, childSessions) {
|
|
|
4797
4804
|
runtimeAcknowledgedExtensions: singleRuntimeAcknowledgedExtensions,
|
|
4798
4805
|
sessionId: config.sessionId,
|
|
4799
4806
|
completionOwnerId: config.completionOwnerId,
|
|
4807
|
+
completionOwnerProcess: config.completionOwnerProcess,
|
|
4800
4808
|
sessionFile: effectiveSessionFile,
|
|
4801
4809
|
intercomTarget: config.controlIntercomTarget,
|
|
4802
4810
|
shareUrl,
|
|
@@ -54,7 +54,7 @@ export interface SubagentWaitParams {
|
|
|
54
54
|
all?: boolean;
|
|
55
55
|
/** Give up after this many milliseconds. Defaults to waitTool.defaultTimeoutMs, then 30 minutes. */
|
|
56
56
|
timeoutMs?: number;
|
|
57
|
-
/** False keeps a blocking wait open through
|
|
57
|
+
/** False keeps a blocking wait open through all attention except supervisor/contact requests, such as idle time, a tool held open, or repeated tool failures. */
|
|
58
58
|
stopOnAttention?: boolean;
|
|
59
59
|
}
|
|
60
60
|
/** Minimal event-bus surface wait subscribes to (matches pi.events). */
|
|
@@ -707,8 +707,13 @@ export async function waitForSubagents(params, signal, deps) {
|
|
|
707
707
|
const supervisorAttentionHint = relevantAttention.some(hasSupervisorTool)
|
|
708
708
|
? " Reply to any pending supervisor request. If subagent_supervisor({ action: \"pending\" }) is empty, check intercom({ action: \"pending\" }) because an external intercom tool may own the request."
|
|
709
709
|
: "";
|
|
710
|
+
// Only when watchdog attention alone ended the wait: stopOnAttention: false would have kept blocking.
|
|
711
|
+
const keepWaitingHint = stopOnAttention && supervisorAttentionHint === ""
|
|
712
|
+
&& (waitForAll || finishedAsyncCount + providerFinishedCount === 0)
|
|
713
|
+
? " These runs are still running and none is waiting on a supervisor reply. To keep waiting through this kind of attention, call bg_wait again with stopOnAttention: false; supervisor requests still end that wait."
|
|
714
|
+
: "";
|
|
710
715
|
const attentionNote = relevantAttention.length > 0
|
|
711
|
-
? ` ${relevantAttention.length} run(s) need attention: ${relevantAttention.map((run) => run.id).join(", ")} —${supervisorAttentionHint} inspect with subagent({ action: "status" }) then steer a top-level live async child, resume a paused/completed/failed child, or interrupt explicitly
|
|
716
|
+
? ` ${relevantAttention.length} run(s) need attention: ${relevantAttention.map((run) => run.id).join(", ")} —${supervisorAttentionHint} inspect with subagent({ action: "status" }) then steer a top-level live async child, resume a paused/completed/failed child, or interrupt explicitly.${keepWaitingHint}`
|
|
712
717
|
: "";
|
|
713
718
|
const stillRunning = active.filter((run) => initialAsyncIds.has(run.id)).length
|
|
714
719
|
+ providerActive.filter((item) => initialProviderIds.has(backgroundWorkIdentity(item))).length;
|
|
@@ -5,4 +5,6 @@ export declare function readTerminalRunToolCallIndex(asyncDirRoot: string, toolC
|
|
|
5
5
|
export declare function readRecentTerminalRunIndex(asyncDirRoot: string, options?: {
|
|
6
6
|
sessionId?: string;
|
|
7
7
|
limit?: number;
|
|
8
|
+
endedAfter?: number;
|
|
9
|
+
onCorruptStatus?: (warning: string) => void;
|
|
8
10
|
}): string[];
|
|
@@ -12,6 +12,35 @@ const TOOL_CALL_INDEX_DIR = "@tool-calls";
|
|
|
12
12
|
function isTerminalState(state) {
|
|
13
13
|
return state === "complete" || state === "failed" || state === "partial" || state === "paused" || state === "stopped" || state === "rejected";
|
|
14
14
|
}
|
|
15
|
+
function isCorruptStatusError(error, statusPath) {
|
|
16
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
17
|
+
return message.startsWith(`Failed to parse async status file '${statusPath}'`)
|
|
18
|
+
|| message.startsWith(`Failed to validate async status file '${statusPath}'`);
|
|
19
|
+
}
|
|
20
|
+
// A corrupt indexed status is retried on every read. Emit a warning only when
|
|
21
|
+
// its observed file identity or parse outcome changes, like active-run diagnostics.
|
|
22
|
+
const reportedCorruptTerminalStatus = new Map();
|
|
23
|
+
function warnCorruptTerminalStatus(runId, statusPath, error, onCorruptStatus) {
|
|
24
|
+
let fileSignature = "unavailable";
|
|
25
|
+
try {
|
|
26
|
+
const stat = fs.statSync(statusPath);
|
|
27
|
+
fileSignature = `${stat.size}:${stat.mtimeMs}:${stat.ctimeMs}:${stat.ino}`;
|
|
28
|
+
}
|
|
29
|
+
catch (statError) {
|
|
30
|
+
if (statError.code !== "ENOENT")
|
|
31
|
+
throw statError;
|
|
32
|
+
}
|
|
33
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
34
|
+
const signature = `${fileSignature}\n${message}`;
|
|
35
|
+
if (reportedCorruptTerminalStatus.get(statusPath) === signature)
|
|
36
|
+
return;
|
|
37
|
+
reportedCorruptTerminalStatus.set(statusPath, signature);
|
|
38
|
+
const warning = `Skipping indexed terminal run '${runId}' with corrupt status at '${statusPath}': ${message}`;
|
|
39
|
+
if (onCorruptStatus)
|
|
40
|
+
onCorruptStatus(warning);
|
|
41
|
+
else
|
|
42
|
+
console.error(`[pi-subagents] ${warning}`);
|
|
43
|
+
}
|
|
15
44
|
function indexRoot(asyncDirRoot) {
|
|
16
45
|
return path.join(asyncDirRoot, TERMINAL_RUN_INDEX_DIR);
|
|
17
46
|
}
|
|
@@ -99,8 +128,10 @@ function sessionDirs(asyncDirRoot, sessionId) {
|
|
|
99
128
|
throw error;
|
|
100
129
|
}
|
|
101
130
|
}
|
|
102
|
-
function recentMarkerFiles(dirs, limit) {
|
|
131
|
+
function recentMarkerFiles(dirs, limit, endedAfter) {
|
|
103
132
|
return dirs.flatMap(markerFiles)
|
|
133
|
+
// The name starts with the run's end time, so an old run is skipped without reading its marker.
|
|
134
|
+
.filter((marker) => endedAfter === undefined || !(Number(marker.name.slice(0, TIMESTAMP_WIDTH)) < endedAfter))
|
|
104
135
|
.sort((left, right) => right.name.localeCompare(left.name))
|
|
105
136
|
.slice(0, limit)
|
|
106
137
|
.map((marker) => path.join(marker.dir, marker.name));
|
|
@@ -135,7 +166,7 @@ export function readTerminalRunToolCallIndex(asyncDirRoot, toolCallId) {
|
|
|
135
166
|
}
|
|
136
167
|
export function readRecentTerminalRunIndex(asyncDirRoot, options = {}) {
|
|
137
168
|
const limit = options.limit === undefined ? Number.POSITIVE_INFINITY : Math.max(0, Math.floor(options.limit));
|
|
138
|
-
const candidates = recentMarkerFiles(sessionDirs(asyncDirRoot, options.sessionId), limit);
|
|
169
|
+
const candidates = recentMarkerFiles(sessionDirs(asyncDirRoot, options.sessionId), limit, options.endedAfter);
|
|
139
170
|
const runIds = [];
|
|
140
171
|
const seen = new Set();
|
|
141
172
|
for (const marker of candidates) {
|
|
@@ -152,7 +183,17 @@ export function readRecentTerminalRunIndex(asyncDirRoot, options = {}) {
|
|
|
152
183
|
continue;
|
|
153
184
|
}
|
|
154
185
|
const asyncDir = path.join(asyncDirRoot, entry.runId);
|
|
155
|
-
const
|
|
186
|
+
const statusPath = path.join(asyncDir, "status.json");
|
|
187
|
+
let status;
|
|
188
|
+
try {
|
|
189
|
+
status = readStatus(asyncDir);
|
|
190
|
+
}
|
|
191
|
+
catch (error) {
|
|
192
|
+
if (!isCorruptStatusError(error, statusPath))
|
|
193
|
+
throw error;
|
|
194
|
+
warnCorruptTerminalStatus(entry.runId, statusPath, error, options.onCorruptStatus);
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
156
197
|
if (!status || !isTerminalState(status.state) || status.sessionId !== entry.sessionId || (status.runId && status.runId !== entry.runId)) {
|
|
157
198
|
removeInvalidMarker(marker);
|
|
158
199
|
continue;
|
|
@@ -44,6 +44,8 @@ function sealPausedRun(asyncDir, status, resultsDir) {
|
|
|
44
44
|
sessionId: status.sessionId,
|
|
45
45
|
asyncDir,
|
|
46
46
|
...(status.completionOwnerId ? { completionOwnerId: status.completionOwnerId } : {}),
|
|
47
|
+
...(status.completionOwnerProcess ? { completionOwnerProcess: status.completionOwnerProcess } : {}),
|
|
48
|
+
...(status.parentWorkflowRunId ? { parentWorkflowRunId: status.parentWorkflowRunId } : {}),
|
|
47
49
|
...(status.toolCallId ? { toolCallId: status.toolCallId } : {}),
|
|
48
50
|
results: (status.steps ?? []).map((step) => ({
|
|
49
51
|
agent: step.agent,
|
|
@@ -146,7 +148,7 @@ export function stopAsyncRun(state, runId, kill, location, childId) {
|
|
|
146
148
|
if (!target)
|
|
147
149
|
return null;
|
|
148
150
|
const status = reconcileAsyncRun(target.asyncDir, { kill }).status;
|
|
149
|
-
// A
|
|
151
|
+
// A relaunched workflow stops the exact child run it re-attached from its relaunch chain, whichever session launched it.
|
|
150
152
|
if (state.currentSessionId && !ownsRun(state.currentSessionId, status?.sessionId) && location?.reattachedRunId !== target.asyncId) {
|
|
151
153
|
return {
|
|
152
154
|
content: [{ type: "text", text: `Async run '${target.asyncId}' was not found in the active session.` }],
|
|
@@ -46,6 +46,7 @@ import { buildInProcessChildLaunch, createReportedChildSessionInput } from "../s
|
|
|
46
46
|
import { childSessionFactory, childSessionHasQueuedMessages, projectChildSessionEventForJson } from "../shared/child-session.js";
|
|
47
47
|
import { reconcileAttemptUsage } from "../shared/usage-reconciliation.js";
|
|
48
48
|
import { clearProviderRetry, observeProviderDiagnostics, snapshotProviderDiagnostics } from "../../shared/provider-diagnostics.js";
|
|
49
|
+
import { isRexLocalMachine } from "../shared/rex-machine.js";
|
|
49
50
|
const artifactOutputByResult = new WeakMap();
|
|
50
51
|
const acceptanceOutputByResult = new WeakMap();
|
|
51
52
|
function emptyUsage() {
|
|
@@ -441,7 +442,9 @@ async function runSingleAttempt(runtimeCwd, agent, task, model, options, shared)
|
|
|
441
442
|
};
|
|
442
443
|
return result;
|
|
443
444
|
}
|
|
444
|
-
|
|
445
|
+
// A machine 'local' child edits this disk, so its local Git evidence is authoritative, as for an unplaced run.
|
|
446
|
+
const mutationCwd = isRexLocalMachine(options.machine) ? options.machine.cwd : options.cwd ?? runtimeCwd;
|
|
447
|
+
const mutationSnapshot = options.machine && !isRexLocalMachine(options.machine) ? { source: "tracked-files", trackedOnly: true, cwd: mutationCwd, dirtyFiles: [], fingerprints: {}, unavailable: "Local Git evidence is not authoritative for a pane-native remote run." } : snapshotTrackedMutations(mutationCwd);
|
|
445
448
|
let structuredOutputToolInvoked = false;
|
|
446
449
|
let structuredOutputMessageStartIndex;
|
|
447
450
|
let toolAvailabilityError;
|
|
@@ -1259,7 +1262,7 @@ async function runSingleAttempt(runtimeCwd, agent, task, model, options, shared)
|
|
|
1259
1262
|
toolAvailabilityError = toolDiagnosticError;
|
|
1260
1263
|
result.runtimeAcknowledgedExtensions = capture.runtimeAcknowledgedExtensions();
|
|
1261
1264
|
if (session?.machineEvidence)
|
|
1262
|
-
result.nativeMachine = { provider:
|
|
1265
|
+
result.nativeMachine = { provider: session.machineEvidence.provider, machineId: session.machineEvidence.machineId, ...(session.machineEvidence.initial ? { initialGit: session.machineEvidence.initial } : {}), ...(session.machineEvidence.final ? { finalGit: session.machineEvidence.final } : {}) };
|
|
1263
1266
|
let closeError = result.error ?? toolDiagnosticError ?? assistantError;
|
|
1264
1267
|
const promptErrorMessage = promptError === undefined ? undefined : promptError instanceof Error ? promptError.message : String(promptError);
|
|
1265
1268
|
if (promptError !== undefined)
|
|
@@ -1533,7 +1536,7 @@ async function runSingleAttempt(runtimeCwd, agent, task, model, options, shared)
|
|
|
1533
1536
|
durationMs: progress.durationMs,
|
|
1534
1537
|
};
|
|
1535
1538
|
const remoteGitChanged = result.nativeMachine?.initialGit && result.nativeMachine.finalGit ? result.nativeMachine.initialGit.head !== result.nativeMachine.finalGit.head || result.nativeMachine.initialGit.dirty !== result.nativeMachine.finalGit.dirty : undefined;
|
|
1536
|
-
const mutationEvidence = result.nativeMachine ? { source: "tracked-files", trackedOnly: true, changedFiles: [], attemptedMutation: remoteGitChanged === true, ...(remoteGitChanged === undefined ? { unavailable: "Remote Git before/after evidence was incomplete." } : {}) } : collectTrackedMutationEvidence(mutationSnapshot,
|
|
1539
|
+
const mutationEvidence = result.nativeMachine && !isRexLocalMachine(options.machine) ? { source: "tracked-files", trackedOnly: true, changedFiles: [], attemptedMutation: remoteGitChanged === true, ...(remoteGitChanged === undefined ? { unavailable: "Remote Git before/after evidence was incomplete." } : {}) } : collectTrackedMutationEvidence(mutationSnapshot, mutationCwd);
|
|
1537
1540
|
const acceptanceOutput = getFinalOutput(result.messages ?? []);
|
|
1538
1541
|
const structuredText = result.structuredOutput === undefined ? undefined : JSON.stringify(result.structuredOutput, null, 2);
|
|
1539
1542
|
let fullOutput = stripAcceptanceReport(acceptanceOutput);
|
|
@@ -1,11 +1,25 @@
|
|
|
1
|
-
import type { SubagentState } from "../../shared/types.ts";
|
|
1
|
+
import type { ForegroundResumeChild, ForegroundResumeRun, SubagentState } from "../../shared/types.ts";
|
|
2
2
|
export declare const MAX_REMEMBERED_FOREGROUND_RUNS = 50;
|
|
3
|
-
export declare
|
|
3
|
+
export declare const FOREGROUND_OWNER_EXITED_STOP_ERROR = "Subagent stopped because the Pi process that ran it exited before the run finished.";
|
|
4
|
+
/**
|
|
5
|
+
* Saves one foreground run to its own history file. A run with a `running` child is a launch-time
|
|
6
|
+
* record; the run's final save replaces it.
|
|
7
|
+
*/
|
|
8
|
+
export declare function persistForegroundRun(run: ForegroundResumeRun, options?: {
|
|
4
9
|
resultsDir?: string;
|
|
5
10
|
limit?: number;
|
|
6
11
|
}): void;
|
|
12
|
+
/** Drops this process's `running` record for a launch that threw, so it never loads as interrupted. */
|
|
13
|
+
export declare function discardRunningForegroundRun(runId: string, options?: {
|
|
14
|
+
resultsDir?: string;
|
|
15
|
+
}): void;
|
|
16
|
+
/** For a record with a `running` child: its owning Pi process is gone. */
|
|
17
|
+
export declare function ownerConfirmedDead(run: ForegroundResumeRun): boolean;
|
|
18
|
+
/** State text for a remembered child; a child cut off by a Pi exit names the resume target. */
|
|
19
|
+
export declare function foregroundChildStateLabel(run: Pick<ForegroundResumeRun, "runId">, child: Pick<ForegroundResumeChild, "status" | "error" | "sessionFile">): string;
|
|
7
20
|
export declare function restoreForegroundRunHistory(state: SubagentState, options?: {
|
|
8
21
|
resultsDir?: string;
|
|
9
22
|
sessionId?: string | null;
|
|
10
23
|
limit?: number;
|
|
24
|
+
observeForeign?: (run: ForegroundResumeRun) => void;
|
|
11
25
|
}): number;
|