@fitchmultz/pi-subagents 0.44.6 → 0.45.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 (947) hide show
  1. package/CHANGELOG.md +265 -7
  2. package/LICENSE +1 -0
  3. package/README.md +58 -1483
  4. package/agents/context-builder.md +19 -1
  5. package/agents/debugger.md +10 -3
  6. package/agents/delegate.md +1 -0
  7. package/agents/fixer.md +4 -1
  8. package/agents/oracle.md +13 -2
  9. package/agents/planner.md +14 -3
  10. package/agents/researcher.md +11 -2
  11. package/agents/reviewer-claude.md +11 -2
  12. package/agents/reviewer-gpt.md +12 -2
  13. package/agents/reviewer-ponytail.md +11 -1
  14. package/agents/reviewer-security.md +13 -2
  15. package/agents/reviewer.md +12 -3
  16. package/agents/scout.md +12 -1
  17. package/agents/ui-designer.md +10 -3
  18. package/agents/watcher.md +1 -0
  19. package/agents/worker.md +8 -2
  20. package/agents/writer.md +6 -3
  21. package/dist/agents/agent-defaults.js +9 -0
  22. package/dist/agents/agent-definition.js +196 -0
  23. package/dist/agents/agent-management.js +64 -905
  24. package/dist/agents/agent-scope.js +4 -2
  25. package/dist/agents/agent-selection.js +10 -5
  26. package/dist/agents/agent-serializer.js +55 -67
  27. package/dist/agents/agents.js +75 -716
  28. package/dist/agents/builtin-overrides.js +218 -0
  29. package/dist/agents/chain-serializer.js +3 -367
  30. package/dist/agents/config-values.js +52 -0
  31. package/dist/agents/discovery-paths.js +91 -0
  32. package/dist/agents/frontmatter.js +15 -5
  33. package/dist/agents/identity.js +25 -8
  34. package/dist/agents/json-chain.js +254 -0
  35. package/dist/agents/management-config.js +332 -0
  36. package/dist/agents/management-format.js +231 -0
  37. package/dist/agents/management-persistence.js +287 -0
  38. package/dist/agents/management-targets.js +136 -0
  39. package/dist/agents/management-warnings.js +81 -0
  40. package/dist/agents/markdown-chain.js +210 -0
  41. package/dist/agents/package-agents.js +154 -0
  42. package/dist/agents/skill-files.js +157 -0
  43. package/dist/agents/skill-search-paths.js +246 -0
  44. package/dist/agents/skill-types.js +1 -0
  45. package/dist/agents/skills.js +54 -499
  46. package/dist/extension/acceptance-schema.js +55 -0
  47. package/dist/extension/build-info.js +1 -1
  48. package/dist/extension/chain-schema.js +196 -0
  49. package/dist/extension/child-runtime.js +237 -0
  50. package/dist/extension/compact-tools.js +122 -51
  51. package/dist/extension/config-schema.js +29 -0
  52. package/dist/extension/config.js +27 -11
  53. package/dist/extension/control-notice-schema.js +37 -0
  54. package/dist/extension/control-notices.js +13 -6
  55. package/dist/extension/delegation-bridges.js +43 -0
  56. package/dist/extension/doctor.js +48 -25
  57. package/dist/extension/everyday-schemas.js +207 -0
  58. package/dist/extension/fanout-child.js +18 -319
  59. package/dist/extension/index.js +8 -563
  60. package/dist/extension/message-renderers.js +225 -0
  61. package/dist/extension/nested-control-inbox.js +154 -0
  62. package/dist/extension/parent-runtime.js +339 -0
  63. package/dist/extension/primary-tool.js +69 -0
  64. package/dist/extension/result-snapshot.js +22 -0
  65. package/dist/extension/runtime-reload.js +62 -0
  66. package/dist/extension/runtime-storage.js +43 -0
  67. package/dist/extension/schema-overrides.js +75 -0
  68. package/dist/extension/schemas.js +265 -336
  69. package/dist/extension/tool-input.js +27 -12
  70. package/dist/extension/tool-result.js +19 -4
  71. package/dist/history/answer-texts.js +57 -0
  72. package/dist/history/canonical-result.js +76 -43
  73. package/dist/history/canonical-selection.js +40 -0
  74. package/dist/history/database-generation.js +82 -0
  75. package/dist/history/database.js +57 -33
  76. package/dist/history/entry-ingestion.js +61 -0
  77. package/dist/history/index.js +242 -97
  78. package/dist/history/ingest.js +168 -331
  79. package/dist/history/output-digests.js +40 -0
  80. package/dist/history/preview.js +210 -0
  81. package/dist/history/prune.js +33 -0
  82. package/dist/history/queries.js +60 -349
  83. package/dist/history/query-scope.js +190 -0
  84. package/dist/history/rows.js +77 -0
  85. package/dist/history/run-projection.js +137 -0
  86. package/dist/history/run-queries.js +153 -0
  87. package/dist/history/schema.js +31 -0
  88. package/dist/history/search-queries.js +163 -0
  89. package/dist/history/selected-record.js +108 -0
  90. package/dist/history/source-file.js +45 -0
  91. package/dist/history/source-watches.js +141 -0
  92. package/dist/history/store.js +164 -153
  93. package/dist/history/text-chunks.js +169 -0
  94. package/dist/history/text.js +35 -0
  95. package/dist/history/transcript-queries.js +177 -0
  96. package/dist/history/types.js +5 -1
  97. package/dist/history/values.js +36 -0
  98. package/dist/history/wire-inputs.js +122 -0
  99. package/dist/history/wire-models.js +38 -0
  100. package/dist/history/worker-runtime.js +441 -0
  101. package/dist/history/worker.js +66 -462
  102. package/dist/intercom/intercom-bridge.js +48 -20
  103. package/dist/intercom/live-intercom.js +80 -23
  104. package/dist/intercom/nested-result-tree.js +163 -0
  105. package/dist/intercom/result-delivery.js +40 -0
  106. package/dist/intercom/result-intercom.js +178 -261
  107. package/dist/pi-intercom/agent-dir.js +7 -3
  108. package/dist/pi-intercom/async.js +27 -0
  109. package/dist/pi-intercom/bridge-ask.js +57 -0
  110. package/dist/pi-intercom/bridge-config.js +79 -0
  111. package/dist/pi-intercom/bridge-http.js +86 -0
  112. package/dist/pi-intercom/bridge-protocol.js +106 -0
  113. package/dist/pi-intercom/bridge-routes.js +64 -0
  114. package/dist/pi-intercom/bridge-session.js +416 -0
  115. package/dist/pi-intercom/bridge.js +182 -603
  116. package/dist/pi-intercom/broker/broker.js +236 -244
  117. package/dist/pi-intercom/broker/client.js +189 -304
  118. package/dist/pi-intercom/broker/connection.js +165 -0
  119. package/dist/pi-intercom/broker/framing.js +5 -3
  120. package/dist/pi-intercom/broker/paths.js +4 -1
  121. package/dist/pi-intercom/broker/pid.js +53 -25
  122. package/dist/pi-intercom/broker/snapshot-reader.js +78 -0
  123. package/dist/pi-intercom/broker/snapshots.js +188 -0
  124. package/dist/pi-intercom/broker/spawn.js +36 -25
  125. package/dist/pi-intercom/config.js +85 -71
  126. package/dist/pi-intercom/connection.js +297 -0
  127. package/dist/pi-intercom/identity.js +58 -0
  128. package/dist/pi-intercom/inbound-delivery.js +356 -0
  129. package/dist/pi-intercom/inbound-journal.js +303 -0
  130. package/dist/pi-intercom/inbound-record.js +113 -0
  131. package/dist/pi-intercom/inbound.js +179 -0
  132. package/dist/pi-intercom/index.js +79 -2933
  133. package/dist/pi-intercom/inspection.js +62 -0
  134. package/dist/pi-intercom/interview.js +236 -0
  135. package/dist/pi-intercom/lifecycle.js +168 -0
  136. package/dist/pi-intercom/message-format.js +69 -0
  137. package/dist/pi-intercom/outbound.js +304 -0
  138. package/dist/pi-intercom/peer-awareness.js +66 -0
  139. package/dist/pi-intercom/reply-tracker.js +62 -43
  140. package/dist/pi-intercom/reply-wait.js +201 -0
  141. package/dist/pi-intercom/runtime-types.js +3 -0
  142. package/dist/pi-intercom/session-events.js +180 -0
  143. package/dist/pi-intercom/session-targets.js +42 -34
  144. package/dist/pi-intercom/subagent-events.js +238 -0
  145. package/dist/pi-intercom/subagent-live-events.js +129 -86
  146. package/dist/pi-intercom/supervisor.js +282 -0
  147. package/dist/pi-intercom/tool-arguments.js +74 -0
  148. package/dist/pi-intercom/tool-registration.js +95 -0
  149. package/dist/pi-intercom/tool-results.js +38 -0
  150. package/dist/pi-intercom/tool-schemas.js +82 -0
  151. package/dist/pi-intercom/tools.js +51 -0
  152. package/dist/pi-intercom/topic-actions.js +177 -0
  153. package/dist/pi-intercom/topics.js +177 -92
  154. package/dist/pi-intercom/transport.js +1 -0
  155. package/dist/pi-intercom/types.js +151 -114
  156. package/dist/pi-intercom/ui/compose-paste.js +93 -0
  157. package/dist/pi-intercom/ui/compose.js +121 -143
  158. package/dist/pi-intercom/ui/inline-message.js +59 -59
  159. package/dist/pi-intercom/ui/message-renderers.js +147 -0
  160. package/dist/pi-intercom/ui/overlay.js +181 -0
  161. package/dist/pi-intercom/ui/session-format.js +124 -0
  162. package/dist/pi-intercom/ui/session-list.js +76 -43
  163. package/dist/pi-intercom/ui/tool-renderers.js +110 -0
  164. package/dist/pi-intercom/ui/topic-view.js +88 -0
  165. package/dist/pi-intercom/validation.js +59 -0
  166. package/dist/runs/background/async-chain-plan.js +265 -0
  167. package/dist/runs/background/async-control.js +134 -58
  168. package/dist/runs/background/async-execution.js +136 -633
  169. package/dist/runs/background/async-job-admission.js +40 -0
  170. package/dist/runs/background/async-job-projection.js +169 -0
  171. package/dist/runs/background/async-job-tracker.js +297 -327
  172. package/dist/runs/background/async-launch.js +216 -0
  173. package/dist/runs/background/async-plan.js +116 -0
  174. package/dist/runs/background/async-result-file.js +47 -23
  175. package/dist/runs/background/async-resume.js +195 -253
  176. package/dist/runs/background/async-run-discovery.js +213 -0
  177. package/dist/runs/background/async-run-location.js +135 -0
  178. package/dist/runs/background/async-run-record.js +1 -0
  179. package/dist/runs/background/async-run-repair.js +223 -0
  180. package/dist/runs/background/async-run-summary.js +1 -0
  181. package/dist/runs/background/async-single-plan.js +105 -0
  182. package/dist/runs/background/async-status-projection.js +155 -0
  183. package/dist/runs/background/async-status-render.js +117 -0
  184. package/dist/runs/background/async-status-validation.js +181 -0
  185. package/dist/runs/background/async-status.js +3 -442
  186. package/dist/runs/background/async-value.js +21 -0
  187. package/dist/runs/background/completion-dedupe.js +36 -12
  188. package/dist/runs/background/completion-delivery.js +211 -205
  189. package/dist/runs/background/completion-receipts.js +237 -0
  190. package/dist/runs/background/legacy-status-acceptance.js +34 -0
  191. package/dist/runs/background/notify.js +96 -48
  192. package/dist/runs/background/parallel-groups.js +36 -19
  193. package/dist/runs/background/result-payload.js +178 -0
  194. package/dist/runs/background/result-watcher.js +348 -339
  195. package/dist/runs/background/run-id-resolver.js +53 -33
  196. package/dist/runs/background/run-schemas.js +189 -0
  197. package/dist/runs/background/run-status-contracts.js +14 -0
  198. package/dist/runs/background/run-status-render.js +270 -0
  199. package/dist/runs/background/run-status.js +231 -339
  200. package/dist/runs/background/runner-attempt-output.js +155 -0
  201. package/dist/runs/background/runner-attempt.js +263 -0
  202. package/dist/runs/background/runner-child-executor.js +166 -0
  203. package/dist/runs/background/runner-child-observer.js +192 -0
  204. package/dist/runs/background/runner-completion-summary.js +71 -0
  205. package/dist/runs/background/runner-completion.js +211 -0
  206. package/dist/runs/background/runner-config.js +1 -0
  207. package/dist/runs/background/runner-contract.js +1 -0
  208. package/dist/runs/background/runner-dynamic.js +121 -0
  209. package/dist/runs/background/runner-finalization.js +149 -0
  210. package/dist/runs/background/runner-graph.js +68 -0
  211. package/dist/runs/background/runner-initial-status.js +60 -0
  212. package/dist/runs/background/runner-lifecycle.js +142 -0
  213. package/dist/runs/background/runner-monitor.js +309 -0
  214. package/dist/runs/background/runner-parallel.js +204 -0
  215. package/dist/runs/background/runner-prepare-step.js +86 -0
  216. package/dist/runs/background/runner-reporting.js +153 -0
  217. package/dist/runs/background/runner-status.js +148 -0
  218. package/dist/runs/background/runner-step-output.js +92 -0
  219. package/dist/runs/background/runner-step-record.js +45 -0
  220. package/dist/runs/background/runner-step.js +112 -0
  221. package/dist/runs/background/runner-streaming.js +173 -0
  222. package/dist/runs/background/runner-workflow.js +213 -0
  223. package/dist/runs/background/stale-run-reconciler.js +155 -292
  224. package/dist/runs/background/subagent-runner-launcher.js +33 -13
  225. package/dist/runs/background/subagent-runner.js +51 -1842
  226. package/dist/runs/background/top-level-async.js +2 -1
  227. package/dist/runs/foreground/chain-clarify.js +293 -1017
  228. package/dist/runs/foreground/clarification-draft.js +87 -0
  229. package/dist/runs/foreground/clarify-contracts.js +1 -0
  230. package/dist/runs/foreground/clarify-invocation.js +129 -38
  231. package/dist/runs/foreground/clarify-text-editor.js +210 -0
  232. package/dist/runs/foreground/clarify-view.js +167 -0
  233. package/dist/runs/foreground/execution-input.js +226 -353
  234. package/dist/runs/foreground/execution-routing.js +33 -0
  235. package/dist/runs/foreground/execution-timeout.js +81 -0
  236. package/dist/runs/foreground/foreground-control.js +222 -763
  237. package/dist/runs/foreground/foreground-memory.js +99 -0
  238. package/dist/runs/foreground/invocation-context.js +55 -0
  239. package/dist/runs/foreground/invocation-execution.js +331 -0
  240. package/dist/runs/foreground/invocation-expansion.js +48 -0
  241. package/dist/runs/foreground/management-actions.js +295 -0
  242. package/dist/runs/foreground/nested-control.js +179 -0
  243. package/dist/runs/foreground/question-continuation.js +78 -0
  244. package/dist/runs/foreground/question-control.js +155 -50
  245. package/dist/runs/foreground/resume-target.js +221 -0
  246. package/dist/runs/foreground/revival-launch-policy.js +58 -0
  247. package/dist/runs/foreground/run-async-path.js +190 -178
  248. package/dist/runs/foreground/run-interrupt.js +164 -0
  249. package/dist/runs/foreground/run-nudge.js +278 -0
  250. package/dist/runs/foreground/saved-revival.js +251 -0
  251. package/dist/runs/foreground/subagent-executor.js +135 -424
  252. package/dist/runs/foreground/subagent-params.js +67 -30
  253. package/dist/runs/foreground/wait-observation.js +104 -0
  254. package/dist/runs/foreground/wait-registration.js +17 -0
  255. package/dist/runs/foreground/wait-run.js +283 -123
  256. package/dist/runs/shared/acceptance-contract.js +193 -99
  257. package/dist/runs/shared/acceptance-defaults.js +1 -0
  258. package/dist/runs/shared/acceptance-evaluation.js +201 -181
  259. package/dist/runs/shared/acceptance-finalization.js +256 -180
  260. package/dist/runs/shared/acceptance-outcome.js +53 -0
  261. package/dist/runs/shared/acceptance-reports.js +137 -72
  262. package/dist/runs/shared/acceptance-submission.js +167 -0
  263. package/dist/runs/shared/acceptance-verification.js +100 -0
  264. package/dist/runs/shared/chain-outputs.js +80 -52
  265. package/dist/runs/shared/child-attempt-types.js +1 -0
  266. package/dist/runs/shared/child-attempt.js +314 -667
  267. package/dist/runs/shared/child-boundaries.js +173 -0
  268. package/dist/runs/shared/child-context-filter.js +44 -0
  269. package/dist/runs/shared/child-event-observer.js +390 -0
  270. package/dist/runs/shared/child-execution-cwd.js +73 -43
  271. package/dist/runs/shared/child-execution-outcome.js +72 -0
  272. package/dist/runs/shared/child-invocation.js +54 -0
  273. package/dist/runs/shared/child-message-validation.js +215 -0
  274. package/dist/runs/shared/child-native-accounting.js +106 -0
  275. package/dist/runs/shared/child-native-observation.js +69 -0
  276. package/dist/runs/shared/child-observation-spool.js +164 -0
  277. package/dist/runs/shared/child-observations.js +157 -76
  278. package/dist/runs/shared/child-presence.js +3 -0
  279. package/dist/runs/shared/child-route-env.js +119 -0
  280. package/dist/runs/shared/child-stream-observer.js +221 -0
  281. package/dist/runs/shared/child-stream-projection.js +137 -0
  282. package/dist/runs/shared/child-structured-tool.js +27 -0
  283. package/dist/runs/shared/claude-code.js +121 -158
  284. package/dist/runs/shared/claude-model.js +42 -0
  285. package/dist/runs/shared/claude-session.js +83 -0
  286. package/dist/runs/shared/claude-types.js +1 -0
  287. package/dist/runs/shared/completion-guard.js +18 -18
  288. package/dist/runs/shared/control-event-policy.js +8 -0
  289. package/dist/runs/shared/control-notification-owner.js +13 -0
  290. package/dist/runs/shared/dynamic-fanout.js +188 -173
  291. package/dist/runs/shared/dynamic-item.js +102 -0
  292. package/dist/runs/shared/history-index.js +62 -36
  293. package/dist/runs/shared/legacy-async-recovery.js +114 -0
  294. package/dist/runs/shared/legacy-output-recovery.js +148 -0
  295. package/dist/runs/shared/mcp-config-schema.js +36 -0
  296. package/dist/runs/shared/mcp-direct-tool-allowlist.js +147 -116
  297. package/dist/runs/shared/model-fallback.js +97 -38
  298. package/dist/runs/shared/mutating-tool-guard.js +128 -88
  299. package/dist/runs/shared/native-finalization-types.js +1 -0
  300. package/dist/runs/shared/native-finalization.js +155 -76
  301. package/dist/runs/shared/native-usage.js +238 -98
  302. package/dist/runs/shared/nested-control-records.js +128 -0
  303. package/dist/runs/shared/nested-events.js +8 -700
  304. package/dist/runs/shared/nested-path.js +32 -28
  305. package/dist/runs/shared/nested-projection.js +155 -0
  306. package/dist/runs/shared/nested-protocol.js +18 -0
  307. package/dist/runs/shared/nested-registry.js +191 -0
  308. package/dist/runs/shared/nested-render.js +106 -58
  309. package/dist/runs/shared/nested-route.js +220 -0
  310. package/dist/runs/shared/nested-validation.js +216 -0
  311. package/dist/runs/shared/owned-child-evidence.js +125 -0
  312. package/dist/runs/shared/owned-run-list.js +146 -0
  313. package/dist/runs/shared/owned-run-observation.js +267 -0
  314. package/dist/runs/shared/owned-run-progress.js +109 -0
  315. package/dist/runs/shared/owned-run-read-state.js +1 -0
  316. package/dist/runs/shared/owned-run-results.js +202 -0
  317. package/dist/runs/shared/owned-run-status.js +180 -0
  318. package/dist/runs/shared/owned-run-view.js +51 -0
  319. package/dist/runs/shared/owned-workflow-details.js +17 -0
  320. package/dist/runs/shared/owner-output.js +43 -0
  321. package/dist/runs/shared/parallel-utils.js +36 -28
  322. package/dist/runs/shared/parent-receipts.js +90 -32
  323. package/dist/runs/shared/parent-usage.js +169 -57
  324. package/dist/runs/shared/pi-args.js +108 -201
  325. package/dist/runs/shared/pi-launch-input.js +1 -0
  326. package/dist/runs/shared/pi-session-launch.js +86 -0
  327. package/dist/runs/shared/pi-spawn.js +35 -21
  328. package/dist/runs/shared/run-history-queries.js +126 -35
  329. package/dist/runs/shared/run-history.js +101 -35
  330. package/dist/runs/shared/run-metadata-paths.js +14 -0
  331. package/dist/runs/shared/run-metadata.js +158 -0
  332. package/dist/runs/shared/run-persistence.js +131 -0
  333. package/dist/runs/shared/run-records.js +9 -679
  334. package/dist/runs/shared/run-restoration.js +338 -0
  335. package/dist/runs/shared/run-state-owner.js +26 -0
  336. package/dist/runs/shared/session-cwd-preload.js +27 -18
  337. package/dist/runs/shared/single-output.js +148 -70
  338. package/dist/runs/shared/stable-value.js +15 -0
  339. package/dist/runs/shared/streaming-text.js +23 -12
  340. package/dist/runs/shared/structured-output.js +25 -13
  341. package/dist/runs/shared/subagent-control.js +167 -100
  342. package/dist/runs/shared/subagent-prompt-runtime.js +27 -130
  343. package/dist/runs/shared/subagent-tool-loop-guard.js +81 -52
  344. package/dist/runs/shared/supervisor-question-state.js +145 -0
  345. package/dist/runs/shared/supervisor-questions.js +185 -254
  346. package/dist/runs/shared/workflow-graph.js +259 -167
  347. package/dist/runs/shared/workflow-policy.js +120 -48
  348. package/dist/runs/shared/worktree-contract.js +1 -0
  349. package/dist/runs/shared/worktree-hook.js +138 -0
  350. package/dist/runs/shared/worktree-location.js +47 -0
  351. package/dist/runs/shared/worktree-preservation.js +8 -0
  352. package/dist/runs/shared/worktree-process.js +107 -0
  353. package/dist/runs/shared/worktree.js +183 -322
  354. package/dist/shared/agent-context-policy.js +34 -44
  355. package/dist/shared/agent-dir.js +14 -0
  356. package/dist/shared/artifacts.js +30 -12
  357. package/dist/shared/atomic-json.js +4 -1
  358. package/dist/shared/chain-files.js +72 -0
  359. package/dist/shared/concurrency.js +18 -0
  360. package/dist/shared/content-preview.js +115 -0
  361. package/dist/shared/cooperative.js +5 -2
  362. package/dist/shared/execution-cwd.js +13 -5
  363. package/dist/shared/file-coalescer.js +2 -1
  364. package/dist/shared/fork-context.js +10 -12
  365. package/dist/shared/formatters.js +45 -19
  366. package/dist/shared/journal-frames.js +164 -0
  367. package/dist/shared/journal-projections.js +121 -0
  368. package/dist/shared/journal-reader.js +6 -407
  369. package/dist/shared/json-projection.js +191 -0
  370. package/dist/shared/lazy-tools.js +19 -8
  371. package/dist/shared/message-output.js +116 -0
  372. package/dist/shared/model-info.js +31 -14
  373. package/dist/shared/native-import.js +20 -0
  374. package/dist/shared/native-journal.js +140 -0
  375. package/dist/shared/native-session.js +5 -2
  376. package/dist/shared/native-tui.js +7 -2
  377. package/dist/shared/native-typebox.js +15 -3
  378. package/dist/shared/output-page.js +63 -0
  379. package/dist/shared/post-exit-stdio-guard.js +128 -88
  380. package/dist/shared/prompt-sections.js +2 -0
  381. package/dist/shared/session-entries.js +70 -35
  382. package/dist/shared/session-identity.js +5 -3
  383. package/dist/shared/settings.js +62 -192
  384. package/dist/shared/status-format.js +97 -37
  385. package/dist/shared/task-file-policy.js +24 -0
  386. package/dist/shared/temp-root.js +44 -15
  387. package/dist/shared/types/acceptance.js +1 -0
  388. package/dist/shared/types/async.js +1 -0
  389. package/dist/shared/types/config.js +1 -0
  390. package/dist/shared/types/details.js +1 -0
  391. package/dist/shared/types/history.js +1 -0
  392. package/dist/shared/types/inputs.js +1 -0
  393. package/dist/shared/types/intercom.js +1 -0
  394. package/dist/shared/types/launch.js +1 -0
  395. package/dist/shared/types/messages.js +1 -0
  396. package/dist/shared/types/nested.js +1 -0
  397. package/dist/shared/types/owned-runs.js +1 -0
  398. package/dist/shared/types/progress.js +1 -0
  399. package/dist/shared/types/questions.js +1 -0
  400. package/dist/shared/types/results.js +1 -0
  401. package/dist/shared/types/state.js +1 -0
  402. package/dist/shared/types/usage.js +1 -0
  403. package/dist/shared/types/workflow.js +1 -0
  404. package/dist/shared/types.js +75 -30
  405. package/dist/shared/unknown.js +52 -0
  406. package/dist/shared/utils.js +54 -260
  407. package/dist/slash/command-discovery.js +82 -0
  408. package/dist/slash/command-input.js +190 -0
  409. package/dist/slash/prompt-template-bridge.js +94 -270
  410. package/dist/slash/prompt-template-contract.js +77 -0
  411. package/dist/slash/prompt-template-results.js +125 -0
  412. package/dist/slash/request-protocol.js +68 -0
  413. package/dist/slash/result-delivery.js +237 -0
  414. package/dist/slash/saved-chain.js +78 -0
  415. package/dist/slash/slash-bridge.js +123 -89
  416. package/dist/slash/slash-commands.js +101 -572
  417. package/dist/slash/slash-live-state.js +68 -47
  418. package/dist/tui/action-hints.js +50 -22
  419. package/dist/tui/activity-lines.js +32 -0
  420. package/dist/tui/agent-browser.js +290 -0
  421. package/dist/tui/agent-controls.js +289 -0
  422. package/dist/tui/agent-conversation.js +444 -0
  423. package/dist/tui/agent-dock.js +171 -0
  424. package/dist/tui/agent-history.js +50 -183
  425. package/dist/tui/agent-model.js +62 -0
  426. package/dist/tui/agent-picker.js +262 -0
  427. package/dist/tui/agent-view.js +232 -1537
  428. package/dist/tui/compact-results.js +193 -0
  429. package/dist/tui/conversation-details.js +190 -0
  430. package/dist/tui/conversation-frame.js +135 -0
  431. package/dist/tui/conversation-history.js +201 -0
  432. package/dist/tui/conversation-menu.js +78 -0
  433. package/dist/tui/conversation-notices.js +79 -0
  434. package/dist/tui/conversation-selection.js +58 -0
  435. package/dist/tui/conversation-viewport.js +129 -0
  436. package/dist/tui/direction-message.js +27 -0
  437. package/dist/tui/display.js +282 -0
  438. package/dist/tui/editor-viewport.js +18 -0
  439. package/dist/tui/expanded-content.js +87 -0
  440. package/dist/tui/expanded-multi.js +170 -0
  441. package/dist/tui/expanded-single.js +65 -0
  442. package/dist/tui/history-cards.js +216 -0
  443. package/dist/tui/history-display.js +238 -0
  444. package/dist/tui/history-json.js +16 -0
  445. package/dist/tui/history-metadata.js +152 -0
  446. package/dist/tui/history-record.js +251 -0
  447. package/dist/tui/history-text.js +34 -0
  448. package/dist/tui/indexed-history.js +116 -0
  449. package/dist/tui/nested-widget.js +120 -0
  450. package/dist/tui/picker-page.js +59 -0
  451. package/dist/tui/render.js +58 -1501
  452. package/dist/tui/result-facts.js +64 -0
  453. package/dist/tui/task-observation.js +59 -0
  454. package/dist/tui/task-store.js +366 -0
  455. package/dist/tui/text-values.js +16 -0
  456. package/dist/tui/view-connections.js +47 -0
  457. package/dist/tui/view-model.js +94 -0
  458. package/dist/tui/view-persistence.js +51 -0
  459. package/dist/tui/view-ports.js +1 -0
  460. package/dist/tui/view-session.js +37 -0
  461. package/dist/tui/widget-details.js +144 -0
  462. package/dist/tui/widget-status.js +245 -0
  463. package/dist/tui/widget.js +145 -0
  464. package/dist/tui/workflow-labels.js +223 -0
  465. package/dist/tui/workflow-outcomes.js +124 -0
  466. package/docs/code-quality.md +38 -0
  467. package/docs/development.md +99 -0
  468. package/docs/intercom-bridge.md +23 -18
  469. package/docs/intercom.md +132 -106
  470. package/docs/performance.md +19 -17
  471. package/docs/reference.md +1472 -0
  472. package/generated/RunValidators.d.ts +28 -0
  473. package/generated/RunValidators.js +2 -0
  474. package/package.json +27 -6
  475. package/prompts/parallel-cleanup.md +3 -0
  476. package/prompts/parallel-context-build.md +3 -0
  477. package/prompts/parallel-handoff-plan.md +6 -0
  478. package/prompts/parallel-research.md +4 -0
  479. package/prompts/parallel-review.md +2 -0
  480. package/prompts/review-loop.md +2 -0
  481. package/scripts/build.mjs +129 -85
  482. package/scripts/check-compat.mjs +48 -11
  483. package/scripts/compat-host.mjs +35 -7
  484. package/scripts/generate-run-schemas.mjs +210 -0
  485. package/scripts/intercom-bridge-credentials.mjs +155 -28
  486. package/scripts/intercom-remote.mjs +175 -50
  487. package/scripts/local-install-smoke.mjs +47 -37
  488. package/scripts/native-package-smoke.mjs +135 -25
  489. package/scripts/package-smoke.mjs +360 -140
  490. package/scripts/prepare.mjs +54 -34
  491. package/scripts/real-pi-processes.mjs +261 -0
  492. package/scripts/real-pi-smoke.mjs +432 -351
  493. package/scripts/run-tests.mjs +29 -15
  494. package/skills/pi-intercom/SKILL.md +11 -11
  495. package/skills/pi-intercom/references/peer-sessions.md +7 -2
  496. package/skills/pi-subagents/SKILL.md +1 -1
  497. package/skills/pi-subagents/references/full-orchestration-guide.md +254 -112
  498. package/src/agents/agent-defaults.ts +13 -0
  499. package/src/agents/agent-definition.ts +253 -0
  500. package/src/agents/agent-management.ts +111 -808
  501. package/src/agents/agent-scope.ts +7 -3
  502. package/src/agents/agent-selection.ts +26 -16
  503. package/src/agents/agent-serializer.ts +84 -93
  504. package/src/agents/agents.ts +199 -906
  505. package/src/agents/builtin-overrides.ts +297 -0
  506. package/src/agents/chain-serializer.ts +3 -329
  507. package/src/agents/config-values.ts +57 -0
  508. package/src/agents/discovery-paths.ts +134 -0
  509. package/src/agents/frontmatter.ts +35 -17
  510. package/src/agents/identity.ts +49 -18
  511. package/src/agents/json-chain.ts +305 -0
  512. package/src/agents/management-config.ts +342 -0
  513. package/src/agents/management-format.ts +243 -0
  514. package/src/agents/management-persistence.ts +408 -0
  515. package/src/agents/management-targets.ts +260 -0
  516. package/src/agents/management-warnings.ts +115 -0
  517. package/src/agents/markdown-chain.ts +237 -0
  518. package/src/agents/package-agents.ts +231 -0
  519. package/src/agents/skill-files.ts +182 -0
  520. package/src/agents/skill-search-paths.ts +289 -0
  521. package/src/agents/skill-types.ts +31 -0
  522. package/src/agents/skills.ts +152 -610
  523. package/src/extension/acceptance-schema.ts +88 -0
  524. package/src/extension/chain-schema.ts +276 -0
  525. package/src/extension/child-runtime.ts +302 -0
  526. package/src/extension/compact-tools.ts +259 -102
  527. package/src/extension/config-schema.ts +59 -0
  528. package/src/extension/config.ts +39 -17
  529. package/src/extension/control-notice-schema.ts +55 -0
  530. package/src/extension/control-notices.ts +57 -33
  531. package/src/extension/delegation-bridges.ts +59 -0
  532. package/src/extension/doctor.ts +171 -135
  533. package/src/extension/everyday-schemas.ts +252 -0
  534. package/src/extension/fanout-child.ts +29 -308
  535. package/src/extension/index.ts +17 -642
  536. package/src/extension/message-renderers.ts +334 -0
  537. package/src/extension/nested-control-inbox.ts +196 -0
  538. package/src/extension/parent-runtime.ts +405 -0
  539. package/src/extension/primary-tool.ts +130 -0
  540. package/src/extension/result-snapshot.ts +35 -0
  541. package/src/extension/runtime-reload.ts +72 -0
  542. package/src/extension/runtime-storage.ts +49 -0
  543. package/src/extension/schema-overrides.ts +114 -0
  544. package/src/extension/schemas.ts +451 -418
  545. package/src/extension/tool-input.ts +40 -13
  546. package/src/extension/tool-result.ts +45 -14
  547. package/src/history/answer-texts.ts +74 -0
  548. package/src/history/canonical-result.ts +127 -51
  549. package/src/history/canonical-selection.ts +54 -0
  550. package/src/history/database-generation.ts +86 -0
  551. package/src/history/database.ts +86 -48
  552. package/src/history/entry-ingestion.ts +129 -0
  553. package/src/history/index.ts +426 -148
  554. package/src/history/ingest.ts +372 -342
  555. package/src/history/output-digests.ts +41 -0
  556. package/src/history/preview.ts +235 -0
  557. package/src/history/prune.ts +48 -0
  558. package/src/history/queries.ts +122 -256
  559. package/src/history/query-scope.ts +278 -0
  560. package/src/history/rows.ts +118 -0
  561. package/src/history/run-projection.ts +164 -0
  562. package/src/history/run-queries.ts +199 -0
  563. package/src/history/schema.ts +34 -0
  564. package/src/history/search-queries.ts +216 -0
  565. package/src/history/selected-record.ts +140 -0
  566. package/src/history/source-file.ts +51 -0
  567. package/src/history/source-watches.ts +156 -0
  568. package/src/history/store.ts +310 -197
  569. package/src/history/text-chunks.ts +181 -0
  570. package/src/history/text.ts +43 -0
  571. package/src/history/transcript-queries.ts +251 -0
  572. package/src/history/types.ts +27 -164
  573. package/src/history/values.ts +36 -0
  574. package/src/history/wire-inputs.ts +141 -0
  575. package/src/history/wire-models.ts +51 -0
  576. package/src/history/worker-runtime.ts +502 -0
  577. package/src/history/worker.ts +94 -336
  578. package/src/intercom/intercom-bridge.ts +136 -69
  579. package/src/intercom/live-intercom.ts +197 -92
  580. package/src/intercom/nested-result-tree.ts +213 -0
  581. package/src/intercom/result-delivery.ts +56 -0
  582. package/src/intercom/result-intercom.ts +364 -382
  583. package/src/pi-intercom/agent-dir.ts +9 -3
  584. package/src/pi-intercom/async.ts +33 -0
  585. package/src/pi-intercom/bridge-ask.ts +64 -0
  586. package/src/pi-intercom/bridge-config.ts +101 -0
  587. package/src/pi-intercom/bridge-http.ts +97 -0
  588. package/src/pi-intercom/bridge-protocol.ts +123 -0
  589. package/src/pi-intercom/bridge-routes.ts +90 -0
  590. package/src/pi-intercom/bridge-session.ts +506 -0
  591. package/src/pi-intercom/bridge.ts +258 -547
  592. package/src/pi-intercom/broker/broker.ts +326 -263
  593. package/src/pi-intercom/broker/client.ts +273 -354
  594. package/src/pi-intercom/broker/connection.ts +192 -0
  595. package/src/pi-intercom/broker/framing.ts +11 -6
  596. package/src/pi-intercom/broker/paths.ts +28 -25
  597. package/src/pi-intercom/broker/pid.ts +68 -24
  598. package/src/pi-intercom/broker/snapshot-reader.ts +91 -0
  599. package/src/pi-intercom/broker/snapshots.ts +241 -0
  600. package/src/pi-intercom/broker/spawn.ts +58 -34
  601. package/src/pi-intercom/config.ts +113 -108
  602. package/src/pi-intercom/connection.ts +346 -0
  603. package/src/pi-intercom/identity.ts +71 -0
  604. package/src/pi-intercom/inbound-delivery.ts +450 -0
  605. package/src/pi-intercom/inbound-journal.ts +350 -0
  606. package/src/pi-intercom/inbound-record.ts +141 -0
  607. package/src/pi-intercom/inbound.ts +237 -0
  608. package/src/pi-intercom/index.ts +86 -2923
  609. package/src/pi-intercom/inspection.ts +82 -0
  610. package/src/pi-intercom/interview.ts +295 -0
  611. package/src/pi-intercom/lifecycle.ts +183 -0
  612. package/src/pi-intercom/message-format.ts +77 -0
  613. package/src/pi-intercom/outbound.ts +418 -0
  614. package/src/pi-intercom/peer-awareness.ts +84 -0
  615. package/src/pi-intercom/reply-tracker.ts +121 -59
  616. package/src/pi-intercom/reply-wait.ts +247 -0
  617. package/src/pi-intercom/runtime-types.ts +97 -0
  618. package/src/pi-intercom/session-events.ts +247 -0
  619. package/src/pi-intercom/session-targets.ts +124 -72
  620. package/src/pi-intercom/subagent-events.ts +299 -0
  621. package/src/pi-intercom/subagent-live-events.ts +212 -109
  622. package/src/pi-intercom/supervisor.ts +362 -0
  623. package/src/pi-intercom/tool-arguments.ts +120 -0
  624. package/src/pi-intercom/tool-registration.ts +121 -0
  625. package/src/pi-intercom/tool-results.ts +54 -0
  626. package/src/pi-intercom/tool-schemas.ts +134 -0
  627. package/src/pi-intercom/tools.ts +80 -0
  628. package/src/pi-intercom/topic-actions.ts +243 -0
  629. package/src/pi-intercom/topics.ts +267 -121
  630. package/src/pi-intercom/transport.ts +14 -0
  631. package/src/pi-intercom/types.ts +288 -190
  632. package/src/pi-intercom/ui/compose-paste.ts +109 -0
  633. package/src/pi-intercom/ui/compose.ts +173 -157
  634. package/src/pi-intercom/ui/inline-message.ts +80 -62
  635. package/src/pi-intercom/ui/message-renderers.ts +182 -0
  636. package/src/pi-intercom/ui/overlay.ts +238 -0
  637. package/src/pi-intercom/ui/session-format.ts +146 -0
  638. package/src/pi-intercom/ui/session-list.ts +145 -62
  639. package/src/pi-intercom/ui/tool-renderers.ts +148 -0
  640. package/src/pi-intercom/ui/topic-view.ts +107 -0
  641. package/src/pi-intercom/validation.ts +69 -0
  642. package/src/runs/background/async-chain-plan.ts +451 -0
  643. package/src/runs/background/async-control.ts +201 -71
  644. package/src/runs/background/async-execution.ts +206 -829
  645. package/src/runs/background/async-job-admission.ts +54 -0
  646. package/src/runs/background/async-job-projection.ts +225 -0
  647. package/src/runs/background/async-job-tracker.ts +416 -360
  648. package/src/runs/background/async-launch.ts +319 -0
  649. package/src/runs/background/async-plan.ts +285 -0
  650. package/src/runs/background/async-result-file.ts +79 -37
  651. package/src/runs/background/async-resume.ts +338 -285
  652. package/src/runs/background/async-run-discovery.ts +270 -0
  653. package/src/runs/background/async-run-location.ts +194 -0
  654. package/src/runs/background/async-run-record.ts +14 -0
  655. package/src/runs/background/async-run-repair.ts +307 -0
  656. package/src/runs/background/async-run-summary.ts +71 -0
  657. package/src/runs/background/async-single-plan.ts +168 -0
  658. package/src/runs/background/async-status-projection.ts +188 -0
  659. package/src/runs/background/async-status-render.ts +164 -0
  660. package/src/runs/background/async-status-validation.ts +238 -0
  661. package/src/runs/background/async-status.ts +9 -481
  662. package/src/runs/background/async-value.ts +29 -0
  663. package/src/runs/background/completion-dedupe.ts +103 -54
  664. package/src/runs/background/completion-delivery.ts +313 -187
  665. package/src/runs/background/completion-receipts.ts +309 -0
  666. package/src/runs/background/legacy-status-acceptance.ts +38 -0
  667. package/src/runs/background/notify.ts +167 -106
  668. package/src/runs/background/parallel-groups.ts +95 -46
  669. package/src/runs/background/result-payload.ts +268 -0
  670. package/src/runs/background/result-watcher.ts +484 -387
  671. package/src/runs/background/run-id-resolver.ts +126 -57
  672. package/src/runs/background/run-schemas.ts +240 -0
  673. package/src/runs/background/run-status-contracts.ts +46 -0
  674. package/src/runs/background/run-status-render.ts +364 -0
  675. package/src/runs/background/run-status.ts +338 -356
  676. package/src/runs/background/runner-attempt-output.ts +281 -0
  677. package/src/runs/background/runner-attempt.ts +354 -0
  678. package/src/runs/background/runner-child-executor.ts +232 -0
  679. package/src/runs/background/runner-child-observer.ts +270 -0
  680. package/src/runs/background/runner-completion-summary.ts +106 -0
  681. package/src/runs/background/runner-completion.ts +274 -0
  682. package/src/runs/background/runner-config.ts +52 -0
  683. package/src/runs/background/runner-contract.ts +51 -0
  684. package/src/runs/background/runner-dynamic.ts +185 -0
  685. package/src/runs/background/runner-finalization.ts +203 -0
  686. package/src/runs/background/runner-graph.ts +91 -0
  687. package/src/runs/background/runner-initial-status.ts +72 -0
  688. package/src/runs/background/runner-lifecycle.ts +159 -0
  689. package/src/runs/background/runner-monitor.ts +399 -0
  690. package/src/runs/background/runner-parallel.ts +280 -0
  691. package/src/runs/background/runner-prepare-step.ts +128 -0
  692. package/src/runs/background/runner-reporting.ts +192 -0
  693. package/src/runs/background/runner-status.ts +220 -0
  694. package/src/runs/background/runner-step-output.ts +158 -0
  695. package/src/runs/background/runner-step-record.ts +76 -0
  696. package/src/runs/background/runner-step.ts +150 -0
  697. package/src/runs/background/runner-streaming.ts +220 -0
  698. package/src/runs/background/runner-workflow.ts +284 -0
  699. package/src/runs/background/stale-run-reconciler.ts +279 -336
  700. package/src/runs/background/subagent-runner-launcher.ts +67 -35
  701. package/src/runs/background/subagent-runner.ts +80 -2048
  702. package/src/runs/background/top-level-async.ts +9 -7
  703. package/src/runs/foreground/chain-clarify.ts +499 -1334
  704. package/src/runs/foreground/clarification-draft.ts +92 -0
  705. package/src/runs/foreground/clarify-contracts.ts +33 -0
  706. package/src/runs/foreground/clarify-invocation.ts +192 -65
  707. package/src/runs/foreground/clarify-text-editor.ts +229 -0
  708. package/src/runs/foreground/clarify-view.ts +222 -0
  709. package/src/runs/foreground/execution-input.ts +358 -424
  710. package/src/runs/foreground/execution-routing.ts +41 -0
  711. package/src/runs/foreground/execution-timeout.ts +92 -0
  712. package/src/runs/foreground/foreground-control.ts +333 -812
  713. package/src/runs/foreground/foreground-memory.ts +132 -0
  714. package/src/runs/foreground/invocation-context.ts +88 -0
  715. package/src/runs/foreground/invocation-execution.ts +465 -0
  716. package/src/runs/foreground/invocation-expansion.ts +58 -0
  717. package/src/runs/foreground/management-actions.ts +360 -0
  718. package/src/runs/foreground/nested-control.ts +248 -0
  719. package/src/runs/foreground/question-continuation.ts +112 -0
  720. package/src/runs/foreground/question-control.ts +297 -70
  721. package/src/runs/foreground/resume-target.ts +330 -0
  722. package/src/runs/foreground/revival-launch-policy.ts +112 -0
  723. package/src/runs/foreground/run-async-path.ts +307 -223
  724. package/src/runs/foreground/run-interrupt.ts +202 -0
  725. package/src/runs/foreground/run-nudge.ts +355 -0
  726. package/src/runs/foreground/saved-revival.ts +356 -0
  727. package/src/runs/foreground/subagent-executor.ts +195 -493
  728. package/src/runs/foreground/subagent-params.ts +314 -242
  729. package/src/runs/foreground/wait-observation.ts +160 -0
  730. package/src/runs/foreground/wait-registration.ts +18 -0
  731. package/src/runs/foreground/wait-run.ts +361 -119
  732. package/src/runs/shared/acceptance-contract.ts +410 -209
  733. package/src/runs/shared/acceptance-defaults.ts +1 -0
  734. package/src/runs/shared/acceptance-evaluation.ts +314 -240
  735. package/src/runs/shared/acceptance-finalization.ts +447 -305
  736. package/src/runs/shared/acceptance-outcome.ts +69 -0
  737. package/src/runs/shared/acceptance-reports.ts +220 -126
  738. package/src/runs/shared/acceptance-submission.ts +251 -0
  739. package/src/runs/shared/acceptance-verification.ts +118 -0
  740. package/src/runs/shared/acceptance.ts +25 -25
  741. package/src/runs/shared/chain-outputs.ts +190 -98
  742. package/src/runs/shared/child-attempt-types.ts +118 -0
  743. package/src/runs/shared/child-attempt.ts +372 -608
  744. package/src/runs/shared/child-boundaries.ts +217 -0
  745. package/src/runs/shared/child-context-filter.ts +53 -0
  746. package/src/runs/shared/child-event-observer.ts +496 -0
  747. package/src/runs/shared/child-execution-cwd.ts +139 -68
  748. package/src/runs/shared/child-execution-outcome.ts +103 -0
  749. package/src/runs/shared/child-invocation.ts +74 -0
  750. package/src/runs/shared/child-message-validation.ts +233 -0
  751. package/src/runs/shared/child-native-accounting.ts +154 -0
  752. package/src/runs/shared/child-native-observation.ts +79 -0
  753. package/src/runs/shared/child-observation-spool.ts +188 -0
  754. package/src/runs/shared/child-observations.ts +219 -89
  755. package/src/runs/shared/child-presence.ts +6 -0
  756. package/src/runs/shared/child-route-env.ts +142 -0
  757. package/src/runs/shared/child-stream-observer.ts +302 -0
  758. package/src/runs/shared/child-stream-projection.ts +160 -0
  759. package/src/runs/shared/child-structured-tool.ts +38 -0
  760. package/src/runs/shared/claude-code.ts +201 -228
  761. package/src/runs/shared/claude-model.ts +67 -0
  762. package/src/runs/shared/claude-session.ts +124 -0
  763. package/src/runs/shared/claude-types.ts +31 -0
  764. package/src/runs/shared/completion-guard.ts +35 -26
  765. package/src/runs/shared/control-event-policy.ts +15 -0
  766. package/src/runs/shared/control-notification-owner.ts +20 -0
  767. package/src/runs/shared/dynamic-fanout.ts +402 -238
  768. package/src/runs/shared/dynamic-item.ts +114 -0
  769. package/src/runs/shared/history-index.ts +112 -51
  770. package/src/runs/shared/legacy-async-recovery.ts +153 -0
  771. package/src/runs/shared/legacy-output-recovery.ts +214 -0
  772. package/src/runs/shared/mcp-config-schema.ts +46 -0
  773. package/src/runs/shared/mcp-direct-tool-allowlist.ts +396 -307
  774. package/src/runs/shared/model-fallback.ts +302 -180
  775. package/src/runs/shared/mutating-tool-guard.ts +259 -158
  776. package/src/runs/shared/native-finalization-types.ts +29 -0
  777. package/src/runs/shared/native-finalization.ts +233 -109
  778. package/src/runs/shared/native-usage.ts +379 -96
  779. package/src/runs/shared/nested-control-records.ts +178 -0
  780. package/src/runs/shared/nested-events.ts +45 -752
  781. package/src/runs/shared/nested-path.ts +47 -34
  782. package/src/runs/shared/nested-projection.ts +230 -0
  783. package/src/runs/shared/nested-protocol.ts +67 -0
  784. package/src/runs/shared/nested-registry.ts +273 -0
  785. package/src/runs/shared/nested-render.ts +198 -100
  786. package/src/runs/shared/nested-route.ts +292 -0
  787. package/src/runs/shared/nested-validation.ts +291 -0
  788. package/src/runs/shared/owned-child-evidence.ts +184 -0
  789. package/src/runs/shared/owned-run-list.ts +187 -0
  790. package/src/runs/shared/owned-run-observation.ts +368 -0
  791. package/src/runs/shared/owned-run-progress.ts +172 -0
  792. package/src/runs/shared/owned-run-read-state.ts +7 -0
  793. package/src/runs/shared/owned-run-results.ts +289 -0
  794. package/src/runs/shared/owned-run-status.ts +239 -0
  795. package/src/runs/shared/owned-run-view.ts +65 -0
  796. package/src/runs/shared/owned-workflow-details.ts +24 -0
  797. package/src/runs/shared/owner-output.ts +73 -0
  798. package/src/runs/shared/parallel-utils.ts +93 -129
  799. package/src/runs/shared/parent-receipts.ts +177 -50
  800. package/src/runs/shared/parent-usage.ts +314 -91
  801. package/src/runs/shared/pi-args.ts +241 -311
  802. package/src/runs/shared/pi-launch-input.ts +48 -0
  803. package/src/runs/shared/pi-session-launch.ts +94 -0
  804. package/src/runs/shared/pi-spawn.ts +57 -33
  805. package/src/runs/shared/run-history-queries.ts +189 -38
  806. package/src/runs/shared/run-history.ts +197 -76
  807. package/src/runs/shared/run-id-ambiguity.ts +7 -3
  808. package/src/runs/shared/run-metadata-paths.ts +17 -0
  809. package/src/runs/shared/run-metadata.ts +240 -0
  810. package/src/runs/shared/run-persistence.ts +181 -0
  811. package/src/runs/shared/run-records.ts +19 -607
  812. package/src/runs/shared/run-restoration.ts +455 -0
  813. package/src/runs/shared/run-state-owner.ts +31 -0
  814. package/src/runs/shared/session-cwd-preload.ts +39 -19
  815. package/src/runs/shared/single-output.ts +358 -205
  816. package/src/runs/shared/stable-value.ts +15 -0
  817. package/src/runs/shared/streaming-text.ts +39 -12
  818. package/src/runs/shared/structured-output.ts +76 -46
  819. package/src/runs/shared/subagent-control.ts +330 -197
  820. package/src/runs/shared/subagent-prompt-runtime.ts +92 -174
  821. package/src/runs/shared/subagent-tool-loop-guard.ts +118 -68
  822. package/src/runs/shared/supervisor-question-state.ts +221 -0
  823. package/src/runs/shared/supervisor-questions.ts +396 -401
  824. package/src/runs/shared/workflow-graph.ts +400 -198
  825. package/src/runs/shared/workflow-policy.ts +245 -110
  826. package/src/runs/shared/worktree-contract.ts +29 -0
  827. package/src/runs/shared/worktree-hook.ts +181 -0
  828. package/src/runs/shared/worktree-location.ts +61 -0
  829. package/src/runs/shared/worktree-preservation.ts +10 -0
  830. package/src/runs/shared/worktree-process.ts +132 -0
  831. package/src/runs/shared/worktree.ts +459 -587
  832. package/src/shared/agent-context-policy.ts +176 -145
  833. package/src/shared/agent-dir.ts +15 -0
  834. package/src/shared/artifacts.ts +99 -68
  835. package/src/shared/atomic-json.ts +14 -11
  836. package/src/shared/chain-files.ts +72 -0
  837. package/src/shared/concurrency.ts +27 -0
  838. package/src/shared/content-preview.ts +117 -0
  839. package/src/shared/cooperative.ts +17 -13
  840. package/src/shared/execution-cwd.ts +34 -9
  841. package/src/shared/file-coalescer.ts +24 -22
  842. package/src/shared/fork-context.ts +52 -48
  843. package/src/shared/formatters.ts +88 -47
  844. package/src/shared/journal-frames.ts +197 -0
  845. package/src/shared/journal-projections.ts +133 -0
  846. package/src/shared/journal-reader.ts +18 -333
  847. package/src/shared/json-projection.ts +224 -0
  848. package/src/shared/lazy-tools.ts +76 -27
  849. package/src/shared/message-output.ts +146 -0
  850. package/src/shared/model-info.ts +94 -58
  851. package/src/shared/native-import.ts +25 -0
  852. package/src/shared/native-journal.ts +172 -0
  853. package/src/shared/native-session.ts +8 -3
  854. package/src/shared/native-tui.ts +13 -3
  855. package/src/shared/native-typebox.ts +18 -3
  856. package/src/shared/output-page.ts +76 -0
  857. package/src/shared/post-exit-stdio-guard.ts +232 -172
  858. package/src/shared/prompt-sections.ts +13 -7
  859. package/src/shared/session-entries.ts +103 -44
  860. package/src/shared/session-identity.ts +17 -10
  861. package/src/shared/settings.ts +182 -367
  862. package/src/shared/status-format.ts +207 -98
  863. package/src/shared/stream-json.d.ts +10 -0
  864. package/src/shared/task-file-policy.ts +35 -0
  865. package/src/shared/temp-root.ts +122 -71
  866. package/src/shared/types/acceptance.ts +149 -0
  867. package/src/shared/types/async.ts +247 -0
  868. package/src/shared/types/config.ts +139 -0
  869. package/src/shared/types/details.ts +104 -0
  870. package/src/shared/types/history.ts +217 -0
  871. package/src/shared/types/inputs.ts +4 -0
  872. package/src/shared/types/intercom.ts +57 -0
  873. package/src/shared/types/launch.ts +39 -0
  874. package/src/shared/types/messages.ts +104 -0
  875. package/src/shared/types/nested.ts +153 -0
  876. package/src/shared/types/owned-runs.ts +148 -0
  877. package/src/shared/types/progress.ts +106 -0
  878. package/src/shared/types/questions.ts +103 -0
  879. package/src/shared/types/results.ts +119 -0
  880. package/src/shared/types/state.ts +56 -0
  881. package/src/shared/types/usage.ts +36 -0
  882. package/src/shared/types/workflow.ts +187 -0
  883. package/src/shared/types.ts +222 -1161
  884. package/src/shared/ui-mode.ts +1 -1
  885. package/src/shared/unknown.ts +59 -0
  886. package/src/shared/utils.ts +111 -305
  887. package/src/slash/command-discovery.ts +109 -0
  888. package/src/slash/command-input.ts +232 -0
  889. package/src/slash/prompt-template-bridge.ts +153 -400
  890. package/src/slash/prompt-template-contract.ts +152 -0
  891. package/src/slash/prompt-template-results.ts +189 -0
  892. package/src/slash/request-protocol.ts +87 -0
  893. package/src/slash/result-delivery.ts +312 -0
  894. package/src/slash/saved-chain.ts +115 -0
  895. package/src/slash/slash-bridge.ts +202 -156
  896. package/src/slash/slash-commands.ts +176 -598
  897. package/src/slash/slash-live-state.ts +287 -229
  898. package/src/tui/action-hints.ts +147 -61
  899. package/src/tui/activity-lines.ts +40 -0
  900. package/src/tui/agent-browser.ts +354 -0
  901. package/src/tui/agent-controls.ts +355 -0
  902. package/src/tui/agent-conversation.ts +514 -0
  903. package/src/tui/agent-dock.ts +250 -0
  904. package/src/tui/agent-history.ts +78 -203
  905. package/src/tui/agent-model.ts +78 -0
  906. package/src/tui/agent-picker.ts +325 -0
  907. package/src/tui/agent-view.ts +391 -1310
  908. package/src/tui/compact-results.ts +342 -0
  909. package/src/tui/conversation-details.ts +206 -0
  910. package/src/tui/conversation-frame.ts +184 -0
  911. package/src/tui/conversation-history.ts +246 -0
  912. package/src/tui/conversation-menu.ts +119 -0
  913. package/src/tui/conversation-notices.ts +116 -0
  914. package/src/tui/conversation-selection.ts +66 -0
  915. package/src/tui/conversation-viewport.ts +169 -0
  916. package/src/tui/direction-message.ts +35 -0
  917. package/src/tui/display.ts +409 -0
  918. package/src/tui/editor-viewport.ts +19 -0
  919. package/src/tui/expanded-content.ts +134 -0
  920. package/src/tui/expanded-multi.ts +264 -0
  921. package/src/tui/expanded-single.ts +92 -0
  922. package/src/tui/history-cards.ts +316 -0
  923. package/src/tui/history-display.ts +334 -0
  924. package/src/tui/history-json.ts +17 -0
  925. package/src/tui/history-metadata.ts +177 -0
  926. package/src/tui/history-record.ts +321 -0
  927. package/src/tui/history-text.ts +34 -0
  928. package/src/tui/indexed-history.ts +149 -0
  929. package/src/tui/nested-widget.ts +192 -0
  930. package/src/tui/picker-page.ts +80 -0
  931. package/src/tui/render.ts +100 -1546
  932. package/src/tui/result-facts.ts +99 -0
  933. package/src/tui/task-observation.ts +96 -0
  934. package/src/tui/task-store.ts +432 -0
  935. package/src/tui/text-values.ts +20 -0
  936. package/src/tui/view-connections.ts +64 -0
  937. package/src/tui/view-model.ts +181 -0
  938. package/src/tui/view-persistence.ts +57 -0
  939. package/src/tui/view-ports.ts +55 -0
  940. package/src/tui/view-session.ts +42 -0
  941. package/src/tui/widget-details.ts +220 -0
  942. package/src/tui/widget-status.ts +331 -0
  943. package/src/tui/widget.ts +208 -0
  944. package/src/tui/workflow-labels.ts +340 -0
  945. package/src/tui/workflow-outcomes.ts +150 -0
  946. package/tsconfig.build.json +11 -10
  947. package/tsconfig.json +30 -17
@@ -1,817 +1,276 @@
1
- import { randomUUID } from "node:crypto";
2
- import { formatRunIdAmbiguity } from "../shared/run-id-ambiguity.js";
3
- import { resolveRootSessionId } from "../../shared/session-identity.js";
4
- import { writeAsyncControlRequest, writeAsyncInterruptRequest } from "../background/async-control.js";
5
- import { getRunMetadataDir, listSupervisorQuestions, questionProcessAlive, readQuestionContract, readRunJson, recordQuestionDelivery, saveQuestionOwner } from "../shared/supervisor-questions.js";
6
- import * as fs from "node:fs";
7
1
  import * as path from "node:path";
8
- import {} from "../../agents/agents.js";
9
- import { providerQualifiedModelId, toModelInfo } from "../../shared/model-info.js";
10
- import { normalizeSkillInput } from "../../agents/skills.js";
11
- import { resolveExecutionAgentScope } from "../../agents/agent-scope.js";
12
- import { executeAsyncSingle, formatAsyncStartedMessage } from "../background/async-execution.js";
13
- import { resolveConfiguredChildProjectTrustPolicy } from "../shared/pi-args.js";
14
- import { requestChildExecutionCwd } from "../shared/child-execution-cwd.js";
15
- import { resolveCurrentSessionId } from "../../shared/session-identity.js";
16
- import { resolveIntercomBridge, resolveIntercomSessionTarget, resolveOrchestratorIntercomTarget, resolveSubagentIntercomTarget } from "../../intercom/intercom-bridge.js";
17
- import { resolveControlConfig } from "../shared/subagent-control.js";
18
- import { readStatus } from "../../shared/utils.js";
2
+ import { errorMessage } from "../../shared/unknown.js";
3
+ import { listSupervisorQuestions, readQuestionContract } from "../shared/supervisor-questions.js";
19
4
  import { deliverSubagentIntercomMessageEvent } from "../../intercom/result-intercom.js";
20
- import { sendLiveSubagentMessage } from "../../intercom/live-intercom.js";
21
- import { buildRevivedAsyncTask, resolveAsyncResumeTarget } from "../background/async-resume.js";
22
- import { readNestedControlResults, resolveInheritedNestedRouteFromEnv, resolveNestedAsyncDir, resolveNestedParentAddressFromEnv, writeNestedControlRequest } from "../shared/nested-events.js";
23
- import { inspectSubagentStatus } from "../background/run-status.js";
24
5
  import { resolveSubagentRunId } from "../background/run-id-resolver.js";
25
6
  import { buildManagementControl, formatRunAction } from "../../shared/status-format.js";
26
- import { acceptanceInputFromResolved } from "../shared/acceptance.js";
27
- import { ownedRunStatusResult, ownedRunView, rememberOwnedRun, resolveOwnedRun } from "../shared/run-records.js";
28
- import { ASYNC_DIR, getAsyncConfigPath, RUNNER_ERROR_LOG_FILE, checkSubagentDepth, resolveCurrentMaxSubagentDepth, } from "../../shared/types.js";
29
- import {} from "./subagent-params.js";
7
+ import { ownedRunView, resolveOwnedRun } from "../shared/run-records.js";
8
+ import { nestedResolutionScopeForExecutor } from "./execution-routing.js";
9
+ import { resolveResumeTarget, resolveNestedResumeTarget, } from "./resume-target.js";
10
+ import { LIVE_ACCEPTANCE_OVERRIDE_NOTICE, resumeLiveNestedRun } from "./nested-control.js";
11
+ import { nudgeSubagentRun } from "./run-nudge.js";
12
+ import { reviveSavedSubagent } from "./saved-revival.js";
13
+ import { continueQuestionSession } from "./question-continuation.js";
30
14
  export { writeAsyncInterruptRequest } from "../background/async-control.js";
31
- export const MUTATING_MANAGEMENT_ACTIONS = new Set(["create", "update", "delete"]);
32
- export function resolveRequestedCwd(runtimeCwd, requestedCwd) {
33
- return requestedCwd ? path.resolve(runtimeCwd, requestedCwd) : runtimeCwd;
34
- }
35
- export function nestedResolutionScopeForExecutor(deps) {
36
- if (deps.allowMutatingManagementActions !== false)
37
- return undefined;
38
- const route = resolveInheritedNestedRouteFromEnv();
39
- const address = route ? resolveNestedParentAddressFromEnv() : undefined;
40
- return {
41
- routes: route ? [route] : [],
42
- ...(address ? { descendantOf: { parentRunId: address.parentRunId, ...(address.parentStepIndex !== undefined ? { parentStepIndex: address.parentStepIndex } : {}) } } : {}),
43
- };
44
- }
45
- const LATEST_FOREGROUND_ALIASES = new Set(["last", "latest"]);
46
- export function resolveRememberedForegroundRun(requested, state) {
47
- if (!requested || !state.foregroundRuns?.size)
48
- return undefined;
49
- const normalized = requested.trim();
50
- if (!normalized)
51
- return undefined;
52
- if (LATEST_FOREGROUND_ALIASES.has(normalized)) {
53
- return [...state.foregroundRuns.values()].sort((left, right) => right.updatedAt - left.updatedAt)[0];
54
- }
55
- const direct = state.foregroundRuns.get(normalized);
56
- const matches = direct ? [direct] : [...state.foregroundRuns.values()].filter((run) => run.runId.startsWith(normalized));
57
- if (matches.length === 0)
58
- return undefined;
59
- if (matches.length > 1)
60
- throw new Error(formatRunIdAmbiguity("foreground", normalized, matches.map((run) => run.runId)));
61
- return matches[0];
62
- }
63
- function foregroundResumeGuidance(run, childSafe) {
64
- const childWithSession = run.children.find((child) => child.sessionFile && child.status !== "detached");
65
- if (!childWithSession && run.children.some((child) => child.status === "detached"))
66
- return `Completion unconfirmed. Check ${formatRunAction("questions", run.runId, {}, childSafe)} before continuing.`;
67
- if (run.children.length === 1 && childWithSession)
68
- return `Continue: ${formatRunAction("resume", run.runId, { message: "..." }, childSafe)}`;
69
- if (!childWithSession)
70
- return "Revive: unavailable; no child session file was persisted.";
71
- return `Continue child: ${formatRunAction("resume", run.runId, { index: childWithSession.index, message: "..." }, childSafe)}`;
72
- }
73
- function compactStatusText(value, maxLength = 240) {
74
- const normalized = value.replace(/\s+/g, " ").trim();
75
- return normalized.length > maxLength ? `${normalized.slice(0, maxLength - 1)}…` : normalized;
76
- }
77
- function foregroundResultChildren(run) {
78
- return run.children.map((child) => ({ child, finalOutput: child.summary }));
79
- }
80
- function rememberedForegroundState(children) {
81
- if (children.some(({ child }) => child.status === "failed" || child.status === "timed-out"))
82
- return "failed";
83
- if (children.some(({ child }) => child.status === "blocked"))
84
- return "blocked";
85
- if (children.some(({ child }) => child.status === "paused"))
86
- return "paused";
87
- return children.some(({ child }) => child.status === "detached") ? "unknown" : "completed";
88
- }
89
- export function rememberedForegroundStatusResult(run, childSafe = false) {
90
- const children = foregroundResultChildren(run);
91
- const childState = rememberedForegroundState(children);
92
- const state = run.error ? "failed" : childState === "completed" && run.pausedReason ? "paused" : childState;
93
- const resumable = children.find(({ child }) => child.sessionFile && child.status !== "detached")?.child;
94
- const lines = [
95
- `Run: ${run.runId}`,
96
- "State: remembered foreground",
97
- `Outcome: ${state}`,
98
- ...(run.error ? [`Error: ${run.error}`] : state === "paused" && run.pausedReason ? [run.pausedReason] : []),
99
- `Mode: ${run.mode}`,
100
- `Updated: ${new Date(run.updatedAt).toISOString()}`,
101
- `Launch cwd: ${run.cwd}`,
102
- "Children:",
103
- ...children.map(({ child, finalOutput }) => ` ${child.index + 1}. ${child.agent} ${child.status}${child.sessionFile ? `, session: ${child.sessionFile}` : ""}${child.artifactPath ? `, artifact: ${child.artifactPath}` : ""}${finalOutput ? `, final: ${compactStatusText(finalOutput)}` : ""}`),
104
- foregroundResumeGuidance(run, childSafe),
105
- `Status: ${formatRunAction("status", run.runId, {}, childSafe)}`,
106
- ];
15
+ export { MUTATING_MANAGEMENT_ACTIONS, resolveRequestedCwd, nestedResolutionScopeForExecutor, } from "./execution-routing.js";
16
+ export { rememberedForegroundStatusResult, resolveRememberedForegroundRun, } from "./foreground-memory.js";
17
+ export { extendAsyncTimeoutResult, interruptAsyncRun } from "./run-interrupt.js";
18
+ export { interruptNestedRun } from "./nested-control.js";
19
+ export { nudgeSubagentRun } from "./run-nudge.js";
20
+ export { reviveSavedSubagent } from "./saved-revival.js";
21
+ function failure(text) {
107
22
  return {
108
- content: [{ type: "text", text: lines.join("\n") }],
109
- details: {
110
- mode: "management", results: [],
111
- managementControl: buildManagementControl({ state, runId: run.runId, index: resumable?.index, canResume: Boolean(resumable) }),
112
- },
23
+ content: [{ type: "text", text }],
24
+ isError: true,
25
+ details: { mode: "management", results: [] },
113
26
  };
114
27
  }
115
- function resolveForegroundResumeTarget(params, state) {
116
- const requested = (params.id ?? params.runId)?.trim();
117
- const run = resolveRememberedForegroundRun(requested, state);
118
- if (!run)
119
- return undefined;
120
- if (run.children.length > 1 && params.index === undefined)
121
- throw new Error(`Foreground run '${run.runId}' has ${run.children.length} children. Provide index to choose one.`);
122
- const index = params.index ?? 0;
123
- if (!Number.isInteger(index))
124
- throw new Error(`Foreground run '${run.runId}' index must be an integer.`);
125
- if (index < 0 || index >= run.children.length)
126
- throw new Error(`Foreground run '${run.runId}' has ${run.children.length} children. Index ${index} is out of range.`);
127
- const child = run.children[index];
128
- if (child.status === "detached")
129
- throw new Error(`Foreground run '${run.runId}' child ${index} is detached for intercom coordination and cannot be revived safely from the remembered foreground state. Reply to the supervisor request first; after the child exits, start a fresh follow-up if needed.`);
130
- if (!child.sessionFile)
131
- throw new Error(`Foreground run '${run.runId}' child ${index} does not have a persisted session file to resume from.`);
132
- if (path.extname(child.sessionFile) !== ".jsonl")
133
- throw new Error(`Foreground run '${run.runId}' child ${index} session file must be a .jsonl file: ${child.sessionFile}`);
134
- const sessionFile = path.resolve(child.sessionFile);
135
- if (!fs.existsSync(sessionFile))
136
- throw new Error(`Foreground run '${run.runId}' child ${index} session file does not exist: ${child.sessionFile}`);
137
- return { runId: run.runId, mode: run.mode, state: "complete", agent: child.agent, index, intercomTarget: resolveSubagentIntercomTarget(run.runId, child.agent, index), cwd: run.cwd, sessionFile, effectiveAcceptance: child.effectiveAcceptance };
138
- }
139
- function isAsyncRunNotFound(error) {
140
- return error instanceof Error && error.message.startsWith("Async run not found.");
141
- }
142
- function isResumeAmbiguity(error) {
143
- return error instanceof Error && /Ambiguous .*run id prefix/.test(error.message);
28
+ function requestedOwnedId(params) {
29
+ const id = params.id ?? params.runId;
30
+ return id !== undefined && id.length > 0 && (params.dir === undefined || params.dir.length === 0)
31
+ ? id
32
+ : undefined;
144
33
  }
145
- function resumeTargetExact(target, requested) {
146
- return target?.runId === requested;
34
+ export function liveLaunchOverrideNotice(params) {
35
+ if (params.acceptance !== undefined) {
36
+ return LIVE_ACCEPTANCE_OVERRIDE_NOTICE;
37
+ }
38
+ return [
39
+ params.agent,
40
+ params.model,
41
+ params.cwd,
42
+ params.output,
43
+ params.outputMode,
44
+ params.outputSchema,
45
+ params.skill,
46
+ params.maxOutput,
47
+ params.control,
48
+ params.artifacts,
49
+ params.share,
50
+ ].some((value) => value !== undefined)
51
+ ? "Launch overrides change a newly started continuation, not this live child. No launch settings were changed."
52
+ : undefined;
147
53
  }
148
- function escapeRegExp(value) {
149
- return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
54
+ function withLiveNotice(result, params) {
55
+ const notice = liveLaunchOverrideNotice(params);
56
+ if (notice !== undefined) {
57
+ result.content.push({ type: "text", text: notice });
58
+ }
59
+ return result;
150
60
  }
151
- function isExactResumeError(error, source, requested) {
152
- if (!(error instanceof Error) || !requested)
153
- return false;
154
- return new RegExp(`\\b${source} run '${escapeRegExp(requested)}'`, "i").test(error.message);
61
+ function normalizedFollowUp(params) {
62
+ return (params.message ?? params.task ?? "").trim();
155
63
  }
156
- function resolveResumeTarget(params, state) {
157
- const requested = (params.id ?? params.runId)?.trim() ?? "";
158
- let foregroundTarget;
159
- let foregroundError;
160
- let asyncTarget;
161
- let asyncError;
162
- try {
163
- const target = resolveForegroundResumeTarget(params, state);
164
- if (target)
165
- foregroundTarget = { kind: "revive", source: "foreground", ...target };
166
- }
167
- catch (error) {
168
- foregroundError = error;
169
- }
170
- try {
171
- asyncTarget = { source: "async", ...resolveAsyncResumeTarget(params) };
172
- }
173
- catch (error) {
174
- asyncError = error;
175
- }
176
- if (foregroundTarget && asyncTarget) {
177
- const foregroundExact = resumeTargetExact(foregroundTarget, requested);
178
- const asyncExact = resumeTargetExact(asyncTarget, requested);
179
- if (foregroundExact && !asyncExact)
180
- return foregroundTarget;
181
- if (asyncExact && !foregroundExact)
182
- return asyncTarget;
183
- throw new Error(`Resume id '${requested}' is ambiguous between foreground run '${foregroundTarget.runId}' and async run '${asyncTarget.runId}'. Provide a full run id.`);
184
- }
185
- if (foregroundTarget) {
186
- if (isExactResumeError(asyncError, "async", requested))
187
- throw asyncError;
188
- if (isResumeAmbiguity(asyncError) && !resumeTargetExact(foregroundTarget, requested))
189
- throw asyncError;
190
- return foregroundTarget;
191
- }
192
- if (asyncTarget) {
193
- if (isExactResumeError(foregroundError, "foreground", requested))
194
- throw foregroundError;
195
- if (isResumeAmbiguity(foregroundError) && !resumeTargetExact(asyncTarget, requested))
196
- throw foregroundError;
197
- return asyncTarget;
198
- }
199
- if (foregroundError && !isAsyncRunNotFound(asyncError))
200
- throw foregroundError;
201
- if (foregroundError)
202
- throw foregroundError;
203
- if (asyncError)
204
- throw asyncError;
205
- throw new Error("Run not found. Provide id or runId.");
64
+ function usesSession(candidate, deps, sessionFile) {
65
+ return (candidate.children.some((child) => child.sessionFile === sessionFile) ||
66
+ deps.state.asyncJobs.get(candidate.runId)?.sessionFile === sessionFile);
206
67
  }
207
- function getAsyncInterruptTarget(state, runId) {
208
- if (runId) {
209
- const direct = state.asyncJobs.get(runId);
210
- if (direct)
211
- return { asyncId: direct.asyncId, asyncDir: direct.asyncDir };
212
- const owned = resolveOwnedRun(state, runId);
213
- return owned?.asyncDir ? { asyncId: owned.runId, asyncDir: owned.asyncDir } : undefined;
68
+ function nudgeContinuation(input, runId, sessionFile) {
69
+ if (sessionFile === undefined || sessionFile.length === 0) {
70
+ return;
214
71
  }
215
- let newest;
216
- for (const job of state.asyncJobs.values()) {
217
- if (job.status !== "running")
72
+ for (const candidate of input.deps.state.ownedRuns?.values() ?? []) {
73
+ if (candidate.runId === runId) {
218
74
  continue;
219
- if (!newest || (job.updatedAt ?? 0) > newest.updatedAt) {
220
- newest = { asyncId: job.asyncId, asyncDir: job.asyncDir, updatedAt: job.updatedAt ?? 0 };
221
75
  }
222
- }
223
- for (const run of state.ownedRuns?.values() ?? []) {
224
- if (!run.asyncDir || (newest && run.startedAt <= newest.updatedAt))
76
+ if (!usesSession(candidate, input.deps, sessionFile)) {
225
77
  continue;
226
- const status = readStatus(run.asyncDir);
227
- if (status ? status.state !== "running" && status.state !== "queued" : !run.pid || !questionProcessAlive({ pid: run.pid }))
78
+ }
79
+ const active = ownedRunView(candidate, input.deps.state, {
80
+ readConfiguration: false,
81
+ }).children.find((child) => child.sessionFile === sessionFile && child.state === "live");
82
+ if (!active) {
228
83
  continue;
229
- newest = { asyncId: run.runId, asyncDir: run.asyncDir, updatedAt: run.startedAt };
230
- }
231
- return newest ? { asyncId: newest.asyncId, asyncDir: newest.asyncDir } : undefined;
232
- }
233
- export function extendAsyncTimeoutResult(state, runId, extendMs) {
234
- const target = getAsyncInterruptTarget(state, runId);
235
- const status = target && readStatus(target.asyncDir);
236
- const launch = target && readRunJson(path.join(target.asyncDir, "launch.json"));
237
- const extendable = status ? status.runtimeVersion === 2 && status.state === "running" && !status.timedOut && status.timeoutAt
238
- : launch?.runtimeVersion === 2 && launch.timeoutMs;
239
- if (!target || !extendable)
240
- return {
241
- content: [{ type: "text", text: "No live run with an extendable timeout was found. No extension was requested." }], isError: true, details: { mode: "management", results: [] },
242
- };
243
- try {
244
- writeAsyncControlRequest(target.asyncDir, target.asyncId, "extend", undefined, extendMs);
245
- return { content: [{ type: "text", text: `Requested ${extendMs}ms more for run ${target.asyncId}. Inspect status for the owner's updated deadline.` }],
246
- details: { mode: "management", results: [], managementControl: buildManagementControl({ state: "live", runId: target.asyncId, canInterrupt: true, canExtend: true }) } };
247
- }
248
- catch (error) {
249
- return { content: [{ type: "text", text: error instanceof Error ? error.message : String(error) }], isError: true, details: { mode: "management", results: [] } };
250
- }
251
- }
252
- export function interruptAsyncRun(state, runId, index) {
253
- const target = getAsyncInterruptTarget(state, runId);
254
- if (!target)
255
- return null;
256
- const status = readStatus(target.asyncDir);
257
- if (!status || status.runId !== target.asyncId || status.state !== "running") {
258
- return {
259
- content: [{ type: "text", text: `No running async run with a matching control channel was found for '${runId ?? "current"}'.` }],
260
- isError: true,
261
- details: { mode: "management", results: [] },
262
- };
263
- }
264
- if (index !== undefined && !status.indexedControl && (status.steps?.length ?? 0) > 1)
265
- return {
266
- content: [{ type: "text", text: "This older runner does not support selected-child stop. No stop was sent; whole-run stop remains an explicit separate action." }], isError: true, details: { mode: "management", results: [] },
267
- };
268
- if (index !== undefined && (!Number.isSafeInteger(index) || index < 0 || status.steps?.[index]?.status !== "running")) {
269
- return { content: [{ type: "text", text: `Async run ${target.asyncId} has no running child at index ${index}. No siblings were stopped.` }], isError: true, details: { mode: "management", results: [] } };
270
- }
271
- try {
272
- writeAsyncInterruptRequest(target.asyncDir, target.asyncId, index);
273
- const tracked = state.asyncJobs.get(target.asyncId);
274
- if (tracked) {
275
- tracked.activityState = undefined;
276
- tracked.updatedAt = Date.now();
277
84
  }
278
- return {
279
- content: [{ type: "text", text: `Interrupt requested for async run ${target.asyncId}${index !== undefined ? ` child ${index} only` : ""}. Agent and command exit are not yet confirmed.` }],
280
- details: { mode: "management", results: [], managementControl: buildManagementControl({ state: "live", runId: target.asyncId }) },
281
- };
282
- }
283
- catch (error) {
284
- const message = error instanceof Error ? error.message : String(error);
285
- return {
286
- content: [{ type: "text", text: `Failed to interrupt async run ${target.asyncId}: ${message}` }],
287
- isError: true,
288
- details: { mode: "management", results: [] },
289
- };
290
- }
291
- }
292
- function nestedRunSessionFile(run) {
293
- return run.sessionFile ?? (run.steps?.length === 1 ? run.steps[0]?.sessionFile : undefined);
294
- }
295
- function nestedRunAgent(run) {
296
- return run.agent ?? run.agents?.[0] ?? (run.steps?.length === 1 ? run.steps[0]?.agent : undefined);
297
- }
298
- function pathWithin(base, candidate) {
299
- const resolvedBase = path.resolve(base);
300
- const resolvedCandidate = path.resolve(candidate);
301
- return resolvedCandidate === resolvedBase || resolvedCandidate.startsWith(`${resolvedBase}${path.sep}`);
302
- }
303
- function validateNestedSessionFile(run, trustedSessionRoots) {
304
- const sessionFile = nestedRunSessionFile(run);
305
- if (!sessionFile)
306
- throw new Error(`Nested run '${run.id}' does not have a persisted session file to resume from.`);
307
- if (path.extname(sessionFile) !== ".jsonl")
308
- throw new Error(`Nested run '${run.id}' session file must be a .jsonl file: ${sessionFile}`);
309
- const resolved = path.resolve(sessionFile);
310
- if (!path.isAbsolute(sessionFile))
311
- throw new Error(`Nested run '${run.id}' session file must be absolute: ${sessionFile}`);
312
- if (!fs.existsSync(resolved))
313
- throw new Error(`Nested run '${run.id}' session file does not exist: ${sessionFile}`);
314
- const stat = fs.lstatSync(resolved);
315
- if (!stat.isFile() || stat.isSymbolicLink())
316
- throw new Error(`Nested run '${run.id}' session file is not a regular file: ${sessionFile}`);
317
- const realSessionFile = fs.realpathSync(resolved);
318
- const trustedRoots = trustedSessionRoots
319
- .filter((root) => fs.existsSync(root))
320
- .map((root) => fs.realpathSync(root));
321
- if (!trustedRoots.some((root) => pathWithin(root, realSessionFile))) {
322
- throw new Error(`Nested run '${run.id}' session file is outside trusted nested session roots: ${sessionFile}`);
85
+ return nudgeSubagentRun({
86
+ params: {
87
+ ...input.params,
88
+ dir: undefined,
89
+ id: candidate.runId,
90
+ index: active.index,
91
+ message: normalizedFollowUp(input.params),
92
+ },
93
+ deps: input.deps,
94
+ ctx: input.ctx,
95
+ }).then((result) => withLiveNotice(result, input.params));
96
+ }
97
+ return;
98
+ }
99
+ async function resumeOwned(
100
+ // Owned continuation may persist a new run; deps retains the actual session mutation owner.
101
+ input, owned) {
102
+ const view = ownedRunView(owned, input.deps.state);
103
+ if (view.children.length > 1 && input.params.index === undefined) {
104
+ throw new Error(`Run '${owned.runId}' has ${view.children.length} children. Provide index to choose one.`);
105
+ }
106
+ const child = view.children.find((entry) => entry.index === (input.params.index ?? 0));
107
+ if (!child) {
108
+ throw new Error(`Run '${owned.runId}' has no child at index ${input.params.index ?? 0}.`);
109
+ }
110
+ if (child.state === "live") {
111
+ return withLiveNotice(await nudgeSubagentRun({
112
+ params: {
113
+ ...input.params,
114
+ id: owned.runId,
115
+ message: normalizedFollowUp(input.params),
116
+ },
117
+ deps: input.deps,
118
+ ctx: input.ctx,
119
+ }), input.params);
323
120
  }
324
- if (!realSessionFile.split(path.sep).includes(run.id)) {
325
- throw new Error(`Nested run '${run.id}' session file is not under that nested run's session directory: ${sessionFile}`);
121
+ const liveContinuation = nudgeContinuation(input, owned.runId, child.sessionFile);
122
+ if (liveContinuation) {
123
+ return await liveContinuation;
326
124
  }
327
- return realSessionFile;
125
+ return reviveSavedSubagent(input, ownedRevivalTarget(owned, child));
328
126
  }
329
- function resolveNestedResumeTarget(match, trustedSessionRoots) {
330
- const run = match.match.run;
331
- if (run.state === "running" || run.state === "queued")
332
- throw new Error(`Nested run '${run.id}' is live; route the follow-up to the owner process instead.`);
333
- const agent = nestedRunAgent(run);
334
- if (!agent)
335
- throw new Error(`Could not determine child agent for nested run '${run.id}'.`);
336
- const state = run.state === "complete" || run.state === "failed" || run.state === "blocked" || run.state === "paused" ? run.state : "failed";
337
- const asyncDir = resolveNestedAsyncDir(match.match.rootRunId, run);
338
- const effectiveAcceptance = asyncDir ? readStatus(asyncDir)?.steps?.[0]?.acceptance?.effectiveAcceptance : undefined;
127
+ function ownedRevivalTarget(owned, child) {
128
+ const contract = readQuestionContract(owned.runId, child.index);
339
129
  return {
340
- kind: "revive",
341
- source: "nested",
342
- runId: run.id,
343
- state,
344
- agent,
345
- index: 0,
346
- intercomTarget: resolveSubagentIntercomTarget(run.id, agent, 0),
347
- cwd: asyncDir ? path.dirname(asyncDir) : undefined,
348
- sessionFile: validateNestedSessionFile(run, trustedSessionRoots),
349
- effectiveAcceptance,
130
+ ...contract,
131
+ runId: owned.runId,
132
+ agent: child.agent,
133
+ index: child.index,
134
+ source: owned.source,
135
+ cwd: child.launch?.cwd ?? owned.cwd,
136
+ sessionFile: child.sessionFile,
137
+ effectiveAcceptance: contract?.effectiveAcceptance ?? child.result?.acceptance?.effectiveAcceptance,
138
+ model: child.result?.model,
350
139
  };
351
140
  }
352
- async function waitForNestedControlResult(target, requestId, timeoutMs = 1_000) {
353
- const deadline = Date.now() + timeoutMs;
354
- while (Date.now() < deadline) {
355
- const result = readNestedControlResults(target.match.route).find((candidate) => candidate.requestId === requestId && candidate.targetRunId === target.match.run.id);
356
- if (result)
357
- return result;
358
- await new Promise((resolve) => setTimeout(resolve, 50));
141
+ function trustedSessionRoots(input, parentSessionFile) {
142
+ const roots = [];
143
+ const configured = input.deps.config.defaultSessionDir;
144
+ if (configured !== undefined && configured.length > 0) {
145
+ roots.push(path.resolve(input.deps.expandTilde(configured)));
146
+ }
147
+ if (parentSessionFile !== null && parentSessionFile.length > 0) {
148
+ roots.push(input.deps.getSubagentSessionRoot(parentSessionFile));
359
149
  }
360
- return undefined;
150
+ return roots;
361
151
  }
362
- async function sendNestedControlRequest(target, action, message, index) {
363
- const requestId = randomUUID();
364
- const targetChildIndex = target.match.run.path?.[0]?.stepIndex ?? target.match.run.parentStepIndex;
365
- writeNestedControlRequest(target.match.route, {
366
- ts: Date.now(),
367
- requestId,
368
- targetRunId: target.match.run.id,
369
- ...(targetChildIndex !== undefined ? { targetChildIndex } : {}),
370
- action,
371
- ...(index !== undefined ? { index } : {}),
372
- ...(message ? { message } : {}),
152
+ function resolveRequestedRun(params, deps) {
153
+ const id = params.id ?? params.runId;
154
+ if (id === undefined || id.length === 0) {
155
+ return;
156
+ }
157
+ return resolveSubagentRunId(id, {
158
+ state: deps.state,
159
+ nested: nestedResolutionScopeForExecutor(deps),
373
160
  });
374
- return waitForNestedControlResult(target, requestId);
375
161
  }
376
- function directNestedAsyncInterrupt(target, index) {
377
- const run = target.match.run;
378
- const asyncDir = resolveNestedAsyncDir(target.match.rootRunId, run);
379
- if (!asyncDir)
380
- return undefined;
381
- const status = readStatus(asyncDir);
382
- if (!status || status.runId !== run.id || status.state !== "running")
383
- return undefined;
384
- if (index !== undefined && !status.indexedControl && (status.steps?.length ?? 0) > 1)
385
- return undefined;
386
- if (index !== undefined && status.steps?.[index]?.status !== "running")
387
- return { content: [{ type: "text", text: `No running nested child at index ${index}. No siblings were stopped.` }], isError: true, details: { mode: "management", results: [] } };
388
- try {
389
- writeAsyncInterruptRequest(asyncDir, run.id, index);
390
- return { content: [{ type: "text", text: `Interrupt requested for nested async run ${run.id}.` }], details: { mode: "management", results: [], managementControl: buildManagementControl({ state: "live", runId: run.id, intercomTarget: run.intercomTarget ?? run.leafIntercomTarget, canInterrupt: true }) } };
162
+ async function resolveContinuation(
163
+ // Resolution includes question/owned revival, whose durable updates belong to this session owner.
164
+ input, parentSessionFile) {
165
+ const requested = requestedOwnedId(input.params);
166
+ const questions = requested !== undefined
167
+ ? listSupervisorQuestions(input.ctx.sessionManager.getSessionId(), requested).filter((question) => question.state === "awaiting_input" || question.state === "answer_pending")
168
+ : [];
169
+ if (questions.length > 0) {
170
+ return { kind: "result", result: continueQuestionSession(input, questions) };
171
+ }
172
+ const owned = requested !== undefined ? resolveOwnedRun(input.deps.state, requested) : undefined;
173
+ if (owned) {
174
+ return { kind: "result", result: await resumeOwned(input, owned) };
391
175
  }
392
- catch (error) {
393
- const message = error instanceof Error ? error.message : String(error);
394
- return { content: [{ type: "text", text: `Failed to interrupt nested async run ${run.id}: ${message}` }], isError: true, details: { mode: "management", results: [] } };
176
+ const resolved = resolveRequestedRun(input.params, input.deps);
177
+ if (resolved?.kind !== "nested") {
178
+ return { kind: "target", target: resolveResumeTarget(input.params, input.deps.state) };
395
179
  }
396
- }
397
- export async function interruptNestedRun(target, index) {
398
- const run = target.match.run;
399
- if (run.state === "complete")
400
- return { content: [{ type: "text", text: `Nested run ${run.id} is already complete and cannot be interrupted.` }], isError: true, details: { mode: "management", results: [] } };
401
- if (run.state === "failed")
402
- return { content: [{ type: "text", text: `Nested run ${run.id} has failed and cannot be interrupted.` }], isError: true, details: { mode: "management", results: [] } };
403
- if (run.state === "paused")
404
- return { content: [{ type: "text", text: `Nested run ${run.id} is already paused.` }], isError: true, details: { mode: "management", results: [] } };
405
- if (index !== undefined && run.indexedControl !== true)
406
- return directNestedAsyncInterrupt(target, index) ?? {
407
- content: [{ type: "text", text: "This nested owner does not advertise selected-child stop. No stop was sent; inspect the child or explicitly stop the whole run." }], isError: true, details: { mode: "management", results: [] },
408
- };
409
- const result = await sendNestedControlRequest(target, "interrupt", undefined, index);
410
- if (result?.ok)
180
+ if (resolved.match.run.state === "running" || resolved.match.run.state === "queued") {
411
181
  return {
412
- content: [{ type: "text", text: result.message }],
413
- details: {
414
- mode: "management", results: [],
415
- managementControl: buildManagementControl({ state: "live", runId: run.id, intercomTarget: run.intercomTarget ?? run.leafIntercomTarget, canResume: true, canInterrupt: true }),
416
- },
182
+ kind: "result",
183
+ result: await resumeLiveNestedRun({
184
+ target: resolved,
185
+ message: normalizedFollowUp(input.params),
186
+ index: input.params.index,
187
+ acceptanceOverrideSupplied: input.params.acceptance !== undefined,
188
+ pi: input.deps.pi,
189
+ childSafe: nestedResolutionScopeForExecutor(input.deps) !== undefined,
190
+ }),
417
191
  };
418
- const direct = directNestedAsyncInterrupt(target, index);
419
- if (direct)
420
- return direct;
421
- if (result)
422
- return { content: [{ type: "text", text: result.message }], isError: true, details: { mode: "management", results: [] } };
423
- return { content: [{ type: "text", text: `Nested run ${run.id} owner is not reachable and no safe direct async interrupt fallback is available.` }], isError: true, details: { mode: "management", results: [] } };
424
- }
425
- const LIVE_ACCEPTANCE_OVERRIDE_NOTICE = "Acceptance override applies only to revive and was not applied to this live delivery.";
426
- export function liveLaunchOverrideNotice(params) {
427
- if (params.acceptance !== undefined)
428
- return LIVE_ACCEPTANCE_OVERRIDE_NOTICE;
429
- return [params.agent, params.model, params.cwd, params.output, params.outputMode, params.outputSchema, params.skill, params.maxOutput, params.control, params.artifacts, params.share].some((value) => value !== undefined)
430
- ? "Launch overrides change a newly started continuation, not this live child. No launch settings were changed."
431
- : undefined;
432
- }
433
- async function resumeLiveNestedRun(input) {
434
- const run = input.target.match.run;
435
- const result = await sendNestedControlRequest(input.target, "resume", input.message, input.index);
436
- if (result?.ok) {
437
- return { content: [{ type: "text", text: [result.message, input.acceptanceOverrideSupplied ? LIVE_ACCEPTANCE_OVERRIDE_NOTICE : undefined].filter(Boolean).join("\n") }], details: { mode: "management", results: [] } };
438
192
  }
439
- const asyncDir = input.index !== undefined ? resolveNestedAsyncDir(input.target.match.rootRunId, run) : undefined;
440
- const selected = asyncDir ? readStatus(asyncDir)?.steps?.[input.index] : undefined;
441
- const directTarget = input.index === undefined ? run.leafIntercomTarget ?? run.intercomTarget
442
- : selected?.status === "running" ? resolveSubagentIntercomTarget(run.id, selected.agent, input.index) : undefined;
443
- if (directTarget) {
444
- const delivered = await deliverSubagentIntercomMessageEvent(input.pi.events, directTarget, `Follow-up for nested run ${run.id}:\n\n${input.message}`, 500, { source: "nested-resume-fallback", runId: run.id, agent: run.agent, index: input.index ?? run.currentStep });
445
- if (delivered) {
446
- return { content: [{ type: "text", text: [`Delivered follow-up directly to live nested run ${run.id}.`, input.acceptanceOverrideSupplied ? LIVE_ACCEPTANCE_OVERRIDE_NOTICE : undefined].filter(Boolean).join("\n") }], details: { mode: "management", results: [] } };
447
- }
448
- }
449
- if (result)
450
- return { content: [{ type: "text", text: result.message }], isError: true, details: { mode: "management", results: [] } };
451
- return { content: [{ type: "text", text: `Nested run ${run.id} appears live but its owner route is not reachable. Wait for completion, then retry ${formatRunAction("resume", run.id, { message: "..." }, input.childSafe)}.` }], isError: true, details: { mode: "management", results: [] } };
452
- }
453
- function terminalNudgeResult(runId, deps) {
454
- const owned = resolveOwnedRun(deps.state, runId);
455
- if (owned) {
456
- const result = ownedRunStatusResult(owned, deps.state, undefined, { childSafe: Boolean(nestedResolutionScopeForExecutor(deps)) });
457
- const state = result.details.run.state;
458
- if (state === "live")
459
- return undefined;
460
- return { ...result, content: [{ type: "text", text: `Nudge not sent: ${state === "unknown" ? "completion is unconfirmed" : `run is already ${state}`}. No child was restarted.\n\n${result.content.map((part) => part.type === "text" ? part.text : "").join("\n")}` }] };
461
- }
462
- const remembered = deps.state.foregroundRuns?.get(runId);
463
- const status = remembered
464
- ? rememberedForegroundStatusResult(remembered, Boolean(nestedResolutionScopeForExecutor(deps)))
465
- : inspectSubagentStatus({ id: runId }, { state: deps.state, nested: nestedResolutionScopeForExecutor(deps) });
466
- const state = status.details.managementControl?.state;
467
- if (status.isError || !state || state === "live" || state === "unknown")
468
- return undefined;
469
193
  return {
470
- ...status,
471
- content: [{ type: "text", text: `Nudge not sent: run is already ${state}. No child was restarted.\n\n${status.content.filter((part) => part.type === "text").map((part) => part.text).join("\n")}` }],
194
+ kind: "target",
195
+ target: resolveNestedResumeTarget(resolved, trustedSessionRoots(input, parentSessionFile)),
472
196
  };
473
197
  }
474
- export async function nudgeSubagentRun(input) {
475
- const message = input.params.message?.trim() || "What are you blocked on? Reply with the smallest next step, or state the exact decision you need.";
476
- const requestedId = input.params.id ?? input.params.runId;
477
- let runId;
478
- let agent;
479
- let index;
480
- let target;
481
- let resolvedRunId;
482
- try {
483
- const owned = input.params.dir ? undefined : resolveOwnedRun(input.deps.state, requestedId ?? getAsyncInterruptTarget(input.deps.state, undefined)?.asyncId ?? "latest");
484
- if (owned) {
485
- resolvedRunId = owned.runId;
486
- const terminal = terminalNudgeResult(owned.runId, input.deps);
487
- if (terminal)
488
- return terminal;
489
- const view = ownedRunView(owned, input.deps.state);
490
- const children = view.children.filter((child) => child.state === "live" && (input.params.index === undefined || input.params.index === child.index));
491
- if (children.length !== 1)
492
- throw new Error(`Run '${owned.runId}' has ${children.length} matching live children. Provide index to choose one.`);
493
- const child = children[0];
494
- if (child.activity?.status === "pending")
495
- throw new Error(`Child ${child.index} is waiting to start in run ${owned.runId}. No message was sent and no continuation was started.`);
496
- runId = owned.runId;
497
- agent = child.agent;
498
- index = child.index;
499
- target = resolveSubagentIntercomTarget(runId, agent, index);
500
- }
501
- else {
502
- const resolved = requestedId ? resolveSubagentRunId(requestedId, { state: input.deps.state, nested: nestedResolutionScopeForExecutor(input.deps) }) : undefined;
503
- const remembered = !resolved && requestedId ? resolveRememberedForegroundRun(requestedId, input.deps.state) : undefined;
504
- resolvedRunId = resolved?.id ?? remembered?.runId;
505
- const terminal = resolvedRunId ? terminalNudgeResult(resolvedRunId, input.deps) : undefined;
506
- if (terminal)
507
- return terminal;
508
- if (resolved?.kind === "nested") {
509
- const run = resolved.match.run;
510
- const state = run.state === "running" || run.state === "queued" ? "live" : run.state === "complete" ? "completed" : run.state === "paused" || run.state === "blocked" || run.state === "failed" ? run.state : "unknown";
511
- const intercomTarget = run.intercomTarget ?? run.leafIntercomTarget;
512
- const childSafe = Boolean(nestedResolutionScopeForExecutor(input.deps));
513
- const valid = [formatRunAction("status", run.id, {}, childSafe)];
514
- if (state === "live" || run.sessionFile)
515
- valid.push(formatRunAction("resume", run.id, { message: "..." }, childSafe));
516
- if (state === "live")
517
- valid.push(formatRunAction("interrupt", run.id, {}, childSafe));
518
- return {
519
- content: [{ type: "text", text: `Nested run ${run.id} cannot be nudged. Valid actions: ${valid.join(" or ")}${intercomTarget ? `. Intercom target: ${intercomTarget}` : "."}` }],
520
- isError: true,
521
- details: { mode: "management", results: [], managementControl: buildManagementControl({ state, runId: run.id, intercomTarget, canNudge: false, canResume: state === "live" || Boolean(run.sessionFile), canInterrupt: state === "live", unavailableActions: { nudge: "Nested runs do not support nudge; use an advertised exact action or intercom target." } }) },
522
- };
198
+ function lookupFailure(
199
+ // Recovery may revive a saved question; the real dependency state remains owned, not frozen.
200
+ input, error) {
201
+ const message = errorMessage(error), requested = requestedOwnedId(input.params);
202
+ const recoverable = (error instanceof Error && error.message.startsWith("Async run not found.")) ||
203
+ message.includes("is detached for intercom coordination");
204
+ if (requested !== undefined && recoverable) {
205
+ try {
206
+ const questions = listSupervisorQuestions(input.ctx.sessionManager.getSessionId(), requested);
207
+ if (questions.length > 0) {
208
+ return continueQuestionSession(input, questions);
523
209
  }
524
- if (remembered)
525
- return rememberedForegroundStatusResult(remembered, Boolean(nestedResolutionScopeForExecutor(input.deps)));
526
- const asyncTarget = resolveAsyncResumeTarget({ id: input.params.id ?? (!requestedId ? getAsyncInterruptTarget(input.deps.state, undefined)?.asyncId : undefined), runId: input.params.runId, dir: input.params.dir, index: input.params.index });
527
- if (asyncTarget.kind !== "live") {
528
- return terminalNudgeResult(asyncTarget.runId, input.deps)
529
- ?? inspectSubagentStatus({ id: asyncTarget.runId }, { state: input.deps.state, nested: nestedResolutionScopeForExecutor(input.deps) });
530
- }
531
- runId = asyncTarget.runId;
532
- agent = asyncTarget.agent;
533
- index = asyncTarget.index;
534
- target = asyncTarget.intercomTarget;
210
+ }
211
+ catch (questionError) {
212
+ return failure(errorMessage(questionError));
535
213
  }
536
214
  }
537
- catch (error) {
538
- const terminal = resolvedRunId ? terminalNudgeResult(resolvedRunId, input.deps) : undefined;
539
- if (terminal)
540
- return terminal;
541
- const text = error instanceof Error ? error.message : String(error);
542
- return { content: [{ type: "text", text }], isError: true, details: { mode: "management", results: [] } };
215
+ return failure(message);
216
+ }
217
+ async function deliverLiveContinuation(input, target) {
218
+ const followUp = normalizedFollowUp(input.params);
219
+ const delivered = await deliverSubagentIntercomMessageEvent(input.deps.pi.events, target.intercomTarget, `Follow-up for async run ${target.runId} (${target.agent}):\n\n${followUp}`, 500, { source: "async-resume", runId: target.runId, agent: target.agent, index: target.index });
220
+ if (!delivered) {
221
+ return failure([
222
+ "Async child appears live but its intercom target is not registered.",
223
+ `Run: ${target.runId}`,
224
+ `Intercom target: ${target.intercomTarget}`,
225
+ `Wait for completion, then retry ${formatRunAction("resume", target.runId, { message: "..." }, nestedResolutionScopeForExecutor(input.deps) !== undefined)}.`,
226
+ ].join("\n"));
543
227
  }
544
- const result = await sendLiveSubagentMessage(input.deps.pi.events, {
545
- to: target,
546
- message: `Nudge for subagent run ${runId} (${agent}${index !== undefined ? ` step ${index + 1}` : ""}):\n\n${message}`,
547
- delivery: "steer",
548
- extra: { source: "subagent-nudge", runId, agent, index },
549
- });
550
- if (!result.delivered) {
551
- const terminal = terminalNudgeResult(runId, input.deps);
552
- if (terminal)
553
- return terminal;
554
- return { content: [{ type: "text", text: [`Nudge was not delivered.`, `Run: ${runId}`, `Intercom target: ${target}`, result.reason ? `Reason: ${result.reason}` : undefined].filter((line) => Boolean(line)).join("\n") }], isError: true, details: { mode: "management", results: [] } };
228
+ const lines = [
229
+ "Delivered follow-up to live async child.",
230
+ `Run: ${target.runId}`,
231
+ `Intercom target: ${target.intercomTarget}`,
232
+ ];
233
+ if (input.params.acceptance !== undefined) {
234
+ lines.push(LIVE_ACCEPTANCE_OVERRIDE_NOTICE);
555
235
  }
556
236
  return {
557
- content: [{ type: "text", text: [`Nudge delivered to live subagent.`, `Run: ${runId}`, `Agent: ${agent}`, `Intercom target: ${target}`].join("\n") }],
558
- details: { mode: "management", results: [], managementControl: buildManagementControl({ state: "live", runId, index, intercomTarget: target, canNudge: true, canResume: true, canInterrupt: true }) },
237
+ content: [{ type: "text", text: lines.join("\n") }],
238
+ details: {
239
+ mode: "management",
240
+ results: [],
241
+ managementControl: buildManagementControl({
242
+ state: "live",
243
+ runId: target.runId,
244
+ index: target.index,
245
+ intercomTarget: target.intercomTarget,
246
+ canNudge: true,
247
+ canResume: true,
248
+ canInterrupt: true,
249
+ }),
250
+ },
559
251
  };
560
252
  }
561
- export async function resumeAsyncRun(input) {
562
- const followUp = (input.params.message ?? input.params.task ?? "").trim();
563
- if (!followUp) {
564
- return {
565
- content: [{ type: "text", text: "action='resume' requires message." }],
566
- isError: true,
567
- details: { mode: "management", results: [] },
568
- };
253
+ /** Pending question, owned/live continuation, then saved session revival—in that order. */
254
+ export async function resumeAsyncRun(
255
+ // Resume owns durable question delivery and newly launched continuation state through its helpers.
256
+ input) {
257
+ if (normalizedFollowUp(input.params).length === 0) {
258
+ return failure("action='resume' requires message.");
569
259
  }
570
- let target;
571
260
  const parentSessionFile = input.ctx.sessionManager.getSessionFile() ?? null;
572
- const nudgeContinuation = (runId, sessionFile) => {
573
- if (!sessionFile)
574
- return;
575
- for (const candidate of input.deps.state.ownedRuns?.values() ?? []) {
576
- if (candidate.runId === runId)
577
- continue;
578
- if (!candidate.children.some((child) => child.sessionFile === sessionFile)
579
- && input.deps.state.asyncJobs.get(candidate.runId)?.sessionFile !== sessionFile)
580
- continue;
581
- const active = ownedRunView(candidate, input.deps.state, { readConfiguration: false }).children.find((entry) => entry.sessionFile === sessionFile && entry.state === "live");
582
- if (!active)
583
- continue;
584
- return nudgeSubagentRun({ params: { ...input.params, dir: undefined, id: candidate.runId, index: active.index, message: followUp }, deps: input.deps, ctx: input.ctx }).then((result) => {
585
- const notice = liveLaunchOverrideNotice(input.params);
586
- if (notice)
587
- result.content.push({ type: "text", text: notice });
588
- return result;
589
- });
590
- }
591
- };
261
+ let resolution;
592
262
  try {
593
- const requestedId = input.params.id ?? input.params.runId;
594
- const pendingQuestions = requestedId && !input.params.dir
595
- ? listSupervisorQuestions(input.ctx.sessionManager.getSessionId(), requestedId).filter((question) => question.state === "awaiting_input" || question.state === "answer_pending")
596
- : [];
597
- if (pendingQuestions.length)
598
- return continueQuestionSession(input, pendingQuestions);
599
- const owned = requestedId && !input.params.dir ? resolveOwnedRun(input.deps.state, requestedId) : undefined;
600
- if (owned) {
601
- const view = ownedRunView(owned, input.deps.state);
602
- if (view.children.length > 1 && input.params.index === undefined)
603
- throw new Error(`Run '${owned.runId}' has ${view.children.length} children. Provide index to choose one.`);
604
- const child = view.children.find((entry) => entry.index === (input.params.index ?? 0));
605
- if (!child)
606
- throw new Error(`Run '${owned.runId}' has no child at index ${input.params.index ?? 0}.`);
607
- if (child.state === "live") {
608
- const result = await nudgeSubagentRun({ params: { ...input.params, id: owned.runId, message: followUp }, deps: input.deps, ctx: input.ctx });
609
- const notice = liveLaunchOverrideNotice(input.params);
610
- if (notice)
611
- result.content.push({ type: "text", text: notice });
612
- return result;
613
- }
614
- const continuation = nudgeContinuation(owned.runId, child.sessionFile);
615
- if (continuation)
616
- return await continuation;
617
- const contract = readQuestionContract(owned.runId, child.index);
618
- return reviveSavedSubagent(input, {
619
- ...contract, runId: owned.runId, agent: child.agent, index: child.index, source: owned.source,
620
- cwd: child.launch?.cwd ?? owned.cwd, sessionFile: child.sessionFile,
621
- effectiveAcceptance: contract?.effectiveAcceptance ?? child.result?.acceptance?.effectiveAcceptance,
622
- model: child.result?.model,
623
- });
624
- }
625
- const resolved = requestedId ? resolveSubagentRunId(requestedId, { state: input.deps.state, nested: nestedResolutionScopeForExecutor(input.deps) }) : undefined;
626
- if (resolved?.kind === "nested") {
627
- if (resolved.match.run.state === "running" || resolved.match.run.state === "queued") {
628
- return resumeLiveNestedRun({ target: resolved, message: followUp, index: input.params.index, acceptanceOverrideSupplied: input.params.acceptance !== undefined, pi: input.deps.pi, childSafe: Boolean(nestedResolutionScopeForExecutor(input.deps)) });
629
- }
630
- const trustedSessionRoots = [
631
- ...(input.deps.config.defaultSessionDir ? [path.resolve(input.deps.expandTilde(input.deps.config.defaultSessionDir))] : []),
632
- ...(parentSessionFile ? [input.deps.getSubagentSessionRoot(parentSessionFile)] : []),
633
- ];
634
- target = resolveNestedResumeTarget(resolved, trustedSessionRoots);
635
- }
636
- else {
637
- target = resolveResumeTarget(input.params, input.deps.state);
638
- }
263
+ resolution = await resolveContinuation(input, parentSessionFile);
639
264
  }
640
265
  catch (error) {
641
- const message = error instanceof Error ? error.message : String(error);
642
- const requestedId = input.params.id ?? input.params.runId;
643
- if (requestedId && !input.params.dir && (isAsyncRunNotFound(error) || message.includes("is detached for intercom coordination"))) {
644
- try {
645
- const questions = listSupervisorQuestions(input.ctx.sessionManager.getSessionId(), requestedId);
646
- if (questions.length)
647
- return continueQuestionSession(input, questions);
648
- }
649
- catch (questionError) {
650
- return { content: [{ type: "text", text: questionError instanceof Error ? questionError.message : String(questionError) }], isError: true, details: { mode: "management", results: [] } };
651
- }
652
- }
653
- return { content: [{ type: "text", text: message }], isError: true, details: { mode: "management", results: [] } };
654
- }
655
- if (target.kind === "live") {
656
- const delivered = await deliverSubagentIntercomMessageEvent(input.deps.pi.events, target.intercomTarget, `Follow-up for async run ${target.runId} (${target.agent}):\n\n${followUp}`, 500, { source: "async-resume", runId: target.runId, agent: target.agent, index: target.index });
657
- if (delivered) {
658
- return {
659
- content: [{ type: "text", text: [`Delivered follow-up to live async child.`, `Run: ${target.runId}`, `Intercom target: ${target.intercomTarget}`, input.params.acceptance !== undefined ? LIVE_ACCEPTANCE_OVERRIDE_NOTICE : undefined].filter(Boolean).join("\n") }],
660
- details: { mode: "management", results: [], managementControl: buildManagementControl({ state: "live", runId: target.runId, index: target.index, intercomTarget: target.intercomTarget, canNudge: true, canResume: true, canInterrupt: true }) },
661
- };
662
- }
663
- return {
664
- content: [{ type: "text", text: [`Async child appears live but its intercom target is not registered.`, `Run: ${target.runId}`, `Intercom target: ${target.intercomTarget}`, `Wait for completion, then retry ${formatRunAction("resume", target.runId, { message: "..." }, Boolean(nestedResolutionScopeForExecutor(input.deps)))}.`].join("\n") }],
665
- isError: true,
666
- details: { mode: "management", results: [] },
667
- };
668
- }
669
- return nudgeContinuation(target.runId, target.sessionFile) ?? reviveSavedSubagent(input, target);
670
- }
671
- function continueQuestionSession(input, questions) {
672
- if (input.params.index === undefined && new Set(questions.map((question) => question.index)).size > 1)
673
- throw new Error("Provide index to choose which child question to continue.");
674
- const question = questions.findLast((entry) => input.params.index === undefined || entry.index === input.params.index);
675
- if (!question)
676
- throw new Error("No saved question for that child index.");
677
- if (questionProcessAlive(question))
678
- throw new Error("The question's child is still alive. Answer the question or stop it before continuing.");
679
- if (question.delivery?.kind === "revive")
680
- throw new Error(`Use continue with the answer's continuation run ${question.delivery.runId}.`);
681
- const revival = question.revival;
682
- const prior = revival ? resolveSubagentRunId(revival.runId, { state: input.deps.state, nested: nestedResolutionScopeForExecutor(input.deps) }) : undefined;
683
- const priorExists = prior?.kind === "async"
684
- ? prior.location.resultPath || (prior.location.asyncDir && fs.existsSync(path.join(prior.location.asyncDir, "status.json")))
685
- : Boolean(prior);
686
- if (revival && (questionProcessAlive(revival) || priorExists || fs.existsSync(getAsyncConfigPath(revival.runId)) || fs.existsSync(path.join(getRunMetadataDir(revival.runId), "launch.json")) || fs.existsSync(path.join(ASYNC_DIR, revival.runId, RUNNER_ERROR_LOG_FILE)))) {
687
- throw new Error(`Continuation ${revival.runId} may already have launched. Inspect or continue that run; the original question was not restarted.`);
688
- }
689
- const message = [input.params.message ?? input.params.task, question.answer ? `Saved supervisor answer:\n${question.answer.message}\n\nOriginal question:\n${question.message}` : undefined].filter(Boolean).join("\n\n");
690
- const result = reviveSavedSubagent({ ...input, params: { ...input.params, message } }, { ...question, source: "question" });
691
- if (!result.isError && question.answer && !question.delivery)
692
- recordQuestionDelivery(question, { kind: "revive", runId: result.details.asyncId, deliveredAt: Date.now() });
693
- return result;
694
- }
695
- export function reviveSavedSubagent(input, target, runId = randomUUID()) {
696
- const followUp = (input.params.message ?? input.params.task ?? "").trim();
697
- const parentSessionFile = input.ctx.sessionManager.getSessionFile() ?? null;
698
- if (!target.sessionFile || path.extname(target.sessionFile) !== ".jsonl" || !fs.existsSync(target.sessionFile)) {
699
- return { content: [{ type: "text", text: `Saved child session file is unavailable: ${target.sessionFile ?? "none"}. No child was started; any saved answer remains pending.` }], isError: true, details: { mode: "management", results: [] } };
700
- }
701
- const { blocked, depth, maxDepth } = checkSubagentDepth(input.deps.config.maxSubagentDepth);
702
- if (blocked) {
703
- return {
704
- content: [{ type: "text", text: `Nested subagent resume blocked (depth=${depth}, max=${maxDepth}). Complete the follow-up directly instead.` }],
705
- isError: true,
706
- details: { mode: "management", results: [] },
707
- };
708
- }
709
- input.deps.state.currentSessionId = resolveCurrentSessionId(input.ctx.sessionManager);
710
- const contract = readQuestionContract(target.runId, target.index) ?? target;
711
- const savedLaunch = input.params.agent === undefined && contract.launch ? { ...contract.launch, ...contract.effectiveConfiguration } : undefined;
712
- const generatedOutputFilename = input.params.output === undefined ? contract.launch?.generatedOutputFilename : undefined;
713
- const effectiveCwd = input.params.cwd ?? savedLaunch?.cwd ?? target.cwd ?? input.requestCwd;
714
- const scope = resolveExecutionAgentScope(input.params.agentScope);
715
- if (!savedLaunch && !input.params.agent) {
716
- return { content: [{ type: "text", text: `Run '${target.runId}' predates saved launch configuration. Its session and known result remain available, but the original profile cannot be reconstructed safely. Continue with agent: '${target.agent}' to explicitly use that profile's current configuration, including model and thinking; known output and acceptance are retained unless overridden.` }], isError: true, details: { mode: "management", results: [] } };
266
+ return lookupFailure(input, error);
717
267
  }
718
- const discoveredAgents = savedLaunch ? [savedLaunch.agent] : input.deps.discoverAgents(effectiveCwd, scope, { projectTrusted: input.ctx.isProjectTrusted() }).agents;
719
- const fallbackTarget = resolveIntercomSessionTarget(input.deps.pi.getSessionName(), input.ctx.sessionManager.getSessionId());
720
- const orchestratorTarget = resolveOrchestratorIntercomTarget(input.deps.pi.events, fallbackTarget);
721
- const intercomBridge = resolveIntercomBridge(orchestratorTarget);
722
- const inheritedModel = providerQualifiedModelId(input.ctx.model?.provider, input.ctx.model?.id);
723
- const agents = savedLaunch ? discoveredAgents : discoveredAgents.map((agent) => agent.model || !inheritedModel ? agent : { ...agent, model: inheritedModel });
724
- const selectedAgent = input.params.agent ?? target.agent;
725
- const profile = agents.find((agent) => agent.name === selectedAgent);
726
- const agentConfig = profile && savedLaunch ? { ...profile, thinking: savedLaunch.thinking ?? profile.thinking, maxExecutionTimeMs: savedLaunch.maxExecutionTimeMs, maxTokens: savedLaunch.maxTokens } : profile;
727
- if (!agentConfig) {
728
- return {
729
- content: [{ type: "text", text: `Unknown agent for resume: ${selectedAgent}` }],
730
- isError: true,
731
- details: { mode: "management", results: [] },
732
- };
268
+ if (resolution.kind === "result") {
269
+ return resolution.result;
733
270
  }
734
- saveQuestionOwner(runId, input.ctx.sessionManager.getSessionId());
735
- const prior = input.deps.state.ownedRuns?.get(target.runId);
736
- rememberOwnedRun(input.deps.state, {
737
- runId, ownerSessionId: input.ctx.sessionManager.getSessionId(), rootRunId: prior?.rootRunId ?? target.runId,
738
- predecessorRunId: target.runId, predecessorIndex: target.index,
739
- source: "async", mode: "single", cwd: effectiveCwd, task: followUp, startedAt: Date.now(),
740
- children: [{ agent: selectedAgent, index: 0, task: followUp, label: prior?.children.find((child) => child.index === target.index)?.label, sessionFile: target.sessionFile }],
741
- });
742
- const modelOverride = input.params.model;
743
- const skill = normalizeSkillInput(input.params.skill);
744
- const availableModels = input.ctx.modelRegistry.getAvailable().map(toModelInfo);
745
- const launchInput = {
746
- agent: selectedAgent,
747
- task: buildRevivedAsyncTask(target, followUp, input.params.messageOrigin),
748
- agentConfig,
749
- ctx: {
750
- pi: input.deps.pi,
751
- cwd: input.requestCwd,
752
- currentSessionId: input.deps.state.currentSessionId,
753
- rootSessionId: resolveRootSessionId(input.ctx.sessionManager),
754
- currentModelProvider: input.ctx.model?.provider,
755
- projectTrusted: input.ctx.isProjectTrusted(),
756
- },
757
- cwd: effectiveCwd,
758
- maxOutput: input.params.maxOutput ?? savedLaunch?.maxOutput,
759
- artifactsDir: input.params.artifacts === false || (input.params.artifacts === undefined && savedLaunch?.artifacts === false) ? undefined : savedLaunch?.artifactsDir ?? input.deps.tempArtifactsDir,
760
- shareEnabled: input.params.share ?? savedLaunch?.share ?? false,
761
- sessionRoot: input.deps.getSubagentSessionRoot(parentSessionFile),
762
- sessionFile: target.sessionFile,
763
- maxSubagentDepth: savedLaunch?.maxSubagentDepth ?? resolveCurrentMaxSubagentDepth(input.deps.config.maxSubagentDepth),
764
- worktreeSetupHook: input.deps.config.worktreeSetupHook,
765
- worktreeSetupHookTimeoutMs: input.deps.config.worktreeSetupHookTimeoutMs,
766
- controlConfig: resolveControlConfig(savedLaunch?.controlConfig ?? input.deps.config.control, input.params.control),
767
- controlIntercomTarget: intercomBridge.orchestratorTarget,
768
- childIntercomTarget: (agent, index) => resolveSubagentIntercomTarget(runId, agent, index),
769
- availableModels, savedLaunch, modelOverride,
770
- skills: skill,
771
- acceptance: input.params.acceptance ?? acceptanceInputFromResolved(contract.effectiveAcceptance ?? savedLaunch?.effectiveAcceptance),
772
- output: input.params.output ?? (generatedOutputFilename ? true : savedLaunch?.output ?? contract.output),
773
- generatedOutputFilename,
774
- outputMode: input.params.outputMode ?? savedLaunch?.outputMode ?? contract.outputMode,
775
- outputSchema: input.params.outputSchema ?? savedLaunch?.outputSchema ?? contract.outputSchema,
776
- projectTrust: savedLaunch?.projectTrust ?? resolveConfiguredChildProjectTrustPolicy(input.deps.config.projectTrust),
777
- };
778
- const undoCwdRequest = input.params.cwd !== undefined ? requestChildExecutionCwd(target.sessionFile, effectiveCwd) : undefined;
779
- let result;
780
- try {
781
- result = executeAsyncSingle(runId, launchInput);
782
- }
783
- catch (error) {
784
- undoCwdRequest?.();
785
- throw error;
271
+ const { target } = resolution;
272
+ if (target.kind === "live") {
273
+ return deliverLiveContinuation(input, target);
786
274
  }
787
- if (result.isError)
788
- undoCwdRequest?.();
789
- const owned = input.deps.state.ownedRuns?.get(runId);
790
- if (owned)
791
- rememberOwnedRun(input.deps.state, { ...owned, asyncDir: result.details.asyncDir, pid: result.details.asyncPid ?? input.deps.state.asyncJobs.get(runId)?.pid, ...(result.isError ? { error: result.content.map((part) => part.text).join("\n") } : {}) });
792
- if (result.isError)
793
- return result;
794
- const revivedId = result.details.asyncId ?? runId;
795
- const revivedTarget = resolveSubagentIntercomTarget(revivedId, selectedAgent, 0);
796
- const sourceLabel = target.source;
797
- const lines = [
798
- `Revived ${sourceLabel} subagent from ${target.runId}.`,
799
- `Run mapping: ${target.runId} -> ${revivedId}`,
800
- `Revived run: ${revivedId}`,
801
- `Agent: ${selectedAgent}`,
802
- `Configuration: ${savedLaunch ? "saved effective launch" : "explicitly selected current profile"}${modelOverride ? `; model ${modelOverride}` : ""}`,
803
- `Root: ${prior?.rootRunId ?? target.runId}`,
804
- `Session: ${target.sessionFile}`,
805
- result.details.asyncDir ? `Async dir: ${result.details.asyncDir}` : undefined,
806
- revivedTarget ? `Intercom target: ${revivedTarget} (if registered)` : undefined,
807
- `Prior pending-reply context for ${target.runId} is invalid; use the revived run and target only.`,
808
- `Status if needed: ${formatRunAction("status", revivedId, {}, Boolean(nestedResolutionScopeForExecutor(input.deps)))}`,
809
- ].filter((line) => Boolean(line));
810
- return {
811
- content: [{ type: "text", text: formatAsyncStartedMessage(lines.join("\n"), Boolean(nestedResolutionScopeForExecutor(input.deps))) }],
812
- details: {
813
- ...result.details,
814
- managementControl: buildManagementControl({ state: "live", runId: revivedId, index: 0, intercomTarget: revivedTarget, canInterrupt: true, revivedFromRunId: target.runId }),
815
- },
816
- };
275
+ return (nudgeContinuation(input, target.runId, target.sessionFile) ?? reviveSavedSubagent(input, target));
817
276
  }