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
@@ -10,10 +10,10 @@ import {
10
10
  setInlineWorkflowCoverage,
11
11
  setMainThinkingLevelSource,
12
12
  widgetRenderKey
13
- } from "./chunk-2ZSNH26H.js";
13
+ } from "./chunk-4Y2ROR7L.js";
14
14
  import {
15
15
  package_default
16
- } from "./chunk-2XYWN7QJ.js";
16
+ } from "./chunk-UTT254JE.js";
17
17
  import {
18
18
  EXTERNAL_JOB_BRIDGE_REQUEST_DIR,
19
19
  REVIVAL_ORIGIN_FILE,
@@ -36,25 +36,32 @@ import {
36
36
  formatControlNoticeMessage,
37
37
  getInspectorPlugins,
38
38
  hasLiveSubagentWork,
39
+ hasWorkflowResumeRefusal,
39
40
  listRetainedChildren,
40
41
  listScheduledRunSummaries,
41
42
  markSeenWithTtl,
42
43
  normalizePublicSubagentExecution,
43
44
  parseSubagentNotifyContent,
45
+ prepareWorkflowResume,
44
46
  preservedAgentFrontmatterFields,
45
47
  readWorkflowReceipt,
48
+ recordWorkflowResumeRefusal,
49
+ refusalSentence,
46
50
  registerHerdrStatusBridge,
47
51
  registerInspectorEventListener,
48
52
  registerMainWatchdog,
49
53
  registerPiWebSessionLiveness,
50
54
  registerSubagentNotify,
55
+ releaseWorkflowResumeClaim,
51
56
  resolveSubagentResultStatus,
52
- restoreForegroundRunHistory,
57
+ resumedRunStarted,
53
58
  runtimeReplacedAbortReason,
54
59
  sameProviderDiagnostics,
55
60
  serviceExternalJobBridgeRequests,
56
- snapshotProviderDiagnostics
57
- } from "./chunk-26C3WLYQ.js";
61
+ snapshotProviderDiagnostics,
62
+ workflowResumeClaimState,
63
+ workflowResumeRefusal
64
+ } from "./chunk-ZIV4J4HG.js";
58
65
  import {
59
66
  CONTACT_SUPERVISOR_TOOL_NAME,
60
67
  NATIVE_SUPERVISOR_TOOL_NAME,
@@ -78,16 +85,18 @@ import {
78
85
  registerPinnedTool,
79
86
  registerWaitTool,
80
87
  resolveCurrentSessionId,
88
+ resolvePiSessionId,
81
89
  resolveWaitToolConfig,
82
90
  setDeclarationPinning,
83
91
  topLevelSupervisorTool
84
- } from "./chunk-BPS2AGBZ.js";
92
+ } from "./chunk-VSUSLDNW.js";
85
93
  import {
86
- currentCompletionOwnerId,
87
94
  deliverAsyncRunStop,
95
+ ownerConfirmedDead,
88
96
  readSessionMessagesTail,
89
- resolveSubagentRunId
90
- } from "./chunk-KSWQVGDW.js";
97
+ resolveSubagentRunId,
98
+ restoreForegroundRunHistory
99
+ } from "./chunk-FXUXCX2K.js";
91
100
  import {
92
101
  ASYNC_STATUS_SNAPSHOT_KIND,
93
102
  ASYNC_STATUS_SNAPSHOT_VERSION,
@@ -109,7 +118,7 @@ import {
109
118
  resolveAsyncStatusChild,
110
119
  stopStoppableAsyncStatusChildren,
111
120
  withCachedUiContext
112
- } from "./chunk-NNLASTQE.js";
121
+ } from "./chunk-6XJB7PIX.js";
113
122
  import "./chunk-NF7IEKBH.js";
114
123
  import {
115
124
  disabledFeatureUseError,
@@ -120,15 +129,21 @@ import {
120
129
  resolveDisabledFeatureSurface,
121
130
  resolveMaxActiveAsyncRunsPerSession,
122
131
  resolveScheduledStoreRoot
123
- } from "./chunk-WSBNENFS.js";
132
+ } from "./chunk-UCPP4GNU.js";
124
133
  import {
125
134
  ACTIVE_RUN_INDEX_DIR,
126
135
  MissionNotFoundError,
136
+ OWNING_SESSION_COMPLETION_OWNER,
137
+ WORKFLOW_STOP_CAUSE_OWNER_EXITED,
127
138
  acknowledgeMissionObserverSnapshot,
139
+ checkRecordedPidLiveness,
128
140
  cleanupResultIndexes,
141
+ currentCompletionOwnerId,
129
142
  encodeIndexSegment,
130
143
  findNestedRouteForRootId,
131
144
  hasLiveNestedDescendants,
145
+ isRecordedPid,
146
+ isReusableWorkflowStopCause,
132
147
  listMissions,
133
148
  missionObserverIndexPath,
134
149
  missionObserverResultCandidateFiles,
@@ -141,6 +156,7 @@ import {
141
156
  readMission,
142
157
  readMissionBinding,
143
158
  readProcessTerminal,
159
+ readRecentTerminalRunIndex,
144
160
  readResultPayload,
145
161
  reconcileAsyncRun,
146
162
  reconcileNestedAsyncDescendants,
@@ -162,28 +178,28 @@ import {
162
178
  withWorkflowChildRunModel,
163
179
  writeAsyncResultFile,
164
180
  writeResultIndexForData
165
- } from "./chunk-VJHOELQP.js";
166
- import "./chunk-BJN5LUQY.js";
181
+ } from "./chunk-46XKCPJR.js";
182
+ import "./chunk-OYF6AFDY.js";
167
183
  import {
168
184
  shouldUseNativeFsWatch
169
185
  } from "./chunk-NIXWDZZV.js";
170
186
  import {
171
187
  validateIntercomBridgeConfig
172
- } from "./chunk-ZP3HODFH.js";
188
+ } from "./chunk-XSWOTIA3.js";
173
189
  import "./chunk-7F6RKT6W.js";
174
- import "./chunk-G5DKFLLI.js";
190
+ import "./chunk-4SDU2BZX.js";
175
191
  import "./chunk-CTPAE36Y.js";
176
192
  import {
177
193
  listHerdrProjectPaneRoots,
178
194
  restoreHerdrProjectPaneSnapshots
179
- } from "./chunk-V2JWDB5U.js";
195
+ } from "./chunk-52UBALJL.js";
180
196
  import "./chunk-7J4ZXMY7.js";
181
197
  import {
182
198
  cleanupAllArtifactDirs,
183
199
  cleanupOldArtifacts,
184
200
  getArtifactPaths,
185
201
  getArtifactsDir
186
- } from "./chunk-3DC5KBVP.js";
202
+ } from "./chunk-5TYMSZX3.js";
187
203
  import {
188
204
  listBackgroundWorkProviders
189
205
  } from "./chunk-N2BN7BF5.js";
@@ -191,12 +207,12 @@ import "./chunk-YYREO77V.js";
191
207
  import "./chunk-UKG4V45O.js";
192
208
  import {
193
209
  registerRuntimeAgentEventListener
194
- } from "./chunk-LSRUTHT7.js";
210
+ } from "./chunk-43SCHIMD.js";
195
211
  import {
196
212
  clearRuntimeAgentsForPi,
197
213
  listRuntimeAgentConfigs,
198
214
  mergeRuntimeAgents
199
- } from "./chunk-3IF2PGW7.js";
215
+ } from "./chunk-YKEWIB4M.js";
200
216
  import {
201
217
  DEFAULT_FILE_SYSTEM_RETRY_DELAYS_MS,
202
218
  EXTRA_AGENT_DIRS_ENV,
@@ -236,7 +252,7 @@ import {
236
252
  waitForFileSystemRetry,
237
253
  withSettingsFileLease,
238
254
  writeAtomicJson
239
- } from "./chunk-ZBC44JJ3.js";
255
+ } from "./chunk-CIZQXJ5Q.js";
240
256
  import {
241
257
  DEFAULT_ARTIFACT_CONFIG,
242
258
  DIRS,
@@ -282,7 +298,7 @@ import {
282
298
  import { randomUUID as randomUUID3 } from "node:crypto";
283
299
  import * as fs16 from "node:fs";
284
300
  import * as os3 from "node:os";
285
- import * as path15 from "node:path";
301
+ import * as path16 from "node:path";
286
302
  import { Box as Box2, Container as Container3, Spacer as Spacer3, Text as Text2 } from "@earendil-works/pi-tui";
287
303
 
288
304
  // src/agents/global-npm-root.ts
@@ -884,7 +900,7 @@ function createAsyncJobTracker(pi, state, asyncDirRoot, options = {}) {
884
900
  job.sessionFile = status.sessionFile ?? job.sessionFile;
885
901
  if (isTerminalJobStatus(job.status)) {
886
902
  let publication = terminalPublications.get(job.asyncId);
887
- if (!publication && status.mode !== "workflow" && status.processTerminal?.state === "pending" && status.runId === job.asyncId && status.sessionId === state.currentSessionId && status.completionOwnerId && status.completionOwnerId === state.completionOwnerId) {
903
+ if (!publication && status.mode !== "workflow" && status.processTerminal?.state === "pending" && status.runId === job.asyncId && status.completionOwnerId && (status.sessionId === state.currentSessionId && status.completionOwnerId === state.completionOwnerId || typeof status.sessionId === "string" && options.deliveryOwnerId?.(status.sessionId, status.completionOwnerId, status.completionOwnerProcess, status.parentWorkflowRunId) === OWNING_SESSION_COMPLETION_OWNER)) {
888
904
  publication = { instanceId: status.processTerminal.runnerProcessInstanceId, pending: true };
889
905
  terminalPublications.set(job.asyncId, publication);
890
906
  }
@@ -1160,13 +1176,13 @@ function createAsyncJobTracker(pi, state, asyncDirRoot, options = {}) {
1160
1176
  rerenderWidget(ctx, []);
1161
1177
  }
1162
1178
  };
1163
- const restoreActiveJobs = (ctx) => {
1179
+ const restoreActiveJobs = (ctx, observeStatus) => {
1164
1180
  if (ctx?.hasUI) state.lastUiContext = ctx;
1165
1181
  state.statusProjectionSessionId = null;
1166
1182
  if (!state.currentSessionId) return;
1167
1183
  let runs;
1168
1184
  try {
1169
- runs = listAsyncRuns(asyncDirRoot, { states: ["queued", "running"], sessionId: state.currentSessionId, resultsDir, kill: options.kill, now: options.now });
1185
+ runs = listAsyncRuns(asyncDirRoot, { states: ["queued", "running"], sessionId: state.currentSessionId, resultsDir, kill: options.kill, now: options.now, adoptCompletionOwnerId: state.completionOwnerId }, observeStatus);
1170
1186
  } catch (error) {
1171
1187
  console.error(`Failed to restore active async jobs from '${asyncDirRoot}':`, error);
1172
1188
  return;
@@ -1975,22 +1991,27 @@ var HEALTHY_SCAN_INTERVAL_MS = 6e4;
1975
1991
  var RETRY_DELAY_MS = 100;
1976
1992
  var CLEANUP_LEASE_WAIT_MS = 0;
1977
1993
  var SLOW_RESULT_SCAN_MS = 500;
1978
- function jsonStringProperty(raw, property) {
1979
- const matches = raw.matchAll(new RegExp(`"${property}"\\s*:\\s*("(?:\\\\.|[^"\\\\])*")`, "g"));
1994
+ function jsonPropertyValue(raw, property, valuePattern) {
1980
1995
  let encoded;
1981
- for (const match of matches) encoded = match[1];
1996
+ for (const match of raw.matchAll(new RegExp(`"${property}"\\s*:\\s*(${valuePattern})`, "g"))) encoded = match[1];
1982
1997
  if (!encoded) return void 0;
1983
1998
  try {
1984
- const value = JSON.parse(encoded);
1985
- return typeof value === "string" && value ? value : void 0;
1999
+ return JSON.parse(encoded);
1986
2000
  } catch {
1987
2001
  return void 0;
1988
2002
  }
1989
2003
  }
2004
+ function jsonStringProperty(raw, property) {
2005
+ const value = jsonPropertyValue(raw, property, `"(?:\\\\.|[^"\\\\])*"`);
2006
+ return typeof value === "string" && value ? value : void 0;
2007
+ }
1990
2008
  function resultFileIdentity(raw, file) {
1991
2009
  return {
1992
2010
  sessionId: jsonStringProperty(raw, "sessionId"),
1993
2011
  completionOwnerId: jsonStringProperty(raw, "completionOwnerId"),
2012
+ // Recorded as a flat object, so a brace-free match is the whole value.
2013
+ completionOwnerProcess: jsonPropertyValue(raw, "completionOwnerProcess", `\\{[^{}]*\\}`),
2014
+ parentWorkflowRunId: jsonStringProperty(raw, "parentWorkflowRunId"),
1994
2015
  runId: file.replace(/\.json$/i, "")
1995
2016
  };
1996
2017
  }
@@ -2047,12 +2068,14 @@ function createResultWatcher(pi, state, resultsDir, completionTtlMs, deps = {})
2047
2068
  const handling = /* @__PURE__ */ new Set();
2048
2069
  let deliveringPending = 0;
2049
2070
  const identityCache = /* @__PURE__ */ new Map();
2071
+ const reportedMissionSyncFailures = /* @__PURE__ */ new Map();
2050
2072
  let deliveryActive = true;
2051
2073
  let deliveryEpoch = 0;
2052
2074
  let resultScanTimer = null;
2053
2075
  let activeSessionId = null;
2054
2076
  const ownsResult = deps.ownership?.owns ?? ((sessionId, completionOwnerId) => sessionId === state.currentSessionId && typeof completionOwnerId === "string" && completionOwnerId === state.completionOwnerId);
2055
2077
  const claimedSessionIds = () => deps.ownership?.claimedSessionIds() ?? [];
2078
+ const deliveryOwnerId = deps.ownership?.deliveryOwnerId ?? ((_sessionId, completionOwnerId) => completionOwnerId);
2056
2079
  const ownsCompletion = (sessionId, completionOwnerId, epoch) => {
2057
2080
  if (!deliveryActive || epoch !== deliveryEpoch) return false;
2058
2081
  if (!activeSessionId && state.currentSessionId) activeSessionId = state.currentSessionId;
@@ -2136,7 +2159,7 @@ function createResultWatcher(pi, state, resultsDir, completionTtlMs, deps = {})
2136
2159
  if (!inspected) return false;
2137
2160
  const { identity } = inspected;
2138
2161
  if (!identity.sessionId) return true;
2139
- if (ownsResult(identity.sessionId, identity.completionOwnerId)) return true;
2162
+ if (ownsResult(identity.sessionId, deliveryOwnerId(identity.sessionId, identity.completionOwnerId, identity.completionOwnerProcess, identity.parentWorkflowRunId))) return true;
2140
2163
  if (identity.runId && fsApi.existsSync(missionObserverIndexPath(resultsDir, identity.runId))) return true;
2141
2164
  if (identity.runId && (observed ?? observedRunIds()).has(identity.runId)) return true;
2142
2165
  return Boolean(deps.observeCompletion && !deps.observedCompletionRunIds);
@@ -2201,7 +2224,7 @@ function createResultWatcher(pi, state, resultsDir, completionTtlMs, deps = {})
2201
2224
  let data = parseResult(raw);
2202
2225
  if (typeof data.sessionId !== "string" || !data.sessionId) return;
2203
2226
  const sessionId = data.sessionId;
2204
- const completionOwnerId = data.completionOwnerId;
2227
+ const completionOwnerId = deliveryOwnerId(sessionId, data.completionOwnerId, data.completionOwnerProcess, data.parentWorkflowRunId);
2205
2228
  const runId = typeof data.runId === "string" && data.runId ? data.runId : typeof data.id === "string" && data.id ? data.id : file.replace(/\.json$/i, "");
2206
2229
  const toolCallId = typeof data.toolCallId === "string" ? data.toolCallId : void 0;
2207
2230
  let read = { runId, sessionId, toolCallId, snapshot: raw, ...publicAtRead !== void 0 && publicAtRead !== raw ? { stalePublic: publicAtRead } : {} };
@@ -2219,9 +2242,14 @@ function createResultWatcher(pi, state, resultsDir, completionTtlMs, deps = {})
2219
2242
  let observerSucceeded = true;
2220
2243
  try {
2221
2244
  syncMissionFromAsyncCompletion({ ...data, runId });
2245
+ reportedMissionSyncFailures.delete(file);
2222
2246
  } catch (error) {
2223
2247
  observerSucceeded = false;
2224
- console.error(`Mission completion sync failed for '${resultPath}':`, error);
2248
+ const message2 = error instanceof Error ? error.message : String(error);
2249
+ if (reportedMissionSyncFailures.get(file) !== message2) {
2250
+ reportedMissionSyncFailures.set(file, message2);
2251
+ console.error(`Mission completion sync failed for '${resultPath}':`, error);
2252
+ }
2225
2253
  }
2226
2254
  try {
2227
2255
  deps.observeCompletion?.({ ...data, runId });
@@ -2348,6 +2376,7 @@ ${baseOutput}` : ""}` : output;
2348
2376
  ...data,
2349
2377
  id: data.id ?? runId,
2350
2378
  runId,
2379
+ completionOwnerId,
2351
2380
  triggerTurn,
2352
2381
  intercomDelivered,
2353
2382
  ...nestedChildren?.length ? { nestedChildren } : {},
@@ -2622,14 +2651,24 @@ ${baseOutput}` : ""}` : output;
2622
2651
  }
2623
2652
 
2624
2653
  // src/runs/background/result-delivery-ownership.ts
2654
+ var deadCompletionOwnerIds = /* @__PURE__ */ new Set();
2625
2655
  function createResultDeliveryOwnership(state) {
2626
2656
  const currentOwner = () => typeof state.completionOwnerId === "string" && state.completionOwnerId ? state.completionOwnerId : void 0;
2627
2657
  return {
2628
2658
  owns(sessionId, completionOwnerId) {
2629
2659
  const owner = currentOwner();
2630
- if (!owner || completionOwnerId !== owner) return false;
2660
+ if (!owner || completionOwnerId !== owner && completionOwnerId !== OWNING_SESSION_COMPLETION_OWNER) return false;
2631
2661
  return ownsRun(state.currentSessionId, sessionId);
2632
2662
  },
2663
+ deliveryOwnerId(sessionId, completionOwnerId, ownerProcess, parentWorkflowRunId) {
2664
+ const owner = currentOwner();
2665
+ if (!owner || typeof completionOwnerId !== "string" || completionOwnerId === owner || completionOwnerId === OWNING_SESSION_COMPLETION_OWNER || parentWorkflowRunId || !ownsRun(state.currentSessionId, sessionId)) return completionOwnerId;
2666
+ if (!deadCompletionOwnerIds.has(completionOwnerId)) {
2667
+ if (!isRecordedPid(ownerProcess) || checkRecordedPidLiveness(ownerProcess) !== "dead") return completionOwnerId;
2668
+ deadCompletionOwnerIds.add(completionOwnerId);
2669
+ }
2670
+ return OWNING_SESSION_COMPLETION_OWNER;
2671
+ },
2633
2672
  claimedSessionIds() {
2634
2673
  if (!currentOwner() || !state.currentSessionId) return [];
2635
2674
  return inheritedSessionIds(state.currentSessionId);
@@ -5141,7 +5180,7 @@ function registerSlashCommands(pi, state, options = {}) {
5141
5180
  }
5142
5181
  fleetOpen = true;
5143
5182
  try {
5144
- const { openSubagentFleet } = await import("./chunk-563BHAZ5.js");
5183
+ const { openSubagentFleet } = await import("./chunk-G4GZD3OJ.js");
5145
5184
  await openSubagentFleet(ctx, state, { asyncDirRoot: DIRS.async, inspectorPlugins: () => getInspectorPlugins(pi), resultsDir: DIRS.results, fleetKeybindings: options.fleetKeybindings });
5146
5185
  } finally {
5147
5186
  fleetOpen = false;
@@ -6773,6 +6812,7 @@ var MESSAGE_VIEWS = /* @__PURE__ */ new Map([
6773
6812
  ["subagent-wait-subscription", readsContent("result", (message2) => waitSubscriptionHeadline(message2.details))],
6774
6813
  ["subagent-incremental-child-notify", readsContent("result", workflowChildHeadline)],
6775
6814
  ["subagent-workflow-result-write-failed", readsContent("result", () => ["workflow result ", { status: "save failed" }])],
6815
+ ["subagent-auto-resume", readsContent("result", () => ["workflow auto-resume ", { status: "failed" }])],
6776
6816
  [SUBAGENT_CONTROL_MESSAGE_TYPE, readsContent("attention", (message2) => controlNoticeHeadline(message2.details))],
6777
6817
  [SUBAGENT_STEERING_MESSAGE_TYPE, readsContent("attention", (message2) => steeringNoticeHeadline(message2.details))],
6778
6818
  [SUBAGENT_WATCHDOG_WARNING_TYPE, (message2) => watchdogWarningView(message2.details, contentText(message2.content))],
@@ -8039,9 +8079,79 @@ function buildSubagentToolDescription(config = {}, options) {
8039
8079
  return fullDescription(on);
8040
8080
  }
8041
8081
 
8082
+ // src/workflows/workflow-auto-resume.ts
8083
+ import * as path13 from "node:path";
8084
+ var WORKFLOW_AUTO_RESUME_MESSAGE_TYPE = "subagent-auto-resume";
8085
+ var AUTO_RESUME_MAX_AGE_MS = 24 * 60 * 60 * 1e3;
8086
+ var AUTO_RESUME_SCAN_LIMIT = 50;
8087
+ function interruptedAt(status) {
8088
+ return status.workflow?.stopCause === WORKFLOW_STOP_CAUSE_OWNER_EXITED ? status.workflow.ownerExitedAt : status.endedAt;
8089
+ }
8090
+ var registryKey = /* @__PURE__ */ Symbol.for("pi-subagents.workflow-auto-resume.v1");
8091
+ var registryGlobal = globalThis;
8092
+ var pendingAutoResumes = registryGlobal[registryKey] ?? (registryGlobal[registryKey] = /* @__PURE__ */ new Set());
8093
+ function cancelPendingWorkflowAutoResumes(match) {
8094
+ for (const entry of pendingAutoResumes) {
8095
+ if (entry.state !== "pending" || !match(entry)) continue;
8096
+ entry.state = "cancelled";
8097
+ try {
8098
+ releaseWorkflowResumeClaim(entry.prepared.sourceAsyncDir, entry.prepared.newRunId);
8099
+ } catch (error) {
8100
+ console.error(`Failed to give back the auto-resume claim of workflow ${entry.prepared.sourceRunId}:`, error);
8101
+ }
8102
+ }
8103
+ }
8104
+ function finishWorkflowAutoResume(entry) {
8105
+ if (entry.state !== "cancelled") pendingAutoResumes.delete(entry);
8106
+ }
8107
+ function planWorkflowAutoResumes(input) {
8108
+ const { asyncDirRoot, currentSessionId, now } = input;
8109
+ cancelPendingWorkflowAutoResumes((entry) => entry.sessionId === currentSessionId);
8110
+ const reusableRunIds = /* @__PURE__ */ new Map();
8111
+ for (const entry of pendingAutoResumes) {
8112
+ if (entry.sessionId !== currentSessionId || entry.state !== "cancelled") continue;
8113
+ reusableRunIds.set(entry.prepared.sourceRunId, entry.prepared.newRunId);
8114
+ pendingAutoResumes.delete(entry);
8115
+ }
8116
+ let runIds;
8117
+ try {
8118
+ runIds = readRecentTerminalRunIndex(asyncDirRoot, { sessionId: currentSessionId, limit: AUTO_RESUME_SCAN_LIMIT, endedAfter: now - AUTO_RESUME_MAX_AGE_MS });
8119
+ } catch (error) {
8120
+ console.error("Failed to read interrupted workflows for auto-resume:", error);
8121
+ return [];
8122
+ }
8123
+ const planned = [];
8124
+ for (const runId of runIds) {
8125
+ const asyncDir = path13.join(asyncDirRoot, runId);
8126
+ try {
8127
+ const status = readStatus(asyncDir);
8128
+ if (!status || status.mode !== "workflow" || status.parentWorkflowRunId !== void 0 || status.sessionId !== currentSessionId) continue;
8129
+ if (!isReusableWorkflowStopCause(status.workflow?.stopCause)) continue;
8130
+ const at = interruptedAt(status);
8131
+ if (at === void 0 || now - at > AUTO_RESUME_MAX_AGE_MS) continue;
8132
+ if (workflowResumeClaimState(asyncDir).kind !== "none" || hasWorkflowResumeRefusal(asyncDir)) continue;
8133
+ const preparation = prepareWorkflowResume({ asyncDirRoot, sourceRunId: runId, trigger: "auto", now, currentSessionId, newRunId: reusableRunIds.get(runId) });
8134
+ if (preparation.ok) {
8135
+ const entry = { sessionId: currentSessionId, owner: input.owner, prepared: preparation.prepared, state: "pending" };
8136
+ pendingAutoResumes.add(entry);
8137
+ planned.push(entry);
8138
+ continue;
8139
+ }
8140
+ if (preparation.code === "claim-busy" || preparation.code === "claim-resumed") continue;
8141
+ recordWorkflowResumeRefusal(asyncDir, { reason: preparation.reason, byHand: preparation.byHand }, now);
8142
+ } catch (error) {
8143
+ console.error(`Failed to prepare auto-resume of workflow ${runId}:`, error);
8144
+ }
8145
+ }
8146
+ return planned;
8147
+ }
8148
+ function autoResumeFailureText(sourceRunId, refusal) {
8149
+ return `Workflow ${sourceRunId} was not auto-resumed: ${refusalSentence(refusal.reason, refusal.byHand)}`;
8150
+ }
8151
+
8042
8152
  // src/missions/goal-driver.ts
8043
8153
  import * as fs14 from "node:fs";
8044
- import * as path13 from "node:path";
8154
+ import * as path14 from "node:path";
8045
8155
  var TERMINAL_MISSION_STATUSES2 = /* @__PURE__ */ new Set(["completed", "failed", "cancelled"]);
8046
8156
  var ACTIVE_RUN_STATUSES = /* @__PURE__ */ new Set(["queued", "running", "active"]);
8047
8157
  var MAX_ACTION_LENGTH = 180;
@@ -8056,7 +8166,7 @@ function tokenUsage(value) {
8056
8166
  }
8057
8167
  function readLinkedRun(run) {
8058
8168
  if (!run.asyncDir) return run;
8059
- const statusPath = path13.join(run.asyncDir, "status.json");
8169
+ const statusPath = path14.join(run.asyncDir, "status.json");
8060
8170
  if (!fs14.existsSync(statusPath)) return run;
8061
8171
  let parsed;
8062
8172
  try {
@@ -8182,14 +8292,57 @@ function collectGoalContinuationNotices(input) {
8182
8292
  return notices;
8183
8293
  }
8184
8294
 
8295
+ // src/runs/background/interrupted-elsewhere.ts
8296
+ var INTERRUPTED_ELSEWHERE_MAX_AGE_MS = 24 * 60 * 60 * 1e3;
8297
+ function interruptedElsewhereLine(reopenId, count) {
8298
+ const command = `\`pi --session ${reopenId}\``;
8299
+ return count === 1 ? `1 subagent run was interrupted in another session. Reopen it to resume it: ${command}` : `${count} subagent runs were interrupted in another session. Reopen it to resume them: ${command}`;
8300
+ }
8301
+ function createInterruptedElsewhereCollector(input) {
8302
+ const ownSessions = ownerSessionIds(input.currentSessionId);
8303
+ const candidates = /* @__PURE__ */ new Map();
8304
+ const recent = (at) => typeof at === "number" && input.now - at <= INTERRUPTED_ELSEWHERE_MAX_AGE_MS;
8305
+ const add = (sessionId, runId, ownerDead) => {
8306
+ if (ownSessions.has(sessionId)) return;
8307
+ const runs = candidates.get(sessionId) ?? /* @__PURE__ */ new Map();
8308
+ if (!runs.has(runId)) runs.set(runId, ownerDead);
8309
+ candidates.set(sessionId, runs);
8310
+ };
8311
+ return {
8312
+ observeStatus(observed) {
8313
+ const status = observed;
8314
+ if (!status || typeof status.sessionId !== "string" || typeof status.runId !== "string" || status.state !== "running" && status.state !== "queued") return;
8315
+ if (status.parentWorkflowRunId !== void 0 || status.cwd !== input.cwd || !recent(status.lastUpdate ?? status.startedAt)) return;
8316
+ const { pid, pidNamespaceScope, bootId } = status;
8317
+ if (typeof pid !== "number") return;
8318
+ add(status.sessionId, status.runId, () => checkRecordedPidLiveness({ pid, pidNamespaceScope, bootId }) === "dead");
8319
+ },
8320
+ observeForegroundRun(run) {
8321
+ if (!run.sessionId || run.parentWorkflowRunId !== void 0 || run.cwd !== input.cwd || !recent(run.updatedAt)) return;
8322
+ add(run.sessionId, run.runId, () => ownerConfirmedDead(run));
8323
+ },
8324
+ lines() {
8325
+ const lines = [];
8326
+ for (const [sessionId, runs] of candidates) {
8327
+ const reopenId = resolvePiSessionId(sessionId);
8328
+ if (!reopenId) continue;
8329
+ let interrupted = 0;
8330
+ for (const ownerDead of runs.values()) if (ownerDead()) interrupted += 1;
8331
+ if (interrupted > 0) lines.push(interruptedElsewhereLine(reopenId, interrupted));
8332
+ }
8333
+ return lines;
8334
+ }
8335
+ };
8336
+ }
8337
+
8185
8338
  // src/extension/upgrade-notice.ts
8186
8339
  import * as fs15 from "node:fs";
8187
- import * as path14 from "node:path";
8340
+ import * as path15 from "node:path";
8188
8341
  import { fileURLToPath as fileURLToPath2 } from "node:url";
8189
8342
  var versionNumber = (version) => typeof version === "string" && /^\d+\.\d+\.\d+$/.test(version) ? version.split(".").reduce((total, part) => total * 1e6 + Number(part), 0) : void 0;
8190
- async function showUpgradeNotice(ctx, stateDir = path14.join(getAgentDir(), "pi-subagents"), changelogPath = fileURLToPath2(new URL("../../CHANGELOG.md", new URL("../src/extension/upgrade-notice.js", import.meta.url).href)), version = package_default.version) {
8343
+ async function showUpgradeNotice(ctx, stateDir = path15.join(getAgentDir(), "pi-subagents"), changelogPath = fileURLToPath2(new URL("../../CHANGELOG.md", new URL("../src/extension/upgrade-notice.js", import.meta.url).href)), version = package_default.version) {
8191
8344
  if (!ctx.hasUI) return;
8192
- const statePath = path14.join(stateDir, "last-seen-version.json");
8345
+ const statePath = path15.join(stateDir, "last-seen-version.json");
8193
8346
  const lastSeen = await fs15.promises.readFile(statePath, "utf-8").then((raw) => JSON.parse(raw).version).catch(() => void 0);
8194
8347
  const previous = versionNumber(lastSeen);
8195
8348
  const current = versionNumber(version);
@@ -8251,14 +8404,14 @@ function formatWorkflowPreflightCall(input) {
8251
8404
  }
8252
8405
  function getSubagentSessionRoot(parentSessionFile) {
8253
8406
  if (parentSessionFile) {
8254
- const baseName = path15.basename(parentSessionFile, ".jsonl");
8255
- const sessionsDir = path15.dirname(parentSessionFile);
8256
- return path15.join(sessionsDir, baseName);
8407
+ const baseName = path16.basename(parentSessionFile, ".jsonl");
8408
+ const sessionsDir = path16.dirname(parentSessionFile);
8409
+ return path16.join(sessionsDir, baseName);
8257
8410
  }
8258
- return fs16.mkdtempSync(path15.join(os3.tmpdir(), "pi-subagent-session-"));
8411
+ return fs16.mkdtempSync(path16.join(os3.tmpdir(), "pi-subagent-session-"));
8259
8412
  }
8260
8413
  function expandTilde(p) {
8261
- return p.startsWith("~/") ? path15.join(os3.homedir(), p.slice(2)) : p;
8414
+ return p.startsWith("~/") ? path16.join(os3.homedir(), p.slice(2)) : p;
8262
8415
  }
8263
8416
  function isSlashResultRunning(result) {
8264
8417
  return result.details?.progress?.some((entry) => entry.status === "running") || result.details?.results.some((entry) => entry.progress?.status === "running") || false;
@@ -8414,7 +8567,7 @@ function registerSubagentExtension(pi) {
8414
8567
  const ctx = withLastUiContext((current) => current);
8415
8568
  if (!ctx) return;
8416
8569
  try {
8417
- const { openSubagentFleet } = await import("./chunk-563BHAZ5.js");
8570
+ const { openSubagentFleet } = await import("./chunk-G4GZD3OJ.js");
8418
8571
  await openSubagentFleet(ctx, state, { initialKey: itemKey, asyncDirRoot: DIRS.async, resultsDir: DIRS.results, fleetKeybindings: config.fleetKeybindings, inspectorPlugins: () => getInspectorPlugins(pi) });
8419
8572
  } catch (error) {
8420
8573
  if (isStaleExtensionContextError(error)) {
@@ -8521,6 +8674,7 @@ function registerSubagentExtension(pi) {
8521
8674
  refreshResultDelivery();
8522
8675
  },
8523
8676
  onJobCleanup: (asyncId) => deliveredRunIds.delete(asyncId),
8677
+ deliveryOwnerId: resultDeliveryOwnership.deliveryOwnerId,
8524
8678
  supervisorRequestState: supervisorChannel.getSupervisorRequestState,
8525
8679
  onJobsChanged: programStatus.sync
8526
8680
  });
@@ -8609,7 +8763,7 @@ function registerSubagentExtension(pi) {
8609
8763
  let executor;
8610
8764
  let executorPromise;
8611
8765
  let executorModulePromise;
8612
- const loadExecutorModule = () => executorModulePromise ??= import("./chunk-XMFLCKMQ.js");
8766
+ const loadExecutorModule = () => executorModulePromise ??= import("./chunk-QE4AGIMG.js");
8613
8767
  const getExecutor = () => {
8614
8768
  executorPromise ??= loadExecutorModule().then(({ createSubagentExecutor }) => {
8615
8769
  executor = createSubagentExecutor(executorDeps);
@@ -8623,7 +8777,7 @@ function registerSubagentExtension(pi) {
8623
8777
  modulePreloadTimer = setTimeout(() => {
8624
8778
  loadExecutorModule().catch(() => {
8625
8779
  });
8626
- if (fleetViewEnabled) import("./chunk-563BHAZ5.js").catch(() => {
8780
+ if (fleetViewEnabled) import("./chunk-G4GZD3OJ.js").catch(() => {
8627
8781
  });
8628
8782
  }, MODULE_PRELOAD_DELAY_MS);
8629
8783
  modulePreloadTimer.unref?.();
@@ -8675,6 +8829,43 @@ ${close}` }]
8675
8829
  await waitForAdvertisement();
8676
8830
  return (await getExecutor()).executePublic(id, params, signal, onUpdate, ctx);
8677
8831
  };
8832
+ const autoResumeOwner = {};
8833
+ const postAutoResumeFailure = (sourceRunId, refusal) => {
8834
+ pi.sendMessage({ customType: WORKFLOW_AUTO_RESUME_MESSAGE_TYPE, content: autoResumeFailureText(sourceRunId, refusal), display: true }, { triggerTurn: false });
8835
+ };
8836
+ const launchWorkflowAutoResume = async (entry, ctx) => {
8837
+ const { prepared } = entry;
8838
+ try {
8839
+ await new Promise((resolve6) => setImmediate(resolve6));
8840
+ await waitForAdvertisement();
8841
+ const executor2 = await getExecutor();
8842
+ if (entry.state !== "pending") return;
8843
+ entry.state = "started";
8844
+ const outcome = await executor2.executeWorkflowResume(randomUUID3(), prepared, new AbortController().signal, ctx);
8845
+ if (outcome.launched && runtimeCleaned) state.workflowControllers?.get(prepared.newRunId)?.abort(runtimeReplacedAbortReason());
8846
+ if (outcome.launched || runtimeCleaned) return;
8847
+ try {
8848
+ postAutoResumeFailure(prepared.sourceRunId, outcome.refusal);
8849
+ } catch (error) {
8850
+ console.error(`Failed to post the auto-resume failure of workflow ${prepared.sourceRunId}:`, error);
8851
+ }
8852
+ } catch (error) {
8853
+ if (entry.state === "cancelled") return;
8854
+ const message2 = error instanceof Error ? error.message : String(error);
8855
+ console.error(`Failed to auto-resume workflow ${prepared.sourceRunId}:`, error);
8856
+ try {
8857
+ if (resumedRunStarted(prepared.sourceAsyncDir, prepared.newRunId)) return;
8858
+ releaseWorkflowResumeClaim(prepared.sourceAsyncDir, prepared.newRunId);
8859
+ const refusal = workflowResumeRefusal("launch-failed", `launch failed: ${message2}`, prepared.sourceRunId);
8860
+ recordWorkflowResumeRefusal(prepared.sourceAsyncDir, { reason: refusal.reason, byHand: refusal.byHand, newRunId: prepared.newRunId });
8861
+ postAutoResumeFailure(prepared.sourceRunId, refusal);
8862
+ } catch (cleanupError) {
8863
+ console.error(`Failed to give back the auto-resume claim of workflow ${prepared.sourceRunId}:`, cleanupError);
8864
+ }
8865
+ } finally {
8866
+ finishWorkflowAutoResume(entry);
8867
+ }
8868
+ };
8678
8869
  const executeSubagentCollapsed = (id, params, signal, onUpdate, ctx) => {
8679
8870
  if (ctx.hasUI) ctx.ui.setToolsExpanded(false);
8680
8871
  return executeSubagentReady(id, params, signal, onUpdate, ctx);
@@ -8898,9 +9089,9 @@ ${close}` }]
8898
9089
  owedResultRunIds.clear();
8899
9090
  deliveredRunIds.clear();
8900
9091
  state.parentSessionFile = ctx.sessionManager.getSessionFile();
8901
- state.trustedSessionFileRoot = state.parentSessionFile ? path15.join(getAgentDir(), "sessions") : void 0;
9092
+ state.trustedSessionFileRoot = state.parentSessionFile ? path16.join(getAgentDir(), "sessions") : void 0;
8902
9093
  state.trustedSessionRoots = [.../* @__PURE__ */ new Set([
8903
- ...config.defaultSessionDir ? [path15.resolve(expandTilde(config.defaultSessionDir))] : [],
9094
+ ...config.defaultSessionDir ? [path16.resolve(expandTilde(config.defaultSessionDir))] : [],
8904
9095
  ...state.parentSessionFile ? [getSubagentSessionRoot(state.parentSessionFile)] : []
8905
9096
  ])];
8906
9097
  state.subagentSpawns = {
@@ -8910,7 +9101,7 @@ ${close}` }]
8910
9101
  granted: 0,
8911
9102
  grantHistory: []
8912
9103
  };
8913
- const projectPaneOwnerRoot = path15.resolve(ctx.cwd);
9104
+ const projectPaneOwnerRoot = path16.resolve(ctx.cwd);
8914
9105
  restoreHerdrProjectPaneSnapshots(state, [.../* @__PURE__ */ new Set([...state.herdrProjectPanes?.keys() ?? [], ...listHerdrProjectPaneRoots(projectPaneOwnerRoot), projectPaneOwnerRoot])]);
8915
9106
  if (!process.env[SUBAGENT_CHILD_ENV]) {
8916
9107
  delete process.env[SUBAGENT_PARENT_SESSION_ENV];
@@ -8931,12 +9122,24 @@ ${close}` }]
8931
9122
  resetJobs(ctx);
8932
9123
  logSlowPhase("reset-jobs", phaseStartedAt);
8933
9124
  phaseStartedAt = Date.now();
8934
- restoreForegroundRunHistory(state, { resultsDir: DIRS.results });
9125
+ const interruptedElsewhere = ctx.hasUI ? createInterruptedElsewhereCollector({ currentSessionId: state.currentSessionId, cwd: ctx.cwd, now: Date.now() }) : void 0;
9126
+ restoreForegroundRunHistory(state, { resultsDir: DIRS.results, observeForeign: interruptedElsewhere?.observeForegroundRun });
8935
9127
  logSlowPhase("foreground-history", phaseStartedAt);
8936
9128
  phaseStartedAt = Date.now();
8937
- restoreActiveJobs(ctx);
9129
+ restoreActiveJobs(ctx, interruptedElsewhere?.observeStatus);
8938
9130
  logSlowPhase("active-job-restore", phaseStartedAt);
8939
9131
  phaseStartedAt = Date.now();
9132
+ if (interruptedElsewhere) for (const line of interruptedElsewhere.lines()) ctx.ui.notify(line, "info");
9133
+ logSlowPhase("cross-session-notice", phaseStartedAt);
9134
+ phaseStartedAt = Date.now();
9135
+ cancelPendingWorkflowAutoResumes((entry) => entry.owner === autoResumeOwner);
9136
+ if (recovering && ctx.hasUI && config.autoResume !== false) {
9137
+ for (const entry of planWorkflowAutoResumes({ asyncDirRoot: DIRS.async, currentSessionId: state.currentSessionId, now: Date.now(), owner: autoResumeOwner })) {
9138
+ void launchWorkflowAutoResume(entry, ctx);
9139
+ }
9140
+ }
9141
+ logSlowPhase("workflow-auto-resume", phaseStartedAt);
9142
+ phaseStartedAt = Date.now();
8940
9143
  scheduledRunManager.bindSession(ctx);
8941
9144
  logSlowPhase("scheduled-runs", phaseStartedAt);
8942
9145
  phaseStartedAt = Date.now();
@@ -8960,6 +9163,7 @@ ${close}` }]
8960
9163
  cleanup(shutdownReason) {
8961
9164
  if (runtimeCleaned) return;
8962
9165
  runtimeCleaned = true;
9166
+ cancelPendingWorkflowAutoResumes((entry) => entry.owner === autoResumeOwner);
8963
9167
  programStatus.dispose(shutdownReason);
8964
9168
  releaseHostSessionLiveness();
8965
9169
  releaseHostSessionLiveness = () => {