@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
@@ -0,0 +1,114 @@
1
+ import type {
2
+ AgentEndEvent, AgentStartEvent, ExtensionAPI, ExtensionContext, ExtensionHandler,
3
+ MessageRenderer, ModelSelectEvent, RegisteredCommand, SessionShutdownEvent,
4
+ SessionStartEvent, ToolDefinition, ToolExecutionEndEvent, ToolExecutionStartEvent,
5
+ TurnEndEvent, TurnStartEvent,
6
+ } from "@bastani/atomic";
7
+
8
+ type CapturedCommand = Omit<RegisteredCommand, "name" | "sourceInfo">;
9
+ type CapturedShortcut = Parameters<ExtensionAPI["registerShortcut"]>[1];
10
+ type EventHandler = Parameters<ExtensionAPI["events"]["on"]>[1];
11
+ type EventPayload = Parameters<EventHandler>[0];
12
+ const LIVE_EVENT_SUBSCRIPTIONS = new Set(["pi-intercom:detach-response"]);
13
+
14
+ export type ToolRenderResultArgs = Parameters<NonNullable<ToolDefinition["renderResult"]>>;
15
+ export type ForwardedEventMap = {
16
+ session_start: SessionStartEvent;
17
+ session_shutdown: SessionShutdownEvent;
18
+ turn_start: TurnStartEvent;
19
+ turn_end: TurnEndEvent;
20
+ agent_start: AgentStartEvent;
21
+ agent_end: AgentEndEvent;
22
+ tool_execution_start: ToolExecutionStartEvent;
23
+ tool_execution_end: ToolExecutionEndEvent;
24
+ model_select: ModelSelectEvent;
25
+ };
26
+ type LazyLifecycleEvent = keyof ForwardedEventMap;
27
+ type ForwardedHandler<K extends LazyLifecycleEvent> = ExtensionHandler<ForwardedEventMap[K]>;
28
+ type ForwardedHandlerMap = { [K in LazyLifecycleEvent]: ForwardedHandler<K>[] };
29
+ type AnyForwardedHandler = { [K in LazyLifecycleEvent]: ForwardedHandler<K> }[LazyLifecycleEvent];
30
+ export interface HeavyRuntimeReadiness {
31
+ enabled: boolean;
32
+ awaitAutomaticBrokerReady(): Promise<void>;
33
+ awaitForegroundBrokerReady(): Promise<void>;
34
+ }
35
+
36
+ export type CapturedHeavy = {
37
+ tools: Map<string, ToolDefinition>;
38
+ commands: Map<string, CapturedCommand>;
39
+ handlers: ForwardedHandlerMap;
40
+ shortcuts: Map<string, CapturedShortcut>;
41
+ eventHandlers: Map<string, EventHandler[]>;
42
+ runtimeReadiness?: HeavyRuntimeReadiness;
43
+ };
44
+
45
+ export function createForwardedHandlerMap(): ForwardedHandlerMap {
46
+ return {
47
+ session_start: [], session_shutdown: [], turn_start: [], turn_end: [], agent_start: [],
48
+ agent_end: [], tool_execution_start: [], tool_execution_end: [], model_select: [],
49
+ };
50
+ }
51
+
52
+ function addHandler<K extends LazyLifecycleEvent>(captured: CapturedHeavy, event: K, handler: ForwardedHandler<K>): void {
53
+ captured.handlers[event].push(handler);
54
+ }
55
+
56
+ function captureForwardedHandler(captured: CapturedHeavy, event: LazyLifecycleEvent, handler: AnyForwardedHandler): void {
57
+ switch (event) {
58
+ case "session_start": addHandler(captured, event, handler as ForwardedHandler<"session_start">); return;
59
+ case "session_shutdown": addHandler(captured, event, handler as ForwardedHandler<"session_shutdown">); return;
60
+ case "turn_start": addHandler(captured, event, handler as ForwardedHandler<"turn_start">); return;
61
+ case "turn_end": addHandler(captured, event, handler as ForwardedHandler<"turn_end">); return;
62
+ case "agent_start": addHandler(captured, event, handler as ForwardedHandler<"agent_start">); return;
63
+ case "agent_end": addHandler(captured, event, handler as ForwardedHandler<"agent_end">); return;
64
+ case "tool_execution_start": addHandler(captured, event, handler as ForwardedHandler<"tool_execution_start">); return;
65
+ case "tool_execution_end": addHandler(captured, event, handler as ForwardedHandler<"tool_execution_end">); return;
66
+ case "model_select": addHandler(captured, event, handler as ForwardedHandler<"model_select">);
67
+ }
68
+ }
69
+
70
+ function addEventHandler(captured: CapturedHeavy, event: string, handler: EventHandler): void {
71
+ const handlers = captured.eventHandlers.get(event) ?? [];
72
+ handlers.push(handler);
73
+ captured.eventHandlers.set(event, handlers);
74
+ }
75
+
76
+ export async function dispatchHandlers<K extends LazyLifecycleEvent>(
77
+ captured: CapturedHeavy, eventName: K, event: ForwardedEventMap[K], ctx: ExtensionContext,
78
+ ): Promise<void> {
79
+ for (const handler of captured.handlers[eventName]) await handler(event, ctx);
80
+ }
81
+
82
+ export async function dispatchEventHandlers(captured: CapturedHeavy, eventName: string, payload: EventPayload): Promise<void> {
83
+ for (const handler of captured.eventHandlers.get(eventName) ?? []) await handler(payload);
84
+ }
85
+
86
+ export function createHeavyProxy(pi: ExtensionAPI, captured: CapturedHeavy): ExtensionAPI {
87
+ return new Proxy(pi, {
88
+ get(target, prop, receiver) {
89
+ if (prop === "registerTool") return (tool: ToolDefinition) => captured.tools.set(tool.name, tool);
90
+ if (prop === "registerCommand") return (name: string, options: CapturedCommand) => captured.commands.set(name, options);
91
+ if (prop === "on") return (event: LazyLifecycleEvent, handler: AnyForwardedHandler) => captureForwardedHandler(captured, event, handler);
92
+ if (prop === "registerShortcut") return (shortcut: string, options: CapturedShortcut) => captured.shortcuts.set(shortcut, options);
93
+ if (prop === "registerMessageRenderer") return (customType: string, renderer: MessageRenderer) => pi.registerMessageRenderer(customType, renderer);
94
+ if (prop === "events") {
95
+ return new Proxy(pi.events, {
96
+ get(eventTarget, eventProp, eventReceiver) {
97
+ if (eventProp === "on") {
98
+ return (event: string, handler: EventHandler) => {
99
+ if (LIVE_EVENT_SUBSCRIPTIONS.has(event)) return pi.events.on(event, handler);
100
+ addEventHandler(captured, event, handler);
101
+ return () => {
102
+ const handlers = captured.eventHandlers.get(event) ?? [];
103
+ captured.eventHandlers.set(event, handlers.filter((candidate) => candidate !== handler));
104
+ };
105
+ };
106
+ }
107
+ return Reflect.get(eventTarget, eventProp, eventReceiver);
108
+ },
109
+ });
110
+ }
111
+ return Reflect.get(target, prop, receiver);
112
+ },
113
+ }) as ExtensionAPI;
114
+ }
@@ -0,0 +1,20 @@
1
+ import type { ExtensionAPI } from "@bastani/atomic";
2
+
3
+ const SUBAGENT_RESULT_INTERCOM_EVENT = "subagent:result-intercom";
4
+ const SUBAGENT_RESULT_INTERCOM_DELIVERY_EVENT = "subagent:result-intercom-delivery";
5
+
6
+ export function rejectLazyResultRelay(
7
+ pi: ExtensionAPI,
8
+ eventName: string,
9
+ payload: unknown,
10
+ error: unknown,
11
+ ): void {
12
+ if (eventName !== SUBAGENT_RESULT_INTERCOM_EVENT || !payload || typeof payload !== "object") return;
13
+ const requestId = (payload as { requestId?: unknown }).requestId;
14
+ if (typeof requestId !== "string") return;
15
+ pi.events.emit(SUBAGENT_RESULT_INTERCOM_DELIVERY_EVENT, {
16
+ requestId,
17
+ delivered: false,
18
+ error: error instanceof Error ? error.message : String(error),
19
+ });
20
+ }
@@ -0,0 +1,39 @@
1
+ import type { ExtensionCommandContext, ExtensionContext, ToolDefinition } from "@bastani/atomic";
2
+
3
+ type CommandHandler = (args: string, ctx: ExtensionCommandContext) => void | Promise<void>;
4
+ type ExecutableHeavy = {
5
+ tools: Map<string, ToolDefinition>;
6
+ commands: Map<string, { handler: CommandHandler }>;
7
+ };
8
+
9
+ export type HeavyHandle<THeavy extends ExecutableHeavy> = {
10
+ heavy: THeavy;
11
+ assertCurrent: () => void;
12
+ };
13
+
14
+ export async function executeHeavyTool<THeavy extends ExecutableHeavy>(
15
+ loadHeavy: (ctx?: ExtensionContext) => Promise<HeavyHandle<THeavy>>,
16
+ name: string,
17
+ args: Parameters<NonNullable<ToolDefinition["execute"]>>,
18
+ ): Promise<Awaited<ReturnType<NonNullable<ToolDefinition["execute"]>>>> {
19
+ const handle = await loadHeavy(args[4]);
20
+ handle.assertCurrent();
21
+ const tool = handle.heavy.tools.get(name);
22
+ if (!tool?.execute) throw new Error(`Intercom tool implementation not found: ${name}`);
23
+ const result = await tool.execute(...args);
24
+ handle.assertCurrent();
25
+ return result as Awaited<ReturnType<NonNullable<ToolDefinition["execute"]>>>;
26
+ }
27
+
28
+ export async function runHeavyCommand<THeavy extends ExecutableHeavy>(
29
+ loadHeavy: (ctx?: ExtensionContext) => Promise<HeavyHandle<THeavy>>,
30
+ args: string | undefined,
31
+ ctx: ExtensionCommandContext,
32
+ ): Promise<void> {
33
+ const handle = await loadHeavy(ctx);
34
+ handle.assertCurrent();
35
+ const command = handle.heavy.commands.get("intercom");
36
+ if (!command) throw new Error("Intercom command implementation not found");
37
+ await command.handler(args ?? "", ctx);
38
+ handle.assertCurrent();
39
+ }
@@ -0,0 +1,51 @@
1
+ export interface LifecycleLease<TShutdown> {
2
+ readonly id: number;
3
+ readonly priorCleanup: Promise<void>;
4
+ retired: boolean;
5
+ shutdown: TShutdown | null;
6
+ cleanupBarrier: Promise<void>;
7
+ }
8
+
9
+ export function createLifecycleLease<TShutdown>(
10
+ id: number,
11
+ priorCleanup: Promise<void> = Promise.resolve(),
12
+ ): LifecycleLease<TShutdown> {
13
+ return { id, priorCleanup, retired: false, shutdown: null, cleanupBarrier: priorCleanup };
14
+ }
15
+
16
+ export function retireLifecycleLease<TShutdown>(lease: LifecycleLease<TShutdown>, shutdown: TShutdown): void {
17
+ if (lease.retired) return;
18
+ lease.retired = true;
19
+ lease.shutdown = shutdown;
20
+ }
21
+
22
+ export function retainSettledLifecycleCleanup<TShutdown>(
23
+ lease: LifecycleLease<TShutdown>,
24
+ cleanup: readonly (Promise<unknown> | null)[],
25
+ ): Promise<void> {
26
+ const previousCleanup = lease.cleanupBarrier;
27
+ const pendingCleanup = cleanup.filter((task): task is Promise<unknown> => task !== null);
28
+ lease.cleanupBarrier = Promise.allSettled([previousCleanup, ...pendingCleanup]).then(() => undefined);
29
+ return lease.cleanupBarrier;
30
+ }
31
+
32
+ export function assertCurrentLifecycleLease<TShutdown>(
33
+ current: LifecycleLease<TShutdown>,
34
+ expected: LifecycleLease<TShutdown>,
35
+ message: string,
36
+ ): void {
37
+ if (current !== expected || expected.retired) throw new Error(message);
38
+ }
39
+
40
+ /** Rejection-safe FIFO for lifecycle forwarding that must not overtake replay. */
41
+ export class SerializedLifecycleForwarder {
42
+ private tail: Promise<void> = Promise.resolve();
43
+
44
+ get settled(): Promise<void> { return this.tail; }
45
+
46
+ enqueue<T>(operation: () => Promise<T>): Promise<T> {
47
+ const result = this.tail.then(operation, operation);
48
+ this.tail = result.then(() => undefined, () => undefined);
49
+ return result;
50
+ }
51
+ }
@@ -33,11 +33,44 @@ interface LifecycleDeps {
33
33
  syncPresenceStatus(): void;
34
34
  syncPresenceIdentity(sessionId: string): void;
35
35
  currentStatus(): string;
36
+ restoreIntercomSessionIdEnv?(): void;
36
37
  }
37
38
 
38
39
  export function registerIntercomLifecycle(pi: ExtensionAPI, deps: LifecycleDeps): void {
39
- pi.on("session_start", (_event, ctx) => {
40
+ let hasActiveSession = false;
41
+
42
+ async function cleanupRuntime(reason: string): Promise<void> {
43
+ deps.setRuntimeStarted(false);
44
+ deps.setShuttingDown(true);
45
+ deps.setDisposed(true);
46
+ deps.incrementRuntimeGeneration();
47
+ deps.clearStartupConnectTimer();
48
+ deps.clearReconnectTimer();
49
+ deps.rejectReplyWaiter(new Error(reason));
50
+ deps.replyTracker.reset();
51
+ deps.pendingIdleMessages.length = 0;
52
+ deps.clearInboundFlushTimer();
53
+ deps.setAgentRunning(false);
54
+ deps.activeTools.clear();
55
+ const activeClient = deps.client();
56
+ deps.setClient(null);
57
+ if (activeClient) {
58
+ try {
59
+ await activeClient.disconnect();
60
+ } catch (error) {
61
+ console.error(`Intercom failed to disconnect during ${reason.toLowerCase()}; continuing cleanup:`, error);
62
+ }
63
+ }
64
+ deps.restoreIntercomSessionIdEnv?.();
65
+ deps.setRuntimeContext(null);
66
+ deps.setCurrentSessionId(null);
67
+ deps.setSessionStartedAt(null);
68
+ }
69
+
70
+ pi.on("session_start", async (_event, ctx) => {
40
71
  if (!deps.config.enabled) return;
72
+ if (hasActiveSession) await cleanupRuntime("Session replaced");
73
+ hasActiveSession = true;
41
74
  deps.setShuttingDown(false);
42
75
  deps.setDisposed(false);
43
76
  deps.setRuntimeStarted(true);
@@ -63,25 +96,9 @@ export function registerIntercomLifecycle(pi: ExtensionAPI, deps: LifecycleDeps)
63
96
  });
64
97
 
65
98
  pi.on("session_shutdown", async () => {
66
- deps.setShuttingDown(true);
67
- deps.setDisposed(true);
68
- deps.incrementRuntimeGeneration();
69
- deps.clearStartupConnectTimer();
70
- deps.clearReconnectTimer();
71
- deps.rejectReplyWaiter(new Error("Session shutting down"));
72
- deps.replyTracker.reset();
73
- deps.pendingIdleMessages.length = 0;
74
- deps.clearInboundFlushTimer();
75
- deps.setAgentRunning(false);
76
- deps.activeTools.clear();
77
- const activeClient = deps.client();
78
- if (activeClient) {
79
- await activeClient.disconnect();
80
- deps.setClient(null);
81
- }
82
- deps.setRuntimeContext(null);
83
- deps.setCurrentSessionId(null);
84
- deps.setSessionStartedAt(null);
99
+ if (!hasActiveSession) return;
100
+ hasActiveSession = false;
101
+ await cleanupRuntime("Session shutting down");
85
102
  });
86
103
 
87
104
  pi.on("turn_end", () => {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bastani/intercom",
3
- "version": "0.9.5-alpha.8",
3
+ "version": "0.9.5",
4
4
  "private": true,
5
5
  "description": "Atomic extension providing a private coordination channel between parent and child agent sessions. Fork of: https://github.com/nicobailon/pi-intercom",
6
6
  "contributors": [
@@ -18,10 +18,7 @@
18
18
  ".": "./index.ts"
19
19
  },
20
20
  "files": [
21
- "index.ts",
22
- "types.ts",
23
- "config.ts",
24
- "reply-tracker.ts",
21
+ "*.ts",
25
22
  "broker/**/*.ts",
26
23
  "ui/**/*.ts",
27
24
  "skills/**/*",
@@ -47,7 +44,7 @@
47
44
  },
48
45
  "peerDependencies": {
49
46
  "@bastani/atomic": "*",
50
- "@earendil-works/pi-tui": "^0.80.3"
47
+ "@earendil-works/pi-tui": "^0.80.6"
51
48
  },
52
49
  "peerDependenciesMeta": {
53
50
  "@bastani/atomic": {
@@ -0,0 +1,17 @@
1
+ import type { Message, SessionInfo } from "./types.js";
2
+
3
+ export interface PendingReplyRoute {
4
+ from: string;
5
+ replyTo: string;
6
+ resolve(message: Message): void;
7
+ }
8
+
9
+ /** Routes only the exact sender/thread pair to a blocking tool waiter. */
10
+ export function routeIncomingReply(waiter: PendingReplyRoute | null | undefined, from: SessionInfo, message: Message): boolean {
11
+ if (!waiter) return false;
12
+ const senderTarget = from.name || from.id;
13
+ const fromMatches = senderTarget.toLowerCase() === waiter.from.toLowerCase() || from.id === waiter.from;
14
+ if (!fromMatches || message.replyTo !== waiter.replyTo) return false;
15
+ waiter.resolve(message);
16
+ return true;
17
+ }
@@ -9,6 +9,8 @@ import {
9
9
  getErrorMessage,
10
10
  parseSubagentIntercomPayload,
11
11
  } from "./intercom-utils.js";
12
+ import { DeliveredMessageCache } from "./broker/delivered-message-cache.js";
13
+ import { buildSendSignature } from "./broker/send-signature.js";
12
14
 
13
15
  interface SubagentRelayDeps {
14
16
  runtimeGeneration(): number;
@@ -23,6 +25,7 @@ interface SubagentRelayDeps {
23
25
 
24
26
  export function registerSubagentRelay(pi: ExtensionAPI, deps: SubagentRelayDeps): void {
25
27
  const { getLiveContext, currentSessionTargetMatches, sendIncomingMessage, ensureConnected, resolveSessionTarget } = deps;
28
+ const localDeliveries = new DeliveredMessageCache();
26
29
  function deliverLocalSubagentRelayMessage(sender: "subagent-control" | "subagent-result", status: string, messageText: string): void {
27
30
  const now = Date.now();
28
31
  sendIncomingMessage({
@@ -60,6 +63,37 @@ export function registerSubagentRelay(pi: ExtensionAPI, deps: SubagentRelayDeps)
60
63
  ...(error ? { error: getErrorMessage(error) } : {}),
61
64
  });
62
65
  }
66
+ function acknowledgeResult(options: { acknowledge?: boolean }, requestId: string | undefined, delivered: boolean, error?: unknown): void {
67
+ if (options.acknowledge) emitResultDelivery(requestId, delivered, error);
68
+ }
69
+ function deliverLocal(
70
+ parsed: ReturnType<typeof parseSubagentIntercomPayload> & {},
71
+ options: { sender: "subagent-control" | "subagent-result"; status: string; errorEntryType: string; acknowledge?: boolean },
72
+ ): void {
73
+ try {
74
+ const signature = buildSendSignature(parsed.to, { text: parsed.message });
75
+ const match = parsed.requestId ? localDeliveries.lookup(parsed.requestId, signature) : "miss";
76
+ if (match === "conflict") {
77
+ throw new Error(`Intercom message ID '${parsed.requestId}' was already delivered with a different target or payload`);
78
+ }
79
+ if (match === "miss") {
80
+ deliverLocalSubagentRelayMessage(options.sender, options.status, parsed.message);
81
+ if (parsed.requestId) localDeliveries.record(parsed.requestId, signature);
82
+ }
83
+ acknowledgeResult(options, parsed.requestId, true);
84
+ } catch (error) {
85
+ try {
86
+ recordSubagentDeliveryError(options.errorEntryType, parsed.to, parsed.message, error);
87
+ } catch (recordError) {
88
+ console.error("Failed to record local subagent relay error:", recordError);
89
+ }
90
+ try {
91
+ acknowledgeResult(options, parsed.requestId, false, error);
92
+ } catch (ackError) {
93
+ console.error("Failed to acknowledge local subagent relay error:", ackError);
94
+ }
95
+ }
96
+ }
63
97
  function relaySubagentIntercomPayload(payload: unknown, options: {
64
98
  sender: "subagent-control" | "subagent-result";
65
99
  status: string;
@@ -73,11 +107,11 @@ export function registerSubagentRelay(pi: ExtensionAPI, deps: SubagentRelayDeps)
73
107
  void (async () => {
74
108
  const relayStillLive = () => !deps.runtimeStarted() || Boolean(getLiveContext(deps.runtimeContext(), relayGeneration));
75
109
  if (!relayStillLive()) {
110
+ acknowledgeResult(options, parsed.requestId, false);
76
111
  return;
77
112
  }
78
113
  if (currentSessionTargetMatches(parsed.to)) {
79
- deliverLocalSubagentRelayMessage(options.sender, options.status, parsed.message);
80
- if (options.acknowledge) emitResultDelivery(parsed.requestId, true);
114
+ deliverLocal(parsed, options);
81
115
  return;
82
116
  }
83
117
 
@@ -87,35 +121,47 @@ export function registerSubagentRelay(pi: ExtensionAPI, deps: SubagentRelayDeps)
87
121
  activeClient = await ensureConnected("background");
88
122
  target = await resolveSessionTarget(activeClient, parsed.to) ?? parsed.to;
89
123
  } catch (error) {
90
- if (!relayStillLive()) return;
124
+ if (!relayStillLive()) {
125
+ acknowledgeResult(options, parsed.requestId, false, error);
126
+ return;
127
+ }
91
128
  recordSubagentDeliveryError(options.errorEntryType, parsed.to, parsed.message, error);
92
- if (options.acknowledge) emitResultDelivery(parsed.requestId, false, error);
129
+ acknowledgeResult(options, parsed.requestId, false, error);
93
130
  return;
94
131
  }
95
132
 
96
133
  if (!relayStillLive()) {
134
+ acknowledgeResult(options, parsed.requestId, false);
97
135
  return;
98
136
  }
99
137
  if (currentSessionTargetMatches(parsed.to, target, activeClient)) {
100
- deliverLocalSubagentRelayMessage(options.sender, options.status, parsed.message);
101
- if (options.acknowledge) emitResultDelivery(parsed.requestId, true);
138
+ deliverLocal(parsed, options);
102
139
  return;
103
140
  }
104
141
 
105
142
  try {
106
- const result = await activeClient.send(target, { text: parsed.message });
107
- if (!relayStillLive()) return;
143
+ const result = await activeClient.send(target, {
144
+ text: parsed.message,
145
+ ...(parsed.requestId ? { messageId: parsed.requestId } : {}),
146
+ });
147
+ if (!relayStillLive()) {
148
+ acknowledgeResult(options, parsed.requestId, result.delivered);
149
+ return;
150
+ }
108
151
  if (!result.delivered) {
109
152
  const error = new Error(result.reason ?? "Session may not exist or has disconnected.");
110
153
  recordSubagentDeliveryError(options.errorEntryType, parsed.to, parsed.message, error);
111
- if (options.acknowledge) emitResultDelivery(parsed.requestId, false, error);
154
+ acknowledgeResult(options, parsed.requestId, false, error);
112
155
  return;
113
156
  }
114
- if (options.acknowledge) emitResultDelivery(parsed.requestId, true);
157
+ acknowledgeResult(options, parsed.requestId, true);
115
158
  } catch (error) {
116
- if (!relayStillLive()) return;
159
+ if (!relayStillLive()) {
160
+ acknowledgeResult(options, parsed.requestId, false, error);
161
+ return;
162
+ }
117
163
  recordSubagentDeliveryError(options.errorEntryType, parsed.to, parsed.message, error);
118
- if (options.acknowledge) emitResultDelivery(parsed.requestId, false, error);
164
+ acknowledgeResult(options, parsed.requestId, false, error);
119
165
  }
120
166
  })();
121
167
  }
@@ -31,7 +31,7 @@ export type ClientMessage =
31
31
  | { type: "register"; session: Omit<SessionInfo, "id"> }
32
32
  | { type: "unregister" }
33
33
  | { type: "list"; requestId: string }
34
- | { type: "send"; to: string; message: Message }
34
+ | { type: "send"; to: string; message: Message; attemptId?: string }
35
35
  | { type: "presence"; name?: string; status?: string; model?: string };
36
36
 
37
37
  export type BrokerMessage =
@@ -42,5 +42,5 @@ export type BrokerMessage =
42
42
  | { type: "session_joined"; session: SessionInfo }
43
43
  | { type: "session_left"; sessionId: string }
44
44
  | { type: "error"; error: string }
45
- | { type: "delivered"; messageId: string }
46
- | { type: "delivery_failed"; messageId: string; reason: string };
45
+ | { type: "delivered"; messageId: string; attemptId?: string }
46
+ | { type: "delivery_failed"; messageId: string; reason: string; attemptId?: string };
@@ -7,6 +7,44 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.9.5] - 2026-07-11
11
+
12
+ ### Changed
13
+
14
+ - Aligned the MCP extension peer dependencies with upstream `pi-ai`/`pi-tui` `^0.80.6` as part of the consolidated Pi sync; no MCP source behavior changed ([#1703](https://github.com/bastani-inc/atomic/issues/1703)).
15
+ - Improved startup responsiveness by keeping first-run/default lazy MCP metadata bootstrap out of `initializeMcp()`'s synchronous path. Cached direct tools and the MCP proxy still register immediately, explicit `eager`/`keep-alive` servers still connect during initialization, missing configured or `MCP_DIRECT_TOOLS`-selected direct-tool metadata is warmed in the background, and explicit proxy `search`, `describe`, and server-list requests hydrate cold-cache lazy server metadata on demand instead of broadening startup warmup. Warmed direct tools are registered live in the current session after metadata refresh rather than requiring restart. Cold-cache `describe` first narrows hydration to prefix-matched or explicitly requested servers, treats hyphen/underscore prefixes as aliases, and does not fan out to unrelated lazy servers after a prefix-directed miss; cold-cache proxy `search` intentionally hydrates all matching lazy servers so unscoped searches can see every configured tool.
16
+
17
+ ### Fixed
18
+
19
+ - Replaced one-shot detached MCP startup with generation-safe, retryable single-flight initialization shared by background startup, proxy/direct tools, and readiness-critical commands. Initialization fast paths now validate the active context and exact session lease, commands retain the state they initialized across lazy module imports, and stale or unpublished state cannot execute or publish after shutdown, restart, or context disposal. Replacement startup normally waits for retired initialization plus state/OAuth cleanup, but bounded observed teardown prevents non-abortable SDK work from permanently poisoning later sessions while fencing late completion.
20
+ - Made readiness, lazy-connection, manager-close, and UI-start waits caller-local across direct tools and proxy connect/call/search/describe/list paths. Pre-aborted calls start no producer; one aborted waiter rejects promptly with its exact reason; late shared failures stay observed; late UI runtimes are closed; and proxy modes plus metadata hydration revalidate session ownership after waits and before metadata mutation or SDK side effects.
21
+ - Completed MCP Apps cancellation lifecycles for direct and proxy UI calls by emitting exactly one terminal `tool-cancelled` before session teardown, preserving the exact host abort reason over SDK wrappers, isolating notification failures, keeping success `tool-result` mutually exclusive, forwarding real cancellation events from reused runtimes, and observing asynchronous browser AppBridge send failures.
22
+ - Aligned MCP tool result expansion hints with the CLI-wide `Ctrl+o` keybinding copy.
23
+ - Fixed MCP background direct-tool warmup cancellation so stale in-flight connects are discarded before metadata/cache mutation, direct-tool refresh callbacks are guarded to the active session, completed warmups clear their active handle safely, and env-selected direct tool servers hydrate without forcing every lazy server eager.
24
+
25
+ ## [0.9.5-alpha.10] - 2026-07-11
26
+
27
+ ### Changed
28
+
29
+ - Aligned the MCP extension peer dependencies with upstream `pi-ai`/`pi-tui` `^0.80.6` as part of the consolidated Pi sync; no MCP source behavior changed ([#1703](https://github.com/bastani-inc/atomic/issues/1703)).
30
+
31
+ ### Fixed
32
+
33
+ - Replaced one-shot detached MCP startup with generation-safe, retryable single-flight initialization shared by background startup, proxy/direct tools, and readiness-critical commands. Initialization fast paths now validate the active context and exact session lease, commands retain the state they initialized across lazy module imports, and stale or unpublished state cannot execute or publish after shutdown, restart, or context disposal. Replacement startup normally waits for retired initialization plus state/OAuth cleanup, but bounded observed teardown prevents non-abortable SDK work from permanently poisoning later sessions while fencing late completion.
34
+ - Made readiness, lazy-connection, manager-close, and UI-start waits caller-local across direct tools and proxy connect/call/search/describe/list paths. Pre-aborted calls start no producer; one aborted waiter rejects promptly with its exact reason; late shared failures stay observed; late UI runtimes are closed; and proxy modes plus metadata hydration revalidate session ownership after waits and before metadata mutation or SDK side effects.
35
+ - Completed MCP Apps cancellation lifecycles for direct and proxy UI calls by emitting exactly one terminal `tool-cancelled` before session teardown, preserving the exact host abort reason over SDK wrappers, isolating notification failures, keeping success `tool-result` mutually exclusive, forwarding real cancellation events from reused runtimes, and observing asynchronous browser AppBridge send failures.
36
+
37
+ ## [0.9.5-alpha.9] - 2026-07-09
38
+
39
+ ### Changed
40
+
41
+ - Improved startup responsiveness by keeping first-run/default lazy MCP metadata bootstrap out of `initializeMcp()`'s synchronous path. Cached direct tools and the MCP proxy still register immediately, explicit `eager`/`keep-alive` servers still connect during initialization, missing configured or `MCP_DIRECT_TOOLS`-selected direct-tool metadata is warmed in the background, and explicit proxy `search`, `describe`, and server-list requests hydrate cold-cache lazy server metadata on demand instead of broadening startup warmup. Warmed direct tools are registered live in the current session after metadata refresh rather than requiring restart. Cold-cache `describe` first narrows hydration to prefix-matched or explicitly requested servers, treats hyphen/underscore prefixes as aliases, and does not fan out to unrelated lazy servers after a prefix-directed miss; cold-cache proxy `search` intentionally hydrates all matching lazy servers so unscoped searches can see every configured tool.
42
+
43
+ ### Fixed
44
+
45
+ - Aligned MCP tool result expansion hints with the CLI-wide `Ctrl+o` keybinding copy.
46
+ - Fixed MCP background direct-tool warmup cancellation so stale in-flight connects are discarded before metadata/cache mutation, direct-tool refresh callbacks are guarded to the active session, completed warmups clear their active handle safely, and env-selected direct tool servers hydrate without forcing every lazy server eager.
47
+
10
48
  ## [0.9.4] - 2026-07-03
11
49
 
12
50
  ### Changed
@@ -191,6 +191,7 @@ A Node.js HTTP server runs on `localhost` at path `/callback`:
191
191
  - Displays success/error HTML pages
192
192
  - Validates state parameter for CSRF protection
193
193
  - Has a 5-minute timeout for pending authorizations
194
+ - Rejects and removes pending authorization waiters during session restart/shutdown before replacement-session startup continues
194
195
 
195
196
  ## Token Storage
196
197
 
@@ -65,7 +65,11 @@ Precedence is:
65
65
  3. `.mcp.json`
66
66
  4. `.pi/mcp.json`
67
67
 
68
- Servers are **lazy by default** — they won't connect until you actually call one of their tools. The adapter caches tool metadata so search and describe work without live connections.
68
+ Servers are **lazy by default** — they won't connect until you actually call one of their tools. The adapter caches tool metadata so search and describe work without live connections when a valid cache exists; on a cold cache, explicit proxy search/describe/server-list requests may connect lazy server(s) once to hydrate metadata on demand. `describe` narrows cold-cache hydration to an explicitly requested server or the server identified by the configured tool-name prefix before falling back to broader discovery. Unscoped `search` intentionally hydrates every configured lazy server that lacks cached metadata so the search can see all available tools.
69
+
70
+ MCP startup and first-use calls share one initialization attempt per session. If background initialization fails, the next proxy, direct-tool, `/mcp`, or `/mcp-auth` use retries it; concurrent callers join that retry rather than starting duplicates, and a stale attempt cannot publish after session shutdown or context disposal. Replacement sessions normally wait for retired initialization, state, and OAuth cleanup; teardown uses a finite deadline so a non-abortable SDK producer cannot permanently block later sessions, while late settlement stays observed and fenced from publication. Shared lazy server connections and auto-authentication flows use the same caller-local cancellation rule: a pre-cancelled call starts nothing, while cancelling one waiter promptly rejects that call with its exact host reason without cancelling the producer needed by surviving callers. Session restart/shutdown deterministically rejects retired OAuth callers with retry guidance and clears old ownership before replacement authentication begins. Direct tools, proxy modes, metadata hydration, and readiness-critical commands revalidate the exact session lease after lifecycle-spanning waits and before SDK calls or state mutation; a UI runtime produced after caller cancellation is closed rather than orphaned. Direct and proxy resource/tool requests still forward the call's abort signal to the MCP SDK; protocol-level remote cancellation remains advisory.
71
+
72
+ For MCP Apps tools, host cancellation sends one terminal `tool-cancelled` event after tool input and before session teardown, then rejects with the exact host abort reason even when the SDK wraps cancellation or the browser notification fails. A successful `tool-result` is mutually exclusive with that cancellation event. Non-UI tools and resource reads do not participate in the Apps lifecycle.
69
73
 
70
74
  ```
71
75
  mcp({ search: "screenshot" })
@@ -136,7 +140,7 @@ Pi-specific files are the write targets for imported or shared global servers wh
136
140
 
137
141
  ### Lifecycle Modes
138
142
 
139
- - **`lazy`** (default) — Don't connect at startup. Connect on first tool call. Disconnect after idle timeout. Cached metadata keeps search/list working without connections.
143
+ - **`lazy`** (default) — Don't connect at startup. Connect on first tool call or explicit cold-cache proxy metadata request (`search`, `describe`, or `server` list). Disconnect after idle timeout. Cached metadata keeps search/list working without connections.
140
144
  - **`eager`** — Connect at startup but don't auto-reconnect if the connection drops. No idle timeout by default (set `idleTimeout` explicitly to enable).
141
145
  - **`keep-alive`** — Connect at startup. Auto-reconnect via health checks. No idle timeout. Use for servers you always need available.
142
146
 
@@ -232,7 +236,7 @@ To exclude specific tools while still using `directTools: true`, add `excludeToo
232
236
 
233
237
  Each direct tool costs ~150-300 tokens in the system prompt (name + description + schema). Good for targeted sets of 5-20 tools. For servers with 75+ tools, stick with the proxy or pick specific tools with a `string[]`.
234
238
 
235
- Direct tools register from the metadata cache in the Pi agent dir (`~/.pi/agent/mcp-cache.json` by default, or `$PI_CODING_AGENT_DIR/mcp-cache.json` when set), so no server connections are needed at startup. On the first session after adding `directTools` to a new server, the cache won't exist yet — tools fall back to proxy-only and the cache populates in the background. To force it: `/mcp reconnect <server>`.
239
+ Direct tools register from the metadata cache in the Pi agent dir (`~/.pi/agent/mcp-cache.json` by default, or `$PI_CODING_AGENT_DIR/mcp-cache.json` when set), so no server connections are needed at startup when the cache is warm. On the first session after adding `directTools` to a new server, or when a child/subagent selects tools through `MCP_DIRECT_TOOLS`, the cache may not exist yet — tools fall back to proxy-only while the selected/configured direct-tool servers populate in the background, then the extension refreshes tool registration so the warmed direct tools become available in the current session. To force it immediately: `/mcp reconnect <server>`.
236
240
 
237
241
  When you change direct-tool toggles in `/mcp` or write new config through `/mcp setup`, the extension triggers Pi's normal reload flow automatically. That refreshes extensions, prompts, skills, and MCP tool registration in one shot, so newly configured direct tools can appear without a manual restart.
238
242
 
@@ -332,7 +336,7 @@ Prefer `.mcp.json` for project-local shared MCP config. Use `.pi/mcp.json` only
332
336
  | Connect | `mcp({ connect: "server-name" })` |
333
337
  | UI messages | `mcp({ action: "ui-messages" })` |
334
338
 
335
- MCP proxy and direct-tool results render compactly by default: long text shows the first three lines plus a `CTRL+O Expand` hint, while the full result remains available when expanded and is still returned unchanged to the model.
339
+ MCP proxy and direct-tool results render compactly by default: long text shows the first three lines plus a `Ctrl+o Expand` hint, while the full result remains available when expanded and is still returned unchanged to the model.
336
340
 
337
341
  Search includes both MCP tools and Pi tools (from extensions). Pi tools appear first with `[pi tool]` prefix. Space-separated words are OR'd.
338
342
 
@@ -358,8 +362,8 @@ In interactive sessions, you can also authenticate from `/mcp` with `CTRL+A` or
358
362
  ## How It Works
359
363
 
360
364
  - One `mcp` tool in context (~200 tokens) instead of hundreds
361
- - Servers are lazy by default — they connect on first tool call, not at startup
362
- - Tool metadata is cached to disk so search/list/describe work without live connections
365
+ - Servers are lazy by default — they connect on first tool call or explicit cold-cache proxy metadata request, not at startup
366
+ - Tool metadata is cached to disk so search/list/describe work without live connections when the cache is valid; cold-cache explicit search/describe/server-list requests hydrate metadata on demand
363
367
  - Idle servers disconnect after 10 minutes (configurable), reconnect automatically on next use
364
368
  - npx-based servers resolve to direct binary paths, skipping the ~143 MB npm parent process
365
369
  - MCP server validates arguments, not the adapter
@@ -0,0 +1,32 @@
1
+ import type { UiSessionRuntime } from "./ui-session.js";
2
+ import { logger } from "./logger.js";
3
+
4
+ function formatCancellationReason(signal: AbortSignal): string {
5
+ const reason = signal.reason;
6
+ return reason instanceof Error ? reason.message : String(reason);
7
+ }
8
+
9
+ export async function notifyUiCancellation(
10
+ uiSession: UiSessionRuntime | null,
11
+ reason: string,
12
+ ): Promise<void> {
13
+ if (!uiSession) return;
14
+ try {
15
+ await uiSession.sendToolCancelled(reason);
16
+ } catch (error) {
17
+ logger.error(
18
+ "Failed to notify MCP App about tool cancellation",
19
+ error instanceof Error ? error : new Error(String(error)),
20
+ { server: uiSession.serverName, tool: uiSession.toolName },
21
+ );
22
+ }
23
+ }
24
+
25
+ export async function rethrowHostAbortAfterUiCancellation(
26
+ signal: AbortSignal | undefined,
27
+ uiSession: UiSessionRuntime | null,
28
+ ): Promise<void> {
29
+ if (!signal?.aborted) return;
30
+ await notifyUiCancellation(uiSession, formatCancellationReason(signal));
31
+ signal.throwIfAborted();
32
+ }
@@ -0,0 +1,9 @@
1
+ import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
2
+
3
+ /**
4
+ * The SDK schema's inferred result also includes task handles, while these
5
+ * legacy adapter paths consume the terminal CallToolResult shape.
6
+ */
7
+ export function asCallToolResult(result: object): CallToolResult {
8
+ return result as CallToolResult;
9
+ }