@bastani/atomic 0.9.5-alpha.8 → 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 (530) hide show
  1. package/CHANGELOG.md +122 -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 +38 -0
  27. package/dist/builtin/mcp/OAUTH.md +1 -0
  28. package/dist/builtin/mcp/README.md +10 -6
  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 +40 -255
  35. package/dist/builtin/mcp/host-html-template.ts +4 -2
  36. package/dist/builtin/mcp/index.ts +274 -239
  37. package/dist/builtin/mcp/init.ts +96 -126
  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 +52 -0
  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 +106 -23
  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/startup-warmup.ts +98 -0
  50. package/dist/builtin/mcp/state-lease.ts +12 -0
  51. package/dist/builtin/mcp/tool-result-renderer.ts +3 -3
  52. package/dist/builtin/mcp/ui-server.ts +8 -8
  53. package/dist/builtin/mcp/ui-session.ts +9 -18
  54. package/dist/builtin/subagents/CHANGELOG.md +78 -0
  55. package/dist/builtin/subagents/README.md +30 -29
  56. package/dist/builtin/subagents/agents/code-simplifier.md +2 -2
  57. package/dist/builtin/subagents/agents/codebase-analyzer.md +2 -2
  58. package/dist/builtin/subagents/agents/codebase-locator.md +2 -2
  59. package/dist/builtin/subagents/agents/codebase-online-researcher.md +2 -2
  60. package/dist/builtin/subagents/agents/codebase-pattern-finder.md +2 -2
  61. package/dist/builtin/subagents/agents/codebase-research-analyzer.md +2 -2
  62. package/dist/builtin/subagents/agents/codebase-research-locator.md +2 -2
  63. package/dist/builtin/subagents/agents/debugger.md +2 -2
  64. package/dist/builtin/subagents/agents/worker.md +2 -2
  65. package/dist/builtin/subagents/package.json +5 -5
  66. package/dist/builtin/subagents/prompts/review-loop.md +1 -1
  67. package/dist/builtin/subagents/skills/subagent/SKILL.md +37 -36
  68. package/dist/builtin/subagents/src/extension/api-lifecycle.ts +64 -0
  69. package/dist/builtin/subagents/src/extension/fanout-child.ts +44 -51
  70. package/dist/builtin/subagents/src/extension/index.ts +289 -320
  71. package/dist/builtin/subagents/src/extension/prompt-guidance.ts +7 -10
  72. package/dist/builtin/subagents/src/extension/schemas.ts +22 -5
  73. package/dist/builtin/subagents/src/extension/startup-maintenance.ts +89 -0
  74. package/dist/builtin/subagents/src/extension/tool-description.ts +29 -0
  75. package/dist/builtin/subagents/src/intercom/intercom-bridge.ts +13 -2
  76. package/dist/builtin/subagents/src/intercom/result-intercom.ts +4 -4
  77. package/dist/builtin/subagents/src/runs/background/async-event-journal.ts +106 -0
  78. package/dist/builtin/subagents/src/runs/background/async-execution-common.ts +26 -20
  79. package/dist/builtin/subagents/src/runs/background/async-execution-single.ts +13 -2
  80. package/dist/builtin/subagents/src/runs/background/async-execution-types.ts +3 -0
  81. package/dist/builtin/subagents/src/runs/background/async-job-tracker.ts +1 -1
  82. package/dist/builtin/subagents/src/runs/background/completion-claims.ts +189 -0
  83. package/dist/builtin/subagents/src/runs/background/completion-dedupe.ts +44 -7
  84. package/dist/builtin/subagents/src/runs/background/completion-notification.ts +34 -0
  85. package/dist/builtin/subagents/src/runs/background/notify.ts +72 -22
  86. package/dist/builtin/subagents/src/runs/background/result-delivery-processor.ts +232 -0
  87. package/dist/builtin/subagents/src/runs/background/result-file-claims.ts +151 -0
  88. package/dist/builtin/subagents/src/runs/background/result-quarantine.ts +72 -0
  89. package/dist/builtin/subagents/src/runs/background/result-retry-scheduler.ts +48 -0
  90. package/dist/builtin/subagents/src/runs/background/result-status.ts +81 -0
  91. package/dist/builtin/subagents/src/runs/background/result-watcher-data.ts +59 -0
  92. package/dist/builtin/subagents/src/runs/background/result-watcher.ts +177 -233
  93. package/dist/builtin/subagents/src/runs/background/run-id-resolver.ts +3 -2
  94. package/dist/builtin/subagents/src/runs/background/stale-run-reconciler.ts +73 -14
  95. package/dist/builtin/subagents/src/runs/background/subagent-runner-streaming.ts +29 -15
  96. package/dist/builtin/subagents/src/runs/background/top-level-async.ts +1 -2
  97. package/dist/builtin/subagents/src/runs/foreground/chain-execution-dynamic-step.ts +1 -0
  98. package/dist/builtin/subagents/src/runs/foreground/chain-execution-parallel-runner.ts +1 -0
  99. package/dist/builtin/subagents/src/runs/foreground/chain-execution-parallel-step.ts +1 -0
  100. package/dist/builtin/subagents/src/runs/foreground/chain-execution-sequential-step.ts +7 -9
  101. package/dist/builtin/subagents/src/runs/foreground/chain-execution-types.ts +3 -13
  102. package/dist/builtin/subagents/src/runs/foreground/chain-execution.ts +2 -15
  103. package/dist/builtin/subagents/src/runs/foreground/execution-attempt-finalize.ts +2 -2
  104. package/dist/builtin/subagents/src/runs/foreground/execution-attempt.ts +63 -46
  105. package/dist/builtin/subagents/src/runs/foreground/execution-detach-reservations.ts +48 -0
  106. package/dist/builtin/subagents/src/runs/foreground/execution-detach-route.ts +17 -0
  107. package/dist/builtin/subagents/src/runs/foreground/execution-run-sync.ts +39 -26
  108. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-async.ts +3 -1
  109. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-chain.ts +3 -51
  110. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-context.ts +6 -11
  111. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-input.ts +11 -2
  112. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-parallel-task.ts +2 -0
  113. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-parallel.ts +5 -112
  114. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-resume.ts +2 -0
  115. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-single.ts +68 -118
  116. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-status.ts +79 -7
  117. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-types.ts +2 -2
  118. package/dist/builtin/subagents/src/runs/foreground/subagent-executor.ts +3 -0
  119. package/dist/builtin/subagents/src/runs/shared/pi-args.ts +2 -2
  120. package/dist/builtin/subagents/src/runs/shared/pi-spawn.ts +55 -12
  121. package/dist/builtin/subagents/src/shared/artifacts.ts +22 -11
  122. package/dist/builtin/subagents/src/shared/event-jsonl-writer.ts +294 -0
  123. package/dist/builtin/subagents/src/shared/exclusive-file-publication.ts +44 -0
  124. package/dist/builtin/subagents/src/shared/jsonl-writer.ts +1 -0
  125. package/dist/builtin/subagents/src/shared/model-info.ts +2 -2
  126. package/dist/builtin/subagents/src/shared/settings.ts +20 -10
  127. package/dist/builtin/subagents/src/shared/types-async.ts +3 -1
  128. package/dist/builtin/subagents/src/shared/types-config.ts +2 -0
  129. package/dist/builtin/subagents/src/shared/types-runtime.ts +3 -2
  130. package/dist/builtin/subagents/src/slash/slash-commands.ts +9 -12
  131. package/dist/builtin/subagents/src/slash/slash-live-state.ts +63 -32
  132. package/dist/builtin/subagents/src/tui/render-result.ts +7 -0
  133. package/dist/builtin/subagents/src/tui/render-stable-output.ts +1 -0
  134. package/dist/builtin/subagents/src/tui/render-widget.ts +157 -89
  135. package/dist/builtin/web-access/CHANGELOG.md +28 -0
  136. package/dist/builtin/web-access/README.md +4 -0
  137. package/dist/builtin/web-access/content-tools.ts +8 -3
  138. package/dist/builtin/web-access/index-heavy.ts +1 -1
  139. package/dist/builtin/web-access/index.ts +190 -46
  140. package/dist/builtin/web-access/lifecycle-lease.ts +38 -0
  141. package/dist/builtin/web-access/package.json +2 -2
  142. package/dist/builtin/web-access/result-renderers.ts +1 -1
  143. package/dist/builtin/web-access/summary-review.ts +1 -1
  144. package/dist/builtin/web-access/web-search-activity.ts +1 -1
  145. package/dist/builtin/web-access/web-search-return.ts +7 -0
  146. package/dist/builtin/web-access/web-search-summary.ts +1 -1
  147. package/dist/builtin/web-access/web-search-tool.ts +4 -2
  148. package/dist/builtin/workflows/CHANGELOG.md +86 -0
  149. package/dist/builtin/workflows/README.md +5 -5
  150. package/dist/builtin/workflows/builtin/deep-research-codebase-utils.ts +27 -4
  151. package/dist/builtin/workflows/builtin/goal-runner.ts +86 -27
  152. package/dist/builtin/workflows/builtin/open-claude-design-runner.ts +10 -0
  153. package/dist/builtin/workflows/builtin/ralph-core.ts +9 -9
  154. package/dist/builtin/workflows/builtin/ralph-models.ts +71 -36
  155. package/dist/builtin/workflows/builtin/ralph-runner.ts +20 -31
  156. package/dist/builtin/workflows/package.json +2 -2
  157. package/dist/builtin/workflows/skills/impeccable/SKILL.md +16 -13
  158. package/dist/builtin/workflows/skills/impeccable/reference/adapt.md +1 -0
  159. package/dist/builtin/workflows/skills/impeccable/reference/adapt.native.md +58 -0
  160. package/dist/builtin/workflows/skills/impeccable/reference/android.md +40 -0
  161. package/dist/builtin/workflows/skills/impeccable/reference/animate.md +2 -0
  162. package/dist/builtin/workflows/skills/impeccable/reference/audit.md +2 -0
  163. package/dist/builtin/workflows/skills/impeccable/reference/audit.native.md +139 -0
  164. package/dist/builtin/workflows/skills/impeccable/reference/bolder.md +69 -62
  165. package/dist/builtin/workflows/skills/impeccable/reference/critique.md +21 -7
  166. package/dist/builtin/workflows/skills/impeccable/reference/document.md +1 -1
  167. package/dist/builtin/workflows/skills/impeccable/reference/hooks.md +92 -0
  168. package/dist/builtin/workflows/skills/impeccable/reference/init.md +29 -7
  169. package/dist/builtin/workflows/skills/impeccable/reference/ios.md +45 -0
  170. package/dist/builtin/workflows/skills/impeccable/reference/layout.md +25 -1
  171. package/dist/builtin/workflows/skills/impeccable/reference/typeset.md +23 -1
  172. package/dist/builtin/workflows/skills/impeccable/scripts/context-signals.mjs +2 -1
  173. package/dist/builtin/workflows/skills/impeccable/scripts/context.mjs +75 -14
  174. package/dist/builtin/workflows/skills/impeccable/scripts/detector/browser/injected/index.mjs +1 -1
  175. package/dist/builtin/workflows/skills/impeccable/scripts/detector/cli/main.mjs +31 -0
  176. package/dist/builtin/workflows/skills/impeccable/scripts/detector/design-system.mjs +64 -0
  177. package/dist/builtin/workflows/skills/impeccable/scripts/detector/detect-antipatterns-browser.js +118 -11
  178. package/dist/builtin/workflows/skills/impeccable/scripts/detector/engines/regex/detect-text.mjs +16 -11
  179. package/dist/builtin/workflows/skills/impeccable/scripts/detector/registry/antipatterns.mjs +66 -0
  180. package/dist/builtin/workflows/skills/impeccable/scripts/detector/rules/checks.mjs +42 -10
  181. package/dist/builtin/workflows/skills/impeccable/scripts/detector/shared/fonts.mjs +30 -0
  182. package/dist/builtin/workflows/skills/impeccable/scripts/detector/shared/page.mjs +4 -6
  183. package/dist/builtin/workflows/skills/impeccable/scripts/hook-admin.mjs +660 -0
  184. package/dist/builtin/workflows/skills/impeccable/scripts/hook-before-edit.mjs +516 -0
  185. package/dist/builtin/workflows/skills/impeccable/scripts/hook-lib.mjs +1764 -0
  186. package/dist/builtin/workflows/skills/impeccable/scripts/hook.mjs +61 -0
  187. package/dist/builtin/workflows/skills/impeccable/scripts/lib/impeccable-config.mjs +4 -2
  188. package/dist/builtin/workflows/skills/impeccable/scripts/lib/is-generated.mjs +2 -2
  189. package/dist/builtin/workflows/skills/impeccable/scripts/live/svelte-component.mjs +13 -16
  190. package/dist/builtin/workflows/skills/impeccable/scripts/live-accept.mjs +17 -11
  191. package/dist/builtin/workflows/skills/impeccable/scripts/live-browser.js +104 -37
  192. package/dist/builtin/workflows/skills/impeccable/scripts/live-wrap.mjs +9 -0
  193. package/dist/builtin/workflows/src/durable/backend.ts +12 -0
  194. package/dist/builtin/workflows/src/durable/dbos-backend.ts +17 -1
  195. package/dist/builtin/workflows/src/durable/resume-catalog.ts +12 -0
  196. package/dist/builtin/workflows/src/durable/resume-runtime.ts +5 -2
  197. package/dist/builtin/workflows/src/durable/stage-primitive.ts +2 -1
  198. package/dist/builtin/workflows/src/durable/types.ts +16 -0
  199. package/dist/builtin/workflows/src/engine/primitives/task.ts +3 -1
  200. package/dist/builtin/workflows/src/engine/run-durable-finalize.ts +1 -2
  201. package/dist/builtin/workflows/src/engine/run-returned-status.ts +50 -16
  202. package/dist/builtin/workflows/src/engine/run.ts +20 -19
  203. package/dist/builtin/workflows/src/engine/runtime.ts +5 -0
  204. package/dist/builtin/workflows/src/extension/extension-factory.ts +3 -0
  205. package/dist/builtin/workflows/src/extension/extension-lifecycle.ts +9 -2
  206. package/dist/builtin/workflows/src/extension/extension-runtime-state.ts +137 -27
  207. package/dist/builtin/workflows/src/extension/lifecycle-notifications.ts +22 -6
  208. package/dist/builtin/workflows/src/extension/public-types.ts +1 -1
  209. package/dist/builtin/workflows/src/extension/workflow-command-completions.ts +13 -1
  210. package/dist/builtin/workflows/src/extension/workflow-command-registration.ts +19 -4
  211. package/dist/builtin/workflows/src/extension/workflow-command-surfaces.ts +9 -0
  212. package/dist/builtin/workflows/src/extension/workflow-prompts.ts +17 -22
  213. package/dist/builtin/workflows/src/extension/workflow-run-control-command.ts +48 -23
  214. package/dist/builtin/workflows/src/extension/workflow-schema.ts +15 -2
  215. package/dist/builtin/workflows/src/extension/workflow-tool-control.ts +20 -8
  216. package/dist/builtin/workflows/src/extension/workflow-tool.ts +24 -8
  217. package/dist/builtin/workflows/src/runs/background/status.ts +4 -3
  218. package/dist/builtin/workflows/src/runs/foreground/executor-direct-helpers.ts +29 -8
  219. package/dist/builtin/workflows/src/runs/foreground/executor-hil.ts +1 -1
  220. package/dist/builtin/workflows/src/runs/foreground/executor-stage-factory.ts +3 -2
  221. package/dist/builtin/workflows/src/runs/shared/model-fallback-candidates.ts +1 -1
  222. package/dist/builtin/workflows/src/runs/shared/worktree-git.ts +155 -20
  223. package/dist/builtin/workflows/src/runs/shared/worktree-types.ts +6 -0
  224. package/dist/builtin/workflows/src/runs/shared/worktree.ts +2 -1
  225. package/dist/builtin/workflows/src/shared/authoring-contract-stage.d.ts +2 -2
  226. package/dist/builtin/workflows/src/shared/authoring-contract-stage.ts +2 -2
  227. package/dist/builtin/workflows/src/shared/resume-continuation.ts +2 -0
  228. package/dist/builtin/workflows/src/shared/returned-run-status.ts +116 -0
  229. package/dist/builtin/workflows/src/shared/workflow-failures-decisions.ts +2 -0
  230. package/dist/builtin/workflows/src/tui/graph-view-render-helpers.ts +21 -3
  231. package/dist/builtin/workflows/src/tui/graph-view-state.ts +3 -0
  232. package/dist/builtin/workflows/src/tui/graph-view-types.ts +3 -0
  233. package/dist/builtin/workflows/src/tui/stage-chat-view-archive-history.ts +1 -23
  234. package/dist/builtin/workflows/src/tui/stage-chat-view-footer-status.ts +54 -9
  235. package/dist/builtin/workflows/src/tui/stage-chat-view.ts +5 -2
  236. package/dist/builtin/workflows/src/tui/status-list.ts +22 -15
  237. package/dist/builtin/workflows/src/tui/workflow-attach-pane.ts +4 -4
  238. package/dist/cli/args.d.ts.map +1 -1
  239. package/dist/cli/args.js +2 -2
  240. package/dist/cli/args.js.map +1 -1
  241. package/dist/core/agent-session-auto-compaction.d.ts +23 -3
  242. package/dist/core/agent-session-auto-compaction.d.ts.map +1 -1
  243. package/dist/core/agent-session-auto-compaction.js +129 -17
  244. package/dist/core/agent-session-auto-compaction.js.map +1 -1
  245. package/dist/core/agent-session-events.d.ts.map +1 -1
  246. package/dist/core/agent-session-events.js +9 -1
  247. package/dist/core/agent-session-events.js.map +1 -1
  248. package/dist/core/agent-session-message-queue.d.ts.map +1 -1
  249. package/dist/core/agent-session-message-queue.js +1 -1
  250. package/dist/core/agent-session-message-queue.js.map +1 -1
  251. package/dist/core/agent-session-methods.d.ts +6 -3
  252. package/dist/core/agent-session-methods.d.ts.map +1 -1
  253. package/dist/core/agent-session-methods.js.map +1 -1
  254. package/dist/core/agent-session-prompt.d.ts.map +1 -1
  255. package/dist/core/agent-session-prompt.js +2 -2
  256. package/dist/core/agent-session-prompt.js.map +1 -1
  257. package/dist/core/agent-session-retry.d.ts.map +1 -1
  258. package/dist/core/agent-session-retry.js +1 -1
  259. package/dist/core/agent-session-retry.js.map +1 -1
  260. package/dist/core/agent-session-services.d.ts.map +1 -1
  261. package/dist/core/agent-session-services.js +3 -2
  262. package/dist/core/agent-session-services.js.map +1 -1
  263. package/dist/core/agent-session-types.d.ts.map +1 -1
  264. package/dist/core/agent-session-types.js +1 -1
  265. package/dist/core/agent-session-types.js.map +1 -1
  266. package/dist/core/agent-session.d.ts +4 -2
  267. package/dist/core/agent-session.d.ts.map +1 -1
  268. package/dist/core/agent-session.js +4 -2
  269. package/dist/core/agent-session.js.map +1 -1
  270. package/dist/core/anthropic-thinking-guard.d.ts +5 -5
  271. package/dist/core/anthropic-thinking-guard.d.ts.map +1 -1
  272. package/dist/core/anthropic-thinking-guard.js +42 -32
  273. package/dist/core/anthropic-thinking-guard.js.map +1 -1
  274. package/dist/core/atomic-guide-command.d.ts.map +1 -1
  275. package/dist/core/atomic-guide-command.js +15 -15
  276. package/dist/core/atomic-guide-command.js.map +1 -1
  277. package/dist/core/auth-storage.d.ts.map +1 -1
  278. package/dist/core/auth-storage.js +14 -9
  279. package/dist/core/auth-storage.js.map +1 -1
  280. package/dist/core/compaction/compaction.d.ts +2 -0
  281. package/dist/core/compaction/compaction.d.ts.map +1 -1
  282. package/dist/core/compaction/compaction.js +79 -46
  283. package/dist/core/compaction/compaction.js.map +1 -1
  284. package/dist/core/compaction/context-assistant-turns.d.ts +42 -0
  285. package/dist/core/compaction/context-assistant-turns.d.ts.map +1 -0
  286. package/dist/core/compaction/context-assistant-turns.js +87 -0
  287. package/dist/core/compaction/context-assistant-turns.js.map +1 -0
  288. package/dist/core/compaction/context-compaction-critical.d.ts +1 -1
  289. package/dist/core/compaction/context-compaction-critical.d.ts.map +1 -1
  290. package/dist/core/compaction/context-compaction-critical.js +2 -2
  291. package/dist/core/compaction/context-compaction-critical.js.map +1 -1
  292. package/dist/core/compaction/context-compaction-eviction-alternates.d.ts +18 -0
  293. package/dist/core/compaction/context-compaction-eviction-alternates.d.ts.map +1 -0
  294. package/dist/core/compaction/context-compaction-eviction-alternates.js +186 -0
  295. package/dist/core/compaction/context-compaction-eviction-alternates.js.map +1 -0
  296. package/dist/core/compaction/context-compaction-eviction.d.ts +10 -2
  297. package/dist/core/compaction/context-compaction-eviction.d.ts.map +1 -1
  298. package/dist/core/compaction/context-compaction-eviction.js +196 -146
  299. package/dist/core/compaction/context-compaction-eviction.js.map +1 -1
  300. package/dist/core/compaction/context-compaction-prompt.d.ts.map +1 -1
  301. package/dist/core/compaction/context-compaction-prompt.js +1 -1
  302. package/dist/core/compaction/context-compaction-prompt.js.map +1 -1
  303. package/dist/core/compaction/context-compaction-types.d.ts +2 -0
  304. package/dist/core/compaction/context-compaction-types.d.ts.map +1 -1
  305. package/dist/core/compaction/context-compaction-types.js.map +1 -1
  306. package/dist/core/compaction/context-deletion-application.d.ts +5 -4
  307. package/dist/core/compaction/context-deletion-application.d.ts.map +1 -1
  308. package/dist/core/compaction/context-deletion-application.js +17 -15
  309. package/dist/core/compaction/context-deletion-application.js.map +1 -1
  310. package/dist/core/compaction/context-deletion-store.d.ts.map +1 -1
  311. package/dist/core/compaction/context-deletion-store.js +1 -1
  312. package/dist/core/compaction/context-deletion-store.js.map +1 -1
  313. package/dist/core/compaction/context-deletion-targets.d.ts +2 -1
  314. package/dist/core/compaction/context-deletion-targets.d.ts.map +1 -1
  315. package/dist/core/compaction/context-deletion-targets.js +36 -31
  316. package/dist/core/compaction/context-deletion-targets.js.map +1 -1
  317. package/dist/core/compaction/context-deletion-tool-helpers.d.ts.map +1 -1
  318. package/dist/core/compaction/context-deletion-tool-helpers.js +116 -43
  319. package/dist/core/compaction/context-deletion-tool-helpers.js.map +1 -1
  320. package/dist/core/compaction/context-transcript-analysis.d.ts +1 -2
  321. package/dist/core/compaction/context-transcript-analysis.d.ts.map +1 -1
  322. package/dist/core/compaction/context-transcript-analysis.js +33 -37
  323. package/dist/core/compaction/context-transcript-analysis.js.map +1 -1
  324. package/dist/core/copilot-model-synthesis.d.ts.map +1 -1
  325. package/dist/core/copilot-model-synthesis.js +3 -1
  326. package/dist/core/copilot-model-synthesis.js.map +1 -1
  327. package/dist/core/extensions/loader-virtual-modules.d.ts +8 -1
  328. package/dist/core/extensions/loader-virtual-modules.d.ts.map +1 -1
  329. package/dist/core/extensions/loader-virtual-modules.js +2 -1
  330. package/dist/core/extensions/loader-virtual-modules.js.map +1 -1
  331. package/dist/core/extensions/provider-types.d.ts +2 -7
  332. package/dist/core/extensions/provider-types.d.ts.map +1 -1
  333. package/dist/core/extensions/provider-types.js.map +1 -1
  334. package/dist/core/footer-data-provider.d.ts +6 -0
  335. package/dist/core/footer-data-provider.d.ts.map +1 -1
  336. package/dist/core/footer-data-provider.js +72 -29
  337. package/dist/core/footer-data-provider.js.map +1 -1
  338. package/dist/core/messages.d.ts +9 -0
  339. package/dist/core/messages.d.ts.map +1 -1
  340. package/dist/core/messages.js +100 -18
  341. package/dist/core/messages.js.map +1 -1
  342. package/dist/core/model-registry-builtins.d.ts.map +1 -1
  343. package/dist/core/model-registry-builtins.js +5 -0
  344. package/dist/core/model-registry-builtins.js.map +1 -1
  345. package/dist/core/model-registry-custom-loader.d.ts.map +1 -1
  346. package/dist/core/model-registry-custom-loader.js +49 -8
  347. package/dist/core/model-registry-custom-loader.js.map +1 -1
  348. package/dist/core/model-registry-dynamic.d.ts.map +1 -1
  349. package/dist/core/model-registry-dynamic.js +11 -5
  350. package/dist/core/model-registry-dynamic.js.map +1 -1
  351. package/dist/core/model-registry-loader.d.ts.map +1 -1
  352. package/dist/core/model-registry-loader.js +8 -0
  353. package/dist/core/model-registry-loader.js.map +1 -1
  354. package/dist/core/model-registry-schemas.d.ts +93 -8
  355. package/dist/core/model-registry-schemas.d.ts.map +1 -1
  356. package/dist/core/model-registry-schemas.js +24 -12
  357. package/dist/core/model-registry-schemas.js.map +1 -1
  358. package/dist/core/model-registry-types.d.ts +7 -6
  359. package/dist/core/model-registry-types.d.ts.map +1 -1
  360. package/dist/core/model-registry-types.js.map +1 -1
  361. package/dist/core/model-registry.d.ts +5 -0
  362. package/dist/core/model-registry.d.ts.map +1 -1
  363. package/dist/core/model-registry.js +23 -0
  364. package/dist/core/model-registry.js.map +1 -1
  365. package/dist/core/model-resolver-cli.d.ts.map +1 -1
  366. package/dist/core/model-resolver-cli.js +33 -5
  367. package/dist/core/model-resolver-cli.js.map +1 -1
  368. package/dist/core/model-resolver-initial.d.ts +6 -1
  369. package/dist/core/model-resolver-initial.d.ts.map +1 -1
  370. package/dist/core/model-resolver-initial.js +12 -7
  371. package/dist/core/model-resolver-initial.js.map +1 -1
  372. package/dist/core/model-resolver.d.ts +1 -1
  373. package/dist/core/model-resolver.d.ts.map +1 -1
  374. package/dist/core/model-resolver.js +1 -1
  375. package/dist/core/model-resolver.js.map +1 -1
  376. package/dist/core/openai-responses-payload-sanitizer.d.ts +1 -0
  377. package/dist/core/openai-responses-payload-sanitizer.d.ts.map +1 -1
  378. package/dist/core/openai-responses-payload-sanitizer.js +24 -9
  379. package/dist/core/openai-responses-payload-sanitizer.js.map +1 -1
  380. package/dist/core/resource-loader-context-files.d.ts +1 -0
  381. package/dist/core/resource-loader-context-files.d.ts.map +1 -1
  382. package/dist/core/resource-loader-context-files.js +13 -10
  383. package/dist/core/resource-loader-context-files.js.map +1 -1
  384. package/dist/core/sdk.d.ts.map +1 -1
  385. package/dist/core/sdk.js +2 -2
  386. package/dist/core/sdk.js.map +1 -1
  387. package/dist/core/session-entry-normalization.d.ts +7 -0
  388. package/dist/core/session-entry-normalization.d.ts.map +1 -0
  389. package/dist/core/session-entry-normalization.js +14 -0
  390. package/dist/core/session-entry-normalization.js.map +1 -0
  391. package/dist/core/session-manager-core.d.ts.map +1 -1
  392. package/dist/core/session-manager-core.js +1 -0
  393. package/dist/core/session-manager-core.js.map +1 -1
  394. package/dist/core/session-manager-history.d.ts +2 -2
  395. package/dist/core/session-manager-history.d.ts.map +1 -1
  396. package/dist/core/session-manager-history.js +127 -108
  397. package/dist/core/session-manager-history.js.map +1 -1
  398. package/dist/core/settings-manager-basic-accessors.d.ts +2 -2
  399. package/dist/core/settings-manager-basic-accessors.d.ts.map +1 -1
  400. package/dist/core/settings-manager-basic-accessors.js.map +1 -1
  401. package/dist/core/settings-types.d.ts +1 -1
  402. package/dist/core/settings-types.d.ts.map +1 -1
  403. package/dist/core/settings-types.js.map +1 -1
  404. package/dist/core/slash-commands.d.ts +2 -0
  405. package/dist/core/slash-commands.d.ts.map +1 -1
  406. package/dist/core/slash-commands.js +141 -0
  407. package/dist/core/slash-commands.js.map +1 -1
  408. package/dist/core/tools/bash.d.ts.map +1 -1
  409. package/dist/core/tools/bash.js +11 -8
  410. package/dist/core/tools/bash.js.map +1 -1
  411. package/dist/index.d.ts +1 -0
  412. package/dist/index.d.ts.map +1 -1
  413. package/dist/index.js +1 -0
  414. package/dist/index.js.map +1 -1
  415. package/dist/main-deferred-startup.d.ts.map +1 -1
  416. package/dist/main-deferred-startup.js +2 -2
  417. package/dist/main-deferred-startup.js.map +1 -1
  418. package/dist/main-early-input.d.ts.map +1 -1
  419. package/dist/main-early-input.js +7 -0
  420. package/dist/main-early-input.js.map +1 -1
  421. package/dist/main-session.d.ts.map +1 -1
  422. package/dist/main-session.js +1 -0
  423. package/dist/main-session.js.map +1 -1
  424. package/dist/main.d.ts.map +1 -1
  425. package/dist/main.js +1 -1
  426. package/dist/main.js.map +1 -1
  427. package/dist/modes/interactive/components/chat-session-host-actions.d.ts.map +1 -1
  428. package/dist/modes/interactive/components/chat-session-host-actions.js +0 -1
  429. package/dist/modes/interactive/components/chat-session-host-actions.js.map +1 -1
  430. package/dist/modes/interactive/components/settings-selector-options.d.ts.map +1 -1
  431. package/dist/modes/interactive/components/settings-selector-options.js +3 -1
  432. package/dist/modes/interactive/components/settings-selector-options.js.map +1 -1
  433. package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
  434. package/dist/modes/interactive/components/thinking-selector.js +2 -1
  435. package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
  436. package/dist/modes/interactive/interactive-agent-events.d.ts.map +1 -1
  437. package/dist/modes/interactive/interactive-agent-events.js +3 -1
  438. package/dist/modes/interactive/interactive-agent-events.js.map +1 -1
  439. package/dist/modes/interactive/interactive-autocomplete.d.ts.map +1 -1
  440. package/dist/modes/interactive/interactive-autocomplete.js +21 -9
  441. package/dist/modes/interactive/interactive-autocomplete.js.map +1 -1
  442. package/dist/modes/interactive/interactive-child-ordering.d.ts +7 -0
  443. package/dist/modes/interactive/interactive-child-ordering.d.ts.map +1 -0
  444. package/dist/modes/interactive/interactive-child-ordering.js +26 -0
  445. package/dist/modes/interactive/interactive-child-ordering.js.map +1 -0
  446. package/dist/modes/interactive/interactive-deferred-startup.d.ts.map +1 -1
  447. package/dist/modes/interactive/interactive-deferred-startup.js +43 -30
  448. package/dist/modes/interactive/interactive-deferred-startup.js.map +1 -1
  449. package/dist/modes/interactive/interactive-hotkeys-debug.d.ts.map +1 -1
  450. package/dist/modes/interactive/interactive-hotkeys-debug.js +1 -0
  451. package/dist/modes/interactive/interactive-hotkeys-debug.js.map +1 -1
  452. package/dist/modes/interactive/interactive-input-handling.d.ts.map +1 -1
  453. package/dist/modes/interactive/interactive-input-handling.js +41 -6
  454. package/dist/modes/interactive/interactive-input-handling.js.map +1 -1
  455. package/dist/modes/interactive/interactive-mode-base.d.ts +3 -0
  456. package/dist/modes/interactive/interactive-mode-base.d.ts.map +1 -1
  457. package/dist/modes/interactive/interactive-mode-base.js +3 -0
  458. package/dist/modes/interactive/interactive-mode-base.js.map +1 -1
  459. package/dist/modes/interactive/interactive-mode-deps.d.ts +2 -2
  460. package/dist/modes/interactive/interactive-mode-deps.d.ts.map +1 -1
  461. package/dist/modes/interactive/interactive-mode-deps.js +2 -2
  462. package/dist/modes/interactive/interactive-mode-deps.js.map +1 -1
  463. package/dist/modes/interactive/interactive-mode-surface.d.ts +2 -2
  464. package/dist/modes/interactive/interactive-mode-surface.d.ts.map +1 -1
  465. package/dist/modes/interactive/interactive-mode-surface.js.map +1 -1
  466. package/dist/modes/interactive/interactive-model-routing.d.ts.map +1 -1
  467. package/dist/modes/interactive/interactive-model-routing.js +11 -4
  468. package/dist/modes/interactive/interactive-model-routing.js.map +1 -1
  469. package/dist/modes/interactive/interactive-process-lifecycle.d.ts.map +1 -1
  470. package/dist/modes/interactive/interactive-process-lifecycle.js +0 -3
  471. package/dist/modes/interactive/interactive-process-lifecycle.js.map +1 -1
  472. package/dist/modes/interactive/interactive-render-chat.d.ts.map +1 -1
  473. package/dist/modes/interactive/interactive-render-chat.js +15 -1
  474. package/dist/modes/interactive/interactive-render-chat.js.map +1 -1
  475. package/dist/modes/interactive/interactive-session-routing.d.ts.map +1 -1
  476. package/dist/modes/interactive/interactive-session-routing.js +5 -1
  477. package/dist/modes/interactive/interactive-session-routing.js.map +1 -1
  478. package/dist/modes/interactive/interactive-startup.d.ts.map +1 -1
  479. package/dist/modes/interactive/interactive-startup.js +20 -21
  480. package/dist/modes/interactive/interactive-startup.js.map +1 -1
  481. package/dist/modes/interactive/theme/global-theme.d.ts.map +1 -1
  482. package/dist/modes/interactive/theme/global-theme.js +26 -2
  483. package/dist/modes/interactive/theme/global-theme.js.map +1 -1
  484. package/dist/modes/interactive/theme/theme-class.d.ts +1 -1
  485. package/dist/modes/interactive/theme/theme-class.d.ts.map +1 -1
  486. package/dist/modes/interactive/theme/theme-class.js +2 -0
  487. package/dist/modes/interactive/theme/theme-class.js.map +1 -1
  488. package/dist/utils/clipboard-image.d.ts.map +1 -1
  489. package/dist/utils/clipboard-image.js +3 -0
  490. package/dist/utils/clipboard-image.js.map +1 -1
  491. package/dist/utils/fs-watch.d.ts +24 -1
  492. package/dist/utils/fs-watch.d.ts.map +1 -1
  493. package/dist/utils/fs-watch.js +60 -5
  494. package/dist/utils/fs-watch.js.map +1 -1
  495. package/docs/changelog.mdx +19 -0
  496. package/docs/compaction.md +60 -49
  497. package/docs/custom-provider.md +18 -5
  498. package/docs/development.md +4 -0
  499. package/docs/extensions.md +11 -2
  500. package/docs/json.md +1 -1
  501. package/docs/models.md +69 -10
  502. package/docs/providers.md +1 -1
  503. package/docs/quickstart.md +12 -8
  504. package/docs/rpc.md +2 -2
  505. package/docs/sdk.md +1 -1
  506. package/docs/settings.md +4 -4
  507. package/docs/subagents.md +40 -5
  508. package/docs/tools.md +1 -1
  509. package/docs/usage.md +4 -2
  510. package/docs/windows.md +4 -0
  511. package/docs/workflows.md +33 -48
  512. package/examples/extensions/preset.ts +2 -2
  513. package/examples/extensions/subagent/README.md +2 -2
  514. package/examples/extensions/subagent/index.ts +1 -2
  515. package/examples/extensions/subagent/schemas.ts +4 -1
  516. package/examples/sdk/12-full-control.ts +1 -1
  517. package/npm-shrinkwrap.json +48 -51
  518. package/package.json +7 -7
  519. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-behavior.ts +0 -75
  520. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-component.ts +0 -202
  521. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-edit.ts +0 -97
  522. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-editor.ts +0 -160
  523. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-frame.ts +0 -72
  524. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-render-modes.ts +0 -161
  525. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-render-selectors.ts +0 -203
  526. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-selectors.ts +0 -234
  527. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-state.ts +0 -103
  528. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-types.ts +0 -29
  529. package/dist/builtin/subagents/src/runs/foreground/chain-clarify.ts +0 -9
  530. package/dist/builtin/subagents/src/runs/foreground/chain-execution-clarify.ts +0 -117
@@ -1,11 +1,10 @@
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";
8
- import { getPiSpawnCommand } from "../shared/pi-spawn.ts";
7
+ import { formatPiSpawnError, getPiSpawnCommand, validatePiSpawnCwd } from "../shared/pi-spawn.ts";
9
8
  import {
10
9
  assistantStopReason,
11
10
  isAssistantFailureStopReason,
@@ -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(
@@ -29,6 +29,17 @@ export function runPiStreaming(
29
29
  registerInterrupt?: (interrupt: (() => void) | undefined) => void,
30
30
  onChildEvent?: (event: ChildEvent) => void,
31
31
  ): Promise<RunPiStreamingResult> {
32
+ const cwdValidation = validatePiSpawnCwd(cwd);
33
+ if (!cwdValidation.ok) {
34
+ return Promise.resolve({
35
+ stderr: "",
36
+ exitCode: 1,
37
+ messages: [],
38
+ usage: emptyUsage(),
39
+ error: cwdValidation.error,
40
+ finalOutput: "",
41
+ });
42
+ }
32
43
  return new Promise((resolve) => {
33
44
  const outputStream = fs.createWriteStream(outputFile, { flags: "w" });
34
45
  const spawnEnv = {
@@ -46,6 +57,11 @@ export function runPiStreaming(
46
57
  env: spawnEnv,
47
58
  windowsHide: true,
48
59
  });
60
+ const childEventJournal = createChildEventJournal(childEventContext?.eventsPath, child.stdout, {
61
+ runId: childEventContext?.runId ?? "",
62
+ stepIndex: childEventContext?.stepIndex,
63
+ agent: childEventContext?.agent ?? "",
64
+ });
49
65
  let stderr = "";
50
66
  let stdoutBuf = "";
51
67
  let stderrBuf = "";
@@ -55,6 +71,7 @@ export function runPiStreaming(
55
71
  let error: string | undefined;
56
72
  let assistantError: string | undefined;
57
73
  let assistantFailureSignal: unknown;
74
+ let spawnErrorText: string | undefined;
58
75
  let interrupted = false;
59
76
  let activeToolExecutions = 0;
60
77
  const rawStdoutLines: string[] = [];
@@ -72,14 +89,7 @@ export function runPiStreaming(
72
89
 
73
90
  const appendChildEvent = (event: Record<string, unknown> | ChildEvent) => {
74
91
  if (!childEventContext) return;
75
- appendJsonl(childEventContext.eventsPath, JSON.stringify({
76
- ...event,
77
- subagentSource: "child",
78
- subagentRunId: childEventContext.runId,
79
- subagentStepIndex: childEventContext.stepIndex,
80
- subagentAgent: childEventContext.agent,
81
- observedAt: Date.now(),
82
- }));
92
+ childEventJournal.append({ ...event });
83
93
  };
84
94
 
85
95
  const appendChildLine = (type: "subagent.child.stdout" | "subagent.child.stderr", line: string) => {
@@ -238,7 +248,7 @@ export function runPiStreaming(
238
248
  childExited = true;
239
249
  clearDrainTimers();
240
250
  });
241
- child.on("close", (exitCode, signal) => {
251
+ child.on("close", async (exitCode, signal) => {
242
252
  settled = true;
243
253
  registerInterrupt?.(undefined);
244
254
  clearDrainTimers();
@@ -247,8 +257,9 @@ export function runPiStreaming(
247
257
  if (stdoutBuf.trim()) processStdoutLine(stdoutBuf);
248
258
  if (stderrBuf.trim()) appendChildLine("subagent.child.stderr", stderrBuf);
249
259
  outputStream.end();
260
+ await childEventJournal.close();
250
261
  const finalOutput = getFinalOutput(messages) || rawStdoutLines.join("\n").trim();
251
- const finalError = error ?? assistantError;
262
+ const finalError = error ?? assistantError ?? spawnErrorText;
252
263
  const forcedDrainAfterFinalSuccess = forcedTerminationSignal && cleanTerminalAssistantStopReceived && !finalError;
253
264
  resolve({
254
265
  stderr,
@@ -265,16 +276,19 @@ export function runPiStreaming(
265
276
  });
266
277
  });
267
278
 
268
- 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);
269
283
  settled = true;
270
284
  registerInterrupt?.(undefined);
271
285
  clearDrainTimers();
272
286
  clearStdioGuard();
273
287
  attemptWatchdog.clear();
274
288
  outputStream.end();
289
+ await childEventJournal.close();
275
290
  const finalOutput = getFinalOutput(messages) || rawStdoutLines.join("\n").trim();
276
- const spawnErrorMessage = spawnError instanceof Error ? spawnError.message : String(spawnError);
277
- const finalError = error ?? assistantError ?? spawnErrorMessage;
291
+ const finalError = error ?? assistantError ?? spawnErrorText;
278
292
  resolve({
279
293
  stderr,
280
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,21 +3,19 @@ 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";
15
11
  import { attachPostExitStdioGuard, trySignalChild } from "../../shared/post-exit-stdio-guard.ts";
16
12
  import { applyThinkingSuffix, buildPiArgs, cleanupTempDir } from "../shared/pi-args.ts";
17
- import { getPiSpawnCommand } from "../shared/pi-spawn.ts";
13
+ import { formatPiSpawnError, getPiSpawnCommand, validatePiSpawnCwd } from "../shared/pi-spawn.ts";
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,
@@ -124,6 +120,14 @@ export async function runSingleAttempt(
124
120
  workflowStageSubagentGuard: options.workflowStageSubagentGuard,
125
121
  }),
126
122
  };
123
+ const cwdValidation = validatePiSpawnCwd(runCwd);
124
+ if (!cwdValidation.ok) {
125
+ cleanupTempDir(tempDir);
126
+ result.error = cwdValidation.error;
127
+ return finalizeSingleAttempt({
128
+ result, progress, exitCode: 1, interruptedByControl, allControlEvents: controlRuntime.allControlEvents, options, shared, startTime,
129
+ });
130
+ }
127
131
  const exitCode = await new Promise<number>((resolve) => {
128
132
  const spawnSpec = getPiSpawnCommand(args);
129
133
  const proc = spawn(spawnSpec.command, spawnSpec.args, {
@@ -137,24 +141,21 @@ export async function runSingleAttempt(
137
141
  let processClosed = false;
138
142
  let settled = false;
139
143
  let detached = false;
140
- let intercomStarted = false;
141
144
  let assistantError: string | undefined;
142
145
  let assistantFailureSignal: unknown;
143
146
  let removeAbortListener: (() => void) | undefined;
144
147
  let removeInterruptListener: (() => void) | undefined;
145
148
  let activityTimer: NodeJS.Timeout | undefined;
146
-
147
149
  const detachForIntercom = () => {
148
150
  detached = true;
149
- processClosed = true;
150
151
  result.detached = true;
151
152
  result.detachedReason = "intercom coordination";
152
153
  progress.status = "detached";
153
154
  progress.durationMs = Date.now() - startTime;
154
155
  result.progressSummary = { toolCount: progress.toolCount, tokens: progress.tokens, durationMs: progress.durationMs };
155
- finish(-2);
156
+ // Settle the foreground tool call, but retain process lifecycle ownership.
157
+ finish(-2, true);
156
158
  };
157
-
158
159
  const FINAL_STOP_GRACE_MS = 1000;
159
160
  const HARD_KILL_MS = 3000;
160
161
  let childExited = false;
@@ -173,9 +174,9 @@ export async function runSingleAttempt(
173
174
  }
174
175
  };
175
176
  const startFinalDrain = () => {
176
- if (childExited || finalDrainTimer || settled || processClosed || detached) return;
177
+ if (childExited || finalDrainTimer || processClosed) return;
177
178
  finalDrainTimer = setTimeout(() => {
178
- if (settled || processClosed || detached) return;
179
+ if (processClosed) return;
179
180
  const termSent = trySignalChild(proc, "SIGTERM");
180
181
  if (!termSent) return;
181
182
  forcedTerminationSignal = true;
@@ -183,39 +184,49 @@ export async function runSingleAttempt(
183
184
  result.error = result.error ?? `Subagent process did not exit within ${FINAL_STOP_GRACE_MS}ms after its final message. Forcing termination.`;
184
185
  }
185
186
  finalHardKillTimer = setTimeout(() => {
186
- if (settled || processClosed || detached) return;
187
+ if (processClosed) return;
187
188
  forcedTerminationSignal = trySignalChild(proc, "SIGKILL") || forcedTerminationSignal;
188
189
  }, HARD_KILL_MS);
189
190
  finalHardKillTimer.unref?.();
190
191
  }, FINAL_STOP_GRACE_MS);
191
192
  finalDrainTimer.unref?.();
192
193
  };
193
-
194
+ const detachReservations = new IntercomDetachReservations();
194
195
  const unsubscribeIntercomDetach = options.intercomEvents?.on?.(INTERCOM_DETACH_REQUEST_EVENT, (payload) => {
195
- if (!options.allowIntercomDetach || detached || processClosed || !intercomStarted) return;
196
+ if (!options.allowIntercomDetach || processClosed || options.signal?.aborted) return;
196
197
  if (!payload || typeof payload !== "object") return;
197
- const requestId = (payload as { requestId?: unknown }).requestId;
198
- if (typeof requestId !== "string" || requestId.length === 0) return;
199
- 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;
200
209
  detachForIntercom();
210
+ options.intercomEvents?.emit?.(INTERCOM_DETACH_RESPONSE_EVENT, { ...event, accepted: true });
201
211
  });
202
-
203
- const finish = (code: number) => {
212
+ const finish = (code: number, retainLifecycleOwner = false) => {
204
213
  if (settled) return;
205
214
  settled = true;
206
- clearFinalDrainTimers();
207
- clearStdioGuard();
208
- attemptWatchdog.clear();
215
+ if (!retainLifecycleOwner) {
216
+ clearFinalDrainTimers();
217
+ clearStdioGuard();
218
+ attemptWatchdog.clear();
219
+ removeAbortListener?.();
220
+ detachReservations.clear();
221
+ unsubscribeIntercomDetach?.();
222
+ }
209
223
  if (activityTimer) {
210
224
  clearInterval(activityTimer);
211
225
  activityTimer = undefined;
212
226
  }
213
- unsubscribeIntercomDetach?.();
214
- removeAbortListener?.();
215
227
  removeInterruptListener?.();
216
228
  resolve(code);
217
229
  };
218
-
219
230
  let pendingToolResult: { tool: string; path?: string; mutates: boolean; startedAt?: number } | undefined;
220
231
  const mutatingFailures = createMutatingFailureState();
221
232
  const mutatingFailureWindowMs = 5 * 60_000;
@@ -238,7 +249,6 @@ export async function runSingleAttempt(
238
249
  progress.durationMs = Date.now() - startTime;
239
250
  emitUpdateSnapshot(getFinalOutput(result.messages ?? []) || "(running...)");
240
251
  };
241
-
242
252
  const processLine = (line: string) => {
243
253
  if (!line.trim()) return;
244
254
  jsonlWriter.writeLine(line);
@@ -256,7 +266,8 @@ export async function runSingleAttempt(
256
266
 
257
267
  if (evt.type === "tool_execution_start") {
258
268
  const toolArgs = evt.args && typeof evt.args === "object" && !Array.isArray(evt.args) ? evt.args as Record<string, unknown> : {};
259
- 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.
260
271
  progress.toolCount++;
261
272
  progress.currentTool = evt.toolName;
262
273
  progress.currentToolArgs = extractToolArgsPreview(toolArgs);
@@ -362,7 +373,7 @@ export async function runSingleAttempt(
362
373
  const clearStdioGuard = attachPostExitStdioGuard(proc, { idleMs: 2000, hardMs: 8000 });
363
374
  const attemptWatchdog = createAttemptWatchdog({
364
375
  child: proc,
365
- isSettled: () => settled || processClosed || detached,
376
+ isSettled: () => processClosed,
366
377
  // A slow, quiet tool call (long build/test run) must not be mistaken for a
367
378
  // stalled attempt: an in-flight tool execution counts as watchdog activity.
368
379
  // Caveat: `progress.currentTool` is cleared on tool_execution_end, so if a
@@ -395,13 +406,12 @@ export async function runSingleAttempt(
395
406
  clearFinalDrainTimers();
396
407
  clearStdioGuard();
397
408
  attemptWatchdog.clear();
409
+ removeAbortListener?.(); removeAbortListener = undefined;
410
+ removeInterruptListener?.(); removeInterruptListener = undefined;
411
+ detachReservations.clear();
412
+ unsubscribeIntercomDetach?.();
398
413
  void jsonlWriter.close().catch(() => undefined);
399
414
  cleanupTempDir(tempDir);
400
- if (detached) {
401
- finish(-2);
402
- return;
403
- }
404
- processClosed = true;
405
415
  if (buf.trim()) processLine(buf);
406
416
  if (!result.error && assistantError) result.error = assistantError;
407
417
  if (assistantFailureSignal !== undefined && result.error === assistantError) {
@@ -410,6 +420,17 @@ export async function runSingleAttempt(
410
420
  const forcedDrainAfterFinalSuccess = forcedTerminationSignal && cleanTerminalAssistantStopReceived && !result.error;
411
421
  if (code !== 0 && stderrBuf.trim() && !result.error && !forcedDrainAfterFinalSuccess) result.error = stderrBuf.trim();
412
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;
413
434
  finish(finalCode);
414
435
  });
415
436
  proc.on("error", (error) => {
@@ -418,19 +439,15 @@ export async function runSingleAttempt(
418
439
  attemptWatchdog.clear();
419
440
  void jsonlWriter.close().catch(() => undefined);
420
441
  cleanupTempDir(tempDir);
421
- if (!result.error) result.error = error instanceof Error ? error.message : String(error);
442
+ if (!result.error) result.error = formatPiSpawnError(error, spawnSpec, runCwd);
422
443
  finish(1);
423
444
  });
424
445
 
425
446
  if (options.signal) {
426
447
  const kill = () => {
427
- if (processClosed || detached) return;
428
- if (options.allowIntercomDetach && intercomStarted) {
429
- detachForIntercom();
430
- return;
431
- }
432
- proc.kill("SIGTERM");
433
- setTimeout(() => !proc.killed && proc.kill("SIGKILL"), 3000);
448
+ if (childExited) return;
449
+ trySignalChild(proc, "SIGTERM");
450
+ setTimeout(() => { if (!childExited) trySignalChild(proc, "SIGKILL"); }, 3000).unref?.();
434
451
  };
435
452
  if (options.signal.aborted) kill();
436
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
+ }