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
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
getAgentDir,
|
|
8
8
|
getConfigDirName,
|
|
9
9
|
getProjectConfigDir
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-CIZQXJ5Q.js";
|
|
11
11
|
import {
|
|
12
12
|
TEMP_ROOT_DIR
|
|
13
13
|
} from "./chunk-5LFLVSTM.js";
|
|
@@ -935,6 +935,15 @@ function formatRuntimeSnapshotMcpServersError(agentName, serverNames) {
|
|
|
935
935
|
const subject = agentName ? `Agent '${agentName}'` : "Subagent";
|
|
936
936
|
return `${subject} selects MCP tools from servers that exist only in pi-mcp-adapter's runtime snapshot (${serverNames.join(", ")}). MCP servers from the runtime snapshot cannot be provided to in-process children; MCP tools must come from an ambient adapter extension in a background child (\`async: true\`), so add the server to the adapter's configuration file instead.`;
|
|
937
937
|
}
|
|
938
|
+
function isToolExtensionPath(entry) {
|
|
939
|
+
return entry.includes("/") || entry.endsWith(".ts") || entry.endsWith(".js");
|
|
940
|
+
}
|
|
941
|
+
function assertNoToolModifierEntries(agentName, tools) {
|
|
942
|
+
const entries = tools.filter((entry) => /^[+-]/u.test(entry) && !isToolExtensionPath(entry));
|
|
943
|
+
if (entries.length === 0) return;
|
|
944
|
+
const subject = agentName ? `Agent '${agentName}'` : "Subagent";
|
|
945
|
+
throw new Error(`${subject} lists Pi tool modifier ${entries.length === 1 ? "entry" : "entries"} in \`tools\`: ${entries.join(", ")}. A child's \`tools\` list is the complete set of tools it gets, so +name and -name entries are not supported; name every tool the child needs, or omit \`tools\` and use \`excludeTools\` to drop one.`);
|
|
946
|
+
}
|
|
938
947
|
function projectLaunchResolvedChildExtensions(toolPlan) {
|
|
939
948
|
const runtime = boundedExtensionIdentifiers(toolPlan.runtimeExtensions);
|
|
940
949
|
const configured = boundedExtensionIdentifiers(toolPlan.configuredExtensions);
|
|
@@ -1014,9 +1023,8 @@ function resolvePiLaunchToolPlan(input) {
|
|
|
1014
1023
|
throw new Error(`Capability ceiling from ${capabilityCeiling.sources.join(", ") || "unknown source"} denies extensions but this host requires: ${requiredExtensions.map(({ id }) => id).join(", ")}.`);
|
|
1015
1024
|
}
|
|
1016
1025
|
const allowedToolSet = capabilityCeiling?.allowedTools === void 0 ? void 0 : new Set(capabilityCeiling.allowedTools);
|
|
1017
|
-
const requestedBuiltinTools = input.tools?.filter(
|
|
1018
|
-
|
|
1019
|
-
) ?? [];
|
|
1026
|
+
const requestedBuiltinTools = input.tools?.filter((tool) => !isToolExtensionPath(tool)) ?? [];
|
|
1027
|
+
assertNoToolModifierEntries(input.agentName, input.tools ?? []);
|
|
1020
1028
|
if (input.requireReadTool && allowedToolSet && !allowedToolSet.has("read")) {
|
|
1021
1029
|
throw new Error(
|
|
1022
1030
|
`Capability ceiling from ${capabilityCeiling?.sources.join(", ") || "unknown source"} excludes required tool 'read' for lazy skill loading.`
|
|
@@ -1031,9 +1039,7 @@ function resolvePiLaunchToolPlan(input) {
|
|
|
1031
1039
|
if (effectiveDeclaredBuiltinTools.includes("subagent_supervisor") && !fanoutAuthorized) {
|
|
1032
1040
|
throw new Error("Tool 'subagent_supervisor' requires fanout authorization: include 'subagent' in the effective tools allowlist or enable allowNestedSubagents.");
|
|
1033
1041
|
}
|
|
1034
|
-
const toolExtensionPaths = capabilityCeiling?.denyExtensions ? [] : (input.tools ?? []).filter(
|
|
1035
|
-
(tool) => !requestedBuiltinTools.includes(tool) && (tool.includes("/") || tool.endsWith(".ts") || tool.endsWith(".js"))
|
|
1036
|
-
);
|
|
1042
|
+
const toolExtensionPaths = capabilityCeiling?.denyExtensions ? [] : (input.tools ?? []).filter(isToolExtensionPath);
|
|
1037
1043
|
const mcpResolution = capabilityCeiling?.denyExtensions ? { selections: [], unresolvedSelectors: [] } : input.builtinMcpTools ? { selections: input.builtinMcpTools, unresolvedSelectors: [], builtin: true } : resolveMcpDirectToolResolution(input.mcpDirectTools, input.cwd, input.runtimeSnapshotHost);
|
|
1038
1044
|
if (mcpResolution.runtimeServerNames?.length) {
|
|
1039
1045
|
throw new Error(formatRuntimeSnapshotMcpServersError(input.agentName, mcpResolution.runtimeServerNames));
|
|
@@ -1114,9 +1120,7 @@ function resolvePiLaunchToolPlan(input) {
|
|
|
1114
1120
|
) ?? [],
|
|
1115
1121
|
internalTools,
|
|
1116
1122
|
extensionsDenied: capabilityCeiling.denyExtensions,
|
|
1117
|
-
removedExtensionCount: capabilityCeiling.denyExtensions ? (input.extensions?.length ?? 0) + (input.subagentOnlyExtensions?.length ?? 0) + (input.tools ?? []).filter(
|
|
1118
|
-
(tool) => tool.includes("/") || tool.endsWith(".ts") || tool.endsWith(".js")
|
|
1119
|
-
).length : 0,
|
|
1123
|
+
removedExtensionCount: capabilityCeiling.denyExtensions ? (input.extensions?.length ?? 0) + (input.subagentOnlyExtensions?.length ?? 0) + (input.tools ?? []).filter(isToolExtensionPath).length : 0,
|
|
1120
1124
|
requestedMcpToolCount: input.mcpDirectTools?.length ?? 0,
|
|
1121
1125
|
effectiveMcpTools,
|
|
1122
1126
|
agentAllowed: input.agentName === void 0 ? true : isAgentAllowedByCapabilityCeiling(
|
|
@@ -1180,6 +1184,7 @@ export {
|
|
|
1180
1184
|
deriveForkPromptCacheKey,
|
|
1181
1185
|
supervisorChannelDir,
|
|
1182
1186
|
applyThinkingSuffix,
|
|
1187
|
+
assertNoToolModifierEntries,
|
|
1183
1188
|
projectLaunchResolvedChildExtensions,
|
|
1184
1189
|
resolvePiLaunchToolPlan
|
|
1185
1190
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
buildWorkflowChatProgressRows
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-FXUXCX2K.js";
|
|
4
4
|
import {
|
|
5
5
|
aggregateStepStatus,
|
|
6
6
|
contextModeBadge,
|
|
@@ -25,13 +25,13 @@ import {
|
|
|
25
25
|
projectWorkflowChecklist,
|
|
26
26
|
withCachedUiContext,
|
|
27
27
|
workflowGraphStageNodes
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-6XJB7PIX.js";
|
|
29
29
|
import {
|
|
30
30
|
flatToLogicalStepIndex,
|
|
31
31
|
formatWorkflowJsonPreview,
|
|
32
32
|
hostStepReportName,
|
|
33
33
|
hostStepVerdictLabel
|
|
34
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-46XKCPJR.js";
|
|
35
35
|
import {
|
|
36
36
|
snapshotExternalRuns
|
|
37
37
|
} from "./chunk-UKG4V45O.js";
|
|
@@ -49,7 +49,7 @@ import {
|
|
|
49
49
|
getSingleResultOutput,
|
|
50
50
|
shortenPath,
|
|
51
51
|
unresolvedChildWatchdogBlockers
|
|
52
|
-
} from "./chunk-
|
|
52
|
+
} from "./chunk-CIZQXJ5Q.js";
|
|
53
53
|
import {
|
|
54
54
|
MAX_WIDGET_JOBS,
|
|
55
55
|
WIDGET_ANIMATION_INTERVAL_MS,
|
|
@@ -1029,12 +1029,11 @@ function shouldCollapseSingleChildDetails(job, step) {
|
|
|
1029
1029
|
if (job.status === "complete") return isCompletedWidgetStepStatus(step.status);
|
|
1030
1030
|
return false;
|
|
1031
1031
|
}
|
|
1032
|
-
function
|
|
1032
|
+
function stepTaskSummary(step, agentName) {
|
|
1033
1033
|
const task = compactTaskText(step.description, step.label);
|
|
1034
1034
|
if (task) return task;
|
|
1035
1035
|
const sessionName = step.sessionName?.trim();
|
|
1036
1036
|
if (!sessionName) return void 0;
|
|
1037
|
-
const agentName = singleChildAgentName(job, step);
|
|
1038
1037
|
const sessionTask = stripRepeatedAgentPrefix(sessionName, agentName);
|
|
1039
1038
|
return sessionTask === agentName ? void 0 : compactTaskText(sessionTask);
|
|
1040
1039
|
}
|
|
@@ -1952,7 +1951,7 @@ function foregroundStyleWidgetStepLines(job, theme, step, itemTitle, index, tota
|
|
|
1952
1951
|
const lines = [`${rowIndent}${rowMarker}${widgetStepGlyph(step.status, theme, widgetStepRunningSeed(step, index - 1), frame, thinking)} ${themeBold(theme, rowLabel)}${contextModeBadge(theme, step.context)} ${theme.fg("dim", "\xB7")} ${status}${modelDisplay}${stats ? ` ${theme.fg("dim", "\xB7")} ${stats}` : ""}`];
|
|
1953
1952
|
const lane = projectAsyncLane(job, step);
|
|
1954
1953
|
if (lane) lines.push(...formatLaneProjectionLines(lane, theme, detailIndent));
|
|
1955
|
-
const task = collapseDetails ?
|
|
1954
|
+
const task = collapseDetails ? stepTaskSummary(step, displayName) : compactTaskText(step.description, step.label);
|
|
1956
1955
|
if (task) lines.push(`${detailIndent}${theme.fg("dim", `task: ${task}`)}`);
|
|
1957
1956
|
const activity = widgetStepActivityLine(step, width, expanded, job.updatedAt);
|
|
1958
1957
|
const currentPath = options?.includeCurrentPath && step.currentPath ? shortenPath(step.currentPath) : void 0;
|
|
@@ -4153,6 +4152,7 @@ export {
|
|
|
4153
4152
|
buildAsyncStatusSnapshotForState,
|
|
4154
4153
|
clearLegacyResultAnimationTimer,
|
|
4155
4154
|
widgetRenderKey,
|
|
4155
|
+
stepTaskSummary,
|
|
4156
4156
|
setInlineWorkflowCoverage,
|
|
4157
4157
|
renderWidget,
|
|
4158
4158
|
renderSubagentSummary,
|
|
@@ -3,11 +3,11 @@ import {
|
|
|
3
3
|
} from "./chunk-7J4ZXMY7.js";
|
|
4
4
|
import {
|
|
5
5
|
getProjectSubagentsDir
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-5TYMSZX3.js";
|
|
7
7
|
import {
|
|
8
8
|
getPiSpawnCommand,
|
|
9
9
|
writeAtomicJson
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-CIZQXJ5Q.js";
|
|
11
11
|
|
|
12
12
|
// src/inspectors/herdr/project-panes.ts
|
|
13
13
|
import * as fs from "node:fs";
|
|
@@ -39,10 +39,10 @@ import {
|
|
|
39
39
|
validateModelResponseAliases,
|
|
40
40
|
withWorkflowChildRunModel,
|
|
41
41
|
withWorktreeTransaction
|
|
42
|
-
} from "./chunk-
|
|
42
|
+
} from "./chunk-46XKCPJR.js";
|
|
43
43
|
import {
|
|
44
44
|
validateIntercomBridgeConfig
|
|
45
|
-
} from "./chunk-
|
|
45
|
+
} from "./chunk-XSWOTIA3.js";
|
|
46
46
|
import {
|
|
47
47
|
stableJsonDigest
|
|
48
48
|
} from "./chunk-7F6RKT6W.js";
|
|
@@ -73,7 +73,7 @@ import {
|
|
|
73
73
|
validateToolBudgetConfig,
|
|
74
74
|
waitForFileSystemRetry,
|
|
75
75
|
writeAtomicJson
|
|
76
|
-
} from "./chunk-
|
|
76
|
+
} from "./chunk-CIZQXJ5Q.js";
|
|
77
77
|
import {
|
|
78
78
|
DIRS,
|
|
79
79
|
RUNNER_LAUNCHER_NAME_PATTERN,
|
|
@@ -2133,6 +2133,7 @@ function isAsyncStatusIsolationError(asyncDir, error) {
|
|
|
2133
2133
|
const message = getErrorMessage(error);
|
|
2134
2134
|
return /^(?:Failed to (?:inspect|read|parse|validate) async status file|Invalid async status file) '/.test(message) || message.startsWith(`Invalid async status '${statusPath}'`) || message.startsWith(`Invalid host step '${statusPath}`) || /^(workflowChildren|Invalid workflowChildren)/.test(message);
|
|
2135
2135
|
}
|
|
2136
|
+
var reportedCorruptStatus = /* @__PURE__ */ new Map();
|
|
2136
2137
|
function isolateCorruptActiveRun(asyncDir, runId, error, now) {
|
|
2137
2138
|
const statusPath = path3.join(asyncDir, "status.json");
|
|
2138
2139
|
const processTerminal = readProcessTerminal(asyncDir, { runId });
|
|
@@ -2152,7 +2153,18 @@ function isolateCorruptActiveRun(asyncDir, runId, error, now) {
|
|
|
2152
2153
|
markerAction = `failed to release active marker: ${getErrorMessage(releaseError)}`;
|
|
2153
2154
|
}
|
|
2154
2155
|
}
|
|
2155
|
-
|
|
2156
|
+
const line = `[pi-subagents] Skipping corrupt active async run '${runId}' at '${statusPath}': ${getErrorMessage(error)}; ${markerAction}.`;
|
|
2157
|
+
let fileSignature = "";
|
|
2158
|
+
try {
|
|
2159
|
+
const stat = fs3.statSync(statusPath);
|
|
2160
|
+
fileSignature = `${stat.size}:${stat.mtimeMs}`;
|
|
2161
|
+
} catch {
|
|
2162
|
+
}
|
|
2163
|
+
const signature = `${fileSignature}
|
|
2164
|
+
${line}`;
|
|
2165
|
+
if (reportedCorruptStatus.get(statusPath) === signature) return;
|
|
2166
|
+
reportedCorruptStatus.set(statusPath, signature);
|
|
2167
|
+
console.error(line);
|
|
2156
2168
|
}
|
|
2157
2169
|
function isNotFoundError(error) {
|
|
2158
2170
|
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
@@ -2442,7 +2454,7 @@ function listAsyncRuns(asyncDirRoot, options = {}, observeStatus) {
|
|
|
2442
2454
|
}
|
|
2443
2455
|
if (wantsTerminal) {
|
|
2444
2456
|
for (const sessionId of owners ?? [void 0]) {
|
|
2445
|
-
for (const entry of readRecentTerminalRunIndex(asyncDirRoot, { sessionId, ...options.entryLimit !== void 0 ? { limit: options.entryLimit } : {} })) indexed.add(entry);
|
|
2457
|
+
for (const entry of readRecentTerminalRunIndex(asyncDirRoot, { sessionId, onCorruptStatus: options.onCorruptStatus, ...options.entryLimit !== void 0 ? { limit: options.entryLimit } : {} })) indexed.add(entry);
|
|
2446
2458
|
}
|
|
2447
2459
|
}
|
|
2448
2460
|
entries = [...indexed];
|
|
@@ -2467,14 +2479,16 @@ function listAsyncRuns(asyncDirRoot, options = {}, observeStatus) {
|
|
|
2467
2479
|
const asyncDir = path3.join(asyncDirRoot, entry);
|
|
2468
2480
|
let status;
|
|
2469
2481
|
try {
|
|
2482
|
+
let owned = false;
|
|
2470
2483
|
if (owners) {
|
|
2471
2484
|
const stored = readStatus(asyncDir);
|
|
2472
2485
|
if (stored && !owners.has(stored.sessionId)) {
|
|
2473
2486
|
observeStatus?.(stored);
|
|
2474
2487
|
continue;
|
|
2475
2488
|
}
|
|
2489
|
+
owned = stored !== null;
|
|
2476
2490
|
}
|
|
2477
|
-
const reconciliation = options.reconcile === false ? void 0 : reconcileAsyncRun(asyncDir, { resultsDir: options.resultsDir, kill: options.kill, now: options.now }, observeStatus);
|
|
2491
|
+
const reconciliation = options.reconcile === false ? void 0 : reconcileAsyncRun(asyncDir, { resultsDir: options.resultsDir, kill: options.kill, now: options.now, adoptCompletionOwnerId: owned ? options.adoptCompletionOwnerId : void 0 }, observeStatus);
|
|
2478
2492
|
status = reconciliation?.status ?? readStatus(asyncDir);
|
|
2479
2493
|
if (options.reconcile === false) observeStatus?.(status);
|
|
2480
2494
|
} catch (error) {
|
|
@@ -307,6 +307,15 @@ function parseFrontmatterList(raw) {
|
|
|
307
307
|
return item.split(",");
|
|
308
308
|
}).map((value) => value.trim()).filter(Boolean);
|
|
309
309
|
}
|
|
310
|
+
function unquoteName(value) {
|
|
311
|
+
if (value.length >= 2 && (value.startsWith("'") && value.endsWith("'") || value.startsWith('"') && value.endsWith('"'))) {
|
|
312
|
+
return value.slice(1, -1);
|
|
313
|
+
}
|
|
314
|
+
return value;
|
|
315
|
+
}
|
|
316
|
+
function parseUnquotedList(raw) {
|
|
317
|
+
return parseFrontmatterList(raw)?.map(unquoteName);
|
|
318
|
+
}
|
|
310
319
|
function parseFrontmatter(content) {
|
|
311
320
|
const frontmatter = {};
|
|
312
321
|
const normalized = content.replace(/\r\n/g, "\n");
|
|
@@ -350,7 +359,10 @@ function parseFrontmatter(content) {
|
|
|
350
359
|
const [key, rawValueValue] = match.slice(1);
|
|
351
360
|
if (key === void 0 || rawValueValue === void 0) continue;
|
|
352
361
|
const rawValue = rawValueValue.trim();
|
|
353
|
-
const
|
|
362
|
+
const quote = rawValue[0];
|
|
363
|
+
const nameList = key === "tools" || key === "excludeTools" || key === "mutationTools" || key === "extensions" || key === "subagentOnlyExtensions";
|
|
364
|
+
const quotedList = nameList && (quote === '"' || quote === "'") && (rawValue.includes(`${quote},`) || rawValue.includes(`, ${quote}`));
|
|
365
|
+
const isQuoted = !quotedList && (quote === '"' || quote === "'") && rawValue.endsWith(quote);
|
|
354
366
|
const value = isQuoted ? rawValue.slice(1, -1) : rawValue;
|
|
355
367
|
const isFolded = !isQuoted && (rawValue === ">" || rawValue === ">-");
|
|
356
368
|
const isLiteral = !isQuoted && (rawValue === "|" || rawValue === "|-");
|
|
@@ -4045,7 +4057,8 @@ function readMemoryFile(memoryDir) {
|
|
|
4045
4057
|
let fd;
|
|
4046
4058
|
try {
|
|
4047
4059
|
const noFollow = typeof fs9.constants.O_NOFOLLOW === "number" ? fs9.constants.O_NOFOLLOW : 0;
|
|
4048
|
-
|
|
4060
|
+
const nonBlock = typeof fs9.constants.O_NONBLOCK === "number" ? fs9.constants.O_NONBLOCK : 0;
|
|
4061
|
+
fd = fs9.openSync(file, fs9.constants.O_RDONLY | noFollow | nonBlock);
|
|
4049
4062
|
} catch (error) {
|
|
4050
4063
|
const code = error && typeof error === "object" && "code" in error ? String(error.code) : "";
|
|
4051
4064
|
return code === "ELOOP" ? "unsafe" : null;
|
|
@@ -5691,11 +5704,11 @@ function loadAgentsFromDefinitionFiles(files, source, discoveryPriority, package
|
|
|
5691
5704
|
else if (frontmatter.advertise === "false") advertise = false;
|
|
5692
5705
|
else throw new Error(`Agent '${localName}' has invalid advertise frontmatter; expected true or false.`);
|
|
5693
5706
|
}
|
|
5694
|
-
const rawTools =
|
|
5707
|
+
const rawTools = parseUnquotedList(frontmatter.tools);
|
|
5695
5708
|
const parsedTools = splitToolList(rawTools);
|
|
5696
5709
|
const tools = parsedTools.tools ?? [];
|
|
5697
5710
|
const mcpDirectTools = parsedTools.mcpDirectTools ?? [];
|
|
5698
|
-
const excludeTools =
|
|
5711
|
+
const excludeTools = parseUnquotedList(frontmatter.excludeTools);
|
|
5699
5712
|
const parsedAllowedAgents = parseFrontmatterList(frontmatter.allowedAgents);
|
|
5700
5713
|
const allowedAgents = parsedAllowedAgents === void 0 ? void 0 : normalizeCapabilityCeilingAllowedAgents(parsedAllowedAgents);
|
|
5701
5714
|
const defaultReads = parseFrontmatterList(frontmatter.defaultReads);
|
|
@@ -5744,9 +5757,9 @@ function loadAgentsFromDefinitionFiles(files, source, discoveryPriority, package
|
|
|
5744
5757
|
if (frontmatter.acceptanceRole === "read-only" || frontmatter.acceptanceRole === "writer") acceptanceRole = frontmatter.acceptanceRole;
|
|
5745
5758
|
else throw new Error(`Agent '${localName}' has invalid acceptanceRole frontmatter; expected 'read-only' or 'writer'.`);
|
|
5746
5759
|
}
|
|
5747
|
-
const extensions = resolveAgentRelativeExtensionPaths(
|
|
5748
|
-
const subagentOnlyExtensions = resolveAgentRelativeExtensionPaths(
|
|
5749
|
-
const mutationTools =
|
|
5760
|
+
const extensions = resolveAgentRelativeExtensionPaths(parseUnquotedList(frontmatter.extensions), filePath);
|
|
5761
|
+
const subagentOnlyExtensions = resolveAgentRelativeExtensionPaths(parseUnquotedList(frontmatter.subagentOnlyExtensions), filePath);
|
|
5762
|
+
const mutationTools = parseUnquotedList(frontmatter.mutationTools);
|
|
5750
5763
|
let fast;
|
|
5751
5764
|
if (frontmatter.fast !== void 0) {
|
|
5752
5765
|
if (frontmatter.fast === "true") fast = true;
|
|
@@ -7824,7 +7837,7 @@ function readOptionalJsonFile(filePath, label) {
|
|
|
7824
7837
|
return JSON.parse(fs15.readFileSync(filePath, "utf-8"));
|
|
7825
7838
|
} catch (error) {
|
|
7826
7839
|
const code = typeof error === "object" && error !== null && "code" in error ? error.code : void 0;
|
|
7827
|
-
if (code === "ENOENT") return null;
|
|
7840
|
+
if (code === "ENOENT" || code === "ENOTDIR") return null;
|
|
7828
7841
|
const message = error instanceof Error ? error.message : String(error);
|
|
7829
7842
|
throw new Error(`Failed to read ${label} '${filePath}': ${message}`, {
|
|
7830
7843
|
cause: error instanceof Error ? error : void 0
|
|
@@ -8393,7 +8406,7 @@ export {
|
|
|
8393
8406
|
resolveExternalCliRunnerStatus,
|
|
8394
8407
|
normalizeExternalCliRunnerStatus,
|
|
8395
8408
|
externalCliReceiptMetadata,
|
|
8396
|
-
|
|
8409
|
+
parseUnquotedList,
|
|
8397
8410
|
parseFrontmatter,
|
|
8398
8411
|
resolveSkills,
|
|
8399
8412
|
resolveSkillsWithFallback,
|
|
@@ -11,11 +11,15 @@ import {
|
|
|
11
11
|
resolveAsyncStatusChild,
|
|
12
12
|
stopStoppableAsyncStatusChildren,
|
|
13
13
|
summarizeContextModes,
|
|
14
|
+
utf8Tail,
|
|
14
15
|
workflowPreflightLaneForRuntimeKey
|
|
15
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-6XJB7PIX.js";
|
|
16
17
|
import {
|
|
17
18
|
assertSafeNestedId,
|
|
19
|
+
checkRecordedPidLiveness,
|
|
20
|
+
encodeIndexSegment,
|
|
18
21
|
findNestedRunMatchesById,
|
|
22
|
+
isRecordedPid,
|
|
19
23
|
readActiveRunToolCallIndex,
|
|
20
24
|
readProcessTerminal,
|
|
21
25
|
readTerminalRunToolCallIndex,
|
|
@@ -26,12 +30,13 @@ import {
|
|
|
26
30
|
resultPayloadPathForIndexedRun,
|
|
27
31
|
resultPayloadPathForSessionRun,
|
|
28
32
|
updateActiveRunIndex,
|
|
33
|
+
validateModelResponseAliases,
|
|
29
34
|
writeAsyncResultFile
|
|
30
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-46XKCPJR.js";
|
|
31
36
|
import {
|
|
32
37
|
deliverStopRequest,
|
|
33
38
|
stopInboxClosedPath
|
|
34
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-OYF6AFDY.js";
|
|
35
40
|
import {
|
|
36
41
|
SUBAGENT_STOPPED_MESSAGE,
|
|
37
42
|
formatDuration,
|
|
@@ -39,8 +44,10 @@ import {
|
|
|
39
44
|
formatTokens,
|
|
40
45
|
readStatus,
|
|
41
46
|
shortenPath,
|
|
42
|
-
|
|
43
|
-
|
|
47
|
+
validateAcceptanceInput,
|
|
48
|
+
writeAtomicJson,
|
|
49
|
+
writePrivateAtomicJson
|
|
50
|
+
} from "./chunk-CIZQXJ5Q.js";
|
|
44
51
|
import {
|
|
45
52
|
DIRS
|
|
46
53
|
} from "./chunk-5LFLVSTM.js";
|
|
@@ -49,15 +56,6 @@ import {
|
|
|
49
56
|
truncateDisplayText
|
|
50
57
|
} from "./chunk-YFCK7H2S.js";
|
|
51
58
|
|
|
52
|
-
// src/shared/completion-owner.ts
|
|
53
|
-
import { randomUUID } from "node:crypto";
|
|
54
|
-
var COMPLETION_OWNER_KEY = /* @__PURE__ */ Symbol.for("pi-subagents.completion-owner-id");
|
|
55
|
-
function currentCompletionOwnerId() {
|
|
56
|
-
const runtime = globalThis;
|
|
57
|
-
runtime[COMPLETION_OWNER_KEY] ??= randomUUID();
|
|
58
|
-
return runtime[COMPLETION_OWNER_KEY];
|
|
59
|
-
}
|
|
60
|
-
|
|
61
59
|
// src/workflows/chat-progress.ts
|
|
62
60
|
import { spawnSync } from "node:child_process";
|
|
63
61
|
import * as fs from "node:fs";
|
|
@@ -411,8 +409,8 @@ function formatDetachedForegroundFleetLines(runs) {
|
|
|
411
409
|
}
|
|
412
410
|
function externalCliStepFacts(step, now) {
|
|
413
411
|
if (step.runner?.type !== "external-cli") return void 0;
|
|
414
|
-
const
|
|
415
|
-
const elapsed =
|
|
412
|
+
const process2 = step.externalProcess;
|
|
413
|
+
const elapsed = process2 ? process2.durationMs ?? Math.max(0, (process2.endedAt ?? now) - process2.startedAt) : void 0;
|
|
416
414
|
return `external-cli${elapsed !== void 0 ? ` \xB7 ${formatDuration(elapsed)}` : ""}`;
|
|
417
415
|
}
|
|
418
416
|
function formatAsyncFleetLines(runs, now = Date.now()) {
|
|
@@ -861,6 +859,8 @@ function sealPausedRun(asyncDir, status, resultsDir) {
|
|
|
861
859
|
sessionId: status.sessionId,
|
|
862
860
|
asyncDir,
|
|
863
861
|
...status.completionOwnerId ? { completionOwnerId: status.completionOwnerId } : {},
|
|
862
|
+
...status.completionOwnerProcess ? { completionOwnerProcess: status.completionOwnerProcess } : {},
|
|
863
|
+
...status.parentWorkflowRunId ? { parentWorkflowRunId: status.parentWorkflowRunId } : {},
|
|
864
864
|
...status.toolCallId ? { toolCallId: status.toolCallId } : {},
|
|
865
865
|
results: (status.steps ?? []).map((step) => ({
|
|
866
866
|
agent: step.agent,
|
|
@@ -1010,8 +1010,209 @@ function stopAsyncRun(state, runId, kill, location, childId) {
|
|
|
1010
1010
|
}
|
|
1011
1011
|
}
|
|
1012
1012
|
|
|
1013
|
+
// src/runs/foreground/foreground-history.ts
|
|
1014
|
+
import * as fs6 from "node:fs";
|
|
1015
|
+
import * as path6 from "node:path";
|
|
1016
|
+
var MAX_REMEMBERED_FOREGROUND_RUNS = 50;
|
|
1017
|
+
var FOREGROUND_OWNER_EXITED_STOP_ERROR = "Subagent stopped because the Pi process that ran it exited before the run finished.";
|
|
1018
|
+
var MAX_INLINE_OUTPUT_BYTES = 64 * 1024;
|
|
1019
|
+
var MAX_RESUME_CONTRACT_BYTES = 64 * 1024;
|
|
1020
|
+
function historyDir(resultsDir) {
|
|
1021
|
+
return path6.join(resultsDir, "foreground-history");
|
|
1022
|
+
}
|
|
1023
|
+
function runHistoryPath(resultsDir, runId) {
|
|
1024
|
+
return path6.join(historyDir(resultsDir), `${encodeIndexSegment(runId)}.json`);
|
|
1025
|
+
}
|
|
1026
|
+
function boundedTail(value) {
|
|
1027
|
+
return utf8Tail(value, MAX_INLINE_OUTPUT_BYTES).text;
|
|
1028
|
+
}
|
|
1029
|
+
function compactChild(child) {
|
|
1030
|
+
const outputPath = child.artifactPaths?.outputPath ?? child.savedOutputPath;
|
|
1031
|
+
return {
|
|
1032
|
+
agent: child.agent,
|
|
1033
|
+
index: child.index,
|
|
1034
|
+
...child.sessionName ? { sessionName: child.sessionName } : {},
|
|
1035
|
+
...child.context ? { context: child.context } : {},
|
|
1036
|
+
...child.sessionFile ? { sessionFile: child.sessionFile } : {},
|
|
1037
|
+
...child.model ? { model: child.model } : {},
|
|
1038
|
+
...child.thinking ? { thinking: child.thinking } : {},
|
|
1039
|
+
status: child.status,
|
|
1040
|
+
...child.activityState ? { activityState: child.activityState } : {},
|
|
1041
|
+
...child.lastActivityAt !== void 0 ? { lastActivityAt: child.lastActivityAt } : {},
|
|
1042
|
+
...child.currentTool ? { currentTool: child.currentTool } : {},
|
|
1043
|
+
...child.currentToolStartedAt !== void 0 ? { currentToolStartedAt: child.currentToolStartedAt } : {},
|
|
1044
|
+
...child.currentPath ? { currentPath: child.currentPath } : {},
|
|
1045
|
+
...child.turnCount !== void 0 ? { turnCount: child.turnCount } : {},
|
|
1046
|
+
...child.tokens !== void 0 ? { tokens: child.tokens } : {},
|
|
1047
|
+
...child.toolCount !== void 0 ? { toolCount: child.toolCount } : {},
|
|
1048
|
+
...child.exitCode !== void 0 ? { exitCode: child.exitCode } : {},
|
|
1049
|
+
...child.error ? { error: child.error } : {},
|
|
1050
|
+
...!outputPath && child.finalOutput ? { finalOutput: boundedTail(child.finalOutput) } : {},
|
|
1051
|
+
...child.outputState ? { outputState: child.outputState } : {},
|
|
1052
|
+
...child.outputPartial ? { outputPartial: true } : {},
|
|
1053
|
+
...child.outputMode ? { outputMode: child.outputMode } : {},
|
|
1054
|
+
...child.savedOutputPath ? { savedOutputPath: child.savedOutputPath } : {},
|
|
1055
|
+
...child.outputSaveError ? { outputSaveError: child.outputSaveError } : {},
|
|
1056
|
+
...child.artifactPaths ? { artifactPaths: child.artifactPaths } : {},
|
|
1057
|
+
...child.transcriptPath ? { transcriptPath: child.transcriptPath } : {},
|
|
1058
|
+
...child.transcriptError ? { transcriptError: child.transcriptError } : {},
|
|
1059
|
+
...child.acceptance ? { acceptance: child.acceptance } : {},
|
|
1060
|
+
...child.resumeContract ? { resumeContract: child.resumeContract } : {},
|
|
1061
|
+
...child.launchContractDigest ? { launchContractDigest: child.launchContractDigest } : {},
|
|
1062
|
+
...child.extensionBindings ? { extensionBindings: child.extensionBindings } : {},
|
|
1063
|
+
...child.requiredExtensions ? { requiredExtensions: child.requiredExtensions } : {},
|
|
1064
|
+
...child.capabilityCeiling ? { capabilityCeiling: child.capabilityCeiling } : {},
|
|
1065
|
+
...child.updatedAt !== void 0 ? { updatedAt: child.updatedAt } : {}
|
|
1066
|
+
};
|
|
1067
|
+
}
|
|
1068
|
+
function isRestorableForegroundStatus(status) {
|
|
1069
|
+
return status === "completed" || status === "failed" || status === "paused" || status === "stopped";
|
|
1070
|
+
}
|
|
1071
|
+
function hasRunningChild(run) {
|
|
1072
|
+
return run.children.some((child) => child.status === "running");
|
|
1073
|
+
}
|
|
1074
|
+
function isAdmittedChildStatus(run, status) {
|
|
1075
|
+
return isRestorableForegroundStatus(status) || status === "running" && run.mode === "single" && isRecordedPid(run.owner);
|
|
1076
|
+
}
|
|
1077
|
+
function isRestorableResumeContract(value) {
|
|
1078
|
+
if (value === void 0) return true;
|
|
1079
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
1080
|
+
try {
|
|
1081
|
+
if (Buffer.byteLength(JSON.stringify(value), "utf8") > MAX_RESUME_CONTRACT_BYTES) return false;
|
|
1082
|
+
validateModelResponseAliases(value?.modelResponseAliases);
|
|
1083
|
+
} catch {
|
|
1084
|
+
return false;
|
|
1085
|
+
}
|
|
1086
|
+
const contract = value;
|
|
1087
|
+
if (Object.keys(contract).some((key) => !["modelResponseAliases", "outputSchema", "agentContract", "acceptance", "output", "outputMode"].includes(key))) return false;
|
|
1088
|
+
if (contract.outputSchema !== void 0 && contract.outputSchema !== false && (!contract.outputSchema || typeof contract.outputSchema !== "object" || Array.isArray(contract.outputSchema))) return false;
|
|
1089
|
+
if (contract.agentContract !== void 0 && (!contract.agentContract || typeof contract.agentContract !== "object" || Array.isArray(contract.agentContract) || contract.agentContract.version !== 1)) return false;
|
|
1090
|
+
if (validateAcceptanceInput(contract.acceptance).length > 0) return false;
|
|
1091
|
+
if (contract.output !== void 0 && typeof contract.output !== "string" && typeof contract.output !== "boolean") return false;
|
|
1092
|
+
return contract.outputMode === void 0 || contract.outputMode === "inline" || contract.outputMode === "file-only";
|
|
1093
|
+
}
|
|
1094
|
+
function compactRun(run) {
|
|
1095
|
+
if (!run.sessionId) return void 0;
|
|
1096
|
+
if (run.children.length === 0 || !run.children.every((child) => isAdmittedChildStatus(run, child.status) && isRestorableResumeContract(child.resumeContract))) return void 0;
|
|
1097
|
+
const running = hasRunningChild(run);
|
|
1098
|
+
return {
|
|
1099
|
+
runId: run.runId,
|
|
1100
|
+
mode: run.mode,
|
|
1101
|
+
cwd: run.cwd,
|
|
1102
|
+
sessionId: run.sessionId,
|
|
1103
|
+
updatedAt: run.updatedAt,
|
|
1104
|
+
children: run.children.map(compactChild),
|
|
1105
|
+
...running ? { owner: run.owner } : {},
|
|
1106
|
+
...run.parentWorkflowRunId ? { parentWorkflowRunId: run.parentWorkflowRunId } : {}
|
|
1107
|
+
};
|
|
1108
|
+
}
|
|
1109
|
+
function readRunFile(filePath) {
|
|
1110
|
+
try {
|
|
1111
|
+
const parsed = JSON.parse(fs6.readFileSync(filePath, "utf-8"));
|
|
1112
|
+
return isRestorableRun(parsed) ? parsed : void 0;
|
|
1113
|
+
} catch {
|
|
1114
|
+
return void 0;
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
function historyFiles(dir) {
|
|
1118
|
+
try {
|
|
1119
|
+
return fs6.readdirSync(dir).filter((name) => name.endsWith(".json"));
|
|
1120
|
+
} catch {
|
|
1121
|
+
return [];
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
function isRestorableRun(value) {
|
|
1125
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
1126
|
+
const run = value;
|
|
1127
|
+
return typeof run.runId === "string" && Boolean(run.runId) && (run.mode === "single" || run.mode === "parallel" || run.mode === "chain") && typeof run.cwd === "string" && Boolean(run.cwd) && typeof run.sessionId === "string" && Boolean(run.sessionId) && typeof run.updatedAt === "number" && Number.isFinite(run.updatedAt) && Array.isArray(run.children) && run.children.length > 0 && (run.owner === void 0 || isRecordedPid(run.owner)) && (run.parentWorkflowRunId === void 0 || typeof run.parentWorkflowRunId === "string") && run.children.every((child) => Boolean(child && typeof child === "object" && !Array.isArray(child) && typeof child.agent === "string" && typeof child.index === "number" && isRestorableResumeContract(child.resumeContract) && isAdmittedChildStatus(run, child.status)));
|
|
1128
|
+
}
|
|
1129
|
+
function pruneHistory(dir, limit) {
|
|
1130
|
+
const files = historyFiles(dir);
|
|
1131
|
+
if (files.length <= limit) return;
|
|
1132
|
+
const byAge = files.flatMap((name) => {
|
|
1133
|
+
try {
|
|
1134
|
+
return [{ name, mtimeMs: fs6.statSync(path6.join(dir, name)).mtimeMs }];
|
|
1135
|
+
} catch {
|
|
1136
|
+
return [];
|
|
1137
|
+
}
|
|
1138
|
+
}).sort((left, right) => left.mtimeMs - right.mtimeMs);
|
|
1139
|
+
for (const { name, mtimeMs } of byAge.slice(0, byAge.length - limit)) {
|
|
1140
|
+
const filePath = path6.join(dir, name);
|
|
1141
|
+
const run = readRunFile(filePath);
|
|
1142
|
+
if (run && hasRunningChild(run) && !ownerConfirmedDead(run)) continue;
|
|
1143
|
+
try {
|
|
1144
|
+
if (fs6.statSync(filePath).mtimeMs !== mtimeMs) continue;
|
|
1145
|
+
} catch {
|
|
1146
|
+
continue;
|
|
1147
|
+
}
|
|
1148
|
+
fs6.rmSync(filePath, { force: true });
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1151
|
+
function persistForegroundRun(run, options = {}) {
|
|
1152
|
+
const compact = compactRun(run);
|
|
1153
|
+
if (!compact) return;
|
|
1154
|
+
const resultsDir = options.resultsDir ?? DIRS.results;
|
|
1155
|
+
const dir = historyDir(resultsDir);
|
|
1156
|
+
if (!fs6.existsSync(dir)) {
|
|
1157
|
+
fs6.mkdirSync(dir, { recursive: true });
|
|
1158
|
+
fs6.rmSync(path6.join(resultsDir, "foreground-history.json"), { force: true });
|
|
1159
|
+
}
|
|
1160
|
+
writePrivateAtomicJson(runHistoryPath(resultsDir, compact.runId), compact);
|
|
1161
|
+
pruneHistory(dir, options.limit ?? MAX_REMEMBERED_FOREGROUND_RUNS);
|
|
1162
|
+
}
|
|
1163
|
+
function discardRunningForegroundRun(runId, options = {}) {
|
|
1164
|
+
const filePath = runHistoryPath(options.resultsDir ?? DIRS.results, runId);
|
|
1165
|
+
const run = readRunFile(filePath);
|
|
1166
|
+
if (run && hasRunningChild(run) && run.owner?.pid === process.pid) fs6.rmSync(filePath, { force: true });
|
|
1167
|
+
}
|
|
1168
|
+
function ownerConfirmedDead(run) {
|
|
1169
|
+
return checkRecordedPidLiveness(run.owner) === "dead";
|
|
1170
|
+
}
|
|
1171
|
+
function restoreInterruptedRun(run) {
|
|
1172
|
+
if (!ownerConfirmedDead(run)) return void 0;
|
|
1173
|
+
const { owner: _owner, ...rest } = run;
|
|
1174
|
+
return {
|
|
1175
|
+
...rest,
|
|
1176
|
+
children: run.children.map((child) => {
|
|
1177
|
+
if (child.status !== "running") return child;
|
|
1178
|
+
const { activityState: _activityState, currentTool: _currentTool, currentToolStartedAt: _currentToolStartedAt, currentPath: _currentPath, sessionFile, ...stopped } = child;
|
|
1179
|
+
return {
|
|
1180
|
+
...stopped,
|
|
1181
|
+
status: "stopped",
|
|
1182
|
+
exitCode: 1,
|
|
1183
|
+
error: FOREGROUND_OWNER_EXITED_STOP_ERROR,
|
|
1184
|
+
finalOutput: FOREGROUND_OWNER_EXITED_STOP_ERROR,
|
|
1185
|
+
...sessionFile && fs6.existsSync(sessionFile) ? { sessionFile } : {}
|
|
1186
|
+
};
|
|
1187
|
+
})
|
|
1188
|
+
};
|
|
1189
|
+
}
|
|
1190
|
+
function foregroundChildStateLabel(run, child) {
|
|
1191
|
+
if (child.status !== "stopped" || child.error !== FOREGROUND_OWNER_EXITED_STOP_ERROR) return child.status;
|
|
1192
|
+
return child.sessionFile ? `interrupted when Pi exited \xB7 resume ${run.runId}` : "interrupted when Pi exited";
|
|
1193
|
+
}
|
|
1194
|
+
function restoreForegroundRunHistory(state, options = {}) {
|
|
1195
|
+
const sessionId = options.sessionId ?? state.currentSessionId;
|
|
1196
|
+
if (!sessionId) return 0;
|
|
1197
|
+
const dir = historyDir(options.resultsDir ?? DIRS.results);
|
|
1198
|
+
const saved = historyFiles(dir).flatMap((name) => readRunFile(path6.join(dir, name)) ?? []);
|
|
1199
|
+
if (options.observeForeign) {
|
|
1200
|
+
for (const run of saved) if (run.sessionId !== sessionId && hasRunningChild(run)) options.observeForeign(run);
|
|
1201
|
+
}
|
|
1202
|
+
const runs = saved.filter((run) => run.sessionId === sessionId).sort((left, right) => right.updatedAt - left.updatedAt).slice(0, options.limit ?? MAX_REMEMBERED_FOREGROUND_RUNS);
|
|
1203
|
+
state.foregroundRuns ??= /* @__PURE__ */ new Map();
|
|
1204
|
+
let restored = 0;
|
|
1205
|
+
for (const run of runs) {
|
|
1206
|
+
if (state.foregroundRuns.has(run.runId)) continue;
|
|
1207
|
+
const loaded = hasRunningChild(run) ? restoreInterruptedRun(run) : run;
|
|
1208
|
+
if (!loaded) continue;
|
|
1209
|
+
state.foregroundRuns.set(run.runId, loaded);
|
|
1210
|
+
restored += 1;
|
|
1211
|
+
}
|
|
1212
|
+
return restored;
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1013
1215
|
export {
|
|
1014
|
-
currentCompletionOwnerId,
|
|
1015
1216
|
resolveGitRepositoryIdentity,
|
|
1016
1217
|
resolveWorkflowChatProgress,
|
|
1017
1218
|
buildWorkflowChatProgressRows,
|
|
@@ -1023,5 +1224,11 @@ export {
|
|
|
1023
1224
|
formatAsyncResultTranscript,
|
|
1024
1225
|
resolveSubagentRunId,
|
|
1025
1226
|
deliverAsyncRunStop,
|
|
1026
|
-
stopAsyncRun
|
|
1227
|
+
stopAsyncRun,
|
|
1228
|
+
MAX_REMEMBERED_FOREGROUND_RUNS,
|
|
1229
|
+
persistForegroundRun,
|
|
1230
|
+
discardRunningForegroundRun,
|
|
1231
|
+
ownerConfirmedDead,
|
|
1232
|
+
foregroundChildStateLabel,
|
|
1233
|
+
restoreForegroundRunHistory
|
|
1027
1234
|
};
|