@akon-labs/nexus-cli 0.1.9 → 0.1.11-rc.2

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 (369) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/LICENSE +1 -0
  3. package/README.md +3 -2
  4. package/dist/app-bridge.bundle.js +67 -0
  5. package/dist/cli/require-login.d.ts.map +1 -1
  6. package/dist/cli/require-login.js +2 -2
  7. package/dist/cli/require-login.js.map +1 -1
  8. package/dist/cli.js +20866 -1882
  9. package/dist/core/agent-session.d.ts +3 -1
  10. package/dist/core/agent-session.d.ts.map +1 -1
  11. package/dist/core/agent-session.js +5 -1
  12. package/dist/core/agent-session.js.map +1 -1
  13. package/dist/core/auto-model.d.ts +1 -1
  14. package/dist/core/auto-model.d.ts.map +1 -1
  15. package/dist/core/auto-model.js +1 -1
  16. package/dist/core/auto-model.js.map +1 -1
  17. package/dist/core/extensions/index.d.ts +1 -1
  18. package/dist/core/extensions/index.d.ts.map +1 -1
  19. package/dist/core/extensions/index.js.map +1 -1
  20. package/dist/core/extensions/loader.d.ts.map +1 -1
  21. package/dist/core/extensions/loader.js +6 -0
  22. package/dist/core/extensions/loader.js.map +1 -1
  23. package/dist/core/extensions/runner.d.ts +7 -1
  24. package/dist/core/extensions/runner.d.ts.map +1 -1
  25. package/dist/core/extensions/runner.js +14 -0
  26. package/dist/core/extensions/runner.js.map +1 -1
  27. package/dist/core/extensions/types.d.ts +18 -0
  28. package/dist/core/extensions/types.d.ts.map +1 -1
  29. package/dist/core/extensions/types.js.map +1 -1
  30. package/dist/core/model-resolver.d.ts +2 -2
  31. package/dist/core/model-resolver.d.ts.map +1 -1
  32. package/dist/core/model-resolver.js +3 -3
  33. package/dist/core/model-resolver.js.map +1 -1
  34. package/dist/core/package-manager.d.ts +15 -0
  35. package/dist/core/package-manager.d.ts.map +1 -1
  36. package/dist/core/package-manager.js +50 -0
  37. package/dist/core/package-manager.js.map +1 -1
  38. package/dist/core/sdk.d.ts.map +1 -1
  39. package/dist/core/sdk.js +1 -1
  40. package/dist/core/sdk.js.map +1 -1
  41. package/dist/core/slash-commands.d.ts.map +1 -1
  42. package/dist/core/slash-commands.js +3 -3
  43. package/dist/core/slash-commands.js.map +1 -1
  44. package/dist/core/system-prompt.d.ts.map +1 -1
  45. package/dist/core/system-prompt.js +1 -1
  46. package/dist/core/system-prompt.js.map +1 -1
  47. package/dist/core/tools/find.d.ts.map +1 -1
  48. package/dist/core/tools/find.js +1 -1
  49. package/dist/core/tools/find.js.map +1 -1
  50. package/dist/core/tools/grep.d.ts.map +1 -1
  51. package/dist/core/tools/grep.js +1 -1
  52. package/dist/core/tools/grep.js.map +1 -1
  53. package/dist/core/tools/index.d.ts +1 -1
  54. package/dist/core/tools/index.d.ts.map +1 -1
  55. package/dist/core/tools/index.js +5 -5
  56. package/dist/core/tools/index.js.map +1 -1
  57. package/dist/core/tools/websearch.d.ts.map +1 -1
  58. package/dist/core/tools/websearch.js +3 -3
  59. package/dist/core/tools/websearch.js.map +1 -1
  60. package/dist/extensions/gitnexus/config.d.ts +15 -1
  61. package/dist/extensions/gitnexus/config.d.ts.map +1 -1
  62. package/dist/extensions/gitnexus/config.js +86 -2
  63. package/dist/extensions/gitnexus/config.js.map +1 -1
  64. package/dist/extensions/gitnexus/gateway.d.ts +6 -6
  65. package/dist/extensions/gitnexus/gateway.d.ts.map +1 -1
  66. package/dist/extensions/gitnexus/gateway.js +4 -4
  67. package/dist/extensions/gitnexus/gateway.js.map +1 -1
  68. package/dist/extensions/gitnexus/index.d.ts.map +1 -1
  69. package/dist/extensions/gitnexus/index.js +6 -4
  70. package/dist/extensions/gitnexus/index.js.map +1 -1
  71. package/dist/extensions/gitnexus/observatory.d.ts.map +1 -1
  72. package/dist/extensions/gitnexus/observatory.js +2 -2
  73. package/dist/extensions/gitnexus/observatory.js.map +1 -1
  74. package/dist/extensions/index.d.ts.map +1 -1
  75. package/dist/extensions/index.js +3 -0
  76. package/dist/extensions/index.js.map +1 -1
  77. package/dist/extensions/mcp/abort.d.ts +3 -0
  78. package/dist/extensions/mcp/abort.d.ts.map +1 -0
  79. package/dist/extensions/mcp/abort.js +41 -0
  80. package/dist/extensions/mcp/abort.js.map +1 -0
  81. package/dist/extensions/mcp/agent-dir.d.ts +6 -0
  82. package/dist/extensions/mcp/agent-dir.d.ts.map +1 -0
  83. package/dist/extensions/mcp/agent-dir.js +18 -0
  84. package/dist/extensions/mcp/agent-dir.js.map +1 -0
  85. package/dist/extensions/mcp/agent-plugin-loader.d.ts +9 -0
  86. package/dist/extensions/mcp/agent-plugin-loader.d.ts.map +1 -0
  87. package/dist/extensions/mcp/agent-plugin-loader.js +384 -0
  88. package/dist/extensions/mcp/agent-plugin-loader.js.map +1 -0
  89. package/dist/extensions/mcp/app-bridge.bundle.js +67 -0
  90. package/dist/extensions/mcp/commands.d.ts +47 -0
  91. package/dist/extensions/mcp/commands.d.ts.map +1 -0
  92. package/dist/extensions/mcp/commands.js +821 -0
  93. package/dist/extensions/mcp/commands.js.map +1 -0
  94. package/dist/extensions/mcp/config.d.ts +123 -38
  95. package/dist/extensions/mcp/config.d.ts.map +1 -1
  96. package/dist/extensions/mcp/config.js +1035 -70
  97. package/dist/extensions/mcp/config.js.map +1 -1
  98. package/dist/extensions/mcp/consent-manager.d.ts +14 -0
  99. package/dist/extensions/mcp/consent-manager.d.ts.map +1 -0
  100. package/dist/extensions/mcp/consent-manager.js +60 -0
  101. package/dist/extensions/mcp/consent-manager.js.map +1 -0
  102. package/dist/extensions/mcp/direct-tools.d.ts +11 -0
  103. package/dist/extensions/mcp/direct-tools.d.ts.map +1 -0
  104. package/dist/extensions/mcp/direct-tools.js +562 -0
  105. package/dist/extensions/mcp/direct-tools.js.map +1 -0
  106. package/dist/extensions/mcp/elicitation-handler.d.ts +18 -0
  107. package/dist/extensions/mcp/elicitation-handler.d.ts.map +1 -0
  108. package/dist/extensions/mcp/elicitation-handler.js +320 -0
  109. package/dist/extensions/mcp/elicitation-handler.js.map +1 -0
  110. package/dist/extensions/mcp/error-signal.d.ts +16 -0
  111. package/dist/extensions/mcp/error-signal.d.ts.map +1 -0
  112. package/dist/extensions/mcp/error-signal.js +22 -0
  113. package/dist/extensions/mcp/error-signal.js.map +1 -0
  114. package/dist/extensions/mcp/errors.d.ts +104 -0
  115. package/dist/extensions/mcp/errors.d.ts.map +1 -0
  116. package/dist/extensions/mcp/errors.js +171 -0
  117. package/dist/extensions/mcp/errors.js.map +1 -0
  118. package/dist/extensions/mcp/glimpse-ui.d.ts +10 -0
  119. package/dist/extensions/mcp/glimpse-ui.d.ts.map +1 -0
  120. package/dist/extensions/mcp/glimpse-ui.js +67 -0
  121. package/dist/extensions/mcp/glimpse-ui.js.map +1 -0
  122. package/dist/extensions/mcp/host-html-template.d.ts +17 -0
  123. package/dist/extensions/mcp/host-html-template.d.ts.map +1 -0
  124. package/dist/extensions/mcp/host-html-template.js +442 -0
  125. package/dist/extensions/mcp/host-html-template.js.map +1 -0
  126. package/dist/extensions/mcp/index.d.ts +20 -15
  127. package/dist/extensions/mcp/index.d.ts.map +1 -1
  128. package/dist/extensions/mcp/index.js +1113 -82
  129. package/dist/extensions/mcp/index.js.map +1 -1
  130. package/dist/extensions/mcp/init.d.ts +28 -0
  131. package/dist/extensions/mcp/init.d.ts.map +1 -0
  132. package/dist/extensions/mcp/init.js +631 -0
  133. package/dist/extensions/mcp/init.js.map +1 -0
  134. package/dist/extensions/mcp/json-schema-validator.d.ts +3 -0
  135. package/dist/extensions/mcp/json-schema-validator.d.ts.map +1 -0
  136. package/dist/extensions/mcp/json-schema-validator.js +53 -0
  137. package/dist/extensions/mcp/json-schema-validator.js.map +1 -0
  138. package/dist/extensions/mcp/lifecycle.d.ts +56 -0
  139. package/dist/extensions/mcp/lifecycle.d.ts.map +1 -0
  140. package/dist/extensions/mcp/lifecycle.js +395 -0
  141. package/dist/extensions/mcp/lifecycle.js.map +1 -0
  142. package/dist/extensions/mcp/logger.d.ts +52 -0
  143. package/dist/extensions/mcp/logger.d.ts.map +1 -0
  144. package/dist/extensions/mcp/logger.js +134 -0
  145. package/dist/extensions/mcp/logger.js.map +1 -0
  146. package/dist/extensions/mcp/mcp-auth-flow.d.ts +117 -0
  147. package/dist/extensions/mcp/mcp-auth-flow.d.ts.map +1 -0
  148. package/dist/extensions/mcp/mcp-auth-flow.js +869 -0
  149. package/dist/extensions/mcp/mcp-auth-flow.js.map +1 -0
  150. package/dist/extensions/mcp/mcp-auth.d.ts +162 -0
  151. package/dist/extensions/mcp/mcp-auth.d.ts.map +1 -0
  152. package/dist/extensions/mcp/mcp-auth.js +897 -0
  153. package/dist/extensions/mcp/mcp-auth.js.map +1 -0
  154. package/dist/extensions/mcp/mcp-bearer-store.d.ts +25 -0
  155. package/dist/extensions/mcp/mcp-bearer-store.d.ts.map +1 -0
  156. package/dist/extensions/mcp/mcp-bearer-store.js +350 -0
  157. package/dist/extensions/mcp/mcp-bearer-store.js.map +1 -0
  158. package/dist/extensions/mcp/mcp-callback-server.d.ts +54 -0
  159. package/dist/extensions/mcp/mcp-callback-server.d.ts.map +1 -0
  160. package/dist/extensions/mcp/mcp-callback-server.js +454 -0
  161. package/dist/extensions/mcp/mcp-callback-server.js.map +1 -0
  162. package/dist/extensions/mcp/mcp-code.d.ts +48 -0
  163. package/dist/extensions/mcp/mcp-code.d.ts.map +1 -0
  164. package/dist/extensions/mcp/mcp-code.js +358 -0
  165. package/dist/extensions/mcp/mcp-code.js.map +1 -0
  166. package/dist/extensions/mcp/mcp-keyring-helper.cjs +89 -0
  167. package/dist/extensions/mcp/mcp-oauth-provider.d.ts +135 -0
  168. package/dist/extensions/mcp/mcp-oauth-provider.d.ts.map +1 -0
  169. package/dist/extensions/mcp/mcp-oauth-provider.js +491 -0
  170. package/dist/extensions/mcp/mcp-oauth-provider.js.map +1 -0
  171. package/dist/extensions/mcp/mcp-output-guard.d.ts +59 -0
  172. package/dist/extensions/mcp/mcp-output-guard.d.ts.map +1 -0
  173. package/dist/extensions/mcp/mcp-output-guard.js +343 -0
  174. package/dist/extensions/mcp/mcp-output-guard.js.map +1 -0
  175. package/dist/extensions/mcp/mcp-panel.d.ts +71 -0
  176. package/dist/extensions/mcp/mcp-panel.d.ts.map +1 -0
  177. package/dist/extensions/mcp/mcp-panel.js +973 -0
  178. package/dist/extensions/mcp/mcp-panel.js.map +1 -0
  179. package/dist/extensions/mcp/mcp-probe.d.ts +7 -0
  180. package/dist/extensions/mcp/mcp-probe.d.ts.map +1 -0
  181. package/dist/extensions/mcp/mcp-probe.js +155 -0
  182. package/dist/extensions/mcp/mcp-probe.js.map +1 -0
  183. package/dist/extensions/mcp/mcp-script-worker.mjs +130 -0
  184. package/dist/extensions/mcp/mcp-setup-panel.d.ts +146 -0
  185. package/dist/extensions/mcp/mcp-setup-panel.d.ts.map +1 -0
  186. package/dist/extensions/mcp/mcp-setup-panel.js +1104 -0
  187. package/dist/extensions/mcp/mcp-setup-panel.js.map +1 -0
  188. package/dist/extensions/mcp/mcp-status.d.ts +12 -0
  189. package/dist/extensions/mcp/mcp-status.d.ts.map +1 -0
  190. package/dist/extensions/mcp/mcp-status.js +98 -0
  191. package/dist/extensions/mcp/mcp-status.js.map +1 -0
  192. package/dist/extensions/mcp/mcp-trace.d.ts +95 -0
  193. package/dist/extensions/mcp/mcp-trace.d.ts.map +1 -0
  194. package/dist/extensions/mcp/mcp-trace.js +252 -0
  195. package/dist/extensions/mcp/mcp-trace.js.map +1 -0
  196. package/dist/extensions/mcp/metadata-cache.d.ts +20 -0
  197. package/dist/extensions/mcp/metadata-cache.d.ts.map +1 -0
  198. package/dist/extensions/mcp/metadata-cache.js +318 -0
  199. package/dist/extensions/mcp/metadata-cache.js.map +1 -0
  200. package/dist/extensions/mcp/npx-resolver.d.ts +7 -0
  201. package/dist/extensions/mcp/npx-resolver.d.ts.map +1 -0
  202. package/dist/extensions/mcp/npx-resolver.js +505 -0
  203. package/dist/extensions/mcp/npx-resolver.js.map +1 -0
  204. package/dist/extensions/mcp/oauth.d.ts +21 -0
  205. package/dist/extensions/mcp/oauth.d.ts.map +1 -0
  206. package/dist/extensions/mcp/oauth.js +15 -0
  207. package/dist/extensions/mcp/oauth.js.map +1 -0
  208. package/dist/extensions/mcp/onboarding-state.d.ts +13 -0
  209. package/dist/extensions/mcp/onboarding-state.d.ts.map +1 -0
  210. package/dist/extensions/mcp/onboarding-state.js +65 -0
  211. package/dist/extensions/mcp/onboarding-state.js.map +1 -0
  212. package/dist/extensions/mcp/package-mcp-loader.d.ts +3 -0
  213. package/dist/extensions/mcp/package-mcp-loader.d.ts.map +1 -0
  214. package/dist/extensions/mcp/package-mcp-loader.js +170 -0
  215. package/dist/extensions/mcp/package-mcp-loader.js.map +1 -0
  216. package/dist/extensions/mcp/panel-keys.d.ts +21 -0
  217. package/dist/extensions/mcp/panel-keys.d.ts.map +1 -0
  218. package/dist/extensions/mcp/panel-keys.js +29 -0
  219. package/dist/extensions/mcp/panel-keys.js.map +1 -0
  220. package/dist/extensions/mcp/prompts.d.ts +63 -0
  221. package/dist/extensions/mcp/prompts.d.ts.map +1 -0
  222. package/dist/extensions/mcp/prompts.js +297 -0
  223. package/dist/extensions/mcp/prompts.js.map +1 -0
  224. package/dist/extensions/mcp/proxy-modes.d.ts +15 -0
  225. package/dist/extensions/mcp/proxy-modes.d.ts.map +1 -0
  226. package/dist/extensions/mcp/proxy-modes.js +1421 -0
  227. package/dist/extensions/mcp/proxy-modes.js.map +1 -0
  228. package/dist/extensions/mcp/request-headers-command.d.ts +11 -0
  229. package/dist/extensions/mcp/request-headers-command.d.ts.map +1 -0
  230. package/dist/extensions/mcp/request-headers-command.js +334 -0
  231. package/dist/extensions/mcp/request-headers-command.js.map +1 -0
  232. package/dist/extensions/mcp/resource-tools.d.ts +2 -0
  233. package/dist/extensions/mcp/resource-tools.d.ts.map +1 -0
  234. package/dist/extensions/mcp/resource-tools.js +15 -0
  235. package/dist/extensions/mcp/resource-tools.js.map +1 -0
  236. package/dist/extensions/mcp/runtime-owner.d.ts +14 -0
  237. package/dist/extensions/mcp/runtime-owner.d.ts.map +1 -0
  238. package/dist/extensions/mcp/runtime-owner.js +84 -0
  239. package/dist/extensions/mcp/runtime-owner.js.map +1 -0
  240. package/dist/extensions/mcp/sampling-handler.d.ts +18 -0
  241. package/dist/extensions/mcp/sampling-handler.d.ts.map +1 -0
  242. package/dist/extensions/mcp/sampling-handler.js +229 -0
  243. package/dist/extensions/mcp/sampling-handler.js.map +1 -0
  244. package/dist/extensions/mcp/search-ranking.d.ts +25 -0
  245. package/dist/extensions/mcp/search-ranking.d.ts.map +1 -0
  246. package/dist/extensions/mcp/search-ranking.js +234 -0
  247. package/dist/extensions/mcp/search-ranking.js.map +1 -0
  248. package/dist/extensions/mcp/server-manager.d.ts +116 -0
  249. package/dist/extensions/mcp/server-manager.d.ts.map +1 -0
  250. package/dist/extensions/mcp/server-manager.js +1052 -0
  251. package/dist/extensions/mcp/server-manager.js.map +1 -0
  252. package/dist/extensions/mcp/session-recovery.d.ts +27 -0
  253. package/dist/extensions/mcp/session-recovery.d.ts.map +1 -0
  254. package/dist/extensions/mcp/session-recovery.js +140 -0
  255. package/dist/extensions/mcp/session-recovery.js.map +1 -0
  256. package/dist/extensions/mcp/skills/mcp-scripting/SKILL.md +38 -0
  257. package/dist/extensions/mcp/state.d.ts +62 -0
  258. package/dist/extensions/mcp/state.d.ts.map +1 -0
  259. package/dist/extensions/mcp/state.js +2 -0
  260. package/dist/extensions/mcp/state.js.map +1 -0
  261. package/dist/extensions/mcp/tool-approval.d.ts +11 -0
  262. package/dist/extensions/mcp/tool-approval.d.ts.map +1 -0
  263. package/dist/extensions/mcp/tool-approval.js +156 -0
  264. package/dist/extensions/mcp/tool-approval.js.map +1 -0
  265. package/dist/extensions/mcp/tool-metadata.d.ts +11 -0
  266. package/dist/extensions/mcp/tool-metadata.d.ts.map +1 -0
  267. package/dist/extensions/mcp/tool-metadata.js +264 -0
  268. package/dist/extensions/mcp/tool-metadata.js.map +1 -0
  269. package/dist/extensions/mcp/tool-registrar.d.ts +21 -0
  270. package/dist/extensions/mcp/tool-registrar.d.ts.map +1 -0
  271. package/dist/extensions/mcp/tool-registrar.js +229 -0
  272. package/dist/extensions/mcp/tool-registrar.js.map +1 -0
  273. package/dist/extensions/mcp/tool-result-renderer.d.ts +83 -0
  274. package/dist/extensions/mcp/tool-result-renderer.d.ts.map +1 -0
  275. package/dist/extensions/mcp/tool-result-renderer.js +345 -0
  276. package/dist/extensions/mcp/tool-result-renderer.js.map +1 -0
  277. package/dist/extensions/mcp/ts-shape.d.ts +3 -0
  278. package/dist/extensions/mcp/ts-shape.d.ts.map +1 -0
  279. package/dist/extensions/mcp/ts-shape.js +160 -0
  280. package/dist/extensions/mcp/ts-shape.js.map +1 -0
  281. package/dist/extensions/mcp/types.d.ts +521 -0
  282. package/dist/extensions/mcp/types.d.ts.map +1 -0
  283. package/dist/extensions/mcp/types.js +294 -0
  284. package/dist/extensions/mcp/types.js.map +1 -0
  285. package/dist/extensions/mcp/ui-app-bridge-helpers.d.ts +7 -0
  286. package/dist/extensions/mcp/ui-app-bridge-helpers.d.ts.map +1 -0
  287. package/dist/extensions/mcp/ui-app-bridge-helpers.js +37 -0
  288. package/dist/extensions/mcp/ui-app-bridge-helpers.js.map +1 -0
  289. package/dist/extensions/mcp/ui-resource-handler.d.ts +18 -0
  290. package/dist/extensions/mcp/ui-resource-handler.d.ts.map +1 -0
  291. package/dist/extensions/mcp/ui-resource-handler.js +210 -0
  292. package/dist/extensions/mcp/ui-resource-handler.js.map +1 -0
  293. package/dist/extensions/mcp/ui-server.d.ts +52 -0
  294. package/dist/extensions/mcp/ui-server.d.ts.map +1 -0
  295. package/dist/extensions/mcp/ui-server.js +740 -0
  296. package/dist/extensions/mcp/ui-server.js.map +1 -0
  297. package/dist/extensions/mcp/ui-session.d.ts +40 -0
  298. package/dist/extensions/mcp/ui-session.d.ts.map +1 -0
  299. package/dist/extensions/mcp/ui-session.js +477 -0
  300. package/dist/extensions/mcp/ui-session.js.map +1 -0
  301. package/dist/extensions/mcp/ui-stream-types.d.ts +105 -0
  302. package/dist/extensions/mcp/ui-stream-types.d.ts.map +1 -0
  303. package/dist/extensions/mcp/ui-stream-types.js +61 -0
  304. package/dist/extensions/mcp/ui-stream-types.js.map +1 -0
  305. package/dist/extensions/mcp/ui-tool-visibility.d.ts +5 -0
  306. package/dist/extensions/mcp/ui-tool-visibility.d.ts.map +1 -0
  307. package/dist/extensions/mcp/ui-tool-visibility.js +27 -0
  308. package/dist/extensions/mcp/ui-tool-visibility.js.map +1 -0
  309. package/dist/extensions/mcp/unix-socket-transport.d.ts +15 -0
  310. package/dist/extensions/mcp/unix-socket-transport.d.ts.map +1 -0
  311. package/dist/extensions/mcp/unix-socket-transport.js +85 -0
  312. package/dist/extensions/mcp/unix-socket-transport.js.map +1 -0
  313. package/dist/extensions/mcp/utils.d.ts +32 -0
  314. package/dist/extensions/mcp/utils.d.ts.map +1 -0
  315. package/dist/extensions/mcp/utils.js +336 -0
  316. package/dist/extensions/mcp/utils.js.map +1 -0
  317. package/dist/extensions/subagent/index.d.ts +62 -1
  318. package/dist/extensions/subagent/index.d.ts.map +1 -1
  319. package/dist/extensions/subagent/index.js +195 -9
  320. package/dist/extensions/subagent/index.js.map +1 -1
  321. package/dist/extensions/subagent-render.d.ts +3 -0
  322. package/dist/extensions/subagent-render.d.ts.map +1 -0
  323. package/dist/extensions/subagent-render.js +39 -0
  324. package/dist/extensions/subagent-render.js.map +1 -0
  325. package/dist/extensions/web-access.d.ts.map +1 -1
  326. package/dist/extensions/web-access.js +1 -1
  327. package/dist/extensions/web-access.js.map +1 -1
  328. package/dist/index.d.ts +2 -0
  329. package/dist/index.d.ts.map +1 -1
  330. package/dist/index.js +20992 -2003
  331. package/dist/index.js.map +1 -1
  332. package/dist/mcp-keyring-helper.cjs +89 -0
  333. package/dist/mcp-script-worker.mjs +130 -0
  334. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  335. package/dist/modes/interactive/components/model-selector.js +1 -1
  336. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  337. package/dist/modes/interactive/components/response-separator.d.ts +1 -1
  338. package/dist/modes/interactive/components/response-separator.d.ts.map +1 -1
  339. package/dist/modes/interactive/components/response-separator.js +1 -1
  340. package/dist/modes/interactive/components/response-separator.js.map +1 -1
  341. package/dist/modes/interactive/components/tool-execution.d.ts +3 -2
  342. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  343. package/dist/modes/interactive/components/tool-execution.js +12 -2
  344. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  345. package/dist/modes/interactive/interactive-mode.d.ts +2 -0
  346. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  347. package/dist/modes/interactive/interactive-mode.js +14 -8
  348. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  349. package/dist/rpc-entry.js +20866 -1882
  350. package/dist/skills/mcp-scripting/SKILL.md +38 -0
  351. package/dist/utils/hidden-spawn.d.ts +29 -0
  352. package/dist/utils/hidden-spawn.d.ts.map +1 -0
  353. package/dist/utils/hidden-spawn.js +101 -0
  354. package/dist/utils/hidden-spawn.js.map +1 -0
  355. package/dist/vendor/ai.js +110 -35
  356. package/docs/mcp.md +178 -0
  357. package/docs/pi-subagents.md +75 -0
  358. package/docs/quickstart.md +1 -1
  359. package/docs/usage.md +2 -1
  360. package/examples/extensions/pi-subagents-worker-policy.ts +86 -0
  361. package/native/win32/build.mjs +95 -0
  362. package/native/win32/prebuilds/win32-x64/hidden-spawn.exe +0 -0
  363. package/native/win32/src/hidden-spawn.c +157 -0
  364. package/npm-shrinkwrap.json +728 -6
  365. package/package.json +21 -6
  366. package/dist/extensions/mcp/client.d.ts +0 -86
  367. package/dist/extensions/mcp/client.d.ts.map +0 -1
  368. package/dist/extensions/mcp/client.js +0 -275
  369. package/dist/extensions/mcp/client.js.map +0 -1
@@ -0,0 +1,740 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import fs from "node:fs/promises";
3
+ import http from "node:http";
4
+ import path from "node:path";
5
+ import { ContentBlockSchema } from "@modelcontextprotocol/core";
6
+ import { ServerError, wrapError } from "./errors.js";
7
+ import { buildCspMetaContent, buildHostHtmlTemplate } from "./host-html-template.js";
8
+ import { logger } from "./logger.js";
9
+ import { resourceNameToToolName } from "./resource-tools.js";
10
+ import { SessionRecoveryAuthRequiredError, withSessionRecovery } from "./session-recovery.js";
11
+ import { ensureToolCallApproved, isToolCallApprovalRequired } from "./tool-approval.js";
12
+ import { createUiModelContextUpdate, extractUiPromptText, getVisualizationStreamEnvelope, isServerDisabled, } from "./types.js";
13
+ import { buildAllowAttribute } from "./ui-app-bridge-helpers.js";
14
+ import { extractUiToolVisibility, isUiToolCallableByApp, isUiToolVisibleToModel } from "./ui-tool-visibility.js";
15
+ import { formatAuthRequiredMessage, normalizeToolArguments } from "./utils.js";
16
+ const MAX_BODY_SIZE = 2 * 1024 * 1024;
17
+ const ABANDONED_GRACE_MS = 60_000;
18
+ const WATCHDOG_INTERVAL_MS = 5_000;
19
+ const MAX_EVENT_LOG = 128;
20
+ const MAX_CONTEXT_UPDATES = 20;
21
+ const MOSHI_DISCOVERY_PORT_START = 8377;
22
+ const MOSHI_DISCOVERY_PORT_END = 8396;
23
+ let nextMoshiDiscoveryPort = MOSHI_DISCOVERY_PORT_START;
24
+ export async function startUiServer(options) {
25
+ const sessionToken = options.sessionToken ?? randomUUID();
26
+ const uiResourceToken = randomUUID();
27
+ const log = logger.child({
28
+ component: "UiServer",
29
+ server: options.serverName,
30
+ tool: options.toolName,
31
+ session: sessionToken.slice(0, 8),
32
+ });
33
+ log.debug("Starting UI server");
34
+ const sseClients = new Set();
35
+ let completed = false;
36
+ let lastHeartbeatAt = Date.now();
37
+ let watchdog = null;
38
+ let currentDisplayMode = options.hostContext?.displayMode ?? "inline";
39
+ let nextEventId = 1;
40
+ const eventLog = [];
41
+ let latestCheckpointEventId;
42
+ let streamSummary;
43
+ // Track messages from UI for retrieval
44
+ const sessionMessages = {
45
+ prompts: [],
46
+ notifications: [],
47
+ intents: [],
48
+ contexts: [],
49
+ };
50
+ const hostContext = {
51
+ displayMode: currentDisplayMode,
52
+ availableDisplayModes: ["inline", "fullscreen", "pip"],
53
+ platform: "desktop",
54
+ ...options.hostContext,
55
+ // Only include toolInfo if caller provides full tool definition with inputSchema
56
+ // The App validates toolInfo.tool.inputSchema as required object
57
+ };
58
+ const initialStreamContext = hostContext["nexus-mcp/stream"];
59
+ if (initialStreamContext && typeof initialStreamContext === "object") {
60
+ const streamId = initialStreamContext.streamId;
61
+ const mode = initialStreamContext.mode;
62
+ if (typeof streamId === "string" && (mode === "eager" || mode === "stream-first")) {
63
+ streamSummary = {
64
+ streamId,
65
+ mode,
66
+ frames: 0,
67
+ phases: [],
68
+ };
69
+ }
70
+ }
71
+ const isAppOnlyTool = (toolName) => {
72
+ const toolDefinition = options.manager
73
+ .getConnection(options.serverName)
74
+ ?.tools?.find((tool) => tool.name === toolName);
75
+ if (!toolDefinition)
76
+ return false;
77
+ const visibility = extractUiToolVisibility(toolDefinition._meta);
78
+ return isUiToolCallableByApp(visibility) && !isUiToolVisibleToModel(visibility);
79
+ };
80
+ const recordUiMessage = async (msgParams) => {
81
+ const promptText = extractUiPromptText(msgParams);
82
+ // Track messages by type (order: prompt → intent → notify)
83
+ // Must match the order in index.ts onMessage handler
84
+ if (promptText) {
85
+ sessionMessages.prompts.push(promptText);
86
+ log.debug("UI prompt received", { prompt: promptText.slice(0, 100) });
87
+ }
88
+ else if (msgParams.type === "intent" || msgParams.intent) {
89
+ const intentName = msgParams.intent ?? "";
90
+ if (intentName) {
91
+ sessionMessages.intents.push({
92
+ intent: intentName,
93
+ ...(msgParams.params !== undefined ? { params: msgParams.params } : {}),
94
+ });
95
+ log.debug("UI intent received", { intent: intentName });
96
+ }
97
+ }
98
+ else if (msgParams.type === "notify" || msgParams.message) {
99
+ const notifyText = msgParams.message ?? "";
100
+ if (notifyText) {
101
+ sessionMessages.notifications.push(notifyText);
102
+ log.debug("UI notification", { message: notifyText.slice(0, 100) });
103
+ }
104
+ }
105
+ await options.onMessage?.(msgParams);
106
+ };
107
+ const touchHeartbeat = () => {
108
+ lastHeartbeatAt = Date.now();
109
+ };
110
+ const updateStreamSummary = (eventId, payload) => {
111
+ const envelope = getVisualizationStreamEnvelope(payload?.structuredContent);
112
+ if (!envelope)
113
+ return;
114
+ if (envelope.frameType === "checkpoint" || envelope.frameType === "final") {
115
+ latestCheckpointEventId = eventId;
116
+ }
117
+ if (!streamSummary) {
118
+ streamSummary = {
119
+ streamId: envelope.streamId,
120
+ mode: "eager",
121
+ frames: 0,
122
+ phases: [],
123
+ };
124
+ }
125
+ streamSummary.frames += 1;
126
+ if (!streamSummary.phases.includes(envelope.phase)) {
127
+ streamSummary.phases.push(envelope.phase);
128
+ }
129
+ streamSummary.finalStatus = envelope.status;
130
+ if (envelope.message !== undefined)
131
+ streamSummary.lastMessage = envelope.message;
132
+ else
133
+ delete streamSummary.lastMessage;
134
+ };
135
+ const serializeEvent = (eventId, name, payload) => {
136
+ return `id: ${eventId}\nevent: ${name}\ndata: ${JSON.stringify(payload)}\n\n`;
137
+ };
138
+ const getLatestCheckpointIndex = () => {
139
+ const firstEventId = eventLog[0]?.id;
140
+ if (latestCheckpointEventId === undefined || firstEventId === undefined || latestCheckpointEventId < firstEventId)
141
+ return -1;
142
+ return latestCheckpointEventId - firstEventId;
143
+ };
144
+ const pruneEventLog = () => {
145
+ if (eventLog.length <= MAX_EVENT_LOG)
146
+ return;
147
+ const latestCheckpointIndex = getLatestCheckpointIndex();
148
+ if (latestCheckpointIndex > 0) {
149
+ eventLog.splice(0, latestCheckpointIndex);
150
+ }
151
+ if (eventLog.length > MAX_EVENT_LOG) {
152
+ eventLog.splice(0, eventLog.length - MAX_EVENT_LOG);
153
+ }
154
+ };
155
+ const pushEvent = (name, payload) => {
156
+ if (completed)
157
+ return;
158
+ const eventId = nextEventId++;
159
+ eventLog.push({ id: eventId, name, payload });
160
+ updateStreamSummary(eventId, payload);
161
+ pruneEventLog();
162
+ const chunk = serializeEvent(eventId, name, payload);
163
+ for (const client of sseClients) {
164
+ try {
165
+ client.write(chunk);
166
+ }
167
+ catch {
168
+ sseClients.delete(client);
169
+ }
170
+ }
171
+ };
172
+ const replayEvents = (res, lastEventIdHeader) => {
173
+ const parsedLastId = lastEventIdHeader ? Number(lastEventIdHeader) : Number.NaN;
174
+ const eventsToReplay = Number.isFinite(parsedLastId)
175
+ ? eventLog.filter((entry) => entry.id > parsedLastId)
176
+ : (() => {
177
+ const latestCheckpointIndex = getLatestCheckpointIndex();
178
+ return latestCheckpointIndex >= 0 ? eventLog.slice(latestCheckpointIndex) : eventLog;
179
+ })();
180
+ for (const entry of eventsToReplay) {
181
+ try {
182
+ res.write(serializeEvent(entry.id, entry.name, entry.payload));
183
+ }
184
+ catch {
185
+ sseClients.delete(res);
186
+ return;
187
+ }
188
+ }
189
+ };
190
+ const closeSse = () => {
191
+ for (const client of sseClients) {
192
+ try {
193
+ client.end();
194
+ }
195
+ catch { }
196
+ }
197
+ sseClients.clear();
198
+ };
199
+ const stopWatchdog = () => {
200
+ if (!watchdog)
201
+ return;
202
+ clearInterval(watchdog);
203
+ watchdog = null;
204
+ };
205
+ const markCompleted = (reason) => {
206
+ if (completed)
207
+ return;
208
+ log.debug("Session completed", { reason });
209
+ pushEvent("session-complete", { reason });
210
+ completed = true;
211
+ stopWatchdog();
212
+ options.onComplete?.(reason);
213
+ };
214
+ const server = http.createServer(async (req, res) => {
215
+ try {
216
+ const method = req.method || "GET";
217
+ const hostHeader = req.headers.host;
218
+ const url = new URL(req.url || "/", `http://${hostHeader || "127.0.0.1"}`);
219
+ if (hostHeader !== undefined && !isAllowedHost(url.hostname)) {
220
+ sendText(res, 403, "Invalid host");
221
+ return;
222
+ }
223
+ if (method === "HEAD" && url.pathname === "/") {
224
+ res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
225
+ res.end();
226
+ return;
227
+ }
228
+ if (method === "GET" && url.pathname === "/") {
229
+ if (!url.searchParams.has("session")) {
230
+ res.writeHead(200, { "Content-Type": "text/html; charset=utf-8", "Cache-Control": "no-store" });
231
+ res.end('<!doctype html><html><head><meta charset="utf-8"><title>MCP UI</title></head>' +
232
+ "<body><p>Open the authenticated MCP UI URL shown by Nexus.</p></body></html>");
233
+ return;
234
+ }
235
+ if (!validateTokenQuery(url, sessionToken, res))
236
+ return;
237
+ touchHeartbeat();
238
+ const html = buildHostHtmlTemplate({
239
+ sessionToken,
240
+ uiResourceToken,
241
+ serverName: options.serverName,
242
+ toolName: options.toolName,
243
+ toolArgs: options.toolArgs,
244
+ resource: options.resource,
245
+ allowAttribute: buildAllowAttribute(options.resource.meta.permissions),
246
+ requireToolConsent: options.consentManager.requiresPrompt(options.serverName),
247
+ cacheToolConsent: options.consentManager.shouldCacheConsent(),
248
+ hostContext,
249
+ });
250
+ res.writeHead(200, {
251
+ "Content-Type": "text/html; charset=utf-8",
252
+ "Cache-Control": "no-store",
253
+ });
254
+ res.end(html);
255
+ return;
256
+ }
257
+ if (method === "GET" && url.pathname === "/events") {
258
+ if (!validateTokenQuery(url, sessionToken, res))
259
+ return;
260
+ touchHeartbeat();
261
+ log.debug("SSE client connected", { clientCount: sseClients.size + 1 });
262
+ res.writeHead(200, {
263
+ "Content-Type": "text/event-stream",
264
+ "Cache-Control": "no-cache, no-transform",
265
+ Connection: "keep-alive",
266
+ "X-Accel-Buffering": "no",
267
+ });
268
+ res.write(": connected\n\n");
269
+ sseClients.add(res);
270
+ replayEvents(res, req.headers["last-event-id"] ? String(req.headers["last-event-id"]) : null);
271
+ req.on("close", () => {
272
+ sseClients.delete(res);
273
+ });
274
+ return;
275
+ }
276
+ if (method === "GET" && url.pathname === "/health") {
277
+ if (!validateTokenQuery(url, sessionToken, res))
278
+ return;
279
+ sendJson(res, 200, { ok: true, result: { healthy: true } });
280
+ return;
281
+ }
282
+ if (method === "GET" && url.pathname === "/ui-app") {
283
+ if (!validateTokenQuery(url, uiResourceToken, res, "resource"))
284
+ return;
285
+ touchHeartbeat();
286
+ // Enforce host metadata independently of where app HTML places its document head.
287
+ const cspContent = buildCspMetaContent(options.resource.meta.csp);
288
+ res.writeHead(200, {
289
+ "Content-Type": "text/html; charset=utf-8",
290
+ "Cache-Control": "no-store",
291
+ "Content-Security-Policy": cspContent,
292
+ });
293
+ res.end(options.resource.html);
294
+ return;
295
+ }
296
+ if (method === "GET" && url.pathname === "/app-bridge.bundle.js") {
297
+ // Serve the pre-bundled AppBridge module
298
+ const bundlePath = path.join(import.meta.dirname, "app-bridge.bundle.js");
299
+ try {
300
+ const content = await fs.readFile(bundlePath, "utf-8");
301
+ res.writeHead(200, {
302
+ "Content-Type": "application/javascript",
303
+ "Cache-Control": "public, max-age=31536000",
304
+ });
305
+ res.end(content);
306
+ }
307
+ catch {
308
+ sendJson(res, 500, { ok: false, error: "Bundle not found" });
309
+ }
310
+ return;
311
+ }
312
+ if (method !== "POST") {
313
+ sendJson(res, 404, { ok: false, error: "Not found" });
314
+ return;
315
+ }
316
+ const body = await parseBody(req, res);
317
+ if (!body)
318
+ return;
319
+ if (!validateTokenBody(body, sessionToken, res))
320
+ return;
321
+ const params = body.params ?? {};
322
+ touchHeartbeat();
323
+ if (url.pathname === "/proxy/tools/call") {
324
+ options.consentManager.ensureApproved(options.serverName);
325
+ const callParams = params;
326
+ if (!callParams || typeof callParams.name !== "string" || !callParams.name.trim()) {
327
+ sendJson(res, 400, { ok: false, error: "Invalid tools/call params" });
328
+ return;
329
+ }
330
+ const connection = options.manager.getConnection(options.serverName);
331
+ if (!connection || connection.status !== "connected") {
332
+ sendJson(res, 503, { ok: false, error: `Server "${options.serverName}" is not connected` });
333
+ return;
334
+ }
335
+ if (isServerDisabled(options.config?.mcpServers[options.serverName]) ||
336
+ isServerDisabled(connection.definition)) {
337
+ sendJson(res, 503, { ok: false, error: `Server "${options.serverName}" is disabled` });
338
+ return;
339
+ }
340
+ const toolDefinitions = Array.isArray(connection.tools) ? connection.tools : [];
341
+ const toolDefinition = toolDefinitions.find((tool) => tool.name === callParams.name);
342
+ if (!toolDefinition) {
343
+ sendJson(res, 403, { ok: false, error: `MCP tool "${callParams.name}" is not callable by apps` });
344
+ return;
345
+ }
346
+ const uiVisibility = extractUiToolVisibility(toolDefinition._meta);
347
+ if (!isUiToolCallableByApp(uiVisibility)) {
348
+ sendJson(res, 403, { ok: false, error: `MCP tool "${callParams.name}" is not callable by apps` });
349
+ return;
350
+ }
351
+ let normalizedArguments;
352
+ try {
353
+ normalizedArguments = normalizeToolArguments(callParams.arguments, `tool "${callParams.name}" arguments`);
354
+ }
355
+ catch (error) {
356
+ sendJson(res, 400, { ok: false, error: error instanceof Error ? error.message : String(error) });
357
+ return;
358
+ }
359
+ const callArgs = {
360
+ name: callParams.name,
361
+ arguments: normalizedArguments,
362
+ };
363
+ const toolMeta = {
364
+ name: callParams.name,
365
+ originalName: callParams.name,
366
+ description: toolDefinition?.description ?? "",
367
+ ...(toolDefinition?.inputSchema !== undefined ? { inputSchema: toolDefinition.inputSchema } : {}),
368
+ ...(uiVisibility !== undefined ? { uiVisibility } : {}),
369
+ };
370
+ const approvalMetadata = new Map(options.state?.toolMetadata);
371
+ const definition = options.config?.mcpServers[options.serverName] ?? options.state?.config.mcpServers[options.serverName];
372
+ approvalMetadata.set(options.serverName, [
373
+ ...connection.tools.map((tool) => ({
374
+ name: tool.name,
375
+ originalName: tool.name,
376
+ description: tool.description ?? "",
377
+ })),
378
+ ...(definition?.exposeResources !== false
379
+ ? (connection.resources ?? []).map((resource) => {
380
+ const originalName = `read_${resourceNameToToolName(resource.name)}`;
381
+ return {
382
+ name: originalName,
383
+ originalName,
384
+ description: resource.description ?? `Read resource: ${resource.uri}`,
385
+ };
386
+ })
387
+ : []),
388
+ ]);
389
+ const approval = options.state
390
+ ? await ensureToolCallApproved(options.state, options.serverName, toolMeta, callArgs.arguments, options.state.owner?.signal, "iframe", approvalMetadata)
391
+ : options.config &&
392
+ isToolCallApprovalRequired(options.config, options.serverName, toolMeta, approvalMetadata)
393
+ ? { ok: false, reason: "approval_required_headless" }
394
+ : { ok: true };
395
+ if (approval.ok === false) {
396
+ const denied = approval.reason === "denied";
397
+ const message = denied
398
+ ? `The user declined approval to run MCP tool "${callParams.name}" on server "${options.serverName}".`
399
+ : `MCP tool "${callParams.name}" on server "${options.serverName}" is approval-gated and requires an interactive session.`;
400
+ sendJson(res, 200, {
401
+ ok: true,
402
+ result: {
403
+ content: [{ type: "text", text: message }],
404
+ details: {
405
+ error: denied ? "approval_denied" : "approval_required",
406
+ server: options.serverName,
407
+ tool: callParams.name,
408
+ },
409
+ },
410
+ });
411
+ return;
412
+ }
413
+ try {
414
+ options.manager.touch(options.serverName);
415
+ options.manager.incrementInFlight(options.serverName);
416
+ const result = options.config
417
+ ? await withSessionRecovery({
418
+ manager: options.manager,
419
+ config: options.config,
420
+ ...(options.onNeedsAuth ? { onNeedsAuth: options.onNeedsAuth } : {}),
421
+ }, options.serverName, (conn) => conn.client.callTool(callArgs, options.manager.getRequestOptions?.(options.serverName)))
422
+ : await connection.client.callTool(callArgs, options.manager.getRequestOptions?.(options.serverName));
423
+ sendJson(res, 200, { ok: true, result });
424
+ }
425
+ finally {
426
+ options.manager.decrementInFlight(options.serverName);
427
+ options.manager.touch(options.serverName);
428
+ }
429
+ return;
430
+ }
431
+ if (url.pathname === "/proxy/ui/consent") {
432
+ const approved = !!params.approved;
433
+ options.consentManager.registerDecision(options.serverName, approved);
434
+ sendJson(res, 200, { ok: true, result: { approved } });
435
+ return;
436
+ }
437
+ if (url.pathname === "/proxy/ui/generated-tool-call-intent") {
438
+ const tool = typeof params.tool === "string" ? params.tool : undefined;
439
+ if (tool && isAppOnlyTool(tool)) {
440
+ log.debug("Ignored generated app-only tool call intent", { tool });
441
+ }
442
+ else {
443
+ await recordUiMessage({
444
+ type: "intent",
445
+ intent: "call_tool",
446
+ params: {
447
+ ...(tool !== undefined ? { tool } : {}),
448
+ ...(params.arguments !== undefined ? { arguments: params.arguments } : {}),
449
+ ...(params.isError !== undefined ? { isError: params.isError } : {}),
450
+ },
451
+ });
452
+ }
453
+ sendJson(res, 200, { ok: true, result: {} });
454
+ return;
455
+ }
456
+ if (url.pathname === "/proxy/ui/message") {
457
+ await recordUiMessage(params);
458
+ sendJson(res, 200, { ok: true, result: {} });
459
+ return;
460
+ }
461
+ if (url.pathname === "/proxy/ui/context") {
462
+ const content = params.content;
463
+ const structuredContent = params.structuredContent;
464
+ if ((content !== undefined &&
465
+ (!Array.isArray(content) || content.some((block) => !ContentBlockSchema.safeParse(block).success))) ||
466
+ (structuredContent !== undefined &&
467
+ (!structuredContent || typeof structuredContent !== "object" || Array.isArray(structuredContent)))) {
468
+ sendJson(res, 400, { ok: false, error: "Invalid update-model-context params" });
469
+ return;
470
+ }
471
+ const ctxParams = {
472
+ ...(content !== undefined ? { content: content } : {}),
473
+ ...(structuredContent !== undefined
474
+ ? { structuredContent: structuredContent }
475
+ : {}),
476
+ };
477
+ const update = createUiModelContextUpdate(ctxParams);
478
+ if (update) {
479
+ sessionMessages.contexts.push(update);
480
+ while (sessionMessages.contexts.length > MAX_CONTEXT_UPDATES) {
481
+ sessionMessages.contexts.shift();
482
+ }
483
+ }
484
+ log.debug("UI context update", { hasContent: !!ctxParams.content, hasUpdate: !!update });
485
+ await options.onContextUpdate?.(ctxParams);
486
+ sendJson(res, 200, { ok: true, result: {} });
487
+ return;
488
+ }
489
+ if (url.pathname === "/proxy/ui/open-link") {
490
+ const openParams = params;
491
+ if (!openParams?.url || typeof openParams.url !== "string") {
492
+ sendJson(res, 400, { ok: false, error: "Invalid open-link params" });
493
+ return;
494
+ }
495
+ let result = {};
496
+ try {
497
+ const externalUrl = new URL(openParams.url);
498
+ if ((externalUrl.protocol !== "http:" && externalUrl.protocol !== "https:") ||
499
+ externalUrl.username ||
500
+ externalUrl.password) {
501
+ result = { isError: true };
502
+ }
503
+ }
504
+ catch {
505
+ result = { isError: true };
506
+ }
507
+ sendJson(res, 200, { ok: true, result });
508
+ return;
509
+ }
510
+ if (url.pathname === "/proxy/ui/download-file") {
511
+ sendJson(res, 200, { ok: true, result: { isError: true } });
512
+ return;
513
+ }
514
+ if (url.pathname === "/proxy/ui/request-display-mode") {
515
+ const displayParams = params;
516
+ const requested = displayParams?.mode;
517
+ const available = hostContext.availableDisplayModes ?? ["inline"];
518
+ if (requested && available.includes(requested)) {
519
+ currentDisplayMode = requested;
520
+ }
521
+ hostContext.displayMode = currentDisplayMode;
522
+ pushEvent("host-context", { displayMode: currentDisplayMode });
523
+ const result = { mode: currentDisplayMode };
524
+ sendJson(res, 200, { ok: true, result });
525
+ return;
526
+ }
527
+ if (url.pathname === "/proxy/ui/heartbeat") {
528
+ sendJson(res, 200, { ok: true, result: {} });
529
+ return;
530
+ }
531
+ if (url.pathname === "/proxy/ui/complete") {
532
+ const reason = typeof params.reason === "string"
533
+ ? params.reason
534
+ : "done";
535
+ markCompleted(reason);
536
+ sendJson(res, 200, { ok: true, result: {} });
537
+ setTimeout(() => {
538
+ try {
539
+ server.close();
540
+ }
541
+ catch { }
542
+ closeSse();
543
+ }, 20).unref();
544
+ return;
545
+ }
546
+ sendJson(res, 404, { ok: false, error: "Not found" });
547
+ }
548
+ catch (error) {
549
+ if (error instanceof SessionRecoveryAuthRequiredError) {
550
+ const fallback = `Server "${options.serverName}" requires OAuth authentication. Run mcp({ action: "auth-start", server: "${options.serverName}" }) to get a browser URL, or /mcp-auth ${options.serverName} in an interactive local session.`;
551
+ const message = error.authMessage ??
552
+ (options.config ? formatAuthRequiredMessage(options.config, options.serverName, fallback) : fallback);
553
+ sendJson(res, 401, { ok: false, error: message });
554
+ return;
555
+ }
556
+ const wrapped = wrapError(error, { server: options.serverName, tool: options.toolName });
557
+ const status = /approval required|denied/i.test(wrapped.message) ? 403 : 500;
558
+ if (status === 500) {
559
+ log.error("Request handler error", error instanceof Error ? error : undefined);
560
+ }
561
+ sendJson(res, status, { ok: false, error: wrapped.message });
562
+ }
563
+ });
564
+ if (options.initialResultPromise) {
565
+ options.initialResultPromise.then((result) => pushEvent("tool-result", result), (error) => {
566
+ const reason = error instanceof Error ? error.message : String(error);
567
+ pushEvent("tool-cancelled", { reason });
568
+ });
569
+ }
570
+ watchdog = setInterval(() => {
571
+ if (completed)
572
+ return;
573
+ if (Date.now() - lastHeartbeatAt <= ABANDONED_GRACE_MS)
574
+ return;
575
+ markCompleted("stale");
576
+ try {
577
+ server.close();
578
+ }
579
+ catch { }
580
+ closeSse();
581
+ }, WATCHDOG_INTERVAL_MS);
582
+ watchdog.unref();
583
+ return new Promise((resolve, reject) => {
584
+ const candidates = resolvePortCandidates(options.port);
585
+ let candidateIndex = 0;
586
+ const listen = () => {
587
+ server.once("error", onError);
588
+ server.listen(candidates[candidateIndex], "127.0.0.1", onListening);
589
+ };
590
+ const onError = (error) => {
591
+ server.off("listening", onListening);
592
+ if (error.code === "EADDRINUSE" && candidateIndex < candidates.length - 1) {
593
+ candidateIndex += 1;
594
+ listen();
595
+ return;
596
+ }
597
+ log.error("Failed to start server", error);
598
+ const port = candidates[candidateIndex];
599
+ reject(new ServerError(error.message, {
600
+ ...(port !== undefined ? { port } : {}),
601
+ cause: error,
602
+ }));
603
+ };
604
+ const onListening = () => {
605
+ server.off("error", onError);
606
+ const address = server.address();
607
+ if (!address || typeof address === "string") {
608
+ const err = new ServerError("invalid address");
609
+ log.error("Invalid server address", err);
610
+ reject(err);
611
+ return;
612
+ }
613
+ log.debug("Server started", { port: address.port });
614
+ rememberMoshiDiscoveryPort(address.port);
615
+ const handle = {
616
+ url: `http://localhost:${address.port}/?session=${sessionToken}`,
617
+ port: address.port,
618
+ sessionToken,
619
+ serverName: options.serverName,
620
+ toolName: options.toolName,
621
+ close: (reason) => {
622
+ markCompleted(reason ?? "closed");
623
+ try {
624
+ server.close();
625
+ }
626
+ catch { }
627
+ closeSse();
628
+ },
629
+ sendToolInput: (args) => {
630
+ pushEvent("tool-input", { arguments: args });
631
+ },
632
+ sendToolResult: (result) => {
633
+ pushEvent("tool-result", result);
634
+ },
635
+ sendResultPatch: (result) => {
636
+ pushEvent("result-patch", result);
637
+ },
638
+ sendToolCancelled: (reason) => {
639
+ pushEvent("tool-cancelled", { reason });
640
+ },
641
+ sendHostContext: (context) => {
642
+ Object.assign(hostContext, context);
643
+ pushEvent("host-context", context);
644
+ },
645
+ getSessionMessages: () => ({ ...sessionMessages }),
646
+ getStreamSummary: () => streamSummary ? { ...streamSummary, phases: [...streamSummary.phases] } : undefined,
647
+ };
648
+ resolve(handle);
649
+ };
650
+ listen();
651
+ });
652
+ }
653
+ async function parseBody(req, res) {
654
+ try {
655
+ const body = await readBody(req);
656
+ if (!body || typeof body !== "object") {
657
+ sendJson(res, 400, { ok: false, error: "Invalid request body" });
658
+ return null;
659
+ }
660
+ return body;
661
+ }
662
+ catch (error) {
663
+ sendJson(res, 400, { ok: false, error: error instanceof Error ? error.message : "Invalid body" });
664
+ return null;
665
+ }
666
+ }
667
+ function readBody(req) {
668
+ return new Promise((resolve, reject) => {
669
+ let size = 0;
670
+ const chunks = [];
671
+ req.on("data", (chunk) => {
672
+ size += chunk.length;
673
+ if (size > MAX_BODY_SIZE) {
674
+ req.destroy();
675
+ reject(new Error("Request body too large"));
676
+ return;
677
+ }
678
+ chunks.push(chunk);
679
+ });
680
+ req.on("end", () => {
681
+ try {
682
+ resolve(JSON.parse(Buffer.concat(chunks).toString("utf-8")));
683
+ }
684
+ catch (error) {
685
+ reject(error);
686
+ }
687
+ });
688
+ req.on("error", reject);
689
+ });
690
+ }
691
+ function resolvePortCandidates(port) {
692
+ if (port !== undefined)
693
+ return [port];
694
+ const candidates = [];
695
+ const count = MOSHI_DISCOVERY_PORT_END - MOSHI_DISCOVERY_PORT_START + 1;
696
+ for (let offset = 0; offset < count; offset += 1) {
697
+ const candidate = MOSHI_DISCOVERY_PORT_START + ((nextMoshiDiscoveryPort - MOSHI_DISCOVERY_PORT_START + offset) % count);
698
+ candidates.push(candidate);
699
+ }
700
+ candidates.push(0);
701
+ return candidates;
702
+ }
703
+ function rememberMoshiDiscoveryPort(port) {
704
+ if (port < MOSHI_DISCOVERY_PORT_START || port > MOSHI_DISCOVERY_PORT_END)
705
+ return;
706
+ nextMoshiDiscoveryPort = port >= MOSHI_DISCOVERY_PORT_END ? MOSHI_DISCOVERY_PORT_START : port + 1;
707
+ }
708
+ function isAllowedHost(hostname) {
709
+ return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "[::1]";
710
+ }
711
+ function validateTokenQuery(url, expected, res, parameter = "session") {
712
+ const token = url.searchParams.get(parameter);
713
+ if (token !== expected) {
714
+ sendJson(res, 403, { ok: false, error: "Invalid session" });
715
+ return false;
716
+ }
717
+ return true;
718
+ }
719
+ function validateTokenBody(body, expected, res) {
720
+ if (body.token !== expected) {
721
+ sendJson(res, 403, { ok: false, error: "Invalid session" });
722
+ return false;
723
+ }
724
+ return true;
725
+ }
726
+ function sendJson(res, status, payload) {
727
+ res.writeHead(status, {
728
+ "Content-Type": "application/json; charset=utf-8",
729
+ "Cache-Control": "no-store",
730
+ });
731
+ res.end(JSON.stringify(payload));
732
+ }
733
+ function sendText(res, status, text) {
734
+ res.writeHead(status, {
735
+ "Content-Type": "text/plain; charset=utf-8",
736
+ "Cache-Control": "no-store",
737
+ });
738
+ res.end(text);
739
+ }
740
+ //# sourceMappingURL=ui-server.js.map