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.
Files changed (152) hide show
  1. package/CHANGELOG.md +55 -0
  2. package/README.md +1 -1
  3. package/bundle/agents.js +3 -3
  4. package/bundle/child-tool-plan.js +2 -2
  5. package/bundle/{chunk-L5ZHE4L4.js → chunk-3JCDWF4V.js} +4 -4
  6. package/bundle/{chunk-LSRUTHT7.js → chunk-43SCHIMD.js} +1 -1
  7. package/bundle/{chunk-VJHOELQP.js → chunk-46XKCPJR.js} +193 -81
  8. package/bundle/{chunk-G5DKFLLI.js → chunk-4SDU2BZX.js} +15 -10
  9. package/bundle/{chunk-2ZSNH26H.js → chunk-4Y2ROR7L.js} +7 -7
  10. package/bundle/{chunk-V2JWDB5U.js → chunk-52UBALJL.js} +2 -2
  11. package/bundle/{chunk-3DC5KBVP.js → chunk-5TYMSZX3.js} +1 -1
  12. package/bundle/{chunk-NNLASTQE.js → chunk-6XJB7PIX.js} +20 -6
  13. package/bundle/{chunk-ZBC44JJ3.js → chunk-CIZQXJ5Q.js} +22 -9
  14. package/bundle/{chunk-KSWQVGDW.js → chunk-FXUXCX2K.js} +225 -18
  15. package/bundle/{chunk-563BHAZ5.js → chunk-G4GZD3OJ.js} +35 -26
  16. package/bundle/{chunk-ARRKBB2B.js → chunk-GJECHSAR.js} +2 -2
  17. package/bundle/{chunk-V3BIUPLU.js → chunk-IVAE5Z6Q.js} +256 -52
  18. package/bundle/{chunk-V6MR5TOQ.js → chunk-JYUKW2SY.js} +25 -19
  19. package/bundle/{chunk-BJN5LUQY.js → chunk-OYF6AFDY.js} +1 -1
  20. package/bundle/{chunk-CEKS3TFO.js → chunk-PBK2I7WY.js} +6 -6
  21. package/bundle/{chunk-TUWLXTAM.js → chunk-PDZWJCHD.js} +681 -320
  22. package/bundle/{chunk-EYNJ6VL6.js → chunk-PLCCBLPY.js} +2 -2
  23. package/bundle/{chunk-XMFLCKMQ.js → chunk-QE4AGIMG.js} +339 -132
  24. package/bundle/{chunk-74RT5YQE.js → chunk-RMQFMMAT.js} +123 -33
  25. package/bundle/{chunk-WSBNENFS.js → chunk-UCPP4GNU.js} +14 -4
  26. package/bundle/{chunk-2XYWN7QJ.js → chunk-UTT254JE.js} +2 -2
  27. package/bundle/{chunk-BPS2AGBZ.js → chunk-VSUSLDNW.js} +93 -52
  28. package/bundle/{chunk-ZP3HODFH.js → chunk-XSWOTIA3.js} +1 -1
  29. package/bundle/{chunk-3IF2PGW7.js → chunk-YKEWIB4M.js} +1 -1
  30. package/bundle/{chunk-26C3WLYQ.js → chunk-ZIV4J4HG.js} +498 -274
  31. package/bundle/control-channel.js +2 -2
  32. package/bundle/index.js +1 -1
  33. package/bundle/intercom-bridge.js +2 -2
  34. package/bundle/preflight.js +8 -8
  35. package/bundle/project-panes.js +3 -3
  36. package/docs/agents.md +37 -7
  37. package/docs/configuration.md +9 -1
  38. package/docs/tool-reference.md +3 -1
  39. package/docs/workflows.md +16 -0
  40. package/package.json +2 -2
  41. package/skills/council-mode/SKILL.md +1 -4
  42. package/skills/pi-subagents/SKILL.md +130 -107
  43. package/skills/pi-subagents/references/orchestration.md +124 -0
  44. package/skills/pi-subagents/references/prompting-and-roles.md +96 -295
  45. package/src/agents/agent-management.js +3 -3
  46. package/src/agents/agent-memory.js +3 -1
  47. package/src/agents/agents.js +6 -6
  48. package/src/agents/frontmatter.d.ts +2 -0
  49. package/src/agents/frontmatter.js +15 -1
  50. package/src/agents/skills.js +2 -1
  51. package/src/extension/config.js +3 -0
  52. package/src/extension/herdr-pi-bridge.js +17 -10
  53. package/src/extension/index.js +82 -2
  54. package/src/extension/reply-workflow-script.js +5 -2
  55. package/src/extension/schemas.js +3 -3
  56. package/src/extension/subagent-guide.js +1 -2
  57. package/src/intercom/native-supervisor-channel.js +20 -0
  58. package/src/missions/lifecycle.js +7 -1
  59. package/src/runs/background/active-async-capacity.d.ts +1 -0
  60. package/src/runs/background/active-async-capacity.js +9 -3
  61. package/src/runs/background/async-execution.js +20 -10
  62. package/src/runs/background/async-job-tracker.d.ts +6 -1
  63. package/src/runs/background/async-job-tracker.js +9 -4
  64. package/src/runs/background/async-status.d.ts +4 -0
  65. package/src/runs/background/async-status.js +22 -3
  66. package/src/runs/background/await-async-run.js +3 -7
  67. package/src/runs/background/boot-id.d.ts +12 -0
  68. package/src/runs/background/boot-id.js +47 -0
  69. package/src/runs/background/interrupted-elsewhere.d.ts +22 -0
  70. package/src/runs/background/interrupted-elsewhere.js +68 -0
  71. package/src/runs/background/notify.d.ts +2 -0
  72. package/src/runs/background/notify.js +13 -0
  73. package/src/runs/background/result-delivery-ownership.d.ts +6 -0
  74. package/src/runs/background/result-delivery-ownership.js +19 -1
  75. package/src/runs/background/result-watcher.d.ts +3 -1
  76. package/src/runs/background/result-watcher.js +24 -8
  77. package/src/runs/background/run-child-session.d.ts +1 -6
  78. package/src/runs/background/run-child-session.js +1 -1
  79. package/src/runs/background/run-status.js +2 -1
  80. package/src/runs/background/stale-run-reconciler.d.ts +25 -0
  81. package/src/runs/background/stale-run-reconciler.js +52 -13
  82. package/src/runs/background/subagent-runner-bootstrap.js +3 -0
  83. package/src/runs/background/subagent-runner.d.ts +4 -0
  84. package/src/runs/background/subagent-runner.js +13 -5
  85. package/src/runs/background/subagent-wait.d.ts +1 -1
  86. package/src/runs/background/subagent-wait.js +6 -1
  87. package/src/runs/background/terminal-run-index.d.ts +2 -0
  88. package/src/runs/background/terminal-run-index.js +44 -3
  89. package/src/runs/foreground/async-stop-action.js +3 -1
  90. package/src/runs/foreground/execution.js +6 -3
  91. package/src/runs/foreground/foreground-history.d.ts +16 -2
  92. package/src/runs/foreground/foreground-history.js +133 -31
  93. package/src/runs/foreground/subagent-executor.d.ts +11 -0
  94. package/src/runs/foreground/subagent-executor.js +277 -74
  95. package/src/runs/shared/child-launch.d.ts +2 -2
  96. package/src/runs/shared/child-session.d.ts +3 -2
  97. package/src/runs/shared/child-session.js +51 -8
  98. package/src/runs/shared/child-tool-plan.d.ts +7 -0
  99. package/src/runs/shared/child-tool-plan.js +21 -6
  100. package/src/runs/shared/herdr-connection.d.ts +17 -8
  101. package/src/runs/shared/herdr-connection.js +19 -7
  102. package/src/runs/shared/herdr-external-adapters.d.ts +3 -2
  103. package/src/runs/shared/herdr-external-adapters.js +1 -1
  104. package/src/runs/shared/herdr-machine.d.ts +12 -2
  105. package/src/runs/shared/herdr-machine.js +55 -9
  106. package/src/runs/shared/herdr-pane-host.d.ts +88 -0
  107. package/src/runs/shared/herdr-pane-host.js +155 -0
  108. package/src/runs/shared/herdr-placed-run.d.ts +27 -150
  109. package/src/runs/shared/herdr-placed-run.js +48 -395
  110. package/src/runs/shared/local-machine-access.d.ts +5 -0
  111. package/src/runs/shared/local-machine-access.js +28 -0
  112. package/src/runs/shared/orca-progress-tabs.d.ts +0 -1
  113. package/src/runs/shared/orca-progress-tabs.js +1 -24
  114. package/src/runs/shared/parallel-utils.d.ts +1 -1
  115. package/src/runs/shared/placed-run-owner.d.ts +49 -0
  116. package/src/runs/shared/placed-run-owner.js +93 -0
  117. package/src/runs/shared/placement-host.d.ts +99 -0
  118. package/src/runs/shared/placement-host.js +157 -0
  119. package/src/runs/shared/rex-machine.d.ts +25 -0
  120. package/src/runs/shared/rex-machine.js +83 -0
  121. package/src/runs/shared/rex-pane-host.d.ts +62 -0
  122. package/src/runs/shared/rex-pane-host.js +327 -0
  123. package/src/shared/completion-owner.d.ts +5 -0
  124. package/src/shared/completion-owner.js +5 -0
  125. package/src/shared/session-identity.d.ts +2 -0
  126. package/src/shared/session-identity.js +26 -0
  127. package/src/shared/types.d.ts +45 -6
  128. package/src/tui/fleet.d.ts +1 -0
  129. package/src/tui/fleet.js +25 -15
  130. package/src/tui/render.d.ts +6 -0
  131. package/src/tui/render.js +3 -3
  132. package/src/tui/subagent-messages.js +1 -0
  133. package/src/workflows/scripted-workflow.d.ts +1 -1
  134. package/src/workflows/workflow-auto-resume.d.ts +32 -0
  135. package/src/workflows/workflow-auto-resume.js +102 -0
  136. package/src/workflows/workflow-launch-record.d.ts +27 -0
  137. package/src/workflows/workflow-launch-record.js +48 -0
  138. package/src/workflows/workflow-resume-claim.d.ts +82 -0
  139. package/src/workflows/workflow-resume-claim.js +210 -0
  140. package/src/workflows/workflow-resume.d.ts +56 -0
  141. package/src/workflows/workflow-resume.js +106 -0
  142. package/src/workflows/workflow-reuse.d.ts +15 -9
  143. package/src/workflows/workflow-reuse.js +77 -14
  144. package/src/workflows/workflow-revival.d.ts +2 -0
  145. package/src/workflows/workflow-revival.js +2 -1
  146. package/src/workflows/workflow-stop-cause.d.ts +6 -0
  147. package/src/workflows/workflow-stop-cause.js +8 -0
  148. package/skills/pi-subagents/references/constraints-and-recipes.md +0 -74
  149. package/skills/pi-subagents/references/execution-controls.md +0 -563
  150. package/skills/pi-subagents/references/management-authoring-rpc.md +0 -165
  151. package/skills/pi-subagents/references/multi-lane-orchestration.md +0 -61
  152. package/skills/pi-subagents/references/review-and-validation.md +0 -73
@@ -3,7 +3,7 @@ import {
3
3
  projectRuntimeAcknowledgedExtensions,
4
4
  registerSubagentPromptBoundary,
5
5
  registerSubagentPromptRuntime
6
- } from "./chunk-L5ZHE4L4.js";
6
+ } from "./chunk-3JCDWF4V.js";
7
7
  import {
8
8
  INSPECTOR_ACTIONS,
9
9
  canQueueRetainedAsyncFollowUp,
@@ -25,15 +25,19 @@ import {
25
25
  updateSteeringTarget,
26
26
  waitForSteeringAction,
27
27
  workflowAsyncChildSteeringGuidance
28
- } from "./chunk-CEKS3TFO.js";
29
- import "./chunk-74RT5YQE.js";
28
+ } from "./chunk-PBK2I7WY.js";
29
+ import {
30
+ REX_LOCAL_MACHINE,
31
+ isRexLocalMachine,
32
+ resolveRexLocalPlacement
33
+ } from "./chunk-RMQFMMAT.js";
30
34
  import {
31
35
  COMPLETION_ACTION,
32
36
  DEFAULT_CONTROL_CONFIG,
33
37
  HERDR_FOREGROUND_CONTROL_CHANGED_EVENT,
34
38
  JITI_ALIAS_ENV,
35
- MAX_REMEMBERED_FOREGROUND_RUNS,
36
39
  STATUS_ACTION,
40
+ WORKFLOW_RUNTIME_REPLACED_STOP_NOTICE,
37
41
  appendWorkflowChildJournal,
38
42
  attachNestedChildrenToResultChildren,
39
43
  buildControlEvent,
@@ -45,6 +49,8 @@ import {
45
49
  childSessionFactoryModule,
46
50
  childSessionHasQueuedMessages,
47
51
  claimControlNotification,
52
+ claimWorkflowResume,
53
+ claimedWorkflowRunRefusal,
48
54
  clearProviderRetry,
49
55
  controlChildCommand,
50
56
  createChildExternalJobBridgeSweeper,
@@ -72,11 +78,12 @@ import {
72
78
  isScheduledRunAction,
73
79
  isWorkflowScriptPath,
74
80
  listRetainedChildren,
81
+ manualWorkflowResumeRefusalText,
75
82
  matchWorkflowReuse,
76
83
  normalizePublicSubagentExecution,
77
84
  observeProviderDiagnostics,
78
85
  parseWatchdogThinkingInput,
79
- persistForegroundRunHistory,
86
+ prepareWorkflowResume,
80
87
  projectChildSessionEventForJson,
81
88
  projectWorkflowKeyRevival,
82
89
  readNamedWorkflowReuseSource,
@@ -84,13 +91,16 @@ import {
84
91
  readWorkflowReceipt,
85
92
  recommendStrongWatchdogModel,
86
93
  recommendWatchdogModel,
94
+ recordWorkflowResumeRefusal,
87
95
  recordWorkflowRevival,
96
+ releaseWorkflowResumeClaim,
88
97
  resolveControlConfig,
89
98
  resolveHostPeerAliases,
90
99
  resolveSubagentResultStatus,
91
100
  resolveToolTimeoutMs,
92
101
  resolveWatchdogModelInput,
93
102
  resolveWorkflowReceiptResumeEntry,
103
+ resumedRunStarted,
94
104
  retainLiveForegroundNestedRoute,
95
105
  retainsChildCommand,
96
106
  shouldEmitOpenToolAttention,
@@ -103,11 +113,13 @@ import {
103
113
  withWorkflowRevivals,
104
114
  workflowChildFingerprint,
105
115
  workflowReceiptPath,
106
- workflowRuntimeReplacedRelaunchNotice,
116
+ workflowResumeRefusal,
117
+ workflowResumeTargetId,
107
118
  workflowScriptDigest,
108
119
  workflowStopCause,
120
+ writeWorkflowLaunchRecord,
109
121
  writeWorkflowReceipt
110
- } from "./chunk-26C3WLYQ.js";
122
+ } from "./chunk-ZIV4J4HG.js";
111
123
  import {
112
124
  NATIVE_SUPERVISOR_TOOL_NAME,
113
125
  SUBAGENT_PARENT_SESSION_ENV,
@@ -117,22 +129,26 @@ import {
117
129
  finalizeToolResult,
118
130
  registerPinnedTool,
119
131
  resolveCurrentSessionId,
132
+ resolvePiSessionId,
120
133
  resolveSupervisorChannelDir,
121
134
  resolveWaitToolConfig,
122
135
  resolveWatchdogConfig,
123
136
  sendRuleViolationWarning,
124
137
  writeWatchdogModelSettings
125
- } from "./chunk-BPS2AGBZ.js";
138
+ } from "./chunk-VSUSLDNW.js";
126
139
  import {
127
- currentCompletionOwnerId,
140
+ MAX_REMEMBERED_FOREGROUND_RUNS,
141
+ discardRunningForegroundRun,
142
+ foregroundChildStateLabel,
128
143
  formatAsyncResultTranscript,
129
144
  formatAsyncRunTranscript,
130
145
  formatNestedRunTranscript,
131
146
  inspectSubagentFleet,
147
+ persistForegroundRun,
132
148
  resolveSubagentRunId,
133
149
  resolveWorkflowChatProgress,
134
150
  stopAsyncRun
135
- } from "./chunk-KSWQVGDW.js";
151
+ } from "./chunk-FXUXCX2K.js";
136
152
  import {
137
153
  MODEL_ONLY_TOOL,
138
154
  RunFanoutLimitError,
@@ -194,7 +210,7 @@ import {
194
210
  writeParallelHandoffGroup,
195
211
  writeRunFanoutBudgetDescriptor,
196
212
  writeWorktreeSetupHandoff
197
- } from "./chunk-NNLASTQE.js";
213
+ } from "./chunk-6XJB7PIX.js";
198
214
  import {
199
215
  authorizeWorkflowResourceHost,
200
216
  claimWorkflowChildPermit,
@@ -211,10 +227,10 @@ import {
211
227
  canPreferFork,
212
228
  createForkContextResolver,
213
229
  resolveSubagentLaunchContext
214
- } from "./chunk-ARRKBB2B.js";
230
+ } from "./chunk-GJECHSAR.js";
215
231
  import {
216
232
  handleRefinementAction
217
- } from "./chunk-EYNJ6VL6.js";
233
+ } from "./chunk-PLCCBLPY.js";
218
234
  import {
219
235
  ActiveAsyncCapacityError,
220
236
  acquireActiveAsyncCapacity,
@@ -228,7 +244,7 @@ import {
228
244
  resolveDisabledFeatureSurface,
229
245
  resolveMaxActiveAsyncRunsPerSession,
230
246
  transferActiveAsyncCapacity
231
- } from "./chunk-WSBNENFS.js";
247
+ } from "./chunk-UCPP4GNU.js";
232
248
  import {
233
249
  DEFAULT_STALE_TERMINAL_ACTIVE_MARKER_MS,
234
250
  MACHINE_DIFF_OPTIONS,
@@ -239,12 +255,15 @@ import {
239
255
  activeRunMarkerAgeMs,
240
256
  attachMissionToLaunchResult,
241
257
  attachRootChildrenToSteps,
242
- checkPidLiveness,
258
+ checkRecordedPidLiveness,
243
259
  cleanupWorktrees,
244
260
  createMissionWorkflowState,
245
261
  createNestedRoute,
246
262
  createWorktrees,
263
+ currentBootId,
264
+ currentCompletionOwnerId,
247
265
  currentPidNamespaceScope,
266
+ currentRecordedPid,
248
267
  diffWorktrees,
249
268
  encodeIndexSegment,
250
269
  executeWorkflowHostCommand,
@@ -304,7 +323,7 @@ import {
304
323
  writeNestedControlRequest,
305
324
  writeNestedControlResult,
306
325
  writeNestedEvent
307
- } from "./chunk-VJHOELQP.js";
326
+ } from "./chunk-46XKCPJR.js";
308
327
  import {
309
328
  closeSteerInbox,
310
329
  consumeSteerRequests,
@@ -312,7 +331,7 @@ import {
312
331
  readRevivalBriefs,
313
332
  requestAsyncSteer,
314
333
  watchAsyncControlInbox
315
- } from "./chunk-BJN5LUQY.js";
334
+ } from "./chunk-OYF6AFDY.js";
316
335
  import "./chunk-NIXWDZZV.js";
317
336
  import {
318
337
  INTERCOM_BRIDGE_MARKER,
@@ -321,7 +340,7 @@ import {
321
340
  resolveIntercomBridge,
322
341
  resolveIntercomSessionTarget,
323
342
  resolveSubagentIntercomTarget
324
- } from "./chunk-ZP3HODFH.js";
343
+ } from "./chunk-XSWOTIA3.js";
325
344
  import {
326
345
  resolveLaunchBinding,
327
346
  stableJsonDigest
@@ -335,7 +354,7 @@ import {
335
354
  resolvePiLaunchToolPlan,
336
355
  resolveRuntimeModulePath,
337
356
  supervisorChannelDir
338
- } from "./chunk-G5DKFLLI.js";
357
+ } from "./chunk-4SDU2BZX.js";
339
358
  import {
340
359
  assertRequiredChildExtensionsAdmitted,
341
360
  hasMandatoryRequiredChildExtensions,
@@ -346,7 +365,7 @@ import {
346
365
  import {
347
366
  HERDR_PROJECT_PANE_ACTIONS,
348
367
  handleHerdrProjectPaneAction
349
- } from "./chunk-V2JWDB5U.js";
368
+ } from "./chunk-52UBALJL.js";
350
369
  import "./chunk-7J4ZXMY7.js";
351
370
  import {
352
371
  PROJECT_SUBAGENTS_RELATIVE_DIR,
@@ -359,12 +378,12 @@ import {
359
378
  getProjectSubagentsDir,
360
379
  writeArtifact,
361
380
  writeMetadata
362
- } from "./chunk-3DC5KBVP.js";
381
+ } from "./chunk-5TYMSZX3.js";
363
382
  import "./chunk-N2BN7BF5.js";
364
383
  import {
365
384
  getExternalJobProvider
366
385
  } from "./chunk-YYREO77V.js";
367
- import "./chunk-3IF2PGW7.js";
386
+ import "./chunk-YKEWIB4M.js";
368
387
  import {
369
388
  CODE_OWNED_EXTERNAL_CLI_ADAPTER_IDS,
370
389
  ChainOutputValidationError,
@@ -512,7 +531,7 @@ import {
512
531
  writeAtomicJson,
513
532
  writeInitialProgressFile,
514
533
  writePrivateAtomicJson
515
- } from "./chunk-ZBC44JJ3.js";
534
+ } from "./chunk-CIZQXJ5Q.js";
516
535
  import {
517
536
  CHAIN_RUNS_DIR,
518
537
  DEFAULT_ARTIFACT_CONFIG,
@@ -884,6 +903,11 @@ function machineSettingsFrom(settings, keys, filePath) {
884
903
  throw new Error(`Subagent settings in '${filePath}' set 'machines.${key}.env'. Saved-machine runs use the remote Herdr/Pi environment; configure credentials and environment on '${key}' and remove the local env map.`);
885
904
  }
886
905
  }
906
+ if (record2.rex !== void 0) {
907
+ const rex = record2.rex, ssh = rex && typeof rex === "object" && !Array.isArray(rex) && Object.keys(rex).every((field) => field === "ssh") ? rex.ssh : void 0;
908
+ if (typeof ssh !== "string") throw new Error(`Subagent settings in '${filePath}' have invalid 'machines.${key}.rex'; expected { "ssh": "<ssh target>" }.`);
909
+ entry.rex = { ssh: validateTarget(ssh, key) };
910
+ }
887
911
  return entry;
888
912
  }
889
913
  function readMachineSettings(cwd, keys) {
@@ -891,9 +915,14 @@ function readMachineSettings(cwd, keys) {
891
915
  const projectPath = path.join(getProjectConfigDir(findProjectRootForSettings(cwd)), "settings.json");
892
916
  const user = machineSettingsFrom(readJsonObject(userPath), keys, userPath);
893
917
  const project = projectPath === userPath ? void 0 : machineSettingsFrom(readJsonObject(projectPath), keys, projectPath);
918
+ if (project?.rex) throw new Error(`Project settings '${projectPath}' set a Rex SSH host in 'machines'. Move the rex entry to your user settings '${userPath}'; only user settings choose which host a task runs on.`);
894
919
  if (!user && !project) return void 0;
895
920
  return { ...user, ...project };
896
921
  }
922
+ function userRexMachine(machine) {
923
+ const userPath = path.join(getAgentDir(), "settings.json");
924
+ return machineSettingsFrom(readJsonObject(userPath), [machine], userPath)?.rex !== void 0;
925
+ }
897
926
  function findProjectRootForSettings(cwd) {
898
927
  let current = path.resolve(cwd);
899
928
  while (true) {
@@ -903,6 +932,12 @@ function findProjectRootForSettings(cwd) {
903
932
  current = parent;
904
933
  }
905
934
  }
935
+ function remoteMachineCwd(stepCwd, root, name) {
936
+ const step = stepCwd?.trim();
937
+ if (step && isRemoteAbsolute(step)) return step;
938
+ if (!root) throw new Error(`No root for ${name} in this repo. Set subagents.machines.${name}.cwd in .pi/settings.json or pass an absolute cwd on that machine.`);
939
+ return step ? path.posix.join(root, step) : root;
940
+ }
906
941
  function resolveHerdrMachinePlacement(input) {
907
942
  const requested = validateMachineName(input.machine);
908
943
  const catalog = input.catalogJson !== void 0 ? parseMachineCatalog(input.catalogJson) : readHerdrMachineCatalog(input.env ?? process.env, input.herdrBin ?? process.env.HERDR_BIN ?? "herdr");
@@ -913,11 +948,7 @@ function resolveHerdrMachinePlacement(input) {
913
948
  if (settings?.env && Object.keys(settings.env).length > 0) {
914
949
  throw new Error(`Saved-machine environment for '${name}' must be configured remotely. Remove machines.${name}.env and configure the remote Herdr/Pi session instead.`);
915
950
  }
916
- const stepCwd = input.stepCwd?.trim();
917
- let cwd;
918
- if (stepCwd && isRemoteAbsolute(stepCwd)) cwd = stepCwd;
919
- else if (settings?.cwd) cwd = stepCwd ? path.posix.join(settings.cwd, stepCwd) : settings.cwd;
920
- else throw new Error(`No root for ${name} in this repo. Set subagents.machines.${name}.cwd in .pi/settings.json or pass an absolute cwd on that machine.`);
951
+ const cwd = remoteMachineCwd(input.stepCwd, settings?.cwd, name);
921
952
  return {
922
953
  machine: {
923
954
  provider: "herdr",
@@ -930,8 +961,31 @@ function resolveHerdrMachinePlacement(input) {
930
961
  ...settings?.env ? { env: settings.env } : {}
931
962
  };
932
963
  }
964
+ function resolveMachinePlacement(input) {
965
+ const requested = validateMachineName(input.machine);
966
+ const settings = input.settings ?? readMachineSettings(input.cwd, [requested]);
967
+ if (requested === REX_LOCAL_MACHINE) {
968
+ if (settings?.rex) throw new Error("Machine 'local' is reserved for a Rex pane on this machine; give the Rex SSH host in subagents.machines.local.rex another name.");
969
+ return { machine: resolveRexLocalPlacement({ cwd: input.cwd, stepCwd: input.stepCwd, env: input.env }) };
970
+ }
971
+ if (settings?.rex) return { machine: { provider: "rex", id: requested, target: settings.rex.ssh, cwd: validateRemoteCwd(remoteMachineCwd(input.stepCwd, settings.cwd, requested), requested) } };
972
+ return resolveHerdrMachinePlacement(input);
973
+ }
933
974
  function formatHerdrMachineRunnerUnsupported(input) {
934
975
  if (input.machine === void 0) return void 0;
976
+ const name = input.machine.trim();
977
+ let rex;
978
+ try {
979
+ rex = name === REX_LOCAL_MACHINE || userRexMachine(name);
980
+ } catch (error) {
981
+ return error instanceof Error ? error.message : String(error);
982
+ }
983
+ if (rex) {
984
+ if (input.runnerType !== void 0 && input.runnerType !== "pi") return `Agent '${input.agentName}' requested machine '${name}', but Rex supports native Pi children only. Remove the machine or use a native Pi agent.`;
985
+ if (input.worktree === true) return `Agent '${input.agentName}' requested machine '${name}', but managed worktrees cannot be combined with machine placement.`;
986
+ if (process.platform === "win32") return `Machine '${name}' runs the child in a Rex pane, which is not supported on Windows.`;
987
+ return void 0;
988
+ }
935
989
  if (input.runnerType !== void 0 && input.runnerType !== "pi" && input.runnerType !== "external-cli") {
936
990
  return `Agent '${input.agentName}' requested machine '${input.machine}', but this runner cannot use pane-native Herdr placement. Use native Pi or a built-in Claude, Codex, or Cursor profile.`;
937
991
  }
@@ -2044,7 +2098,9 @@ function spawnRunner(cfg, suffix, cwd, initialStatus, initialStatusPath, launchP
2044
2098
  const runnerProcessInstanceId = randomUUID2();
2045
2099
  const hasRevivalLease = typeof cfg.revivalLease === "object";
2046
2100
  const launchBarrierToken = hasRevivalLease ? void 0 : runnerProcessInstanceId;
2047
- const launchConfig = { ...cfg, runnerProcessInstanceId, ...launchBarrierToken ? { launchBarrierToken } : {} };
2101
+ const launcher = cfg.launcher;
2102
+ const bootId = launcher ? void 0 : currentBootId();
2103
+ const launchConfig = { ...cfg, runnerProcessInstanceId, ...launchBarrierToken ? { launchBarrierToken } : {}, ...bootId ? { bootId } : {} };
2048
2104
  writePrivateAtomicJson(cfgPath, launchConfig);
2049
2105
  const command = binaryHost ?? nodeExecutable;
2050
2106
  const launchForStartup = launchConfig;
@@ -2060,7 +2116,6 @@ function spawnRunner(cfg, suffix, cwd, initialStatus, initialStatusPath, launchP
2060
2116
  if (startupAckPath) fs7.rmSync(startupAckPath, { force: true });
2061
2117
  if (startupConfirmPath) fs7.rmSync(startupConfirmPath, { force: true });
2062
2118
  if (startupProceedPath) fs7.rmSync(startupProceedPath, { force: true });
2063
- const launcher = launchConfig.launcher;
2064
2119
  const identityPath = launcher && launchBarrierToken && launchAsyncDir ? path6.join(launchAsyncDir, "runner-startup.json") : void 0;
2065
2120
  if (identityPath) fs7.rmSync(identityPath, { force: true });
2066
2121
  let runnerIdentity;
@@ -2132,7 +2187,7 @@ function spawnRunner(cfg, suffix, cwd, initialStatus, initialStatusPath, launchP
2132
2187
  writePrivateAtomicJson(path6.join(asyncDir, "launcher-close.json"), { version: 1, runId, runnerProcessInstanceId, closeObservedAt: Date.now(), exitCode, signal, ...runnerIdentity ? { runnerPid: runnerIdentity.pid } : {} });
2133
2188
  } catch {
2134
2189
  }
2135
- if (!runnerIdentity || runnerIdentity.pidNamespaceScope !== currentPidNamespaceScope() || checkPidLiveness(runnerIdentity.pid, process.kill, runnerIdentity.pidNamespaceScope !== void 0) !== "dead") return;
2190
+ if (!runnerIdentity || runnerIdentity.pidNamespaceScope !== currentPidNamespaceScope() || checkRecordedPidLiveness(runnerIdentity) !== "dead") return;
2136
2191
  }
2137
2192
  finalizeProcessTerminal(asyncDir, runId, {
2138
2193
  processInstanceId: runnerProcessInstanceId,
@@ -2188,7 +2243,7 @@ function spawnRunner(cfg, suffix, cwd, initialStatus, initialStatusPath, launchP
2188
2243
  try {
2189
2244
  writePrivateAtomicJson(initialStatusPath, {
2190
2245
  ...initialStatus,
2191
- ...launcher ? {} : { pid: proc.pid, pidNamespaceScope: currentPidNamespaceScope() },
2246
+ ...launcher ? {} : { pid: proc.pid, pidNamespaceScope: currentPidNamespaceScope(), ...bootId ? { bootId } : {} },
2192
2247
  processTerminal: { version: 1, state: "pending", runId: initialStatus.runId, runnerProcessInstanceId }
2193
2248
  });
2194
2249
  updateActiveRunIndex(path6.dirname(initialStatusPath), initialStatus.state, initialStatus.toolCallId);
@@ -2375,7 +2430,7 @@ function buildAsyncRunnerSteps(id, params) {
2375
2430
  let machineEnv;
2376
2431
  if (requestedMachine) {
2377
2432
  try {
2378
- const placement = resolveHerdrMachinePlacement({ machine: requestedMachine, cwd: runnerCwd, stepCwd: s.cwd ?? params.machineCwd });
2433
+ const placement = resolveMachinePlacement({ machine: requestedMachine, cwd: runnerCwd, stepCwd: s.cwd ?? params.machineCwd });
2379
2434
  machine = placement.machine;
2380
2435
  machineEnv = placement.env;
2381
2436
  } catch (error) {
@@ -2867,6 +2922,7 @@ function executeAsyncChain(id, params) {
2867
2922
  }
2868
2923
  const initialStatusAt = Date.now();
2869
2924
  const initialCompletionOwnerId = ctx.completionOwnerId ?? currentCompletionOwnerId();
2925
+ const completionOwnerProcess = currentRecordedPid();
2870
2926
  const launchParentSessionId = ctx.parentSessionId ?? ctx.currentSessionId;
2871
2927
  try {
2872
2928
  writeRetainedRequiredChildExtensions(asyncDir, params.requiredExtensions ?? ctx.childRuntime?.requiredExtensions ?? resolveRequiredChildExtensions(launchParentSessionId ?? void 0));
@@ -2891,6 +2947,7 @@ function executeAsyncChain(id, params) {
2891
2947
  asyncDir,
2892
2948
  sessionId: ctx.currentSessionId,
2893
2949
  completionOwnerId: ctx.completionOwnerId ?? currentCompletionOwnerId(),
2950
+ completionOwnerProcess,
2894
2951
  ...capabilityCeiling ? { capabilityCeiling } : {},
2895
2952
  piPackageRoot,
2896
2953
  childSessionFactoryModule: childSessionFactoryModule(),
@@ -2932,6 +2989,7 @@ function executeAsyncChain(id, params) {
2932
2989
  runId: id,
2933
2990
  ...ctx.currentSessionId ? { sessionId: ctx.currentSessionId } : {},
2934
2991
  ...initialCompletionOwnerId ? { completionOwnerId: initialCompletionOwnerId } : {},
2992
+ completionOwnerProcess,
2935
2993
  mode: resultMode,
2936
2994
  state: "running",
2937
2995
  startedAt: initialStatusAt,
@@ -3148,7 +3206,7 @@ function executeAsyncSingle(id, params) {
3148
3206
  let machineEnv;
3149
3207
  if (requestedMachine) {
3150
3208
  try {
3151
- const placement = resolveHerdrMachinePlacement({ machine: requestedMachine, cwd: runnerCwd, stepCwd: params.machineCwd });
3209
+ const placement = resolveMachinePlacement({ machine: requestedMachine, cwd: runnerCwd, stepCwd: params.machineCwd });
3152
3210
  machine = placement.machine;
3153
3211
  machineEnv = placement.env;
3154
3212
  } catch (error) {
@@ -3404,6 +3462,7 @@ function executeAsyncSingle(id, params) {
3404
3462
  let spawnResultOrPromise = {};
3405
3463
  const initialStatusAt = Date.now();
3406
3464
  const initialCompletionOwnerId = ctx.completionOwnerId ?? currentCompletionOwnerId();
3465
+ const completionOwnerProcess = currentRecordedPid();
3407
3466
  const launchParentSessionId = ctx.parentSessionId ?? ctx.currentSessionId;
3408
3467
  try {
3409
3468
  spawnResultOrPromise = spawnRunner(
@@ -3485,6 +3544,7 @@ function executeAsyncSingle(id, params) {
3485
3544
  asyncDir,
3486
3545
  sessionId: ctx.currentSessionId,
3487
3546
  completionOwnerId: ctx.completionOwnerId ?? currentCompletionOwnerId(),
3547
+ completionOwnerProcess,
3488
3548
  ...capabilityCeiling ? { capabilityCeiling } : {},
3489
3549
  piPackageRoot,
3490
3550
  childSessionFactoryModule: childSessionFactoryModule(),
@@ -3529,6 +3589,7 @@ function executeAsyncSingle(id, params) {
3529
3589
  runId: id,
3530
3590
  ...ctx.currentSessionId ? { sessionId: ctx.currentSessionId } : {},
3531
3591
  ...initialCompletionOwnerId ? { completionOwnerId: initialCompletionOwnerId } : {},
3592
+ completionOwnerProcess,
3532
3593
  mode: "single",
3533
3594
  ...params.toolCallId ? { toolCallId: params.toolCallId } : {},
3534
3595
  state: "running",
@@ -3926,7 +3987,8 @@ var WORKFLOW_FENCE = /^```(?:js|javascript) workflow[ \t]*$/;
3926
3987
  var PLAIN_JS_FENCE = /^```(?:js|javascript)[ \t]*$/;
3927
3988
  var OPEN_FENCE = /^(`{3,}|~{3,})/;
3928
3989
  var CLOSE_FENCE = /^(`{3,}|~{3,})[ \t]*$/;
3929
- var FILE_FALLBACK = 'Or write the script to a file and pass its path, such as workflow: "./script.js".';
3990
+ var SUMMARY_NOTE = 'On some models, text written after a tool call in the same turn reaches the session only as a summary without code blocks, so for the rest of this turn write the script to a file and pass its path, such as workflow: "./script.js".';
3991
+ var FILE_FALLBACK = `If the block is in your reply: ${SUMMARY_NOTE}`;
3930
3992
  function readReplyWorkflowScript(sessionManager, toolCallId) {
3931
3993
  const branch = sessionManager.getBranch();
3932
3994
  for (let index = branch.length - 1; index >= 0; index--) {
@@ -3942,7 +4004,7 @@ function readReplyWorkflowScript(sessionManager, toolCallId) {
3942
4004
  function scriptFromReply(content) {
3943
4005
  const replyCalls = content.filter((block) => block.type === "toolCall" && block.name === "subagent" && (block.arguments?.workflow === true || block.arguments?.workflow === "true")).length;
3944
4006
  if (replyCalls > 1) return { error: `This reply has ${replyCalls} subagent calls with workflow: true; a reply can carry only one. Pass other scripts as workflow file paths.` };
3945
- if (!content.some((block) => block.type === "text")) return { error: 'The assistant message that issued this call has no text in the session, so the reply\'s visible text, including any ```js workflow block, never reached it. Write the script to a file and pass its path, such as workflow: "./script.js".' };
4007
+ if (!content.some((block) => block.type === "text")) return { error: `The assistant message that issued this call has no text in the session, so the reply's visible text, including any \`\`\`js workflow block, never reached it. ${SUMMARY_NOTE}` };
3946
4008
  const text = content.flatMap((block) => block.type === "text" && typeof block.text === "string" ? [block.text] : []).join("\n");
3947
4009
  const { tagged, plain, unclosed } = workflowBlocks(text);
3948
4010
  if (unclosed) return { error: "The script's fenced block in this reply is not closed." };
@@ -4535,25 +4597,6 @@ ${createDone}
4535
4597
  }
4536
4598
  });
4537
4599
  }
4538
- function resolvePiSessionId(sessionFile) {
4539
- if (!sessionFile) return void 0;
4540
- try {
4541
- const fd = fs12.openSync(sessionFile, "r");
4542
- try {
4543
- const buffer = Buffer.alloc(16 * 1024);
4544
- const bytes = fs12.readSync(fd, buffer, 0, buffer.length, 0);
4545
- const line = buffer.toString("utf-8", 0, bytes).split("\n", 1)[0];
4546
- if (!line) return void 0;
4547
- const header = JSON.parse(line);
4548
- if (header.type === "session" && typeof header.id === "string" && /^[A-Za-z0-9-]{8,}$/.test(header.id)) return header.id;
4549
- return void 0;
4550
- } finally {
4551
- fs12.closeSync(fd);
4552
- }
4553
- } catch {
4554
- return void 0;
4555
- }
4556
- }
4557
4600
  function scheduleCleanup(nodeExecutable, paths) {
4558
4601
  try {
4559
4602
  const watchdog = spawn2(nodeExecutable, ["-e", ORCA_CLEANUP_WATCHDOG_SCRIPT, String(CLEANUP_DELAY_MS), ...paths], {
@@ -5576,7 +5619,8 @@ ${shared.acceptancePrompt}` : shared.systemPrompt,
5576
5619
  };
5577
5620
  return result2;
5578
5621
  }
5579
- const mutationSnapshot = options.machine ? { source: "tracked-files", trackedOnly: true, cwd: options.cwd ?? runtimeCwd, dirtyFiles: [], fingerprints: {}, unavailable: "Local Git evidence is not authoritative for a pane-native remote run." } : snapshotTrackedMutations(options.cwd ?? runtimeCwd);
5622
+ const mutationCwd = isRexLocalMachine(options.machine) ? options.machine.cwd : options.cwd ?? runtimeCwd;
5623
+ const mutationSnapshot = options.machine && !isRexLocalMachine(options.machine) ? { source: "tracked-files", trackedOnly: true, cwd: mutationCwd, dirtyFiles: [], fingerprints: {}, unavailable: "Local Git evidence is not authoritative for a pane-native remote run." } : snapshotTrackedMutations(mutationCwd);
5580
5624
  let structuredOutputToolInvoked = false;
5581
5625
  let structuredOutputMessageStartIndex;
5582
5626
  let toolAvailabilityError;
@@ -6293,7 +6337,7 @@ ${shared.acceptancePrompt}` : shared.systemPrompt,
6293
6337
  const toolDiagnosticError = diagnostic ? formatChildToolDiagnostic(diagnostic, { host: "parent" }) : void 0;
6294
6338
  toolAvailabilityError = toolDiagnosticError;
6295
6339
  result2.runtimeAcknowledgedExtensions = capture.runtimeAcknowledgedExtensions();
6296
- if (session?.machineEvidence) result2.nativeMachine = { provider: "herdr", machineId: session.machineEvidence.machineId, ...session.machineEvidence.initial ? { initialGit: session.machineEvidence.initial } : {}, ...session.machineEvidence.final ? { finalGit: session.machineEvidence.final } : {} };
6340
+ if (session?.machineEvidence) result2.nativeMachine = { provider: session.machineEvidence.provider, machineId: session.machineEvidence.machineId, ...session.machineEvidence.initial ? { initialGit: session.machineEvidence.initial } : {}, ...session.machineEvidence.final ? { finalGit: session.machineEvidence.final } : {} };
6297
6341
  let closeError = result2.error ?? toolDiagnosticError ?? assistantError;
6298
6342
  const promptErrorMessage = promptError === void 0 ? void 0 : promptError instanceof Error ? promptError.message : String(promptError);
6299
6343
  if (promptError !== void 0) childPromptFailed = true;
@@ -6500,7 +6544,7 @@ ${formatInheritedProviderDiagnostic({ agent: agent.name, model: launch.session.m
6500
6544
  durationMs: progress.durationMs
6501
6545
  };
6502
6546
  const remoteGitChanged = result2.nativeMachine?.initialGit && result2.nativeMachine.finalGit ? result2.nativeMachine.initialGit.head !== result2.nativeMachine.finalGit.head || result2.nativeMachine.initialGit.dirty !== result2.nativeMachine.finalGit.dirty : void 0;
6503
- const mutationEvidence = result2.nativeMachine ? { source: "tracked-files", trackedOnly: true, changedFiles: [], attemptedMutation: remoteGitChanged === true, ...remoteGitChanged === void 0 ? { unavailable: "Remote Git before/after evidence was incomplete." } : {} } : collectTrackedMutationEvidence(mutationSnapshot, options.cwd ?? runtimeCwd);
6547
+ const mutationEvidence = result2.nativeMachine && !isRexLocalMachine(options.machine) ? { source: "tracked-files", trackedOnly: true, changedFiles: [], attemptedMutation: remoteGitChanged === true, ...remoteGitChanged === void 0 ? { unavailable: "Remote Git before/after evidence was incomplete." } : {} } : collectTrackedMutationEvidence(mutationSnapshot, mutationCwd);
6504
6548
  const acceptanceOutput = getFinalOutput(result2.messages ?? []);
6505
6549
  const structuredText = result2.structuredOutput === void 0 ? void 0 : JSON.stringify(result2.structuredOutput, null, 2);
6506
6550
  let fullOutput = stripAcceptanceReport(acceptanceOutput);
@@ -8350,10 +8394,7 @@ function errorMessage2(error) {
8350
8394
  function runnerExitedWithoutResult(asyncDir, runId, resultPath) {
8351
8395
  const status = readStatus(asyncDir);
8352
8396
  if (!status || status.state !== "running" && status.state !== "queued" || typeof status.pid !== "number") return false;
8353
- const observedScope = currentPidNamespaceScope();
8354
- if (status.pidNamespaceScope !== void 0 && status.pidNamespaceScope !== observedScope) return false;
8355
- const pidScopeVerified = status.pidNamespaceScope !== void 0 && status.pidNamespaceScope === observedScope;
8356
- if (checkPidLiveness(status.pid, void 0, pidScopeVerified) !== "dead") return false;
8397
+ if (checkRecordedPidLiveness({ pid: status.pid, pidNamespaceScope: status.pidNamespaceScope, bootId: status.bootId }) !== "dead") return false;
8357
8398
  return !fs17.existsSync(resultPath) && !(status.sessionId && resultPayloadPathForSessionRun(asyncDir, status.sessionId, runId));
8358
8399
  }
8359
8400
  async function awaitExistingAsyncRun(asyncDir, runId, signal) {
@@ -8543,7 +8584,7 @@ function formatRememberedForegroundStatus(run) {
8543
8584
  for (const child of run.children) {
8544
8585
  const output = rememberedForegroundChildOutput(child).trim().split(/\r?\n/).find((line) => line.trim());
8545
8586
  const parts = [
8546
- `${child.index + 1}. ${child.sessionName?.trim() || child.agent} ${child.status}`,
8587
+ `${child.index + 1}. ${child.sessionName?.trim() || child.agent} ${foregroundChildStateLabel(run, child)}`,
8547
8588
  child.exitCode !== void 0 ? `exit ${child.exitCode}` : void 0,
8548
8589
  child.detachedReason ? `detached: ${child.detachedReason}` : void 0,
8549
8590
  child.acceptance ? `acceptance: ${child.acceptance.status}` : void 0,
@@ -10159,9 +10200,11 @@ function trimRememberedForegroundRuns(state) {
10159
10200
  state.foregroundRuns.delete(oldestTerminal.runId);
10160
10201
  }
10161
10202
  }
10162
- function persistRememberedForegroundRuns(state) {
10203
+ function persistRememberedForegroundRun(state, runId) {
10204
+ const run = state.foregroundRuns?.get(runId);
10205
+ if (!run) return;
10163
10206
  try {
10164
- persistForegroundRunHistory(state);
10207
+ persistForegroundRun(run);
10165
10208
  } catch (error) {
10166
10209
  console.error("Failed to persist foreground run history:", error);
10167
10210
  }
@@ -10180,6 +10223,49 @@ function foregroundChildActivityFromProgress(progress) {
10180
10223
  ...progress?.toolCount !== void 0 ? { toolCount: progress.toolCount } : {}
10181
10224
  };
10182
10225
  }
10226
+ function rememberedForegroundChild(input, result2, index, status, updatedAt) {
10227
+ const resumeContract = omitUndefinedProperties({
10228
+ modelResponseAliases: input.modelResponseAliases,
10229
+ outputSchema: input.params.outputSchema,
10230
+ agentContract: input.params.agentContract,
10231
+ acceptance: input.params.acceptance,
10232
+ output: input.effectiveOutput,
10233
+ outputMode: input.effectiveOutputMode
10234
+ });
10235
+ return {
10236
+ agent: result2.agent,
10237
+ index,
10238
+ ...result2.sessionName ? { sessionName: result2.sessionName } : {},
10239
+ ...result2.context ? { context: result2.context } : {},
10240
+ status,
10241
+ ...foregroundChildActivityFromProgress(result2.progress),
10242
+ updatedAt,
10243
+ ...result2.exitCode !== void 0 ? { exitCode: result2.exitCode } : {},
10244
+ ...result2.error ? { error: result2.error } : {},
10245
+ ...result2.finalOutput ? { finalOutput: result2.finalOutput } : {},
10246
+ ...result2.outputState ? { outputState: result2.outputState } : {},
10247
+ ...result2.outputPartial ? { outputPartial: true } : {},
10248
+ ...result2.outputMode ? { outputMode: result2.outputMode } : {},
10249
+ ...result2.savedOutputPath ? { savedOutputPath: result2.savedOutputPath } : {},
10250
+ ...result2.outputSaveError ? { outputSaveError: result2.outputSaveError } : {},
10251
+ ...result2.sessionFile ? { sessionFile: result2.sessionFile } : {},
10252
+ ...result2.model ? { model: result2.model } : {},
10253
+ ...result2.thinking ? { thinking: result2.thinking } : {},
10254
+ ...result2.artifactPaths ? { artifactPaths: result2.artifactPaths } : {},
10255
+ ...result2.transcriptPath ? { transcriptPath: result2.transcriptPath } : {},
10256
+ ...result2.transcriptError ? { transcriptError: result2.transcriptError } : {},
10257
+ ...result2.detachedReason ? { detachedReason: result2.detachedReason } : {},
10258
+ ...result2.acceptance ? { acceptance: result2.acceptance } : {},
10259
+ ...Object.keys(resumeContract).length ? { resumeContract } : {},
10260
+ ...result2.launchContractDigest ? { launchContractDigest: result2.launchContractDigest } : {},
10261
+ ...input.extensionBindings ? { extensionBindings: input.extensionBindings } : {},
10262
+ ...input.requiredExtensions?.length ? { requiredExtensions: input.requiredExtensions } : {},
10263
+ ...result2.launchResolvedExtensions ? { launchResolvedExtensions: result2.launchResolvedExtensions } : {},
10264
+ ...result2.runtimeAcknowledgedExtensions ? { runtimeAcknowledgedExtensions: result2.runtimeAcknowledgedExtensions } : {},
10265
+ ...result2.capabilityCeiling ? { capabilityCeiling: result2.capabilityCeiling } : {},
10266
+ ...result2.capabilityAudit ? { capabilityAudit: result2.capabilityAudit } : {}
10267
+ };
10268
+ }
10183
10269
  function rememberForegroundRun(state, input) {
10184
10270
  state.foregroundRuns ??= /* @__PURE__ */ new Map();
10185
10271
  const previous = state.foregroundRuns.get(input.runId);
@@ -10191,61 +10277,38 @@ function rememberForegroundRun(state, input) {
10191
10277
  ...input.sessionId ? { sessionId: input.sessionId } : {},
10192
10278
  updatedAt,
10193
10279
  children: input.results.map((result2, index) => {
10194
- const resumeContract = omitUndefinedProperties({
10195
- modelResponseAliases: input.modelResponseAliases,
10196
- outputSchema: input.params.outputSchema,
10197
- agentContract: input.params.agentContract,
10198
- acceptance: input.params.acceptance,
10199
- output: input.effectiveOutput,
10200
- outputMode: input.effectiveOutputMode
10201
- });
10202
- const child = {
10203
- agent: result2.agent,
10204
- index,
10205
- ...result2.sessionName ? { sessionName: result2.sessionName } : {},
10206
- ...result2.context ? { context: result2.context } : {},
10207
- status: resolveSubagentResultStatus(omitUndefinedProperties({
10208
- exitCode: result2.exitCode,
10209
- interrupted: result2.interrupted,
10210
- detached: result2.detached,
10211
- processSignal: result2.processSignal,
10212
- timedOut: result2.timedOut,
10213
- stopped: result2.stopped,
10214
- turnBudgetExceeded: result2.turnBudgetExceeded
10215
- })),
10216
- ...foregroundChildActivityFromProgress(result2.progress),
10217
- updatedAt,
10218
- ...result2.exitCode !== void 0 ? { exitCode: result2.exitCode } : {},
10219
- ...result2.error ? { error: result2.error } : {},
10220
- ...result2.finalOutput ? { finalOutput: result2.finalOutput } : {},
10221
- ...result2.outputState ? { outputState: result2.outputState } : {},
10222
- ...result2.outputPartial ? { outputPartial: true } : {},
10223
- ...result2.outputMode ? { outputMode: result2.outputMode } : {},
10224
- ...result2.savedOutputPath ? { savedOutputPath: result2.savedOutputPath } : {},
10225
- ...result2.outputSaveError ? { outputSaveError: result2.outputSaveError } : {},
10226
- ...result2.sessionFile ? { sessionFile: result2.sessionFile } : {},
10227
- ...result2.model ? { model: result2.model } : {},
10228
- ...result2.thinking ? { thinking: result2.thinking } : {},
10229
- ...result2.artifactPaths ? { artifactPaths: result2.artifactPaths } : {},
10230
- ...result2.transcriptPath ? { transcriptPath: result2.transcriptPath } : {},
10231
- ...result2.transcriptError ? { transcriptError: result2.transcriptError } : {},
10232
- ...result2.detachedReason ? { detachedReason: result2.detachedReason } : {},
10233
- ...result2.acceptance ? { acceptance: result2.acceptance } : {},
10234
- ...Object.keys(resumeContract).length ? { resumeContract } : {},
10235
- ...result2.launchContractDigest ? { launchContractDigest: result2.launchContractDigest } : {},
10236
- ...input.extensionBindings ? { extensionBindings: input.extensionBindings } : {},
10237
- ...input.requiredExtensions?.length ? { requiredExtensions: input.requiredExtensions } : {},
10238
- ...result2.launchResolvedExtensions ? { launchResolvedExtensions: result2.launchResolvedExtensions } : {},
10239
- ...result2.runtimeAcknowledgedExtensions ? { runtimeAcknowledgedExtensions: result2.runtimeAcknowledgedExtensions } : {},
10240
- ...result2.capabilityCeiling ? { capabilityCeiling: result2.capabilityCeiling } : {},
10241
- ...result2.capabilityAudit ? { capabilityAudit: result2.capabilityAudit } : {}
10242
- };
10280
+ const child = rememberedForegroundChild(input, result2, index, resolveSubagentResultStatus(omitUndefinedProperties({
10281
+ exitCode: result2.exitCode,
10282
+ interrupted: result2.interrupted,
10283
+ detached: result2.detached,
10284
+ processSignal: result2.processSignal,
10285
+ timedOut: result2.timedOut,
10286
+ stopped: result2.stopped,
10287
+ turnBudgetExceeded: result2.turnBudgetExceeded
10288
+ })), updatedAt);
10243
10289
  const recovered = previous?.children[index];
10244
10290
  return child.status === "detached" && recovered && recovered.status !== "detached" ? recovered : child;
10245
10291
  })
10246
10292
  });
10247
10293
  trimRememberedForegroundRuns(state);
10248
- persistRememberedForegroundRuns(state);
10294
+ persistRememberedForegroundRun(state, input.runId);
10295
+ }
10296
+ function rememberRunningForegroundRun(input) {
10297
+ const updatedAt = Date.now();
10298
+ try {
10299
+ persistForegroundRun({
10300
+ runId: input.runId,
10301
+ mode: "single",
10302
+ cwd: input.cwd,
10303
+ ...input.sessionId ? { sessionId: input.sessionId } : {},
10304
+ updatedAt,
10305
+ children: [rememberedForegroundChild(input, input.child, 0, "running", updatedAt)],
10306
+ owner: currentRecordedPid(),
10307
+ ...input.parentWorkflowRunId ? { parentWorkflowRunId: input.parentWorkflowRunId } : {}
10308
+ });
10309
+ } catch (error) {
10310
+ console.error("Failed to persist running foreground run:", error);
10311
+ }
10249
10312
  }
10250
10313
  function applyControlEventToRememberedForegroundRun(state, event) {
10251
10314
  const run = state.foregroundRuns?.get(event.runId);
@@ -10320,7 +10383,7 @@ function updateRememberedForegroundChild(state, input) {
10320
10383
  ...input.result.capabilityAudit ? { capabilityAudit: input.result.capabilityAudit } : {}
10321
10384
  });
10322
10385
  trimRememberedForegroundRuns(state);
10323
- persistRememberedForegroundRuns(state);
10386
+ persistRememberedForegroundRun(state, input.runId);
10324
10387
  const output = getSingleResultOutput(input.result).trim();
10325
10388
  const success = terminalStatus === "completed";
10326
10389
  const summary = !success && input.result.error ? `${input.result.error}${output ? `
@@ -12501,9 +12564,9 @@ function importWorkflowAwaitedChildResult(completed, options) {
12501
12564
  }
12502
12565
  };
12503
12566
  }
12504
- function stopAwaitedAsyncChildOnAbort(signal, state, runId, asyncDir, kill, reattachedFromOtherSession = false) {
12567
+ function stopAwaitedAsyncChildOnAbort(signal, state, runId, asyncDir, kill, reattached = false) {
12505
12568
  const stopOnAbort = () => {
12506
- if (!workflowStopCause(signal?.reason)) stopAsyncRun(state, runId, kill, { asyncDir, resolvedId: runId, ...reattachedFromOtherSession ? { reattachedRunId: runId } : {} });
12569
+ if (!workflowStopCause(signal?.reason)) stopAsyncRun(state, runId, kill, { asyncDir, resolvedId: runId, ...reattached ? { reattachedRunId: runId } : {} });
12507
12570
  };
12508
12571
  if (signal?.aborted) stopOnAbort();
12509
12572
  else signal?.addEventListener("abort", stopOnAbort, { once: true });
@@ -13016,7 +13079,7 @@ async function runSinglePath(data, deps) {
13016
13079
  if (requestedMachine) {
13017
13080
  try {
13018
13081
  assertRequiredChildExtensionsAdmitted([requiredExtensions], { agent: agentConfig.name, runnerType: agentConfig.runner?.type, machine: requestedMachine });
13019
- foregroundMachine = resolveHerdrMachinePlacement({ machine: requestedMachine, cwd: ctx.cwd, stepCwd: params.machineCwd }).machine;
13082
+ foregroundMachine = resolveMachinePlacement({ machine: requestedMachine, cwd: ctx.cwd, stepCwd: params.machineCwd }).machine;
13020
13083
  } catch (error) {
13021
13084
  return toExecutionErrorResult(params, error instanceof Error ? error : new Error(String(error)), data.contextPolicy.contextSummary);
13022
13085
  }
@@ -13209,6 +13272,13 @@ async function runSinglePath(data, deps) {
13209
13272
  onUpdate(update);
13210
13273
  } : void 0;
13211
13274
  const deadlineAt = data.deadlineAt ?? (data.timeoutMs !== void 0 ? Date.now() + data.timeoutMs : void 0);
13275
+ const discardRunningRecord = () => {
13276
+ try {
13277
+ discardRunningForegroundRun(runId);
13278
+ } catch (discardError) {
13279
+ console.error("Failed to discard running foreground run:", discardError);
13280
+ }
13281
+ };
13212
13282
  let r;
13213
13283
  let resolveDetachedWorkflowChild;
13214
13284
  const detachedWorkflowChild = params.workflowAwaitDetached === true ? new Promise((resolve10) => {
@@ -13216,6 +13286,27 @@ async function runSinglePath(data, deps) {
13216
13286
  }) : void 0;
13217
13287
  try {
13218
13288
  const childSessionFile = sessionFileForTask(params.agent, 0, modelOverride, modelOverrideFromParent, modelOrigin);
13289
+ rememberRunningForegroundRun({
13290
+ modelResponseAliases,
13291
+ runId,
13292
+ mode: "single",
13293
+ cwd: singleCwd,
13294
+ sessionId: data.parentSessionId,
13295
+ params,
13296
+ effectiveOutput,
13297
+ effectiveOutputMode,
13298
+ extensionBindings: params.extensionBindings,
13299
+ requiredExtensions,
13300
+ child: omitUndefinedProperties({
13301
+ agent: params.agent,
13302
+ context: shouldForkAgent(contextPolicy, params.agent) ? "fork" : "fresh",
13303
+ sessionFile: childSessionFile,
13304
+ model: modelOverride,
13305
+ thinking: resolveEffectiveThinking(modelOverride, thinkingOverrideForTask()),
13306
+ capabilityCeiling: data.capabilityCeiling
13307
+ }),
13308
+ parentWorkflowRunId: params.workflowParentRunId ?? foregroundControl?.parentWorkflowRunId
13309
+ });
13219
13310
  const launched = await runSync(ctx.cwd, agents, params.agent, task, compactOptional({
13220
13311
  machine: foregroundMachine,
13221
13312
  parentProviderRegistry: ctx.modelRegistry,
@@ -13291,7 +13382,12 @@ async function runSinglePath(data, deps) {
13291
13382
  }
13292
13383
  try {
13293
13384
  if (worktreeSetup) {
13294
- await finalizeSingleWorktreeHandoff({ worktreeSetup, artifactsDir, runId, cwd: sourceCwd, agent: params.agent, result: result2, workflowKey: params.workflowKey, lane });
13385
+ try {
13386
+ await finalizeSingleWorktreeHandoff({ worktreeSetup, artifactsDir, runId, cwd: sourceCwd, agent: params.agent, result: result2, workflowKey: params.workflowKey, lane });
13387
+ } catch (error) {
13388
+ discardRunningRecord();
13389
+ throw error;
13390
+ }
13295
13391
  }
13296
13392
  try {
13297
13393
  updateRememberedForegroundChild(deps.state, { runId, mode: "single", cwd: singleCwd, sessionId: data.parentSessionId, index: 0, result: result2, events: deps.pi.events, notify: true });
@@ -13340,6 +13436,7 @@ async function runSinglePath(data, deps) {
13340
13436
  }
13341
13437
  r = launched.detached && detachedWorkflowChild ? await detachedWorkflowChild : launched;
13342
13438
  } catch (error) {
13439
+ discardRunningRecord();
13343
13440
  await cleanupSingleWorktree();
13344
13441
  throw error;
13345
13442
  } finally {
@@ -13350,7 +13447,12 @@ async function runSinglePath(data, deps) {
13350
13447
  }
13351
13448
  let worktreeHandoff;
13352
13449
  if (worktreeSetup) {
13353
- worktreeHandoff = r.detached ? { suffix: pendingHandoff ? formatParallelHandoffReference(pendingHandoff) : "", reference: pendingHandoff } : await finalizeSingleWorktreeHandoff({ worktreeSetup, artifactsDir, runId, cwd: sourceCwd, agent: params.agent, result: r, workflowKey: params.workflowKey, lane });
13450
+ try {
13451
+ worktreeHandoff = r.detached ? { suffix: pendingHandoff ? formatParallelHandoffReference(pendingHandoff) : "", reference: pendingHandoff } : await finalizeSingleWorktreeHandoff({ worktreeSetup, artifactsDir, runId, cwd: sourceCwd, agent: params.agent, result: r, workflowKey: params.workflowKey, lane });
13452
+ } catch (error) {
13453
+ discardRunningRecord();
13454
+ throw error;
13455
+ }
13354
13456
  }
13355
13457
  if (r.progress) allProgress.push(r.progress);
13356
13458
  if (r.artifactPaths) allArtifactPaths.push(r.artifactPaths);
@@ -14029,6 +14131,14 @@ function createScheduledOwnerState(source, ownerSessionId, ctx) {
14029
14131
  workflowChildStops: /* @__PURE__ */ new Map()
14030
14132
  };
14031
14133
  }
14134
+ function savedWorkflowLaunchParams(params) {
14135
+ const { reuseFrom: _reuseFrom, scheduleOrigin: _scheduleOrigin, resumeOrigin: _resumeOrigin, ...saved } = params;
14136
+ return saved;
14137
+ }
14138
+ function workflowLaunchRecord(launch, cwd, scriptDigest) {
14139
+ if (launch.source === "structured") return { version: 1, source: "structured", scriptDigest };
14140
+ return { version: 1, source: launch.source, params: { ...launch.params, cwd }, scriptDigest };
14141
+ }
14032
14142
  function createSubagentExecutor(deps) {
14033
14143
  const executorDeps = deps;
14034
14144
  const delegatedThinkingOverrides = /* @__PURE__ */ new WeakMap();
@@ -14036,6 +14146,8 @@ function createSubagentExecutor(deps) {
14036
14146
  const delegatedExecutions = /* @__PURE__ */ new WeakSet();
14037
14147
  const publicExecutions = /* @__PURE__ */ new WeakSet();
14038
14148
  const workflowResourcePermits = /* @__PURE__ */ new WeakMap();
14149
+ const publicWorkflowLaunches = /* @__PURE__ */ new WeakMap();
14150
+ const workflowResumeLaunches = /* @__PURE__ */ new WeakMap();
14039
14151
  const workflowPermitContexts = /* @__PURE__ */ new WeakMap();
14040
14152
  const warnedArtifactPackageDirs = /* @__PURE__ */ new Set();
14041
14153
  const scheduledOwnerExecutors = /* @__PURE__ */ new Map();
@@ -14051,7 +14163,13 @@ function createSubagentExecutor(deps) {
14051
14163
  if (error) throw new Error(error);
14052
14164
  }
14053
14165
  };
14054
- const execute = async (_id, params, signal, onUpdate, ctx, preserveActiveSession = false, parentModelOverride) => {
14166
+ const pendingReuseClaimReleases = /* @__PURE__ */ new WeakMap();
14167
+ const execute = (...args) => executeRequest(...args).finally(() => {
14168
+ const releaseReuseClaim = pendingReuseClaimReleases.get(args[1]);
14169
+ pendingReuseClaimReleases.delete(args[1]);
14170
+ releaseReuseClaim?.();
14171
+ });
14172
+ const executeRequest = async (_id, params, signal, onUpdate, ctx, preserveActiveSession = false, parentModelOverride) => {
14055
14173
  const projectScopeError = projectScopeTrustError(params, ctx);
14056
14174
  if (projectScopeError) return projectScopeError;
14057
14175
  const deps2 = withSessionProjectTrust(executorDeps, ctx);
@@ -14063,6 +14181,8 @@ function createSubagentExecutor(deps) {
14063
14181
  const delegatedExecution = delegatedExecutions.has(params);
14064
14182
  const publicExecution = publicExecutions.has(params);
14065
14183
  const workflowResourcePermit = workflowResourcePermits.get(params);
14184
+ const workflowResumeLaunch = workflowResumeLaunches.get(params);
14185
+ const publicWorkflowLaunch = publicWorkflowLaunches.get(params);
14066
14186
  const workflowPermitContext = workflowPermitContexts.get(params);
14067
14187
  const delegatedWorkflowPermit = workflowPermitContext && "root" in workflowPermitContext ? workflowPermitContext.root : void 0;
14068
14188
  const workflowChildPermitLaunch = workflowPermitContext && "child" in workflowPermitContext ? workflowPermitContext.child : void 0;
@@ -14180,13 +14300,14 @@ function createSubagentExecutor(deps) {
14180
14300
  const workflowDepth = checkSubagentDepth(deps2.config.maxSubagentDepth, deps2.childRuntime).depth;
14181
14301
  const asyncWorkflow = requestParams.async !== false;
14182
14302
  const topLevelAsyncWorkflow = asyncWorkflow && workflowDepth === 0 && !inheritedNestedRoute(deps2) && !requestParams.workflowParentRunId;
14183
- const workflowRunId = asyncWorkflow ? randomUUID5() : void 0;
14303
+ const workflowRunId = asyncWorkflow ? workflowResumeLaunch?.presetRunId ?? randomUUID5() : void 0;
14184
14304
  if (requestParams.reuseFrom !== void 0 && !topLevelAsyncWorkflow) {
14185
14305
  return { content: [{ type: "text", text: "options.reuseFrom requires an async top-level workflow." }], isError: true, details: { mode: "workflow", results: [] } };
14186
14306
  }
14187
- let namedWorkflowReuseSource;
14307
+ let workflowReuseSource;
14188
14308
  try {
14189
- if (requestParams.reuseFrom !== void 0) namedWorkflowReuseSource = readNamedWorkflowReuseSource(DIRS.async, requestParams.reuseFrom, workflowScriptDigest(requestParams.workflowScript), workflowCwd);
14309
+ if (requestParams.reuseFrom !== void 0) workflowReuseSource = readNamedWorkflowReuseSource(DIRS.async, requestParams.reuseFrom, workflowScriptDigest(requestParams.workflowScript), workflowCwd, workflowResumeLaunch?.presetRunId);
14310
+ else if (workflowRunId) workflowReuseSource = findWorkflowReuseSource(DIRS.async, resolveCurrentSessionId(ctx.sessionManager), workflowScriptDigest(requestParams.workflowScript), workflowArgsDigest);
14190
14311
  } catch (error) {
14191
14312
  return { content: [{ type: "text", text: error instanceof Error ? error.message : String(error) }], isError: true, details: { mode: "workflow", results: [] } };
14192
14313
  }
@@ -14256,17 +14377,37 @@ function createSubagentExecutor(deps) {
14256
14377
  const completionOwnerId = deps2.state.completionOwnerId ?? currentCompletionOwnerId();
14257
14378
  deps2.state.completionOwnerId = completionOwnerId;
14258
14379
  const workflowScriptSourceDigest = workflowScriptDigest(requestParams.workflowScript);
14259
- const workflowReuseSource = namedWorkflowReuseSource ?? findWorkflowReuseSource(DIRS.async, currentSessionId, workflowScriptSourceDigest, workflowArgsDigest);
14260
14380
  const workflowRunEvidence = { ...workflowArgsEvidence, scriptDigest: workflowScriptSourceDigest };
14261
14381
  if (workflowReuseSource) workflowRunEvidence.reusedFrom = workflowReuseSource.runId;
14382
+ if (workflowResumeLaunch) workflowRunEvidence.resumeOrigin = workflowResumeLaunch.resumeOrigin;
14262
14383
  const workflowJournalFingerprints = /* @__PURE__ */ new Map();
14384
+ const storageFailure = (error) => {
14385
+ workflowCapacity?.rollback();
14386
+ return { content: [{ type: "text", text: `Failed to create async workflow storage: ${error instanceof Error ? error.message : String(error)}` }], isError: true, details: { mode: "workflow", results: [] } };
14387
+ };
14388
+ if (workflowReuseSource) {
14389
+ const reuseSourceDir = path19.join(DIRS.async, workflowReuseSource.runId);
14390
+ let claim;
14391
+ try {
14392
+ claim = claimWorkflowResume(reuseSourceDir, { newRunId: workflowRunId, trigger: "reuse" });
14393
+ } catch (error) {
14394
+ return storageFailure(error);
14395
+ }
14396
+ if (claim.kind !== "owner") {
14397
+ workflowCapacity?.rollback();
14398
+ return { content: [{ type: "text", text: claimedWorkflowRunRefusal(workflowReuseSource.runId, claim, requestParams.reuseFrom !== void 0) }], isError: true, details: { mode: "workflow", results: [] } };
14399
+ }
14400
+ pendingReuseClaimReleases.set(params, () => {
14401
+ if (!fs21.existsSync(statusPath)) releaseWorkflowResumeClaim(reuseSourceDir, workflowRunId);
14402
+ });
14403
+ }
14263
14404
  try {
14264
14405
  fs21.mkdirSync(asyncDir, { recursive: true });
14265
14406
  writeRunFanoutBudgetDescriptor(asyncDir, workflowFanoutBudget);
14407
+ if (topLevelAsyncWorkflow && publicWorkflowLaunch) writeWorkflowLaunchRecord(asyncDir, workflowLaunchRecord(publicWorkflowLaunch, workflowCwd, workflowScriptSourceDigest));
14266
14408
  fs21.mkdirSync(DIRS.results, { recursive: true });
14267
14409
  } catch (error) {
14268
- workflowCapacity?.rollback();
14269
- return { content: [{ type: "text", text: `Failed to create async workflow storage: ${error instanceof Error ? error.message : String(error)}` }], isError: true, details: { mode: "workflow", results: [] } };
14410
+ return storageFailure(error);
14270
14411
  }
14271
14412
  const controller = new AbortController();
14272
14413
  deps2.state.workflowControllers ??= /* @__PURE__ */ new Map();
@@ -14287,7 +14428,7 @@ function createSubagentExecutor(deps) {
14287
14428
  cwd: workflowCwd,
14288
14429
  ...workflowSessionRoot ? { sessionRoot: workflowSessionRoot } : {},
14289
14430
  ...requestParams.scheduleOrigin ? { scheduleOrigin: requestParams.scheduleOrigin } : {},
14290
- pid: process.pid,
14431
+ ...currentRecordedPid(),
14291
14432
  ...workflowCapabilityCeiling2 ? { admissionCapabilityCeiling: workflowCapabilityCeiling2 } : {},
14292
14433
  steps: [],
14293
14434
  ...workflowPreflight ? { preflight: workflowPreflight } : {},
@@ -14876,7 +15017,7 @@ Parent action: ${COMPLETION_ACTION}` : content,
14876
15017
  const priorAsyncDir = path19.join(DIRS.async, priorRunId);
14877
15018
  appendWorkflowChildJournal(asyncDir, { type: "start", key, fingerprint: journalFingerprint, runId: priorRunId });
14878
15019
  recordReusedWorkflowChild(key, priorRunId);
14879
- const stopListener = stopAwaitedAsyncChildOnAbort(workflowSignal, deps2.state, priorRunId, priorAsyncDir, deps2.kill, requestParams.reuseFrom !== void 0);
15020
+ const stopListener = stopAwaitedAsyncChildOnAbort(workflowSignal, deps2.state, priorRunId, priorAsyncDir, deps2.kill, true);
14880
15021
  const reattached = await awaitExistingAsyncRun(priorAsyncDir, priorRunId, workflowSignal).finally(stopListener.remove);
14881
15022
  const claimedPath = reattached.status === "settled" ? claimWorkflowAwaitedResult(priorAsyncDir, workflowRunId, { ...reattached.result.importedPublication, runId: priorRunId }) : void 0;
14882
15023
  if (reattached.status === "settled" && claimedPath) {
@@ -15052,7 +15193,7 @@ Parent action: ${COMPLETION_ACTION}` : content,
15052
15193
  if (promoted) status = promoted;
15053
15194
  }
15054
15195
  const errorPreview = status.error && status.error.length > 1e3 ? `${status.error.slice(0, 1e3)}\u2026 (truncated; full error: ${statusPath} (error))` : status.error;
15055
- const terminalSummary = `${status.state === "complete" ? "Workflow completed after detached child finished." : errorPreview ?? (pauseForDetached ? "Workflow paused." : "Workflow failed.")}${stopCause ? ` ${workflowRuntimeReplacedRelaunchNotice(workflowRunId)}` : ""}${workflowOutputPathMappingSummary2(partial.children)}${finalPreflightWarnings.length ? ` ${finalPreflightWarnings.join(" ")}` : ""}`;
15196
+ const terminalSummary = `${status.state === "complete" ? "Workflow completed after detached child finished." : errorPreview ?? (pauseForDetached ? "Workflow paused." : "Workflow failed.")}${stopCause ? ` ${WORKFLOW_RUNTIME_REPLACED_STOP_NOTICE}` : ""}${workflowOutputPathMappingSummary2(partial.children)}${finalPreflightWarnings.length ? ` ${finalPreflightWarnings.join(" ")}` : ""}`;
15056
15197
  const outputWarning = writeWorkflowAggregateOutput(workflowAggregateOutputPath2, terminalSummary, producedChildOutputPaths2);
15057
15198
  const resultSummary = appendWorkflowOutputWarning(terminalSummary, outputWarning);
15058
15199
  const receiptState = status.state === "complete" ? "complete" : status.state === "paused" ? "paused" : status.state === "stopped" ? "stopped" : "failed";
@@ -15115,6 +15256,7 @@ Parent action: ${COMPLETION_ACTION}` : content,
15115
15256
  let liveWorkflow = { trace: [], emits: [], console: [], ...workflowResource ? { resource: workflowResource.provenance } : {} };
15116
15257
  const childProgress = /* @__PURE__ */ new Map();
15117
15258
  const childLaunches = /* @__PURE__ */ new Map();
15259
+ const blockingWorkflowChildren = /* @__PURE__ */ new Set();
15118
15260
  let activityTimer;
15119
15261
  let lastProgressAt = 0;
15120
15262
  let workflowProgressClosed = false;
@@ -15202,6 +15344,10 @@ Parent action: ${COMPLETION_ACTION}` : content,
15202
15344
  workflowPermitContexts.set(childRequest, { child: { permit: delegatedWorkflowPermit, workflowRunId: foregroundWorkflowRunId, childKey: key } });
15203
15345
  }
15204
15346
  workflowLaunchObservers.set(childRequest, (launch) => {
15347
+ if (launch.async && launch.runId && (childRequest.workflowAwaitAsync === true || childRequest.action === "resume")) {
15348
+ (deps2.state.blockingWorkflowChildren ??= /* @__PURE__ */ new Set()).add(launch.runId);
15349
+ blockingWorkflowChildren.add(launch.runId);
15350
+ }
15205
15351
  childLaunches.set(key, { agent: launch.agent, ...launch.runId ? { runId: launch.runId } : {} });
15206
15352
  try {
15207
15353
  sendWorkflowProgress();
@@ -15323,6 +15469,7 @@ ${partial.console.map((entry) => `[${entry.level}] ${entry.text}`).join("\n")}`]
15323
15469
  }, workflowFanoutBudget));
15324
15470
  } finally {
15325
15471
  workflowProgressClosed = true;
15472
+ for (const runId2 of blockingWorkflowChildren) deps2.state.blockingWorkflowChildren?.delete(runId2);
15326
15473
  if (activityTimer) clearTimeout(activityTimer);
15327
15474
  childProgress.clear();
15328
15475
  }
@@ -15745,6 +15892,8 @@ ${item.text}` } : item)
15745
15892
  return withBudget(inspectSubagentStatus(paramsWithResolvedCwd, omitUndefinedProperties({ state: deps2.state, nested: nestedScope, sessionRoots, abandonedSlotReleaseAfterMs: resolveAbandonedSlotReleaseAfterMs(deps2.config.capacity?.abandonedSlotReleaseAfterMs) })));
15746
15893
  }
15747
15894
  if (action === "resume") {
15895
+ const workflowResumeSourceId = workflowResumeTargetId(DIRS.async, paramsWithResolvedCwd);
15896
+ if (workflowResumeSourceId) return resumeWorkflowById(_id, workflowResumeSourceId, signal, ctx);
15748
15897
  return resumeAsyncRun(omitUndefinedProperties({
15749
15898
  params: paramsWithResolvedCwd,
15750
15899
  requestCwd,
@@ -16570,6 +16719,8 @@ ${item.text}` } : item)
16570
16719
  const workflow = publicParams.workflow;
16571
16720
  const errorResult = (text) => Promise.resolve({ content: [{ type: "text", text }], isError: true, details: { mode: publicParams.action ? "management" : "workflow", results: [] } });
16572
16721
  const scriptTextHint = " A workflow string is a named workflow resource or a script file path. To run script text, write it in one ```js workflow block in the same reply and call subagent({ workflow: true }).";
16722
+ let workflowLaunch;
16723
+ const workflowResumeLaunch = workflowResumeLaunches.get(params);
16573
16724
  if (publicParams.tasks !== void 0 || publicParams.chain !== void 0) {
16574
16725
  const kind = publicParams.tasks !== void 0 ? "tasks" : "chain";
16575
16726
  const resolved = resolveStructuredWorkflowResource({ kind, steps: publicParams[kind], task: publicParams.task });
@@ -16577,10 +16728,20 @@ ${item.text}` } : item)
16577
16728
  const { tasks: _tasks, chain: _chain, task: _task, ...withoutStructuredInput } = publicParams;
16578
16729
  publicParams = { ...withoutStructuredInput, workflowScript: resolved.resource.script };
16579
16730
  workflowResourcePermits.set(publicParams, resolved.resource.permit);
16731
+ workflowLaunch = { source: "structured" };
16580
16732
  } else if (typeof workflow === "string" && !isWorkflowScriptPath(workflow)) {
16581
16733
  const resolved = resolveWorkflowResource(workflow, publicParams.args, ctx.sessionManager.getSessionId() ?? void 0);
16734
+ if (workflowResumeLaunch && !resolved.ok) {
16735
+ workflowResumeLaunch.refusal = { code: "authority", reason: `workflow resource '${workflow}' can no longer be resolved: ${resolved.error}` };
16736
+ return errorResult(workflowResumeLaunch.refusal.reason);
16737
+ }
16738
+ if (workflowResumeLaunch && resolved.ok && workflowScriptDigest(resolved.resource.script) !== workflowResumeLaunch.expectedScriptDigest) {
16739
+ workflowResumeLaunch.refusal = { code: "digest", reason: `workflow resource '${workflow}' changed since the run started` };
16740
+ return errorResult(workflowResumeLaunch.refusal.reason);
16741
+ }
16582
16742
  if (!resolved.ok) return Promise.resolve({ content: [{ type: "text", text: resolved.error + scriptTextHint }], isError: true, details: { mode: "workflow", results: [] } });
16583
16743
  const { workflow: _workflow, args: _args, ...withoutResourceInput } = publicParams;
16744
+ workflowLaunch = { source: "resource", params: savedWorkflowLaunchParams(publicParams) };
16584
16745
  publicParams = { ...withoutResourceInput, workflowScript: resolved.resource.script };
16585
16746
  workflowResourcePermits.set(publicParams, resolved.resource.permit);
16586
16747
  } else if (workflow !== void 0 || publicParams.workflowScript !== void 0) {
@@ -16595,10 +16756,56 @@ ${item.text}` } : item)
16595
16756
  }
16596
16757
  const { workflow: _workflow, ...withoutWorkflowSource } = publicParams;
16597
16758
  publicParams = { ...withoutWorkflowSource, workflowScript, args: "error" in normalizedArgs ? publicParams.args : deepFreezeWorkflowArgs(normalizedArgs.args) };
16759
+ workflowLaunch = { source: "script", params: savedWorkflowLaunchParams(publicParams) };
16598
16760
  }
16761
+ if (workflowLaunch && publicParams.action === void 0) publicWorkflowLaunches.set(publicParams, workflowLaunch);
16762
+ if (workflowResumeLaunch) workflowResumeLaunches.set(publicParams, workflowResumeLaunch);
16599
16763
  publicExecutions.add(publicParams);
16600
16764
  return executeWithSingleDispatchGuard(id, publicParams, signal, onUpdate, ctx);
16601
16765
  };
16766
+ const executeWorkflowResume = async (id, prepared, signal, ctx) => {
16767
+ const params = { ...prepared.params };
16768
+ const launch = { presetRunId: prepared.newRunId, resumeOrigin: prepared.resumeOrigin, expectedScriptDigest: prepared.expectedScriptDigest };
16769
+ workflowResumeLaunches.set(params, launch);
16770
+ let result2;
16771
+ try {
16772
+ result2 = await executePublic(id, params, signal, void 0, ctx);
16773
+ } catch (error) {
16774
+ result2 = { content: [{ type: "text", text: error instanceof Error ? error.message : String(error) }], isError: true, details: { mode: "workflow", results: [] } };
16775
+ }
16776
+ if (resumedRunStarted(prepared.sourceAsyncDir, prepared.newRunId)) return { result: result2, launched: true };
16777
+ const firstText = result2.content.find((block) => block.type === "text")?.text ?? "no result";
16778
+ const refusal = launch.refusal ? workflowResumeRefusal(launch.refusal.code, launch.refusal.reason, prepared.sourceRunId) : result2.details?.activeAsyncCapacity ? workflowResumeRefusal("capacity", `capacity refused: ${firstText}`, prepared.sourceRunId) : workflowResumeRefusal("launch-failed", `launch failed: ${firstText}`, prepared.sourceRunId);
16779
+ releaseWorkflowResumeClaim(prepared.sourceAsyncDir, prepared.newRunId);
16780
+ if (prepared.trigger === "auto") {
16781
+ try {
16782
+ recordWorkflowResumeRefusal(prepared.sourceAsyncDir, { reason: refusal.reason, byHand: refusal.byHand, newRunId: prepared.newRunId });
16783
+ } catch (error) {
16784
+ console.error(`Failed to record why workflow ${prepared.sourceRunId} was not resumed:`, error);
16785
+ }
16786
+ }
16787
+ return { result: result2, launched: false, refusal };
16788
+ };
16789
+ const resumeWorkflowById = async (id, sourceRunId, signal, ctx) => {
16790
+ const refused = (text) => ({ content: [{ type: "text", text }], isError: true, details: { mode: "management", results: [] } });
16791
+ let preparation;
16792
+ try {
16793
+ preparation = prepareWorkflowResume({ asyncDirRoot: DIRS.async, sourceRunId, trigger: "manual", now: Date.now(), currentSessionId: resolveCurrentSessionId(ctx.sessionManager) });
16794
+ } catch (error) {
16795
+ return refused(`Cannot resume workflow '${sourceRunId}': ${error instanceof Error ? error.message : String(error)}`);
16796
+ }
16797
+ if (!preparation.ok) return refused(manualWorkflowResumeRefusalText(sourceRunId, preparation));
16798
+ const outcome = await executeWorkflowResume(id, preparation.prepared, signal, ctx);
16799
+ if (!outcome.launched) return refused(manualWorkflowResumeRefusalText(sourceRunId, outcome.refusal));
16800
+ const resumedLine = `Resumed workflow '${sourceRunId}' as ${preparation.prepared.newRunId}.`;
16801
+ const textIndex = outcome.result.content.findIndex((block) => block.type === "text");
16802
+ const content = [...outcome.result.content];
16803
+ const first = content[textIndex];
16804
+ if (first?.type === "text") content[textIndex] = { ...first, text: `${resumedLine}
16805
+ ${first.text}` };
16806
+ else content.unshift({ type: "text", text: resumedLine });
16807
+ return { ...outcome.result, content };
16808
+ };
16602
16809
  const executeDelegated = async (id, params, signal, onUpdate, ctx) => {
16603
16810
  const disabledFeatureError = disabledFeatureResult(params);
16604
16811
  if (disabledFeatureError) return disabledFeatureError;
@@ -16637,7 +16844,7 @@ ${item.text}` } : item)
16637
16844
  if (!ownerId) return;
16638
16845
  for (const owner of scheduledOwnerExecutors.get(ownerId)?.values() ?? []) yield owner.state;
16639
16846
  }
16640
- return { execute: executeWithSingleDispatchGuard, executePublic, executeDelegated, executeScheduled, getCurrentSupervisorOwnerStates };
16847
+ return { execute: executeWithSingleDispatchGuard, executePublic, executeDelegated, executeScheduled, executeWorkflowResume, getCurrentSupervisorOwnerStates };
16641
16848
  }
16642
16849
  export {
16643
16850
  DEFAULT_ASYNC_TIMEOUT_MS,