@bastani/atomic 0.9.5-alpha.9 → 0.9.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (377) hide show
  1. package/CHANGELOG.md +106 -0
  2. package/README.md +2 -2
  3. package/dist/builtin/cursor/CHANGELOG.md +12 -0
  4. package/dist/builtin/cursor/package.json +3 -3
  5. package/dist/builtin/cursor/src/model-mapper.ts +6 -3
  6. package/dist/builtin/intercom/CHANGELOG.md +37 -0
  7. package/dist/builtin/intercom/README.md +4 -2
  8. package/dist/builtin/intercom/broker/broker.ts +6 -114
  9. package/dist/builtin/intercom/broker/client.ts +29 -54
  10. package/dist/builtin/intercom/broker/delivered-message-cache.ts +44 -0
  11. package/dist/builtin/intercom/broker/pending-send-registry.ts +142 -0
  12. package/dist/builtin/intercom/broker/send-handler.ts +106 -0
  13. package/dist/builtin/intercom/broker/send-signature.ts +37 -0
  14. package/dist/builtin/intercom/foreground-detach-handoff.ts +136 -0
  15. package/dist/builtin/intercom/index-heavy.ts +49 -53
  16. package/dist/builtin/intercom/index.ts +278 -262
  17. package/dist/builtin/intercom/lazy-heavy-proxy.ts +114 -0
  18. package/dist/builtin/intercom/lazy-subagent-ack.ts +20 -0
  19. package/dist/builtin/intercom/lazy-tool-execution.ts +39 -0
  20. package/dist/builtin/intercom/lifecycle-lease.ts +51 -0
  21. package/dist/builtin/intercom/lifecycle.ts +37 -20
  22. package/dist/builtin/intercom/package.json +3 -6
  23. package/dist/builtin/intercom/reply-routing.ts +17 -0
  24. package/dist/builtin/intercom/subagent-relay.ts +58 -12
  25. package/dist/builtin/intercom/types.ts +3 -3
  26. package/dist/builtin/mcp/CHANGELOG.md +27 -0
  27. package/dist/builtin/mcp/OAUTH.md +1 -0
  28. package/dist/builtin/mcp/README.md +4 -0
  29. package/dist/builtin/mcp/apps-cancellation.ts +32 -0
  30. package/dist/builtin/mcp/call-tool-result.ts +9 -0
  31. package/dist/builtin/mcp/caller-wait.ts +50 -0
  32. package/dist/builtin/mcp/command-registration.ts +82 -0
  33. package/dist/builtin/mcp/direct-tool-executor.ts +279 -0
  34. package/dist/builtin/mcp/direct-tools.ts +6 -239
  35. package/dist/builtin/mcp/host-html-template.ts +4 -2
  36. package/dist/builtin/mcp/index.ts +258 -250
  37. package/dist/builtin/mcp/init.ts +96 -87
  38. package/dist/builtin/mcp/mcp-auth-flow.ts +247 -237
  39. package/dist/builtin/mcp/mcp-callback-server.ts +89 -68
  40. package/dist/builtin/mcp/mcp-oauth-provider.ts +23 -1
  41. package/dist/builtin/mcp/metadata-hydration.ts +21 -6
  42. package/dist/builtin/mcp/package.json +3 -3
  43. package/dist/builtin/mcp/proxy-auth.ts +4 -4
  44. package/dist/builtin/mcp/proxy-call.ts +111 -40
  45. package/dist/builtin/mcp/proxy-connect.ts +35 -15
  46. package/dist/builtin/mcp/proxy-info-modes.ts +49 -19
  47. package/dist/builtin/mcp/proxy-modes.ts +3 -3
  48. package/dist/builtin/mcp/session-cleanup-barrier.ts +43 -0
  49. package/dist/builtin/mcp/state-lease.ts +12 -0
  50. package/dist/builtin/mcp/ui-server.ts +8 -8
  51. package/dist/builtin/mcp/ui-session.ts +9 -18
  52. package/dist/builtin/subagents/CHANGELOG.md +66 -0
  53. package/dist/builtin/subagents/README.md +30 -29
  54. package/dist/builtin/subagents/agents/code-simplifier.md +2 -2
  55. package/dist/builtin/subagents/agents/codebase-analyzer.md +2 -2
  56. package/dist/builtin/subagents/agents/codebase-locator.md +2 -2
  57. package/dist/builtin/subagents/agents/codebase-online-researcher.md +2 -2
  58. package/dist/builtin/subagents/agents/codebase-pattern-finder.md +2 -2
  59. package/dist/builtin/subagents/agents/codebase-research-analyzer.md +2 -2
  60. package/dist/builtin/subagents/agents/codebase-research-locator.md +2 -2
  61. package/dist/builtin/subagents/agents/debugger.md +2 -2
  62. package/dist/builtin/subagents/agents/worker.md +2 -2
  63. package/dist/builtin/subagents/package.json +5 -5
  64. package/dist/builtin/subagents/prompts/review-loop.md +1 -1
  65. package/dist/builtin/subagents/skills/subagent/SKILL.md +37 -36
  66. package/dist/builtin/subagents/src/extension/api-lifecycle.ts +64 -0
  67. package/dist/builtin/subagents/src/extension/fanout-child.ts +44 -51
  68. package/dist/builtin/subagents/src/extension/index.ts +287 -307
  69. package/dist/builtin/subagents/src/extension/prompt-guidance.ts +7 -10
  70. package/dist/builtin/subagents/src/extension/schemas.ts +22 -5
  71. package/dist/builtin/subagents/src/extension/tool-description.ts +29 -0
  72. package/dist/builtin/subagents/src/intercom/intercom-bridge.ts +13 -2
  73. package/dist/builtin/subagents/src/intercom/result-intercom.ts +4 -4
  74. package/dist/builtin/subagents/src/runs/background/async-event-journal.ts +106 -0
  75. package/dist/builtin/subagents/src/runs/background/async-execution-common.ts +3 -2
  76. package/dist/builtin/subagents/src/runs/background/async-execution-single.ts +13 -2
  77. package/dist/builtin/subagents/src/runs/background/async-execution-types.ts +3 -0
  78. package/dist/builtin/subagents/src/runs/background/async-job-tracker.ts +1 -1
  79. package/dist/builtin/subagents/src/runs/background/completion-claims.ts +189 -0
  80. package/dist/builtin/subagents/src/runs/background/completion-dedupe.ts +44 -7
  81. package/dist/builtin/subagents/src/runs/background/completion-notification.ts +34 -0
  82. package/dist/builtin/subagents/src/runs/background/notify.ts +72 -22
  83. package/dist/builtin/subagents/src/runs/background/result-delivery-processor.ts +232 -0
  84. package/dist/builtin/subagents/src/runs/background/result-file-claims.ts +151 -0
  85. package/dist/builtin/subagents/src/runs/background/result-quarantine.ts +72 -0
  86. package/dist/builtin/subagents/src/runs/background/result-retry-scheduler.ts +48 -0
  87. package/dist/builtin/subagents/src/runs/background/result-status.ts +81 -0
  88. package/dist/builtin/subagents/src/runs/background/result-watcher-data.ts +59 -0
  89. package/dist/builtin/subagents/src/runs/background/result-watcher.ts +172 -238
  90. package/dist/builtin/subagents/src/runs/background/run-id-resolver.ts +3 -2
  91. package/dist/builtin/subagents/src/runs/background/stale-run-reconciler.ts +73 -14
  92. package/dist/builtin/subagents/src/runs/background/subagent-runner-streaming.ts +17 -13
  93. package/dist/builtin/subagents/src/runs/background/top-level-async.ts +1 -2
  94. package/dist/builtin/subagents/src/runs/foreground/chain-execution-dynamic-step.ts +1 -0
  95. package/dist/builtin/subagents/src/runs/foreground/chain-execution-parallel-runner.ts +1 -0
  96. package/dist/builtin/subagents/src/runs/foreground/chain-execution-parallel-step.ts +1 -0
  97. package/dist/builtin/subagents/src/runs/foreground/chain-execution-sequential-step.ts +7 -9
  98. package/dist/builtin/subagents/src/runs/foreground/chain-execution-types.ts +3 -13
  99. package/dist/builtin/subagents/src/runs/foreground/chain-execution.ts +2 -15
  100. package/dist/builtin/subagents/src/runs/foreground/execution-attempt-finalize.ts +2 -2
  101. package/dist/builtin/subagents/src/runs/foreground/execution-attempt.ts +53 -44
  102. package/dist/builtin/subagents/src/runs/foreground/execution-detach-reservations.ts +48 -0
  103. package/dist/builtin/subagents/src/runs/foreground/execution-detach-route.ts +17 -0
  104. package/dist/builtin/subagents/src/runs/foreground/execution-run-sync.ts +39 -26
  105. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-async.ts +3 -1
  106. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-chain.ts +3 -51
  107. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-context.ts +6 -11
  108. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-input.ts +11 -2
  109. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-parallel-task.ts +2 -0
  110. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-parallel.ts +5 -112
  111. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-resume.ts +2 -0
  112. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-single.ts +68 -118
  113. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-status.ts +79 -7
  114. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-types.ts +2 -2
  115. package/dist/builtin/subagents/src/runs/foreground/subagent-executor.ts +3 -0
  116. package/dist/builtin/subagents/src/runs/shared/pi-args.ts +2 -2
  117. package/dist/builtin/subagents/src/runs/shared/pi-spawn.ts +27 -11
  118. package/dist/builtin/subagents/src/shared/artifacts.ts +22 -11
  119. package/dist/builtin/subagents/src/shared/event-jsonl-writer.ts +294 -0
  120. package/dist/builtin/subagents/src/shared/exclusive-file-publication.ts +44 -0
  121. package/dist/builtin/subagents/src/shared/jsonl-writer.ts +1 -0
  122. package/dist/builtin/subagents/src/shared/model-info.ts +2 -2
  123. package/dist/builtin/subagents/src/shared/settings.ts +20 -10
  124. package/dist/builtin/subagents/src/shared/types-async.ts +3 -1
  125. package/dist/builtin/subagents/src/shared/types-config.ts +2 -0
  126. package/dist/builtin/subagents/src/shared/types-runtime.ts +3 -2
  127. package/dist/builtin/subagents/src/slash/slash-commands.ts +9 -12
  128. package/dist/builtin/subagents/src/slash/slash-live-state.ts +63 -32
  129. package/dist/builtin/subagents/src/tui/render-result.ts +7 -0
  130. package/dist/builtin/subagents/src/tui/render-stable-output.ts +1 -0
  131. package/dist/builtin/subagents/src/tui/render-widget.ts +128 -89
  132. package/dist/builtin/web-access/CHANGELOG.md +28 -0
  133. package/dist/builtin/web-access/README.md +4 -0
  134. package/dist/builtin/web-access/content-tools.ts +8 -3
  135. package/dist/builtin/web-access/index-heavy.ts +1 -1
  136. package/dist/builtin/web-access/index.ts +190 -46
  137. package/dist/builtin/web-access/lifecycle-lease.ts +38 -0
  138. package/dist/builtin/web-access/package.json +2 -2
  139. package/dist/builtin/web-access/result-renderers.ts +1 -1
  140. package/dist/builtin/web-access/summary-review.ts +1 -1
  141. package/dist/builtin/web-access/web-search-activity.ts +1 -1
  142. package/dist/builtin/web-access/web-search-return.ts +7 -0
  143. package/dist/builtin/web-access/web-search-summary.ts +1 -1
  144. package/dist/builtin/web-access/web-search-tool.ts +4 -2
  145. package/dist/builtin/workflows/CHANGELOG.md +68 -0
  146. package/dist/builtin/workflows/README.md +4 -4
  147. package/dist/builtin/workflows/builtin/deep-research-codebase-utils.ts +27 -4
  148. package/dist/builtin/workflows/builtin/goal-runner.ts +47 -26
  149. package/dist/builtin/workflows/builtin/open-claude-design-runner.ts +10 -0
  150. package/dist/builtin/workflows/builtin/ralph-core.ts +9 -9
  151. package/dist/builtin/workflows/builtin/ralph-models.ts +71 -36
  152. package/dist/builtin/workflows/builtin/ralph-runner.ts +20 -31
  153. package/dist/builtin/workflows/package.json +2 -2
  154. package/dist/builtin/workflows/src/durable/stage-primitive.ts +2 -1
  155. package/dist/builtin/workflows/src/engine/primitives/task.ts +2 -1
  156. package/dist/builtin/workflows/src/extension/workflow-prompts.ts +17 -22
  157. package/dist/builtin/workflows/src/extension/workflow-schema.ts +15 -2
  158. package/dist/builtin/workflows/src/runs/foreground/executor-hil.ts +1 -2
  159. package/dist/builtin/workflows/src/runs/shared/model-fallback-candidates.ts +1 -1
  160. package/dist/builtin/workflows/src/shared/authoring-contract-stage.d.ts +2 -2
  161. package/dist/builtin/workflows/src/shared/authoring-contract-stage.ts +2 -2
  162. package/dist/builtin/workflows/src/shared/resume-continuation.ts +2 -0
  163. package/dist/builtin/workflows/src/tui/stage-chat-view-archive-history.ts +1 -23
  164. package/dist/builtin/workflows/src/tui/stage-chat-view-footer-status.ts +54 -9
  165. package/dist/builtin/workflows/src/tui/stage-chat-view.ts +5 -2
  166. package/dist/cli/args.d.ts.map +1 -1
  167. package/dist/cli/args.js +2 -2
  168. package/dist/cli/args.js.map +1 -1
  169. package/dist/core/agent-session-events.d.ts.map +1 -1
  170. package/dist/core/agent-session-events.js +2 -1
  171. package/dist/core/agent-session-events.js.map +1 -1
  172. package/dist/core/agent-session-message-queue.d.ts.map +1 -1
  173. package/dist/core/agent-session-message-queue.js +1 -1
  174. package/dist/core/agent-session-message-queue.js.map +1 -1
  175. package/dist/core/agent-session-prompt.d.ts.map +1 -1
  176. package/dist/core/agent-session-prompt.js +1 -1
  177. package/dist/core/agent-session-prompt.js.map +1 -1
  178. package/dist/core/agent-session-retry.d.ts.map +1 -1
  179. package/dist/core/agent-session-retry.js +1 -1
  180. package/dist/core/agent-session-retry.js.map +1 -1
  181. package/dist/core/agent-session-services.d.ts.map +1 -1
  182. package/dist/core/agent-session-services.js +3 -2
  183. package/dist/core/agent-session-services.js.map +1 -1
  184. package/dist/core/agent-session-types.d.ts.map +1 -1
  185. package/dist/core/agent-session-types.js +1 -1
  186. package/dist/core/agent-session-types.js.map +1 -1
  187. package/dist/core/anthropic-thinking-guard.d.ts +5 -5
  188. package/dist/core/anthropic-thinking-guard.d.ts.map +1 -1
  189. package/dist/core/anthropic-thinking-guard.js +42 -32
  190. package/dist/core/anthropic-thinking-guard.js.map +1 -1
  191. package/dist/core/atomic-guide-command.d.ts.map +1 -1
  192. package/dist/core/atomic-guide-command.js +15 -15
  193. package/dist/core/atomic-guide-command.js.map +1 -1
  194. package/dist/core/auth-storage.d.ts.map +1 -1
  195. package/dist/core/auth-storage.js +14 -9
  196. package/dist/core/auth-storage.js.map +1 -1
  197. package/dist/core/compaction/compaction.d.ts +2 -0
  198. package/dist/core/compaction/compaction.d.ts.map +1 -1
  199. package/dist/core/compaction/compaction.js +79 -46
  200. package/dist/core/compaction/compaction.js.map +1 -1
  201. package/dist/core/compaction/context-assistant-turns.d.ts +42 -0
  202. package/dist/core/compaction/context-assistant-turns.d.ts.map +1 -0
  203. package/dist/core/compaction/context-assistant-turns.js +87 -0
  204. package/dist/core/compaction/context-assistant-turns.js.map +1 -0
  205. package/dist/core/compaction/context-compaction-critical.d.ts +1 -1
  206. package/dist/core/compaction/context-compaction-critical.d.ts.map +1 -1
  207. package/dist/core/compaction/context-compaction-critical.js +2 -2
  208. package/dist/core/compaction/context-compaction-critical.js.map +1 -1
  209. package/dist/core/compaction/context-compaction-eviction-alternates.d.ts +18 -0
  210. package/dist/core/compaction/context-compaction-eviction-alternates.d.ts.map +1 -0
  211. package/dist/core/compaction/context-compaction-eviction-alternates.js +186 -0
  212. package/dist/core/compaction/context-compaction-eviction-alternates.js.map +1 -0
  213. package/dist/core/compaction/context-compaction-eviction.d.ts +10 -2
  214. package/dist/core/compaction/context-compaction-eviction.d.ts.map +1 -1
  215. package/dist/core/compaction/context-compaction-eviction.js +196 -146
  216. package/dist/core/compaction/context-compaction-eviction.js.map +1 -1
  217. package/dist/core/compaction/context-compaction-prompt.d.ts.map +1 -1
  218. package/dist/core/compaction/context-compaction-prompt.js +1 -1
  219. package/dist/core/compaction/context-compaction-prompt.js.map +1 -1
  220. package/dist/core/compaction/context-compaction-types.d.ts +2 -0
  221. package/dist/core/compaction/context-compaction-types.d.ts.map +1 -1
  222. package/dist/core/compaction/context-compaction-types.js.map +1 -1
  223. package/dist/core/compaction/context-deletion-application.d.ts +5 -4
  224. package/dist/core/compaction/context-deletion-application.d.ts.map +1 -1
  225. package/dist/core/compaction/context-deletion-application.js +17 -15
  226. package/dist/core/compaction/context-deletion-application.js.map +1 -1
  227. package/dist/core/compaction/context-deletion-store.d.ts.map +1 -1
  228. package/dist/core/compaction/context-deletion-store.js +1 -1
  229. package/dist/core/compaction/context-deletion-store.js.map +1 -1
  230. package/dist/core/compaction/context-deletion-targets.d.ts +2 -1
  231. package/dist/core/compaction/context-deletion-targets.d.ts.map +1 -1
  232. package/dist/core/compaction/context-deletion-targets.js +36 -31
  233. package/dist/core/compaction/context-deletion-targets.js.map +1 -1
  234. package/dist/core/compaction/context-deletion-tool-helpers.d.ts.map +1 -1
  235. package/dist/core/compaction/context-deletion-tool-helpers.js +116 -43
  236. package/dist/core/compaction/context-deletion-tool-helpers.js.map +1 -1
  237. package/dist/core/compaction/context-transcript-analysis.d.ts +1 -2
  238. package/dist/core/compaction/context-transcript-analysis.d.ts.map +1 -1
  239. package/dist/core/compaction/context-transcript-analysis.js +33 -37
  240. package/dist/core/compaction/context-transcript-analysis.js.map +1 -1
  241. package/dist/core/copilot-model-synthesis.d.ts.map +1 -1
  242. package/dist/core/copilot-model-synthesis.js +3 -1
  243. package/dist/core/copilot-model-synthesis.js.map +1 -1
  244. package/dist/core/extensions/provider-types.d.ts +2 -7
  245. package/dist/core/extensions/provider-types.d.ts.map +1 -1
  246. package/dist/core/extensions/provider-types.js.map +1 -1
  247. package/dist/core/messages.d.ts +9 -0
  248. package/dist/core/messages.d.ts.map +1 -1
  249. package/dist/core/messages.js +100 -18
  250. package/dist/core/messages.js.map +1 -1
  251. package/dist/core/model-registry-builtins.d.ts.map +1 -1
  252. package/dist/core/model-registry-builtins.js +5 -0
  253. package/dist/core/model-registry-builtins.js.map +1 -1
  254. package/dist/core/model-registry-custom-loader.d.ts.map +1 -1
  255. package/dist/core/model-registry-custom-loader.js +49 -8
  256. package/dist/core/model-registry-custom-loader.js.map +1 -1
  257. package/dist/core/model-registry-dynamic.d.ts.map +1 -1
  258. package/dist/core/model-registry-dynamic.js +11 -5
  259. package/dist/core/model-registry-dynamic.js.map +1 -1
  260. package/dist/core/model-registry-loader.d.ts.map +1 -1
  261. package/dist/core/model-registry-loader.js +8 -0
  262. package/dist/core/model-registry-loader.js.map +1 -1
  263. package/dist/core/model-registry-schemas.d.ts +93 -8
  264. package/dist/core/model-registry-schemas.d.ts.map +1 -1
  265. package/dist/core/model-registry-schemas.js +24 -12
  266. package/dist/core/model-registry-schemas.js.map +1 -1
  267. package/dist/core/model-registry-types.d.ts +7 -6
  268. package/dist/core/model-registry-types.d.ts.map +1 -1
  269. package/dist/core/model-registry-types.js.map +1 -1
  270. package/dist/core/model-registry.d.ts +5 -0
  271. package/dist/core/model-registry.d.ts.map +1 -1
  272. package/dist/core/model-registry.js +23 -0
  273. package/dist/core/model-registry.js.map +1 -1
  274. package/dist/core/model-resolver-cli.d.ts.map +1 -1
  275. package/dist/core/model-resolver-cli.js +33 -5
  276. package/dist/core/model-resolver-cli.js.map +1 -1
  277. package/dist/core/model-resolver-initial.d.ts +6 -1
  278. package/dist/core/model-resolver-initial.d.ts.map +1 -1
  279. package/dist/core/model-resolver-initial.js +12 -7
  280. package/dist/core/model-resolver-initial.js.map +1 -1
  281. package/dist/core/model-resolver.d.ts +1 -1
  282. package/dist/core/model-resolver.d.ts.map +1 -1
  283. package/dist/core/model-resolver.js +1 -1
  284. package/dist/core/model-resolver.js.map +1 -1
  285. package/dist/core/resource-loader-context-files.d.ts +1 -0
  286. package/dist/core/resource-loader-context-files.d.ts.map +1 -1
  287. package/dist/core/resource-loader-context-files.js +13 -10
  288. package/dist/core/resource-loader-context-files.js.map +1 -1
  289. package/dist/core/sdk.d.ts.map +1 -1
  290. package/dist/core/sdk.js +2 -2
  291. package/dist/core/sdk.js.map +1 -1
  292. package/dist/core/session-entry-normalization.d.ts +7 -0
  293. package/dist/core/session-entry-normalization.d.ts.map +1 -0
  294. package/dist/core/session-entry-normalization.js +14 -0
  295. package/dist/core/session-entry-normalization.js.map +1 -0
  296. package/dist/core/session-manager-core.d.ts.map +1 -1
  297. package/dist/core/session-manager-core.js +1 -0
  298. package/dist/core/session-manager-core.js.map +1 -1
  299. package/dist/core/session-manager-history.d.ts +2 -2
  300. package/dist/core/session-manager-history.d.ts.map +1 -1
  301. package/dist/core/session-manager-history.js +127 -108
  302. package/dist/core/session-manager-history.js.map +1 -1
  303. package/dist/core/settings-manager-basic-accessors.d.ts +2 -2
  304. package/dist/core/settings-manager-basic-accessors.d.ts.map +1 -1
  305. package/dist/core/settings-manager-basic-accessors.js.map +1 -1
  306. package/dist/core/settings-types.d.ts +1 -1
  307. package/dist/core/settings-types.d.ts.map +1 -1
  308. package/dist/core/settings-types.js.map +1 -1
  309. package/dist/core/tools/bash.d.ts.map +1 -1
  310. package/dist/core/tools/bash.js +11 -8
  311. package/dist/core/tools/bash.js.map +1 -1
  312. package/dist/main-session.d.ts.map +1 -1
  313. package/dist/main-session.js +1 -0
  314. package/dist/main-session.js.map +1 -1
  315. package/dist/modes/interactive/components/settings-selector-options.d.ts.map +1 -1
  316. package/dist/modes/interactive/components/settings-selector-options.js +3 -1
  317. package/dist/modes/interactive/components/settings-selector-options.js.map +1 -1
  318. package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
  319. package/dist/modes/interactive/components/thinking-selector.js +2 -1
  320. package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
  321. package/dist/modes/interactive/interactive-agent-events.d.ts.map +1 -1
  322. package/dist/modes/interactive/interactive-agent-events.js +2 -1
  323. package/dist/modes/interactive/interactive-agent-events.js.map +1 -1
  324. package/dist/modes/interactive/interactive-child-ordering.d.ts +7 -0
  325. package/dist/modes/interactive/interactive-child-ordering.d.ts.map +1 -0
  326. package/dist/modes/interactive/interactive-child-ordering.js +26 -0
  327. package/dist/modes/interactive/interactive-child-ordering.js.map +1 -0
  328. package/dist/modes/interactive/interactive-deferred-startup.d.ts.map +1 -1
  329. package/dist/modes/interactive/interactive-deferred-startup.js +2 -2
  330. package/dist/modes/interactive/interactive-deferred-startup.js.map +1 -1
  331. package/dist/modes/interactive/interactive-mode-deps.d.ts +1 -1
  332. package/dist/modes/interactive/interactive-mode-deps.d.ts.map +1 -1
  333. package/dist/modes/interactive/interactive-mode-deps.js +1 -1
  334. package/dist/modes/interactive/interactive-mode-deps.js.map +1 -1
  335. package/dist/modes/interactive/interactive-model-routing.d.ts.map +1 -1
  336. package/dist/modes/interactive/interactive-model-routing.js +8 -3
  337. package/dist/modes/interactive/interactive-model-routing.js.map +1 -1
  338. package/dist/modes/interactive/theme/theme-class.d.ts +1 -1
  339. package/dist/modes/interactive/theme/theme-class.d.ts.map +1 -1
  340. package/dist/modes/interactive/theme/theme-class.js +2 -0
  341. package/dist/modes/interactive/theme/theme-class.js.map +1 -1
  342. package/dist/utils/clipboard-image.d.ts.map +1 -1
  343. package/dist/utils/clipboard-image.js +3 -0
  344. package/dist/utils/clipboard-image.js.map +1 -1
  345. package/docs/changelog.mdx +19 -0
  346. package/docs/compaction.md +55 -48
  347. package/docs/custom-provider.md +18 -5
  348. package/docs/extensions.md +7 -3
  349. package/docs/models.md +69 -10
  350. package/docs/providers.md +1 -1
  351. package/docs/quickstart.md +11 -7
  352. package/docs/rpc.md +2 -2
  353. package/docs/sdk.md +1 -1
  354. package/docs/settings.md +3 -3
  355. package/docs/subagents.md +36 -5
  356. package/docs/tools.md +1 -1
  357. package/docs/usage.md +4 -2
  358. package/docs/workflows.md +26 -43
  359. package/examples/extensions/preset.ts +2 -2
  360. package/examples/extensions/subagent/README.md +2 -2
  361. package/examples/extensions/subagent/index.ts +1 -2
  362. package/examples/extensions/subagent/schemas.ts +4 -1
  363. package/examples/sdk/12-full-control.ts +1 -1
  364. package/npm-shrinkwrap.json +48 -51
  365. package/package.json +7 -7
  366. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-behavior.ts +0 -75
  367. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-component.ts +0 -202
  368. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-edit.ts +0 -97
  369. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-editor.ts +0 -160
  370. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-frame.ts +0 -72
  371. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-render-modes.ts +0 -161
  372. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-render-selectors.ts +0 -203
  373. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-selectors.ts +0 -234
  374. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-state.ts +0 -103
  375. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-types.ts +0 -29
  376. package/dist/builtin/subagents/src/runs/foreground/chain-clarify.ts +0 -9
  377. package/dist/builtin/subagents/src/runs/foreground/chain-execution-clarify.ts +0 -117
@@ -1,11 +1,16 @@
1
1
  import type { AgentToolUpdateCallback, ExtensionAPI, ExtensionContext, ToolInfo } from "@bastani/atomic";
2
- import type { McpExtensionState } from "./state.ts";
3
- import type { McpConfig } from "./types.ts";
4
- import type { MetadataCache } from "./metadata-cache.ts";
2
+ import type { McpExtensionState } from "./state.js";
3
+ import type { McpConfig } from "./types.js";
4
+ import type { MetadataCache } from "./metadata-cache.js";
5
+ import type { ProxyToolResult } from "./proxy-types.js";
6
+ import { waitForCaller } from "./caller-wait.js";
7
+ import { McpSessionCleanupBarrier } from "./session-cleanup-barrier.js";
8
+ import { McpStateChangedError } from "./state-lease.js";
9
+ import { registerMcpCommands } from "./command-registration.js";
5
10
  import { Type } from "typebox";
6
- import { loadMcpConfig } from "./config.ts";
7
- import { getConfigPathFromArgv } from "./utils.ts";
8
- import { renderMcpToolResult } from "./tool-result-renderer.ts";
11
+ import { loadMcpConfig } from "./config.js";
12
+ import { getConfigPathFromArgv } from "./utils.js";
13
+ import { renderMcpToolResult } from "./tool-result-renderer.js";
9
14
 
10
15
  /**
11
16
  * Marker substring from the host's stale-context error (see ExtensionRunner.invalidate).
@@ -13,16 +18,19 @@ import { renderMcpToolResult } from "./tool-result-renderer.ts";
13
18
  * workflow child stage session, or a reload/replace) without emitting `session_shutdown`.
14
19
  */
15
20
  const STALE_EXTENSION_CONTEXT_MARKER = "extension ctx is stale";
21
+ const STALE_INITIALIZATION_PREFIX = "Stale MCP session initialization cancelled";
22
+
23
+ interface ActiveMcpSession {
24
+ readonly generation: number;
25
+ readonly ctx: ExtensionContext;
26
+ readonly cleanup: Promise<void>;
27
+ }
16
28
 
17
29
  function isStaleExtensionContextError(error: unknown): boolean {
18
30
  return error instanceof Error && error.message.includes(STALE_EXTENSION_CONTEXT_MARKER);
19
31
  }
20
32
 
21
- /**
22
- * Probe whether a captured extension context is still active. Every `ctx` getter runs
23
- * the host's `assertActive()` guard, so a cheap property read surfaces staleness without
24
- * mutating anything. Returns false when the context has been invalidated by a dispose.
25
- */
33
+ /** Probe the host guard to determine whether a captured context remains active. */
26
34
  function isContextActive(ctx: ExtensionContext): boolean {
27
35
  try {
28
36
  void ctx.cwd;
@@ -40,14 +48,17 @@ export default function mcpAdapter(pi: ExtensionAPI) {
40
48
  let registeredDirectToolNames = new Set<string>();
41
49
  let registeredProxyTool = false;
42
50
  let startupWarmupCancel: (() => void) | null = null;
51
+ let activeSession: ActiveMcpSession | null = null;
52
+ let stateOwner: ActiveMcpSession | null = null;
53
+ const cleanupBarrier = new McpSessionCleanupBarrier();
43
54
 
44
55
  async function registerDirectToolsFromConfig(
45
56
  config: McpConfig,
46
57
  cache: MetadataCache | null,
47
58
  ): Promise<{ directToolCount: number; missingConfiguredDirectToolServers: string[] }> {
48
59
  const [{ resolveDirectTools, createDirectToolExecutor, getMissingConfiguredDirectToolServers }, { truncateAtWord }] = await Promise.all([
49
- import("./direct-tools.ts"),
50
- import("./utils.ts"),
60
+ import("./direct-tools.js"),
61
+ import("./utils.js"),
51
62
  ]);
52
63
  const prefix = config.settings?.toolPrefix ?? "server";
53
64
  const envRaw = process.env.MCP_DIRECT_TOOLS;
@@ -69,7 +80,11 @@ export default function mcpAdapter(pi: ExtensionAPI) {
69
80
  description: spec.description || "(no description)",
70
81
  promptSnippet: truncateAtWord(spec.description, 100) || `MCP tool from ${spec.serverName}`,
71
82
  parameters: Type.Unsafe((spec.inputSchema || { type: "object", properties: {} }) as never),
72
- execute: createDirectToolExecutor(() => state, () => initPromise, spec),
83
+ execute: createDirectToolExecutor(
84
+ () => ensureMcpInitialized(),
85
+ (candidate) => isOwnedState(candidate),
86
+ spec,
87
+ ),
73
88
  renderResult: renderMcpToolResult,
74
89
  });
75
90
  }
@@ -82,43 +97,49 @@ export default function mcpAdapter(pi: ExtensionAPI) {
82
97
  }
83
98
 
84
99
  async function registerDirectTools(nextState: McpExtensionState): Promise<{ directToolCount: number; missingConfiguredDirectToolServers: string[] }> {
85
- const { loadMetadataCache } = await import("./metadata-cache.ts");
100
+ const { loadMetadataCache } = await import("./metadata-cache.js");
86
101
  return registerDirectToolsFromConfig(nextState.config, loadMetadataCache());
87
102
  }
88
103
 
89
- async function shutdownOAuthFlow(): Promise<void> {
90
- const { shutdownOAuth } = await import("./mcp-auth-flow.ts");
91
- await shutdownOAuth();
104
+ async function shutdownOAuthFlow(reason: string): Promise<void> {
105
+ const { shutdownOAuth } = await import("./mcp-auth-flow.js");
106
+ await shutdownOAuth(reason);
92
107
  }
93
108
 
94
109
  async function shutdownState(currentState: McpExtensionState | null, reason: string): Promise<void> {
95
110
  if (!currentState) return;
96
-
97
- if (currentState.uiServer) {
98
- currentState.uiServer.close(reason);
99
- currentState.uiServer = null;
111
+ const failures: unknown[] = [];
112
+ const uiServer = currentState.uiServer;
113
+ currentState.uiServer = null;
114
+ try {
115
+ uiServer?.close(reason);
116
+ } catch (error) {
117
+ failures.push(error);
100
118
  }
101
-
102
- let flushError: unknown;
103
119
  try {
104
- const { flushMetadataCache } = await import("./init.ts");
120
+ const { flushMetadataCache } = await import("./init.js");
105
121
  flushMetadataCache(currentState);
106
122
  } catch (error) {
107
- flushError = error;
123
+ failures.push(error);
108
124
  }
109
-
110
125
  try {
111
126
  await currentState.lifecycle.gracefulShutdown();
112
127
  } catch (error) {
113
- if (flushError) {
114
- console.error("MCP: graceful shutdown failed after metadata flush error", error);
115
- } else {
116
- throw error;
117
- }
128
+ failures.push(error);
129
+ }
130
+ for (const error of failures.slice(1)) {
131
+ console.error("MCP: additional state shutdown failure", error);
118
132
  }
133
+ if (failures.length > 0) throw failures[0];
134
+ }
119
135
 
120
- if (flushError) {
121
- throw flushError;
136
+ async function cleanupSessionResources(currentState: McpExtensionState | null, reason: string, label: string): Promise<void> {
137
+ const results = await Promise.allSettled([
138
+ shutdownState(currentState, reason),
139
+ shutdownOAuthFlow(reason),
140
+ ]);
141
+ for (const result of results) {
142
+ if (result.status === "rejected") console.error(label, result.reason);
122
143
  }
123
144
  }
124
145
 
@@ -136,228 +157,193 @@ export default function mcpAdapter(pi: ExtensionAPI) {
136
157
  startupWarmupCancel = null;
137
158
  }
138
159
 
139
- pi.on("session_start", async (_event, ctx) => {
140
- const generation = ++lifecycleGeneration;
141
- const previousState = state;
142
- state = null;
143
- initPromise = null;
144
- registeredDirectToolNames = new Set<string>();
145
- cancelStartupWarmup();
160
+ function isCurrentSession(session: ActiveMcpSession): boolean {
161
+ return activeSession === session
162
+ && lifecycleGeneration === session.generation
163
+ && isContextActive(session.ctx);
164
+ }
146
165
 
147
- try {
148
- const config = loadMcpConfig(earlyConfigPath, ctx.cwd);
149
- const { loadMetadataCache } = await import("./metadata-cache.ts");
150
- const directToolState = await registerDirectToolsFromConfig(config, loadMetadataCache());
151
- if (
152
- config.settings?.disableProxyTool !== true
153
- || directToolState.directToolCount === 0
154
- || directToolState.missingConfiguredDirectToolServers.length > 0
155
- ) {
156
- registerProxyTool();
157
- }
158
- } catch (error) {
159
- if (isStaleExtensionContextError(error)) return;
160
- console.error("MCP: failed to register cached startup tools; enabling MCP proxy fallback", error);
161
- registerProxyTool();
162
- }
166
+ function isOwnedState(candidate: McpExtensionState, owner = stateOwner): boolean {
167
+ return state === candidate && owner !== null && stateOwner === owner && isCurrentSession(owner);
168
+ }
163
169
 
164
- const promiseRef: { current: Promise<McpExtensionState> | null } = { current: null };
165
- const promise = (async () => {
166
- try {
167
- await Promise.all([
168
- shutdownState(previousState, "session_restart"),
169
- shutdownOAuthFlow(),
170
- ]);
171
- } catch (error) {
172
- console.error("MCP: failed to shut down previous session state", error);
173
- }
170
+ function assertOwnedState(candidate: McpExtensionState, owner: ActiveMcpSession): void {
171
+ if (!isOwnedState(candidate, owner)) throw new McpStateChangedError();
172
+ }
174
173
 
175
- if (generation !== lifecycleGeneration || !isContextActive(ctx)) {
176
- throw new Error("Stale MCP session initialization cancelled before startup");
177
- }
174
+ async function initializeSession(
175
+ session: ActiveMcpSession,
176
+ expectedPromise: { current: Promise<McpExtensionState> | null },
177
+ ): Promise<McpExtensionState> {
178
+ await session.cleanup;
179
+ if (!isCurrentSession(session)) {
180
+ throw new Error(`${STALE_INITIALIZATION_PREFIX} before startup`);
181
+ }
178
182
 
179
- const [{ initializeMcp, updateStatusBar }, { scheduleMcpStartupWarmup }] = await Promise.all([
180
- import("./init.ts"),
181
- import("./startup-warmup.ts"),
182
- ]);
183
- if (generation !== lifecycleGeneration || !isContextActive(ctx)) {
184
- throw new Error("Stale MCP session initialization cancelled before startup");
185
- }
183
+ const [{ initializeMcp, updateStatusBar }, { scheduleMcpStartupWarmup }] = await Promise.all([
184
+ import("./init.js"),
185
+ import("./startup-warmup.js"),
186
+ ]);
187
+ if (!isCurrentSession(session)) {
188
+ throw new Error(`${STALE_INITIALIZATION_PREFIX} before startup`);
189
+ }
186
190
 
187
- const nextState = await initializeMcp(pi, ctx);
188
- if (generation !== lifecycleGeneration || initPromise !== promiseRef.current || !isContextActive(ctx)) {
189
- try {
190
- await shutdownState(nextState, "stale_session_start");
191
- } catch (error) {
192
- console.error("MCP: failed to clean stale session state", error);
193
- }
194
- throw new Error("Stale MCP session initialization cancelled after startup");
191
+ let candidate: McpExtensionState | null = null;
192
+ try {
193
+ candidate = await initializeMcp(pi, session.ctx);
194
+ const initializedState = candidate;
195
+ if (!isCurrentSession(session) || initPromise !== expectedPromise.current) {
196
+ throw new Error(`${STALE_INITIALIZATION_PREFIX} after startup`);
195
197
  }
196
198
 
197
- state = nextState;
198
- updateStatusBar(nextState);
199
- const directToolState = await registerDirectTools(nextState);
199
+ const directToolState = await registerDirectTools(initializedState);
200
+ if (!isCurrentSession(session) || initPromise !== expectedPromise.current) {
201
+ throw new Error(`${STALE_INITIALIZATION_PREFIX} after tool registration`);
202
+ }
200
203
  if (
201
- nextState.config.settings?.disableProxyTool !== true
204
+ initializedState.config.settings?.disableProxyTool !== true
202
205
  || directToolState.directToolCount === 0
203
206
  || directToolState.missingConfiguredDirectToolServers.length > 0
204
207
  ) {
205
208
  registerProxyTool();
206
209
  }
210
+
211
+ updateStatusBar(initializedState);
207
212
  let cancelWarmup: (() => void) | null = null;
208
- const warmup = scheduleMcpStartupWarmup(nextState, {
209
- shouldContinue: () => generation === lifecycleGeneration && state === nextState,
213
+ const warmup = scheduleMcpStartupWarmup(initializedState, {
214
+ shouldContinue: () => isCurrentSession(session) && state === initializedState,
210
215
  onDirectToolsChanged: async () => {
211
- if (generation !== lifecycleGeneration || state !== nextState) return;
212
- await registerDirectTools(nextState);
216
+ if (!isCurrentSession(session) || state !== initializedState) return;
217
+ await registerDirectTools(initializedState);
213
218
  },
214
219
  onSettled: () => {
215
- if (generation === lifecycleGeneration && state === nextState && startupWarmupCancel === cancelWarmup) {
220
+ if (isCurrentSession(session) && state === initializedState && startupWarmupCancel === cancelWarmup) {
216
221
  startupWarmupCancel = null;
217
222
  }
218
223
  },
219
224
  });
220
225
  cancelWarmup = () => warmup.cancel();
221
226
  startupWarmupCancel = cancelWarmup;
222
- if (initPromise === promiseRef.current) {
223
- initPromise = null;
224
- }
225
- return nextState;
226
- })();
227
- promiseRef.current = promise;
228
- initPromise = promise;
229
- promise.catch((err) => {
230
- if (generation !== lifecycleGeneration) {
231
- return;
232
- }
233
- if (initPromise !== promise && initPromise !== null) {
234
- return;
227
+ stateOwner = session;
228
+ state = initializedState;
229
+ return initializedState;
230
+ } catch (error) {
231
+ if (candidate && state !== candidate) {
232
+ try {
233
+ await shutdownState(candidate, "failed_initialization");
234
+ } catch (cleanupError) {
235
+ console.error("MCP: failed to clean unpublished initialization state", cleanupError);
236
+ }
235
237
  }
236
- const message = err instanceof Error ? err.message : String(err);
238
+ throw error;
239
+ }
240
+ }
241
+
242
+ function ensureMcpInitialized(): Promise<McpExtensionState> {
243
+ const session = activeSession;
244
+ if (!session || session.generation !== lifecycleGeneration || !isContextActive(session.ctx)) {
245
+ return Promise.reject(new Error("MCP initialization unavailable: no active session"));
246
+ }
247
+ if (state) {
248
+ if (stateOwner === session && isOwnedState(state, session)) return Promise.resolve(state);
249
+ return Promise.reject(new Error("MCP initialization unavailable: stale session state"));
250
+ }
251
+ if (initPromise) return initPromise;
252
+
253
+ const expectedPromise: { current: Promise<McpExtensionState> | null } = { current: null };
254
+ const attempt = initializeSession(session, expectedPromise);
255
+ expectedPromise.current = attempt;
256
+ initPromise = attempt;
257
+ void attempt.then(
258
+ () => {
259
+ if (initPromise === attempt) initPromise = null;
260
+ },
261
+ (error: unknown) => {
262
+ if (activeSession !== session || session.generation !== lifecycleGeneration) return;
263
+ const message = error instanceof Error ? error.message : String(error);
264
+ if (!message.startsWith(STALE_INITIALIZATION_PREFIX) && !isStaleExtensionContextError(error)) {
265
+ console.error(
266
+ `MCP initialization failed for session generation ${session.generation}; a later MCP call will retry:`,
267
+ error,
268
+ );
269
+ }
270
+ if (initPromise === attempt) initPromise = null;
271
+ },
272
+ );
273
+ return attempt;
274
+ }
275
+
276
+ pi.on("session_start", async (_event, ctx) => {
277
+ const generation = ++lifecycleGeneration;
278
+ const previousState = state;
279
+ const retiredInitialization = initPromise;
280
+ state = null;
281
+ stateOwner = null;
282
+ initPromise = null;
283
+ registeredDirectToolNames = new Set<string>();
284
+ cancelStartupWarmup();
285
+ const previousStateCleanup = cleanupSessionResources(
286
+ previousState,
287
+ "session_restart",
288
+ "MCP: failed to shut down previous session state",
289
+ );
290
+ const cleanup = cleanupBarrier.retain([retiredInitialization, previousStateCleanup]);
291
+ const isStartCurrent = (): boolean => generation === lifecycleGeneration && isContextActive(ctx);
292
+ await cleanup;
293
+ if (!isStartCurrent()) return;
294
+
295
+ try {
296
+ const config = loadMcpConfig(earlyConfigPath, ctx.cwd);
297
+ const { loadMetadataCache } = await import("./metadata-cache.js");
298
+ if (!isStartCurrent()) return;
299
+ const directToolState = await registerDirectToolsFromConfig(config, loadMetadataCache());
300
+ if (!isStartCurrent()) return;
237
301
  if (
238
- !message.startsWith("Stale MCP session initialization cancelled") &&
239
- !isStaleExtensionContextError(err)
302
+ config.settings?.disableProxyTool !== true
303
+ || directToolState.directToolCount === 0
304
+ || directToolState.missingConfiguredDirectToolServers.length > 0
240
305
  ) {
241
- console.error("MCP initialization failed:", err);
242
- }
243
- if (initPromise === promise) {
244
- initPromise = null;
306
+ registerProxyTool();
245
307
  }
246
- });
308
+ } catch (error) {
309
+ if (!isStartCurrent() || isStaleExtensionContextError(error)) return;
310
+ console.error("MCP: failed to register cached startup tools; enabling MCP proxy fallback", error);
311
+ registerProxyTool();
312
+ }
313
+
314
+ if (!isStartCurrent()) return;
315
+ activeSession = { generation, ctx, cleanup };
316
+ void ensureMcpInitialized().catch(() => undefined);
247
317
  });
248
318
 
249
319
  pi.on("session_shutdown", async () => {
250
320
  ++lifecycleGeneration;
251
321
  const currentState = state;
322
+ const retiredInitialization = initPromise;
323
+ activeSession = null;
252
324
  state = null;
325
+ stateOwner = null;
253
326
  initPromise = null;
254
327
  registeredDirectToolNames = new Set<string>();
255
328
  cancelStartupWarmup();
256
329
 
257
- try {
258
- await Promise.all([
259
- shutdownState(currentState, "session_shutdown"),
260
- shutdownOAuthFlow(),
261
- ]);
262
- } catch (error) {
263
- console.error("MCP: session shutdown cleanup failed", error);
264
- }
265
- });
266
-
267
- pi.registerCommand("mcp", {
268
- description: "Show MCP server status",
269
- handler: async (args, ctx) => {
270
- if (!state && initPromise) {
271
- try {
272
- state = await initPromise;
273
- } catch (error) {
274
- const message = error instanceof Error ? error.message : String(error);
275
- if (ctx.hasUI) ctx.ui.notify(`MCP initialization failed: ${message}`, "error");
276
- return;
277
- }
278
- }
279
- if (!state) {
280
- if (ctx.hasUI) ctx.ui.notify("MCP not initialized", "error");
281
- return;
282
- }
283
-
284
- const { showStatus, showTools, reconnectServers, logoutServer, openMcpPanel, openMcpSetup } = await import("./commands.ts");
285
- const parts = args?.trim()?.split(/\s+/) ?? [];
286
- const subcommand = parts[0] ?? "";
287
- const targetServer = parts[1];
288
- const rest = parts.slice(1).join(" ");
289
-
290
- switch (subcommand) {
291
- case "reconnect":
292
- await reconnectServers(state, ctx, targetServer);
293
- break;
294
- case "tools":
295
- await showTools(state, ctx);
296
- break;
297
- case "setup": {
298
- const result = await openMcpSetup(state, pi, ctx, earlyConfigPath, "setup");
299
- if (result?.configChanged) {
300
- await ctx.reload();
301
- return;
302
- }
303
- break;
304
- }
305
- case "logout": {
306
- const serverName = rest;
307
- if (!serverName) {
308
- if (ctx.hasUI) ctx.ui.notify("Usage: /mcp logout <server>", "error");
309
- return;
310
- }
311
- await logoutServer(serverName, state, ctx);
312
- break;
313
- }
314
- case "status":
315
- case "":
316
- default:
317
- if (ctx.hasUI) {
318
- const result = await openMcpPanel(state, pi, ctx, earlyConfigPath);
319
- if (result?.configChanged) {
320
- await ctx.reload();
321
- return;
322
- }
323
- } else {
324
- await showStatus(state, ctx);
325
- }
326
- break;
327
- }
328
- },
330
+ const stateCleanup = cleanupSessionResources(
331
+ currentState,
332
+ "session_shutdown",
333
+ "MCP: session shutdown cleanup failed",
334
+ );
335
+ await cleanupBarrier.retain([retiredInitialization, stateCleanup]);
329
336
  });
330
337
 
331
- pi.registerCommand("mcp-auth", {
332
- description: "Authenticate with an MCP server (OAuth)",
333
- handler: async (args, ctx) => {
334
- const serverName = args?.trim();
335
- if (!serverName && !ctx.hasUI) {
336
- return;
337
- }
338
-
339
- if (!state && initPromise) {
340
- try {
341
- state = await initPromise;
342
- } catch (error) {
343
- const message = error instanceof Error ? error.message : String(error);
344
- if (ctx.hasUI) ctx.ui.notify(`MCP initialization failed: ${message}`, "error");
345
- return;
346
- }
347
- }
348
- if (!state) {
349
- if (ctx.hasUI) ctx.ui.notify("MCP not initialized", "error");
350
- return;
351
- }
352
-
353
- const { authenticateServer, openMcpAuthPanel } = await import("./commands.ts");
354
- if (!serverName) {
355
- await openMcpAuthPanel(state, pi, ctx, earlyConfigPath);
356
- return;
357
- }
358
-
359
- await authenticateServer(serverName, state.config, ctx);
360
- },
338
+ registerMcpCommands(pi, earlyConfigPath, async () => {
339
+ const readyState = await ensureMcpInitialized();
340
+ const readyOwner = stateOwner;
341
+ if (!readyOwner) throw new McpStateChangedError();
342
+ assertOwnedState(readyState, readyOwner);
343
+ return {
344
+ state: readyState,
345
+ assertActive: () => assertOwnedState(readyState, readyOwner),
346
+ };
361
347
  });
362
348
 
363
349
  function registerProxyTool(): void {
@@ -390,7 +376,8 @@ export default function mcpAdapter(pi: ExtensionAPI) {
390
376
  includeSchemas?: boolean;
391
377
  server?: string;
392
378
  action?: string;
393
- }, _signal: AbortSignal | undefined, _onUpdate: AgentToolUpdateCallback<Record<string, unknown>> | undefined, _ctx: ExtensionContext) {
379
+ }, signal: AbortSignal | undefined, _onUpdate: AgentToolUpdateCallback<Record<string, unknown>> | undefined, _ctx: ExtensionContext) {
380
+ signal?.throwIfAborted();
394
381
  let parsedArgs: Record<string, unknown> | undefined;
395
382
  if (params.args) {
396
383
  try {
@@ -407,44 +394,65 @@ export default function mcpAdapter(pi: ExtensionAPI) {
407
394
  }
408
395
  }
409
396
 
410
- if (!state && initPromise) {
411
- try {
412
- state = await initPromise;
413
- } catch (error) {
414
- const message = error instanceof Error ? error.message : String(error);
415
- return {
416
- content: [{ type: "text" as const, text: `MCP initialization failed: ${message}` }],
417
- details: { error: "init_failed", message },
418
- };
419
- }
397
+ let readyState: McpExtensionState;
398
+ try {
399
+ readyState = await waitForCaller(ensureMcpInitialized, signal);
400
+ } catch (error) {
401
+ signal?.throwIfAborted();
402
+ const message = error instanceof Error ? error.message : String(error);
403
+ return {
404
+ content: [{ type: "text" as const, text: `MCP initialization failed: ${message}` }],
405
+ details: { error: "init_failed", message },
406
+ };
420
407
  }
421
- if (!state) {
408
+ signal?.throwIfAborted();
409
+ const readyOwner = stateOwner;
410
+ if (!readyOwner || !isOwnedState(readyState, readyOwner)) {
422
411
  return {
423
- content: [{ type: "text" as const, text: "MCP not initialized" }],
424
- details: { error: "not_initialized" },
412
+ content: [{ type: "text" as const, text: "MCP session changed during initialization" }],
413
+ details: { error: "init_cancelled", message: "Session changed before MCP execution" },
425
414
  };
426
415
  }
416
+ const assertActive = (): void => assertOwnedState(readyState, readyOwner);
427
417
 
428
- const { executeCall, executeConnect, executeDescribe, executeList, executeSearch, executeStatus, executeUiMessages } = await import("./proxy-modes.ts");
429
- if (params.action === "ui-messages") {
430
- return executeUiMessages(state);
431
- }
432
- if (params.tool) {
433
- return executeCall(state, params.tool, parsedArgs, params.server, getPiTools);
434
- }
435
- if (params.connect) {
436
- return executeConnect(state, params.connect);
437
- }
438
- if (params.describe) {
439
- return executeDescribe(state, params.describe, params.server);
440
- }
441
- if (params.search) {
442
- return executeSearch(state, params.search, params.regex, params.server, params.includeSchemas);
443
- }
444
- if (params.server) {
445
- return executeList(state, params.server);
418
+ const { executeCall, executeConnect, executeDescribe, executeList, executeSearch, executeStatus, executeUiMessages } = await import("./proxy-modes.js");
419
+ signal?.throwIfAborted();
420
+ try {
421
+ assertActive();
422
+ } catch (error) {
423
+ if (error instanceof McpStateChangedError) {
424
+ return {
425
+ content: [{ type: "text" as const, text: "MCP session changed during execution" }],
426
+ details: { error: "state_changed", message: "Session changed before MCP execution completed" },
427
+ };
428
+ }
429
+ throw error;
446
430
  }
447
- return executeStatus(state);
431
+ const stateChangedResult = (): ProxyToolResult => ({
432
+ content: [{ type: "text" as const, text: "MCP session changed during execution" }],
433
+ details: { error: "state_changed", message: "Session changed before MCP execution completed" },
434
+ });
435
+ const finish = async (start: () => ProxyToolResult | Promise<ProxyToolResult>): Promise<ProxyToolResult> => {
436
+ try {
437
+ signal?.throwIfAborted();
438
+ assertActive();
439
+ const result = await start();
440
+ signal?.throwIfAborted();
441
+ assertActive();
442
+ return result;
443
+ } catch (error) {
444
+ signal?.throwIfAborted();
445
+ if (error instanceof McpStateChangedError) return stateChangedResult();
446
+ throw error;
447
+ }
448
+ };
449
+ if (params.action === "ui-messages") return finish(() => executeUiMessages(readyState, assertActive));
450
+ if (params.tool) return finish(() => executeCall(readyState, params.tool!, parsedArgs, params.server, getPiTools, signal, undefined, assertActive));
451
+ if (params.connect) return finish(() => executeConnect(readyState, params.connect!, signal, undefined, assertActive));
452
+ if (params.describe) return finish(() => executeDescribe(readyState, params.describe!, params.server, signal, assertActive));
453
+ if (params.search) return finish(() => executeSearch(readyState, params.search!, params.regex, params.server, params.includeSchemas, signal, assertActive));
454
+ if (params.server) return finish(() => executeList(readyState, params.server!, signal, assertActive));
455
+ return finish(() => executeStatus(readyState, assertActive));
448
456
  },
449
457
  });
450
458
  }