pi-subagents 0.83.0 → 0.83.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 +22 -2
- package/bundle/agents.js +4 -4
- package/bundle/capability-ceiling.js +1 -1
- package/bundle/child-tool-plan.js +3 -3
- package/bundle/{chunk-P2NCCTZP.js → chunk-2D52JFLF.js} +1 -1
- package/bundle/{chunk-WG2OTTAK.js → chunk-2DHZTCOL.js} +2 -2
- package/bundle/{chunk-MBDOYZ2V.js → chunk-2S4K53MV.js} +1 -1
- package/bundle/{chunk-HJJAVHFB.js → chunk-5YIITCPD.js} +23 -23
- package/bundle/{chunk-CNLDYEH4.js → chunk-AHIFYGR3.js} +11 -11
- package/bundle/{chunk-MHX22USZ.js → chunk-C5P5CHYK.js} +1 -1
- package/bundle/{chunk-XXKG3P2W.js → chunk-C7JMPU5F.js} +4 -4
- package/bundle/{chunk-VTMNBPCQ.js → chunk-D3JAFGMO.js} +1 -1
- package/bundle/{chunk-BKFWQ642.js → chunk-F4ASL6OV.js} +1 -1
- package/bundle/{chunk-CDI3GMNV.js → chunk-F5DBXJ2G.js} +15 -15
- package/bundle/{chunk-JHZ6DZ5M.js → chunk-G2Z6ZH26.js} +1 -1
- package/bundle/{chunk-TJQJ3MEA.js → chunk-IPGZMQXV.js} +10 -10
- package/bundle/{chunk-Y3I6H6DV.js → chunk-LFDBD4PW.js} +2 -2
- package/bundle/{chunk-7F5SK2U3.js → chunk-LNRJCP2Y.js} +17 -14
- package/bundle/{chunk-6B4ITO2W.js → chunk-MABL3FUM.js} +1 -1
- package/bundle/{chunk-CGXWSNPA.js → chunk-NPIYWVOD.js} +4 -4
- package/bundle/{chunk-RZJN63GU.js → chunk-QP5ZWNIS.js} +2 -2
- package/bundle/{chunk-Z7KVHQHL.js → chunk-QXASAHIA.js} +2 -2
- package/bundle/{chunk-5ESXK62X.js → chunk-RNIZLSEA.js} +416 -389
- package/bundle/{chunk-HLE22FSH.js → chunk-SSG7IEP5.js} +2 -2
- package/bundle/{chunk-CZTMUBUI.js → chunk-UFL7IYCW.js} +4 -4
- package/bundle/{chunk-LDMXJIA6.js → chunk-UUP372DR.js} +44 -67
- package/bundle/{chunk-OOFW75PV.js → chunk-UYK5MZWE.js} +15 -11
- package/bundle/{chunk-CSSZRTKY.js → chunk-V2BZYLEP.js} +2 -2
- package/bundle/{chunk-4BW55BTL.js → chunk-VLFZIN6D.js} +4 -4
- package/bundle/{chunk-527E3D2J.js → chunk-YXFJVCOL.js} +5 -5
- package/bundle/{chunk-HXVKGS33.js → chunk-ZVOAMTUQ.js} +4 -4
- package/bundle/control-channel.js +3 -3
- package/bundle/index.js +1 -1
- package/bundle/intercom-bridge.js +3 -3
- package/bundle/preflight.js +9 -9
- package/bundle/project-panes.js +4 -4
- package/docs/configuration.md +12 -1
- package/docs/extension-api.md +2 -0
- package/docs/missions.md +2 -0
- package/docs/tool-reference.md +1 -1
- package/package.json +1 -1
- package/src/agents/agent-management.d.ts +1 -1
- package/src/agents/agent-management.js +2 -2
- package/src/agents/agents.js +1 -2
- package/src/agents/frontmatter.js +22 -18
- package/src/extension/index.js +2 -2
- package/src/missions/actions.js +7 -2
- package/src/missions/lifecycle.d.ts +11 -0
- package/src/missions/lifecycle.js +37 -6
- package/src/missions/store.js +1 -0
- package/src/missions/types.d.ts +2 -0
- package/src/runs/background/async-execution.d.ts +1 -1
- package/src/runs/background/async-execution.js +3 -3
- package/src/runs/background/async-resume.js +3 -2
- package/src/runs/background/retained-children.js +1 -1
- package/src/runs/foreground/subagent-executor.js +24 -51
- package/src/runs/shared/capability-ceiling.d.ts +2 -1
- package/src/runs/shared/capability-ceiling.js +3 -2
- package/src/runs/shared/parallel-handoff.d.ts +1 -1
- package/src/runs/shared/parallel-handoff.js +10 -6
- package/src/shared/types.d.ts +1 -1
- package/src/workflows/scripted-workflow.js +4 -1
- package/workflow-script-worker.cjs +2 -1
|
@@ -87,7 +87,7 @@ import { formatHerdrMachineRunnerUnsupported, resolveMachinePlacement } from "..
|
|
|
87
87
|
import { lookupRunnerLauncher, resolveAgentRunnerLauncher } from "../shared/runner-launcher.js";
|
|
88
88
|
import { applyForceTopLevelAsyncOverride } from "../background/top-level-async.js";
|
|
89
89
|
import { handleMissionAction, MISSION_ACTIONS } from "../../missions/actions.js";
|
|
90
|
-
import { attachMissionToLaunchResult, prepareMissionLaunch, writeMissionAsyncBinding } from "../../missions/lifecycle.js";
|
|
90
|
+
import { attachMissionToLaunchResult, missionAcceptanceStatus, prepareMissionLaunch, writeMissionAsyncBinding } from "../../missions/lifecycle.js";
|
|
91
91
|
import { MissionNotFoundError, updateMission } from "../../missions/store.js";
|
|
92
92
|
import { createMissionWorkflowState } from "../../missions/workflow-state.js";
|
|
93
93
|
import { resolveAuthorityDecision } from "../../policy/authority.js";
|
|
@@ -678,9 +678,6 @@ function resolveForegroundResumeTarget(params, state, options = {}) {
|
|
|
678
678
|
...(child.capabilityCeiling ? { capabilityCeiling: child.capabilityCeiling } : {}),
|
|
679
679
|
};
|
|
680
680
|
}
|
|
681
|
-
function isAsyncRunNotFound(error) {
|
|
682
|
-
return error instanceof Error && error.message.startsWith("Async run not found.");
|
|
683
|
-
}
|
|
684
681
|
function isMissingExactAsyncStatusFile(error, requested) {
|
|
685
682
|
return error instanceof Error && error.message === `Status file not found for async run '${requested}'.`;
|
|
686
683
|
}
|
|
@@ -750,38 +747,12 @@ function resolveResumeTarget(params, state, options = {}) {
|
|
|
750
747
|
throw foregroundError;
|
|
751
748
|
return asyncTarget;
|
|
752
749
|
}
|
|
753
|
-
if (foregroundError && !isAsyncRunNotFound(asyncError))
|
|
754
|
-
throw foregroundError;
|
|
755
750
|
if (foregroundError)
|
|
756
751
|
throw foregroundError;
|
|
757
752
|
if (asyncError)
|
|
758
753
|
throw asyncError;
|
|
759
754
|
throw new Error("Run not found. Provide id or runId.");
|
|
760
755
|
}
|
|
761
|
-
function getAsyncInterruptTarget(state, runId, location, options = {}) {
|
|
762
|
-
if (location?.asyncDir) {
|
|
763
|
-
return {
|
|
764
|
-
asyncId: location.resolvedId ?? runId ?? path.basename(location.asyncDir),
|
|
765
|
-
asyncDir: location.asyncDir,
|
|
766
|
-
};
|
|
767
|
-
}
|
|
768
|
-
if (runId) {
|
|
769
|
-
const direct = state.asyncJobs.get(runId);
|
|
770
|
-
if (direct)
|
|
771
|
-
return { asyncId: direct.asyncId, asyncDir: direct.asyncDir };
|
|
772
|
-
if (options.fallbackToNewest === false)
|
|
773
|
-
return undefined;
|
|
774
|
-
}
|
|
775
|
-
let newest;
|
|
776
|
-
for (const job of state.asyncJobs.values()) {
|
|
777
|
-
if (job.status !== "running")
|
|
778
|
-
continue;
|
|
779
|
-
if (!newest || (job.updatedAt ?? 0) > newest.updatedAt) {
|
|
780
|
-
newest = { asyncId: job.asyncId, asyncDir: job.asyncDir, updatedAt: job.updatedAt ?? 0 };
|
|
781
|
-
}
|
|
782
|
-
}
|
|
783
|
-
return newest ? { asyncId: newest.asyncId, asyncDir: newest.asyncDir } : undefined;
|
|
784
|
-
}
|
|
785
756
|
function isStaleExtensionContextError(error) {
|
|
786
757
|
if (!(error instanceof Error))
|
|
787
758
|
return false;
|
|
@@ -853,13 +824,13 @@ function emitControlNotification(input) {
|
|
|
853
824
|
}
|
|
854
825
|
}
|
|
855
826
|
function interruptAsyncRun(state, runId, kill, location) {
|
|
856
|
-
const target =
|
|
827
|
+
const target = location?.asyncDir ? { asyncId: location.resolvedId ?? runId, asyncDir: location.asyncDir } : state.asyncJobs.get(runId);
|
|
857
828
|
if (!target)
|
|
858
829
|
return null;
|
|
859
830
|
const status = reconcileAsyncRun(target.asyncDir, omitUndefinedProperties({ kill })).status;
|
|
860
831
|
if (!status || status.state !== "running" || typeof status.pid !== "number") {
|
|
861
832
|
return {
|
|
862
|
-
content: [{ type: "text", text: `No running async run with an interrupt-capable pid was found for '${runId
|
|
833
|
+
content: [{ type: "text", text: `No running async run with an interrupt-capable pid was found for '${runId}'.` }],
|
|
863
834
|
isError: true,
|
|
864
835
|
details: { mode: "management", results: [] },
|
|
865
836
|
};
|
|
@@ -1086,7 +1057,7 @@ function appendStepToAsyncChain(input) {
|
|
|
1086
1057
|
worktreeBranchPrefix: input.deps.config.worktreeBranchPrefix,
|
|
1087
1058
|
asyncDir: resolved.location.asyncDir,
|
|
1088
1059
|
validateOutputBindings: false,
|
|
1089
|
-
capabilityCeiling: intersectSubagentCapabilityCeilings(status.capabilityCeiling, resolveCurrentSubagentCapabilityCeiling(asyncCtx.
|
|
1060
|
+
capabilityCeiling: intersectSubagentCapabilityCeilings(status.capabilityCeiling, resolveCurrentSubagentCapabilityCeiling(asyncCtx.parentSessionId)),
|
|
1090
1061
|
requiredExtensions: retainedRequiredExtensions,
|
|
1091
1062
|
}));
|
|
1092
1063
|
if ("error" in built) {
|
|
@@ -1562,7 +1533,7 @@ async function resumeExternalJobFollowUp(input) {
|
|
|
1562
1533
|
availableModels: input.ctx.modelRegistry.getAvailable().map(toModelInfo),
|
|
1563
1534
|
outputBaseDir: resolveSingleRunOutputBaseDir(input.deps, artifactsDir, runId),
|
|
1564
1535
|
...(input.absoluteDeadlineAt !== undefined ? { absoluteDeadlineAt: input.absoluteDeadlineAt } : {}),
|
|
1565
|
-
capabilityCeiling: resolveCurrentSubagentCapabilityCeiling(
|
|
1536
|
+
capabilityCeiling: resolveCurrentSubagentCapabilityCeiling(input.ctx.sessionManager.getSessionId() ?? undefined),
|
|
1566
1537
|
runFanoutBudget: createRunFanoutBudget(runId, resolveMaxSubagentSpawnsPerRun(input.deps.config.maxSubagentSpawnsPerRun)),
|
|
1567
1538
|
activeAsyncCapacity,
|
|
1568
1539
|
externalJobFollowUp: { sourceRunId: input.target.runId, sourceStepIndex: input.target.index, parentProviderJobId: externalJob.providerJobId, requestId, requestDigest },
|
|
@@ -1858,7 +1829,7 @@ async function resumeAsyncRun(input) {
|
|
|
1858
1829
|
childIntercomTarget: intercomBridge.active ? (agent, index) => resolveSubagentIntercomTarget(runId, agent, index) : undefined,
|
|
1859
1830
|
globalConcurrencyLimit: input.deps.config.globalConcurrencyLimit,
|
|
1860
1831
|
runFanoutBudget: createRunFanoutBudget(runId, resolveMaxSubagentSpawnsPerRun(input.deps.config.maxSubagentSpawnsPerRun)),
|
|
1861
|
-
capabilityCeiling: intersectSubagentCapabilityCeilings("capabilityCeiling" in target ? target.capabilityCeiling : undefined, resolveCurrentSubagentCapabilityCeiling(input.
|
|
1832
|
+
capabilityCeiling: intersectSubagentCapabilityCeilings("capabilityCeiling" in target ? target.capabilityCeiling : undefined, resolveCurrentSubagentCapabilityCeiling(input.ctx.sessionManager.getSessionId() ?? undefined)),
|
|
1862
1833
|
thinkingCeiling: target.thinkingCeiling,
|
|
1863
1834
|
activeAsyncCapacity,
|
|
1864
1835
|
}));
|
|
@@ -2028,7 +1999,7 @@ async function resumeAsyncRun(input) {
|
|
|
2028
1999
|
...(input.params.toolBudget !== undefined ? { toolBudget: input.params.toolBudget } : {}),
|
|
2029
2000
|
// Recovery descriptors, remembered foreground runs, and current workflow roots
|
|
2030
2001
|
// preserve parent authority before the selected agent's descendant ceiling.
|
|
2031
|
-
capabilityCeiling: intersectSubagentCapabilityCeilings(recoveryDescriptor?.capabilityCeiling ?? (target.source === "foreground" || (target.source === "async" && target.mode === "workflow") ? target.capabilityCeiling : undefined), resolveCurrentSubagentCapabilityCeiling(input.
|
|
2002
|
+
capabilityCeiling: intersectSubagentCapabilityCeilings(recoveryDescriptor?.capabilityCeiling ?? (target.source === "foreground" || (target.source === "async" && target.mode === "workflow") ? target.capabilityCeiling : undefined), resolveCurrentSubagentCapabilityCeiling(input.ctx.sessionManager.getSessionId() ?? undefined)),
|
|
2032
2003
|
runFanoutBudget: input.params.runFanoutBudget ?? recoveryDescriptor?.runFanoutBudget ?? createRunFanoutBudget(runId, resolveMaxSubagentSpawnsPerRun(input.deps.config.maxSubagentSpawnsPerRun)),
|
|
2033
2004
|
parentWorkflowRunId: input.params.workflowParentRunId,
|
|
2034
2005
|
workflowKey: input.params.workflowKey,
|
|
@@ -5093,7 +5064,7 @@ export function createSubagentExecutor(deps) {
|
|
|
5093
5064
|
const eventsPath = path.join(asyncDir, "events.jsonl");
|
|
5094
5065
|
const startedAt = Date.now();
|
|
5095
5066
|
const currentSessionId = resolveCurrentSessionId(ctx.sessionManager);
|
|
5096
|
-
const workflowCapabilityCeiling = intersectSubagentCapabilityCeilings(requestParams.capabilityCeiling, resolveCurrentSubagentCapabilityCeiling(
|
|
5067
|
+
const workflowCapabilityCeiling = intersectSubagentCapabilityCeilings(requestParams.capabilityCeiling, resolveCurrentSubagentCapabilityCeiling(ctx.sessionManager.getSessionId() ?? undefined));
|
|
5097
5068
|
const completionOwnerId = deps.state.completionOwnerId ?? currentCompletionOwnerId();
|
|
5098
5069
|
deps.state.completionOwnerId = completionOwnerId;
|
|
5099
5070
|
const workflowScriptSourceDigest = workflowScriptDigest(requestParams.workflowScript);
|
|
@@ -5971,6 +5942,7 @@ export function createSubagentExecutor(deps) {
|
|
|
5971
5942
|
...(result.details.results[0]?.sessionFile ? { sessionPath: result.details.results[0].sessionFile } : {}),
|
|
5972
5943
|
artifactPaths: child.artifactPaths,
|
|
5973
5944
|
...(["completed", "failed"].includes(childStatus) ? { completedAt: new Date().toISOString() } : {}),
|
|
5945
|
+
acceptanceStatus: missionAcceptanceStatus(result.details.results),
|
|
5974
5946
|
heartbeat: { status: childStatus, ...(childPhase ? { phase: childPhase } : {}) },
|
|
5975
5947
|
});
|
|
5976
5948
|
if (result.details.asyncId) {
|
|
@@ -6137,7 +6109,7 @@ export function createSubagentExecutor(deps) {
|
|
|
6137
6109
|
let lastProgressAt = 0;
|
|
6138
6110
|
let workflowProgressClosed = false;
|
|
6139
6111
|
const workflowDeadlineAt = timeout === undefined ? undefined : Date.now() + timeout;
|
|
6140
|
-
const workflowCapabilityCeiling = intersectSubagentCapabilityCeilings(requestParams.capabilityCeiling, resolveCurrentSubagentCapabilityCeiling(
|
|
6112
|
+
const workflowCapabilityCeiling = intersectSubagentCapabilityCeilings(requestParams.capabilityCeiling, resolveCurrentSubagentCapabilityCeiling(ctx.sessionManager.getSessionId() ?? undefined));
|
|
6141
6113
|
const sendWorkflowProgress = () => {
|
|
6142
6114
|
if (workflowProgressClosed)
|
|
6143
6115
|
return;
|
|
@@ -6294,6 +6266,7 @@ export function createSubagentExecutor(deps) {
|
|
|
6294
6266
|
...(result.details.results[0]?.sessionFile ? { sessionPath: result.details.results[0].sessionFile } : {}),
|
|
6295
6267
|
artifactPaths: child.artifactPaths,
|
|
6296
6268
|
...(["completed", "failed"].includes(childStatus) ? { completedAt: new Date().toISOString() } : {}),
|
|
6269
|
+
acceptanceStatus: missionAcceptanceStatus(result.details.results),
|
|
6297
6270
|
heartbeat: { status: childStatus, ...(childPhase ? { phase: childPhase } : {}) },
|
|
6298
6271
|
});
|
|
6299
6272
|
return child;
|
|
@@ -7061,22 +7034,22 @@ export function createSubagentExecutor(deps) {
|
|
|
7061
7034
|
if (stopResult)
|
|
7062
7035
|
return stopResult;
|
|
7063
7036
|
return {
|
|
7064
|
-
content: [{ type: "text", text:
|
|
7037
|
+
content: [{ type: "text", text: `No stoppable async run found for '${targetRunId}'.` }],
|
|
7065
7038
|
isError: true,
|
|
7066
7039
|
details: { mode: "management", results: [] },
|
|
7067
7040
|
};
|
|
7068
7041
|
}
|
|
7069
7042
|
if (action === "interrupt") {
|
|
7070
7043
|
const targetRunId = paramsWithResolvedCwd.runId ?? paramsWithResolvedCwd.id;
|
|
7044
|
+
if (!targetRunId)
|
|
7045
|
+
return { content: [{ type: "text", text: "action='interrupt' requires id." }], isError: true, details: { mode: "management", results: [] } };
|
|
7071
7046
|
let resolved;
|
|
7072
|
-
|
|
7073
|
-
|
|
7074
|
-
|
|
7075
|
-
|
|
7076
|
-
|
|
7077
|
-
|
|
7078
|
-
return { content: [{ type: "text", text: message }], isError: true, details: { mode: "management", results: [] } };
|
|
7079
|
-
}
|
|
7047
|
+
try {
|
|
7048
|
+
resolved = resolveSubagentRunId(targetRunId, omitUndefinedProperties({ state: deps.state, nested: nestedResolutionScopeForExecutor(deps) }));
|
|
7049
|
+
}
|
|
7050
|
+
catch (error) {
|
|
7051
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
7052
|
+
return { content: [{ type: "text", text: message }], isError: true, details: { mode: "management", results: [] } };
|
|
7080
7053
|
}
|
|
7081
7054
|
if (resolved?.kind === "nested")
|
|
7082
7055
|
return interruptNestedRun(resolved);
|
|
@@ -7101,7 +7074,7 @@ export function createSubagentExecutor(deps) {
|
|
|
7101
7074
|
if (asyncInterruptResult)
|
|
7102
7075
|
return asyncInterruptResult;
|
|
7103
7076
|
return {
|
|
7104
|
-
content: [{ type: "text", text:
|
|
7077
|
+
content: [{ type: "text", text: `No interrupt-capable run found for '${targetRunId}'.` }],
|
|
7105
7078
|
isError: true,
|
|
7106
7079
|
details: { mode: "management", results: [] },
|
|
7107
7080
|
};
|
|
@@ -7117,7 +7090,7 @@ export function createSubagentExecutor(deps) {
|
|
|
7117
7090
|
...ctx,
|
|
7118
7091
|
cwd: requestCwd,
|
|
7119
7092
|
config: deps.config,
|
|
7120
|
-
|
|
7093
|
+
piSessionId: ctx.sessionManager.getSessionId() ?? undefined,
|
|
7121
7094
|
discoverAgentsAll: deps.discoverAgentsAll,
|
|
7122
7095
|
runtimeAgentOwner: deps.pi,
|
|
7123
7096
|
onAgentsChanged: deps.onAgentsChanged,
|
|
@@ -7218,7 +7191,7 @@ export function createSubagentExecutor(deps) {
|
|
|
7218
7191
|
let prepareForkSessionForIndex = async () => { };
|
|
7219
7192
|
// Check before pruner/session preparation, then recheck immediately before each fork
|
|
7220
7193
|
// because the session capability ceiling can tighten while preparation awaits.
|
|
7221
|
-
const launchCapabilityCeiling = () => intersectSubagentCapabilityCeilings(intersectSubagentCapabilityCeilings(effectiveParams.capabilityCeiling, resolveCurrentSubagentCapabilityCeiling(
|
|
7194
|
+
const launchCapabilityCeiling = () => intersectSubagentCapabilityCeilings(intersectSubagentCapabilityCeilings(effectiveParams.capabilityCeiling, resolveCurrentSubagentCapabilityCeiling(requestPiSessionId)), deps.childRuntime?.capabilityCeiling);
|
|
7222
7195
|
const assertLaunchableAgentsAllowedBeforeFork = () => {
|
|
7223
7196
|
if (!contextPolicy.usesFork)
|
|
7224
7197
|
return;
|
|
@@ -7499,7 +7472,7 @@ export function createSubagentExecutor(deps) {
|
|
|
7499
7472
|
scopedModelIds: scopedModelIdsFromContext(ctx),
|
|
7500
7473
|
parentSessionId: requestSessionId,
|
|
7501
7474
|
parentPiSessionId: requestPiSessionId,
|
|
7502
|
-
capabilityCeiling: intersectSubagentCapabilityCeilings(effectiveParams.capabilityCeiling, resolveCurrentSubagentCapabilityCeiling(
|
|
7475
|
+
capabilityCeiling: intersectSubagentCapabilityCeilings(effectiveParams.capabilityCeiling, resolveCurrentSubagentCapabilityCeiling(requestPiSessionId)),
|
|
7503
7476
|
runFanoutBudget,
|
|
7504
7477
|
topLevelAsyncCapacityEligible,
|
|
7505
7478
|
activeAsyncCapacity,
|
|
@@ -48,7 +48,8 @@ export declare function parseSubagentCapabilityCeiling(value: unknown, field?: s
|
|
|
48
48
|
export declare function registerSubagentCapabilityCeiling(options: RegisterSubagentCapabilityCeilingOptions): SubagentCapabilityCeilingHandle;
|
|
49
49
|
export declare function intersectSubagentCapabilityCeilings(...ceilings: Array<ResolvedSubagentCapabilityCeiling | undefined>): ResolvedSubagentCapabilityCeiling | undefined;
|
|
50
50
|
export declare function resolveSubagentCapabilityCeiling(sessionId: string | undefined, inherited?: ResolvedSubagentCapabilityCeiling): ResolvedSubagentCapabilityCeiling | undefined;
|
|
51
|
-
|
|
51
|
+
/** Ceilings are registered under `ctx.sessionManager.getSessionId()`; pass that id, never the session file path. */
|
|
52
|
+
export declare function resolveCurrentSubagentCapabilityCeiling(piSessionId: string | undefined): ResolvedSubagentCapabilityCeiling | undefined;
|
|
52
53
|
export declare function isAgentAllowedByCapabilityCeiling(agentName: string, ceiling: ResolvedSubagentCapabilityCeiling | undefined): boolean;
|
|
53
54
|
export declare function capabilityCeilingAgentRestrictionMessage(agentName: string, ceiling: ResolvedSubagentCapabilityCeiling | undefined): string | undefined;
|
|
54
55
|
export declare function assertAgentAllowedByCapabilityCeiling(agentName: string, ceiling: ResolvedSubagentCapabilityCeiling | undefined): void;
|
|
@@ -135,8 +135,9 @@ export function resolveSubagentCapabilityCeiling(sessionId, inherited) {
|
|
|
135
135
|
}
|
|
136
136
|
return intersectSubagentCapabilityCeilings(inherited, ...active);
|
|
137
137
|
}
|
|
138
|
-
|
|
139
|
-
|
|
138
|
+
/** Ceilings are registered under `ctx.sessionManager.getSessionId()`; pass that id, never the session file path. */
|
|
139
|
+
export function resolveCurrentSubagentCapabilityCeiling(piSessionId) {
|
|
140
|
+
return resolveSubagentCapabilityCeiling(piSessionId, undefined);
|
|
140
141
|
}
|
|
141
142
|
export function isAgentAllowedByCapabilityCeiling(agentName, ceiling) {
|
|
142
143
|
return ceiling?.allowedAgents === undefined || ceiling.allowedAgents.includes(agentName);
|
|
@@ -23,7 +23,7 @@ export declare function resolveParallelHandoffChild(input: {
|
|
|
23
23
|
child: ParallelHandoffGroup["children"][number];
|
|
24
24
|
} | undefined;
|
|
25
25
|
export declare function protectRetainedWorktreeForResume(manifestPath: string, runId: string, childIndex: number, signal?: AbortSignal): Promise<string>;
|
|
26
|
-
export declare function resolveRetainedWorktreeCwd(manifestPath: string, runId: string, childIndex: number): string | undefined;
|
|
26
|
+
export declare function resolveRetainedWorktreeCwd(manifestPath: string, runId: string, childIndex: number, recordedWorktreePath?: string): string | undefined;
|
|
27
27
|
export declare function isTerminalParallelHandoffChildStatus(status: unknown): boolean;
|
|
28
28
|
export declare function formatStoredParallelHandoffCleanup(manifestPath: string, manifest?: ParallelHandoffManifest): string;
|
|
29
29
|
export interface ParallelHandoffEvidenceResult {
|
|
@@ -165,17 +165,18 @@ export async function protectRetainedWorktreeForResume(manifestPath, runId, chil
|
|
|
165
165
|
return cwd;
|
|
166
166
|
}), { signal }));
|
|
167
167
|
}
|
|
168
|
-
export function resolveRetainedWorktreeCwd(manifestPath, runId, childIndex) {
|
|
168
|
+
export function resolveRetainedWorktreeCwd(manifestPath, runId, childIndex, recordedWorktreePath) {
|
|
169
169
|
const manifest = readParallelHandoffManifest(manifestPath);
|
|
170
|
-
if (
|
|
171
|
-
return undefined;
|
|
172
|
-
if (manifest.runId !== runId)
|
|
170
|
+
if (manifest && manifest.runId !== runId)
|
|
173
171
|
throw new Error(`Managed worktree handoff belongs to run '${manifest.runId}', not '${runId}'.`);
|
|
174
|
-
const match = manifest
|
|
172
|
+
const match = manifest?.groups
|
|
175
173
|
.flatMap((group) => group.children.map((child) => ({ group, child })))
|
|
176
174
|
.find(({ child }) => child.index === childIndex);
|
|
177
|
-
if (!match)
|
|
175
|
+
if (!manifest || !match) {
|
|
176
|
+
if (recordedWorktreePath)
|
|
177
|
+
throw new Error(`Async run '${runId}' child ${childIndex} ran in managed worktree ${recordedWorktreePath}, but its handoff has no resumable record yet. Retry after the run settles; if it already ended, inspect ${manifestPath}.`);
|
|
178
178
|
return undefined;
|
|
179
|
+
}
|
|
179
180
|
const cleanup = match.group.cleanup.tasks.find((task) => task.index === match.child.taskIndex);
|
|
180
181
|
if (!cleanup)
|
|
181
182
|
throw new Error(`Async run '${runId}' child ${childIndex} has no managed worktree cleanup record.`);
|
|
@@ -185,6 +186,9 @@ export function resolveRetainedWorktreeCwd(manifestPath, runId, childIndex) {
|
|
|
185
186
|
const requiredCwd = path.join(cleanup.path, relativeCwd);
|
|
186
187
|
if (cleanup.worktreeRemoved || cleanup.branchRemoved)
|
|
187
188
|
throw new Error(`Async run '${runId}' required managed worktree was removed: ${requiredCwd}`);
|
|
189
|
+
// The runner removes the worktree right after this marker, without the locks that guard resume admission.
|
|
190
|
+
if (cleanup.reason?.includes("pending durable handoff capture"))
|
|
191
|
+
throw new Error(`Async run '${runId}' child ${childIndex} is still finalizing its managed worktree: ${requiredCwd}. Retry after the run settles; if it already ended, inspect ${manifestPath}.`);
|
|
188
192
|
let worktreeRoot = "";
|
|
189
193
|
let resolvedRequiredCwd = "";
|
|
190
194
|
try {
|
package/src/shared/types.d.ts
CHANGED
|
@@ -1936,7 +1936,7 @@ export interface AsyncStatus {
|
|
|
1936
1936
|
label?: string;
|
|
1937
1937
|
workflowKey?: string;
|
|
1938
1938
|
lane?: WorkflowLaneMetadata;
|
|
1939
|
-
/**
|
|
1939
|
+
/** Worktree path copied at setup; the handoff stays authoritative for the cwd. */
|
|
1940
1940
|
worktreePath?: string;
|
|
1941
1941
|
/** Display-only branch copied at launch; handoff remains authoritative. */
|
|
1942
1942
|
branch?: string;
|
|
@@ -774,7 +774,8 @@ export function validateWorkflowScript(script, options = {}) {
|
|
|
774
774
|
: undefined;
|
|
775
775
|
const workflowBody = wrapper && astNode(wrapper.body) ? wrapper.body : root;
|
|
776
776
|
// A rebound `runs` may not be the workflow API, so its calls prove nothing about child launches.
|
|
777
|
-
const
|
|
777
|
+
const runsRebound = invalidatesRunsBinding(workflowBody);
|
|
778
|
+
const agentNameError = options.agentNameError && !runsRebound ? options.agentNameError : undefined;
|
|
778
779
|
walkAst(workflowBody, (node) => {
|
|
779
780
|
if (node !== wrapper && node.async === true && (node.type === "FunctionDeclaration" || node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression")) {
|
|
780
781
|
errors.push({ message: "workflowScript does not support nested async functions. Use top-level await, plain helper functions that return runs.run(...), or explicit Promise chains.", ...nodeLocation(node) });
|
|
@@ -785,6 +786,8 @@ export function validateWorkflowScript(script, options = {}) {
|
|
|
785
786
|
const key = literalString(keyNode);
|
|
786
787
|
if (keyNode && key !== undefined && !KEY_PATTERN.test(key))
|
|
787
788
|
errors.push({ message: "runs.run key must be 1-128 characters using letters, numbers, '.', '_' or '-', and start with a letter or number.", ...nodeLocation(keyNode) });
|
|
789
|
+
if (keyNode?.type === "ObjectExpression" && !runsRebound)
|
|
790
|
+
errors.push({ message: `runs.run expects (key, params); got an object as the first argument. Use runs.run("plan", { agent, task }) or runs.all([{ key, agent, task }]).`, ...nodeLocation(keyNode) });
|
|
788
791
|
if (astNode(args[1])) {
|
|
789
792
|
errors.push(...validateStaticBaseRef(args[1], "runs.run"));
|
|
790
793
|
const message = definitelyNonJson(args[1]);
|
|
@@ -307,7 +307,7 @@ function laneBoardText(value) {
|
|
|
307
307
|
if (typeof value !== "string" || !value) return undefined;
|
|
308
308
|
if (laneByteLength(value) <= MAX_LANE_BOARD_TEXT_BYTES) return value;
|
|
309
309
|
const bytes = new TextEncoder().encode(value).subarray(0, MAX_LANE_BOARD_TEXT_BYTES - 3);
|
|
310
|
-
return new TextDecoder().decode(bytes) + "...";
|
|
310
|
+
return new TextDecoder().decode(bytes, { stream: true }) + "...";
|
|
311
311
|
}
|
|
312
312
|
|
|
313
313
|
function laneBoardPath(value) {
|
|
@@ -758,6 +758,7 @@ function launchRunsAllPermissive(items) {
|
|
|
758
758
|
|
|
759
759
|
const runs = Object.freeze({
|
|
760
760
|
run(key, params) {
|
|
761
|
+
if (key && typeof key === "object" && !Array.isArray(key)) throw new Error('runs.run expects (key, params); got an object as the first argument. Use runs.run("plan", { agent, task }) or runs.all([{ key, agent, task }]).');
|
|
761
762
|
validateRunCall(key, params, "runs.run", runFingerprints);
|
|
762
763
|
const launched = runHostCall(key, params, false);
|
|
763
764
|
return trackRunObservation([{ key, operation: "run", callId: launched.callId }], launched.promise.then(decorateWorkflowChildResult));
|