pi-subagents 0.74.0 → 0.75.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/docs/agents.md +15 -5
  3. package/docs/configuration.md +10 -0
  4. package/docs/extension-api.md +1 -1
  5. package/docs/missions.md +15 -1
  6. package/docs/models.md +6 -2
  7. package/docs/observability.md +8 -3
  8. package/docs/tool-reference.md +28 -3
  9. package/docs/workflows.md +2 -2
  10. package/package.json +1 -1
  11. package/src/agents/agents.d.ts +1 -0
  12. package/src/agents/agents.d.ts.map +1 -1
  13. package/src/agents/agents.js +65 -3
  14. package/src/agents/agents.js.map +1 -1
  15. package/src/api/preflight.d.ts +1 -1
  16. package/src/api/preflight.d.ts.map +1 -1
  17. package/src/api/preflight.js +44 -1
  18. package/src/api/preflight.js.map +1 -1
  19. package/src/extension/config.d.ts.map +1 -1
  20. package/src/extension/config.js +4 -1
  21. package/src/extension/config.js.map +1 -1
  22. package/src/extension/index.d.ts.map +1 -1
  23. package/src/extension/index.js +26 -19
  24. package/src/extension/index.js.map +1 -1
  25. package/src/extension/public-execution.d.ts.map +1 -1
  26. package/src/extension/public-execution.js +4 -0
  27. package/src/extension/public-execution.js.map +1 -1
  28. package/src/extension/reply-workflow-script.js +1 -1
  29. package/src/extension/reply-workflow-script.js.map +1 -1
  30. package/src/extension/rpc.js +1 -1
  31. package/src/extension/rpc.js.map +1 -1
  32. package/src/extension/schemas.d.ts +1 -0
  33. package/src/extension/schemas.d.ts.map +1 -1
  34. package/src/extension/schemas.js +5 -3
  35. package/src/extension/schemas.js.map +1 -1
  36. package/src/extension/tool-description.js +1 -1
  37. package/src/extension/tool-description.js.map +1 -1
  38. package/src/missions/goal-driver.d.ts +1 -0
  39. package/src/missions/goal-driver.d.ts.map +1 -1
  40. package/src/missions/goal-driver.js +49 -34
  41. package/src/missions/goal-driver.js.map +1 -1
  42. package/src/missions/store.d.ts.map +1 -1
  43. package/src/missions/store.js +11 -1
  44. package/src/missions/store.js.map +1 -1
  45. package/src/profiles/profiles.d.ts +1 -1
  46. package/src/profiles/profiles.d.ts.map +1 -1
  47. package/src/profiles/profiles.js +4 -0
  48. package/src/profiles/profiles.js.map +1 -1
  49. package/src/runs/background/async-execution.d.ts +13 -0
  50. package/src/runs/background/async-execution.d.ts.map +1 -1
  51. package/src/runs/background/async-execution.js +89 -6
  52. package/src/runs/background/async-execution.js.map +1 -1
  53. package/src/runs/background/async-job-tracker.d.ts +1 -0
  54. package/src/runs/background/async-job-tracker.d.ts.map +1 -1
  55. package/src/runs/background/async-job-tracker.js +2 -2
  56. package/src/runs/background/async-job-tracker.js.map +1 -1
  57. package/src/runs/background/await-async-run.d.ts.map +1 -1
  58. package/src/runs/background/await-async-run.js +4 -2
  59. package/src/runs/background/await-async-run.js.map +1 -1
  60. package/src/runs/background/control-channel.d.ts +10 -0
  61. package/src/runs/background/control-channel.d.ts.map +1 -1
  62. package/src/runs/background/control-channel.js +51 -0
  63. package/src/runs/background/control-channel.js.map +1 -1
  64. package/src/runs/background/run-child-session.d.ts.map +1 -1
  65. package/src/runs/background/run-child-session.js +20 -6
  66. package/src/runs/background/run-child-session.js.map +1 -1
  67. package/src/runs/background/runner-aliases.d.ts +1 -0
  68. package/src/runs/background/runner-aliases.d.ts.map +1 -1
  69. package/src/runs/background/runner-aliases.js +6 -2
  70. package/src/runs/background/runner-aliases.js.map +1 -1
  71. package/src/runs/background/scheduled-runs.d.ts +2 -1
  72. package/src/runs/background/scheduled-runs.d.ts.map +1 -1
  73. package/src/runs/background/scheduled-runs.js +28 -11
  74. package/src/runs/background/scheduled-runs.js.map +1 -1
  75. package/src/runs/background/stale-run-reconciler.d.ts +1 -1
  76. package/src/runs/background/stale-run-reconciler.d.ts.map +1 -1
  77. package/src/runs/background/stale-run-reconciler.js +15 -2
  78. package/src/runs/background/stale-run-reconciler.js.map +1 -1
  79. package/src/runs/background/subagent-runner.d.ts.map +1 -1
  80. package/src/runs/background/subagent-runner.js +44 -3
  81. package/src/runs/background/subagent-runner.js.map +1 -1
  82. package/src/runs/foreground/command-action.d.ts +13 -0
  83. package/src/runs/foreground/command-action.d.ts.map +1 -0
  84. package/src/runs/foreground/command-action.js +38 -0
  85. package/src/runs/foreground/command-action.js.map +1 -0
  86. package/src/runs/foreground/execution.d.ts.map +1 -1
  87. package/src/runs/foreground/execution.js +19 -5
  88. package/src/runs/foreground/execution.js.map +1 -1
  89. package/src/runs/foreground/subagent-executor.d.ts +1 -0
  90. package/src/runs/foreground/subagent-executor.d.ts.map +1 -1
  91. package/src/runs/foreground/subagent-executor.js +64 -11
  92. package/src/runs/foreground/subagent-executor.js.map +1 -1
  93. package/src/runs/shared/child-commands.d.ts +28 -0
  94. package/src/runs/shared/child-commands.d.ts.map +1 -0
  95. package/src/runs/shared/child-commands.js +250 -0
  96. package/src/runs/shared/child-commands.js.map +1 -0
  97. package/src/runs/shared/child-session.d.ts +4 -0
  98. package/src/runs/shared/child-session.d.ts.map +1 -1
  99. package/src/runs/shared/child-session.js +97 -20
  100. package/src/runs/shared/child-session.js.map +1 -1
  101. package/src/runs/shared/child-tool-plan.js +1 -1
  102. package/src/runs/shared/child-tool-plan.js.map +1 -1
  103. package/src/runs/shared/claude-code-adapter.d.ts +56 -0
  104. package/src/runs/shared/claude-code-adapter.d.ts.map +1 -1
  105. package/src/runs/shared/claude-code-adapter.js +138 -2
  106. package/src/runs/shared/claude-code-adapter.js.map +1 -1
  107. package/src/runs/shared/dynamic-fanout.js +1 -1
  108. package/src/runs/shared/dynamic-fanout.js.map +1 -1
  109. package/src/runs/shared/external-cli-preflight.d.ts +10 -0
  110. package/src/runs/shared/external-cli-preflight.d.ts.map +1 -1
  111. package/src/runs/shared/external-cli-preflight.js +50 -6
  112. package/src/runs/shared/external-cli-preflight.js.map +1 -1
  113. package/src/runs/shared/external-cli-runner.d.ts.map +1 -1
  114. package/src/runs/shared/external-cli-runner.js +4 -2
  115. package/src/runs/shared/external-cli-runner.js.map +1 -1
  116. package/src/runs/shared/mcp-direct-tool-allowlist.d.ts.map +1 -1
  117. package/src/runs/shared/mcp-direct-tool-allowlist.js +5 -4
  118. package/src/runs/shared/mcp-direct-tool-allowlist.js.map +1 -1
  119. package/src/runs/shared/model-resolution.d.ts +6 -2
  120. package/src/runs/shared/model-resolution.d.ts.map +1 -1
  121. package/src/runs/shared/model-resolution.js +9 -2
  122. package/src/runs/shared/model-resolution.js.map +1 -1
  123. package/src/runs/shared/parallel-utils.d.ts +2 -0
  124. package/src/runs/shared/parallel-utils.d.ts.map +1 -1
  125. package/src/runs/shared/parallel-utils.js.map +1 -1
  126. package/src/runs/shared/run-history.d.ts +47 -0
  127. package/src/runs/shared/run-history.d.ts.map +1 -1
  128. package/src/runs/shared/run-history.js +70 -0
  129. package/src/runs/shared/run-history.js.map +1 -1
  130. package/src/runs/shared/subagent-control.d.ts.map +1 -1
  131. package/src/runs/shared/subagent-control.js +30 -17
  132. package/src/runs/shared/subagent-control.js.map +1 -1
  133. package/src/runs/shared/subagent-prompt-runtime.d.ts +1 -0
  134. package/src/runs/shared/subagent-prompt-runtime.d.ts.map +1 -1
  135. package/src/runs/shared/subagent-prompt-runtime.js +12 -5
  136. package/src/runs/shared/subagent-prompt-runtime.js.map +1 -1
  137. package/src/shared/required-child-extensions.d.ts +16 -1
  138. package/src/shared/required-child-extensions.d.ts.map +1 -1
  139. package/src/shared/required-child-extensions.js +37 -5
  140. package/src/shared/required-child-extensions.js.map +1 -1
  141. package/src/shared/types.d.ts +6 -1
  142. package/src/shared/types.d.ts.map +1 -1
  143. package/src/shared/types.js +1 -1
  144. package/src/shared/types.js.map +1 -1
  145. package/src/slash/subagent-cost.d.ts.map +1 -1
  146. package/src/slash/subagent-cost.js +8 -4
  147. package/src/slash/subagent-cost.js.map +1 -1
  148. package/src/tui/render.d.ts +1 -1
  149. package/src/tui/render.d.ts.map +1 -1
  150. package/src/tui/render.js +4 -4
  151. package/src/tui/render.js.map +1 -1
  152. package/src/workflows/workflow-receipt.js +2 -2
  153. package/src/workflows/workflow-receipt.js.map +1 -1
  154. package/src/workflows/workflow-resources.d.ts +4 -0
  155. package/src/workflows/workflow-resources.d.ts.map +1 -1
  156. package/src/workflows/workflow-resources.js +7 -4
  157. package/src/workflows/workflow-resources.js.map +1 -1
@@ -19,6 +19,7 @@ import { isWorkflowScriptPath, normalizePublicSubagentExecution, validateWorkflo
19
19
  import { readReplyWorkflowScript } from "../../extension/reply-workflow-script.js";
20
20
  import { disabledFeatureNotice, disabledFeatureUseError, resolveDisabledFeatureSurface } from "../../shared/disabled-features.js";
21
21
  import { runSync } from "./execution.js";
22
+ import { commandAction } from "./command-action.js";
22
23
  import { handleWatchdogToolAction, WATCHDOG_TOOL_ACTIONS } from "../../watchdog/tool-actions.js";
23
24
  import { applyWatchdogLaunchRules } from "../../watchdog/rules.js";
24
25
  import { childWatchdogProgressForModel } from "../../watchdog/child-status.js";
@@ -54,7 +55,7 @@ import { usageBudgetExceededMessage, usageBudgetState, validateUsageBudgetConfig
54
55
  import { assertAgentAllowedByCapabilityCeiling, intersectSubagentCapabilityCeilings, resolveCurrentSubagentCapabilityCeiling } from "../shared/capability-ceiling.js";
55
56
  import { isAgentContract } from "../shared/agent-contract.js";
56
57
  import { normalizeExtensionBindings } from "../shared/extension-bindings.js";
57
- import { resolveRequiredChildExtensions } from "../../shared/required-child-extensions.js";
58
+ import { assertRequiredChildExtensionsAdmitted, hasMandatoryRequiredChildExtensions, readRetainedRequiredChildExtensions, resolveRequiredChildExtensions } from "../../shared/required-child-extensions.js";
58
59
  import { finalizeSingleOutput, injectSingleOutputInstruction, normalizeSingleOutputOverride, outputPathMappingFromTask, resolveSingleOutputPath, validateFileOnlyOutputMode } from "../shared/single-output.js";
59
60
  import { assertJsonSchemaObject, cleanupStructuredOutputRuntime, createStructuredOutputRuntime } from "../shared/structured-output.js";
60
61
  import { compactForegroundDetails, getSingleResultOutput, PROMPT_REDACTED, readStatus, resolveChildCwd, sumResultsCost, sumResultsUsage, toAgentToolUsage } from "../../shared/utils.js";
@@ -109,8 +110,8 @@ import { cleanupWorktrees, createWorktrees, preflightWorktreeSource, withWorktre
109
110
  import { createWorktreeCleanupPlan, formatWorktreeCleanupPlan } from "../shared/worktree-cleanup-plan.js";
110
111
  import { DIRS, DEFAULT_ARTIFACT_CONFIG, DEFAULT_MAX_OUTPUT, DEFAULT_FORK_PREAMBLE, SUBAGENT_ACTIONS, SUBAGENT_ASYNC_STARTED_EVENT, SUBAGENT_CHILD_STATUS_EVENT, SUBAGENT_CONTROL_EVENT, SUBAGENT_CONTROL_INTERCOM_EVENT, SUBAGENT_FOREGROUND_COMPLETE_EVENT, SUBAGENT_LIFECYCLE_ARTIFACT_VERSION, checkSubagentDepth, resolveChildMaxSubagentDepth, resolveCurrentMaxSubagentDepth, resolveMaxSubagentSpawnsPerRun, truncateOutput, wrapForkTask, } from "../../shared/types.js";
111
112
  import { deriveChildSessionName } from "../../shared/child-session-name.js";
112
- const MUTATING_MANAGEMENT_ACTIONS = new Set(["create", "update", "delete", "eject", "disable", "enable", "reset", "grant-spawn-budget", "watchdog.configure", "mission.create", "mission.update", "mission.resolve-decision", "mission.attach-run", "mission.close", "inspector.open", "inspector.close", "project.open", "project.close", "worktree.discard", "worktree.cleanup", "lane.recordMerge", "lane.recordSupersession", "refine", "refine.rollback", "dismiss", "schedule.create", "schedule.pause", "schedule.resume", "schedule.run", "schedule.run-due", "schedule.delete"]);
113
- const DESTRUCTIVE_MANAGEMENT_ACTIONS = new Set(["delete", "eject", "disable", "reset", "mission.close", "worktree.discard", "refine.rollback", "inspector.close", "project.close", "stop", "interrupt", "schedule.delete"]);
113
+ const MUTATING_MANAGEMENT_ACTIONS = new Set(["command.yield", "command.cancel", "create", "update", "delete", "eject", "disable", "enable", "reset", "grant-spawn-budget", "watchdog.configure", "mission.create", "mission.update", "mission.resolve-decision", "mission.attach-run", "mission.close", "inspector.open", "inspector.close", "project.open", "project.close", "worktree.discard", "worktree.cleanup", "lane.recordMerge", "lane.recordSupersession", "refine", "refine.rollback", "dismiss", "schedule.create", "schedule.pause", "schedule.resume", "schedule.run", "schedule.run-due", "schedule.delete"]);
114
+ const DESTRUCTIVE_MANAGEMENT_ACTIONS = new Set(["command.cancel", "delete", "eject", "disable", "reset", "mission.close", "worktree.discard", "refine.rollback", "inspector.close", "project.close", "stop", "interrupt", "schedule.delete"]);
114
115
  function resolveSteerDeliveryMode(mode) {
115
116
  return mode === "steer" || mode === "follow_up" || mode === "auto" ? mode : undefined;
116
117
  }
@@ -960,6 +961,17 @@ function appendStepToAsyncChain(input) {
960
961
  details: { mode: "management", results: [] },
961
962
  };
962
963
  }
964
+ let retainedRequiredExtensions;
965
+ try {
966
+ retainedRequiredExtensions = readRetainedRequiredChildExtensions(resolved.location.asyncDir);
967
+ }
968
+ catch (error) {
969
+ return {
970
+ content: [{ type: "text", text: `Cannot append step to run '${resolved.id}': ${error instanceof Error ? error.message : String(error)}` }],
971
+ isError: true,
972
+ details: { mode: "management", results: [] },
973
+ };
974
+ }
963
975
  const pendingAppendRequests = readPendingChainAppendRequests(resolved.location.asyncDir);
964
976
  const reservedOutputNames = new Set([
965
977
  ...Object.keys(status.outputs ?? {}),
@@ -1031,6 +1043,7 @@ function appendStepToAsyncChain(input) {
1031
1043
  asyncDir: resolved.location.asyncDir,
1032
1044
  validateOutputBindings: false,
1033
1045
  capabilityCeiling: intersectSubagentCapabilityCeilings(status.capabilityCeiling, resolveCurrentSubagentCapabilityCeiling(asyncCtx.currentSessionId)),
1046
+ requiredExtensions: retainedRequiredExtensions,
1034
1047
  }));
1035
1048
  if ("error" in built) {
1036
1049
  return {
@@ -3069,6 +3082,7 @@ async function runAsyncPath(data, deps) {
3069
3082
  goal: params.task ?? "",
3070
3083
  agentConfig: a,
3071
3084
  recoveryAgentConfig: data.recoveryAgents.find((agent) => agent.name === params.agent),
3085
+ requiredExtensions: data.requiredExtensions,
3072
3086
  ctx: asyncCtx,
3073
3087
  availableModels,
3074
3088
  cwd: effectiveCwd,
@@ -3455,8 +3469,10 @@ async function runSinglePath(data, deps) {
3455
3469
  }
3456
3470
  let foregroundMachine;
3457
3471
  const requestedMachine = params.machine ?? agentConfig.machine;
3472
+ const requiredExtensions = data.requiredExtensions ?? deps.childRuntime?.requiredExtensions ?? resolveRequiredChildExtensions(data.parentPiSessionId);
3458
3473
  if (requestedMachine) {
3459
3474
  try {
3475
+ assertRequiredChildExtensionsAdmitted([requiredExtensions], { agent: agentConfig.name, runnerType: agentConfig.runner?.type, machine: requestedMachine });
3460
3476
  foregroundMachine = resolveHerdrMachinePlacement({ machine: requestedMachine, cwd: ctx.cwd, stepCwd: params.machineCwd }).machine;
3461
3477
  }
3462
3478
  catch (error) {
@@ -3643,7 +3659,6 @@ async function runSinglePath(data, deps) {
3643
3659
  }
3644
3660
  : undefined;
3645
3661
  const deadlineAt = data.deadlineAt ?? (data.timeoutMs !== undefined ? Date.now() + data.timeoutMs : undefined);
3646
- const requiredExtensions = deps.childRuntime?.requiredExtensions ?? resolveRequiredChildExtensions(data.parentPiSessionId);
3647
3662
  let r;
3648
3663
  let resolveDetachedWorkflowChild;
3649
3664
  const detachedWorkflowChild = params.workflowAwaitDetached === true
@@ -3900,6 +3915,7 @@ function duplicateSubagentCallResult(params) {
3900
3915
  }
3901
3916
  const workflowLaunchObservers = new WeakMap();
3902
3917
  const workflowOwnedUsageBudgets = new WeakMap();
3918
+ const workflowRetainedRequiredExtensions = new WeakMap();
3903
3919
  /**
3904
3920
  * Terminal-mission retention can remove a mission while its children still
3905
3921
  * report. Remember it to prevent later heartbeats from warning repeatedly.
@@ -4087,7 +4103,11 @@ function workflowOutputPathMappingSummary(children) {
4087
4103
  return mappings.length > 0 ? ` Output path mappings: ${mappings.join("; ")}.` : "";
4088
4104
  }
4089
4105
  function workflowDetailsResults(children) {
4090
- return children.flatMap((child) => (child.results ?? []).map((result) => result.workflowKey ? result : { ...result, workflowKey: child.key }));
4106
+ return children.flatMap((child) => (child.results ?? []).map((result) => ({
4107
+ ...result,
4108
+ workflowKey: result.workflowKey ?? child.key,
4109
+ ...(child.runId && !result.runId ? { runId: child.runId } : {}),
4110
+ })));
4091
4111
  }
4092
4112
  function workflowSteerReceipt(key, result) {
4093
4113
  const steering = result.details.steering;
@@ -4625,6 +4645,7 @@ export function createSubagentExecutor(deps) {
4625
4645
  const execute = async (_id, params, signal, onUpdate, ctx, preserveActiveSession = false, parentModelOverride) => {
4626
4646
  const workflowLaunchObserver = workflowLaunchObservers.get(params);
4627
4647
  const inheritedUsageBudget = workflowOwnedUsageBudgets.get(params);
4648
+ const retainedRequiredExtensions = workflowRetainedRequiredExtensions.get(params);
4628
4649
  const delegatedThinkingOverride = delegatedThinkingOverrides.get(params);
4629
4650
  const allowZeroToolBudget = delegatedZeroToolBudgets.has(params);
4630
4651
  const delegatedExecution = delegatedExecutions.has(params);
@@ -4655,6 +4676,12 @@ export function createSubagentExecutor(deps) {
4655
4676
  ? currentParentModel
4656
4677
  : rememberParentModel(deps.state, resolveCurrentSessionId(ctx.sessionManager), currentParentModel)) ?? null;
4657
4678
  })();
4679
+ // validate checks args with the same normalization launch uses, reported beside script errors.
4680
+ const validateWorkflowRequest = () => {
4681
+ const validation = validateWorkflowScript(requestParams.workflowScript ?? "", workflowValidationOptions(deps, requestParams, ctx.cwd, () => resolveWorkflowParentModel()?.provider));
4682
+ const normalizedArgs = normalizeWorkflowArgs(requestParams.args);
4683
+ return "error" in normalizedArgs ? { ...validation, ok: false, errors: [...validation.errors, { message: normalizedArgs.error }] } : validation;
4684
+ };
4658
4685
  try {
4659
4686
  if (requestParams.preflight !== undefined && requestParams.workflowScript === undefined) {
4660
4687
  throw new Error("preflight requires workflow: true or a workflow script path.");
@@ -4666,7 +4693,7 @@ export function createSubagentExecutor(deps) {
4666
4693
  catch (error) {
4667
4694
  const message = error instanceof Error ? error.message : String(error);
4668
4695
  if (requestParams.action?.trim() === "validate") {
4669
- const validation = validateWorkflowScript(requestParams.workflowScript ?? "", workflowValidationOptions(deps, requestParams, ctx.cwd, () => resolveWorkflowParentModel()?.provider));
4696
+ const validation = validateWorkflowRequest();
4670
4697
  const invalidValidation = { ...validation, ok: false, errors: [...validation.errors, { message }] };
4671
4698
  return {
4672
4699
  content: [{ type: "text", text: JSON.stringify(invalidValidation) }],
@@ -4677,8 +4704,7 @@ export function createSubagentExecutor(deps) {
4677
4704
  return buildRequestedModeError(requestParams, message);
4678
4705
  }
4679
4706
  if (requestParams.action?.trim() === "validate") {
4680
- const validation = validateWorkflowScript(requestParams.workflowScript ?? "", workflowValidationOptions(deps, requestParams, ctx.cwd, () => resolveWorkflowParentModel()?.provider));
4681
- return buildWorkflowValidationResult(validation, "management", workflowPreflight);
4707
+ return buildWorkflowValidationResult(validateWorkflowRequest(), "management", workflowPreflight);
4682
4708
  }
4683
4709
  const normalizedAction = typeof requestParams.action === "string" ? requestParams.action.trim() : requestParams.action;
4684
4710
  if (normalizedAction === "resume" && requestParams.extensionBindings !== undefined)
@@ -4713,6 +4739,9 @@ export function createSubagentExecutor(deps) {
4713
4739
  const acceptanceErrors = validateAcceptanceInput(requestParams.acceptance);
4714
4740
  if (acceptanceErrors.length > 0)
4715
4741
  return buildRequestedModeError(requestParams, acceptanceErrors.join(" "));
4742
+ // Capture mandatory host extensions at admission: script children may launch after the host disposes its registration.
4743
+ const admittedRequiredExtensions = retainedRequiredExtensions ?? deps.childRuntime?.requiredExtensions ?? resolveRequiredChildExtensions(ctx.sessionManager.getSessionId() ?? undefined);
4744
+ const workflowRequiredExtensions = hasMandatoryRequiredChildExtensions(admittedRequiredExtensions) ? admittedRequiredExtensions : undefined;
4716
4745
  const foregroundWorkflowRunId = encodeIndexSegment(_id);
4717
4746
  if (delegatedWorkflowPermit) {
4718
4747
  const permitError = validateWorkflowChildPermitRoot(delegatedWorkflowPermit, foregroundWorkflowRunId);
@@ -5588,6 +5617,8 @@ export function createSubagentExecutor(deps) {
5588
5617
  preparedChildParams = childRequest;
5589
5618
  if (workflowUsageBudget.budget)
5590
5619
  workflowOwnedUsageBudgets.set(childRequest, workflowUsageBudget.budget);
5620
+ if (workflowRequiredExtensions)
5621
+ workflowRetainedRequiredExtensions.set(childRequest, workflowRequiredExtensions);
5591
5622
  workflowLaunchObservers.set(childRequest, (launch) => {
5592
5623
  if (launch.runId)
5593
5624
  appendWorkflowChildJournal(asyncDir, { type: "start", key, fingerprint: journalFingerprint, runId: launch.runId });
@@ -5910,6 +5941,8 @@ export function createSubagentExecutor(deps) {
5910
5941
  preparedChildParams = childRequest;
5911
5942
  if (workflowUsageBudget.budget)
5912
5943
  workflowOwnedUsageBudgets.set(childRequest, workflowUsageBudget.budget);
5944
+ if (workflowRequiredExtensions)
5945
+ workflowRetainedRequiredExtensions.set(childRequest, workflowRequiredExtensions);
5913
5946
  if (delegatedWorkflowPermit) {
5914
5947
  if (childRequest.async !== false)
5915
5948
  throw new Error("Workflow child permit supports one foreground child only.");
@@ -6178,7 +6211,7 @@ export function createSubagentExecutor(deps) {
6178
6211
  return { content: [{ type: "text", text: error instanceof Error ? error.message : String(error) }], isError: true, details: { mode: "management", results: [] } };
6179
6212
  }
6180
6213
  }
6181
- const policyAction = action === "stop" ? "stopRun" : action === "steer" ? "steerRun" : action === "schedule.create" ? "scheduleCreate" : action === "inspector.open" ? "inspectorOpen" : action === "project.open" ? "projectOpen" : undefined;
6214
+ const policyAction = action === "stop" || action === "command.cancel" ? "stopRun" : action === "steer" || action === "command.yield" ? "steerRun" : action === "schedule.create" ? "scheduleCreate" : action === "inspector.open" ? "inspectorOpen" : action === "project.open" ? "projectOpen" : undefined;
6182
6215
  if (policyAction) {
6183
6216
  // Child-safe mode is a hard capability boundary; the policy is an operator
6184
6217
  // preference. Refuse first, so the gate never prompts for an action that is
@@ -6402,6 +6435,23 @@ export function createSubagentExecutor(deps) {
6402
6435
  details: { mode: "management", results: [], spawnBudget, activeAsyncCapacity },
6403
6436
  };
6404
6437
  }
6438
+ if (["command.status", "command.yield", "command.cancel"].includes(action)) {
6439
+ try {
6440
+ if (deps.allowMutatingManagementActions === false && action !== "command.status")
6441
+ throw new Error(`Action '${action}' is not available from child-safe subagent fanout mode.`);
6442
+ const targetRunId = paramsWithResolvedCwd.id ?? paramsWithResolvedCwd.runId;
6443
+ if (!targetRunId || paramsWithResolvedCwd.dir)
6444
+ throw new Error(`${action} requires id or runId; directory targets are not supported.`);
6445
+ deps.state.currentSessionId = resolveCurrentSessionId(ctx.sessionManager);
6446
+ const target = resolveSubagentRunId(targetRunId, { state: deps.state, nested: nestedResolutionScopeForExecutor(deps) });
6447
+ if (!target)
6448
+ throw new Error(`No run found for '${targetRunId}'.`);
6449
+ return await commandAction({ state: deps.state, target, operation: action.slice("command.".length), index: paramsWithResolvedCwd.index, toolCallId: paramsWithResolvedCwd.toolCallId, signal });
6450
+ }
6451
+ catch (error) {
6452
+ return { content: [{ type: "text", text: error instanceof Error ? error.message : String(error) }], isError: true, details: { mode: "management", results: [] } };
6453
+ }
6454
+ }
6405
6455
  if (action === "status" || action === "debug.run") {
6406
6456
  if (!preserveActiveSession)
6407
6457
  deps.state.currentSessionId = resolveCurrentSessionId(ctx.sessionManager);
@@ -7088,6 +7138,7 @@ export function createSubagentExecutor(deps) {
7088
7138
  toolBudget: runToolBudget.toolBudget,
7089
7139
  usageBudget: usageBudget.budget,
7090
7140
  inheritedUsageBudget,
7141
+ requiredExtensions: retainedRequiredExtensions,
7091
7142
  allowZeroToolBudget,
7092
7143
  configToolBudget: configToolBudget.toolBudget,
7093
7144
  configToolTimeoutMs: deps.config.toolTimeoutMs,
@@ -7373,7 +7424,9 @@ export function createSubagentExecutor(deps) {
7373
7424
  }
7374
7425
  else if (workflow !== undefined || publicParams.workflowScript !== undefined) {
7375
7426
  const normalizedArgs = normalizeWorkflowArgs(publicParams.args);
7376
- if ("error" in normalizedArgs)
7427
+ // validate reports args errors with its script errors; launch rejects them here.
7428
+ const validateOnly = publicParams.action === "validate";
7429
+ if ("error" in normalizedArgs && !validateOnly)
7377
7430
  return errorResult(normalizedArgs.error);
7378
7431
  let workflowScript = publicParams.workflowScript;
7379
7432
  if (workflow !== undefined) {
@@ -7383,7 +7436,7 @@ export function createSubagentExecutor(deps) {
7383
7436
  workflowScript = source.script;
7384
7437
  }
7385
7438
  const { workflow: _workflow, ...withoutWorkflowSource } = publicParams;
7386
- publicParams = { ...withoutWorkflowSource, workflowScript, args: deepFreezeWorkflowArgs(normalizedArgs.args) };
7439
+ publicParams = { ...withoutWorkflowSource, workflowScript, args: "error" in normalizedArgs ? publicParams.args : deepFreezeWorkflowArgs(normalizedArgs.args) };
7387
7440
  }
7388
7441
  publicExecutions.add(publicParams);
7389
7442
  return executeWithSingleDispatchGuard(id, publicParams, signal, onUpdate, ctx);