@bastani/atomic 0.9.5-alpha.9 → 0.9.5

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 (377) hide show
  1. package/CHANGELOG.md +106 -0
  2. package/README.md +2 -2
  3. package/dist/builtin/cursor/CHANGELOG.md +12 -0
  4. package/dist/builtin/cursor/package.json +3 -3
  5. package/dist/builtin/cursor/src/model-mapper.ts +6 -3
  6. package/dist/builtin/intercom/CHANGELOG.md +37 -0
  7. package/dist/builtin/intercom/README.md +4 -2
  8. package/dist/builtin/intercom/broker/broker.ts +6 -114
  9. package/dist/builtin/intercom/broker/client.ts +29 -54
  10. package/dist/builtin/intercom/broker/delivered-message-cache.ts +44 -0
  11. package/dist/builtin/intercom/broker/pending-send-registry.ts +142 -0
  12. package/dist/builtin/intercom/broker/send-handler.ts +106 -0
  13. package/dist/builtin/intercom/broker/send-signature.ts +37 -0
  14. package/dist/builtin/intercom/foreground-detach-handoff.ts +136 -0
  15. package/dist/builtin/intercom/index-heavy.ts +49 -53
  16. package/dist/builtin/intercom/index.ts +278 -262
  17. package/dist/builtin/intercom/lazy-heavy-proxy.ts +114 -0
  18. package/dist/builtin/intercom/lazy-subagent-ack.ts +20 -0
  19. package/dist/builtin/intercom/lazy-tool-execution.ts +39 -0
  20. package/dist/builtin/intercom/lifecycle-lease.ts +51 -0
  21. package/dist/builtin/intercom/lifecycle.ts +37 -20
  22. package/dist/builtin/intercom/package.json +3 -6
  23. package/dist/builtin/intercom/reply-routing.ts +17 -0
  24. package/dist/builtin/intercom/subagent-relay.ts +58 -12
  25. package/dist/builtin/intercom/types.ts +3 -3
  26. package/dist/builtin/mcp/CHANGELOG.md +27 -0
  27. package/dist/builtin/mcp/OAUTH.md +1 -0
  28. package/dist/builtin/mcp/README.md +4 -0
  29. package/dist/builtin/mcp/apps-cancellation.ts +32 -0
  30. package/dist/builtin/mcp/call-tool-result.ts +9 -0
  31. package/dist/builtin/mcp/caller-wait.ts +50 -0
  32. package/dist/builtin/mcp/command-registration.ts +82 -0
  33. package/dist/builtin/mcp/direct-tool-executor.ts +279 -0
  34. package/dist/builtin/mcp/direct-tools.ts +6 -239
  35. package/dist/builtin/mcp/host-html-template.ts +4 -2
  36. package/dist/builtin/mcp/index.ts +258 -250
  37. package/dist/builtin/mcp/init.ts +96 -87
  38. package/dist/builtin/mcp/mcp-auth-flow.ts +247 -237
  39. package/dist/builtin/mcp/mcp-callback-server.ts +89 -68
  40. package/dist/builtin/mcp/mcp-oauth-provider.ts +23 -1
  41. package/dist/builtin/mcp/metadata-hydration.ts +21 -6
  42. package/dist/builtin/mcp/package.json +3 -3
  43. package/dist/builtin/mcp/proxy-auth.ts +4 -4
  44. package/dist/builtin/mcp/proxy-call.ts +111 -40
  45. package/dist/builtin/mcp/proxy-connect.ts +35 -15
  46. package/dist/builtin/mcp/proxy-info-modes.ts +49 -19
  47. package/dist/builtin/mcp/proxy-modes.ts +3 -3
  48. package/dist/builtin/mcp/session-cleanup-barrier.ts +43 -0
  49. package/dist/builtin/mcp/state-lease.ts +12 -0
  50. package/dist/builtin/mcp/ui-server.ts +8 -8
  51. package/dist/builtin/mcp/ui-session.ts +9 -18
  52. package/dist/builtin/subagents/CHANGELOG.md +66 -0
  53. package/dist/builtin/subagents/README.md +30 -29
  54. package/dist/builtin/subagents/agents/code-simplifier.md +2 -2
  55. package/dist/builtin/subagents/agents/codebase-analyzer.md +2 -2
  56. package/dist/builtin/subagents/agents/codebase-locator.md +2 -2
  57. package/dist/builtin/subagents/agents/codebase-online-researcher.md +2 -2
  58. package/dist/builtin/subagents/agents/codebase-pattern-finder.md +2 -2
  59. package/dist/builtin/subagents/agents/codebase-research-analyzer.md +2 -2
  60. package/dist/builtin/subagents/agents/codebase-research-locator.md +2 -2
  61. package/dist/builtin/subagents/agents/debugger.md +2 -2
  62. package/dist/builtin/subagents/agents/worker.md +2 -2
  63. package/dist/builtin/subagents/package.json +5 -5
  64. package/dist/builtin/subagents/prompts/review-loop.md +1 -1
  65. package/dist/builtin/subagents/skills/subagent/SKILL.md +37 -36
  66. package/dist/builtin/subagents/src/extension/api-lifecycle.ts +64 -0
  67. package/dist/builtin/subagents/src/extension/fanout-child.ts +44 -51
  68. package/dist/builtin/subagents/src/extension/index.ts +287 -307
  69. package/dist/builtin/subagents/src/extension/prompt-guidance.ts +7 -10
  70. package/dist/builtin/subagents/src/extension/schemas.ts +22 -5
  71. package/dist/builtin/subagents/src/extension/tool-description.ts +29 -0
  72. package/dist/builtin/subagents/src/intercom/intercom-bridge.ts +13 -2
  73. package/dist/builtin/subagents/src/intercom/result-intercom.ts +4 -4
  74. package/dist/builtin/subagents/src/runs/background/async-event-journal.ts +106 -0
  75. package/dist/builtin/subagents/src/runs/background/async-execution-common.ts +3 -2
  76. package/dist/builtin/subagents/src/runs/background/async-execution-single.ts +13 -2
  77. package/dist/builtin/subagents/src/runs/background/async-execution-types.ts +3 -0
  78. package/dist/builtin/subagents/src/runs/background/async-job-tracker.ts +1 -1
  79. package/dist/builtin/subagents/src/runs/background/completion-claims.ts +189 -0
  80. package/dist/builtin/subagents/src/runs/background/completion-dedupe.ts +44 -7
  81. package/dist/builtin/subagents/src/runs/background/completion-notification.ts +34 -0
  82. package/dist/builtin/subagents/src/runs/background/notify.ts +72 -22
  83. package/dist/builtin/subagents/src/runs/background/result-delivery-processor.ts +232 -0
  84. package/dist/builtin/subagents/src/runs/background/result-file-claims.ts +151 -0
  85. package/dist/builtin/subagents/src/runs/background/result-quarantine.ts +72 -0
  86. package/dist/builtin/subagents/src/runs/background/result-retry-scheduler.ts +48 -0
  87. package/dist/builtin/subagents/src/runs/background/result-status.ts +81 -0
  88. package/dist/builtin/subagents/src/runs/background/result-watcher-data.ts +59 -0
  89. package/dist/builtin/subagents/src/runs/background/result-watcher.ts +172 -238
  90. package/dist/builtin/subagents/src/runs/background/run-id-resolver.ts +3 -2
  91. package/dist/builtin/subagents/src/runs/background/stale-run-reconciler.ts +73 -14
  92. package/dist/builtin/subagents/src/runs/background/subagent-runner-streaming.ts +17 -13
  93. package/dist/builtin/subagents/src/runs/background/top-level-async.ts +1 -2
  94. package/dist/builtin/subagents/src/runs/foreground/chain-execution-dynamic-step.ts +1 -0
  95. package/dist/builtin/subagents/src/runs/foreground/chain-execution-parallel-runner.ts +1 -0
  96. package/dist/builtin/subagents/src/runs/foreground/chain-execution-parallel-step.ts +1 -0
  97. package/dist/builtin/subagents/src/runs/foreground/chain-execution-sequential-step.ts +7 -9
  98. package/dist/builtin/subagents/src/runs/foreground/chain-execution-types.ts +3 -13
  99. package/dist/builtin/subagents/src/runs/foreground/chain-execution.ts +2 -15
  100. package/dist/builtin/subagents/src/runs/foreground/execution-attempt-finalize.ts +2 -2
  101. package/dist/builtin/subagents/src/runs/foreground/execution-attempt.ts +53 -44
  102. package/dist/builtin/subagents/src/runs/foreground/execution-detach-reservations.ts +48 -0
  103. package/dist/builtin/subagents/src/runs/foreground/execution-detach-route.ts +17 -0
  104. package/dist/builtin/subagents/src/runs/foreground/execution-run-sync.ts +39 -26
  105. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-async.ts +3 -1
  106. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-chain.ts +3 -51
  107. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-context.ts +6 -11
  108. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-input.ts +11 -2
  109. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-parallel-task.ts +2 -0
  110. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-parallel.ts +5 -112
  111. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-resume.ts +2 -0
  112. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-single.ts +68 -118
  113. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-status.ts +79 -7
  114. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-types.ts +2 -2
  115. package/dist/builtin/subagents/src/runs/foreground/subagent-executor.ts +3 -0
  116. package/dist/builtin/subagents/src/runs/shared/pi-args.ts +2 -2
  117. package/dist/builtin/subagents/src/runs/shared/pi-spawn.ts +27 -11
  118. package/dist/builtin/subagents/src/shared/artifacts.ts +22 -11
  119. package/dist/builtin/subagents/src/shared/event-jsonl-writer.ts +294 -0
  120. package/dist/builtin/subagents/src/shared/exclusive-file-publication.ts +44 -0
  121. package/dist/builtin/subagents/src/shared/jsonl-writer.ts +1 -0
  122. package/dist/builtin/subagents/src/shared/model-info.ts +2 -2
  123. package/dist/builtin/subagents/src/shared/settings.ts +20 -10
  124. package/dist/builtin/subagents/src/shared/types-async.ts +3 -1
  125. package/dist/builtin/subagents/src/shared/types-config.ts +2 -0
  126. package/dist/builtin/subagents/src/shared/types-runtime.ts +3 -2
  127. package/dist/builtin/subagents/src/slash/slash-commands.ts +9 -12
  128. package/dist/builtin/subagents/src/slash/slash-live-state.ts +63 -32
  129. package/dist/builtin/subagents/src/tui/render-result.ts +7 -0
  130. package/dist/builtin/subagents/src/tui/render-stable-output.ts +1 -0
  131. package/dist/builtin/subagents/src/tui/render-widget.ts +128 -89
  132. package/dist/builtin/web-access/CHANGELOG.md +28 -0
  133. package/dist/builtin/web-access/README.md +4 -0
  134. package/dist/builtin/web-access/content-tools.ts +8 -3
  135. package/dist/builtin/web-access/index-heavy.ts +1 -1
  136. package/dist/builtin/web-access/index.ts +190 -46
  137. package/dist/builtin/web-access/lifecycle-lease.ts +38 -0
  138. package/dist/builtin/web-access/package.json +2 -2
  139. package/dist/builtin/web-access/result-renderers.ts +1 -1
  140. package/dist/builtin/web-access/summary-review.ts +1 -1
  141. package/dist/builtin/web-access/web-search-activity.ts +1 -1
  142. package/dist/builtin/web-access/web-search-return.ts +7 -0
  143. package/dist/builtin/web-access/web-search-summary.ts +1 -1
  144. package/dist/builtin/web-access/web-search-tool.ts +4 -2
  145. package/dist/builtin/workflows/CHANGELOG.md +68 -0
  146. package/dist/builtin/workflows/README.md +4 -4
  147. package/dist/builtin/workflows/builtin/deep-research-codebase-utils.ts +27 -4
  148. package/dist/builtin/workflows/builtin/goal-runner.ts +47 -26
  149. package/dist/builtin/workflows/builtin/open-claude-design-runner.ts +10 -0
  150. package/dist/builtin/workflows/builtin/ralph-core.ts +9 -9
  151. package/dist/builtin/workflows/builtin/ralph-models.ts +71 -36
  152. package/dist/builtin/workflows/builtin/ralph-runner.ts +20 -31
  153. package/dist/builtin/workflows/package.json +2 -2
  154. package/dist/builtin/workflows/src/durable/stage-primitive.ts +2 -1
  155. package/dist/builtin/workflows/src/engine/primitives/task.ts +2 -1
  156. package/dist/builtin/workflows/src/extension/workflow-prompts.ts +17 -22
  157. package/dist/builtin/workflows/src/extension/workflow-schema.ts +15 -2
  158. package/dist/builtin/workflows/src/runs/foreground/executor-hil.ts +1 -2
  159. package/dist/builtin/workflows/src/runs/shared/model-fallback-candidates.ts +1 -1
  160. package/dist/builtin/workflows/src/shared/authoring-contract-stage.d.ts +2 -2
  161. package/dist/builtin/workflows/src/shared/authoring-contract-stage.ts +2 -2
  162. package/dist/builtin/workflows/src/shared/resume-continuation.ts +2 -0
  163. package/dist/builtin/workflows/src/tui/stage-chat-view-archive-history.ts +1 -23
  164. package/dist/builtin/workflows/src/tui/stage-chat-view-footer-status.ts +54 -9
  165. package/dist/builtin/workflows/src/tui/stage-chat-view.ts +5 -2
  166. package/dist/cli/args.d.ts.map +1 -1
  167. package/dist/cli/args.js +2 -2
  168. package/dist/cli/args.js.map +1 -1
  169. package/dist/core/agent-session-events.d.ts.map +1 -1
  170. package/dist/core/agent-session-events.js +2 -1
  171. package/dist/core/agent-session-events.js.map +1 -1
  172. package/dist/core/agent-session-message-queue.d.ts.map +1 -1
  173. package/dist/core/agent-session-message-queue.js +1 -1
  174. package/dist/core/agent-session-message-queue.js.map +1 -1
  175. package/dist/core/agent-session-prompt.d.ts.map +1 -1
  176. package/dist/core/agent-session-prompt.js +1 -1
  177. package/dist/core/agent-session-prompt.js.map +1 -1
  178. package/dist/core/agent-session-retry.d.ts.map +1 -1
  179. package/dist/core/agent-session-retry.js +1 -1
  180. package/dist/core/agent-session-retry.js.map +1 -1
  181. package/dist/core/agent-session-services.d.ts.map +1 -1
  182. package/dist/core/agent-session-services.js +3 -2
  183. package/dist/core/agent-session-services.js.map +1 -1
  184. package/dist/core/agent-session-types.d.ts.map +1 -1
  185. package/dist/core/agent-session-types.js +1 -1
  186. package/dist/core/agent-session-types.js.map +1 -1
  187. package/dist/core/anthropic-thinking-guard.d.ts +5 -5
  188. package/dist/core/anthropic-thinking-guard.d.ts.map +1 -1
  189. package/dist/core/anthropic-thinking-guard.js +42 -32
  190. package/dist/core/anthropic-thinking-guard.js.map +1 -1
  191. package/dist/core/atomic-guide-command.d.ts.map +1 -1
  192. package/dist/core/atomic-guide-command.js +15 -15
  193. package/dist/core/atomic-guide-command.js.map +1 -1
  194. package/dist/core/auth-storage.d.ts.map +1 -1
  195. package/dist/core/auth-storage.js +14 -9
  196. package/dist/core/auth-storage.js.map +1 -1
  197. package/dist/core/compaction/compaction.d.ts +2 -0
  198. package/dist/core/compaction/compaction.d.ts.map +1 -1
  199. package/dist/core/compaction/compaction.js +79 -46
  200. package/dist/core/compaction/compaction.js.map +1 -1
  201. package/dist/core/compaction/context-assistant-turns.d.ts +42 -0
  202. package/dist/core/compaction/context-assistant-turns.d.ts.map +1 -0
  203. package/dist/core/compaction/context-assistant-turns.js +87 -0
  204. package/dist/core/compaction/context-assistant-turns.js.map +1 -0
  205. package/dist/core/compaction/context-compaction-critical.d.ts +1 -1
  206. package/dist/core/compaction/context-compaction-critical.d.ts.map +1 -1
  207. package/dist/core/compaction/context-compaction-critical.js +2 -2
  208. package/dist/core/compaction/context-compaction-critical.js.map +1 -1
  209. package/dist/core/compaction/context-compaction-eviction-alternates.d.ts +18 -0
  210. package/dist/core/compaction/context-compaction-eviction-alternates.d.ts.map +1 -0
  211. package/dist/core/compaction/context-compaction-eviction-alternates.js +186 -0
  212. package/dist/core/compaction/context-compaction-eviction-alternates.js.map +1 -0
  213. package/dist/core/compaction/context-compaction-eviction.d.ts +10 -2
  214. package/dist/core/compaction/context-compaction-eviction.d.ts.map +1 -1
  215. package/dist/core/compaction/context-compaction-eviction.js +196 -146
  216. package/dist/core/compaction/context-compaction-eviction.js.map +1 -1
  217. package/dist/core/compaction/context-compaction-prompt.d.ts.map +1 -1
  218. package/dist/core/compaction/context-compaction-prompt.js +1 -1
  219. package/dist/core/compaction/context-compaction-prompt.js.map +1 -1
  220. package/dist/core/compaction/context-compaction-types.d.ts +2 -0
  221. package/dist/core/compaction/context-compaction-types.d.ts.map +1 -1
  222. package/dist/core/compaction/context-compaction-types.js.map +1 -1
  223. package/dist/core/compaction/context-deletion-application.d.ts +5 -4
  224. package/dist/core/compaction/context-deletion-application.d.ts.map +1 -1
  225. package/dist/core/compaction/context-deletion-application.js +17 -15
  226. package/dist/core/compaction/context-deletion-application.js.map +1 -1
  227. package/dist/core/compaction/context-deletion-store.d.ts.map +1 -1
  228. package/dist/core/compaction/context-deletion-store.js +1 -1
  229. package/dist/core/compaction/context-deletion-store.js.map +1 -1
  230. package/dist/core/compaction/context-deletion-targets.d.ts +2 -1
  231. package/dist/core/compaction/context-deletion-targets.d.ts.map +1 -1
  232. package/dist/core/compaction/context-deletion-targets.js +36 -31
  233. package/dist/core/compaction/context-deletion-targets.js.map +1 -1
  234. package/dist/core/compaction/context-deletion-tool-helpers.d.ts.map +1 -1
  235. package/dist/core/compaction/context-deletion-tool-helpers.js +116 -43
  236. package/dist/core/compaction/context-deletion-tool-helpers.js.map +1 -1
  237. package/dist/core/compaction/context-transcript-analysis.d.ts +1 -2
  238. package/dist/core/compaction/context-transcript-analysis.d.ts.map +1 -1
  239. package/dist/core/compaction/context-transcript-analysis.js +33 -37
  240. package/dist/core/compaction/context-transcript-analysis.js.map +1 -1
  241. package/dist/core/copilot-model-synthesis.d.ts.map +1 -1
  242. package/dist/core/copilot-model-synthesis.js +3 -1
  243. package/dist/core/copilot-model-synthesis.js.map +1 -1
  244. package/dist/core/extensions/provider-types.d.ts +2 -7
  245. package/dist/core/extensions/provider-types.d.ts.map +1 -1
  246. package/dist/core/extensions/provider-types.js.map +1 -1
  247. package/dist/core/messages.d.ts +9 -0
  248. package/dist/core/messages.d.ts.map +1 -1
  249. package/dist/core/messages.js +100 -18
  250. package/dist/core/messages.js.map +1 -1
  251. package/dist/core/model-registry-builtins.d.ts.map +1 -1
  252. package/dist/core/model-registry-builtins.js +5 -0
  253. package/dist/core/model-registry-builtins.js.map +1 -1
  254. package/dist/core/model-registry-custom-loader.d.ts.map +1 -1
  255. package/dist/core/model-registry-custom-loader.js +49 -8
  256. package/dist/core/model-registry-custom-loader.js.map +1 -1
  257. package/dist/core/model-registry-dynamic.d.ts.map +1 -1
  258. package/dist/core/model-registry-dynamic.js +11 -5
  259. package/dist/core/model-registry-dynamic.js.map +1 -1
  260. package/dist/core/model-registry-loader.d.ts.map +1 -1
  261. package/dist/core/model-registry-loader.js +8 -0
  262. package/dist/core/model-registry-loader.js.map +1 -1
  263. package/dist/core/model-registry-schemas.d.ts +93 -8
  264. package/dist/core/model-registry-schemas.d.ts.map +1 -1
  265. package/dist/core/model-registry-schemas.js +24 -12
  266. package/dist/core/model-registry-schemas.js.map +1 -1
  267. package/dist/core/model-registry-types.d.ts +7 -6
  268. package/dist/core/model-registry-types.d.ts.map +1 -1
  269. package/dist/core/model-registry-types.js.map +1 -1
  270. package/dist/core/model-registry.d.ts +5 -0
  271. package/dist/core/model-registry.d.ts.map +1 -1
  272. package/dist/core/model-registry.js +23 -0
  273. package/dist/core/model-registry.js.map +1 -1
  274. package/dist/core/model-resolver-cli.d.ts.map +1 -1
  275. package/dist/core/model-resolver-cli.js +33 -5
  276. package/dist/core/model-resolver-cli.js.map +1 -1
  277. package/dist/core/model-resolver-initial.d.ts +6 -1
  278. package/dist/core/model-resolver-initial.d.ts.map +1 -1
  279. package/dist/core/model-resolver-initial.js +12 -7
  280. package/dist/core/model-resolver-initial.js.map +1 -1
  281. package/dist/core/model-resolver.d.ts +1 -1
  282. package/dist/core/model-resolver.d.ts.map +1 -1
  283. package/dist/core/model-resolver.js +1 -1
  284. package/dist/core/model-resolver.js.map +1 -1
  285. package/dist/core/resource-loader-context-files.d.ts +1 -0
  286. package/dist/core/resource-loader-context-files.d.ts.map +1 -1
  287. package/dist/core/resource-loader-context-files.js +13 -10
  288. package/dist/core/resource-loader-context-files.js.map +1 -1
  289. package/dist/core/sdk.d.ts.map +1 -1
  290. package/dist/core/sdk.js +2 -2
  291. package/dist/core/sdk.js.map +1 -1
  292. package/dist/core/session-entry-normalization.d.ts +7 -0
  293. package/dist/core/session-entry-normalization.d.ts.map +1 -0
  294. package/dist/core/session-entry-normalization.js +14 -0
  295. package/dist/core/session-entry-normalization.js.map +1 -0
  296. package/dist/core/session-manager-core.d.ts.map +1 -1
  297. package/dist/core/session-manager-core.js +1 -0
  298. package/dist/core/session-manager-core.js.map +1 -1
  299. package/dist/core/session-manager-history.d.ts +2 -2
  300. package/dist/core/session-manager-history.d.ts.map +1 -1
  301. package/dist/core/session-manager-history.js +127 -108
  302. package/dist/core/session-manager-history.js.map +1 -1
  303. package/dist/core/settings-manager-basic-accessors.d.ts +2 -2
  304. package/dist/core/settings-manager-basic-accessors.d.ts.map +1 -1
  305. package/dist/core/settings-manager-basic-accessors.js.map +1 -1
  306. package/dist/core/settings-types.d.ts +1 -1
  307. package/dist/core/settings-types.d.ts.map +1 -1
  308. package/dist/core/settings-types.js.map +1 -1
  309. package/dist/core/tools/bash.d.ts.map +1 -1
  310. package/dist/core/tools/bash.js +11 -8
  311. package/dist/core/tools/bash.js.map +1 -1
  312. package/dist/main-session.d.ts.map +1 -1
  313. package/dist/main-session.js +1 -0
  314. package/dist/main-session.js.map +1 -1
  315. package/dist/modes/interactive/components/settings-selector-options.d.ts.map +1 -1
  316. package/dist/modes/interactive/components/settings-selector-options.js +3 -1
  317. package/dist/modes/interactive/components/settings-selector-options.js.map +1 -1
  318. package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
  319. package/dist/modes/interactive/components/thinking-selector.js +2 -1
  320. package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
  321. package/dist/modes/interactive/interactive-agent-events.d.ts.map +1 -1
  322. package/dist/modes/interactive/interactive-agent-events.js +2 -1
  323. package/dist/modes/interactive/interactive-agent-events.js.map +1 -1
  324. package/dist/modes/interactive/interactive-child-ordering.d.ts +7 -0
  325. package/dist/modes/interactive/interactive-child-ordering.d.ts.map +1 -0
  326. package/dist/modes/interactive/interactive-child-ordering.js +26 -0
  327. package/dist/modes/interactive/interactive-child-ordering.js.map +1 -0
  328. package/dist/modes/interactive/interactive-deferred-startup.d.ts.map +1 -1
  329. package/dist/modes/interactive/interactive-deferred-startup.js +2 -2
  330. package/dist/modes/interactive/interactive-deferred-startup.js.map +1 -1
  331. package/dist/modes/interactive/interactive-mode-deps.d.ts +1 -1
  332. package/dist/modes/interactive/interactive-mode-deps.d.ts.map +1 -1
  333. package/dist/modes/interactive/interactive-mode-deps.js +1 -1
  334. package/dist/modes/interactive/interactive-mode-deps.js.map +1 -1
  335. package/dist/modes/interactive/interactive-model-routing.d.ts.map +1 -1
  336. package/dist/modes/interactive/interactive-model-routing.js +8 -3
  337. package/dist/modes/interactive/interactive-model-routing.js.map +1 -1
  338. package/dist/modes/interactive/theme/theme-class.d.ts +1 -1
  339. package/dist/modes/interactive/theme/theme-class.d.ts.map +1 -1
  340. package/dist/modes/interactive/theme/theme-class.js +2 -0
  341. package/dist/modes/interactive/theme/theme-class.js.map +1 -1
  342. package/dist/utils/clipboard-image.d.ts.map +1 -1
  343. package/dist/utils/clipboard-image.js +3 -0
  344. package/dist/utils/clipboard-image.js.map +1 -1
  345. package/docs/changelog.mdx +19 -0
  346. package/docs/compaction.md +55 -48
  347. package/docs/custom-provider.md +18 -5
  348. package/docs/extensions.md +7 -3
  349. package/docs/models.md +69 -10
  350. package/docs/providers.md +1 -1
  351. package/docs/quickstart.md +11 -7
  352. package/docs/rpc.md +2 -2
  353. package/docs/sdk.md +1 -1
  354. package/docs/settings.md +3 -3
  355. package/docs/subagents.md +36 -5
  356. package/docs/tools.md +1 -1
  357. package/docs/usage.md +4 -2
  358. package/docs/workflows.md +26 -43
  359. package/examples/extensions/preset.ts +2 -2
  360. package/examples/extensions/subagent/README.md +2 -2
  361. package/examples/extensions/subagent/index.ts +1 -2
  362. package/examples/extensions/subagent/schemas.ts +4 -1
  363. package/examples/sdk/12-full-control.ts +1 -1
  364. package/npm-shrinkwrap.json +48 -51
  365. package/package.json +7 -7
  366. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-behavior.ts +0 -75
  367. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-component.ts +0 -202
  368. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-edit.ts +0 -97
  369. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-editor.ts +0 -160
  370. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-frame.ts +0 -72
  371. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-render-modes.ts +0 -161
  372. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-render-selectors.ts +0 -203
  373. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-selectors.ts +0 -234
  374. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-state.ts +0 -103
  375. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-types.ts +0 -29
  376. package/dist/builtin/subagents/src/runs/foreground/chain-clarify.ts +0 -9
  377. package/dist/builtin/subagents/src/runs/foreground/chain-execution-clarify.ts +0 -117
@@ -1,7 +1,6 @@
1
1
  import { spawn } from "node:child_process";
2
2
  import * as fs from "node:fs";
3
3
  import type { Message } from "@earendil-works/pi-ai/compat";
4
- import { appendJsonl } from "../../shared/artifacts.ts";
5
4
  import { attachPostExitStdioGuard, trySignalChild } from "../../shared/post-exit-stdio-guard.ts";
6
5
  import { detectSubagentError, extractTextFromContent, extractToolArgsPreview, getFinalOutput } from "../../shared/utils.ts";
7
6
  import { getSubagentDepthEnv } from "../../shared/types.ts";
@@ -14,6 +13,7 @@ import {
14
13
  import { modelFailureMessage } from "../shared/model-fallback.ts";
15
14
  import { createAttemptWatchdog } from "../shared/attempt-watchdog.ts";
16
15
  import type { ChildEvent, ChildEventContext, RunPiStreamingResult } from "./subagent-runner-types.ts";
16
+ import { createChildEventJournal } from "./async-event-journal.ts";
17
17
  import { emptyUsage } from "./subagent-runner-utils.ts";
18
18
 
19
19
  export function runPiStreaming(
@@ -57,6 +57,11 @@ export function runPiStreaming(
57
57
  env: spawnEnv,
58
58
  windowsHide: true,
59
59
  });
60
+ const childEventJournal = createChildEventJournal(childEventContext?.eventsPath, child.stdout, {
61
+ runId: childEventContext?.runId ?? "",
62
+ stepIndex: childEventContext?.stepIndex,
63
+ agent: childEventContext?.agent ?? "",
64
+ });
60
65
  let stderr = "";
61
66
  let stdoutBuf = "";
62
67
  let stderrBuf = "";
@@ -66,6 +71,7 @@ export function runPiStreaming(
66
71
  let error: string | undefined;
67
72
  let assistantError: string | undefined;
68
73
  let assistantFailureSignal: unknown;
74
+ let spawnErrorText: string | undefined;
69
75
  let interrupted = false;
70
76
  let activeToolExecutions = 0;
71
77
  const rawStdoutLines: string[] = [];
@@ -83,14 +89,7 @@ export function runPiStreaming(
83
89
 
84
90
  const appendChildEvent = (event: Record<string, unknown> | ChildEvent) => {
85
91
  if (!childEventContext) return;
86
- appendJsonl(childEventContext.eventsPath, JSON.stringify({
87
- ...event,
88
- subagentSource: "child",
89
- subagentRunId: childEventContext.runId,
90
- subagentStepIndex: childEventContext.stepIndex,
91
- subagentAgent: childEventContext.agent,
92
- observedAt: Date.now(),
93
- }));
92
+ childEventJournal.append({ ...event });
94
93
  };
95
94
 
96
95
  const appendChildLine = (type: "subagent.child.stdout" | "subagent.child.stderr", line: string) => {
@@ -249,7 +248,7 @@ export function runPiStreaming(
249
248
  childExited = true;
250
249
  clearDrainTimers();
251
250
  });
252
- child.on("close", (exitCode, signal) => {
251
+ child.on("close", async (exitCode, signal) => {
253
252
  settled = true;
254
253
  registerInterrupt?.(undefined);
255
254
  clearDrainTimers();
@@ -258,8 +257,9 @@ export function runPiStreaming(
258
257
  if (stdoutBuf.trim()) processStdoutLine(stdoutBuf);
259
258
  if (stderrBuf.trim()) appendChildLine("subagent.child.stderr", stderrBuf);
260
259
  outputStream.end();
260
+ await childEventJournal.close();
261
261
  const finalOutput = getFinalOutput(messages) || rawStdoutLines.join("\n").trim();
262
- const finalError = error ?? assistantError;
262
+ const finalError = error ?? assistantError ?? spawnErrorText;
263
263
  const forcedDrainAfterFinalSuccess = forcedTerminationSignal && cleanTerminalAssistantStopReceived && !finalError;
264
264
  resolve({
265
265
  stderr,
@@ -276,15 +276,19 @@ export function runPiStreaming(
276
276
  });
277
277
  });
278
278
 
279
- child.on("error", (spawnError) => {
279
+ child.on("error", async (spawnError) => {
280
+ // Capture the diagnostic before awaiting journal drain: `close` may fire
281
+ // while this handler is suspended and win Promise settlement.
282
+ spawnErrorText = formatPiSpawnError(spawnError, spawnSpec, cwd);
280
283
  settled = true;
281
284
  registerInterrupt?.(undefined);
282
285
  clearDrainTimers();
283
286
  clearStdioGuard();
284
287
  attemptWatchdog.clear();
285
288
  outputStream.end();
289
+ await childEventJournal.close();
286
290
  const finalOutput = getFinalOutput(messages) || rawStdoutLines.join("\n").trim();
287
- const finalError = error ?? assistantError ?? formatPiSpawnError(spawnError, spawnSpec, cwd);
291
+ const finalError = error ?? assistantError ?? spawnErrorText;
288
292
  resolve({
289
293
  stderr,
290
294
  exitCode: 1,
@@ -1,6 +1,5 @@
1
1
  interface AsyncOverrideParams {
2
2
  async?: boolean;
3
- clarify?: boolean;
4
3
  }
5
4
 
6
5
  export function applyForceTopLevelAsyncOverride<T extends AsyncOverrideParams>(
@@ -9,5 +8,5 @@ export function applyForceTopLevelAsyncOverride<T extends AsyncOverrideParams>(
9
8
  forceTopLevelAsync: boolean,
10
9
  ): T {
11
10
  if (!(depth === 0 && forceTopLevelAsync)) return params;
12
- return { ...params, async: true, clarify: false };
11
+ return { ...params, async: true };
13
12
  }
@@ -129,6 +129,7 @@ export async function runDynamicParallelChainStep(input: {
129
129
  maxSubagentDepth: context.params.maxSubagentDepth,
130
130
  workflowStageSubagentGuard: context.params.workflowStageSubagentGuard,
131
131
  runSync: context.executeRunSync,
132
+ onDetachedExit: context.onDetachedExit,
132
133
  });
133
134
  state.globalTaskIndex += dynamicParallelStep.parallel.length;
134
135
  for (const result of parallelResults) {
@@ -123,6 +123,7 @@ export async function runParallelChainTasks(input: ParallelChainRunInput): Promi
123
123
  intercomSessionName: input.childIntercomTarget?.(task.agent, input.globalTaskIndex + taskIndex),
124
124
  orchestratorIntercomTarget: input.orchestratorIntercomTarget,
125
125
  nestedRoute: input.nestedRoute,
126
+ onDetachedExit: (recovered) => input.onDetachedExit?.(input.globalTaskIndex + taskIndex, recovered),
126
127
  modelOverride: effectiveModel,
127
128
  availableModels: input.availableModels,
128
129
  knownModelProviders: input.knownModelProviders,
@@ -112,6 +112,7 @@ export async function runStaticParallelChainStep(input: {
112
112
  maxSubagentDepth: context.params.maxSubagentDepth,
113
113
  workflowStageSubagentGuard: context.params.workflowStageSubagentGuard,
114
114
  runSync: context.executeRunSync,
115
+ onDetachedExit: context.onDetachedExit,
115
116
  });
116
117
  state.globalTaskIndex += step.parallel.length;
117
118
  for (const result of parallelResults) {
@@ -20,7 +20,6 @@ import { validateFileOnlyOutputMode } from "../shared/single-output.ts";
20
20
  import { createStructuredOutputRuntime } from "../shared/structured-output.ts";
21
21
  import { buildWorkflowGraphSnapshot } from "../shared/workflow-graph.ts";
22
22
  import { buildChainExecutionDetails, buildChainExecutionErrorResult } from "./chain-execution-details.ts";
23
- import type { BehaviorOverride } from "./chain-clarify.ts";
24
23
  import type { ChainExecutionMutableState, ChainExecutionResult, ChainRuntimeContext } from "./chain-execution-types.ts";
25
24
 
26
25
  export async function runSequentialChainStep(input: {
@@ -29,9 +28,8 @@ export async function runSequentialChainStep(input: {
29
28
  seqStep: SequentialStep;
30
29
  stepIndex: number;
31
30
  stepTemplate: string;
32
- tuiOverride?: BehaviorOverride;
33
31
  }): Promise<ChainExecutionResult | undefined> {
34
- const { context, state, seqStep, stepIndex, stepTemplate, tuiOverride } = input;
32
+ const { context, state, seqStep, stepIndex, stepTemplate } = input;
35
33
  const agentConfig = context.agents.find((agent) => agent.name === seqStep.agent);
36
34
  if (!agentConfig) {
37
35
  removeChainDir(context.chainDir);
@@ -43,11 +41,11 @@ export async function runSequentialChainStep(input: {
43
41
  }
44
42
 
45
43
  const stepOverride: StepOverrides = {
46
- output: tuiOverride?.output !== undefined ? tuiOverride.output : seqStep.output,
44
+ output: seqStep.output,
47
45
  outputMode: seqStep.outputMode,
48
- reads: tuiOverride?.reads !== undefined ? tuiOverride.reads : seqStep.reads,
49
- progress: tuiOverride?.progress !== undefined ? tuiOverride.progress : seqStep.progress,
50
- skills: tuiOverride?.skills !== undefined ? tuiOverride.skills : normalizeSkillInput(seqStep.skill),
46
+ reads: seqStep.reads,
47
+ progress: seqStep.progress,
48
+ skills: normalizeSkillInput(seqStep.skill),
51
49
  };
52
50
  const behavior = suppressProgressForReadOnlyTask(
53
51
  resolveStepBehavior(agentConfig, stepOverride, context.chainSkills),
@@ -73,8 +71,7 @@ export async function runSequentialChainStep(input: {
73
71
  stepTask = prefix + stepTask + suffix;
74
72
 
75
73
  const effectiveModel =
76
- tuiOverride?.model
77
- ?? (seqStep.model ? resolveModelCandidate(seqStep.model, context.availableModels, context.ctx.model?.provider) : null)
74
+ (seqStep.model ? resolveModelCandidate(seqStep.model, context.availableModels, context.ctx.model?.provider) : null)
78
75
  ?? resolveModelCandidate(agentConfig.model, context.availableModels, context.ctx.model?.provider);
79
76
  const outputPath = typeof behavior.output === "string"
80
77
  ? (path.isAbsolute(behavior.output) ? behavior.output : path.join(context.chainDir, behavior.output))
@@ -124,6 +121,7 @@ export async function runSequentialChainStep(input: {
124
121
  intercomSessionName: context.childIntercomTarget?.(seqStep.agent, flatIndex),
125
122
  orchestratorIntercomTarget: context.orchestratorIntercomTarget,
126
123
  nestedRoute: context.params.nestedRoute,
124
+ onDetachedExit: (recovered) => context.onDetachedExit?.(flatIndex, recovered),
127
125
  modelOverride: effectiveModel,
128
126
  availableModels: context.availableModels,
129
127
  knownModelProviders: context.knownModelProviders,
@@ -6,7 +6,6 @@ import type {
6
6
  ChainStep,
7
7
  ParallelStep,
8
8
  ResolvedStepBehavior,
9
- ResolvedTemplates,
10
9
  } from "../../shared/settings.ts";
11
10
  import type {
12
11
  ActivityState,
@@ -23,7 +22,6 @@ import type {
23
22
  import type { ChainOutputMap } from "../../shared/types.ts";
24
23
  import type { WorktreeSetup } from "../shared/worktree.ts";
25
24
  import type { runSync } from "./execution.ts";
26
- import type { BehaviorOverride } from "./chain-clarify.ts";
27
25
 
28
26
  export type RunSyncDependency = typeof runSync;
29
27
 
@@ -74,7 +72,6 @@ export interface ChainExecutionParams {
74
72
  artifactsDir: string;
75
73
  artifactConfig: ArtifactConfig;
76
74
  includeProgress?: boolean;
77
- clarify?: boolean;
78
75
  onUpdate?: (r: AgentToolResult<Details>) => void;
79
76
  onControlEvent?: (event: ControlEvent) => void;
80
77
  controlConfig: ResolvedControlConfig;
@@ -90,16 +87,13 @@ export interface ChainExecutionParams {
90
87
  worktreeSetupHook?: string;
91
88
  worktreeSetupHookTimeoutMs?: number;
92
89
  runSync?: RunSyncDependency;
90
+ onDetachedExit?: (index: number, result: SingleResult) => void;
93
91
  }
94
92
 
95
93
  export interface ChainExecutionResult {
96
94
  content: Array<{ type: "text"; text: string }>;
97
95
  details: Details;
98
96
  isError?: boolean;
99
- requestedAsync?: {
100
- chain: ChainStep[];
101
- chainSkills: string[];
102
- };
103
97
  }
104
98
 
105
99
  export interface ParallelChainRunInput {
@@ -143,6 +137,7 @@ export interface ParallelChainRunInput {
143
137
  workflowStageSubagentGuard?: boolean;
144
138
  nestedRoute?: NestedRouteInfo;
145
139
  runSync: RunSyncDependency;
140
+ onDetachedExit?: (index: number, result: SingleResult) => void;
146
141
  }
147
142
 
148
143
  export interface ChainExecutionMutableState {
@@ -187,10 +182,5 @@ export interface ChainRuntimeContext {
187
182
  totalSteps: number;
188
183
  executeRunSync: RunSyncDependency;
189
184
  makeDetailsInput(overrides?: Pick<Partial<ChainExecutionDetailsInput>, "currentStepIndex" | "currentFlatIndex">): ChainExecutionDetailsInput;
185
+ onDetachedExit?: (index: number, result: SingleResult) => void;
190
186
  }
191
-
192
- export type ChainClarificationOutcome = {
193
- result?: ChainExecutionResult;
194
- templates: ResolvedTemplates;
195
- tuiBehaviorOverrides?: (BehaviorOverride | undefined)[];
196
- };
@@ -14,7 +14,6 @@ import {
14
14
  import { buildChainSummary } from "../../shared/formatters.ts";
15
15
  import { ChainOutputValidationError, validateChainOutputBindings } from "../shared/chain-outputs.ts";
16
16
  import { buildChainExecutionDetails } from "./chain-execution-details.ts";
17
- import { resolveChainClarification } from "./chain-execution-clarify.ts";
18
17
  import { runDynamicParallelChainStep } from "./chain-execution-dynamic-step.ts";
19
18
  import { runStaticParallelChainStep } from "./chain-execution-parallel-step.ts";
20
19
  import { runSequentialChainStep } from "./chain-execution-sequential-step.ts";
@@ -45,7 +44,6 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
45
44
  artifactsDir,
46
45
  artifactConfig,
47
46
  includeProgress,
48
- clarify,
49
47
  onUpdate,
50
48
  onControlEvent,
51
49
  controlConfig,
@@ -113,9 +111,7 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
113
111
  }
114
112
 
115
113
  const chainDir = createChainDir(runId, chainDirBase);
116
- const hasParallelSteps = chainSteps.some((step) => isParallelStep(step) || isDynamicParallelStep(step));
117
- let templates: ResolvedTemplates = resolveChainTemplates(chainSteps);
118
- let tuiBehaviorOverrides: Awaited<ReturnType<typeof resolveChainClarification>>["tuiBehaviorOverrides"];
114
+ const templates: ResolvedTemplates = resolveChainTemplates(chainSteps);
119
115
  const availableModels: ModelInfo[] = ctx.modelRegistry.getAvailable().map(toModelInfo);
120
116
  const knownModelProviders = collectKnownModelProviders(ctx.modelRegistry);
121
117
  const context: ChainRuntimeContext = {
@@ -148,17 +144,9 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
148
144
  totalSteps,
149
145
  executeRunSync,
150
146
  makeDetailsInput,
147
+ onDetachedExit: params.onDetachedExit,
151
148
  };
152
149
 
153
- const clarification = await resolveChainClarification({
154
- context,
155
- templates,
156
- shouldClarify: clarify !== false && ctx.hasUI && !hasParallelSteps,
157
- });
158
- if (clarification.result) return clarification.result;
159
- templates = clarification.templates;
160
- tuiBehaviorOverrides = clarification.tuiBehaviorOverrides;
161
-
162
150
  for (let stepIndex = 0; stepIndex < chainSteps.length; stepIndex++) {
163
151
  const step = chainSteps[stepIndex]!;
164
152
  const stepTemplates = templates[stepIndex]!;
@@ -180,7 +168,6 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
180
168
  seqStep: step as SequentialStep,
181
169
  stepIndex,
182
170
  stepTemplate: stepTemplates as string,
183
- tuiOverride: tuiBehaviorOverrides?.[stepIndex],
184
171
  });
185
172
  }
186
173
  if (earlyResult) return earlyResult;
@@ -33,8 +33,8 @@ export function finalizeSingleAttempt(input: {
33
33
  return result;
34
34
  }
35
35
  if (result.detached) {
36
- result.exitCode = 0;
37
- result.finalOutput = "Detached for intercom coordination.";
36
+ result.exitCode = -2;
37
+ result.finalOutput = "Detached for intercom coordination; awaiting the child's eventual result.";
38
38
  return result;
39
39
  }
40
40
 
@@ -3,12 +3,8 @@ import { existsSync, unlinkSync } from "node:fs";
3
3
  import type { Message } from "@earendil-works/pi-ai/compat";
4
4
  import type { AgentConfig } from "../../agents/agents.ts";
5
5
  import {
6
- type AgentProgress,
7
- type RunSyncOptions,
8
- type SingleResult,
9
- INTERCOM_DETACH_REQUEST_EVENT,
10
- INTERCOM_DETACH_RESPONSE_EVENT,
11
- getSubagentDepthEnv,
6
+ type AgentProgress, type RunSyncOptions, type SingleResult,
7
+ INTERCOM_DETACH_REQUEST_EVENT, INTERCOM_DETACH_RESPONSE_EVENT, getSubagentDepthEnv,
12
8
  } from "../../shared/types.ts";
13
9
  import { extractTextFromContent, extractToolArgsPreview, getFinalOutput } from "../../shared/utils.ts";
14
10
  import { createJsonlWriter } from "../../shared/jsonl-writer.ts";
@@ -18,6 +14,8 @@ import { formatPiSpawnError, getPiSpawnCommand, validatePiSpawnCwd } from "../sh
18
14
  import { assistantStopReason, isAssistantFailureStopReason, shouldStartSubagentFinalDrain } from "../shared/final-drain.ts";
19
15
  import { modelFailureMessage } from "../shared/model-fallback.ts";
20
16
  import { createAttemptWatchdog } from "../shared/attempt-watchdog.ts";
17
+ import { matchesIntercomDetachRoute, type IntercomDetachRoute } from "./execution-detach-route.ts";
18
+ import { IntercomDetachReservations } from "./execution-detach-reservations.ts";
21
19
  import {
22
20
  createMutatingFailureState,
23
21
  didMutatingToolFail,
@@ -33,7 +31,6 @@ import { appendRecentOutput, emptyUsage, modelFailureSignalByResult, snapshotPro
33
31
  import { createAttemptControlRuntime } from "./execution-attempt-control.ts";
34
32
  import { finalizeSingleAttempt } from "./execution-attempt-finalize.ts";
35
33
  import type { RunSingleAttemptShared } from "./execution-attempt-types.ts";
36
-
37
34
  export async function runSingleAttempt(
38
35
  runtimeCwd: string,
39
36
  agent: AgentConfig,
@@ -80,7 +77,6 @@ export async function runSingleAttempt(
80
77
  codexFastModeScope: shared.fastModeScope,
81
78
  structuredOutput: options.structuredOutput,
82
79
  });
83
-
84
80
  const result: SingleResult = {
85
81
  agent: agent.name,
86
82
  task: shared.originalTask ?? task,
@@ -145,24 +141,21 @@ export async function runSingleAttempt(
145
141
  let processClosed = false;
146
142
  let settled = false;
147
143
  let detached = false;
148
- let intercomStarted = false;
149
144
  let assistantError: string | undefined;
150
145
  let assistantFailureSignal: unknown;
151
146
  let removeAbortListener: (() => void) | undefined;
152
147
  let removeInterruptListener: (() => void) | undefined;
153
148
  let activityTimer: NodeJS.Timeout | undefined;
154
-
155
149
  const detachForIntercom = () => {
156
150
  detached = true;
157
- processClosed = true;
158
151
  result.detached = true;
159
152
  result.detachedReason = "intercom coordination";
160
153
  progress.status = "detached";
161
154
  progress.durationMs = Date.now() - startTime;
162
155
  result.progressSummary = { toolCount: progress.toolCount, tokens: progress.tokens, durationMs: progress.durationMs };
163
- finish(-2);
156
+ // Settle the foreground tool call, but retain process lifecycle ownership.
157
+ finish(-2, true);
164
158
  };
165
-
166
159
  const FINAL_STOP_GRACE_MS = 1000;
167
160
  const HARD_KILL_MS = 3000;
168
161
  let childExited = false;
@@ -181,9 +174,9 @@ export async function runSingleAttempt(
181
174
  }
182
175
  };
183
176
  const startFinalDrain = () => {
184
- if (childExited || finalDrainTimer || settled || processClosed || detached) return;
177
+ if (childExited || finalDrainTimer || processClosed) return;
185
178
  finalDrainTimer = setTimeout(() => {
186
- if (settled || processClosed || detached) return;
179
+ if (processClosed) return;
187
180
  const termSent = trySignalChild(proc, "SIGTERM");
188
181
  if (!termSent) return;
189
182
  forcedTerminationSignal = true;
@@ -191,39 +184,49 @@ export async function runSingleAttempt(
191
184
  result.error = result.error ?? `Subagent process did not exit within ${FINAL_STOP_GRACE_MS}ms after its final message. Forcing termination.`;
192
185
  }
193
186
  finalHardKillTimer = setTimeout(() => {
194
- if (settled || processClosed || detached) return;
187
+ if (processClosed) return;
195
188
  forcedTerminationSignal = trySignalChild(proc, "SIGKILL") || forcedTerminationSignal;
196
189
  }, HARD_KILL_MS);
197
190
  finalHardKillTimer.unref?.();
198
191
  }, FINAL_STOP_GRACE_MS);
199
192
  finalDrainTimer.unref?.();
200
193
  };
201
-
194
+ const detachReservations = new IntercomDetachReservations();
202
195
  const unsubscribeIntercomDetach = options.intercomEvents?.on?.(INTERCOM_DETACH_REQUEST_EVENT, (payload) => {
203
- if (!options.allowIntercomDetach || detached || processClosed || !intercomStarted) return;
196
+ if (!options.allowIntercomDetach || processClosed || options.signal?.aborted) return;
204
197
  if (!payload || typeof payload !== "object") return;
205
- const requestId = (payload as { requestId?: unknown }).requestId;
206
- if (typeof requestId !== "string" || requestId.length === 0) return;
207
- options.intercomEvents?.emit(INTERCOM_DETACH_RESPONSE_EVENT, { requestId, accepted: true });
198
+ const event = payload as IntercomDetachRoute;
199
+ const reservationKeyValid = typeof event.requestId === "string";
200
+ if (!reservationKeyValid || !matchesIntercomDetachRoute(event, {
201
+ childIntercomTarget: options.intercomSessionName,
202
+ })) return;
203
+ if (event.phase === "probe") {
204
+ if (detached || !detachReservations.reserve(event)) return;
205
+ options.intercomEvents?.emit?.(INTERCOM_DETACH_RESPONSE_EVENT, { ...event, accepted: true });
206
+ return;
207
+ }
208
+ if (event.phase !== "commit" || detached || !detachReservations.commit(event)) return;
208
209
  detachForIntercom();
210
+ options.intercomEvents?.emit?.(INTERCOM_DETACH_RESPONSE_EVENT, { ...event, accepted: true });
209
211
  });
210
-
211
- const finish = (code: number) => {
212
+ const finish = (code: number, retainLifecycleOwner = false) => {
212
213
  if (settled) return;
213
214
  settled = true;
214
- clearFinalDrainTimers();
215
- clearStdioGuard();
216
- attemptWatchdog.clear();
215
+ if (!retainLifecycleOwner) {
216
+ clearFinalDrainTimers();
217
+ clearStdioGuard();
218
+ attemptWatchdog.clear();
219
+ removeAbortListener?.();
220
+ detachReservations.clear();
221
+ unsubscribeIntercomDetach?.();
222
+ }
217
223
  if (activityTimer) {
218
224
  clearInterval(activityTimer);
219
225
  activityTimer = undefined;
220
226
  }
221
- unsubscribeIntercomDetach?.();
222
- removeAbortListener?.();
223
227
  removeInterruptListener?.();
224
228
  resolve(code);
225
229
  };
226
-
227
230
  let pendingToolResult: { tool: string; path?: string; mutates: boolean; startedAt?: number } | undefined;
228
231
  const mutatingFailures = createMutatingFailureState();
229
232
  const mutatingFailureWindowMs = 5 * 60_000;
@@ -246,7 +249,6 @@ export async function runSingleAttempt(
246
249
  progress.durationMs = Date.now() - startTime;
247
250
  emitUpdateSnapshot(getFinalOutput(result.messages ?? []) || "(running...)");
248
251
  };
249
-
250
252
  const processLine = (line: string) => {
251
253
  if (!line.trim()) return;
252
254
  jsonlWriter.writeLine(line);
@@ -264,7 +266,8 @@ export async function runSingleAttempt(
264
266
 
265
267
  if (evt.type === "tool_execution_start") {
266
268
  const toolArgs = evt.args && typeof evt.args === "object" && !Array.isArray(evt.args) ? evt.args as Record<string, unknown> : {};
267
- if (options.allowIntercomDetach && (evt.toolName === "intercom" || evt.toolName === "contact_supervisor")) intercomStarted = true;
269
+ // Broker delivery is the authoritative detach trigger; tool-start observation
270
+ // is intentionally not required because the broker event may arrive first.
268
271
  progress.toolCount++;
269
272
  progress.currentTool = evt.toolName;
270
273
  progress.currentToolArgs = extractToolArgsPreview(toolArgs);
@@ -370,7 +373,7 @@ export async function runSingleAttempt(
370
373
  const clearStdioGuard = attachPostExitStdioGuard(proc, { idleMs: 2000, hardMs: 8000 });
371
374
  const attemptWatchdog = createAttemptWatchdog({
372
375
  child: proc,
373
- isSettled: () => settled || processClosed || detached,
376
+ isSettled: () => processClosed,
374
377
  // A slow, quiet tool call (long build/test run) must not be mistaken for a
375
378
  // stalled attempt: an in-flight tool execution counts as watchdog activity.
376
379
  // Caveat: `progress.currentTool` is cleared on tool_execution_end, so if a
@@ -403,13 +406,12 @@ export async function runSingleAttempt(
403
406
  clearFinalDrainTimers();
404
407
  clearStdioGuard();
405
408
  attemptWatchdog.clear();
409
+ removeAbortListener?.(); removeAbortListener = undefined;
410
+ removeInterruptListener?.(); removeInterruptListener = undefined;
411
+ detachReservations.clear();
412
+ unsubscribeIntercomDetach?.();
406
413
  void jsonlWriter.close().catch(() => undefined);
407
414
  cleanupTempDir(tempDir);
408
- if (detached) {
409
- finish(-2);
410
- return;
411
- }
412
- processClosed = true;
413
415
  if (buf.trim()) processLine(buf);
414
416
  if (!result.error && assistantError) result.error = assistantError;
415
417
  if (assistantFailureSignal !== undefined && result.error === assistantError) {
@@ -418,6 +420,17 @@ export async function runSingleAttempt(
418
420
  const forcedDrainAfterFinalSuccess = forcedTerminationSignal && cleanTerminalAssistantStopReceived && !result.error;
419
421
  if (code !== 0 && stderrBuf.trim() && !result.error && !forcedDrainAfterFinalSuccess) result.error = stderrBuf.trim();
420
422
  const finalCode = forcedDrainAfterFinalSuccess ? 0 : forcedTerminationSignal || signal ? (code ?? 1) : (code ?? 0);
423
+ if (detached) {
424
+ processClosed = true;
425
+ const recovered: SingleResult = { ...result, detached: undefined, detachedReason: undefined };
426
+ const recoveredProgress = recovered.progress ? { ...recovered.progress } : progress;
427
+ options.onDetachedExit?.(finalizeSingleAttempt({
428
+ result: recovered, progress: recoveredProgress, exitCode: finalCode, interruptedByControl,
429
+ allControlEvents: controlRuntime.allControlEvents, options: { ...options, onUpdate: undefined }, shared, startTime,
430
+ }));
431
+ return;
432
+ }
433
+ processClosed = true;
421
434
  finish(finalCode);
422
435
  });
423
436
  proc.on("error", (error) => {
@@ -432,13 +445,9 @@ export async function runSingleAttempt(
432
445
 
433
446
  if (options.signal) {
434
447
  const kill = () => {
435
- if (processClosed || detached) return;
436
- if (options.allowIntercomDetach && intercomStarted) {
437
- detachForIntercom();
438
- return;
439
- }
440
- proc.kill("SIGTERM");
441
- setTimeout(() => !proc.killed && proc.kill("SIGKILL"), 3000);
448
+ if (childExited) return;
449
+ trySignalChild(proc, "SIGTERM");
450
+ setTimeout(() => { if (!childExited) trySignalChild(proc, "SIGKILL"); }, 3000).unref?.();
442
451
  };
443
452
  if (options.signal.aborted) kill();
444
453
  else {
@@ -0,0 +1,48 @@
1
+ import type { IntercomDetachRoute } from "./execution-detach-route.js";
2
+
3
+ interface Reservation {
4
+ route: IntercomDetachRoute;
5
+ timer: ReturnType<typeof setTimeout>;
6
+ }
7
+
8
+ function identity(event: IntercomDetachRoute): string | undefined {
9
+ if (typeof event.requestId !== "string" || event.requestId.length === 0
10
+ || typeof event.messageId !== "string" || event.messageId.length === 0
11
+ || typeof event.senderId !== "string" || event.senderId.length === 0
12
+ || typeof event.runtimeGeneration !== "number") return undefined;
13
+ return `${event.requestId}\0${event.messageId}\0${event.senderId}\0${event.runtimeGeneration}`;
14
+ }
15
+
16
+ function sameRoute(left: IntercomDetachRoute, right: IntercomDetachRoute): boolean {
17
+ return left.requestId === right.requestId && left.messageId === right.messageId
18
+ && left.senderId === right.senderId && left.runtimeGeneration === right.runtimeGeneration
19
+ && left.childIntercomTarget === right.childIntercomTarget;
20
+ }
21
+
22
+ export class IntercomDetachReservations {
23
+ private readonly entries = new Map<string, Reservation>();
24
+
25
+ reserve(event: IntercomDetachRoute): boolean {
26
+ const key = identity(event);
27
+ if (!key || this.entries.has(key)) return false;
28
+ const timer = setTimeout(() => this.entries.delete(key), 1000);
29
+ timer.unref?.();
30
+ this.entries.set(key, { route: event, timer });
31
+ return true;
32
+ }
33
+
34
+ commit(event: IntercomDetachRoute): boolean {
35
+ const key = identity(event);
36
+ if (!key) return false;
37
+ const reservation = this.entries.get(key);
38
+ if (!reservation || !sameRoute(event, reservation.route)) return false;
39
+ clearTimeout(reservation.timer);
40
+ this.entries.delete(key);
41
+ return true;
42
+ }
43
+
44
+ clear(): void {
45
+ for (const reservation of this.entries.values()) clearTimeout(reservation.timer);
46
+ this.entries.clear();
47
+ }
48
+ }
@@ -0,0 +1,17 @@
1
+ export interface IntercomDetachRoute {
2
+ phase?: unknown;
3
+ requestId?: unknown;
4
+ messageId?: unknown;
5
+ senderId?: unknown;
6
+ childIntercomTarget?: unknown;
7
+ runtimeGeneration?: unknown;
8
+ }
9
+
10
+ export function matchesIntercomDetachRoute(
11
+ event: IntercomDetachRoute,
12
+ expected: { childIntercomTarget?: string },
13
+ ): boolean {
14
+ return typeof event.childIntercomTarget === "string"
15
+ && event.childIntercomTarget.length > 0
16
+ && event.childIntercomTarget === expected.childIntercomTarget;
17
+ }