pi-subagents 0.81.0 → 0.82.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 (141) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/bundle/agents.js +3 -3
  3. package/bundle/child-tool-plan.js +2 -2
  4. package/bundle/{chunk-LSRUTHT7.js → chunk-43SCHIMD.js} +1 -1
  5. package/bundle/{chunk-G5DKFLLI.js → chunk-4SDU2BZX.js} +15 -10
  6. package/bundle/{chunk-V2JWDB5U.js → chunk-52UBALJL.js} +2 -2
  7. package/bundle/{chunk-3DC5KBVP.js → chunk-5TYMSZX3.js} +1 -1
  8. package/bundle/{chunk-CEKS3TFO.js → chunk-7IVSUMQQ.js} +6 -6
  9. package/bundle/{chunk-KSWQVGDW.js → chunk-7PCKZHR5.js} +225 -18
  10. package/bundle/{chunk-563BHAZ5.js → chunk-7YMXOYEU.js} +33 -25
  11. package/bundle/{chunk-XMFLCKMQ.js → chunk-B5EKXDHE.js} +336 -130
  12. package/bundle/{chunk-ZBC44JJ3.js → chunk-CIZQXJ5Q.js} +22 -9
  13. package/bundle/{chunk-L5ZHE4L4.js → chunk-GC4DSPMH.js} +4 -4
  14. package/bundle/{chunk-ARRKBB2B.js → chunk-GJECHSAR.js} +2 -2
  15. package/bundle/{chunk-2ZSNH26H.js → chunk-M2CTFYT3.js} +7 -7
  16. package/bundle/{chunk-TUWLXTAM.js → chunk-MHZ4G23A.js} +681 -320
  17. package/bundle/{chunk-WSBNENFS.js → chunk-NGGAFDL6.js} +14 -4
  18. package/bundle/{chunk-VJHOELQP.js → chunk-NRQ75MGH.js} +160 -78
  19. package/bundle/{chunk-BJN5LUQY.js → chunk-OYF6AFDY.js} +1 -1
  20. package/bundle/{chunk-EYNJ6VL6.js → chunk-PLCCBLPY.js} +2 -2
  21. package/bundle/{chunk-74RT5YQE.js → chunk-RMQFMMAT.js} +123 -33
  22. package/bundle/{chunk-V6MR5TOQ.js → chunk-SIJ4S3EN.js} +25 -19
  23. package/bundle/{chunk-NNLASTQE.js → chunk-VH5OAWVG.js} +19 -5
  24. package/bundle/{chunk-BPS2AGBZ.js → chunk-W2SZ22EM.js} +93 -52
  25. package/bundle/{chunk-V3BIUPLU.js → chunk-WVD4UEL4.js} +256 -52
  26. package/bundle/{chunk-ZP3HODFH.js → chunk-XSWOTIA3.js} +1 -1
  27. package/bundle/{chunk-3IF2PGW7.js → chunk-YKEWIB4M.js} +1 -1
  28. package/bundle/{chunk-26C3WLYQ.js → chunk-ZLINIYTP.js} +497 -272
  29. package/bundle/{chunk-2XYWN7QJ.js → chunk-ZQGSDHL6.js} +2 -2
  30. package/bundle/control-channel.js +2 -2
  31. package/bundle/index.js +1 -1
  32. package/bundle/intercom-bridge.js +2 -2
  33. package/bundle/preflight.js +8 -8
  34. package/bundle/project-panes.js +3 -3
  35. package/docs/agents.md +31 -0
  36. package/docs/configuration.md +9 -1
  37. package/docs/tool-reference.md +3 -1
  38. package/docs/workflows.md +16 -0
  39. package/package.json +2 -2
  40. package/skills/pi-subagents/references/execution-controls.md +5 -4
  41. package/src/agents/agent-management.js +3 -3
  42. package/src/agents/agent-memory.js +3 -1
  43. package/src/agents/agents.js +6 -6
  44. package/src/agents/frontmatter.d.ts +2 -0
  45. package/src/agents/frontmatter.js +15 -1
  46. package/src/agents/skills.js +2 -1
  47. package/src/extension/config.js +3 -0
  48. package/src/extension/herdr-pi-bridge.js +17 -10
  49. package/src/extension/index.js +82 -2
  50. package/src/extension/schemas.js +3 -3
  51. package/src/intercom/native-supervisor-channel.js +20 -0
  52. package/src/missions/lifecycle.js +7 -1
  53. package/src/runs/background/active-async-capacity.d.ts +1 -0
  54. package/src/runs/background/active-async-capacity.js +9 -3
  55. package/src/runs/background/async-execution.js +20 -10
  56. package/src/runs/background/async-job-tracker.d.ts +6 -1
  57. package/src/runs/background/async-job-tracker.js +9 -4
  58. package/src/runs/background/async-status.d.ts +2 -0
  59. package/src/runs/background/async-status.js +21 -2
  60. package/src/runs/background/await-async-run.js +3 -7
  61. package/src/runs/background/boot-id.d.ts +12 -0
  62. package/src/runs/background/boot-id.js +47 -0
  63. package/src/runs/background/interrupted-elsewhere.d.ts +22 -0
  64. package/src/runs/background/interrupted-elsewhere.js +68 -0
  65. package/src/runs/background/notify.d.ts +2 -0
  66. package/src/runs/background/notify.js +13 -0
  67. package/src/runs/background/result-delivery-ownership.d.ts +6 -0
  68. package/src/runs/background/result-delivery-ownership.js +19 -1
  69. package/src/runs/background/result-watcher.d.ts +3 -1
  70. package/src/runs/background/result-watcher.js +24 -8
  71. package/src/runs/background/run-child-session.d.ts +1 -6
  72. package/src/runs/background/run-child-session.js +1 -1
  73. package/src/runs/background/run-status.js +2 -1
  74. package/src/runs/background/stale-run-reconciler.d.ts +25 -0
  75. package/src/runs/background/stale-run-reconciler.js +52 -13
  76. package/src/runs/background/subagent-runner-bootstrap.js +3 -0
  77. package/src/runs/background/subagent-runner.d.ts +4 -0
  78. package/src/runs/background/subagent-runner.js +13 -5
  79. package/src/runs/background/subagent-wait.d.ts +1 -1
  80. package/src/runs/background/subagent-wait.js +6 -1
  81. package/src/runs/background/terminal-run-index.d.ts +1 -0
  82. package/src/runs/background/terminal-run-index.js +4 -2
  83. package/src/runs/foreground/async-stop-action.js +3 -1
  84. package/src/runs/foreground/execution.js +6 -3
  85. package/src/runs/foreground/foreground-history.d.ts +16 -2
  86. package/src/runs/foreground/foreground-history.js +133 -31
  87. package/src/runs/foreground/subagent-executor.d.ts +11 -0
  88. package/src/runs/foreground/subagent-executor.js +277 -74
  89. package/src/runs/shared/child-launch.d.ts +2 -2
  90. package/src/runs/shared/child-session.d.ts +3 -2
  91. package/src/runs/shared/child-session.js +51 -8
  92. package/src/runs/shared/child-tool-plan.d.ts +7 -0
  93. package/src/runs/shared/child-tool-plan.js +21 -6
  94. package/src/runs/shared/herdr-connection.d.ts +17 -8
  95. package/src/runs/shared/herdr-connection.js +19 -7
  96. package/src/runs/shared/herdr-external-adapters.d.ts +3 -2
  97. package/src/runs/shared/herdr-external-adapters.js +1 -1
  98. package/src/runs/shared/herdr-machine.d.ts +12 -2
  99. package/src/runs/shared/herdr-machine.js +55 -9
  100. package/src/runs/shared/herdr-pane-host.d.ts +88 -0
  101. package/src/runs/shared/herdr-pane-host.js +155 -0
  102. package/src/runs/shared/herdr-placed-run.d.ts +27 -150
  103. package/src/runs/shared/herdr-placed-run.js +48 -395
  104. package/src/runs/shared/local-machine-access.d.ts +5 -0
  105. package/src/runs/shared/local-machine-access.js +28 -0
  106. package/src/runs/shared/orca-progress-tabs.d.ts +0 -1
  107. package/src/runs/shared/orca-progress-tabs.js +1 -24
  108. package/src/runs/shared/parallel-utils.d.ts +1 -1
  109. package/src/runs/shared/placed-run-owner.d.ts +49 -0
  110. package/src/runs/shared/placed-run-owner.js +93 -0
  111. package/src/runs/shared/placement-host.d.ts +99 -0
  112. package/src/runs/shared/placement-host.js +157 -0
  113. package/src/runs/shared/rex-machine.d.ts +25 -0
  114. package/src/runs/shared/rex-machine.js +83 -0
  115. package/src/runs/shared/rex-pane-host.d.ts +62 -0
  116. package/src/runs/shared/rex-pane-host.js +327 -0
  117. package/src/shared/completion-owner.d.ts +5 -0
  118. package/src/shared/completion-owner.js +5 -0
  119. package/src/shared/session-identity.d.ts +2 -0
  120. package/src/shared/session-identity.js +26 -0
  121. package/src/shared/types.d.ts +45 -6
  122. package/src/tui/fleet.d.ts +1 -0
  123. package/src/tui/fleet.js +24 -15
  124. package/src/tui/render.d.ts +6 -0
  125. package/src/tui/render.js +3 -3
  126. package/src/tui/subagent-messages.js +1 -0
  127. package/src/workflows/scripted-workflow.d.ts +1 -1
  128. package/src/workflows/workflow-auto-resume.d.ts +32 -0
  129. package/src/workflows/workflow-auto-resume.js +102 -0
  130. package/src/workflows/workflow-launch-record.d.ts +27 -0
  131. package/src/workflows/workflow-launch-record.js +48 -0
  132. package/src/workflows/workflow-resume-claim.d.ts +82 -0
  133. package/src/workflows/workflow-resume-claim.js +210 -0
  134. package/src/workflows/workflow-resume.d.ts +56 -0
  135. package/src/workflows/workflow-resume.js +106 -0
  136. package/src/workflows/workflow-reuse.d.ts +15 -9
  137. package/src/workflows/workflow-reuse.js +77 -14
  138. package/src/workflows/workflow-revival.d.ts +2 -0
  139. package/src/workflows/workflow-revival.js +2 -1
  140. package/src/workflows/workflow-stop-cause.d.ts +6 -0
  141. package/src/workflows/workflow-stop-cause.js +8 -0
@@ -3,7 +3,7 @@ import {
3
3
  projectRuntimeAcknowledgedExtensions,
4
4
  registerSubagentPromptBoundary,
5
5
  registerSubagentPromptRuntime
6
- } from "./chunk-L5ZHE4L4.js";
6
+ } from "./chunk-GC4DSPMH.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-7IVSUMQQ.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-ZLINIYTP.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-W2SZ22EM.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-7PCKZHR5.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-VH5OAWVG.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-NGGAFDL6.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-NRQ75MGH.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",
@@ -4535,25 +4596,6 @@ ${createDone}
4535
4596
  }
4536
4597
  });
4537
4598
  }
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
4599
  function scheduleCleanup(nodeExecutable, paths) {
4558
4600
  try {
4559
4601
  const watchdog = spawn2(nodeExecutable, ["-e", ORCA_CLEANUP_WATCHDOG_SCRIPT, String(CLEANUP_DELAY_MS), ...paths], {
@@ -5576,7 +5618,8 @@ ${shared.acceptancePrompt}` : shared.systemPrompt,
5576
5618
  };
5577
5619
  return result2;
5578
5620
  }
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);
5621
+ const mutationCwd = isRexLocalMachine(options.machine) ? options.machine.cwd : options.cwd ?? runtimeCwd;
5622
+ 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
5623
  let structuredOutputToolInvoked = false;
5581
5624
  let structuredOutputMessageStartIndex;
5582
5625
  let toolAvailabilityError;
@@ -6293,7 +6336,7 @@ ${shared.acceptancePrompt}` : shared.systemPrompt,
6293
6336
  const toolDiagnosticError = diagnostic ? formatChildToolDiagnostic(diagnostic, { host: "parent" }) : void 0;
6294
6337
  toolAvailabilityError = toolDiagnosticError;
6295
6338
  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 } : {} };
6339
+ 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
6340
  let closeError = result2.error ?? toolDiagnosticError ?? assistantError;
6298
6341
  const promptErrorMessage = promptError === void 0 ? void 0 : promptError instanceof Error ? promptError.message : String(promptError);
6299
6342
  if (promptError !== void 0) childPromptFailed = true;
@@ -6500,7 +6543,7 @@ ${formatInheritedProviderDiagnostic({ agent: agent.name, model: launch.session.m
6500
6543
  durationMs: progress.durationMs
6501
6544
  };
6502
6545
  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);
6546
+ 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
6547
  const acceptanceOutput = getFinalOutput(result2.messages ?? []);
6505
6548
  const structuredText = result2.structuredOutput === void 0 ? void 0 : JSON.stringify(result2.structuredOutput, null, 2);
6506
6549
  let fullOutput = stripAcceptanceReport(acceptanceOutput);
@@ -8350,10 +8393,7 @@ function errorMessage2(error) {
8350
8393
  function runnerExitedWithoutResult(asyncDir, runId, resultPath) {
8351
8394
  const status = readStatus(asyncDir);
8352
8395
  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;
8396
+ if (checkRecordedPidLiveness({ pid: status.pid, pidNamespaceScope: status.pidNamespaceScope, bootId: status.bootId }) !== "dead") return false;
8357
8397
  return !fs17.existsSync(resultPath) && !(status.sessionId && resultPayloadPathForSessionRun(asyncDir, status.sessionId, runId));
8358
8398
  }
8359
8399
  async function awaitExistingAsyncRun(asyncDir, runId, signal) {
@@ -8543,7 +8583,7 @@ function formatRememberedForegroundStatus(run) {
8543
8583
  for (const child of run.children) {
8544
8584
  const output = rememberedForegroundChildOutput(child).trim().split(/\r?\n/).find((line) => line.trim());
8545
8585
  const parts = [
8546
- `${child.index + 1}. ${child.sessionName?.trim() || child.agent} ${child.status}`,
8586
+ `${child.index + 1}. ${child.sessionName?.trim() || child.agent} ${foregroundChildStateLabel(run, child)}`,
8547
8587
  child.exitCode !== void 0 ? `exit ${child.exitCode}` : void 0,
8548
8588
  child.detachedReason ? `detached: ${child.detachedReason}` : void 0,
8549
8589
  child.acceptance ? `acceptance: ${child.acceptance.status}` : void 0,
@@ -10159,9 +10199,11 @@ function trimRememberedForegroundRuns(state) {
10159
10199
  state.foregroundRuns.delete(oldestTerminal.runId);
10160
10200
  }
10161
10201
  }
10162
- function persistRememberedForegroundRuns(state) {
10202
+ function persistRememberedForegroundRun(state, runId) {
10203
+ const run = state.foregroundRuns?.get(runId);
10204
+ if (!run) return;
10163
10205
  try {
10164
- persistForegroundRunHistory(state);
10206
+ persistForegroundRun(run);
10165
10207
  } catch (error) {
10166
10208
  console.error("Failed to persist foreground run history:", error);
10167
10209
  }
@@ -10180,6 +10222,49 @@ function foregroundChildActivityFromProgress(progress) {
10180
10222
  ...progress?.toolCount !== void 0 ? { toolCount: progress.toolCount } : {}
10181
10223
  };
10182
10224
  }
10225
+ function rememberedForegroundChild(input, result2, index, status, updatedAt) {
10226
+ const resumeContract = omitUndefinedProperties({
10227
+ modelResponseAliases: input.modelResponseAliases,
10228
+ outputSchema: input.params.outputSchema,
10229
+ agentContract: input.params.agentContract,
10230
+ acceptance: input.params.acceptance,
10231
+ output: input.effectiveOutput,
10232
+ outputMode: input.effectiveOutputMode
10233
+ });
10234
+ return {
10235
+ agent: result2.agent,
10236
+ index,
10237
+ ...result2.sessionName ? { sessionName: result2.sessionName } : {},
10238
+ ...result2.context ? { context: result2.context } : {},
10239
+ status,
10240
+ ...foregroundChildActivityFromProgress(result2.progress),
10241
+ updatedAt,
10242
+ ...result2.exitCode !== void 0 ? { exitCode: result2.exitCode } : {},
10243
+ ...result2.error ? { error: result2.error } : {},
10244
+ ...result2.finalOutput ? { finalOutput: result2.finalOutput } : {},
10245
+ ...result2.outputState ? { outputState: result2.outputState } : {},
10246
+ ...result2.outputPartial ? { outputPartial: true } : {},
10247
+ ...result2.outputMode ? { outputMode: result2.outputMode } : {},
10248
+ ...result2.savedOutputPath ? { savedOutputPath: result2.savedOutputPath } : {},
10249
+ ...result2.outputSaveError ? { outputSaveError: result2.outputSaveError } : {},
10250
+ ...result2.sessionFile ? { sessionFile: result2.sessionFile } : {},
10251
+ ...result2.model ? { model: result2.model } : {},
10252
+ ...result2.thinking ? { thinking: result2.thinking } : {},
10253
+ ...result2.artifactPaths ? { artifactPaths: result2.artifactPaths } : {},
10254
+ ...result2.transcriptPath ? { transcriptPath: result2.transcriptPath } : {},
10255
+ ...result2.transcriptError ? { transcriptError: result2.transcriptError } : {},
10256
+ ...result2.detachedReason ? { detachedReason: result2.detachedReason } : {},
10257
+ ...result2.acceptance ? { acceptance: result2.acceptance } : {},
10258
+ ...Object.keys(resumeContract).length ? { resumeContract } : {},
10259
+ ...result2.launchContractDigest ? { launchContractDigest: result2.launchContractDigest } : {},
10260
+ ...input.extensionBindings ? { extensionBindings: input.extensionBindings } : {},
10261
+ ...input.requiredExtensions?.length ? { requiredExtensions: input.requiredExtensions } : {},
10262
+ ...result2.launchResolvedExtensions ? { launchResolvedExtensions: result2.launchResolvedExtensions } : {},
10263
+ ...result2.runtimeAcknowledgedExtensions ? { runtimeAcknowledgedExtensions: result2.runtimeAcknowledgedExtensions } : {},
10264
+ ...result2.capabilityCeiling ? { capabilityCeiling: result2.capabilityCeiling } : {},
10265
+ ...result2.capabilityAudit ? { capabilityAudit: result2.capabilityAudit } : {}
10266
+ };
10267
+ }
10183
10268
  function rememberForegroundRun(state, input) {
10184
10269
  state.foregroundRuns ??= /* @__PURE__ */ new Map();
10185
10270
  const previous = state.foregroundRuns.get(input.runId);
@@ -10191,61 +10276,38 @@ function rememberForegroundRun(state, input) {
10191
10276
  ...input.sessionId ? { sessionId: input.sessionId } : {},
10192
10277
  updatedAt,
10193
10278
  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
- };
10279
+ const child = rememberedForegroundChild(input, result2, index, resolveSubagentResultStatus(omitUndefinedProperties({
10280
+ exitCode: result2.exitCode,
10281
+ interrupted: result2.interrupted,
10282
+ detached: result2.detached,
10283
+ processSignal: result2.processSignal,
10284
+ timedOut: result2.timedOut,
10285
+ stopped: result2.stopped,
10286
+ turnBudgetExceeded: result2.turnBudgetExceeded
10287
+ })), updatedAt);
10243
10288
  const recovered = previous?.children[index];
10244
10289
  return child.status === "detached" && recovered && recovered.status !== "detached" ? recovered : child;
10245
10290
  })
10246
10291
  });
10247
10292
  trimRememberedForegroundRuns(state);
10248
- persistRememberedForegroundRuns(state);
10293
+ persistRememberedForegroundRun(state, input.runId);
10294
+ }
10295
+ function rememberRunningForegroundRun(input) {
10296
+ const updatedAt = Date.now();
10297
+ try {
10298
+ persistForegroundRun({
10299
+ runId: input.runId,
10300
+ mode: "single",
10301
+ cwd: input.cwd,
10302
+ ...input.sessionId ? { sessionId: input.sessionId } : {},
10303
+ updatedAt,
10304
+ children: [rememberedForegroundChild(input, input.child, 0, "running", updatedAt)],
10305
+ owner: currentRecordedPid(),
10306
+ ...input.parentWorkflowRunId ? { parentWorkflowRunId: input.parentWorkflowRunId } : {}
10307
+ });
10308
+ } catch (error) {
10309
+ console.error("Failed to persist running foreground run:", error);
10310
+ }
10249
10311
  }
10250
10312
  function applyControlEventToRememberedForegroundRun(state, event) {
10251
10313
  const run = state.foregroundRuns?.get(event.runId);
@@ -10320,7 +10382,7 @@ function updateRememberedForegroundChild(state, input) {
10320
10382
  ...input.result.capabilityAudit ? { capabilityAudit: input.result.capabilityAudit } : {}
10321
10383
  });
10322
10384
  trimRememberedForegroundRuns(state);
10323
- persistRememberedForegroundRuns(state);
10385
+ persistRememberedForegroundRun(state, input.runId);
10324
10386
  const output = getSingleResultOutput(input.result).trim();
10325
10387
  const success = terminalStatus === "completed";
10326
10388
  const summary = !success && input.result.error ? `${input.result.error}${output ? `
@@ -12501,9 +12563,9 @@ function importWorkflowAwaitedChildResult(completed, options) {
12501
12563
  }
12502
12564
  };
12503
12565
  }
12504
- function stopAwaitedAsyncChildOnAbort(signal, state, runId, asyncDir, kill, reattachedFromOtherSession = false) {
12566
+ function stopAwaitedAsyncChildOnAbort(signal, state, runId, asyncDir, kill, reattached = false) {
12505
12567
  const stopOnAbort = () => {
12506
- if (!workflowStopCause(signal?.reason)) stopAsyncRun(state, runId, kill, { asyncDir, resolvedId: runId, ...reattachedFromOtherSession ? { reattachedRunId: runId } : {} });
12568
+ if (!workflowStopCause(signal?.reason)) stopAsyncRun(state, runId, kill, { asyncDir, resolvedId: runId, ...reattached ? { reattachedRunId: runId } : {} });
12507
12569
  };
12508
12570
  if (signal?.aborted) stopOnAbort();
12509
12571
  else signal?.addEventListener("abort", stopOnAbort, { once: true });
@@ -13016,7 +13078,7 @@ async function runSinglePath(data, deps) {
13016
13078
  if (requestedMachine) {
13017
13079
  try {
13018
13080
  assertRequiredChildExtensionsAdmitted([requiredExtensions], { agent: agentConfig.name, runnerType: agentConfig.runner?.type, machine: requestedMachine });
13019
- foregroundMachine = resolveHerdrMachinePlacement({ machine: requestedMachine, cwd: ctx.cwd, stepCwd: params.machineCwd }).machine;
13081
+ foregroundMachine = resolveMachinePlacement({ machine: requestedMachine, cwd: ctx.cwd, stepCwd: params.machineCwd }).machine;
13020
13082
  } catch (error) {
13021
13083
  return toExecutionErrorResult(params, error instanceof Error ? error : new Error(String(error)), data.contextPolicy.contextSummary);
13022
13084
  }
@@ -13209,6 +13271,13 @@ async function runSinglePath(data, deps) {
13209
13271
  onUpdate(update);
13210
13272
  } : void 0;
13211
13273
  const deadlineAt = data.deadlineAt ?? (data.timeoutMs !== void 0 ? Date.now() + data.timeoutMs : void 0);
13274
+ const discardRunningRecord = () => {
13275
+ try {
13276
+ discardRunningForegroundRun(runId);
13277
+ } catch (discardError) {
13278
+ console.error("Failed to discard running foreground run:", discardError);
13279
+ }
13280
+ };
13212
13281
  let r;
13213
13282
  let resolveDetachedWorkflowChild;
13214
13283
  const detachedWorkflowChild = params.workflowAwaitDetached === true ? new Promise((resolve10) => {
@@ -13216,6 +13285,27 @@ async function runSinglePath(data, deps) {
13216
13285
  }) : void 0;
13217
13286
  try {
13218
13287
  const childSessionFile = sessionFileForTask(params.agent, 0, modelOverride, modelOverrideFromParent, modelOrigin);
13288
+ rememberRunningForegroundRun({
13289
+ modelResponseAliases,
13290
+ runId,
13291
+ mode: "single",
13292
+ cwd: singleCwd,
13293
+ sessionId: data.parentSessionId,
13294
+ params,
13295
+ effectiveOutput,
13296
+ effectiveOutputMode,
13297
+ extensionBindings: params.extensionBindings,
13298
+ requiredExtensions,
13299
+ child: omitUndefinedProperties({
13300
+ agent: params.agent,
13301
+ context: shouldForkAgent(contextPolicy, params.agent) ? "fork" : "fresh",
13302
+ sessionFile: childSessionFile,
13303
+ model: modelOverride,
13304
+ thinking: resolveEffectiveThinking(modelOverride, thinkingOverrideForTask()),
13305
+ capabilityCeiling: data.capabilityCeiling
13306
+ }),
13307
+ parentWorkflowRunId: params.workflowParentRunId ?? foregroundControl?.parentWorkflowRunId
13308
+ });
13219
13309
  const launched = await runSync(ctx.cwd, agents, params.agent, task, compactOptional({
13220
13310
  machine: foregroundMachine,
13221
13311
  parentProviderRegistry: ctx.modelRegistry,
@@ -13291,7 +13381,12 @@ async function runSinglePath(data, deps) {
13291
13381
  }
13292
13382
  try {
13293
13383
  if (worktreeSetup) {
13294
- await finalizeSingleWorktreeHandoff({ worktreeSetup, artifactsDir, runId, cwd: sourceCwd, agent: params.agent, result: result2, workflowKey: params.workflowKey, lane });
13384
+ try {
13385
+ await finalizeSingleWorktreeHandoff({ worktreeSetup, artifactsDir, runId, cwd: sourceCwd, agent: params.agent, result: result2, workflowKey: params.workflowKey, lane });
13386
+ } catch (error) {
13387
+ discardRunningRecord();
13388
+ throw error;
13389
+ }
13295
13390
  }
13296
13391
  try {
13297
13392
  updateRememberedForegroundChild(deps.state, { runId, mode: "single", cwd: singleCwd, sessionId: data.parentSessionId, index: 0, result: result2, events: deps.pi.events, notify: true });
@@ -13340,6 +13435,7 @@ async function runSinglePath(data, deps) {
13340
13435
  }
13341
13436
  r = launched.detached && detachedWorkflowChild ? await detachedWorkflowChild : launched;
13342
13437
  } catch (error) {
13438
+ discardRunningRecord();
13343
13439
  await cleanupSingleWorktree();
13344
13440
  throw error;
13345
13441
  } finally {
@@ -13350,7 +13446,12 @@ async function runSinglePath(data, deps) {
13350
13446
  }
13351
13447
  let worktreeHandoff;
13352
13448
  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 });
13449
+ try {
13450
+ 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 });
13451
+ } catch (error) {
13452
+ discardRunningRecord();
13453
+ throw error;
13454
+ }
13354
13455
  }
13355
13456
  if (r.progress) allProgress.push(r.progress);
13356
13457
  if (r.artifactPaths) allArtifactPaths.push(r.artifactPaths);
@@ -14029,6 +14130,14 @@ function createScheduledOwnerState(source, ownerSessionId, ctx) {
14029
14130
  workflowChildStops: /* @__PURE__ */ new Map()
14030
14131
  };
14031
14132
  }
14133
+ function savedWorkflowLaunchParams(params) {
14134
+ const { reuseFrom: _reuseFrom, scheduleOrigin: _scheduleOrigin, resumeOrigin: _resumeOrigin, ...saved } = params;
14135
+ return saved;
14136
+ }
14137
+ function workflowLaunchRecord(launch, cwd, scriptDigest) {
14138
+ if (launch.source === "structured") return { version: 1, source: "structured", scriptDigest };
14139
+ return { version: 1, source: launch.source, params: { ...launch.params, cwd }, scriptDigest };
14140
+ }
14032
14141
  function createSubagentExecutor(deps) {
14033
14142
  const executorDeps = deps;
14034
14143
  const delegatedThinkingOverrides = /* @__PURE__ */ new WeakMap();
@@ -14036,6 +14145,8 @@ function createSubagentExecutor(deps) {
14036
14145
  const delegatedExecutions = /* @__PURE__ */ new WeakSet();
14037
14146
  const publicExecutions = /* @__PURE__ */ new WeakSet();
14038
14147
  const workflowResourcePermits = /* @__PURE__ */ new WeakMap();
14148
+ const publicWorkflowLaunches = /* @__PURE__ */ new WeakMap();
14149
+ const workflowResumeLaunches = /* @__PURE__ */ new WeakMap();
14039
14150
  const workflowPermitContexts = /* @__PURE__ */ new WeakMap();
14040
14151
  const warnedArtifactPackageDirs = /* @__PURE__ */ new Set();
14041
14152
  const scheduledOwnerExecutors = /* @__PURE__ */ new Map();
@@ -14051,7 +14162,13 @@ function createSubagentExecutor(deps) {
14051
14162
  if (error) throw new Error(error);
14052
14163
  }
14053
14164
  };
14054
- const execute = async (_id, params, signal, onUpdate, ctx, preserveActiveSession = false, parentModelOverride) => {
14165
+ const pendingReuseClaimReleases = /* @__PURE__ */ new WeakMap();
14166
+ const execute = (...args) => executeRequest(...args).finally(() => {
14167
+ const releaseReuseClaim = pendingReuseClaimReleases.get(args[1]);
14168
+ pendingReuseClaimReleases.delete(args[1]);
14169
+ releaseReuseClaim?.();
14170
+ });
14171
+ const executeRequest = async (_id, params, signal, onUpdate, ctx, preserveActiveSession = false, parentModelOverride) => {
14055
14172
  const projectScopeError = projectScopeTrustError(params, ctx);
14056
14173
  if (projectScopeError) return projectScopeError;
14057
14174
  const deps2 = withSessionProjectTrust(executorDeps, ctx);
@@ -14063,6 +14180,8 @@ function createSubagentExecutor(deps) {
14063
14180
  const delegatedExecution = delegatedExecutions.has(params);
14064
14181
  const publicExecution = publicExecutions.has(params);
14065
14182
  const workflowResourcePermit = workflowResourcePermits.get(params);
14183
+ const workflowResumeLaunch = workflowResumeLaunches.get(params);
14184
+ const publicWorkflowLaunch = publicWorkflowLaunches.get(params);
14066
14185
  const workflowPermitContext = workflowPermitContexts.get(params);
14067
14186
  const delegatedWorkflowPermit = workflowPermitContext && "root" in workflowPermitContext ? workflowPermitContext.root : void 0;
14068
14187
  const workflowChildPermitLaunch = workflowPermitContext && "child" in workflowPermitContext ? workflowPermitContext.child : void 0;
@@ -14180,13 +14299,14 @@ function createSubagentExecutor(deps) {
14180
14299
  const workflowDepth = checkSubagentDepth(deps2.config.maxSubagentDepth, deps2.childRuntime).depth;
14181
14300
  const asyncWorkflow = requestParams.async !== false;
14182
14301
  const topLevelAsyncWorkflow = asyncWorkflow && workflowDepth === 0 && !inheritedNestedRoute(deps2) && !requestParams.workflowParentRunId;
14183
- const workflowRunId = asyncWorkflow ? randomUUID5() : void 0;
14302
+ const workflowRunId = asyncWorkflow ? workflowResumeLaunch?.presetRunId ?? randomUUID5() : void 0;
14184
14303
  if (requestParams.reuseFrom !== void 0 && !topLevelAsyncWorkflow) {
14185
14304
  return { content: [{ type: "text", text: "options.reuseFrom requires an async top-level workflow." }], isError: true, details: { mode: "workflow", results: [] } };
14186
14305
  }
14187
- let namedWorkflowReuseSource;
14306
+ let workflowReuseSource;
14188
14307
  try {
14189
- if (requestParams.reuseFrom !== void 0) namedWorkflowReuseSource = readNamedWorkflowReuseSource(DIRS.async, requestParams.reuseFrom, workflowScriptDigest(requestParams.workflowScript), workflowCwd);
14308
+ if (requestParams.reuseFrom !== void 0) workflowReuseSource = readNamedWorkflowReuseSource(DIRS.async, requestParams.reuseFrom, workflowScriptDigest(requestParams.workflowScript), workflowCwd, workflowResumeLaunch?.presetRunId);
14309
+ else if (workflowRunId) workflowReuseSource = findWorkflowReuseSource(DIRS.async, resolveCurrentSessionId(ctx.sessionManager), workflowScriptDigest(requestParams.workflowScript), workflowArgsDigest);
14190
14310
  } catch (error) {
14191
14311
  return { content: [{ type: "text", text: error instanceof Error ? error.message : String(error) }], isError: true, details: { mode: "workflow", results: [] } };
14192
14312
  }
@@ -14256,17 +14376,37 @@ function createSubagentExecutor(deps) {
14256
14376
  const completionOwnerId = deps2.state.completionOwnerId ?? currentCompletionOwnerId();
14257
14377
  deps2.state.completionOwnerId = completionOwnerId;
14258
14378
  const workflowScriptSourceDigest = workflowScriptDigest(requestParams.workflowScript);
14259
- const workflowReuseSource = namedWorkflowReuseSource ?? findWorkflowReuseSource(DIRS.async, currentSessionId, workflowScriptSourceDigest, workflowArgsDigest);
14260
14379
  const workflowRunEvidence = { ...workflowArgsEvidence, scriptDigest: workflowScriptSourceDigest };
14261
14380
  if (workflowReuseSource) workflowRunEvidence.reusedFrom = workflowReuseSource.runId;
14381
+ if (workflowResumeLaunch) workflowRunEvidence.resumeOrigin = workflowResumeLaunch.resumeOrigin;
14262
14382
  const workflowJournalFingerprints = /* @__PURE__ */ new Map();
14383
+ const storageFailure = (error) => {
14384
+ workflowCapacity?.rollback();
14385
+ return { content: [{ type: "text", text: `Failed to create async workflow storage: ${error instanceof Error ? error.message : String(error)}` }], isError: true, details: { mode: "workflow", results: [] } };
14386
+ };
14387
+ if (workflowReuseSource) {
14388
+ const reuseSourceDir = path19.join(DIRS.async, workflowReuseSource.runId);
14389
+ let claim;
14390
+ try {
14391
+ claim = claimWorkflowResume(reuseSourceDir, { newRunId: workflowRunId, trigger: "reuse" });
14392
+ } catch (error) {
14393
+ return storageFailure(error);
14394
+ }
14395
+ if (claim.kind !== "owner") {
14396
+ workflowCapacity?.rollback();
14397
+ return { content: [{ type: "text", text: claimedWorkflowRunRefusal(workflowReuseSource.runId, claim, requestParams.reuseFrom !== void 0) }], isError: true, details: { mode: "workflow", results: [] } };
14398
+ }
14399
+ pendingReuseClaimReleases.set(params, () => {
14400
+ if (!fs21.existsSync(statusPath)) releaseWorkflowResumeClaim(reuseSourceDir, workflowRunId);
14401
+ });
14402
+ }
14263
14403
  try {
14264
14404
  fs21.mkdirSync(asyncDir, { recursive: true });
14265
14405
  writeRunFanoutBudgetDescriptor(asyncDir, workflowFanoutBudget);
14406
+ if (topLevelAsyncWorkflow && publicWorkflowLaunch) writeWorkflowLaunchRecord(asyncDir, workflowLaunchRecord(publicWorkflowLaunch, workflowCwd, workflowScriptSourceDigest));
14266
14407
  fs21.mkdirSync(DIRS.results, { recursive: true });
14267
14408
  } 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: [] } };
14409
+ return storageFailure(error);
14270
14410
  }
14271
14411
  const controller = new AbortController();
14272
14412
  deps2.state.workflowControllers ??= /* @__PURE__ */ new Map();
@@ -14287,7 +14427,7 @@ function createSubagentExecutor(deps) {
14287
14427
  cwd: workflowCwd,
14288
14428
  ...workflowSessionRoot ? { sessionRoot: workflowSessionRoot } : {},
14289
14429
  ...requestParams.scheduleOrigin ? { scheduleOrigin: requestParams.scheduleOrigin } : {},
14290
- pid: process.pid,
14430
+ ...currentRecordedPid(),
14291
14431
  ...workflowCapabilityCeiling2 ? { admissionCapabilityCeiling: workflowCapabilityCeiling2 } : {},
14292
14432
  steps: [],
14293
14433
  ...workflowPreflight ? { preflight: workflowPreflight } : {},
@@ -14876,7 +15016,7 @@ Parent action: ${COMPLETION_ACTION}` : content,
14876
15016
  const priorAsyncDir = path19.join(DIRS.async, priorRunId);
14877
15017
  appendWorkflowChildJournal(asyncDir, { type: "start", key, fingerprint: journalFingerprint, runId: priorRunId });
14878
15018
  recordReusedWorkflowChild(key, priorRunId);
14879
- const stopListener = stopAwaitedAsyncChildOnAbort(workflowSignal, deps2.state, priorRunId, priorAsyncDir, deps2.kill, requestParams.reuseFrom !== void 0);
15019
+ const stopListener = stopAwaitedAsyncChildOnAbort(workflowSignal, deps2.state, priorRunId, priorAsyncDir, deps2.kill, true);
14880
15020
  const reattached = await awaitExistingAsyncRun(priorAsyncDir, priorRunId, workflowSignal).finally(stopListener.remove);
14881
15021
  const claimedPath = reattached.status === "settled" ? claimWorkflowAwaitedResult(priorAsyncDir, workflowRunId, { ...reattached.result.importedPublication, runId: priorRunId }) : void 0;
14882
15022
  if (reattached.status === "settled" && claimedPath) {
@@ -15052,7 +15192,7 @@ Parent action: ${COMPLETION_ACTION}` : content,
15052
15192
  if (promoted) status = promoted;
15053
15193
  }
15054
15194
  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(" ")}` : ""}`;
15195
+ 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
15196
  const outputWarning = writeWorkflowAggregateOutput(workflowAggregateOutputPath2, terminalSummary, producedChildOutputPaths2);
15057
15197
  const resultSummary = appendWorkflowOutputWarning(terminalSummary, outputWarning);
15058
15198
  const receiptState = status.state === "complete" ? "complete" : status.state === "paused" ? "paused" : status.state === "stopped" ? "stopped" : "failed";
@@ -15115,6 +15255,7 @@ Parent action: ${COMPLETION_ACTION}` : content,
15115
15255
  let liveWorkflow = { trace: [], emits: [], console: [], ...workflowResource ? { resource: workflowResource.provenance } : {} };
15116
15256
  const childProgress = /* @__PURE__ */ new Map();
15117
15257
  const childLaunches = /* @__PURE__ */ new Map();
15258
+ const blockingWorkflowChildren = /* @__PURE__ */ new Set();
15118
15259
  let activityTimer;
15119
15260
  let lastProgressAt = 0;
15120
15261
  let workflowProgressClosed = false;
@@ -15202,6 +15343,10 @@ Parent action: ${COMPLETION_ACTION}` : content,
15202
15343
  workflowPermitContexts.set(childRequest, { child: { permit: delegatedWorkflowPermit, workflowRunId: foregroundWorkflowRunId, childKey: key } });
15203
15344
  }
15204
15345
  workflowLaunchObservers.set(childRequest, (launch) => {
15346
+ if (launch.async && launch.runId && (childRequest.workflowAwaitAsync === true || childRequest.action === "resume")) {
15347
+ (deps2.state.blockingWorkflowChildren ??= /* @__PURE__ */ new Set()).add(launch.runId);
15348
+ blockingWorkflowChildren.add(launch.runId);
15349
+ }
15205
15350
  childLaunches.set(key, { agent: launch.agent, ...launch.runId ? { runId: launch.runId } : {} });
15206
15351
  try {
15207
15352
  sendWorkflowProgress();
@@ -15323,6 +15468,7 @@ ${partial.console.map((entry) => `[${entry.level}] ${entry.text}`).join("\n")}`]
15323
15468
  }, workflowFanoutBudget));
15324
15469
  } finally {
15325
15470
  workflowProgressClosed = true;
15471
+ for (const runId2 of blockingWorkflowChildren) deps2.state.blockingWorkflowChildren?.delete(runId2);
15326
15472
  if (activityTimer) clearTimeout(activityTimer);
15327
15473
  childProgress.clear();
15328
15474
  }
@@ -15745,6 +15891,8 @@ ${item.text}` } : item)
15745
15891
  return withBudget(inspectSubagentStatus(paramsWithResolvedCwd, omitUndefinedProperties({ state: deps2.state, nested: nestedScope, sessionRoots, abandonedSlotReleaseAfterMs: resolveAbandonedSlotReleaseAfterMs(deps2.config.capacity?.abandonedSlotReleaseAfterMs) })));
15746
15892
  }
15747
15893
  if (action === "resume") {
15894
+ const workflowResumeSourceId = workflowResumeTargetId(DIRS.async, paramsWithResolvedCwd);
15895
+ if (workflowResumeSourceId) return resumeWorkflowById(_id, workflowResumeSourceId, signal, ctx);
15748
15896
  return resumeAsyncRun(omitUndefinedProperties({
15749
15897
  params: paramsWithResolvedCwd,
15750
15898
  requestCwd,
@@ -16570,6 +16718,8 @@ ${item.text}` } : item)
16570
16718
  const workflow = publicParams.workflow;
16571
16719
  const errorResult = (text) => Promise.resolve({ content: [{ type: "text", text }], isError: true, details: { mode: publicParams.action ? "management" : "workflow", results: [] } });
16572
16720
  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 }).";
16721
+ let workflowLaunch;
16722
+ const workflowResumeLaunch = workflowResumeLaunches.get(params);
16573
16723
  if (publicParams.tasks !== void 0 || publicParams.chain !== void 0) {
16574
16724
  const kind = publicParams.tasks !== void 0 ? "tasks" : "chain";
16575
16725
  const resolved = resolveStructuredWorkflowResource({ kind, steps: publicParams[kind], task: publicParams.task });
@@ -16577,10 +16727,20 @@ ${item.text}` } : item)
16577
16727
  const { tasks: _tasks, chain: _chain, task: _task, ...withoutStructuredInput } = publicParams;
16578
16728
  publicParams = { ...withoutStructuredInput, workflowScript: resolved.resource.script };
16579
16729
  workflowResourcePermits.set(publicParams, resolved.resource.permit);
16730
+ workflowLaunch = { source: "structured" };
16580
16731
  } else if (typeof workflow === "string" && !isWorkflowScriptPath(workflow)) {
16581
16732
  const resolved = resolveWorkflowResource(workflow, publicParams.args, ctx.sessionManager.getSessionId() ?? void 0);
16733
+ if (workflowResumeLaunch && !resolved.ok) {
16734
+ workflowResumeLaunch.refusal = { code: "authority", reason: `workflow resource '${workflow}' can no longer be resolved: ${resolved.error}` };
16735
+ return errorResult(workflowResumeLaunch.refusal.reason);
16736
+ }
16737
+ if (workflowResumeLaunch && resolved.ok && workflowScriptDigest(resolved.resource.script) !== workflowResumeLaunch.expectedScriptDigest) {
16738
+ workflowResumeLaunch.refusal = { code: "digest", reason: `workflow resource '${workflow}' changed since the run started` };
16739
+ return errorResult(workflowResumeLaunch.refusal.reason);
16740
+ }
16582
16741
  if (!resolved.ok) return Promise.resolve({ content: [{ type: "text", text: resolved.error + scriptTextHint }], isError: true, details: { mode: "workflow", results: [] } });
16583
16742
  const { workflow: _workflow, args: _args, ...withoutResourceInput } = publicParams;
16743
+ workflowLaunch = { source: "resource", params: savedWorkflowLaunchParams(publicParams) };
16584
16744
  publicParams = { ...withoutResourceInput, workflowScript: resolved.resource.script };
16585
16745
  workflowResourcePermits.set(publicParams, resolved.resource.permit);
16586
16746
  } else if (workflow !== void 0 || publicParams.workflowScript !== void 0) {
@@ -16595,10 +16755,56 @@ ${item.text}` } : item)
16595
16755
  }
16596
16756
  const { workflow: _workflow, ...withoutWorkflowSource } = publicParams;
16597
16757
  publicParams = { ...withoutWorkflowSource, workflowScript, args: "error" in normalizedArgs ? publicParams.args : deepFreezeWorkflowArgs(normalizedArgs.args) };
16758
+ workflowLaunch = { source: "script", params: savedWorkflowLaunchParams(publicParams) };
16598
16759
  }
16760
+ if (workflowLaunch && publicParams.action === void 0) publicWorkflowLaunches.set(publicParams, workflowLaunch);
16761
+ if (workflowResumeLaunch) workflowResumeLaunches.set(publicParams, workflowResumeLaunch);
16599
16762
  publicExecutions.add(publicParams);
16600
16763
  return executeWithSingleDispatchGuard(id, publicParams, signal, onUpdate, ctx);
16601
16764
  };
16765
+ const executeWorkflowResume = async (id, prepared, signal, ctx) => {
16766
+ const params = { ...prepared.params };
16767
+ const launch = { presetRunId: prepared.newRunId, resumeOrigin: prepared.resumeOrigin, expectedScriptDigest: prepared.expectedScriptDigest };
16768
+ workflowResumeLaunches.set(params, launch);
16769
+ let result2;
16770
+ try {
16771
+ result2 = await executePublic(id, params, signal, void 0, ctx);
16772
+ } catch (error) {
16773
+ result2 = { content: [{ type: "text", text: error instanceof Error ? error.message : String(error) }], isError: true, details: { mode: "workflow", results: [] } };
16774
+ }
16775
+ if (resumedRunStarted(prepared.sourceAsyncDir, prepared.newRunId)) return { result: result2, launched: true };
16776
+ const firstText = result2.content.find((block) => block.type === "text")?.text ?? "no result";
16777
+ 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);
16778
+ releaseWorkflowResumeClaim(prepared.sourceAsyncDir, prepared.newRunId);
16779
+ if (prepared.trigger === "auto") {
16780
+ try {
16781
+ recordWorkflowResumeRefusal(prepared.sourceAsyncDir, { reason: refusal.reason, byHand: refusal.byHand, newRunId: prepared.newRunId });
16782
+ } catch (error) {
16783
+ console.error(`Failed to record why workflow ${prepared.sourceRunId} was not resumed:`, error);
16784
+ }
16785
+ }
16786
+ return { result: result2, launched: false, refusal };
16787
+ };
16788
+ const resumeWorkflowById = async (id, sourceRunId, signal, ctx) => {
16789
+ const refused = (text) => ({ content: [{ type: "text", text }], isError: true, details: { mode: "management", results: [] } });
16790
+ let preparation;
16791
+ try {
16792
+ preparation = prepareWorkflowResume({ asyncDirRoot: DIRS.async, sourceRunId, trigger: "manual", now: Date.now(), currentSessionId: resolveCurrentSessionId(ctx.sessionManager) });
16793
+ } catch (error) {
16794
+ return refused(`Cannot resume workflow '${sourceRunId}': ${error instanceof Error ? error.message : String(error)}`);
16795
+ }
16796
+ if (!preparation.ok) return refused(manualWorkflowResumeRefusalText(sourceRunId, preparation));
16797
+ const outcome = await executeWorkflowResume(id, preparation.prepared, signal, ctx);
16798
+ if (!outcome.launched) return refused(manualWorkflowResumeRefusalText(sourceRunId, outcome.refusal));
16799
+ const resumedLine = `Resumed workflow '${sourceRunId}' as ${preparation.prepared.newRunId}.`;
16800
+ const textIndex = outcome.result.content.findIndex((block) => block.type === "text");
16801
+ const content = [...outcome.result.content];
16802
+ const first = content[textIndex];
16803
+ if (first?.type === "text") content[textIndex] = { ...first, text: `${resumedLine}
16804
+ ${first.text}` };
16805
+ else content.unshift({ type: "text", text: resumedLine });
16806
+ return { ...outcome.result, content };
16807
+ };
16602
16808
  const executeDelegated = async (id, params, signal, onUpdate, ctx) => {
16603
16809
  const disabledFeatureError = disabledFeatureResult(params);
16604
16810
  if (disabledFeatureError) return disabledFeatureError;
@@ -16637,7 +16843,7 @@ ${item.text}` } : item)
16637
16843
  if (!ownerId) return;
16638
16844
  for (const owner of scheduledOwnerExecutors.get(ownerId)?.values() ?? []) yield owner.state;
16639
16845
  }
16640
- return { execute: executeWithSingleDispatchGuard, executePublic, executeDelegated, executeScheduled, getCurrentSupervisorOwnerStates };
16846
+ return { execute: executeWithSingleDispatchGuard, executePublic, executeDelegated, executeScheduled, executeWorkflowResume, getCurrentSupervisorOwnerStates };
16641
16847
  }
16642
16848
  export {
16643
16849
  DEFAULT_ASYNC_TIMEOUT_MS,