@fitchmultz/pi-subagents 0.44.7 → 0.46.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 (955) hide show
  1. package/CHANGELOG.md +264 -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 +89 -0
  111. package/dist/pi-intercom/bridge-http.js +86 -0
  112. package/dist/pi-intercom/bridge-launch-policy.js +88 -0
  113. package/dist/pi-intercom/bridge-launch.js +217 -0
  114. package/dist/pi-intercom/bridge-protocol.js +106 -0
  115. package/dist/pi-intercom/bridge-routes.js +72 -0
  116. package/dist/pi-intercom/bridge-rpc-process.js +264 -0
  117. package/dist/pi-intercom/bridge-session.js +420 -0
  118. package/dist/pi-intercom/bridge.js +221 -606
  119. package/dist/pi-intercom/broker/broker.js +236 -244
  120. package/dist/pi-intercom/broker/client.js +189 -304
  121. package/dist/pi-intercom/broker/connection.js +165 -0
  122. package/dist/pi-intercom/broker/framing.js +5 -3
  123. package/dist/pi-intercom/broker/paths.js +4 -1
  124. package/dist/pi-intercom/broker/pid.js +53 -25
  125. package/dist/pi-intercom/broker/snapshot-reader.js +78 -0
  126. package/dist/pi-intercom/broker/snapshots.js +188 -0
  127. package/dist/pi-intercom/broker/spawn.js +36 -25
  128. package/dist/pi-intercom/config.js +85 -71
  129. package/dist/pi-intercom/connection.js +297 -0
  130. package/dist/pi-intercom/identity.js +58 -0
  131. package/dist/pi-intercom/inbound-delivery.js +356 -0
  132. package/dist/pi-intercom/inbound-journal.js +303 -0
  133. package/dist/pi-intercom/inbound-record.js +113 -0
  134. package/dist/pi-intercom/inbound.js +179 -0
  135. package/dist/pi-intercom/index.js +79 -2933
  136. package/dist/pi-intercom/inspection.js +62 -0
  137. package/dist/pi-intercom/interview.js +236 -0
  138. package/dist/pi-intercom/lifecycle.js +168 -0
  139. package/dist/pi-intercom/message-format.js +69 -0
  140. package/dist/pi-intercom/outbound.js +304 -0
  141. package/dist/pi-intercom/peer-awareness.js +66 -0
  142. package/dist/pi-intercom/reply-tracker.js +62 -43
  143. package/dist/pi-intercom/reply-wait.js +201 -0
  144. package/dist/pi-intercom/runtime-types.js +3 -0
  145. package/dist/pi-intercom/session-events.js +180 -0
  146. package/dist/pi-intercom/session-targets.js +42 -34
  147. package/dist/pi-intercom/subagent-events.js +238 -0
  148. package/dist/pi-intercom/subagent-live-events.js +129 -86
  149. package/dist/pi-intercom/supervisor.js +282 -0
  150. package/dist/pi-intercom/tool-arguments.js +74 -0
  151. package/dist/pi-intercom/tool-registration.js +95 -0
  152. package/dist/pi-intercom/tool-results.js +38 -0
  153. package/dist/pi-intercom/tool-schemas.js +82 -0
  154. package/dist/pi-intercom/tools.js +51 -0
  155. package/dist/pi-intercom/topic-actions.js +177 -0
  156. package/dist/pi-intercom/topics.js +177 -92
  157. package/dist/pi-intercom/transport.js +1 -0
  158. package/dist/pi-intercom/types.js +151 -114
  159. package/dist/pi-intercom/ui/compose-paste.js +93 -0
  160. package/dist/pi-intercom/ui/compose.js +121 -143
  161. package/dist/pi-intercom/ui/inline-message.js +59 -59
  162. package/dist/pi-intercom/ui/message-renderers.js +147 -0
  163. package/dist/pi-intercom/ui/overlay.js +181 -0
  164. package/dist/pi-intercom/ui/session-format.js +124 -0
  165. package/dist/pi-intercom/ui/session-list.js +76 -43
  166. package/dist/pi-intercom/ui/tool-renderers.js +110 -0
  167. package/dist/pi-intercom/ui/topic-view.js +88 -0
  168. package/dist/pi-intercom/validation.js +59 -0
  169. package/dist/runs/background/async-chain-plan.js +265 -0
  170. package/dist/runs/background/async-control.js +134 -58
  171. package/dist/runs/background/async-execution.js +136 -633
  172. package/dist/runs/background/async-job-admission.js +40 -0
  173. package/dist/runs/background/async-job-projection.js +169 -0
  174. package/dist/runs/background/async-job-tracker.js +297 -327
  175. package/dist/runs/background/async-launch.js +216 -0
  176. package/dist/runs/background/async-plan.js +116 -0
  177. package/dist/runs/background/async-result-file.js +47 -23
  178. package/dist/runs/background/async-resume.js +195 -253
  179. package/dist/runs/background/async-run-discovery.js +213 -0
  180. package/dist/runs/background/async-run-location.js +135 -0
  181. package/dist/runs/background/async-run-record.js +1 -0
  182. package/dist/runs/background/async-run-repair.js +223 -0
  183. package/dist/runs/background/async-run-summary.js +1 -0
  184. package/dist/runs/background/async-single-plan.js +105 -0
  185. package/dist/runs/background/async-status-projection.js +155 -0
  186. package/dist/runs/background/async-status-render.js +117 -0
  187. package/dist/runs/background/async-status-validation.js +181 -0
  188. package/dist/runs/background/async-status.js +3 -442
  189. package/dist/runs/background/async-value.js +21 -0
  190. package/dist/runs/background/completion-dedupe.js +36 -12
  191. package/dist/runs/background/completion-delivery.js +211 -205
  192. package/dist/runs/background/completion-receipts.js +237 -0
  193. package/dist/runs/background/legacy-status-acceptance.js +34 -0
  194. package/dist/runs/background/notify.js +96 -48
  195. package/dist/runs/background/parallel-groups.js +36 -19
  196. package/dist/runs/background/result-payload.js +178 -0
  197. package/dist/runs/background/result-watcher.js +348 -339
  198. package/dist/runs/background/run-id-resolver.js +53 -33
  199. package/dist/runs/background/run-schemas.js +189 -0
  200. package/dist/runs/background/run-status-contracts.js +14 -0
  201. package/dist/runs/background/run-status-render.js +270 -0
  202. package/dist/runs/background/run-status.js +231 -339
  203. package/dist/runs/background/runner-attempt-output.js +155 -0
  204. package/dist/runs/background/runner-attempt.js +263 -0
  205. package/dist/runs/background/runner-child-executor.js +166 -0
  206. package/dist/runs/background/runner-child-observer.js +192 -0
  207. package/dist/runs/background/runner-completion-summary.js +71 -0
  208. package/dist/runs/background/runner-completion.js +211 -0
  209. package/dist/runs/background/runner-config.js +1 -0
  210. package/dist/runs/background/runner-contract.js +1 -0
  211. package/dist/runs/background/runner-dynamic.js +121 -0
  212. package/dist/runs/background/runner-finalization.js +149 -0
  213. package/dist/runs/background/runner-graph.js +68 -0
  214. package/dist/runs/background/runner-initial-status.js +60 -0
  215. package/dist/runs/background/runner-lifecycle.js +142 -0
  216. package/dist/runs/background/runner-monitor.js +309 -0
  217. package/dist/runs/background/runner-parallel.js +204 -0
  218. package/dist/runs/background/runner-prepare-step.js +86 -0
  219. package/dist/runs/background/runner-reporting.js +153 -0
  220. package/dist/runs/background/runner-status.js +148 -0
  221. package/dist/runs/background/runner-step-output.js +92 -0
  222. package/dist/runs/background/runner-step-record.js +45 -0
  223. package/dist/runs/background/runner-step.js +112 -0
  224. package/dist/runs/background/runner-streaming.js +173 -0
  225. package/dist/runs/background/runner-workflow.js +213 -0
  226. package/dist/runs/background/stale-run-reconciler.js +155 -292
  227. package/dist/runs/background/subagent-runner-launcher.js +33 -13
  228. package/dist/runs/background/subagent-runner.js +51 -1842
  229. package/dist/runs/background/top-level-async.js +2 -1
  230. package/dist/runs/foreground/chain-clarify.js +293 -1017
  231. package/dist/runs/foreground/clarification-draft.js +87 -0
  232. package/dist/runs/foreground/clarify-contracts.js +1 -0
  233. package/dist/runs/foreground/clarify-invocation.js +129 -38
  234. package/dist/runs/foreground/clarify-text-editor.js +210 -0
  235. package/dist/runs/foreground/clarify-view.js +167 -0
  236. package/dist/runs/foreground/execution-input.js +226 -353
  237. package/dist/runs/foreground/execution-routing.js +33 -0
  238. package/dist/runs/foreground/execution-timeout.js +81 -0
  239. package/dist/runs/foreground/foreground-control.js +222 -763
  240. package/dist/runs/foreground/foreground-memory.js +99 -0
  241. package/dist/runs/foreground/invocation-context.js +55 -0
  242. package/dist/runs/foreground/invocation-execution.js +331 -0
  243. package/dist/runs/foreground/invocation-expansion.js +48 -0
  244. package/dist/runs/foreground/management-actions.js +295 -0
  245. package/dist/runs/foreground/nested-control.js +179 -0
  246. package/dist/runs/foreground/question-continuation.js +78 -0
  247. package/dist/runs/foreground/question-control.js +155 -50
  248. package/dist/runs/foreground/resume-target.js +221 -0
  249. package/dist/runs/foreground/revival-launch-policy.js +58 -0
  250. package/dist/runs/foreground/run-async-path.js +190 -178
  251. package/dist/runs/foreground/run-interrupt.js +164 -0
  252. package/dist/runs/foreground/run-nudge.js +278 -0
  253. package/dist/runs/foreground/saved-revival.js +251 -0
  254. package/dist/runs/foreground/subagent-executor.js +135 -424
  255. package/dist/runs/foreground/subagent-params.js +67 -30
  256. package/dist/runs/foreground/wait-observation.js +104 -0
  257. package/dist/runs/foreground/wait-registration.js +17 -0
  258. package/dist/runs/foreground/wait-run.js +283 -123
  259. package/dist/runs/shared/acceptance-contract.js +193 -99
  260. package/dist/runs/shared/acceptance-defaults.js +1 -0
  261. package/dist/runs/shared/acceptance-evaluation.js +201 -181
  262. package/dist/runs/shared/acceptance-finalization.js +256 -180
  263. package/dist/runs/shared/acceptance-outcome.js +53 -0
  264. package/dist/runs/shared/acceptance-reports.js +137 -72
  265. package/dist/runs/shared/acceptance-submission.js +167 -0
  266. package/dist/runs/shared/acceptance-verification.js +100 -0
  267. package/dist/runs/shared/chain-outputs.js +80 -52
  268. package/dist/runs/shared/child-attempt-types.js +1 -0
  269. package/dist/runs/shared/child-attempt.js +314 -667
  270. package/dist/runs/shared/child-boundaries.js +173 -0
  271. package/dist/runs/shared/child-context-filter.js +44 -0
  272. package/dist/runs/shared/child-event-observer.js +390 -0
  273. package/dist/runs/shared/child-execution-cwd.js +73 -43
  274. package/dist/runs/shared/child-execution-outcome.js +72 -0
  275. package/dist/runs/shared/child-invocation.js +54 -0
  276. package/dist/runs/shared/child-message-validation.js +215 -0
  277. package/dist/runs/shared/child-native-accounting.js +106 -0
  278. package/dist/runs/shared/child-native-observation.js +69 -0
  279. package/dist/runs/shared/child-observation-spool.js +164 -0
  280. package/dist/runs/shared/child-observations.js +157 -76
  281. package/dist/runs/shared/child-presence.js +3 -0
  282. package/dist/runs/shared/child-route-env.js +119 -0
  283. package/dist/runs/shared/child-stream-observer.js +221 -0
  284. package/dist/runs/shared/child-stream-projection.js +137 -0
  285. package/dist/runs/shared/child-structured-tool.js +27 -0
  286. package/dist/runs/shared/claude-code.js +121 -158
  287. package/dist/runs/shared/claude-model.js +42 -0
  288. package/dist/runs/shared/claude-session.js +83 -0
  289. package/dist/runs/shared/claude-types.js +1 -0
  290. package/dist/runs/shared/completion-guard.js +18 -18
  291. package/dist/runs/shared/control-event-policy.js +8 -0
  292. package/dist/runs/shared/control-notification-owner.js +13 -0
  293. package/dist/runs/shared/dynamic-fanout.js +188 -173
  294. package/dist/runs/shared/dynamic-item.js +102 -0
  295. package/dist/runs/shared/history-index.js +62 -36
  296. package/dist/runs/shared/legacy-async-recovery.js +114 -0
  297. package/dist/runs/shared/legacy-output-recovery.js +148 -0
  298. package/dist/runs/shared/mcp-config-schema.js +36 -0
  299. package/dist/runs/shared/mcp-direct-tool-allowlist.js +147 -116
  300. package/dist/runs/shared/model-fallback.js +97 -38
  301. package/dist/runs/shared/mutating-tool-guard.js +128 -88
  302. package/dist/runs/shared/native-finalization-types.js +1 -0
  303. package/dist/runs/shared/native-finalization.js +155 -76
  304. package/dist/runs/shared/native-usage.js +238 -98
  305. package/dist/runs/shared/nested-control-records.js +128 -0
  306. package/dist/runs/shared/nested-events.js +8 -700
  307. package/dist/runs/shared/nested-path.js +32 -28
  308. package/dist/runs/shared/nested-projection.js +155 -0
  309. package/dist/runs/shared/nested-protocol.js +18 -0
  310. package/dist/runs/shared/nested-registry.js +191 -0
  311. package/dist/runs/shared/nested-render.js +106 -58
  312. package/dist/runs/shared/nested-route.js +220 -0
  313. package/dist/runs/shared/nested-validation.js +216 -0
  314. package/dist/runs/shared/owned-child-evidence.js +125 -0
  315. package/dist/runs/shared/owned-run-list.js +146 -0
  316. package/dist/runs/shared/owned-run-observation.js +267 -0
  317. package/dist/runs/shared/owned-run-progress.js +109 -0
  318. package/dist/runs/shared/owned-run-read-state.js +1 -0
  319. package/dist/runs/shared/owned-run-results.js +202 -0
  320. package/dist/runs/shared/owned-run-status.js +180 -0
  321. package/dist/runs/shared/owned-run-view.js +51 -0
  322. package/dist/runs/shared/owned-workflow-details.js +17 -0
  323. package/dist/runs/shared/owner-output.js +43 -0
  324. package/dist/runs/shared/parallel-utils.js +36 -28
  325. package/dist/runs/shared/parent-receipts.js +90 -32
  326. package/dist/runs/shared/parent-usage.js +169 -57
  327. package/dist/runs/shared/pi-args.js +108 -201
  328. package/dist/runs/shared/pi-launch-input.js +1 -0
  329. package/dist/runs/shared/pi-session-launch.js +86 -0
  330. package/dist/runs/shared/pi-spawn.js +35 -21
  331. package/dist/runs/shared/run-history-queries.js +126 -35
  332. package/dist/runs/shared/run-history.js +101 -35
  333. package/dist/runs/shared/run-metadata-paths.js +14 -0
  334. package/dist/runs/shared/run-metadata.js +158 -0
  335. package/dist/runs/shared/run-persistence.js +131 -0
  336. package/dist/runs/shared/run-records.js +9 -679
  337. package/dist/runs/shared/run-restoration.js +338 -0
  338. package/dist/runs/shared/run-state-owner.js +26 -0
  339. package/dist/runs/shared/session-cwd-preload.js +27 -18
  340. package/dist/runs/shared/single-output.js +148 -70
  341. package/dist/runs/shared/stable-value.js +15 -0
  342. package/dist/runs/shared/streaming-text.js +23 -12
  343. package/dist/runs/shared/structured-output.js +25 -13
  344. package/dist/runs/shared/subagent-control.js +167 -100
  345. package/dist/runs/shared/subagent-prompt-runtime.js +27 -130
  346. package/dist/runs/shared/subagent-tool-loop-guard.js +81 -52
  347. package/dist/runs/shared/supervisor-question-state.js +145 -0
  348. package/dist/runs/shared/supervisor-questions.js +185 -254
  349. package/dist/runs/shared/workflow-graph.js +259 -167
  350. package/dist/runs/shared/workflow-policy.js +120 -48
  351. package/dist/runs/shared/worktree-contract.js +1 -0
  352. package/dist/runs/shared/worktree-hook.js +138 -0
  353. package/dist/runs/shared/worktree-location.js +47 -0
  354. package/dist/runs/shared/worktree-preservation.js +8 -0
  355. package/dist/runs/shared/worktree-process.js +107 -0
  356. package/dist/runs/shared/worktree.js +183 -322
  357. package/dist/shared/agent-context-policy.js +34 -44
  358. package/dist/shared/agent-dir.js +14 -0
  359. package/dist/shared/artifacts.js +30 -12
  360. package/dist/shared/atomic-json.js +4 -1
  361. package/dist/shared/chain-files.js +72 -0
  362. package/dist/shared/concurrency.js +18 -0
  363. package/dist/shared/content-preview.js +115 -0
  364. package/dist/shared/cooperative.js +5 -2
  365. package/dist/shared/execution-cwd.js +13 -5
  366. package/dist/shared/file-coalescer.js +2 -1
  367. package/dist/shared/fork-context.js +10 -12
  368. package/dist/shared/formatters.js +45 -19
  369. package/dist/shared/journal-frames.js +164 -0
  370. package/dist/shared/journal-projections.js +121 -0
  371. package/dist/shared/journal-reader.js +6 -407
  372. package/dist/shared/json-projection.js +191 -0
  373. package/dist/shared/lazy-tools.js +19 -8
  374. package/dist/shared/message-output.js +116 -0
  375. package/dist/shared/model-info.js +31 -14
  376. package/dist/shared/native-import.js +20 -0
  377. package/dist/shared/native-journal.js +140 -0
  378. package/dist/shared/native-session-loader.js +17 -0
  379. package/dist/shared/native-session.js +2 -13
  380. package/dist/shared/native-tui.js +7 -2
  381. package/dist/shared/native-typebox.js +15 -3
  382. package/dist/shared/output-page.js +63 -0
  383. package/dist/shared/post-exit-stdio-guard.js +128 -88
  384. package/dist/shared/prompt-sections.js +2 -0
  385. package/dist/shared/session-entries.js +70 -35
  386. package/dist/shared/session-identity.js +5 -3
  387. package/dist/shared/settings.js +62 -192
  388. package/dist/shared/status-format.js +97 -37
  389. package/dist/shared/task-file-policy.js +24 -0
  390. package/dist/shared/temp-root.js +44 -15
  391. package/dist/shared/types/acceptance.js +1 -0
  392. package/dist/shared/types/async.js +1 -0
  393. package/dist/shared/types/config.js +1 -0
  394. package/dist/shared/types/details.js +1 -0
  395. package/dist/shared/types/history.js +1 -0
  396. package/dist/shared/types/inputs.js +1 -0
  397. package/dist/shared/types/intercom.js +1 -0
  398. package/dist/shared/types/launch.js +1 -0
  399. package/dist/shared/types/messages.js +1 -0
  400. package/dist/shared/types/nested.js +1 -0
  401. package/dist/shared/types/owned-runs.js +1 -0
  402. package/dist/shared/types/progress.js +1 -0
  403. package/dist/shared/types/questions.js +1 -0
  404. package/dist/shared/types/results.js +1 -0
  405. package/dist/shared/types/state.js +1 -0
  406. package/dist/shared/types/usage.js +1 -0
  407. package/dist/shared/types/workflow.js +1 -0
  408. package/dist/shared/types.js +75 -30
  409. package/dist/shared/unknown.js +52 -0
  410. package/dist/shared/utils.js +54 -260
  411. package/dist/slash/command-discovery.js +82 -0
  412. package/dist/slash/command-input.js +190 -0
  413. package/dist/slash/prompt-template-bridge.js +94 -270
  414. package/dist/slash/prompt-template-contract.js +77 -0
  415. package/dist/slash/prompt-template-results.js +125 -0
  416. package/dist/slash/request-protocol.js +68 -0
  417. package/dist/slash/result-delivery.js +237 -0
  418. package/dist/slash/saved-chain.js +78 -0
  419. package/dist/slash/slash-bridge.js +123 -89
  420. package/dist/slash/slash-commands.js +101 -572
  421. package/dist/slash/slash-live-state.js +68 -47
  422. package/dist/tui/action-hints.js +50 -22
  423. package/dist/tui/activity-lines.js +32 -0
  424. package/dist/tui/agent-browser.js +290 -0
  425. package/dist/tui/agent-controls.js +289 -0
  426. package/dist/tui/agent-conversation.js +444 -0
  427. package/dist/tui/agent-dock.js +171 -0
  428. package/dist/tui/agent-history.js +50 -183
  429. package/dist/tui/agent-model.js +62 -0
  430. package/dist/tui/agent-picker.js +262 -0
  431. package/dist/tui/agent-view.js +232 -1564
  432. package/dist/tui/compact-results.js +193 -0
  433. package/dist/tui/conversation-details.js +190 -0
  434. package/dist/tui/conversation-frame.js +135 -0
  435. package/dist/tui/conversation-history.js +201 -0
  436. package/dist/tui/conversation-menu.js +78 -0
  437. package/dist/tui/conversation-notices.js +79 -0
  438. package/dist/tui/conversation-selection.js +58 -0
  439. package/dist/tui/conversation-viewport.js +129 -0
  440. package/dist/tui/direction-message.js +27 -0
  441. package/dist/tui/display.js +282 -0
  442. package/dist/tui/editor-viewport.js +18 -0
  443. package/dist/tui/expanded-content.js +87 -0
  444. package/dist/tui/expanded-multi.js +170 -0
  445. package/dist/tui/expanded-single.js +65 -0
  446. package/dist/tui/history-cards.js +216 -0
  447. package/dist/tui/history-display.js +238 -0
  448. package/dist/tui/history-json.js +16 -0
  449. package/dist/tui/history-metadata.js +152 -0
  450. package/dist/tui/history-record.js +251 -0
  451. package/dist/tui/history-text.js +34 -0
  452. package/dist/tui/indexed-history.js +116 -0
  453. package/dist/tui/nested-widget.js +120 -0
  454. package/dist/tui/picker-page.js +59 -0
  455. package/dist/tui/render.js +58 -1501
  456. package/dist/tui/result-facts.js +64 -0
  457. package/dist/tui/task-observation.js +59 -0
  458. package/dist/tui/task-store.js +366 -0
  459. package/dist/tui/text-values.js +16 -0
  460. package/dist/tui/view-connections.js +47 -0
  461. package/dist/tui/view-model.js +94 -0
  462. package/dist/tui/view-persistence.js +51 -0
  463. package/dist/tui/view-ports.js +1 -0
  464. package/dist/tui/view-session.js +37 -0
  465. package/dist/tui/widget-details.js +144 -0
  466. package/dist/tui/widget-status.js +245 -0
  467. package/dist/tui/widget.js +145 -0
  468. package/dist/tui/workflow-labels.js +223 -0
  469. package/dist/tui/workflow-outcomes.js +124 -0
  470. package/docs/code-quality.md +38 -0
  471. package/docs/development.md +99 -0
  472. package/docs/intercom-bridge.md +77 -22
  473. package/docs/intercom.md +132 -106
  474. package/docs/performance.md +19 -17
  475. package/docs/reference.md +1472 -0
  476. package/generated/RunValidators.d.ts +28 -0
  477. package/generated/RunValidators.js +2 -0
  478. package/package.json +27 -6
  479. package/prompts/parallel-cleanup.md +3 -0
  480. package/prompts/parallel-context-build.md +3 -0
  481. package/prompts/parallel-handoff-plan.md +6 -0
  482. package/prompts/parallel-research.md +4 -0
  483. package/prompts/parallel-review.md +2 -0
  484. package/prompts/review-loop.md +2 -0
  485. package/scripts/build.mjs +129 -85
  486. package/scripts/check-compat.mjs +48 -11
  487. package/scripts/compat-host.mjs +35 -7
  488. package/scripts/generate-run-schemas.mjs +210 -0
  489. package/scripts/intercom-bridge-credentials.mjs +158 -29
  490. package/scripts/intercom-remote.mjs +213 -52
  491. package/scripts/local-install-smoke.mjs +47 -37
  492. package/scripts/native-package-smoke.mjs +135 -25
  493. package/scripts/package-smoke.mjs +360 -140
  494. package/scripts/prepare.mjs +54 -34
  495. package/scripts/real-pi-processes.mjs +261 -0
  496. package/scripts/real-pi-smoke.mjs +432 -351
  497. package/scripts/run-tests.mjs +29 -15
  498. package/skills/pi-intercom/SKILL.md +11 -11
  499. package/skills/pi-intercom/references/peer-sessions.md +7 -2
  500. package/skills/pi-subagents/SKILL.md +1 -1
  501. package/skills/pi-subagents/references/full-orchestration-guide.md +254 -112
  502. package/src/agents/agent-defaults.ts +13 -0
  503. package/src/agents/agent-definition.ts +253 -0
  504. package/src/agents/agent-management.ts +111 -808
  505. package/src/agents/agent-scope.ts +7 -3
  506. package/src/agents/agent-selection.ts +26 -16
  507. package/src/agents/agent-serializer.ts +84 -93
  508. package/src/agents/agents.ts +199 -906
  509. package/src/agents/builtin-overrides.ts +297 -0
  510. package/src/agents/chain-serializer.ts +3 -329
  511. package/src/agents/config-values.ts +57 -0
  512. package/src/agents/discovery-paths.ts +134 -0
  513. package/src/agents/frontmatter.ts +35 -17
  514. package/src/agents/identity.ts +49 -18
  515. package/src/agents/json-chain.ts +305 -0
  516. package/src/agents/management-config.ts +342 -0
  517. package/src/agents/management-format.ts +243 -0
  518. package/src/agents/management-persistence.ts +408 -0
  519. package/src/agents/management-targets.ts +260 -0
  520. package/src/agents/management-warnings.ts +115 -0
  521. package/src/agents/markdown-chain.ts +237 -0
  522. package/src/agents/package-agents.ts +231 -0
  523. package/src/agents/skill-files.ts +182 -0
  524. package/src/agents/skill-search-paths.ts +289 -0
  525. package/src/agents/skill-types.ts +31 -0
  526. package/src/agents/skills.ts +152 -610
  527. package/src/extension/acceptance-schema.ts +88 -0
  528. package/src/extension/chain-schema.ts +276 -0
  529. package/src/extension/child-runtime.ts +302 -0
  530. package/src/extension/compact-tools.ts +259 -102
  531. package/src/extension/config-schema.ts +59 -0
  532. package/src/extension/config.ts +39 -17
  533. package/src/extension/control-notice-schema.ts +55 -0
  534. package/src/extension/control-notices.ts +57 -33
  535. package/src/extension/delegation-bridges.ts +59 -0
  536. package/src/extension/doctor.ts +171 -135
  537. package/src/extension/everyday-schemas.ts +252 -0
  538. package/src/extension/fanout-child.ts +29 -308
  539. package/src/extension/index.ts +17 -642
  540. package/src/extension/message-renderers.ts +334 -0
  541. package/src/extension/nested-control-inbox.ts +196 -0
  542. package/src/extension/parent-runtime.ts +405 -0
  543. package/src/extension/primary-tool.ts +130 -0
  544. package/src/extension/result-snapshot.ts +35 -0
  545. package/src/extension/runtime-reload.ts +72 -0
  546. package/src/extension/runtime-storage.ts +49 -0
  547. package/src/extension/schema-overrides.ts +114 -0
  548. package/src/extension/schemas.ts +451 -418
  549. package/src/extension/tool-input.ts +40 -13
  550. package/src/extension/tool-result.ts +45 -14
  551. package/src/history/answer-texts.ts +74 -0
  552. package/src/history/canonical-result.ts +127 -51
  553. package/src/history/canonical-selection.ts +54 -0
  554. package/src/history/database-generation.ts +86 -0
  555. package/src/history/database.ts +86 -48
  556. package/src/history/entry-ingestion.ts +129 -0
  557. package/src/history/index.ts +426 -148
  558. package/src/history/ingest.ts +372 -342
  559. package/src/history/output-digests.ts +41 -0
  560. package/src/history/preview.ts +235 -0
  561. package/src/history/prune.ts +48 -0
  562. package/src/history/queries.ts +122 -256
  563. package/src/history/query-scope.ts +278 -0
  564. package/src/history/rows.ts +118 -0
  565. package/src/history/run-projection.ts +164 -0
  566. package/src/history/run-queries.ts +199 -0
  567. package/src/history/schema.ts +34 -0
  568. package/src/history/search-queries.ts +216 -0
  569. package/src/history/selected-record.ts +140 -0
  570. package/src/history/source-file.ts +51 -0
  571. package/src/history/source-watches.ts +156 -0
  572. package/src/history/store.ts +310 -197
  573. package/src/history/text-chunks.ts +181 -0
  574. package/src/history/text.ts +43 -0
  575. package/src/history/transcript-queries.ts +251 -0
  576. package/src/history/types.ts +27 -164
  577. package/src/history/values.ts +36 -0
  578. package/src/history/wire-inputs.ts +141 -0
  579. package/src/history/wire-models.ts +51 -0
  580. package/src/history/worker-runtime.ts +502 -0
  581. package/src/history/worker.ts +94 -336
  582. package/src/intercom/intercom-bridge.ts +136 -69
  583. package/src/intercom/live-intercom.ts +197 -92
  584. package/src/intercom/nested-result-tree.ts +213 -0
  585. package/src/intercom/result-delivery.ts +56 -0
  586. package/src/intercom/result-intercom.ts +364 -382
  587. package/src/pi-intercom/agent-dir.ts +9 -3
  588. package/src/pi-intercom/async.ts +33 -0
  589. package/src/pi-intercom/bridge-ask.ts +64 -0
  590. package/src/pi-intercom/bridge-config.ts +120 -0
  591. package/src/pi-intercom/bridge-http.ts +97 -0
  592. package/src/pi-intercom/bridge-launch-policy.ts +109 -0
  593. package/src/pi-intercom/bridge-launch.ts +317 -0
  594. package/src/pi-intercom/bridge-protocol.ts +123 -0
  595. package/src/pi-intercom/bridge-routes.ts +105 -0
  596. package/src/pi-intercom/bridge-rpc-process.ts +293 -0
  597. package/src/pi-intercom/bridge-session.ts +510 -0
  598. package/src/pi-intercom/bridge.ts +305 -549
  599. package/src/pi-intercom/broker/broker.ts +326 -263
  600. package/src/pi-intercom/broker/client.ts +273 -354
  601. package/src/pi-intercom/broker/connection.ts +192 -0
  602. package/src/pi-intercom/broker/framing.ts +11 -6
  603. package/src/pi-intercom/broker/paths.ts +28 -25
  604. package/src/pi-intercom/broker/pid.ts +68 -24
  605. package/src/pi-intercom/broker/snapshot-reader.ts +91 -0
  606. package/src/pi-intercom/broker/snapshots.ts +241 -0
  607. package/src/pi-intercom/broker/spawn.ts +58 -34
  608. package/src/pi-intercom/config.ts +113 -108
  609. package/src/pi-intercom/connection.ts +346 -0
  610. package/src/pi-intercom/identity.ts +71 -0
  611. package/src/pi-intercom/inbound-delivery.ts +450 -0
  612. package/src/pi-intercom/inbound-journal.ts +350 -0
  613. package/src/pi-intercom/inbound-record.ts +141 -0
  614. package/src/pi-intercom/inbound.ts +237 -0
  615. package/src/pi-intercom/index.ts +86 -2923
  616. package/src/pi-intercom/inspection.ts +82 -0
  617. package/src/pi-intercom/interview.ts +295 -0
  618. package/src/pi-intercom/lifecycle.ts +183 -0
  619. package/src/pi-intercom/message-format.ts +77 -0
  620. package/src/pi-intercom/outbound.ts +418 -0
  621. package/src/pi-intercom/peer-awareness.ts +84 -0
  622. package/src/pi-intercom/reply-tracker.ts +121 -59
  623. package/src/pi-intercom/reply-wait.ts +247 -0
  624. package/src/pi-intercom/runtime-types.ts +97 -0
  625. package/src/pi-intercom/session-events.ts +247 -0
  626. package/src/pi-intercom/session-targets.ts +124 -72
  627. package/src/pi-intercom/subagent-events.ts +299 -0
  628. package/src/pi-intercom/subagent-live-events.ts +212 -109
  629. package/src/pi-intercom/supervisor.ts +362 -0
  630. package/src/pi-intercom/tool-arguments.ts +120 -0
  631. package/src/pi-intercom/tool-registration.ts +121 -0
  632. package/src/pi-intercom/tool-results.ts +54 -0
  633. package/src/pi-intercom/tool-schemas.ts +134 -0
  634. package/src/pi-intercom/tools.ts +80 -0
  635. package/src/pi-intercom/topic-actions.ts +243 -0
  636. package/src/pi-intercom/topics.ts +267 -121
  637. package/src/pi-intercom/transport.ts +14 -0
  638. package/src/pi-intercom/types.ts +288 -190
  639. package/src/pi-intercom/ui/compose-paste.ts +109 -0
  640. package/src/pi-intercom/ui/compose.ts +173 -157
  641. package/src/pi-intercom/ui/inline-message.ts +80 -62
  642. package/src/pi-intercom/ui/message-renderers.ts +182 -0
  643. package/src/pi-intercom/ui/overlay.ts +238 -0
  644. package/src/pi-intercom/ui/session-format.ts +146 -0
  645. package/src/pi-intercom/ui/session-list.ts +145 -62
  646. package/src/pi-intercom/ui/tool-renderers.ts +148 -0
  647. package/src/pi-intercom/ui/topic-view.ts +107 -0
  648. package/src/pi-intercom/validation.ts +69 -0
  649. package/src/runs/background/async-chain-plan.ts +451 -0
  650. package/src/runs/background/async-control.ts +201 -71
  651. package/src/runs/background/async-execution.ts +206 -829
  652. package/src/runs/background/async-job-admission.ts +54 -0
  653. package/src/runs/background/async-job-projection.ts +225 -0
  654. package/src/runs/background/async-job-tracker.ts +416 -360
  655. package/src/runs/background/async-launch.ts +319 -0
  656. package/src/runs/background/async-plan.ts +285 -0
  657. package/src/runs/background/async-result-file.ts +79 -37
  658. package/src/runs/background/async-resume.ts +338 -285
  659. package/src/runs/background/async-run-discovery.ts +270 -0
  660. package/src/runs/background/async-run-location.ts +194 -0
  661. package/src/runs/background/async-run-record.ts +14 -0
  662. package/src/runs/background/async-run-repair.ts +307 -0
  663. package/src/runs/background/async-run-summary.ts +71 -0
  664. package/src/runs/background/async-single-plan.ts +168 -0
  665. package/src/runs/background/async-status-projection.ts +188 -0
  666. package/src/runs/background/async-status-render.ts +164 -0
  667. package/src/runs/background/async-status-validation.ts +238 -0
  668. package/src/runs/background/async-status.ts +9 -481
  669. package/src/runs/background/async-value.ts +29 -0
  670. package/src/runs/background/completion-dedupe.ts +103 -54
  671. package/src/runs/background/completion-delivery.ts +313 -187
  672. package/src/runs/background/completion-receipts.ts +309 -0
  673. package/src/runs/background/legacy-status-acceptance.ts +38 -0
  674. package/src/runs/background/notify.ts +167 -106
  675. package/src/runs/background/parallel-groups.ts +95 -46
  676. package/src/runs/background/result-payload.ts +268 -0
  677. package/src/runs/background/result-watcher.ts +484 -387
  678. package/src/runs/background/run-id-resolver.ts +126 -57
  679. package/src/runs/background/run-schemas.ts +240 -0
  680. package/src/runs/background/run-status-contracts.ts +46 -0
  681. package/src/runs/background/run-status-render.ts +364 -0
  682. package/src/runs/background/run-status.ts +338 -356
  683. package/src/runs/background/runner-attempt-output.ts +281 -0
  684. package/src/runs/background/runner-attempt.ts +354 -0
  685. package/src/runs/background/runner-child-executor.ts +232 -0
  686. package/src/runs/background/runner-child-observer.ts +270 -0
  687. package/src/runs/background/runner-completion-summary.ts +106 -0
  688. package/src/runs/background/runner-completion.ts +274 -0
  689. package/src/runs/background/runner-config.ts +52 -0
  690. package/src/runs/background/runner-contract.ts +51 -0
  691. package/src/runs/background/runner-dynamic.ts +185 -0
  692. package/src/runs/background/runner-finalization.ts +203 -0
  693. package/src/runs/background/runner-graph.ts +91 -0
  694. package/src/runs/background/runner-initial-status.ts +72 -0
  695. package/src/runs/background/runner-lifecycle.ts +159 -0
  696. package/src/runs/background/runner-monitor.ts +399 -0
  697. package/src/runs/background/runner-parallel.ts +280 -0
  698. package/src/runs/background/runner-prepare-step.ts +128 -0
  699. package/src/runs/background/runner-reporting.ts +192 -0
  700. package/src/runs/background/runner-status.ts +220 -0
  701. package/src/runs/background/runner-step-output.ts +158 -0
  702. package/src/runs/background/runner-step-record.ts +76 -0
  703. package/src/runs/background/runner-step.ts +150 -0
  704. package/src/runs/background/runner-streaming.ts +220 -0
  705. package/src/runs/background/runner-workflow.ts +284 -0
  706. package/src/runs/background/stale-run-reconciler.ts +279 -336
  707. package/src/runs/background/subagent-runner-launcher.ts +67 -35
  708. package/src/runs/background/subagent-runner.ts +80 -2048
  709. package/src/runs/background/top-level-async.ts +9 -7
  710. package/src/runs/foreground/chain-clarify.ts +499 -1334
  711. package/src/runs/foreground/clarification-draft.ts +92 -0
  712. package/src/runs/foreground/clarify-contracts.ts +33 -0
  713. package/src/runs/foreground/clarify-invocation.ts +192 -65
  714. package/src/runs/foreground/clarify-text-editor.ts +229 -0
  715. package/src/runs/foreground/clarify-view.ts +222 -0
  716. package/src/runs/foreground/execution-input.ts +358 -424
  717. package/src/runs/foreground/execution-routing.ts +41 -0
  718. package/src/runs/foreground/execution-timeout.ts +92 -0
  719. package/src/runs/foreground/foreground-control.ts +333 -812
  720. package/src/runs/foreground/foreground-memory.ts +132 -0
  721. package/src/runs/foreground/invocation-context.ts +88 -0
  722. package/src/runs/foreground/invocation-execution.ts +465 -0
  723. package/src/runs/foreground/invocation-expansion.ts +58 -0
  724. package/src/runs/foreground/management-actions.ts +360 -0
  725. package/src/runs/foreground/nested-control.ts +248 -0
  726. package/src/runs/foreground/question-continuation.ts +112 -0
  727. package/src/runs/foreground/question-control.ts +297 -70
  728. package/src/runs/foreground/resume-target.ts +330 -0
  729. package/src/runs/foreground/revival-launch-policy.ts +112 -0
  730. package/src/runs/foreground/run-async-path.ts +307 -223
  731. package/src/runs/foreground/run-interrupt.ts +202 -0
  732. package/src/runs/foreground/run-nudge.ts +355 -0
  733. package/src/runs/foreground/saved-revival.ts +356 -0
  734. package/src/runs/foreground/subagent-executor.ts +195 -493
  735. package/src/runs/foreground/subagent-params.ts +314 -242
  736. package/src/runs/foreground/wait-observation.ts +160 -0
  737. package/src/runs/foreground/wait-registration.ts +18 -0
  738. package/src/runs/foreground/wait-run.ts +361 -119
  739. package/src/runs/shared/acceptance-contract.ts +410 -209
  740. package/src/runs/shared/acceptance-defaults.ts +1 -0
  741. package/src/runs/shared/acceptance-evaluation.ts +314 -240
  742. package/src/runs/shared/acceptance-finalization.ts +447 -305
  743. package/src/runs/shared/acceptance-outcome.ts +69 -0
  744. package/src/runs/shared/acceptance-reports.ts +220 -126
  745. package/src/runs/shared/acceptance-submission.ts +251 -0
  746. package/src/runs/shared/acceptance-verification.ts +118 -0
  747. package/src/runs/shared/acceptance.ts +25 -25
  748. package/src/runs/shared/chain-outputs.ts +190 -98
  749. package/src/runs/shared/child-attempt-types.ts +118 -0
  750. package/src/runs/shared/child-attempt.ts +372 -608
  751. package/src/runs/shared/child-boundaries.ts +217 -0
  752. package/src/runs/shared/child-context-filter.ts +53 -0
  753. package/src/runs/shared/child-event-observer.ts +496 -0
  754. package/src/runs/shared/child-execution-cwd.ts +139 -68
  755. package/src/runs/shared/child-execution-outcome.ts +103 -0
  756. package/src/runs/shared/child-invocation.ts +74 -0
  757. package/src/runs/shared/child-message-validation.ts +233 -0
  758. package/src/runs/shared/child-native-accounting.ts +154 -0
  759. package/src/runs/shared/child-native-observation.ts +79 -0
  760. package/src/runs/shared/child-observation-spool.ts +188 -0
  761. package/src/runs/shared/child-observations.ts +219 -89
  762. package/src/runs/shared/child-presence.ts +6 -0
  763. package/src/runs/shared/child-route-env.ts +142 -0
  764. package/src/runs/shared/child-stream-observer.ts +302 -0
  765. package/src/runs/shared/child-stream-projection.ts +160 -0
  766. package/src/runs/shared/child-structured-tool.ts +38 -0
  767. package/src/runs/shared/claude-code.ts +201 -228
  768. package/src/runs/shared/claude-model.ts +67 -0
  769. package/src/runs/shared/claude-session.ts +124 -0
  770. package/src/runs/shared/claude-types.ts +31 -0
  771. package/src/runs/shared/completion-guard.ts +35 -26
  772. package/src/runs/shared/control-event-policy.ts +15 -0
  773. package/src/runs/shared/control-notification-owner.ts +20 -0
  774. package/src/runs/shared/dynamic-fanout.ts +402 -238
  775. package/src/runs/shared/dynamic-item.ts +114 -0
  776. package/src/runs/shared/history-index.ts +112 -51
  777. package/src/runs/shared/legacy-async-recovery.ts +153 -0
  778. package/src/runs/shared/legacy-output-recovery.ts +214 -0
  779. package/src/runs/shared/mcp-config-schema.ts +46 -0
  780. package/src/runs/shared/mcp-direct-tool-allowlist.ts +396 -307
  781. package/src/runs/shared/model-fallback.ts +302 -180
  782. package/src/runs/shared/mutating-tool-guard.ts +259 -158
  783. package/src/runs/shared/native-finalization-types.ts +29 -0
  784. package/src/runs/shared/native-finalization.ts +233 -109
  785. package/src/runs/shared/native-usage.ts +379 -96
  786. package/src/runs/shared/nested-control-records.ts +178 -0
  787. package/src/runs/shared/nested-events.ts +45 -752
  788. package/src/runs/shared/nested-path.ts +47 -34
  789. package/src/runs/shared/nested-projection.ts +230 -0
  790. package/src/runs/shared/nested-protocol.ts +67 -0
  791. package/src/runs/shared/nested-registry.ts +273 -0
  792. package/src/runs/shared/nested-render.ts +198 -100
  793. package/src/runs/shared/nested-route.ts +292 -0
  794. package/src/runs/shared/nested-validation.ts +291 -0
  795. package/src/runs/shared/owned-child-evidence.ts +184 -0
  796. package/src/runs/shared/owned-run-list.ts +187 -0
  797. package/src/runs/shared/owned-run-observation.ts +368 -0
  798. package/src/runs/shared/owned-run-progress.ts +172 -0
  799. package/src/runs/shared/owned-run-read-state.ts +7 -0
  800. package/src/runs/shared/owned-run-results.ts +289 -0
  801. package/src/runs/shared/owned-run-status.ts +239 -0
  802. package/src/runs/shared/owned-run-view.ts +65 -0
  803. package/src/runs/shared/owned-workflow-details.ts +24 -0
  804. package/src/runs/shared/owner-output.ts +73 -0
  805. package/src/runs/shared/parallel-utils.ts +93 -129
  806. package/src/runs/shared/parent-receipts.ts +177 -50
  807. package/src/runs/shared/parent-usage.ts +314 -91
  808. package/src/runs/shared/pi-args.ts +241 -311
  809. package/src/runs/shared/pi-launch-input.ts +48 -0
  810. package/src/runs/shared/pi-session-launch.ts +94 -0
  811. package/src/runs/shared/pi-spawn.ts +57 -33
  812. package/src/runs/shared/run-history-queries.ts +189 -38
  813. package/src/runs/shared/run-history.ts +197 -76
  814. package/src/runs/shared/run-id-ambiguity.ts +7 -3
  815. package/src/runs/shared/run-metadata-paths.ts +17 -0
  816. package/src/runs/shared/run-metadata.ts +240 -0
  817. package/src/runs/shared/run-persistence.ts +181 -0
  818. package/src/runs/shared/run-records.ts +19 -607
  819. package/src/runs/shared/run-restoration.ts +455 -0
  820. package/src/runs/shared/run-state-owner.ts +31 -0
  821. package/src/runs/shared/session-cwd-preload.ts +39 -19
  822. package/src/runs/shared/single-output.ts +358 -205
  823. package/src/runs/shared/stable-value.ts +15 -0
  824. package/src/runs/shared/streaming-text.ts +39 -12
  825. package/src/runs/shared/structured-output.ts +76 -46
  826. package/src/runs/shared/subagent-control.ts +330 -197
  827. package/src/runs/shared/subagent-prompt-runtime.ts +92 -174
  828. package/src/runs/shared/subagent-tool-loop-guard.ts +118 -68
  829. package/src/runs/shared/supervisor-question-state.ts +221 -0
  830. package/src/runs/shared/supervisor-questions.ts +396 -401
  831. package/src/runs/shared/workflow-graph.ts +400 -198
  832. package/src/runs/shared/workflow-policy.ts +245 -110
  833. package/src/runs/shared/worktree-contract.ts +29 -0
  834. package/src/runs/shared/worktree-hook.ts +181 -0
  835. package/src/runs/shared/worktree-location.ts +61 -0
  836. package/src/runs/shared/worktree-preservation.ts +10 -0
  837. package/src/runs/shared/worktree-process.ts +132 -0
  838. package/src/runs/shared/worktree.ts +459 -587
  839. package/src/shared/agent-context-policy.ts +176 -145
  840. package/src/shared/agent-dir.ts +15 -0
  841. package/src/shared/artifacts.ts +99 -68
  842. package/src/shared/atomic-json.ts +14 -11
  843. package/src/shared/chain-files.ts +72 -0
  844. package/src/shared/concurrency.ts +27 -0
  845. package/src/shared/content-preview.ts +117 -0
  846. package/src/shared/cooperative.ts +17 -13
  847. package/src/shared/execution-cwd.ts +34 -9
  848. package/src/shared/file-coalescer.ts +24 -22
  849. package/src/shared/fork-context.ts +52 -48
  850. package/src/shared/formatters.ts +88 -47
  851. package/src/shared/journal-frames.ts +197 -0
  852. package/src/shared/journal-projections.ts +133 -0
  853. package/src/shared/journal-reader.ts +18 -333
  854. package/src/shared/json-projection.ts +224 -0
  855. package/src/shared/lazy-tools.ts +76 -27
  856. package/src/shared/message-output.ts +146 -0
  857. package/src/shared/model-info.ts +94 -58
  858. package/src/shared/native-import.ts +25 -0
  859. package/src/shared/native-journal.ts +172 -0
  860. package/src/shared/native-session-loader.ts +13 -0
  861. package/src/shared/native-session.ts +3 -5
  862. package/src/shared/native-tui.ts +13 -3
  863. package/src/shared/native-typebox.ts +18 -3
  864. package/src/shared/output-page.ts +76 -0
  865. package/src/shared/post-exit-stdio-guard.ts +232 -172
  866. package/src/shared/prompt-sections.ts +13 -7
  867. package/src/shared/session-entries.ts +103 -44
  868. package/src/shared/session-identity.ts +17 -10
  869. package/src/shared/settings.ts +182 -367
  870. package/src/shared/status-format.ts +207 -98
  871. package/src/shared/stream-json.d.ts +10 -0
  872. package/src/shared/task-file-policy.ts +35 -0
  873. package/src/shared/temp-root.ts +122 -71
  874. package/src/shared/types/acceptance.ts +149 -0
  875. package/src/shared/types/async.ts +247 -0
  876. package/src/shared/types/config.ts +139 -0
  877. package/src/shared/types/details.ts +104 -0
  878. package/src/shared/types/history.ts +217 -0
  879. package/src/shared/types/inputs.ts +4 -0
  880. package/src/shared/types/intercom.ts +57 -0
  881. package/src/shared/types/launch.ts +39 -0
  882. package/src/shared/types/messages.ts +104 -0
  883. package/src/shared/types/nested.ts +153 -0
  884. package/src/shared/types/owned-runs.ts +148 -0
  885. package/src/shared/types/progress.ts +106 -0
  886. package/src/shared/types/questions.ts +103 -0
  887. package/src/shared/types/results.ts +119 -0
  888. package/src/shared/types/state.ts +56 -0
  889. package/src/shared/types/usage.ts +36 -0
  890. package/src/shared/types/workflow.ts +187 -0
  891. package/src/shared/types.ts +222 -1161
  892. package/src/shared/ui-mode.ts +1 -1
  893. package/src/shared/unknown.ts +59 -0
  894. package/src/shared/utils.ts +111 -305
  895. package/src/slash/command-discovery.ts +109 -0
  896. package/src/slash/command-input.ts +232 -0
  897. package/src/slash/prompt-template-bridge.ts +153 -400
  898. package/src/slash/prompt-template-contract.ts +152 -0
  899. package/src/slash/prompt-template-results.ts +189 -0
  900. package/src/slash/request-protocol.ts +87 -0
  901. package/src/slash/result-delivery.ts +312 -0
  902. package/src/slash/saved-chain.ts +115 -0
  903. package/src/slash/slash-bridge.ts +202 -156
  904. package/src/slash/slash-commands.ts +176 -598
  905. package/src/slash/slash-live-state.ts +287 -229
  906. package/src/tui/action-hints.ts +147 -61
  907. package/src/tui/activity-lines.ts +40 -0
  908. package/src/tui/agent-browser.ts +354 -0
  909. package/src/tui/agent-controls.ts +355 -0
  910. package/src/tui/agent-conversation.ts +514 -0
  911. package/src/tui/agent-dock.ts +250 -0
  912. package/src/tui/agent-history.ts +78 -203
  913. package/src/tui/agent-model.ts +78 -0
  914. package/src/tui/agent-picker.ts +325 -0
  915. package/src/tui/agent-view.ts +391 -1333
  916. package/src/tui/compact-results.ts +342 -0
  917. package/src/tui/conversation-details.ts +206 -0
  918. package/src/tui/conversation-frame.ts +184 -0
  919. package/src/tui/conversation-history.ts +246 -0
  920. package/src/tui/conversation-menu.ts +119 -0
  921. package/src/tui/conversation-notices.ts +116 -0
  922. package/src/tui/conversation-selection.ts +66 -0
  923. package/src/tui/conversation-viewport.ts +169 -0
  924. package/src/tui/direction-message.ts +35 -0
  925. package/src/tui/display.ts +409 -0
  926. package/src/tui/editor-viewport.ts +19 -0
  927. package/src/tui/expanded-content.ts +134 -0
  928. package/src/tui/expanded-multi.ts +264 -0
  929. package/src/tui/expanded-single.ts +92 -0
  930. package/src/tui/history-cards.ts +316 -0
  931. package/src/tui/history-display.ts +334 -0
  932. package/src/tui/history-json.ts +17 -0
  933. package/src/tui/history-metadata.ts +177 -0
  934. package/src/tui/history-record.ts +321 -0
  935. package/src/tui/history-text.ts +34 -0
  936. package/src/tui/indexed-history.ts +149 -0
  937. package/src/tui/nested-widget.ts +192 -0
  938. package/src/tui/picker-page.ts +80 -0
  939. package/src/tui/render.ts +100 -1546
  940. package/src/tui/result-facts.ts +99 -0
  941. package/src/tui/task-observation.ts +96 -0
  942. package/src/tui/task-store.ts +432 -0
  943. package/src/tui/text-values.ts +20 -0
  944. package/src/tui/view-connections.ts +64 -0
  945. package/src/tui/view-model.ts +181 -0
  946. package/src/tui/view-persistence.ts +57 -0
  947. package/src/tui/view-ports.ts +55 -0
  948. package/src/tui/view-session.ts +42 -0
  949. package/src/tui/widget-details.ts +220 -0
  950. package/src/tui/widget-status.ts +331 -0
  951. package/src/tui/widget.ts +208 -0
  952. package/src/tui/workflow-labels.ts +340 -0
  953. package/src/tui/workflow-outcomes.ts +150 -0
  954. package/tsconfig.build.json +11 -10
  955. package/tsconfig.json +30 -17
@@ -5,419 +5,516 @@ import { getRunMetadataDir } from "../shared/supervisor-questions.ts";
5
5
  import { buildCompletionKey, markSeenWithTtl } from "./completion-dedupe.ts";
6
6
  import { createFileCoalescer } from "../../shared/file-coalescer.ts";
7
7
  import { journalStamp } from "../../shared/journal-reader.ts";
8
- import { resolveOrchestratorIntercomTarget } from "../../intercom/intercom-bridge.ts";
9
8
  import {
10
- SUBAGENT_ASYNC_COMPLETE_EVENT,
11
- type IntercomEventBus,
12
- type NestedRunSummary,
13
- type SubagentResultIntercomChild,
14
- type SubagentState,
9
+ SUBAGENT_ASYNC_COMPLETE_EVENT,
10
+ type IntercomEventBus,
11
+ type SubagentState,
12
+ type OwnedRun,
15
13
  } from "../../shared/types.ts";
14
+ import type { ReadonlyInput } from "../../shared/types/inputs.ts";
16
15
  import {
17
- attachNestedChildrenToResultChildren,
18
- buildSubagentResultIntercomPayload,
19
- compactNestedResultChildren,
20
- deliverSubagentResultIntercomEvent,
21
- resolveSubagentResultStatus,
22
- } from "../../intercom/result-intercom.ts";
23
- import { projectNestedRegistryForRoot, sanitizeSummary } from "../shared/nested-events.ts";
24
- import { isDurableRun, readAsyncResultFile } from "./async-result-file.ts";
16
+ completionEvent,
17
+ deliverResultIntercom,
18
+ prepareResult,
19
+ readResultEnvelope,
20
+ type ResultEnvelope,
21
+ type PreparedResult,
22
+ } from "./result-payload.ts";
23
+ import { errorCode, hasText } from "./async-value.ts";
25
24
 
26
- const WATCHER_RESTART_DELAY_MS = 3000;
25
+ const RESTART_DELAY_MS = 3000;
27
26
  const POLL_INTERVAL_MS = 3000;
28
-
29
- type ResultWatcherDeps = {
30
- reconcileDelivery?: (runId: string, completionKey: string, accounting?: boolean) => boolean;
31
- isCompletionPublished?: (runId: string, completionKey: string) => boolean;
32
- withReceiptBatch?: (work: () => void) => void;
33
- };
34
-
35
- function sanitizeNestedResultChildren(value: unknown, resultPath: string, label: string): NestedRunSummary[] | undefined {
36
- if (value === undefined) return undefined;
37
- if (!Array.isArray(value)) {
38
- console.error(`Ignoring invalid nested children in subagent result file '${resultPath}' at ${label}: expected an array.`);
39
- return undefined;
40
- }
41
- const children = value.map((child) => sanitizeSummary(child)).filter((child): child is NestedRunSummary => Boolean(child));
42
- if (children.length !== value.length) {
43
- console.error(`Ignoring ${value.length - children.length} invalid nested child record(s) in subagent result file '${resultPath}' at ${label}.`);
44
- }
45
- return children.length ? children : undefined;
27
+ interface ResultWatcherDeps {
28
+ readonly reconcileDelivery?: (
29
+ runId: string,
30
+ completionKey: string,
31
+ accounting?: boolean,
32
+ ) => boolean;
33
+ readonly isCompletionPublished?: (runId: string, completionKey: string) => boolean;
34
+ readonly withReceiptBatch?: (work: () => void) => void;
46
35
  }
47
-
48
- function getErrorCode(error: unknown): string | undefined {
49
- return typeof error === "object" && error !== null && "code" in error
50
- ? (error as NodeJS.ErrnoException).code
51
- : undefined;
36
+ interface StopOptions {
37
+ readonly preservePending?: boolean;
38
+ readonly joinInFlight?: boolean;
52
39
  }
53
-
54
- function isNotFoundError(error: unknown): boolean {
55
- if (getErrorCode(error) === "ENOENT") return true;
56
- const cause = error instanceof Error ? error.cause : undefined;
57
- return getErrorCode(cause) === "ENOENT";
40
+ interface ResultWatcherHandle {
41
+ readonly startResultWatcher: () => void;
42
+ readonly primeExistingResults: () => void;
43
+ readonly stopResultWatcher: (options?: StopOptions) => void;
44
+ readonly joinInFlight: () => Promise<void>;
58
45
  }
59
-
60
- function shouldFallBackToPolling(error: unknown): boolean {
61
- const code = getErrorCode(error);
62
- return code === "EMFILE" || code === "ENOSPC";
46
+ interface ForeignResult {
47
+ readonly stamp: string;
48
+ readonly sessionId: string | null;
49
+ readonly runId: string;
50
+ readonly ownerSessionId?: string;
51
+ readonly canonicalPath?: string;
52
+ readonly canonicalStamp?: string;
53
+ }
54
+ function notFound(error: unknown): boolean {
55
+ return (
56
+ errorCode(error) === "ENOENT" ||
57
+ errorCode(error instanceof Error ? error.cause : undefined) === "ENOENT"
58
+ );
59
+ }
60
+ function pollingRequired(error: unknown): boolean {
61
+ const code = errorCode(error);
62
+ return code === "EMFILE" || code === "ENOSPC";
63
63
  }
64
64
 
65
- export function createResultWatcher(
66
- pi: { events: IntercomEventBus },
67
- state: SubagentState,
68
- resultsDir: string,
69
- deps: ResultWatcherDeps = {},
70
- ): {
71
- startResultWatcher: () => void;
72
- primeExistingResults: () => void;
73
- stopResultWatcher: (options?: { preservePending?: boolean; joinInFlight?: boolean }) => void;
74
- joinInFlight: () => Promise<void>;
75
- } {
76
- let periodicScanTimer: ReturnType<typeof setInterval> | null = null;
77
- const processingCompletionKeys = new Set<string>();
78
- const inFlight = new Set<Promise<void>>();
79
- let startTail = Promise.resolve(), generation = 0, preserveBeforeGeneration = 0;
80
- let joiningGeneration: number | undefined;
81
- const foreignResults = new Map<string, { stamp: string; sessionId: string | null; runId: string; ownerSessionId?: string; canonicalPath?: string; canonicalStamp?: string }>();
65
+ /** Owns admitted background deliveries, watcher resources, and shutdown generations. */
66
+ class ResultWatcher {
67
+ private readonly pi: ReadonlyInput<{ events: IntercomEventBus }>;
68
+ private readonly state: SubagentState;
69
+ private readonly resultsDir: string;
70
+ private readonly deps: ResultWatcherDeps;
71
+ private periodicScanTimer: ReturnType<typeof setInterval> | null = null;
72
+ private readonly processingCompletionKeys = new Set<string>();
73
+ private readonly inFlight = new Set<Promise<void>>();
74
+ private startTail = Promise.resolve();
75
+ private generation = 0;
76
+ private preserveBeforeGeneration = 0;
77
+ private joiningGeneration: number | undefined;
78
+ private readonly foreignResults = new Map<string, ForeignResult>();
79
+ private readonly scheduled = new Set<string>();
80
+ private drainGeneration: number | undefined;
81
+
82
+ constructor(
83
+ pi: ReadonlyInput<{ events: IntercomEventBus }>,
84
+ state: SubagentState,
85
+ resultsDir: string,
86
+ deps: ResultWatcherDeps,
87
+ ) {
88
+ this.pi = pi;
89
+ this.state = state;
90
+ this.resultsDir = resultsDir;
91
+ this.deps = deps;
92
+ this.state.resultFileCoalescer = createFileCoalescer(this.scheduleResult, 50);
93
+ }
82
94
 
83
- const pendingResultFiles = () => {
84
- const files = fs.existsSync(resultsDir) ? fs.readdirSync(resultsDir).filter((name) => name.endsWith(".json")) : [];
85
- const notified = new Map(files.map((file, index) => [file, index]));
86
- for (const run of state.ownedRuns?.values() ?? []) {
87
- if (run.source !== "async" || run.accounting?.state !== "incomplete" && run.delivery?.entryId) continue;
88
- const file = path.join(getRunMetadataDir(run.runId), "result.json");
89
- if (!fs.existsSync(file)) continue;
90
- // Disposable hints cannot veto canonical recovery, including corrupt hints.
91
- const notification = notified.get(`${run.runId}.json`);
92
- if (notification === undefined) files.push(file);
93
- else files[notification] = file;
94
- }
95
- const present = new Set(files.map((file) => path.isAbsolute(file) ? file : path.join(resultsDir, file)));
96
- for (const file of foreignResults.keys()) if (!present.has(file)) foreignResults.delete(file);
97
- return files.filter((file) => {
98
- const resultPath = path.isAbsolute(file) ? file : path.join(resultsDir, file);
99
- try { return !isForeignUnchanged(resultPath); }
100
- catch (error) { if (isNotFoundError(error)) { foreignResults.delete(resultPath); return false; } return true; }
101
- });
102
- };
95
+ private isForeignUnchanged(resultPath: string): boolean {
96
+ const cached = this.foreignResults.get(resultPath);
97
+ if (
98
+ !cached ||
99
+ cached.sessionId !== this.state.currentSessionId ||
100
+ cached.ownerSessionId !== this.state.ownedRuns?.get(cached.runId)?.ownerSessionId
101
+ ) {
102
+ return false;
103
+ }
104
+ return (
105
+ cached.stamp === journalStamp(fs.statSync(resultPath, { bigint: true })) &&
106
+ (cached.canonicalPath === undefined ||
107
+ cached.canonicalStamp === journalStamp(fs.statSync(cached.canonicalPath, { bigint: true })))
108
+ );
109
+ }
103
110
 
104
- const isForeignUnchanged = (resultPath: string): boolean => {
105
- const cached = foreignResults.get(resultPath);
106
- if (!cached || cached.sessionId !== state.currentSessionId || cached.ownerSessionId !== state.ownedRuns?.get(cached.runId)?.ownerSessionId) return false;
107
- return cached.stamp === journalStamp(fs.statSync(resultPath, { bigint: true }))
108
- && (!cached.canonicalPath || cached.canonicalStamp === journalStamp(fs.statSync(cached.canonicalPath, { bigint: true })));
109
- };
111
+ private resultPath(file: string): string {
112
+ return path.isAbsolute(file) ? file : path.join(this.resultsDir, file);
113
+ }
114
+ private needsRecovery(run: ReadonlyInput<OwnedRun>): boolean {
115
+ return (
116
+ run.source === "async" &&
117
+ (run.accounting?.state === "incomplete" || !hasText(run.delivery?.entryId))
118
+ );
119
+ }
110
120
 
111
- const handleResult = async (file: string) => {
112
- const startedGeneration = generation, ownerSessionId = state.currentSessionId;
113
- let claimedCompletionKey: string | undefined;
114
- let completionEmitted = false;
115
- const durableFile = path.isAbsolute(file);
116
- const resultPath = durableFile ? file : path.join(resultsDir, file);
117
- if (!fs.existsSync(resultPath)) return;
118
- try {
119
- if (isForeignUnchanged(resultPath)) return;
120
- const stamp = journalStamp(fs.statSync(resultPath, { bigint: true }));
121
- const notification = readAsyncResultFile(resultPath);
122
- const runId = notification.runId ?? notification.id ?? path.basename(file, ".json");
123
- const run = state.ownedRuns?.get(runId);
124
- const canonicalPath = isDurableRun(notification) && !durableFile ? path.join(getRunMetadataDir(runId), "result.json") : undefined;
125
- const canonicalStamp = canonicalPath ? journalStamp(fs.statSync(canonicalPath, { bigint: true })) : undefined;
126
- const data = canonicalPath ? readAsyncResultFile(canonicalPath) : notification;
127
- if ((data.runId ?? data.id ?? runId) !== runId) throw new Error(`Result identity does not match notification '${runId}'.`);
128
- if (durableFile && resultPath !== path.join(getRunMetadataDir(runId), "result.json")) throw new Error(`Canonical result identity does not match path '${resultPath}'.`);
129
- if (data.sessionId ? data.sessionId !== state.currentSessionId && run?.ownerSessionId !== state.currentSessionId : !run) {
130
- if (stamp) foreignResults.set(resultPath, { stamp, sessionId: state.currentSessionId, runId, ownerSessionId: run?.ownerSessionId, canonicalPath, canonicalStamp });
131
- return;
132
- }
133
- foreignResults.delete(resultPath);
134
- const consumeNotification = () => {
135
- // A legacy hint can be the only saved result. Native queue admission
136
- // is not publication; retain it until the verified parent receipt exists.
137
- if (!durableFile && !canonicalPath && deps.isCompletionPublished && !deps.isCompletionPublished(runId, completionKey)) return;
138
- const hint = durableFile ? path.join(resultsDir, `${runId}.json`) : resultPath;
139
- if (fs.existsSync(hint)) fs.unlinkSync(hint);
140
- };
141
- data.completionId ??= `legacy:${runId}:${data.timestamp ?? "unknown"}`;
142
- const completionKey = buildCompletionKey({ ...data, id: runId }, "result");
143
- if (deps.reconcileDelivery ? deps.reconcileDelivery(runId, completionKey) : state.isRunResultConsumed?.(runId)) { consumeNotification(); return; }
144
- if (state.waitingRuns?.has(runId)) {
145
- pi.events.emit(SUBAGENT_ASYNC_COMPLETE_EVENT, { ...data, runId, suppressNotification: true, intercomResultDelivered: false });
146
- return;
147
- }
148
- const hasExplicitNestedChildren = data.nestedChildren !== undefined;
149
- let nestedChildren = compactNestedResultChildren(sanitizeNestedResultChildren(data.nestedChildren, resultPath, "nestedChildren"));
150
- if (!nestedChildren?.length && !hasExplicitNestedChildren) {
151
- try {
152
- nestedChildren = compactNestedResultChildren(projectNestedRegistryForRoot(runId)?.children);
153
- } catch (error) {
154
- console.error(`Failed to enrich subagent result file '${resultPath}' with nested registry children; will retry later:`, error);
155
- return;
156
- }
157
- }
158
- const hasResultChildren = Array.isArray(data.results) && data.results.length > 0;
159
- const resultChildren = hasResultChildren
160
- ? data.results!
161
- : [{
162
- agent: data.agent,
163
- output: data.summary,
164
- success: data.success,
165
- }];
166
- const normalizedChildren = attachNestedChildrenToResultChildren(runId, resultChildren.map((result = {}, index): SubagentResultIntercomChild => {
167
- const baseOutput = result.output ?? result.finalOutput ?? data.summary;
168
- const hasRealOutput = typeof baseOutput === "string" && baseOutput.trim().length > 0;
169
- const output = hasRealOutput ? baseOutput : "(no output)";
170
- const summary = result.success === false && result.error
171
- ? `${result.error}${hasRealOutput ? `\n\nOutput:\n${baseOutput}` : ""}`
172
- : output;
173
- const sessionPath = result.sessionFile ?? (resultChildren.length === 1 ? data.sessionFile : undefined);
174
- const childNestedChildren = sanitizeNestedResultChildren(result.children, resultPath, `results[${index}].children`);
175
- return {
176
- agent: result.agent ?? data.agent ?? `step-${index + 1}`,
177
- status: resolveSubagentResultStatus({
178
- success: result.success,
179
- exitCode: result.exitCode ?? undefined,
180
- acceptance: result.acceptance,
181
- interrupted: result.interrupted,
182
- state: result.interrupted || typeof result.success !== "boolean" ? data.state : undefined,
183
- }),
184
- summary,
185
- index,
186
- artifactPath: result.artifactPaths?.outputPath,
187
- metadataPath: result.artifactPaths?.metadataPath,
188
- ...(typeof sessionPath === "string" && fs.existsSync(sessionPath) ? { sessionPath } : {}),
189
- ...(result.intercomTarget ? { intercomTarget: result.intercomTarget } : {}),
190
- ...(childNestedChildren ? { children: childNestedChildren } : {}),
191
- };
192
- }), nestedChildren);
121
+ private candidateFiles(): string[] {
122
+ const files = fs.existsSync(this.resultsDir)
123
+ ? fs.readdirSync(this.resultsDir).filter((name) => name.endsWith(".json"))
124
+ : [];
125
+ const notified = new Map(files.map((file, index) => [file, index]));
126
+ for (const run of this.state.ownedRuns?.values() ?? []) {
127
+ if (!this.needsRecovery(run)) {
128
+ continue;
129
+ }
130
+ const file = path.join(getRunMetadataDir(run.runId), "result.json");
131
+ if (!fs.existsSync(file)) {
132
+ continue;
133
+ }
134
+ // Disposable hints cannot veto canonical recovery, including corrupt hints.
135
+ const notification = notified.get(`${run.runId}.json`);
136
+ if (notification === undefined) {
137
+ files.push(file);
138
+ } else {
139
+ files[notification] = file;
140
+ }
141
+ }
142
+ return files;
143
+ }
193
144
 
194
- if (processingCompletionKeys.has(completionKey)) return;
195
- // Owned queue/receipt reconciliation above remains authoritative after TTL expiry.
196
- if (markSeenWithTtl(state.completionSeen, completionKey, Date.now(), 10 * 60 * 1000)) {
197
- consumeNotification();
198
- return;
199
- }
200
- processingCompletionKeys.add(completionKey);
201
- claimedCompletionKey = completionKey;
145
+ private pendingResultFiles(): string[] {
146
+ const files = this.candidateFiles();
147
+ const present = new Set(files.map((file) => this.resultPath(file)));
148
+ for (const file of this.foreignResults.keys()) {
149
+ if (!present.has(file)) {
150
+ this.foreignResults.delete(file);
151
+ }
152
+ }
153
+ return files.filter((file) => {
154
+ const resultPath = this.resultPath(file);
155
+ try {
156
+ return !this.isForeignUnchanged(resultPath);
157
+ } catch (error) {
158
+ if (notFound(error)) {
159
+ this.foreignResults.delete(resultPath);
160
+ return false;
161
+ }
162
+ return true;
163
+ }
164
+ });
165
+ }
202
166
 
203
- // Saved ownership is stable; the owner's live intercom identity can change on restart.
204
- const intercomTarget = resolveOrchestratorIntercomTarget(pi.events, data.intercomTarget?.trim() ?? "");
205
- let intercomResultDelivered = false;
206
- if (intercomTarget) {
207
- const mode = data.mode === "single" || data.mode === "parallel" || data.mode === "chain"
208
- ? data.mode
209
- : resultChildren.length > 1 ? "chain" : "single";
210
- const savedResultPath = path.join(getRunMetadataDir(runId), "result.json");
211
- const payload = buildSubagentResultIntercomPayload({
212
- to: intercomTarget,
213
- runId,
214
- completionId: data.completionId,
215
- mode,
216
- source: "async",
217
- ...(fs.existsSync(savedResultPath) ? { resultPath: savedResultPath } : {}),
218
- status: resolveSubagentResultStatus({ state: data.terminalState }),
219
- error: data.workflowGraph?.nodes.find((node) => node.error)?.error,
220
- children: normalizedChildren,
221
- asyncId: data.id,
222
- asyncDir: data.asyncDir,
223
- });
224
- intercomResultDelivered = await deliverSubagentResultIntercomEvent(pi.events, payload);
225
- }
226
- if (startedGeneration !== generation && startedGeneration !== joiningGeneration || ownerSessionId !== state.currentSessionId) {
227
- state.completionSeen.delete(completionKey);
228
- return;
229
- }
167
+ private foreign(envelope: ReadonlyInput<ResultEnvelope>): boolean {
168
+ const run = this.state.ownedRuns?.get(envelope.runId);
169
+ const sessionId = envelope.data.sessionId;
170
+ const foreign = hasText(sessionId)
171
+ ? sessionId !== this.state.currentSessionId &&
172
+ run?.ownerSessionId !== this.state.currentSessionId
173
+ : run === undefined;
174
+ if (foreign) {
175
+ this.foreignResults.set(envelope.resultPath, {
176
+ stamp: envelope.stamp,
177
+ sessionId: this.state.currentSessionId,
178
+ runId: envelope.runId,
179
+ ownerSessionId: run?.ownerSessionId,
180
+ canonicalPath: envelope.canonicalPath,
181
+ canonicalStamp: envelope.canonicalStamp,
182
+ });
183
+ } else {
184
+ this.foreignResults.delete(envelope.resultPath);
185
+ }
186
+ return foreign;
187
+ }
230
188
 
231
- // Shutdown closes native turn ingress. Retain failed deliveries for the
232
- // next startup, while still recording acknowledgements already accepted.
233
- if (!intercomResultDelivered && startedGeneration < preserveBeforeGeneration) return;
189
+ private consumeNotification(envelope: ReadonlyInput<ResultEnvelope>, key: string): void {
190
+ // Native queue admission is not publication. Retain the only legacy saved result until publication.
191
+ if (
192
+ !envelope.durableFile &&
193
+ envelope.canonicalPath === undefined &&
194
+ this.deps.isCompletionPublished !== undefined &&
195
+ !this.deps.isCompletionPublished(envelope.runId, key)
196
+ ) {
197
+ return;
198
+ }
199
+ const hint = envelope.durableFile
200
+ ? path.join(this.resultsDir, `${envelope.runId}.json`)
201
+ : envelope.resultPath;
202
+ if (fs.existsSync(hint)) {
203
+ fs.unlinkSync(hint);
204
+ }
205
+ }
234
206
 
235
- const { terminalState: _terminalState, ...eventData } = data;
236
- pi.events.emit(SUBAGENT_ASYNC_COMPLETE_EVENT, {
237
- ...eventData,
238
- agent: data.agent ?? normalizedChildren.map((child) => child.agent).join(", "),
239
- summary: data.summary?.trim() ? data.summary : normalizedChildren.map((child) => child.summary).join("\n\n"),
240
- runId,
241
- completionKey,
242
- intercomResultDelivered,
243
- ...(nestedChildren?.length ? { nestedChildren } : {}),
244
- ...(Array.isArray(data.results) ? {
245
- results: hasResultChildren
246
- ? normalizedChildren.map((child, index) => ({
247
- ...data.results![index],
248
- agent: child.agent,
249
- status: child.status,
250
- summary: child.summary,
251
- index: child.index,
252
- artifactPath: child.artifactPath,
253
- sessionPath: child.sessionPath,
254
- children: child.children,
255
- }))
256
- : [],
257
- } : {}),
258
- });
259
- completionEmitted = true;
260
- consumeNotification();
261
- } catch (error) {
262
- if (isNotFoundError(error)) return;
263
- console.error(`Failed to process subagent result file '${resultPath}':`, error);
264
- } finally {
265
- if (claimedCompletionKey) {
266
- processingCompletionKeys.delete(claimedCompletionKey);
267
- if (!completionEmitted) state.completionSeen.delete(claimedCompletionKey);
268
- }
269
- }
270
- };
207
+ private alreadyHandled(envelope: ReadonlyInput<ResultEnvelope>, key: string): boolean {
208
+ const handled =
209
+ this.deps.reconcileDelivery === undefined
210
+ ? this.state.isRunResultConsumed?.(envelope.runId) === true
211
+ : this.deps.reconcileDelivery(envelope.runId, key);
212
+ if (handled) {
213
+ this.consumeNotification(envelope, key);
214
+ return true;
215
+ }
216
+ if (this.state.waitingRuns?.has(envelope.runId) === true) {
217
+ this.pi.events.emit(SUBAGENT_ASYNC_COMPLETE_EVENT, {
218
+ ...envelope.data,
219
+ runId: envelope.runId,
220
+ suppressNotification: true,
221
+ intercomResultDelivered: false,
222
+ });
223
+ return true;
224
+ }
225
+ return false;
226
+ }
271
227
 
272
- const scheduled = new Set<string>();
273
- let drainGeneration: number | undefined;
274
- const scheduleResult = (file: string) => {
275
- scheduled.add(file);
276
- if (drainGeneration === generation) return;
277
- drainGeneration = generation;
278
- const scheduledGeneration = generation;
279
- startTail = startTail.then(async () => {
280
- try {
281
- while (scheduled.size) {
282
- await yieldToInput();
283
- if (scheduledGeneration !== generation) return;
284
- const files = [...scheduled].slice(0, 4);
285
- for (const file of files) scheduled.delete(file);
286
- // Only synchronous starts share publication proof. Async delivery
287
- // resumes outside this scope; yield between batches for native input.
288
- const start = () => {
289
- for (const file of files) {
290
- if (scheduledGeneration !== generation) return;
291
- const tail = handleResult(file);
292
- inFlight.add(tail);
293
- void tail.finally(() => inFlight.delete(tail));
294
- }
295
- };
296
- if (deps.withReceiptBatch) deps.withReceiptBatch(start); else start();
297
- }
298
- } finally { if (drainGeneration === scheduledGeneration) drainGeneration = undefined; }
299
- });
300
- };
301
- state.resultFileCoalescer = createFileCoalescer(scheduleResult, 50);
228
+ private claimCompletion(envelope: ReadonlyInput<ResultEnvelope>, key: string): boolean {
229
+ if (this.processingCompletionKeys.has(key)) {
230
+ return false;
231
+ }
232
+ // Owned queue/receipt reconciliation remains authoritative after TTL expiry.
233
+ if (markSeenWithTtl(this.state.completionSeen, key, Date.now(), 10 * 60 * 1000)) {
234
+ this.consumeNotification(envelope, key);
235
+ return false;
236
+ }
237
+ this.processingCompletionKeys.add(key);
238
+ return true;
239
+ }
302
240
 
303
- const primeExistingResults = () => {
304
- try {
305
- // Admit one recovery scan synchronously; separate zero-delay file timers
306
- // can split the same scan into additional verification batches.
307
- pendingResultFiles().forEach(scheduleResult);
308
- } catch (error) {
309
- if (isNotFoundError(error)) return;
310
- console.error(`Failed to scan subagent result directory '${resultsDir}':`, error);
311
- }
312
- };
241
+ private async deliverClaimed(
242
+ envelope: ReadonlyInput<ResultEnvelope>,
243
+ prepared: ReadonlyInput<PreparedResult>,
244
+ key: string,
245
+ ownership: { readonly generation: number; readonly sessionId: string | null },
246
+ ): Promise<boolean> {
247
+ const delivered = await deliverResultIntercom(this.pi.events, envelope, prepared);
248
+ // Stop/session callbacks may change generation and owner during suspension.
249
+ if (
250
+ (ownership.generation !== this.generation &&
251
+ ownership.generation !== this.joiningGeneration) ||
252
+ ownership.sessionId !== this.state.currentSessionId
253
+ ) {
254
+ this.state.completionSeen.delete(key);
255
+ return false;
256
+ }
257
+ // Shutdown closes native turn ingress; accepted acknowledgements are still recorded.
258
+ if (!delivered && ownership.generation < this.preserveBeforeGeneration) {
259
+ return false;
260
+ }
261
+ this.pi.events.emit(
262
+ SUBAGENT_ASYNC_COMPLETE_EVENT,
263
+ completionEvent(envelope, prepared, key, delivered),
264
+ );
265
+ return true;
266
+ }
313
267
 
314
- const ensurePeriodicScan = () => {
315
- if (periodicScanTimer) return;
316
- periodicScanTimer = setInterval(primeExistingResults, POLL_INTERVAL_MS);
317
- periodicScanTimer.unref?.();
318
- };
268
+ private releaseCompletion(key: string | undefined, emitted: boolean): void {
269
+ if (!hasText(key)) {
270
+ return;
271
+ }
272
+ this.processingCompletionKeys.delete(key);
273
+ if (!emitted) {
274
+ this.state.completionSeen.delete(key);
275
+ }
276
+ }
319
277
 
320
- const clearPeriodicScan = () => {
321
- if (!periodicScanTimer) return;
322
- clearInterval(periodicScanTimer);
323
- periodicScanTimer = null;
324
- };
278
+ private readonly handleResult = async (file: string): Promise<void> => {
279
+ const startedGeneration = this.generation;
280
+ const ownerSessionId = this.state.currentSessionId;
281
+ let claimed: string | undefined;
282
+ let emitted = false;
283
+ const resultPath = this.resultPath(file);
284
+ if (!fs.existsSync(resultPath)) {
285
+ return;
286
+ }
287
+ try {
288
+ if (this.isForeignUnchanged(resultPath)) {
289
+ return;
290
+ }
291
+ const envelope = readResultEnvelope(file, this.resultsDir);
292
+ if (this.foreign(envelope)) {
293
+ return;
294
+ }
295
+ const key = buildCompletionKey({ ...envelope.data, id: envelope.runId }, "result");
296
+ if (this.alreadyHandled(envelope, key)) {
297
+ return;
298
+ }
299
+ const prepared = prepareResult(envelope);
300
+ if (prepared === undefined) {
301
+ return;
302
+ }
303
+ if (!this.claimCompletion(envelope, key)) {
304
+ return;
305
+ }
306
+ claimed = key;
307
+ emitted = await this.deliverClaimed(envelope, prepared, key, {
308
+ generation: startedGeneration,
309
+ sessionId: ownerSessionId,
310
+ });
311
+ if (emitted) {
312
+ this.consumeNotification(envelope, key);
313
+ }
314
+ } catch (error) {
315
+ if (!notFound(error)) {
316
+ console.error(`Failed to process subagent result file '${resultPath}':`, error);
317
+ }
318
+ } finally {
319
+ this.releaseCompletion(claimed, emitted);
320
+ }
321
+ };
325
322
 
326
- const startPollingFallback = (reason: unknown) => {
327
- state.watcher?.close();
328
- state.watcher = null;
329
- clearPeriodicScan();
330
- if (state.watcherRestartTimer) return;
323
+ private startBatch(files: readonly string[], generation: number): void {
324
+ for (const file of files) {
325
+ if (generation !== this.generation) {
326
+ return;
327
+ }
328
+ const tail = this.handleResult(file)
329
+ .catch((error: unknown) => {
330
+ console.error(`Subagent delivery failed for '${file}':`, error);
331
+ })
332
+ .finally(() => {
333
+ this.inFlight.delete(tail);
334
+ });
335
+ this.inFlight.add(tail);
336
+ }
337
+ }
331
338
 
332
- console.error(
333
- `Subagent result watcher for '${resultsDir}' fell back to polling because native fs.watch is unavailable (${getErrorCode(reason) ?? "unknown error"}).`,
334
- );
335
- primeExistingResults();
336
- state.watcherRestartTimer = setInterval(primeExistingResults, POLL_INTERVAL_MS);
337
- state.watcherRestartTimer.unref?.();
338
- };
339
+ private async drain(generation: number): Promise<void> {
340
+ try {
341
+ while (this.scheduled.size > 0) {
342
+ // Batches yield to native input; later starts depend on this generation guard.
343
+ // oxlint-disable-next-line no-await-in-loop
344
+ await yieldToInput();
345
+ if (generation !== this.generation) {
346
+ return;
347
+ }
348
+ const files = [...this.scheduled].slice(0, 4);
349
+ for (const file of files) {
350
+ this.scheduled.delete(file);
351
+ }
352
+ const start = (): void => {
353
+ this.startBatch(files, generation);
354
+ };
355
+ if (this.deps.withReceiptBatch) {
356
+ this.deps.withReceiptBatch(start);
357
+ } else {
358
+ start();
359
+ }
360
+ }
361
+ } finally {
362
+ if (this.drainGeneration === generation) {
363
+ this.drainGeneration = undefined;
364
+ }
365
+ }
366
+ }
339
367
 
340
- const scheduleRestart = () => {
341
- if (state.watcherRestartTimer) return;
342
- state.watcherRestartTimer = setTimeout(() => {
343
- state.watcherRestartTimer = null;
344
- try {
345
- fs.mkdirSync(resultsDir, { recursive: true });
346
- startResultWatcher();
347
- } catch (error) {
348
- if (shouldFallBackToPolling(error)) {
349
- startPollingFallback(error);
350
- return;
351
- }
352
- console.error(`Failed to restart subagent result watcher for '${resultsDir}':`, error);
353
- scheduleRestart();
354
- }
355
- }, WATCHER_RESTART_DELAY_MS);
356
- state.watcherRestartTimer.unref?.();
357
- };
368
+ private readonly scheduleResult = (file: string): void => {
369
+ this.scheduled.add(file);
370
+ if (this.drainGeneration === this.generation) {
371
+ return;
372
+ }
373
+ this.drainGeneration = this.generation;
374
+ const generation = this.generation;
375
+ this.startTail = this.startTail
376
+ .then(() => this.drain(generation))
377
+ .catch((error: unknown) => {
378
+ console.error("Failed to drain admitted subagent results:", error);
379
+ });
380
+ };
358
381
 
359
- const startResultWatcher = () => {
360
- if (state.watcher) {
361
- ensurePeriodicScan();
362
- return;
363
- }
364
- if (state.watcherRestartTimer) {
365
- clearTimeout(state.watcherRestartTimer);
366
- clearInterval(state.watcherRestartTimer);
367
- state.watcherRestartTimer = null;
368
- }
369
- try {
370
- state.watcher = fs.watch(resultsDir, (ev, file) => {
371
- if (ev !== "rename" || !file) return;
372
- const fileName = file.toString();
373
- if (!fileName.endsWith(".json")) return;
374
- if (!fs.existsSync(path.join(resultsDir, fileName))) return;
375
- state.resultFileCoalescer.schedule(fileName);
376
- });
377
- state.watcher.on("error", (error) => {
378
- if (shouldFallBackToPolling(error)) {
379
- startPollingFallback(error);
380
- return;
381
- }
382
- console.error(`Subagent result watcher failed for '${resultsDir}':`, error);
383
- state.watcher?.close();
384
- state.watcher = null;
385
- scheduleRestart();
386
- });
387
- state.watcher.unref?.();
388
- ensurePeriodicScan();
389
- } catch (error) {
390
- if (shouldFallBackToPolling(error)) {
391
- startPollingFallback(error);
392
- return;
393
- }
394
- console.error(`Failed to start subagent result watcher for '${resultsDir}':`, error);
395
- state.watcher = null;
396
- scheduleRestart();
397
- }
398
- };
382
+ primeExistingResults = (): void => {
383
+ try {
384
+ this.pendingResultFiles().forEach(this.scheduleResult);
385
+ } catch (error) {
386
+ if (!notFound(error)) {
387
+ console.error(`Failed to scan subagent result directory '${this.resultsDir}':`, error);
388
+ }
389
+ }
390
+ };
399
391
 
400
- const stopResultWatcher = (options: { preservePending?: boolean; joinInFlight?: boolean } = {}) => {
401
- joiningGeneration = options.joinInFlight ? generation : undefined;
402
- generation++;
403
- if (options.preservePending) preserveBeforeGeneration = generation;
404
- state.watcher?.close();
405
- state.watcher = null;
406
- clearPeriodicScan();
407
- if (state.watcherRestartTimer) {
408
- clearTimeout(state.watcherRestartTimer);
409
- clearInterval(state.watcherRestartTimer);
410
- }
411
- state.watcherRestartTimer = null;
412
- state.resultFileCoalescer.clear();
413
- scheduled.clear();
414
- foreignResults.clear();
415
- };
392
+ private ensurePeriodicScan(): void {
393
+ if (this.periodicScanTimer) {
394
+ return;
395
+ }
396
+ this.periodicScanTimer = setInterval(this.primeExistingResults, POLL_INTERVAL_MS);
397
+ this.periodicScanTimer.unref();
398
+ }
399
+ private clearPeriodicScan(): void {
400
+ if (this.periodicScanTimer) {
401
+ clearInterval(this.periodicScanTimer);
402
+ this.periodicScanTimer = null;
403
+ }
404
+ }
405
+ private startPollingFallback(reason: unknown): void {
406
+ this.state.watcher?.close();
407
+ this.state.watcher = null;
408
+ this.clearPeriodicScan();
409
+ if (this.state.watcherRestartTimer) {
410
+ return;
411
+ }
412
+ console.error(
413
+ `Subagent result watcher for '${this.resultsDir}' fell back to polling because native fs.watch is unavailable (${errorCode(reason) ?? "unknown error"}).`,
414
+ );
415
+ this.primeExistingResults();
416
+ this.state.watcherRestartTimer = setInterval(this.primeExistingResults, POLL_INTERVAL_MS);
417
+ this.state.watcherRestartTimer.unref();
418
+ }
419
+ private scheduleRestart(): void {
420
+ if (this.state.watcherRestartTimer) {
421
+ return;
422
+ }
423
+ this.state.watcherRestartTimer = setTimeout(() => {
424
+ this.state.watcherRestartTimer = null;
425
+ try {
426
+ fs.mkdirSync(this.resultsDir, { recursive: true });
427
+ this.startResultWatcher();
428
+ } catch (error) {
429
+ if (pollingRequired(error)) {
430
+ this.startPollingFallback(error);
431
+ return;
432
+ }
433
+ console.error(`Failed to restart subagent result watcher for '${this.resultsDir}':`, error);
434
+ this.scheduleRestart();
435
+ }
436
+ }, RESTART_DELAY_MS);
437
+ this.state.watcherRestartTimer.unref();
438
+ }
416
439
 
417
- const joinInFlight = async () => {
418
- await Promise.all([...inFlight]);
419
- joiningGeneration = undefined;
420
- };
440
+ startResultWatcher = (): void => {
441
+ if (this.state.watcher) {
442
+ this.ensurePeriodicScan();
443
+ return;
444
+ }
445
+ if (this.state.watcherRestartTimer) {
446
+ clearTimeout(this.state.watcherRestartTimer);
447
+ clearInterval(this.state.watcherRestartTimer);
448
+ this.state.watcherRestartTimer = null;
449
+ }
450
+ try {
451
+ this.state.watcher = fs.watch(this.resultsDir, (event, file) => {
452
+ if (event !== "rename" || !hasText(file)) {
453
+ return;
454
+ }
455
+ if (file.endsWith(".json") && fs.existsSync(path.join(this.resultsDir, file))) {
456
+ this.state.resultFileCoalescer.schedule(file);
457
+ }
458
+ });
459
+ this.state.watcher.on("error", (error) => {
460
+ if (pollingRequired(error)) {
461
+ this.startPollingFallback(error);
462
+ return;
463
+ }
464
+ console.error(`Subagent result watcher failed for '${this.resultsDir}':`, error);
465
+ this.state.watcher?.close();
466
+ this.state.watcher = null;
467
+ this.scheduleRestart();
468
+ });
469
+ this.state.watcher.unref();
470
+ this.ensurePeriodicScan();
471
+ } catch (error) {
472
+ if (pollingRequired(error)) {
473
+ this.startPollingFallback(error);
474
+ return;
475
+ }
476
+ console.error(`Failed to start subagent result watcher for '${this.resultsDir}':`, error);
477
+ this.state.watcher = null;
478
+ this.scheduleRestart();
479
+ }
480
+ };
421
481
 
422
- return { startResultWatcher, primeExistingResults, stopResultWatcher, joinInFlight };
482
+ stopResultWatcher = (options: StopOptions = {}): void => {
483
+ this.joiningGeneration = options.joinInFlight === true ? this.generation : undefined;
484
+ this.generation++;
485
+ if (options.preservePending === true) {
486
+ this.preserveBeforeGeneration = this.generation;
487
+ }
488
+ this.state.watcher?.close();
489
+ this.state.watcher = null;
490
+ this.clearPeriodicScan();
491
+ if (this.state.watcherRestartTimer) {
492
+ clearTimeout(this.state.watcherRestartTimer);
493
+ clearInterval(this.state.watcherRestartTimer);
494
+ }
495
+ this.state.watcherRestartTimer = null;
496
+ this.state.resultFileCoalescer.clear();
497
+ this.scheduled.clear();
498
+ this.foreignResults.clear();
499
+ };
500
+ joinInFlight = async (): Promise<void> => {
501
+ await this.startTail;
502
+ await Promise.all(this.inFlight);
503
+ this.joiningGeneration = undefined;
504
+ };
505
+ }
506
+
507
+ export function createResultWatcher(
508
+ pi: ReadonlyInput<{ events: IntercomEventBus }>,
509
+ state: SubagentState,
510
+ resultsDir: string,
511
+ deps: ResultWatcherDeps = {},
512
+ ): ResultWatcherHandle {
513
+ const watcher = new ResultWatcher(pi, state, resultsDir, deps);
514
+ return {
515
+ startResultWatcher: watcher.startResultWatcher,
516
+ primeExistingResults: watcher.primeExistingResults,
517
+ stopResultWatcher: watcher.stopResultWatcher,
518
+ joinInFlight: watcher.joinInFlight,
519
+ };
423
520
  }