@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,65 @@
1
+ import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
2
+ import { dirname } from "node:path";
3
+ import { getAgentPath } from "./agent-dir.js";
4
+ const DEFAULT_STATE = {
5
+ version: 1,
6
+ sharedConfigHintShown: false,
7
+ setupCompleted: false,
8
+ };
9
+ export function getOnboardingStatePath() {
10
+ return getAgentPath("mcp-onboarding.json");
11
+ }
12
+ export function loadOnboardingState() {
13
+ const path = getOnboardingStatePath();
14
+ if (!existsSync(path))
15
+ return { ...DEFAULT_STATE };
16
+ try {
17
+ const raw = JSON.parse(readFileSync(path, "utf-8"));
18
+ if (!raw || typeof raw !== "object")
19
+ return { ...DEFAULT_STATE };
20
+ return {
21
+ version: 1,
22
+ sharedConfigHintShown: raw.sharedConfigHintShown === true,
23
+ setupCompleted: raw.setupCompleted === true,
24
+ ...(typeof raw.lastDiscoveryFingerprint === "string"
25
+ ? { lastDiscoveryFingerprint: raw.lastDiscoveryFingerprint }
26
+ : {}),
27
+ };
28
+ }
29
+ catch {
30
+ return { ...DEFAULT_STATE };
31
+ }
32
+ }
33
+ export function saveOnboardingState(state) {
34
+ const path = getOnboardingStatePath();
35
+ mkdirSync(dirname(path), { recursive: true });
36
+ const tmpPath = `${path}.${process.pid}.tmp`;
37
+ writeFileSync(tmpPath, `${JSON.stringify(state, null, 2)}\n`, "utf-8");
38
+ renameSync(tmpPath, path);
39
+ }
40
+ export function updateOnboardingState(updater) {
41
+ const next = updater(loadOnboardingState());
42
+ saveOnboardingState(next);
43
+ return next;
44
+ }
45
+ export function markSharedConfigHintShown(fingerprint) {
46
+ return updateOnboardingState((state) => {
47
+ const lastDiscoveryFingerprint = fingerprint ?? state.lastDiscoveryFingerprint;
48
+ return {
49
+ ...state,
50
+ sharedConfigHintShown: true,
51
+ ...(lastDiscoveryFingerprint !== undefined ? { lastDiscoveryFingerprint } : {}),
52
+ };
53
+ });
54
+ }
55
+ export function markSetupCompleted(fingerprint) {
56
+ return updateOnboardingState((state) => {
57
+ const lastDiscoveryFingerprint = fingerprint ?? state.lastDiscoveryFingerprint;
58
+ return {
59
+ ...state,
60
+ setupCompleted: true,
61
+ ...(lastDiscoveryFingerprint !== undefined ? { lastDiscoveryFingerprint } : {}),
62
+ };
63
+ });
64
+ }
65
+ //# sourceMappingURL=onboarding-state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"onboarding-state.js","sourceRoot":"","sources":["../../../src/extensions/mcp/onboarding-state.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport { getAgentPath } from \"./agent-dir.ts\";\n\nexport interface McpOnboardingState {\n\tversion: 1;\n\tsharedConfigHintShown: boolean;\n\tsetupCompleted: boolean;\n\tlastDiscoveryFingerprint?: string;\n}\n\nconst DEFAULT_STATE: McpOnboardingState = {\n\tversion: 1,\n\tsharedConfigHintShown: false,\n\tsetupCompleted: false,\n};\n\nexport function getOnboardingStatePath(): string {\n\treturn getAgentPath(\"mcp-onboarding.json\");\n}\n\nexport function loadOnboardingState(): McpOnboardingState {\n\tconst path = getOnboardingStatePath();\n\tif (!existsSync(path)) return { ...DEFAULT_STATE };\n\n\ttry {\n\t\tconst raw = JSON.parse(readFileSync(path, \"utf-8\")) as Partial<McpOnboardingState>;\n\t\tif (!raw || typeof raw !== \"object\") return { ...DEFAULT_STATE };\n\t\treturn {\n\t\t\tversion: 1,\n\t\t\tsharedConfigHintShown: raw.sharedConfigHintShown === true,\n\t\t\tsetupCompleted: raw.setupCompleted === true,\n\t\t\t...(typeof raw.lastDiscoveryFingerprint === \"string\"\n\t\t\t\t? { lastDiscoveryFingerprint: raw.lastDiscoveryFingerprint }\n\t\t\t\t: {}),\n\t\t};\n\t} catch {\n\t\treturn { ...DEFAULT_STATE };\n\t}\n}\n\nexport function saveOnboardingState(state: McpOnboardingState): void {\n\tconst path = getOnboardingStatePath();\n\tmkdirSync(dirname(path), { recursive: true });\n\tconst tmpPath = `${path}.${process.pid}.tmp`;\n\twriteFileSync(tmpPath, `${JSON.stringify(state, null, 2)}\\n`, \"utf-8\");\n\trenameSync(tmpPath, path);\n}\n\nexport function updateOnboardingState(updater: (state: McpOnboardingState) => McpOnboardingState): McpOnboardingState {\n\tconst next = updater(loadOnboardingState());\n\tsaveOnboardingState(next);\n\treturn next;\n}\n\nexport function markSharedConfigHintShown(fingerprint?: string): McpOnboardingState {\n\treturn updateOnboardingState((state) => {\n\t\tconst lastDiscoveryFingerprint = fingerprint ?? state.lastDiscoveryFingerprint;\n\t\treturn {\n\t\t\t...state,\n\t\t\tsharedConfigHintShown: true,\n\t\t\t...(lastDiscoveryFingerprint !== undefined ? { lastDiscoveryFingerprint } : {}),\n\t\t};\n\t});\n}\n\nexport function markSetupCompleted(fingerprint?: string): McpOnboardingState {\n\treturn updateOnboardingState((state) => {\n\t\tconst lastDiscoveryFingerprint = fingerprint ?? state.lastDiscoveryFingerprint;\n\t\treturn {\n\t\t\t...state,\n\t\t\tsetupCompleted: true,\n\t\t\t...(lastDiscoveryFingerprint !== undefined ? { lastDiscoveryFingerprint } : {}),\n\t\t};\n\t});\n}\n"]}
@@ -0,0 +1,3 @@
1
+ import type { McpConfig } from "./types.ts";
2
+ export declare function loadPackageMcpConfigs(cwd?: string, includeProject?: boolean): McpConfig;
3
+ //# sourceMappingURL=package-mcp-loader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package-mcp-loader.d.ts","sourceRoot":"","sources":["../../../src/extensions/mcp/package-mcp-loader.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAe,MAAM,YAAY,CAAC;AAWzD,wBAAgB,qBAAqB,CAAC,GAAG,SAAgB,EAAE,cAAc,UAAO,GAAG,SAAS,CAmC3F","sourcesContent":["import { existsSync, readFileSync, realpathSync, statSync } from \"node:fs\";\nimport { isAbsolute, join, relative, resolve, sep } from \"node:path\";\nimport stripJsonComments from \"strip-json-comments\";\nimport { getAgentDir, getConfigDirName } from \"./agent-dir.ts\";\nimport type { McpConfig, ServerEntry } from \"./types.ts\";\n\ninterface PackageSetting {\n\tsource: string;\n}\n\ninterface PackageManifest {\n\tname?: unknown;\n\tnexus?: { mcp?: unknown };\n}\n\nexport function loadPackageMcpConfigs(cwd = process.cwd(), includeProject = true): McpConfig {\n\tconst mcpServers: Record<string, ServerEntry> = {};\n\tconst seen = new Set<string>();\n\n\tfor (const packageRoot of getConfiguredPackageRoots(cwd, includeProject)) {\n\t\tconst manifest = readPackageManifest(packageRoot);\n\t\tif (!manifest || typeof manifest.name !== \"string\" || !manifest.name) continue;\n\t\tconst paths = getManifestMcpPaths(manifest.nexus?.mcp, manifest.name);\n\t\tif (!paths) continue;\n\n\t\tconst packagePrefix = formatPackageName(manifest.name);\n\t\tconst packageServers = new Set<string>();\n\t\tfor (const path of paths) {\n\t\t\tconst configPath = resolvePackageConfigPath(packageRoot, path);\n\t\t\tif (!configPath) {\n\t\t\t\tconsole.warn(`Nexus package ${manifest.name} skips MCP config ${path}: file must stay inside the package`);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst config = readMcpConfig(configPath, manifest.name);\n\t\t\tif (!config) continue;\n\t\t\tfor (const [serverName, server] of Object.entries(config.mcpServers)) {\n\t\t\t\tconst normalizedName = `${packagePrefix}__${formatServerName(serverName)}`;\n\t\t\t\tif (packageServers.has(normalizedName) || seen.has(normalizedName)) {\n\t\t\t\t\tconsole.warn(`Nexus package ${manifest.name} skips duplicate normalized MCP server ${normalizedName}`);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tpackageServers.add(normalizedName);\n\t\t\t\tseen.add(normalizedName);\n\t\t\t\tmcpServers[normalizedName] = server;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn { mcpServers };\n}\n\nfunction getConfiguredPackageRoots(cwd: string, includeProject: boolean): string[] {\n\tconst roots: string[] = [];\n\tconst settingsSources: Array<readonly [string, \"project\" | \"user\"]> = [\n\t\t[join(getAgentDir(), \"settings.json\"), \"user\"],\n\t];\n\tif (includeProject) settingsSources.unshift([join(cwd, getConfigDirName(), \"settings.json\"), \"project\"]);\n\tfor (const [settingsPath, scope] of settingsSources) {\n\t\tconst settings = readOptionalJson(settingsPath, `${scope} Nexus settings`);\n\t\tif (settings === undefined) continue;\n\t\tif (typeof settings !== \"object\" || settings === null || Array.isArray(settings)) {\n\t\t\tthrow new Error(`${scope} Nexus settings ${settingsPath} must be a JSON object`);\n\t\t}\n\t\tconst packages = (settings as { packages?: unknown }).packages;\n\t\tif (packages === undefined) continue;\n\t\tif (!Array.isArray(packages))\n\t\t\tthrow new Error(`${scope} Nexus settings ${settingsPath} packages must be an array`);\n\t\tfor (const entry of packages) {\n\t\t\tconst source =\n\t\t\t\ttypeof entry === \"string\"\n\t\t\t\t\t? entry\n\t\t\t\t\t: entry &&\n\t\t\t\t\t\t\ttypeof entry === \"object\" &&\n\t\t\t\t\t\t\t!Array.isArray(entry) &&\n\t\t\t\t\t\t\ttypeof (entry as PackageSetting).source === \"string\"\n\t\t\t\t\t\t? (entry as PackageSetting).source\n\t\t\t\t\t\t: undefined;\n\t\t\tif (!source)\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`${scope} Nexus settings ${settingsPath} package entries must be strings or objects with a string source`,\n\t\t\t\t);\n\t\t\tconst root = resolvePackageRoot(source, scope, cwd);\n\t\t\tif (root && !roots.includes(root)) roots.push(root);\n\t\t}\n\t}\n\treturn roots;\n}\n\nfunction resolvePackageRoot(source: string, scope: \"user\" | \"project\", cwd: string): string | null {\n\tconst baseDir = scope === \"user\" ? getAgentDir() : join(cwd, getConfigDirName());\n\tif (source.startsWith(\"npm:\")) {\n\t\tconst name = source\n\t\t\t.slice(4)\n\t\t\t.trim()\n\t\t\t.match(/^(@?[^@]+(?:\\/[^@]+)?)/)?.[1];\n\t\treturn name ? resolveContainedPath(join(baseDir, \"npm\", \"node_modules\"), name) : null;\n\t}\n\tconst gitSource = source.startsWith(\"git:\")\n\t\t? source.slice(4).trim()\n\t\t: /^(?:(?:https?|ssh):\\/\\/|git@[^:]+:)/.test(source)\n\t\t\t? source\n\t\t\t: null;\n\tif (gitSource) {\n\t\tconst value = gitSource\n\t\t\t.replace(/^ssh:\\/\\/git@/, \"\")\n\t\t\t.replace(/^git@([^:]+):/, \"$1/\")\n\t\t\t.replace(/^[a-z]+:\\/\\//i, \"\");\n\t\tconst path = value.replace(/@[^/]+$/, \"\").replace(/\\.git$/, \"\");\n\t\treturn path && !path.startsWith(\"/\") ? resolveContainedPath(join(baseDir, \"git\"), path) : null;\n\t}\n\treturn isAbsolute(source) ? resolve(source) : resolve(baseDir, source);\n}\n\nfunction readPackageManifest(packageRoot: string): PackageManifest | null {\n\tconst manifest = readOptionalJson(join(packageRoot, \"package.json\"), `Nexus package manifest ${packageRoot}`);\n\treturn manifest && typeof manifest === \"object\" && !Array.isArray(manifest) ? (manifest as PackageManifest) : null;\n}\n\nfunction getManifestMcpPaths(value: unknown, packageName: string): string[] | null {\n\tconst paths =\n\t\ttypeof value === \"string\"\n\t\t\t? [value]\n\t\t\t: Array.isArray(value) && value.every((path): path is string => typeof path === \"string\")\n\t\t\t\t? value\n\t\t\t\t: null;\n\tif (value !== undefined && !paths)\n\t\tconsole.warn(`Nexus package ${packageName} ignores invalid nexus.mcp manifest entry`);\n\treturn paths;\n}\n\nfunction readMcpConfig(path: string, packageName: string): McpConfig | null {\n\tconst config = readRequiredJson(path, `Nexus package ${packageName} MCP config`);\n\tif (!config || typeof config !== \"object\" || Array.isArray(config)) {\n\t\tthrow new Error(`Nexus package ${packageName} MCP config ${path} must be a JSON object`);\n\t}\n\tconst servers = (config as { mcpServers?: unknown }).mcpServers;\n\tif (!servers || typeof servers !== \"object\" || Array.isArray(servers)) {\n\t\tthrow new Error(`Nexus package ${packageName} MCP config ${path} must contain a JSON object mcpServers field`);\n\t}\n\tconst mcpServers: Record<string, ServerEntry> = {};\n\tfor (const [name, server] of Object.entries(servers)) {\n\t\tif (!server || typeof server !== \"object\" || Array.isArray(server)) {\n\t\t\tthrow new Error(`Nexus package ${packageName} MCP config ${path} server ${name} must be a JSON object`);\n\t\t}\n\t\tmcpServers[name] = server as ServerEntry;\n\t}\n\treturn { mcpServers };\n}\n\nfunction readRequiredJson(path: string, description: string): unknown {\n\ttry {\n\t\treturn JSON.parse(stripJsonComments(readFileSync(path, \"utf8\"), { trailingCommas: true }));\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`${description} ${path} contains invalid JSON: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t{ cause: error },\n\t\t);\n\t}\n}\n\nfunction readOptionalJson(path: string, description: string): unknown | undefined {\n\tif (!existsSync(path)) return undefined;\n\treturn readRequiredJson(path, description);\n}\n\nfunction resolveContainedPath(root: string, path: string): string | null {\n\tconst resolved = resolve(root, path);\n\tconst rel = relative(root, resolved);\n\treturn rel === \"\" || (!rel.startsWith(\"..\") && !rel.startsWith(sep) && !isAbsolute(rel)) ? resolved : null;\n}\n\nfunction resolvePackageConfigPath(packageRoot: string, path: string): string | null {\n\tconst lexicalPath = resolveContainedPath(packageRoot, path);\n\tif (!lexicalPath || !existsSync(lexicalPath) || !statSync(lexicalPath).isFile()) return null;\n\ttry {\n\t\tconst realPackageRoot = realpathSync(packageRoot);\n\t\tconst realConfigPath = realpathSync(lexicalPath);\n\t\treturn resolveContainedPath(realPackageRoot, realConfigPath);\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction formatPackageName(name: string): string {\n\treturn name.replace(/[^A-Za-z0-9_-]+/g, \"_\").replace(/^[_-]+|[_-]+$/g, \"\") || \"package\";\n}\n\nfunction formatServerName(name: string): string {\n\treturn name.replace(/[^A-Za-z0-9_-]+/g, \"_\").replace(/^[_-]+|[_-]+$/g, \"\") || \"server\";\n}\n"]}
@@ -0,0 +1,170 @@
1
+ import { existsSync, readFileSync, realpathSync, statSync } from "node:fs";
2
+ import { isAbsolute, join, relative, resolve, sep } from "node:path";
3
+ import stripJsonComments from "strip-json-comments";
4
+ import { getAgentDir, getConfigDirName } from "./agent-dir.js";
5
+ export function loadPackageMcpConfigs(cwd = process.cwd(), includeProject = true) {
6
+ const mcpServers = {};
7
+ const seen = new Set();
8
+ for (const packageRoot of getConfiguredPackageRoots(cwd, includeProject)) {
9
+ const manifest = readPackageManifest(packageRoot);
10
+ if (!manifest || typeof manifest.name !== "string" || !manifest.name)
11
+ continue;
12
+ const paths = getManifestMcpPaths(manifest.nexus?.mcp, manifest.name);
13
+ if (!paths)
14
+ continue;
15
+ const packagePrefix = formatPackageName(manifest.name);
16
+ const packageServers = new Set();
17
+ for (const path of paths) {
18
+ const configPath = resolvePackageConfigPath(packageRoot, path);
19
+ if (!configPath) {
20
+ console.warn(`Nexus package ${manifest.name} skips MCP config ${path}: file must stay inside the package`);
21
+ continue;
22
+ }
23
+ const config = readMcpConfig(configPath, manifest.name);
24
+ if (!config)
25
+ continue;
26
+ for (const [serverName, server] of Object.entries(config.mcpServers)) {
27
+ const normalizedName = `${packagePrefix}__${formatServerName(serverName)}`;
28
+ if (packageServers.has(normalizedName) || seen.has(normalizedName)) {
29
+ console.warn(`Nexus package ${manifest.name} skips duplicate normalized MCP server ${normalizedName}`);
30
+ continue;
31
+ }
32
+ packageServers.add(normalizedName);
33
+ seen.add(normalizedName);
34
+ mcpServers[normalizedName] = server;
35
+ }
36
+ }
37
+ }
38
+ return { mcpServers };
39
+ }
40
+ function getConfiguredPackageRoots(cwd, includeProject) {
41
+ const roots = [];
42
+ const settingsSources = [
43
+ [join(getAgentDir(), "settings.json"), "user"],
44
+ ];
45
+ if (includeProject)
46
+ settingsSources.unshift([join(cwd, getConfigDirName(), "settings.json"), "project"]);
47
+ for (const [settingsPath, scope] of settingsSources) {
48
+ const settings = readOptionalJson(settingsPath, `${scope} Nexus settings`);
49
+ if (settings === undefined)
50
+ continue;
51
+ if (typeof settings !== "object" || settings === null || Array.isArray(settings)) {
52
+ throw new Error(`${scope} Nexus settings ${settingsPath} must be a JSON object`);
53
+ }
54
+ const packages = settings.packages;
55
+ if (packages === undefined)
56
+ continue;
57
+ if (!Array.isArray(packages))
58
+ throw new Error(`${scope} Nexus settings ${settingsPath} packages must be an array`);
59
+ for (const entry of packages) {
60
+ const source = typeof entry === "string"
61
+ ? entry
62
+ : entry &&
63
+ typeof entry === "object" &&
64
+ !Array.isArray(entry) &&
65
+ typeof entry.source === "string"
66
+ ? entry.source
67
+ : undefined;
68
+ if (!source)
69
+ throw new Error(`${scope} Nexus settings ${settingsPath} package entries must be strings or objects with a string source`);
70
+ const root = resolvePackageRoot(source, scope, cwd);
71
+ if (root && !roots.includes(root))
72
+ roots.push(root);
73
+ }
74
+ }
75
+ return roots;
76
+ }
77
+ function resolvePackageRoot(source, scope, cwd) {
78
+ const baseDir = scope === "user" ? getAgentDir() : join(cwd, getConfigDirName());
79
+ if (source.startsWith("npm:")) {
80
+ const name = source
81
+ .slice(4)
82
+ .trim()
83
+ .match(/^(@?[^@]+(?:\/[^@]+)?)/)?.[1];
84
+ return name ? resolveContainedPath(join(baseDir, "npm", "node_modules"), name) : null;
85
+ }
86
+ const gitSource = source.startsWith("git:")
87
+ ? source.slice(4).trim()
88
+ : /^(?:(?:https?|ssh):\/\/|git@[^:]+:)/.test(source)
89
+ ? source
90
+ : null;
91
+ if (gitSource) {
92
+ const value = gitSource
93
+ .replace(/^ssh:\/\/git@/, "")
94
+ .replace(/^git@([^:]+):/, "$1/")
95
+ .replace(/^[a-z]+:\/\//i, "");
96
+ const path = value.replace(/@[^/]+$/, "").replace(/\.git$/, "");
97
+ return path && !path.startsWith("/") ? resolveContainedPath(join(baseDir, "git"), path) : null;
98
+ }
99
+ return isAbsolute(source) ? resolve(source) : resolve(baseDir, source);
100
+ }
101
+ function readPackageManifest(packageRoot) {
102
+ const manifest = readOptionalJson(join(packageRoot, "package.json"), `Nexus package manifest ${packageRoot}`);
103
+ return manifest && typeof manifest === "object" && !Array.isArray(manifest) ? manifest : null;
104
+ }
105
+ function getManifestMcpPaths(value, packageName) {
106
+ const paths = typeof value === "string"
107
+ ? [value]
108
+ : Array.isArray(value) && value.every((path) => typeof path === "string")
109
+ ? value
110
+ : null;
111
+ if (value !== undefined && !paths)
112
+ console.warn(`Nexus package ${packageName} ignores invalid nexus.mcp manifest entry`);
113
+ return paths;
114
+ }
115
+ function readMcpConfig(path, packageName) {
116
+ const config = readRequiredJson(path, `Nexus package ${packageName} MCP config`);
117
+ if (!config || typeof config !== "object" || Array.isArray(config)) {
118
+ throw new Error(`Nexus package ${packageName} MCP config ${path} must be a JSON object`);
119
+ }
120
+ const servers = config.mcpServers;
121
+ if (!servers || typeof servers !== "object" || Array.isArray(servers)) {
122
+ throw new Error(`Nexus package ${packageName} MCP config ${path} must contain a JSON object mcpServers field`);
123
+ }
124
+ const mcpServers = {};
125
+ for (const [name, server] of Object.entries(servers)) {
126
+ if (!server || typeof server !== "object" || Array.isArray(server)) {
127
+ throw new Error(`Nexus package ${packageName} MCP config ${path} server ${name} must be a JSON object`);
128
+ }
129
+ mcpServers[name] = server;
130
+ }
131
+ return { mcpServers };
132
+ }
133
+ function readRequiredJson(path, description) {
134
+ try {
135
+ return JSON.parse(stripJsonComments(readFileSync(path, "utf8"), { trailingCommas: true }));
136
+ }
137
+ catch (error) {
138
+ throw new Error(`${description} ${path} contains invalid JSON: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
139
+ }
140
+ }
141
+ function readOptionalJson(path, description) {
142
+ if (!existsSync(path))
143
+ return undefined;
144
+ return readRequiredJson(path, description);
145
+ }
146
+ function resolveContainedPath(root, path) {
147
+ const resolved = resolve(root, path);
148
+ const rel = relative(root, resolved);
149
+ return rel === "" || (!rel.startsWith("..") && !rel.startsWith(sep) && !isAbsolute(rel)) ? resolved : null;
150
+ }
151
+ function resolvePackageConfigPath(packageRoot, path) {
152
+ const lexicalPath = resolveContainedPath(packageRoot, path);
153
+ if (!lexicalPath || !existsSync(lexicalPath) || !statSync(lexicalPath).isFile())
154
+ return null;
155
+ try {
156
+ const realPackageRoot = realpathSync(packageRoot);
157
+ const realConfigPath = realpathSync(lexicalPath);
158
+ return resolveContainedPath(realPackageRoot, realConfigPath);
159
+ }
160
+ catch {
161
+ return null;
162
+ }
163
+ }
164
+ function formatPackageName(name) {
165
+ return name.replace(/[^A-Za-z0-9_-]+/g, "_").replace(/^[_-]+|[_-]+$/g, "") || "package";
166
+ }
167
+ function formatServerName(name) {
168
+ return name.replace(/[^A-Za-z0-9_-]+/g, "_").replace(/^[_-]+|[_-]+$/g, "") || "server";
169
+ }
170
+ //# sourceMappingURL=package-mcp-loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package-mcp-loader.js","sourceRoot":"","sources":["../../../src/extensions/mcp/package-mcp-loader.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, readFileSync, realpathSync, statSync } from \"node:fs\";\nimport { isAbsolute, join, relative, resolve, sep } from \"node:path\";\nimport stripJsonComments from \"strip-json-comments\";\nimport { getAgentDir, getConfigDirName } from \"./agent-dir.ts\";\nimport type { McpConfig, ServerEntry } from \"./types.ts\";\n\ninterface PackageSetting {\n\tsource: string;\n}\n\ninterface PackageManifest {\n\tname?: unknown;\n\tnexus?: { mcp?: unknown };\n}\n\nexport function loadPackageMcpConfigs(cwd = process.cwd(), includeProject = true): McpConfig {\n\tconst mcpServers: Record<string, ServerEntry> = {};\n\tconst seen = new Set<string>();\n\n\tfor (const packageRoot of getConfiguredPackageRoots(cwd, includeProject)) {\n\t\tconst manifest = readPackageManifest(packageRoot);\n\t\tif (!manifest || typeof manifest.name !== \"string\" || !manifest.name) continue;\n\t\tconst paths = getManifestMcpPaths(manifest.nexus?.mcp, manifest.name);\n\t\tif (!paths) continue;\n\n\t\tconst packagePrefix = formatPackageName(manifest.name);\n\t\tconst packageServers = new Set<string>();\n\t\tfor (const path of paths) {\n\t\t\tconst configPath = resolvePackageConfigPath(packageRoot, path);\n\t\t\tif (!configPath) {\n\t\t\t\tconsole.warn(`Nexus package ${manifest.name} skips MCP config ${path}: file must stay inside the package`);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst config = readMcpConfig(configPath, manifest.name);\n\t\t\tif (!config) continue;\n\t\t\tfor (const [serverName, server] of Object.entries(config.mcpServers)) {\n\t\t\t\tconst normalizedName = `${packagePrefix}__${formatServerName(serverName)}`;\n\t\t\t\tif (packageServers.has(normalizedName) || seen.has(normalizedName)) {\n\t\t\t\t\tconsole.warn(`Nexus package ${manifest.name} skips duplicate normalized MCP server ${normalizedName}`);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tpackageServers.add(normalizedName);\n\t\t\t\tseen.add(normalizedName);\n\t\t\t\tmcpServers[normalizedName] = server;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn { mcpServers };\n}\n\nfunction getConfiguredPackageRoots(cwd: string, includeProject: boolean): string[] {\n\tconst roots: string[] = [];\n\tconst settingsSources: Array<readonly [string, \"project\" | \"user\"]> = [\n\t\t[join(getAgentDir(), \"settings.json\"), \"user\"],\n\t];\n\tif (includeProject) settingsSources.unshift([join(cwd, getConfigDirName(), \"settings.json\"), \"project\"]);\n\tfor (const [settingsPath, scope] of settingsSources) {\n\t\tconst settings = readOptionalJson(settingsPath, `${scope} Nexus settings`);\n\t\tif (settings === undefined) continue;\n\t\tif (typeof settings !== \"object\" || settings === null || Array.isArray(settings)) {\n\t\t\tthrow new Error(`${scope} Nexus settings ${settingsPath} must be a JSON object`);\n\t\t}\n\t\tconst packages = (settings as { packages?: unknown }).packages;\n\t\tif (packages === undefined) continue;\n\t\tif (!Array.isArray(packages))\n\t\t\tthrow new Error(`${scope} Nexus settings ${settingsPath} packages must be an array`);\n\t\tfor (const entry of packages) {\n\t\t\tconst source =\n\t\t\t\ttypeof entry === \"string\"\n\t\t\t\t\t? entry\n\t\t\t\t\t: entry &&\n\t\t\t\t\t\t\ttypeof entry === \"object\" &&\n\t\t\t\t\t\t\t!Array.isArray(entry) &&\n\t\t\t\t\t\t\ttypeof (entry as PackageSetting).source === \"string\"\n\t\t\t\t\t\t? (entry as PackageSetting).source\n\t\t\t\t\t\t: undefined;\n\t\t\tif (!source)\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`${scope} Nexus settings ${settingsPath} package entries must be strings or objects with a string source`,\n\t\t\t\t);\n\t\t\tconst root = resolvePackageRoot(source, scope, cwd);\n\t\t\tif (root && !roots.includes(root)) roots.push(root);\n\t\t}\n\t}\n\treturn roots;\n}\n\nfunction resolvePackageRoot(source: string, scope: \"user\" | \"project\", cwd: string): string | null {\n\tconst baseDir = scope === \"user\" ? getAgentDir() : join(cwd, getConfigDirName());\n\tif (source.startsWith(\"npm:\")) {\n\t\tconst name = source\n\t\t\t.slice(4)\n\t\t\t.trim()\n\t\t\t.match(/^(@?[^@]+(?:\\/[^@]+)?)/)?.[1];\n\t\treturn name ? resolveContainedPath(join(baseDir, \"npm\", \"node_modules\"), name) : null;\n\t}\n\tconst gitSource = source.startsWith(\"git:\")\n\t\t? source.slice(4).trim()\n\t\t: /^(?:(?:https?|ssh):\\/\\/|git@[^:]+:)/.test(source)\n\t\t\t? source\n\t\t\t: null;\n\tif (gitSource) {\n\t\tconst value = gitSource\n\t\t\t.replace(/^ssh:\\/\\/git@/, \"\")\n\t\t\t.replace(/^git@([^:]+):/, \"$1/\")\n\t\t\t.replace(/^[a-z]+:\\/\\//i, \"\");\n\t\tconst path = value.replace(/@[^/]+$/, \"\").replace(/\\.git$/, \"\");\n\t\treturn path && !path.startsWith(\"/\") ? resolveContainedPath(join(baseDir, \"git\"), path) : null;\n\t}\n\treturn isAbsolute(source) ? resolve(source) : resolve(baseDir, source);\n}\n\nfunction readPackageManifest(packageRoot: string): PackageManifest | null {\n\tconst manifest = readOptionalJson(join(packageRoot, \"package.json\"), `Nexus package manifest ${packageRoot}`);\n\treturn manifest && typeof manifest === \"object\" && !Array.isArray(manifest) ? (manifest as PackageManifest) : null;\n}\n\nfunction getManifestMcpPaths(value: unknown, packageName: string): string[] | null {\n\tconst paths =\n\t\ttypeof value === \"string\"\n\t\t\t? [value]\n\t\t\t: Array.isArray(value) && value.every((path): path is string => typeof path === \"string\")\n\t\t\t\t? value\n\t\t\t\t: null;\n\tif (value !== undefined && !paths)\n\t\tconsole.warn(`Nexus package ${packageName} ignores invalid nexus.mcp manifest entry`);\n\treturn paths;\n}\n\nfunction readMcpConfig(path: string, packageName: string): McpConfig | null {\n\tconst config = readRequiredJson(path, `Nexus package ${packageName} MCP config`);\n\tif (!config || typeof config !== \"object\" || Array.isArray(config)) {\n\t\tthrow new Error(`Nexus package ${packageName} MCP config ${path} must be a JSON object`);\n\t}\n\tconst servers = (config as { mcpServers?: unknown }).mcpServers;\n\tif (!servers || typeof servers !== \"object\" || Array.isArray(servers)) {\n\t\tthrow new Error(`Nexus package ${packageName} MCP config ${path} must contain a JSON object mcpServers field`);\n\t}\n\tconst mcpServers: Record<string, ServerEntry> = {};\n\tfor (const [name, server] of Object.entries(servers)) {\n\t\tif (!server || typeof server !== \"object\" || Array.isArray(server)) {\n\t\t\tthrow new Error(`Nexus package ${packageName} MCP config ${path} server ${name} must be a JSON object`);\n\t\t}\n\t\tmcpServers[name] = server as ServerEntry;\n\t}\n\treturn { mcpServers };\n}\n\nfunction readRequiredJson(path: string, description: string): unknown {\n\ttry {\n\t\treturn JSON.parse(stripJsonComments(readFileSync(path, \"utf8\"), { trailingCommas: true }));\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`${description} ${path} contains invalid JSON: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t{ cause: error },\n\t\t);\n\t}\n}\n\nfunction readOptionalJson(path: string, description: string): unknown | undefined {\n\tif (!existsSync(path)) return undefined;\n\treturn readRequiredJson(path, description);\n}\n\nfunction resolveContainedPath(root: string, path: string): string | null {\n\tconst resolved = resolve(root, path);\n\tconst rel = relative(root, resolved);\n\treturn rel === \"\" || (!rel.startsWith(\"..\") && !rel.startsWith(sep) && !isAbsolute(rel)) ? resolved : null;\n}\n\nfunction resolvePackageConfigPath(packageRoot: string, path: string): string | null {\n\tconst lexicalPath = resolveContainedPath(packageRoot, path);\n\tif (!lexicalPath || !existsSync(lexicalPath) || !statSync(lexicalPath).isFile()) return null;\n\ttry {\n\t\tconst realPackageRoot = realpathSync(packageRoot);\n\t\tconst realConfigPath = realpathSync(lexicalPath);\n\t\treturn resolveContainedPath(realPackageRoot, realConfigPath);\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction formatPackageName(name: string): string {\n\treturn name.replace(/[^A-Za-z0-9_-]+/g, \"_\").replace(/^[_-]+|[_-]+$/g, \"\") || \"package\";\n}\n\nfunction formatServerName(name: string): string {\n\treturn name.replace(/[^A-Za-z0-9_-]+/g, \"_\").replace(/^[_-]+|[_-]+$/g, \"\") || \"server\";\n}\n"]}
@@ -0,0 +1,21 @@
1
+ import { type KeyId } from "@earendil-works/pi-tui";
2
+ /** The panel keybinding ids the adapter panels resolve through nexus-tui. */
3
+ export type PanelSelectKeybinding = "tui.select.up" | "tui.select.down" | "tui.select.confirm";
4
+ /** Structural subset of nexus-tui's `KeybindingsManager` (which satisfies it). */
5
+ export interface PanelKeybindings {
6
+ matches(data: string, keybinding: PanelSelectKeybinding): boolean;
7
+ getUserBindings?(): Record<string, KeyId | KeyId[] | undefined>;
8
+ }
9
+ /**
10
+ * Key matchers for panel actions: user bindings when a manager is provided,
11
+ * otherwise the previous hardcoded defaults.
12
+ */
13
+ export interface PanelKeys {
14
+ selectUp(data: string): boolean;
15
+ selectDown(data: string): boolean;
16
+ selectConfirm(data: string): boolean;
17
+ save(data: string): boolean;
18
+ saveLabel(): string | null;
19
+ }
20
+ export declare function createPanelKeys(keybindings?: PanelKeybindings): PanelKeys;
21
+ //# sourceMappingURL=panel-keys.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"panel-keys.d.ts","sourceRoot":"","sources":["../../../src/extensions/mcp/panel-keys.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,KAAK,EAAc,MAAM,wBAAwB,CAAC;AAEhE,6EAA6E;AAC7E,MAAM,MAAM,qBAAqB,GAAG,eAAe,GAAG,iBAAiB,GAAG,oBAAoB,CAAC;AAE/F,kFAAkF;AAClF,MAAM,WAAW,gBAAgB;IAChC,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,qBAAqB,GAAG,OAAO,CAAC;IAClE,eAAe,CAAC,IAAI,MAAM,CAAC,MAAM,EAAE,KAAK,GAAG,KAAK,EAAE,GAAG,SAAS,CAAC,CAAC;CAChE;AAED;;;GAGG;AACH,MAAM,WAAW,SAAS;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAChC,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAClC,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IACrC,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAC5B,SAAS,IAAI,MAAM,GAAG,IAAI,CAAC;CAC3B;AAQD,wBAAgB,eAAe,CAAC,WAAW,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAqBzE","sourcesContent":["import { type KeyId, matchesKey } from \"@earendil-works/pi-tui\";\n\n/** The panel keybinding ids the adapter panels resolve through nexus-tui. */\nexport type PanelSelectKeybinding = \"tui.select.up\" | \"tui.select.down\" | \"tui.select.confirm\";\n\n/** Structural subset of nexus-tui's `KeybindingsManager` (which satisfies it). */\nexport interface PanelKeybindings {\n\tmatches(data: string, keybinding: PanelSelectKeybinding): boolean;\n\tgetUserBindings?(): Record<string, KeyId | KeyId[] | undefined>;\n}\n\n/**\n * Key matchers for panel actions: user bindings when a manager is provided,\n * otherwise the previous hardcoded defaults.\n */\nexport interface PanelKeys {\n\tselectUp(data: string): boolean;\n\tselectDown(data: string): boolean;\n\tselectConfirm(data: string): boolean;\n\tsave(data: string): boolean;\n\tsaveLabel(): string | null;\n}\n\nfunction configuredSaveKeys(keybindings?: PanelKeybindings): { keys: KeyId[]; configured: boolean } {\n\tconst explicit = keybindings?.getUserBindings?.()[\"mcp.panel.save\"];\n\tif (explicit !== undefined) return { keys: Array.isArray(explicit) ? explicit : [explicit], configured: true };\n\treturn { keys: [], configured: false };\n}\n\nexport function createPanelKeys(keybindings?: PanelKeybindings): PanelKeys {\n\tconst saveBinding = configuredSaveKeys(keybindings);\n\tif (keybindings) {\n\t\treturn {\n\t\t\tselectUp: (data) => keybindings.matches(data, \"tui.select.up\"),\n\t\t\tselectDown: (data) => keybindings.matches(data, \"tui.select.down\"),\n\t\t\tselectConfirm: (data) => keybindings.matches(data, \"tui.select.confirm\"),\n\t\t\tsave: (data) =>\n\t\t\t\tsaveBinding.keys.length > 0\n\t\t\t\t\t? saveBinding.keys.some((key) => matchesKey(data, key))\n\t\t\t\t\t: !saveBinding.configured && matchesKey(data, \"ctrl+s\"),\n\t\t\tsaveLabel: () => saveBinding.keys[0] ?? (saveBinding.configured ? null : \"ctrl+s\"),\n\t\t};\n\t}\n\treturn {\n\t\tselectUp: (data) => matchesKey(data, \"up\"),\n\t\tselectDown: (data) => matchesKey(data, \"down\"),\n\t\tselectConfirm: (data) => matchesKey(data, \"return\"),\n\t\tsave: (data) => matchesKey(data, \"ctrl+s\"),\n\t\tsaveLabel: () => \"ctrl+s\",\n\t};\n}\n"]}
@@ -0,0 +1,29 @@
1
+ import { matchesKey } from "@earendil-works/pi-tui";
2
+ function configuredSaveKeys(keybindings) {
3
+ const explicit = keybindings?.getUserBindings?.()["mcp.panel.save"];
4
+ if (explicit !== undefined)
5
+ return { keys: Array.isArray(explicit) ? explicit : [explicit], configured: true };
6
+ return { keys: [], configured: false };
7
+ }
8
+ export function createPanelKeys(keybindings) {
9
+ const saveBinding = configuredSaveKeys(keybindings);
10
+ if (keybindings) {
11
+ return {
12
+ selectUp: (data) => keybindings.matches(data, "tui.select.up"),
13
+ selectDown: (data) => keybindings.matches(data, "tui.select.down"),
14
+ selectConfirm: (data) => keybindings.matches(data, "tui.select.confirm"),
15
+ save: (data) => saveBinding.keys.length > 0
16
+ ? saveBinding.keys.some((key) => matchesKey(data, key))
17
+ : !saveBinding.configured && matchesKey(data, "ctrl+s"),
18
+ saveLabel: () => saveBinding.keys[0] ?? (saveBinding.configured ? null : "ctrl+s"),
19
+ };
20
+ }
21
+ return {
22
+ selectUp: (data) => matchesKey(data, "up"),
23
+ selectDown: (data) => matchesKey(data, "down"),
24
+ selectConfirm: (data) => matchesKey(data, "return"),
25
+ save: (data) => matchesKey(data, "ctrl+s"),
26
+ saveLabel: () => "ctrl+s",
27
+ };
28
+ }
29
+ //# sourceMappingURL=panel-keys.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"panel-keys.js","sourceRoot":"","sources":["../../../src/extensions/mcp/panel-keys.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAuBhE,SAAS,kBAAkB,CAAC,WAA8B,EAA0C;IACnG,MAAM,QAAQ,GAAG,WAAW,EAAE,eAAe,EAAE,EAAE,CAAC,gBAAgB,CAAC,CAAC;IACpE,IAAI,QAAQ,KAAK,SAAS;QAAE,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;IAC/G,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC;AAAA,CACvC;AAED,MAAM,UAAU,eAAe,CAAC,WAA8B,EAAa;IAC1E,MAAM,WAAW,GAAG,kBAAkB,CAAC,WAAW,CAAC,CAAC;IACpD,IAAI,WAAW,EAAE,CAAC;QACjB,OAAO;YACN,QAAQ,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,WAAW,CAAC,OAAO,CAAC,IAAI,EAAE,eAAe,CAAC;YAC9D,UAAU,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,WAAW,CAAC,OAAO,CAAC,IAAI,EAAE,iBAAiB,CAAC;YAClE,aAAa,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,WAAW,CAAC,OAAO,CAAC,IAAI,EAAE,oBAAoB,CAAC;YACxE,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE,CACd,WAAW,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC;gBAC1B,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;gBACvD,CAAC,CAAC,CAAC,WAAW,CAAC,UAAU,IAAI,UAAU,CAAC,IAAI,EAAE,QAAQ,CAAC;YACzD,SAAS,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC;SAClF,CAAC;IACH,CAAC;IACD,OAAO;QACN,QAAQ,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC;QAC1C,UAAU,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC;QAC9C,aAAa,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,EAAE,QAAQ,CAAC;QACnD,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,EAAE,QAAQ,CAAC;QAC1C,SAAS,EAAE,GAAG,EAAE,CAAC,QAAQ;KACzB,CAAC;AAAA,CACF","sourcesContent":["import { type KeyId, matchesKey } from \"@earendil-works/pi-tui\";\n\n/** The panel keybinding ids the adapter panels resolve through nexus-tui. */\nexport type PanelSelectKeybinding = \"tui.select.up\" | \"tui.select.down\" | \"tui.select.confirm\";\n\n/** Structural subset of nexus-tui's `KeybindingsManager` (which satisfies it). */\nexport interface PanelKeybindings {\n\tmatches(data: string, keybinding: PanelSelectKeybinding): boolean;\n\tgetUserBindings?(): Record<string, KeyId | KeyId[] | undefined>;\n}\n\n/**\n * Key matchers for panel actions: user bindings when a manager is provided,\n * otherwise the previous hardcoded defaults.\n */\nexport interface PanelKeys {\n\tselectUp(data: string): boolean;\n\tselectDown(data: string): boolean;\n\tselectConfirm(data: string): boolean;\n\tsave(data: string): boolean;\n\tsaveLabel(): string | null;\n}\n\nfunction configuredSaveKeys(keybindings?: PanelKeybindings): { keys: KeyId[]; configured: boolean } {\n\tconst explicit = keybindings?.getUserBindings?.()[\"mcp.panel.save\"];\n\tif (explicit !== undefined) return { keys: Array.isArray(explicit) ? explicit : [explicit], configured: true };\n\treturn { keys: [], configured: false };\n}\n\nexport function createPanelKeys(keybindings?: PanelKeybindings): PanelKeys {\n\tconst saveBinding = configuredSaveKeys(keybindings);\n\tif (keybindings) {\n\t\treturn {\n\t\t\tselectUp: (data) => keybindings.matches(data, \"tui.select.up\"),\n\t\t\tselectDown: (data) => keybindings.matches(data, \"tui.select.down\"),\n\t\t\tselectConfirm: (data) => keybindings.matches(data, \"tui.select.confirm\"),\n\t\t\tsave: (data) =>\n\t\t\t\tsaveBinding.keys.length > 0\n\t\t\t\t\t? saveBinding.keys.some((key) => matchesKey(data, key))\n\t\t\t\t\t: !saveBinding.configured && matchesKey(data, \"ctrl+s\"),\n\t\t\tsaveLabel: () => saveBinding.keys[0] ?? (saveBinding.configured ? null : \"ctrl+s\"),\n\t\t};\n\t}\n\treturn {\n\t\tselectUp: (data) => matchesKey(data, \"up\"),\n\t\tselectDown: (data) => matchesKey(data, \"down\"),\n\t\tselectConfirm: (data) => matchesKey(data, \"return\"),\n\t\tsave: (data) => matchesKey(data, \"ctrl+s\"),\n\t\tsaveLabel: () => \"ctrl+s\",\n\t};\n}\n"]}
@@ -0,0 +1,63 @@
1
+ import type { GetPromptResult } from "@modelcontextprotocol/client";
2
+ import type { ExtensionAPI, ExtensionCommandContext } from "../../core/extensions/types.ts";
3
+ import type { McpExtensionState } from "./state.ts";
4
+ import { formatPromptCommandName, type McpConfig, type PromptMetadata } from "./types.ts";
5
+ /**
6
+ * Resolve prompt metadata for slash-command registration at extension load
7
+ * time. Mirrors `resolveDirectTools`: reads the persistent metadata cache so
8
+ * commands are available before any server connects.
9
+ */
10
+ export declare function resolveCachedPrompts(config: McpConfig): PromptMetadata[];
11
+ /**
12
+ * Parse a slash-command argument string into positional and named MCP prompt
13
+ * arguments. Supports bash-style quoting so callers can pass values with
14
+ * spaces:
15
+ *
16
+ * /mcp__demo__brief today "important tasks"
17
+ * /mcp__demo__brief day=today topic="important tasks"
18
+ */
19
+ export declare function parsePromptArgs(input: string): {
20
+ positional: string[];
21
+ named: Record<string, string>;
22
+ };
23
+ export interface ResolvedPromptArgs {
24
+ ok: boolean;
25
+ /** Present when `ok === true`. */
26
+ args?: Record<string, string>;
27
+ /** Present when `ok === false`. */
28
+ error?: string;
29
+ }
30
+ /**
31
+ * Map positional and named arguments onto the prompt's declared argument
32
+ * list. Named arguments win over positional when both target the same slot.
33
+ * Missing required arguments produce a helpful usage message that the
34
+ * command handler surfaces via `ctx.ui.notify`.
35
+ */
36
+ export declare function resolvePromptArgs(metadata: PromptMetadata, parsed: {
37
+ positional: string[];
38
+ named: Record<string, string>;
39
+ }): ResolvedPromptArgs;
40
+ /**
41
+ * Flatten a `GetPromptResult` into a single string suitable for
42
+ * `nexus.sendUserMessage`. MCP prompts can contain multiple messages with
43
+ * mixed roles; we preserve role attribution as inline markers so the model
44
+ * still sees the intended conversational shape without needing a
45
+ * multi-message replay API on the nexus side.
46
+ */
47
+ export declare function formatPromptResult(result: GetPromptResult): string;
48
+ /**
49
+ * Build the nexus command definition for a single MCP prompt. Registered once
50
+ * per prompt at extension load time from the metadata cache; the same
51
+ * factory is reused by tests to invoke the handler without a running nexus.
52
+ */
53
+ export declare function createPromptCommand(nexus: ExtensionAPI, getState: () => McpExtensionState | null, metadata: PromptMetadata): {
54
+ description: string;
55
+ handler: (args: string, ctx: ExtensionCommandContext) => Promise<void>;
56
+ };
57
+ /**
58
+ * Public helper used by `/mcp prompts` to render the list of prompts known
59
+ * to the adapter, whether from a live connection or the metadata cache.
60
+ */
61
+ export declare function listAllPromptMetadata(state: McpExtensionState): PromptMetadata[];
62
+ export { formatPromptCommandName };
63
+ //# sourceMappingURL=prompts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../../src/extensions/mcp/prompts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAiB,MAAM,8BAA8B,CAAC;AACnF,OAAO,KAAK,EAAE,YAAY,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAI5F,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,EAAE,uBAAuB,EAAoB,KAAK,SAAS,EAAE,KAAK,cAAc,EAAE,MAAM,YAAY,CAAC;AAG5G;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,GAAG,cAAc,EAAE,CAexE;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG;IAAE,UAAU,EAAE,MAAM,EAAE,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,CAmBtG;AA+DD,MAAM,WAAW,kBAAkB;IAClC,EAAE,EAAE,OAAO,CAAC;IACZ,kCAAkC;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,mCAAmC;IACnC,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAChC,QAAQ,EAAE,cAAc,EACxB,MAAM,EAAE;IAAE,UAAU,EAAE,MAAM,EAAE,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GAC7D,kBAAkB,CAyBpB;AAQD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,CAYlE;AA2BD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAClC,KAAK,EAAE,YAAY,EACnB,QAAQ,EAAE,MAAM,iBAAiB,GAAG,IAAI,EACxC,QAAQ,EAAE,cAAc;;;EA8FxB;AAeD;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,iBAAiB,GAAG,cAAc,EAAE,CAKhF;AAID,OAAO,EAAE,uBAAuB,EAAE,CAAC","sourcesContent":["import type { GetPromptResult, PromptMessage } from \"@modelcontextprotocol/client\";\nimport type { ExtensionAPI, ExtensionCommandContext } from \"../../core/extensions/types.ts\";\nimport { lazyConnect } from \"./init.ts\";\nimport { logger } from \"./logger.ts\";\nimport { isServerCacheValid, loadMetadataCache, reconstructPromptMetadata } from \"./metadata-cache.ts\";\nimport type { McpExtensionState } from \"./state.ts\";\nimport { formatPromptCommandName, isServerDisabled, type McpConfig, type PromptMetadata } from \"./types.ts\";\nimport { truncateAtWord } from \"./utils.ts\";\n\n/**\n * Resolve prompt metadata for slash-command registration at extension load\n * time. Mirrors `resolveDirectTools`: reads the persistent metadata cache so\n * commands are available before any server connects.\n */\nexport function resolveCachedPrompts(config: McpConfig): PromptMetadata[] {\n\tconst cache = loadMetadataCache();\n\tif (!cache?.servers) return [];\n\n\tconst prefix = config.settings?.toolPrefix ?? \"server\";\n\tconst specs: PromptMetadata[] = [];\n\n\tfor (const [serverName, entry] of Object.entries(cache.servers)) {\n\t\tconst definition = config.mcpServers[serverName];\n\t\tif (!definition || isServerDisabled(definition)) continue;\n\t\tif (!entry?.prompts?.length || !isServerCacheValid(entry, definition)) continue;\n\t\tspecs.push(...reconstructPromptMetadata(serverName, entry.prompts, prefix, definition));\n\t}\n\n\treturn specs;\n}\n\n/**\n * Parse a slash-command argument string into positional and named MCP prompt\n * arguments. Supports bash-style quoting so callers can pass values with\n * spaces:\n *\n * /mcp__demo__brief today \"important tasks\"\n * /mcp__demo__brief day=today topic=\"important tasks\"\n */\nexport function parsePromptArgs(input: string): { positional: string[]; named: Record<string, string> } {\n\tconst positional: string[] = [];\n\tconst named: Record<string, string> = {};\n\n\tconst tokens = tokenizeArgs(input);\n\tfor (const token of tokens) {\n\t\tconst eq = findUnquotedEquals(token);\n\t\tif (eq > 0) {\n\t\t\tconst key = token.slice(0, eq).trim();\n\t\t\tconst value = stripQuotes(token.slice(eq + 1).trim());\n\t\t\tif (key) {\n\t\t\t\tnamed[key] = value;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t\tpositional.push(stripQuotes(token));\n\t}\n\n\treturn { positional, named };\n}\n\nfunction tokenizeArgs(input: string): string[] {\n\tconst tokens: string[] = [];\n\tlet current = \"\";\n\tlet quote: '\"' | \"'\" | null = null;\n\tlet escaped = false;\n\n\tfor (const char of input) {\n\t\tif (escaped) {\n\t\t\tcurrent += char;\n\t\t\tescaped = false;\n\t\t\tcontinue;\n\t\t}\n\t\tif (char === \"\\\\\" && quote !== \"'\") {\n\t\t\tescaped = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (quote) {\n\t\t\tcurrent += char;\n\t\t\tif (char === quote) quote = null;\n\t\t\tcontinue;\n\t\t}\n\t\tif (char === '\"' || char === \"'\") {\n\t\t\tquote = char;\n\t\t\tcurrent += char;\n\t\t\tcontinue;\n\t\t}\n\t\tif (/\\s/.test(char)) {\n\t\t\tif (current.length > 0) {\n\t\t\t\ttokens.push(current);\n\t\t\t\tcurrent = \"\";\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tcurrent += char;\n\t}\n\n\tif (current.length > 0) tokens.push(current);\n\treturn tokens;\n}\n\nfunction findUnquotedEquals(token: string): number {\n\tlet quote: '\"' | \"'\" | null = null;\n\tfor (let i = 0; i < token.length; i++) {\n\t\tconst ch = token[i];\n\t\tif (quote) {\n\t\t\tif (ch === quote) quote = null;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === '\"' || ch === \"'\") quote = ch;\n\t\telse if (ch === \"=\") return i;\n\t}\n\treturn -1;\n}\n\nfunction stripQuotes(value: string): string {\n\tif (value.length >= 2 && (value.startsWith('\"') || value.startsWith(\"'\")) && value.endsWith(value.charAt(0))) {\n\t\treturn value.slice(1, -1);\n\t}\n\treturn value;\n}\n\nexport interface ResolvedPromptArgs {\n\tok: boolean;\n\t/** Present when `ok === true`. */\n\targs?: Record<string, string>;\n\t/** Present when `ok === false`. */\n\terror?: string;\n}\n\n/**\n * Map positional and named arguments onto the prompt's declared argument\n * list. Named arguments win over positional when both target the same slot.\n * Missing required arguments produce a helpful usage message that the\n * command handler surfaces via `ctx.ui.notify`.\n */\nexport function resolvePromptArgs(\n\tmetadata: PromptMetadata,\n\tparsed: { positional: string[]; named: Record<string, string> },\n): ResolvedPromptArgs {\n\tconst args: Record<string, string> = {};\n\n\tconst declared = metadata.arguments;\n\tlet positionalIndex = 0;\n\tfor (const argDef of declared) {\n\t\tconst value = parsed.named[argDef.name] ?? parsed.positional[positionalIndex++];\n\t\tif (value !== undefined && value !== \"\") {\n\t\t\targs[argDef.name] = value;\n\t\t}\n\t}\n\n\t// Preserve named arguments the prompt did not declare so servers with\n\t// permissive schemas still receive them. The MCP spec allows arbitrary\n\t// string key/values in `prompts/get` params.arguments.\n\tfor (const [key, value] of Object.entries(parsed.named)) {\n\t\tif (!(key in args)) args[key] = value;\n\t}\n\n\tconst missing = declared.filter((a) => a.required && (args[a.name] === undefined || args[a.name] === \"\"));\n\tif (missing.length > 0) {\n\t\treturn { ok: false, error: buildUsageMessage(metadata, missing) };\n\t}\n\n\treturn { ok: true, args };\n}\n\nfunction buildUsageMessage(metadata: PromptMetadata, missing: PromptMetadata[\"arguments\"]): string {\n\tconst usage = metadata.arguments.map((a) => (a.required ? `<${a.name}>` : `[${a.name}]`)).join(\" \");\n\tconst missingList = missing.map((a) => a.name).join(\", \");\n\treturn `Missing required argument${missing.length > 1 ? \"s\" : \"\"}: ${missingList}.\\nUsage: /${metadata.commandName} ${usage}`.trim();\n}\n\n/**\n * Flatten a `GetPromptResult` into a single string suitable for\n * `nexus.sendUserMessage`. MCP prompts can contain multiple messages with\n * mixed roles; we preserve role attribution as inline markers so the model\n * still sees the intended conversational shape without needing a\n * multi-message replay API on the nexus side.\n */\nexport function formatPromptResult(result: GetPromptResult): string {\n\tconst lines: string[] = [];\n\tfor (const message of result.messages) {\n\t\tconst text = extractMessageText(message);\n\t\tif (!text) continue;\n\t\tif (message.role === \"user\" && result.messages.length === 1) {\n\t\t\tlines.push(text);\n\t\t} else {\n\t\t\tlines.push(`[${message.role}] ${text}`);\n\t\t}\n\t}\n\treturn lines.join(\"\\n\\n\").trim();\n}\n\nfunction extractMessageText(message: PromptMessage): string {\n\tconst content = message.content;\n\tif (!content || typeof content !== \"object\") return \"\";\n\tswitch (content.type) {\n\t\tcase \"text\":\n\t\t\treturn content.text ?? \"\";\n\t\tcase \"resource\": {\n\t\t\tconst resource = content.resource;\n\t\t\tif (!resource) return \"\";\n\t\t\tif (\"text\" in resource && typeof resource.text === \"string\") {\n\t\t\t\treturn `[resource ${resource.uri}]\\n${resource.text}`;\n\t\t\t}\n\t\t\treturn `[resource ${resource.uri}]`;\n\t\t}\n\t\tcase \"resource_link\":\n\t\t\treturn `[resource_link ${content.uri ?? \"\"}${content.name ? ` — ${content.name}` : \"\"}]`;\n\t\tcase \"image\":\n\t\t\treturn `[image ${content.mimeType ?? \"unknown\"}${content.data ? \" (embedded)\" : \"\"}]`;\n\t\tcase \"audio\":\n\t\t\treturn `[audio ${content.mimeType ?? \"unknown\"}]`;\n\t\tdefault:\n\t\t\treturn \"\";\n\t}\n}\n\n/**\n * Build the nexus command definition for a single MCP prompt. Registered once\n * per prompt at extension load time from the metadata cache; the same\n * factory is reused by tests to invoke the handler without a running nexus.\n */\nexport function createPromptCommand(\n\tnexus: ExtensionAPI,\n\tgetState: () => McpExtensionState | null,\n\tmetadata: PromptMetadata,\n) {\n\tconst description = buildCommandDescription(metadata);\n\n\treturn {\n\t\tdescription,\n\t\thandler: async (args: string, ctx: ExtensionCommandContext) => {\n\t\t\tconst state = getState();\n\t\t\tif (!state) {\n\t\t\t\tif (ctx.hasUI) ctx.ui.notify(\"MCP not initialized\", \"error\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst liveMetadata = findLivePromptMetadata(state, metadata.serverName, metadata.originalName);\n\t\t\tif (state.promptMetadataLive?.has(metadata.serverName) && !liveMetadata) {\n\t\t\t\tif (ctx.hasUI) {\n\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t`MCP prompt \"${metadata.originalName}\" is no longer advertised by server \"${metadata.serverName}\". Run /mcp reconnect to refresh.`,\n\t\t\t\t\t\t\"error\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst live = liveMetadata ?? metadata;\n\t\t\tconst parsed = parsePromptArgs(args ?? \"\");\n\t\t\tconst resolved = resolvePromptArgs(live, parsed);\n\t\t\tif (!resolved.ok) {\n\t\t\t\tif (ctx.hasUI) ctx.ui.notify(resolved.error ?? \"Invalid prompt arguments\", \"error\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst promptArgs = resolved.args ?? {};\n\n\t\t\tif (!state.config.mcpServers[metadata.serverName]) {\n\t\t\t\tif (ctx.hasUI) {\n\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t`MCP prompt \"${live.originalName}\" is no longer configured. Run /mcp reconnect to refresh.`,\n\t\t\t\t\t\t\"error\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst connected = await lazyConnect(state, metadata.serverName, ctx.signal);\n\t\t\tif (!connected) {\n\t\t\t\tif (ctx.hasUI) {\n\t\t\t\t\tconst conn = state.manager.getConnection(metadata.serverName);\n\t\t\t\t\tconst message =\n\t\t\t\t\t\tconn?.status === \"needs-auth\"\n\t\t\t\t\t\t\t? `MCP server \"${metadata.serverName}\" needs authentication. Run /mcp-auth ${metadata.serverName}.`\n\t\t\t\t\t\t\t: `MCP server \"${metadata.serverName}\" is not available. Run /mcp reconnect ${metadata.serverName}.`;\n\t\t\t\t\tctx.ui.notify(message, \"error\");\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst refreshed = findLivePromptMetadata(state, metadata.serverName, metadata.originalName);\n\t\t\tif (state.promptMetadataLive?.has(metadata.serverName) && !refreshed) {\n\t\t\t\tif (ctx.hasUI) {\n\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t`MCP prompt \"${metadata.originalName}\" is no longer advertised by server \"${metadata.serverName}\". Run /mcp reconnect to refresh.`,\n\t\t\t\t\t\t\"error\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst dispatchMetadata = refreshed ?? live;\n\t\t\tlet result: GetPromptResult;\n\t\t\ttry {\n\t\t\t\tresult = await state.manager.getPrompt(\n\t\t\t\t\tmetadata.serverName,\n\t\t\t\t\tdispatchMetadata.originalName,\n\t\t\t\t\tObject.keys(promptArgs).length > 0 ? promptArgs : undefined,\n\t\t\t\t\tctx.signal,\n\t\t\t\t);\n\t\t\t} catch (error) {\n\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\t\tlogger.debug(`MCP prompt \"${live.originalName}\" on ${metadata.serverName} failed: ${message}`);\n\t\t\t\tif (ctx.hasUI) {\n\t\t\t\t\tctx.ui.notify(`MCP prompt \"${live.originalName}\" failed: ${message}`, \"error\");\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst text = formatPromptResult(result);\n\t\t\tif (!text) {\n\t\t\t\tif (ctx.hasUI) {\n\t\t\t\t\tctx.ui.notify(`MCP prompt \"${live.originalName}\" returned no text content.`, \"warning\");\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tnexus.sendUserMessage(text);\n\t\t},\n\t};\n}\n\nfunction findLivePromptMetadata(\n\tstate: McpExtensionState,\n\tserverName: string,\n\toriginalName: string,\n): PromptMetadata | undefined {\n\treturn state.promptMetadata?.get(serverName)?.find((p) => p.originalName === originalName);\n}\n\nfunction buildCommandDescription(metadata: PromptMetadata): string {\n\tconst base = metadata.description || metadata.title || `MCP prompt from ${metadata.serverName}`;\n\treturn truncateAtWord(`MCP: ${base}`, 120) || `MCP prompt from ${metadata.serverName}`;\n}\n\n/**\n * Public helper used by `/mcp prompts` to render the list of prompts known\n * to the adapter, whether from a live connection or the metadata cache.\n */\nexport function listAllPromptMetadata(state: McpExtensionState): PromptMetadata[] {\n\tconst flat: PromptMetadata[] = [];\n\tfor (const list of state.promptMetadata?.values() ?? []) flat.push(...list);\n\tflat.sort((a, b) => a.commandName.localeCompare(b.commandName));\n\treturn flat;\n}\n\n// Re-exported so index.ts can format cache-only prompt-command names without\n// duplicating the namespace logic.\nexport { formatPromptCommandName };\n"]}