@openeryc/pi-coding-agent 0.75.28 → 0.75.29

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 (301) hide show
  1. package/CHANGELOG.md +0 -3
  2. package/dist/cli/config-selector.d.ts +13 -1
  3. package/dist/cli/config-selector.d.ts.map +1 -1
  4. package/dist/cli/config-selector.js +29 -4
  5. package/dist/cli/config-selector.js.map +1 -1
  6. package/dist/cli/list-models.d.ts.map +1 -1
  7. package/dist/cli/list-models.js +1 -1
  8. package/dist/cli/list-models.js.map +1 -1
  9. package/dist/cli/session-picker.d.ts +9 -0
  10. package/dist/cli/session-picker.d.ts.map +1 -0
  11. package/dist/cli/session-picker.js +35 -0
  12. package/dist/cli/session-picker.js.map +1 -0
  13. package/dist/core/agent-session.d.ts +2 -0
  14. package/dist/core/agent-session.d.ts.map +1 -1
  15. package/dist/core/agent-session.js +20 -12
  16. package/dist/core/agent-session.js.map +1 -1
  17. package/dist/core/export-html/tool-renderer.d.ts.map +1 -1
  18. package/dist/core/export-html/tool-renderer.js.map +1 -1
  19. package/dist/core/extensions/loader.d.ts.map +1 -1
  20. package/dist/core/extensions/loader.js +1 -1
  21. package/dist/core/extensions/loader.js.map +1 -1
  22. package/dist/core/extensions/runner.d.ts +1 -1
  23. package/dist/core/extensions/runner.d.ts.map +1 -1
  24. package/dist/core/extensions/runner.js +1 -1
  25. package/dist/core/extensions/runner.js.map +1 -1
  26. package/dist/core/extensions/types.d.ts +1 -1
  27. package/dist/core/extensions/types.d.ts.map +1 -1
  28. package/dist/core/extensions/types.js.map +1 -1
  29. package/dist/core/keybindings.d.ts +135 -7
  30. package/dist/core/keybindings.d.ts.map +1 -1
  31. package/dist/core/keybindings.js +1 -1
  32. package/dist/core/keybindings.js.map +1 -1
  33. package/dist/core/mcp/client.d.ts +11 -30
  34. package/dist/core/mcp/client.d.ts.map +1 -1
  35. package/dist/core/mcp/client.js +110 -55
  36. package/dist/core/mcp/client.js.map +1 -1
  37. package/dist/core/mcp/index.d.ts +3 -1
  38. package/dist/core/mcp/index.d.ts.map +1 -1
  39. package/dist/core/mcp/index.js.map +1 -1
  40. package/dist/core/mcp/manager.d.ts +9 -3
  41. package/dist/core/mcp/manager.d.ts.map +1 -1
  42. package/dist/core/mcp/manager.js +105 -71
  43. package/dist/core/mcp/manager.js.map +1 -1
  44. package/dist/core/mcp/types.d.ts +86 -0
  45. package/dist/core/mcp/types.d.ts.map +1 -0
  46. package/dist/core/mcp/types.js +8 -0
  47. package/dist/core/mcp/types.js.map +1 -0
  48. package/dist/core/tools/bash.d.ts.map +1 -1
  49. package/dist/core/tools/bash.js +1 -1
  50. package/dist/core/tools/bash.js.map +1 -1
  51. package/dist/core/tools/edit.d.ts +1 -1
  52. package/dist/core/tools/edit.d.ts.map +1 -1
  53. package/dist/core/tools/edit.js +1 -1
  54. package/dist/core/tools/edit.js.map +1 -1
  55. package/dist/core/tools/find.d.ts.map +1 -1
  56. package/dist/core/tools/find.js +1 -1
  57. package/dist/core/tools/find.js.map +1 -1
  58. package/dist/core/tools/grep.d.ts.map +1 -1
  59. package/dist/core/tools/grep.js +1 -1
  60. package/dist/core/tools/grep.js.map +1 -1
  61. package/dist/core/tools/ls.d.ts.map +1 -1
  62. package/dist/core/tools/ls.js +1 -1
  63. package/dist/core/tools/ls.js.map +1 -1
  64. package/dist/core/tools/read.d.ts.map +1 -1
  65. package/dist/core/tools/read.js +1 -1
  66. package/dist/core/tools/read.js.map +1 -1
  67. package/dist/core/tools/render-utils.d.ts.map +1 -1
  68. package/dist/core/tools/render-utils.js +1 -1
  69. package/dist/core/tools/render-utils.js.map +1 -1
  70. package/dist/core/tools/write.d.ts.map +1 -1
  71. package/dist/core/tools/write.js +1 -1
  72. package/dist/core/tools/write.js.map +1 -1
  73. package/dist/index.d.ts +3 -5
  74. package/dist/index.d.ts.map +1 -1
  75. package/dist/index.js +5 -7
  76. package/dist/index.js.map +1 -1
  77. package/dist/main.d.ts.map +1 -1
  78. package/dist/main.js +106 -92
  79. package/dist/main.js.map +1 -1
  80. package/dist/modes/index.d.ts +4 -0
  81. package/dist/modes/index.d.ts.map +1 -1
  82. package/dist/modes/index.js +4 -0
  83. package/dist/modes/index.js.map +1 -1
  84. package/dist/modes/interactive/assets/clankolas.png +0 -0
  85. package/dist/modes/interactive/components/armin.d.ts +34 -0
  86. package/dist/modes/interactive/components/armin.d.ts.map +1 -0
  87. package/dist/modes/interactive/components/armin.js +333 -0
  88. package/dist/modes/interactive/components/armin.js.map +1 -0
  89. package/dist/modes/interactive/components/assistant-message.d.ts +20 -0
  90. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -0
  91. package/dist/modes/interactive/components/assistant-message.js +121 -0
  92. package/dist/modes/interactive/components/assistant-message.js.map +1 -0
  93. package/dist/modes/interactive/components/bash-execution.d.ts +34 -0
  94. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -0
  95. package/dist/modes/interactive/components/bash-execution.js +175 -0
  96. package/dist/modes/interactive/components/bash-execution.js.map +1 -0
  97. package/dist/modes/interactive/components/bordered-loader.d.ts +16 -0
  98. package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -0
  99. package/dist/modes/interactive/components/bordered-loader.js +54 -0
  100. package/dist/modes/interactive/components/bordered-loader.js.map +1 -0
  101. package/dist/modes/interactive/components/branch-summary-message.d.ts +16 -0
  102. package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -0
  103. package/dist/modes/interactive/components/branch-summary-message.js +44 -0
  104. package/dist/modes/interactive/components/branch-summary-message.js.map +1 -0
  105. package/dist/modes/interactive/components/compaction-summary-message.d.ts +16 -0
  106. package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -0
  107. package/dist/modes/interactive/components/compaction-summary-message.js +45 -0
  108. package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -0
  109. package/dist/modes/interactive/components/config-selector.d.ts +71 -0
  110. package/dist/modes/interactive/components/config-selector.d.ts.map +1 -0
  111. package/dist/modes/interactive/components/config-selector.js +506 -0
  112. package/dist/modes/interactive/components/config-selector.js.map +1 -0
  113. package/dist/modes/interactive/components/countdown-timer.d.ts +14 -0
  114. package/dist/modes/interactive/components/countdown-timer.d.ts.map +1 -0
  115. package/dist/modes/interactive/components/countdown-timer.js +33 -0
  116. package/dist/modes/interactive/components/countdown-timer.js.map +1 -0
  117. package/dist/modes/interactive/components/custom-editor.d.ts +21 -0
  118. package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -0
  119. package/dist/modes/interactive/components/custom-editor.js +70 -0
  120. package/dist/modes/interactive/components/custom-editor.js.map +1 -0
  121. package/dist/modes/interactive/components/custom-message.d.ts +20 -0
  122. package/dist/modes/interactive/components/custom-message.d.ts.map +1 -0
  123. package/dist/modes/interactive/components/custom-message.js +79 -0
  124. package/dist/modes/interactive/components/custom-message.js.map +1 -0
  125. package/dist/modes/interactive/components/daxnuts.d.ts +23 -0
  126. package/dist/modes/interactive/components/daxnuts.d.ts.map +1 -0
  127. package/dist/modes/interactive/components/daxnuts.js +140 -0
  128. package/dist/modes/interactive/components/daxnuts.js.map +1 -0
  129. package/dist/modes/interactive/components/diff.d.ts +8 -1
  130. package/dist/modes/interactive/components/diff.d.ts.map +1 -1
  131. package/dist/modes/interactive/components/diff.js +131 -2
  132. package/dist/modes/interactive/components/diff.js.map +1 -1
  133. package/dist/modes/interactive/components/dynamic-border.d.ts +15 -0
  134. package/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -0
  135. package/dist/modes/interactive/components/dynamic-border.js +21 -0
  136. package/dist/modes/interactive/components/dynamic-border.js.map +1 -0
  137. package/dist/modes/interactive/components/earendil-announcement.d.ts +5 -0
  138. package/dist/modes/interactive/components/earendil-announcement.d.ts.map +1 -0
  139. package/dist/modes/interactive/components/earendil-announcement.js +40 -0
  140. package/dist/modes/interactive/components/earendil-announcement.js.map +1 -0
  141. package/dist/modes/interactive/components/extension-editor.d.ts +20 -0
  142. package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -0
  143. package/dist/modes/interactive/components/extension-editor.js +119 -0
  144. package/dist/modes/interactive/components/extension-editor.js.map +1 -0
  145. package/dist/modes/interactive/components/extension-input.d.ts +23 -0
  146. package/dist/modes/interactive/components/extension-input.d.ts.map +1 -0
  147. package/dist/modes/interactive/components/extension-input.js +61 -0
  148. package/dist/modes/interactive/components/extension-input.js.map +1 -0
  149. package/dist/modes/interactive/components/extension-selector.d.ts +26 -0
  150. package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -0
  151. package/dist/modes/interactive/components/extension-selector.js +83 -0
  152. package/dist/modes/interactive/components/extension-selector.js.map +1 -0
  153. package/dist/modes/interactive/components/footer.d.ts +27 -0
  154. package/dist/modes/interactive/components/footer.d.ts.map +1 -0
  155. package/dist/modes/interactive/components/footer.js +201 -0
  156. package/dist/modes/interactive/components/footer.js.map +1 -0
  157. package/dist/modes/interactive/components/index.d.ts +32 -0
  158. package/dist/modes/interactive/components/index.d.ts.map +1 -0
  159. package/dist/modes/interactive/components/index.js +33 -0
  160. package/dist/modes/interactive/components/index.js.map +1 -0
  161. package/dist/modes/interactive/components/keybinding-hints.d.ts +12 -2
  162. package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
  163. package/dist/modes/interactive/components/keybinding-hints.js +33 -4
  164. package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
  165. package/dist/modes/interactive/components/login-dialog.d.ts +46 -0
  166. package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -0
  167. package/dist/modes/interactive/components/login-dialog.js +160 -0
  168. package/dist/modes/interactive/components/login-dialog.js.map +1 -0
  169. package/dist/modes/interactive/components/model-selector.d.ts +47 -0
  170. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -0
  171. package/dist/modes/interactive/components/model-selector.js +278 -0
  172. package/dist/modes/interactive/components/model-selector.js.map +1 -0
  173. package/dist/modes/interactive/components/oauth-selector.d.ts +31 -0
  174. package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -0
  175. package/dist/modes/interactive/components/oauth-selector.js +165 -0
  176. package/dist/modes/interactive/components/oauth-selector.js.map +1 -0
  177. package/dist/modes/interactive/components/scoped-models-selector.d.ts +42 -0
  178. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -0
  179. package/dist/modes/interactive/components/scoped-models-selector.js +290 -0
  180. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -0
  181. package/dist/modes/interactive/components/session-selector-search.d.ts +23 -0
  182. package/dist/modes/interactive/components/session-selector-search.d.ts.map +1 -0
  183. package/dist/modes/interactive/components/session-selector-search.js +155 -0
  184. package/dist/modes/interactive/components/session-selector-search.js.map +1 -0
  185. package/dist/modes/interactive/components/session-selector.d.ts +96 -0
  186. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -0
  187. package/dist/modes/interactive/components/session-selector.js +861 -0
  188. package/dist/modes/interactive/components/session-selector.js.map +1 -0
  189. package/dist/modes/interactive/components/settings-selector.d.ts +69 -0
  190. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -0
  191. package/dist/modes/interactive/components/settings-selector.js +390 -0
  192. package/dist/modes/interactive/components/settings-selector.js.map +1 -0
  193. package/dist/modes/interactive/components/show-images-selector.d.ts +10 -0
  194. package/dist/modes/interactive/components/show-images-selector.d.ts.map +1 -0
  195. package/dist/modes/interactive/components/show-images-selector.js +39 -0
  196. package/dist/modes/interactive/components/show-images-selector.js.map +1 -0
  197. package/dist/modes/interactive/components/skill-invocation-message.d.ts +17 -0
  198. package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -0
  199. package/dist/modes/interactive/components/skill-invocation-message.js +47 -0
  200. package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -0
  201. package/dist/modes/interactive/components/theme-selector.d.ts +11 -0
  202. package/dist/modes/interactive/components/theme-selector.d.ts.map +1 -0
  203. package/dist/modes/interactive/components/theme-selector.js +50 -0
  204. package/dist/modes/interactive/components/theme-selector.js.map +1 -0
  205. package/dist/modes/interactive/components/thinking-selector.d.ts +11 -0
  206. package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -0
  207. package/dist/modes/interactive/components/thinking-selector.js +51 -0
  208. package/dist/modes/interactive/components/thinking-selector.js.map +1 -0
  209. package/dist/modes/interactive/components/tool-execution.d.ts +63 -0
  210. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -0
  211. package/dist/modes/interactive/components/tool-execution.js +295 -0
  212. package/dist/modes/interactive/components/tool-execution.js.map +1 -0
  213. package/dist/modes/interactive/components/tree-selector.d.ts +89 -0
  214. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -0
  215. package/dist/modes/interactive/components/tree-selector.js +1093 -0
  216. package/dist/modes/interactive/components/tree-selector.js.map +1 -0
  217. package/dist/modes/interactive/components/user-message-selector.d.ts +30 -0
  218. package/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -0
  219. package/dist/modes/interactive/components/user-message-selector.js +114 -0
  220. package/dist/modes/interactive/components/user-message-selector.js.map +1 -0
  221. package/dist/modes/interactive/components/user-message.d.ts +10 -0
  222. package/dist/modes/interactive/components/user-message.d.ts.map +1 -0
  223. package/dist/modes/interactive/components/user-message.js +29 -0
  224. package/dist/modes/interactive/components/user-message.js.map +1 -0
  225. package/dist/modes/interactive/components/visual-truncate.d.ts +19 -1
  226. package/dist/modes/interactive/components/visual-truncate.d.ts.map +1 -1
  227. package/dist/modes/interactive/components/visual-truncate.js +31 -4
  228. package/dist/modes/interactive/components/visual-truncate.js.map +1 -1
  229. package/dist/modes/interactive/interactive-mode.d.ts +375 -0
  230. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -0
  231. package/dist/modes/interactive/interactive-mode.js +4799 -0
  232. package/dist/modes/interactive/interactive-mode.js.map +1 -0
  233. package/dist/modes/interactive/theme/dark.json +86 -0
  234. package/dist/modes/interactive/theme/light.json +85 -0
  235. package/dist/modes/interactive/theme/theme-schema.json +335 -0
  236. package/dist/modes/interactive/theme/theme.d.ts +89 -27
  237. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  238. package/dist/modes/interactive/theme/theme.js +992 -44
  239. package/dist/modes/interactive/theme/theme.js.map +1 -1
  240. package/dist/package-manager-cli.d.ts.map +1 -1
  241. package/dist/package-manager-cli.js +1 -1
  242. package/dist/package-manager-cli.js.map +1 -1
  243. package/examples/extensions/border-status-editor.ts +150 -0
  244. package/examples/extensions/built-in-tool-renderer.ts +249 -0
  245. package/examples/extensions/custom-footer.ts +64 -0
  246. package/examples/extensions/custom-header.ts +73 -0
  247. package/examples/extensions/custom-provider-anthropic/index.ts +604 -0
  248. package/examples/extensions/custom-provider-anthropic/package-lock.json +24 -0
  249. package/examples/extensions/custom-provider-anthropic/package.json +19 -0
  250. package/examples/extensions/custom-provider-gitlab-duo/index.ts +349 -0
  251. package/examples/extensions/custom-provider-gitlab-duo/package.json +16 -0
  252. package/examples/extensions/custom-provider-gitlab-duo/test.ts +82 -0
  253. package/examples/extensions/doom-overlay/README.md +46 -0
  254. package/examples/extensions/doom-overlay/doom/build/doom.js +21 -0
  255. package/examples/extensions/doom-overlay/doom/build/doom.wasm +0 -0
  256. package/examples/extensions/doom-overlay/doom/build.sh +152 -0
  257. package/examples/extensions/doom-overlay/doom/doomgeneric_pi.c +72 -0
  258. package/examples/extensions/doom-overlay/doom-component.ts +132 -0
  259. package/examples/extensions/doom-overlay/doom-engine.ts +173 -0
  260. package/examples/extensions/doom-overlay/doom-keys.ts +104 -0
  261. package/examples/extensions/doom-overlay/index.ts +74 -0
  262. package/examples/extensions/doom-overlay/wad-finder.ts +51 -0
  263. package/examples/extensions/github-issue-autocomplete.ts +185 -0
  264. package/examples/extensions/handoff.ts +191 -0
  265. package/examples/extensions/interactive-shell.ts +196 -0
  266. package/examples/extensions/message-renderer.ts +59 -0
  267. package/examples/extensions/minimal-mode.ts +426 -0
  268. package/examples/extensions/modal-editor.ts +85 -0
  269. package/examples/extensions/overlay-qa-tests.ts +1379 -0
  270. package/examples/extensions/overlay-test.ts +153 -0
  271. package/examples/extensions/plan-mode/index.ts +340 -0
  272. package/examples/extensions/preset.ts +430 -0
  273. package/examples/extensions/qna.ts +122 -0
  274. package/examples/extensions/question.ts +264 -0
  275. package/examples/extensions/questionnaire.ts +427 -0
  276. package/examples/extensions/rainbow-editor.ts +88 -0
  277. package/examples/extensions/sandbox/index.ts +321 -0
  278. package/examples/extensions/sandbox/package-lock.json +92 -0
  279. package/examples/extensions/sandbox/package.json +19 -0
  280. package/examples/extensions/snake.ts +343 -0
  281. package/examples/extensions/space-invaders.ts +560 -0
  282. package/examples/extensions/ssh.ts +220 -0
  283. package/examples/extensions/status-line.ts +32 -0
  284. package/examples/extensions/structured-output.ts +65 -0
  285. package/examples/extensions/subagent/index.ts +1009 -0
  286. package/examples/extensions/summarize.ts +206 -0
  287. package/examples/extensions/tic-tac-toe.ts +1008 -0
  288. package/examples/extensions/todo.ts +297 -0
  289. package/examples/extensions/tools.ts +141 -0
  290. package/examples/extensions/truncated-tool.ts +195 -0
  291. package/examples/extensions/with-deps/index.ts +32 -0
  292. package/examples/extensions/with-deps/package-lock.json +31 -0
  293. package/examples/extensions/with-deps/package.json +22 -0
  294. package/examples/extensions/working-indicator.ts +123 -0
  295. package/examples/rpc-extension-ui.ts +632 -0
  296. package/npm-shrinkwrap.json +246 -240
  297. package/package.json +7 -6
  298. package/dist/core/tui-stubs.d.ts +0 -95
  299. package/dist/core/tui-stubs.d.ts.map +0 -1
  300. package/dist/core/tui-stubs.js +0 -90
  301. package/dist/core/tui-stubs.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"keybindings.js","sourceRoot":"","sources":["../../src/core/keybindings.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAC9C,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAKN,eAAe,EACf,kBAAkB,IAAI,qBAAqB,GAC3C,MAAM,gBAAgB,CAAC;AAgDxB,MAAM,CAAC,MAAM,WAAW,GAAG;IAC1B,GAAG,eAAe;IAClB,eAAe,EAAE,EAAE,WAAW,EAAE,QAAQ,EAAE,WAAW,EAAE,iBAAiB,EAAE;IAC1E,WAAW,EAAE,EAAE,WAAW,EAAE,QAAQ,EAAE,WAAW,EAAE,cAAc,EAAE;IACnE,UAAU,EAAE,EAAE,WAAW,EAAE,QAAQ,EAAE,WAAW,EAAE,2BAA2B,EAAE;IAC/E,aAAa,EAAE;QACd,WAAW,EAAE,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ;QACzD,WAAW,EAAE,uBAAuB;KACpC;IACD,oBAAoB,EAAE;QACrB,WAAW,EAAE,WAAW;QACxB,WAAW,EAAE,sBAAsB;KACnC;IACD,wBAAwB,EAAE;QACzB,WAAW,EAAE,QAAQ;QACrB,WAAW,EAAE,qBAAqB;KAClC;IACD,yBAAyB,EAAE;QAC1B,WAAW,EAAE,cAAc;QAC3B,WAAW,EAAE,yBAAyB;KACtC;IACD,kBAAkB,EAAE,EAAE,WAAW,EAAE,QAAQ,EAAE,WAAW,EAAE,qBAAqB,EAAE;IACjF,kBAAkB,EAAE,EAAE,WAAW,EAAE,QAAQ,EAAE,WAAW,EAAE,oBAAoB,EAAE;IAChF,qBAAqB,EAAE;QACtB,WAAW,EAAE,QAAQ;QACrB,WAAW,EAAE,wBAAwB;KACrC;IACD,+BAA+B,EAAE;QAChC,WAAW,EAAE,QAAQ;QACrB,WAAW,EAAE,6BAA6B;KAC1C;IACD,qBAAqB,EAAE;QACtB,WAAW,EAAE,QAAQ;QACrB,WAAW,EAAE,sBAAsB;KACnC;IACD,sBAAsB,EAAE;QACvB,WAAW,EAAE,WAAW;QACxB,WAAW,EAAE,yBAAyB;KACtC;IACD,qBAAqB,EAAE;QACtB,WAAW,EAAE,QAAQ;QACrB,WAAW,EAAE,yBAAyB;KACtC;IACD,0BAA0B,EAAE;QAC3B,WAAW,EAAE,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ;QAC9D,WAAW,EAAE,4BAA4B;KACzC;IACD,iBAAiB,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,WAAW,EAAE,qBAAqB,EAAE;IAC1E,kBAAkB,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,WAAW,EAAE,mBAAmB,EAAE;IACzE,kBAAkB,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,WAAW,EAAE,sBAAsB,EAAE;IAC5E,oBAAoB,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,WAAW,EAAE,kBAAkB,EAAE;IAC1E,mBAAmB,EAAE;QACpB,WAAW,EAAE,CAAC,WAAW,EAAE,UAAU,CAAC;QACtC,WAAW,EAAE,6BAA6B;KAC1C;IACD,uBAAuB,EAAE;QACxB,WAAW,EAAE,CAAC,YAAY,EAAE,WAAW,CAAC;QACxC,WAAW,EAAE,iCAAiC;KAC9C;IACD,oBAAoB,EAAE;QACrB,WAAW,EAAE,SAAS;QACtB,WAAW,EAAE,iBAAiB;KAC9B;IACD,+BAA+B,EAAE;QAChC,WAAW,EAAE,SAAS;QACtB,WAAW,EAAE,8BAA8B;KAC3C;IACD,wBAAwB,EAAE;QACzB,WAAW,EAAE,QAAQ;QACrB,WAAW,EAAE,6BAA6B;KAC1C;IACD,wBAAwB,EAAE;QACzB,WAAW,EAAE,QAAQ;QACrB,WAAW,EAAE,0BAA0B;KACvC;IACD,oBAAoB,EAAE;QACrB,WAAW,EAAE,QAAQ;QACrB,WAAW,EAAE,gBAAgB;KAC7B;IACD,oBAAoB,EAAE;QACrB,WAAW,EAAE,QAAQ;QACrB,WAAW,EAAE,gBAAgB;KAC7B;IACD,+BAA+B,EAAE;QAChC,WAAW,EAAE,gBAAgB;QAC7B,WAAW,EAAE,oCAAoC;KACjD;IACD,iBAAiB,EAAE;QAClB,WAAW,EAAE,QAAQ;QACrB,WAAW,EAAE,sBAAsB;KACnC;IACD,sBAAsB,EAAE;QACvB,WAAW,EAAE,QAAQ;QACrB,WAAW,EAAE,mBAAmB;KAChC;IACD,qBAAqB,EAAE;QACtB,WAAW,EAAE,QAAQ;QACrB,WAAW,EAAE,kBAAkB;KAC/B;IACD,2BAA2B,EAAE;QAC5B,WAAW,EAAE,QAAQ;QACrB,WAAW,EAAE,gCAAgC;KAC7C;IACD,sBAAsB,EAAE;QACvB,WAAW,EAAE,QAAQ;QACrB,WAAW,EAAE,wBAAwB;KACrC;IACD,wBAAwB,EAAE;QACzB,WAAW,EAAE,UAAU;QACvB,WAAW,EAAE,0BAA0B;KACvC;IACD,yBAAyB,EAAE;QAC1B,WAAW,EAAE,QAAQ;QACrB,WAAW,EAAE,2BAA2B;KACxC;IACD,yBAAyB,EAAE;QAC1B,WAAW,EAAE,QAAQ;QACrB,WAAW,EAAE,gCAAgC;KAC7C;IACD,0BAA0B,EAAE;QAC3B,WAAW,EAAE,QAAQ;QACrB,WAAW,EAAE,iCAAiC;KAC9C;IACD,6BAA6B,EAAE;QAC9B,WAAW,EAAE,QAAQ;QACrB,WAAW,EAAE,mCAAmC;KAChD;IACD,qBAAqB,EAAE;QACtB,WAAW,EAAE,QAAQ;QACrB,WAAW,EAAE,+BAA+B;KAC5C;IACD,8BAA8B,EAAE;QAC/B,WAAW,EAAE,QAAQ;QACrB,WAAW,EAAE,4BAA4B;KACzC;IACD,+BAA+B,EAAE;QAChC,WAAW,EAAE,cAAc;QAC3B,WAAW,EAAE,6BAA6B;KAC1C;CACwC,CAAC;AAE3C,MAAM,0BAA0B,GAAG;IAClC,QAAQ,EAAE,qBAAqB;IAC/B,UAAU,EAAE,uBAAuB;IACnC,UAAU,EAAE,uBAAuB;IACnC,WAAW,EAAE,wBAAwB;IACrC,cAAc,EAAE,2BAA2B;IAC3C,eAAe,EAAE,4BAA4B;IAC7C,eAAe,EAAE,4BAA4B;IAC7C,aAAa,EAAE,0BAA0B;IACzC,WAAW,EAAE,wBAAwB;IACrC,YAAY,EAAE,yBAAyB;IACvC,MAAM,EAAE,mBAAmB;IAC3B,QAAQ,EAAE,qBAAqB;IAC/B,kBAAkB,EAAE,+BAA+B;IACnD,iBAAiB,EAAE,8BAA8B;IACjD,kBAAkB,EAAE,+BAA+B;IACnD,iBAAiB,EAAE,8BAA8B;IACjD,iBAAiB,EAAE,8BAA8B;IACjD,eAAe,EAAE,4BAA4B;IAC7C,IAAI,EAAE,iBAAiB;IACvB,OAAO,EAAE,oBAAoB;IAC7B,IAAI,EAAE,iBAAiB;IACvB,OAAO,EAAE,mBAAmB;IAC5B,MAAM,EAAE,kBAAkB;IAC1B,GAAG,EAAE,eAAe;IACpB,IAAI,EAAE,gBAAgB;IACtB,QAAQ,EAAE,eAAe;IACzB,UAAU,EAAE,iBAAiB;IAC7B,YAAY,EAAE,mBAAmB;IACjC,cAAc,EAAE,qBAAqB;IACrC,aAAa,EAAE,oBAAoB;IACnC,YAAY,EAAE,mBAAmB;IACjC,SAAS,EAAE,eAAe;IAC1B,KAAK,EAAE,WAAW;IAClB,IAAI,EAAE,UAAU;IAChB,OAAO,EAAE,aAAa;IACtB,kBAAkB,EAAE,oBAAoB;IACxC,iBAAiB,EAAE,wBAAwB;IAC3C,kBAAkB,EAAE,yBAAyB;IAC7C,WAAW,EAAE,kBAAkB;IAC/B,WAAW,EAAE,kBAAkB;IAC/B,cAAc,EAAE,qBAAqB;IACrC,wBAAwB,EAAE,+BAA+B;IACzD,cAAc,EAAE,qBAAqB;IACrC,QAAQ,EAAE,sBAAsB;IAChC,OAAO,EAAE,qBAAqB;IAC9B,UAAU,EAAE,0BAA0B;IACtC,UAAU,EAAE,iBAAiB;IAC7B,IAAI,EAAE,kBAAkB;IACxB,IAAI,EAAE,kBAAkB;IACxB,MAAM,EAAE,oBAAoB;IAC5B,YAAY,EAAE,mBAAmB;IACjC,gBAAgB,EAAE,uBAAuB;IACzC,aAAa,EAAE,oBAAoB;IACnC,wBAAwB,EAAE,+BAA+B;IACzD,iBAAiB,EAAE,wBAAwB;IAC3C,iBAAiB,EAAE,wBAAwB;IAC3C,aAAa,EAAE,oBAAoB;IACnC,aAAa,EAAE,oBAAoB;IACnC,wBAAwB,EAAE,+BAA+B;CACX,CAAC;AAEhD,SAAS,QAAQ,CAAC,KAAc,EAAoC;IACnE,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAAA,CAC5E;AAED,SAAS,sBAAsB,CAAC,GAAW,EAAkD;IAC5F,OAAO,GAAG,IAAI,0BAA0B,CAAC;AAAA,CACzC;AAED,SAAS,mBAAmB,CAAC,KAAc,EAAqB;IAC/D,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAEhC,MAAM,MAAM,GAAsB,EAAE,CAAC;IACrC,KAAK,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACpD,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;YACjC,MAAM,CAAC,GAAG,CAAC,GAAG,OAAgB,CAAC;YAC/B,SAAS;QACV,CAAC;QACD,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC,EAAE,CAAC;YACnF,MAAM,CAAC,GAAG,CAAC,GAAG,OAAkB,CAAC;QAClC,CAAC;IACF,CAAC;IACD,OAAO,MAAM,CAAC;AAAA,CACd;AAED,MAAM,UAAU,wBAAwB,CAAC,SAAkC,EAGzE;IACD,MAAM,MAAM,GAA4B,EAAE,CAAC;IAC3C,IAAI,QAAQ,GAAG,KAAK,CAAC;IAErB,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;QACtD,MAAM,OAAO,GAAG,sBAAsB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,0BAA0B,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;QACpF,IAAI,OAAO,KAAK,GAAG,EAAE,CAAC;YACrB,QAAQ,GAAG,IAAI,CAAC;QACjB,CAAC;QACD,IAAI,GAAG,KAAK,OAAO,IAAI,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,EAAE,CAAC;YAC1D,QAAQ,GAAG,IAAI,CAAC;YAChB,SAAS;QACV,CAAC;QACD,MAAM,CAAC,OAAO,CAAC,GAAG,KAAK,CAAC;IACzB,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,sBAAsB,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAC;AAAA,CAC5D;AAED,SAAS,sBAAsB,CAAC,MAA+B,EAA2B;IACzF,MAAM,OAAO,GAA4B,EAAE,CAAC;IAC5C,KAAK,MAAM,UAAU,IAAI,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;QACnD,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,EAAE,CAAC;YACvC,OAAO,CAAC,UAAU,CAAC,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC;QAC1C,CAAC;IACF,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;SAChC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;SAC7C,IAAI,EAAE,CAAC;IACT,KAAK,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;QAC1B,OAAO,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IAC5B,CAAC;IAED,OAAO,OAAO,CAAC;AAAA,CACf;AAED,SAAS,aAAa,CAAC,IAAY,EAAuC;IACzE,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,SAAS,CAAC;IACxC,IAAI,CAAC;QACJ,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAY,CAAC;QAClE,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;IAC9C,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,SAAS,CAAC;IAClB,CAAC;AAAA,CACD;AAED,MAAM,OAAO,kBAAmB,SAAQ,qBAAqB;IACpD,UAAU,CAAqB;IAEvC,YAAY,YAAY,GAAsB,EAAE,EAAE,UAAmB,EAAE;QACtE,KAAK,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC;QACjC,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAAA,CAC7B;IAED,MAAM,CAAC,MAAM,CAAC,QAAQ,GAAW,WAAW,EAAE,EAAsB;QACnE,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,EAAE,kBAAkB,CAAC,CAAC;QACtD,MAAM,YAAY,GAAG,kBAAkB,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC;QACjE,OAAO,IAAI,kBAAkB,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;IAAA,CACxD;IAED,MAAM,GAAS;QACd,IAAI,CAAC,IAAI,CAAC,UAAU;YAAE,OAAO;QAC7B,IAAI,CAAC,eAAe,CAAC,kBAAkB,CAAC,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;IAAA,CACvE;IAED,kBAAkB,GAAsB;QACvC,OAAO,IAAI,CAAC,mBAAmB,EAAE,CAAC;IAAA,CAClC;IAEO,MAAM,CAAC,YAAY,CAAC,IAAY,EAAqB;QAC5D,MAAM,SAAS,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;QACtC,IAAI,CAAC,SAAS;YAAE,OAAO,EAAE,CAAC;QAC1B,OAAO,mBAAmB,CAAC,wBAAwB,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC;IAAA,CACvE;CACD","sourcesContent":["import { existsSync, readFileSync } from \"fs\";\nimport { join } from \"path\";\nimport { getAgentDir } from \"../config.ts\";\nimport {\n\ttype Keybinding,\n\ttype KeybindingDefinitions,\n\ttype KeybindingsConfig,\n\ttype KeyId,\n\tTUI_KEYBINDINGS,\n\tKeybindingsManager as TuiKeybindingsManager,\n} from \"./tui-stubs.ts\";\n\nexport interface AppKeybindings {\n\t\"app.interrupt\": true;\n\t\"app.clear\": true;\n\t\"app.exit\": true;\n\t\"app.suspend\": true;\n\t\"app.thinking.cycle\": true;\n\t\"app.model.cycleForward\": true;\n\t\"app.model.cycleBackward\": true;\n\t\"app.model.select\": true;\n\t\"app.tools.expand\": true;\n\t\"app.thinking.toggle\": true;\n\t\"app.session.toggleNamedFilter\": true;\n\t\"app.editor.external\": true;\n\t\"app.message.followUp\": true;\n\t\"app.message.dequeue\": true;\n\t\"app.clipboard.pasteImage\": true;\n\t\"app.session.new\": true;\n\t\"app.session.tree\": true;\n\t\"app.session.fork\": true;\n\t\"app.session.resume\": true;\n\t\"app.tree.foldOrUp\": true;\n\t\"app.tree.unfoldOrDown\": true;\n\t\"app.tree.editLabel\": true;\n\t\"app.tree.toggleLabelTimestamp\": true;\n\t\"app.session.togglePath\": true;\n\t\"app.session.toggleSort\": true;\n\t\"app.session.rename\": true;\n\t\"app.session.delete\": true;\n\t\"app.session.deleteNoninvasive\": true;\n\t\"app.models.save\": true;\n\t\"app.models.enableAll\": true;\n\t\"app.models.clearAll\": true;\n\t\"app.models.toggleProvider\": true;\n\t\"app.models.reorderUp\": true;\n\t\"app.models.reorderDown\": true;\n\t\"app.tree.filter.default\": true;\n\t\"app.tree.filter.noTools\": true;\n\t\"app.tree.filter.userOnly\": true;\n\t\"app.tree.filter.labeledOnly\": true;\n\t\"app.tree.filter.all\": true;\n\t\"app.tree.filter.cycleForward\": true;\n\t\"app.tree.filter.cycleBackward\": true;\n}\n\nexport type AppKeybinding = keyof AppKeybindings;\n\nexport const KEYBINDINGS = {\n\t...TUI_KEYBINDINGS,\n\t\"app.interrupt\": { defaultKeys: \"escape\", description: \"Cancel or abort\" },\n\t\"app.clear\": { defaultKeys: \"ctrl+c\", description: \"Clear editor\" },\n\t\"app.exit\": { defaultKeys: \"ctrl+d\", description: \"Exit when editor is empty\" },\n\t\"app.suspend\": {\n\t\tdefaultKeys: process.platform === \"win32\" ? [] : \"ctrl+z\",\n\t\tdescription: \"Suspend to background\",\n\t},\n\t\"app.thinking.cycle\": {\n\t\tdefaultKeys: \"shift+tab\",\n\t\tdescription: \"Cycle thinking level\",\n\t},\n\t\"app.model.cycleForward\": {\n\t\tdefaultKeys: \"ctrl+p\",\n\t\tdescription: \"Cycle to next model\",\n\t},\n\t\"app.model.cycleBackward\": {\n\t\tdefaultKeys: \"shift+ctrl+p\",\n\t\tdescription: \"Cycle to previous model\",\n\t},\n\t\"app.model.select\": { defaultKeys: \"ctrl+l\", description: \"Open model selector\" },\n\t\"app.tools.expand\": { defaultKeys: \"ctrl+o\", description: \"Toggle tool output\" },\n\t\"app.thinking.toggle\": {\n\t\tdefaultKeys: \"ctrl+t\",\n\t\tdescription: \"Toggle thinking blocks\",\n\t},\n\t\"app.session.toggleNamedFilter\": {\n\t\tdefaultKeys: \"ctrl+n\",\n\t\tdescription: \"Toggle named session filter\",\n\t},\n\t\"app.editor.external\": {\n\t\tdefaultKeys: \"ctrl+g\",\n\t\tdescription: \"Open external editor\",\n\t},\n\t\"app.message.followUp\": {\n\t\tdefaultKeys: \"alt+enter\",\n\t\tdescription: \"Queue follow-up message\",\n\t},\n\t\"app.message.dequeue\": {\n\t\tdefaultKeys: \"alt+up\",\n\t\tdescription: \"Restore queued messages\",\n\t},\n\t\"app.clipboard.pasteImage\": {\n\t\tdefaultKeys: process.platform === \"win32\" ? \"alt+v\" : \"ctrl+v\",\n\t\tdescription: \"Paste image from clipboard\",\n\t},\n\t\"app.session.new\": { defaultKeys: [], description: \"Start a new session\" },\n\t\"app.session.tree\": { defaultKeys: [], description: \"Open session tree\" },\n\t\"app.session.fork\": { defaultKeys: [], description: \"Fork current session\" },\n\t\"app.session.resume\": { defaultKeys: [], description: \"Resume a session\" },\n\t\"app.tree.foldOrUp\": {\n\t\tdefaultKeys: [\"ctrl+left\", \"alt+left\"],\n\t\tdescription: \"Fold tree branch or move up\",\n\t},\n\t\"app.tree.unfoldOrDown\": {\n\t\tdefaultKeys: [\"ctrl+right\", \"alt+right\"],\n\t\tdescription: \"Unfold tree branch or move down\",\n\t},\n\t\"app.tree.editLabel\": {\n\t\tdefaultKeys: \"shift+l\",\n\t\tdescription: \"Edit tree label\",\n\t},\n\t\"app.tree.toggleLabelTimestamp\": {\n\t\tdefaultKeys: \"shift+t\",\n\t\tdescription: \"Toggle tree label timestamps\",\n\t},\n\t\"app.session.togglePath\": {\n\t\tdefaultKeys: \"ctrl+p\",\n\t\tdescription: \"Toggle session path display\",\n\t},\n\t\"app.session.toggleSort\": {\n\t\tdefaultKeys: \"ctrl+s\",\n\t\tdescription: \"Toggle session sort mode\",\n\t},\n\t\"app.session.rename\": {\n\t\tdefaultKeys: \"ctrl+r\",\n\t\tdescription: \"Rename session\",\n\t},\n\t\"app.session.delete\": {\n\t\tdefaultKeys: \"ctrl+d\",\n\t\tdescription: \"Delete session\",\n\t},\n\t\"app.session.deleteNoninvasive\": {\n\t\tdefaultKeys: \"ctrl+backspace\",\n\t\tdescription: \"Delete session when query is empty\",\n\t},\n\t\"app.models.save\": {\n\t\tdefaultKeys: \"ctrl+s\",\n\t\tdescription: \"Save model selection\",\n\t},\n\t\"app.models.enableAll\": {\n\t\tdefaultKeys: \"ctrl+a\",\n\t\tdescription: \"Enable all models\",\n\t},\n\t\"app.models.clearAll\": {\n\t\tdefaultKeys: \"ctrl+x\",\n\t\tdescription: \"Clear all models\",\n\t},\n\t\"app.models.toggleProvider\": {\n\t\tdefaultKeys: \"ctrl+p\",\n\t\tdescription: \"Toggle all models for provider\",\n\t},\n\t\"app.models.reorderUp\": {\n\t\tdefaultKeys: \"alt+up\",\n\t\tdescription: \"Move model up in order\",\n\t},\n\t\"app.models.reorderDown\": {\n\t\tdefaultKeys: \"alt+down\",\n\t\tdescription: \"Move model down in order\",\n\t},\n\t\"app.tree.filter.default\": {\n\t\tdefaultKeys: \"ctrl+d\",\n\t\tdescription: \"Tree filter: default view\",\n\t},\n\t\"app.tree.filter.noTools\": {\n\t\tdefaultKeys: \"ctrl+t\",\n\t\tdescription: \"Tree filter: hide tool results\",\n\t},\n\t\"app.tree.filter.userOnly\": {\n\t\tdefaultKeys: \"ctrl+u\",\n\t\tdescription: \"Tree filter: user messages only\",\n\t},\n\t\"app.tree.filter.labeledOnly\": {\n\t\tdefaultKeys: \"ctrl+l\",\n\t\tdescription: \"Tree filter: labeled entries only\",\n\t},\n\t\"app.tree.filter.all\": {\n\t\tdefaultKeys: \"ctrl+a\",\n\t\tdescription: \"Tree filter: show all entries\",\n\t},\n\t\"app.tree.filter.cycleForward\": {\n\t\tdefaultKeys: \"ctrl+o\",\n\t\tdescription: \"Tree filter: cycle forward\",\n\t},\n\t\"app.tree.filter.cycleBackward\": {\n\t\tdefaultKeys: \"shift+ctrl+o\",\n\t\tdescription: \"Tree filter: cycle backward\",\n\t},\n} as const satisfies KeybindingDefinitions;\n\nconst KEYBINDING_NAME_MIGRATIONS = {\n\tcursorUp: \"tui.editor.cursorUp\",\n\tcursorDown: \"tui.editor.cursorDown\",\n\tcursorLeft: \"tui.editor.cursorLeft\",\n\tcursorRight: \"tui.editor.cursorRight\",\n\tcursorWordLeft: \"tui.editor.cursorWordLeft\",\n\tcursorWordRight: \"tui.editor.cursorWordRight\",\n\tcursorLineStart: \"tui.editor.cursorLineStart\",\n\tcursorLineEnd: \"tui.editor.cursorLineEnd\",\n\tjumpForward: \"tui.editor.jumpForward\",\n\tjumpBackward: \"tui.editor.jumpBackward\",\n\tpageUp: \"tui.editor.pageUp\",\n\tpageDown: \"tui.editor.pageDown\",\n\tdeleteCharBackward: \"tui.editor.deleteCharBackward\",\n\tdeleteCharForward: \"tui.editor.deleteCharForward\",\n\tdeleteWordBackward: \"tui.editor.deleteWordBackward\",\n\tdeleteWordForward: \"tui.editor.deleteWordForward\",\n\tdeleteToLineStart: \"tui.editor.deleteToLineStart\",\n\tdeleteToLineEnd: \"tui.editor.deleteToLineEnd\",\n\tyank: \"tui.editor.yank\",\n\tyankPop: \"tui.editor.yankPop\",\n\tundo: \"tui.editor.undo\",\n\tnewLine: \"tui.input.newLine\",\n\tsubmit: \"tui.input.submit\",\n\ttab: \"tui.input.tab\",\n\tcopy: \"tui.input.copy\",\n\tselectUp: \"tui.select.up\",\n\tselectDown: \"tui.select.down\",\n\tselectPageUp: \"tui.select.pageUp\",\n\tselectPageDown: \"tui.select.pageDown\",\n\tselectConfirm: \"tui.select.confirm\",\n\tselectCancel: \"tui.select.cancel\",\n\tinterrupt: \"app.interrupt\",\n\tclear: \"app.clear\",\n\texit: \"app.exit\",\n\tsuspend: \"app.suspend\",\n\tcycleThinkingLevel: \"app.thinking.cycle\",\n\tcycleModelForward: \"app.model.cycleForward\",\n\tcycleModelBackward: \"app.model.cycleBackward\",\n\tselectModel: \"app.model.select\",\n\texpandTools: \"app.tools.expand\",\n\ttoggleThinking: \"app.thinking.toggle\",\n\ttoggleSessionNamedFilter: \"app.session.toggleNamedFilter\",\n\texternalEditor: \"app.editor.external\",\n\tfollowUp: \"app.message.followUp\",\n\tdequeue: \"app.message.dequeue\",\n\tpasteImage: \"app.clipboard.pasteImage\",\n\tnewSession: \"app.session.new\",\n\ttree: \"app.session.tree\",\n\tfork: \"app.session.fork\",\n\tresume: \"app.session.resume\",\n\ttreeFoldOrUp: \"app.tree.foldOrUp\",\n\ttreeUnfoldOrDown: \"app.tree.unfoldOrDown\",\n\ttreeEditLabel: \"app.tree.editLabel\",\n\ttreeToggleLabelTimestamp: \"app.tree.toggleLabelTimestamp\",\n\ttoggleSessionPath: \"app.session.togglePath\",\n\ttoggleSessionSort: \"app.session.toggleSort\",\n\trenameSession: \"app.session.rename\",\n\tdeleteSession: \"app.session.delete\",\n\tdeleteSessionNoninvasive: \"app.session.deleteNoninvasive\",\n} as const satisfies Record<string, Keybinding>;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isLegacyKeybindingName(key: string): key is keyof typeof KEYBINDING_NAME_MIGRATIONS {\n\treturn key in KEYBINDING_NAME_MIGRATIONS;\n}\n\nfunction toKeybindingsConfig(value: unknown): KeybindingsConfig {\n\tif (!isRecord(value)) return {};\n\n\tconst config: KeybindingsConfig = {};\n\tfor (const [key, binding] of Object.entries(value)) {\n\t\tif (typeof binding === \"string\") {\n\t\t\tconfig[key] = binding as KeyId;\n\t\t\tcontinue;\n\t\t}\n\t\tif (Array.isArray(binding) && binding.every((entry) => typeof entry === \"string\")) {\n\t\t\tconfig[key] = binding as KeyId[];\n\t\t}\n\t}\n\treturn config;\n}\n\nexport function migrateKeybindingsConfig(rawConfig: Record<string, unknown>): {\n\tconfig: Record<string, unknown>;\n\tmigrated: boolean;\n} {\n\tconst config: Record<string, unknown> = {};\n\tlet migrated = false;\n\n\tfor (const [key, value] of Object.entries(rawConfig)) {\n\t\tconst nextKey = isLegacyKeybindingName(key) ? KEYBINDING_NAME_MIGRATIONS[key] : key;\n\t\tif (nextKey !== key) {\n\t\t\tmigrated = true;\n\t\t}\n\t\tif (key !== nextKey && Object.hasOwn(rawConfig, nextKey)) {\n\t\t\tmigrated = true;\n\t\t\tcontinue;\n\t\t}\n\t\tconfig[nextKey] = value;\n\t}\n\n\treturn { config: orderKeybindingsConfig(config), migrated };\n}\n\nfunction orderKeybindingsConfig(config: Record<string, unknown>): Record<string, unknown> {\n\tconst ordered: Record<string, unknown> = {};\n\tfor (const keybinding of Object.keys(KEYBINDINGS)) {\n\t\tif (Object.hasOwn(config, keybinding)) {\n\t\t\tordered[keybinding] = config[keybinding];\n\t\t}\n\t}\n\n\tconst extras = Object.keys(config)\n\t\t.filter((key) => !Object.hasOwn(ordered, key))\n\t\t.sort();\n\tfor (const key of extras) {\n\t\tordered[key] = config[key];\n\t}\n\n\treturn ordered;\n}\n\nfunction loadRawConfig(path: string): Record<string, unknown> | undefined {\n\tif (!existsSync(path)) return undefined;\n\ttry {\n\t\tconst parsed = JSON.parse(readFileSync(path, \"utf-8\")) as unknown;\n\t\treturn isRecord(parsed) ? parsed : undefined;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nexport class KeybindingsManager extends TuiKeybindingsManager {\n\tprivate configPath: string | undefined;\n\n\tconstructor(userBindings: KeybindingsConfig = {}, configPath?: string) {\n\t\tsuper(KEYBINDINGS, userBindings);\n\t\tthis.configPath = configPath;\n\t}\n\n\tstatic create(agentDir: string = getAgentDir()): KeybindingsManager {\n\t\tconst configPath = join(agentDir, \"keybindings.json\");\n\t\tconst userBindings = KeybindingsManager.loadFromFile(configPath);\n\t\treturn new KeybindingsManager(userBindings, configPath);\n\t}\n\n\treload(): void {\n\t\tif (!this.configPath) return;\n\t\tthis.setUserBindings(KeybindingsManager.loadFromFile(this.configPath));\n\t}\n\n\tgetEffectiveConfig(): KeybindingsConfig {\n\t\treturn this.getResolvedBindings();\n\t}\n\n\tprivate static loadFromFile(path: string): KeybindingsConfig {\n\t\tconst rawConfig = loadRawConfig(path);\n\t\tif (!rawConfig) return {};\n\t\treturn toKeybindingsConfig(migrateKeybindingsConfig(rawConfig).config);\n\t}\n}\n\nexport type { Keybinding, KeyId, KeybindingsConfig };\n"]}
1
+ {"version":3,"file":"keybindings.js","sourceRoot":"","sources":["../../src/core/keybindings.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\ttype Keybinding,\n\ttype KeybindingDefinitions,\n\ttype KeybindingsConfig,\n\ttype KeyId,\n\tTUI_KEYBINDINGS,\n\tKeybindingsManager as TuiKeybindingsManager,\n} from \"@openeryc/pi-tui\";\nimport { existsSync, readFileSync } from \"fs\";\nimport { join } from \"path\";\nimport { getAgentDir } from \"../config.ts\";\n\nexport interface AppKeybindings {\n\t\"app.interrupt\": true;\n\t\"app.clear\": true;\n\t\"app.exit\": true;\n\t\"app.suspend\": true;\n\t\"app.thinking.cycle\": true;\n\t\"app.model.cycleForward\": true;\n\t\"app.model.cycleBackward\": true;\n\t\"app.model.select\": true;\n\t\"app.tools.expand\": true;\n\t\"app.thinking.toggle\": true;\n\t\"app.session.toggleNamedFilter\": true;\n\t\"app.editor.external\": true;\n\t\"app.message.followUp\": true;\n\t\"app.message.dequeue\": true;\n\t\"app.clipboard.pasteImage\": true;\n\t\"app.session.new\": true;\n\t\"app.session.tree\": true;\n\t\"app.session.fork\": true;\n\t\"app.session.resume\": true;\n\t\"app.tree.foldOrUp\": true;\n\t\"app.tree.unfoldOrDown\": true;\n\t\"app.tree.editLabel\": true;\n\t\"app.tree.toggleLabelTimestamp\": true;\n\t\"app.session.togglePath\": true;\n\t\"app.session.toggleSort\": true;\n\t\"app.session.rename\": true;\n\t\"app.session.delete\": true;\n\t\"app.session.deleteNoninvasive\": true;\n\t\"app.models.save\": true;\n\t\"app.models.enableAll\": true;\n\t\"app.models.clearAll\": true;\n\t\"app.models.toggleProvider\": true;\n\t\"app.models.reorderUp\": true;\n\t\"app.models.reorderDown\": true;\n\t\"app.tree.filter.default\": true;\n\t\"app.tree.filter.noTools\": true;\n\t\"app.tree.filter.userOnly\": true;\n\t\"app.tree.filter.labeledOnly\": true;\n\t\"app.tree.filter.all\": true;\n\t\"app.tree.filter.cycleForward\": true;\n\t\"app.tree.filter.cycleBackward\": true;\n}\n\nexport type AppKeybinding = keyof AppKeybindings;\n\ndeclare module \"@openeryc/pi-tui\" {\n\tinterface Keybindings extends AppKeybindings {}\n}\n\nexport const KEYBINDINGS = {\n\t...TUI_KEYBINDINGS,\n\t\"app.interrupt\": { defaultKeys: \"escape\", description: \"Cancel or abort\" },\n\t\"app.clear\": { defaultKeys: \"ctrl+c\", description: \"Clear editor\" },\n\t\"app.exit\": { defaultKeys: \"ctrl+d\", description: \"Exit when editor is empty\" },\n\t\"app.suspend\": {\n\t\tdefaultKeys: process.platform === \"win32\" ? [] : \"ctrl+z\",\n\t\tdescription: \"Suspend to background\",\n\t},\n\t\"app.thinking.cycle\": {\n\t\tdefaultKeys: \"shift+tab\",\n\t\tdescription: \"Cycle thinking level\",\n\t},\n\t\"app.model.cycleForward\": {\n\t\tdefaultKeys: \"ctrl+p\",\n\t\tdescription: \"Cycle to next model\",\n\t},\n\t\"app.model.cycleBackward\": {\n\t\tdefaultKeys: \"shift+ctrl+p\",\n\t\tdescription: \"Cycle to previous model\",\n\t},\n\t\"app.model.select\": { defaultKeys: \"ctrl+l\", description: \"Open model selector\" },\n\t\"app.tools.expand\": { defaultKeys: \"ctrl+o\", description: \"Toggle tool output\" },\n\t\"app.thinking.toggle\": {\n\t\tdefaultKeys: \"ctrl+t\",\n\t\tdescription: \"Toggle thinking blocks\",\n\t},\n\t\"app.session.toggleNamedFilter\": {\n\t\tdefaultKeys: \"ctrl+n\",\n\t\tdescription: \"Toggle named session filter\",\n\t},\n\t\"app.editor.external\": {\n\t\tdefaultKeys: \"ctrl+g\",\n\t\tdescription: \"Open external editor\",\n\t},\n\t\"app.message.followUp\": {\n\t\tdefaultKeys: \"alt+enter\",\n\t\tdescription: \"Queue follow-up message\",\n\t},\n\t\"app.message.dequeue\": {\n\t\tdefaultKeys: \"alt+up\",\n\t\tdescription: \"Restore queued messages\",\n\t},\n\t\"app.clipboard.pasteImage\": {\n\t\tdefaultKeys: process.platform === \"win32\" ? \"alt+v\" : \"ctrl+v\",\n\t\tdescription: \"Paste image from clipboard\",\n\t},\n\t\"app.session.new\": { defaultKeys: [], description: \"Start a new session\" },\n\t\"app.session.tree\": { defaultKeys: [], description: \"Open session tree\" },\n\t\"app.session.fork\": { defaultKeys: [], description: \"Fork current session\" },\n\t\"app.session.resume\": { defaultKeys: [], description: \"Resume a session\" },\n\t\"app.tree.foldOrUp\": {\n\t\tdefaultKeys: [\"ctrl+left\", \"alt+left\"],\n\t\tdescription: \"Fold tree branch or move up\",\n\t},\n\t\"app.tree.unfoldOrDown\": {\n\t\tdefaultKeys: [\"ctrl+right\", \"alt+right\"],\n\t\tdescription: \"Unfold tree branch or move down\",\n\t},\n\t\"app.tree.editLabel\": {\n\t\tdefaultKeys: \"shift+l\",\n\t\tdescription: \"Edit tree label\",\n\t},\n\t\"app.tree.toggleLabelTimestamp\": {\n\t\tdefaultKeys: \"shift+t\",\n\t\tdescription: \"Toggle tree label timestamps\",\n\t},\n\t\"app.session.togglePath\": {\n\t\tdefaultKeys: \"ctrl+p\",\n\t\tdescription: \"Toggle session path display\",\n\t},\n\t\"app.session.toggleSort\": {\n\t\tdefaultKeys: \"ctrl+s\",\n\t\tdescription: \"Toggle session sort mode\",\n\t},\n\t\"app.session.rename\": {\n\t\tdefaultKeys: \"ctrl+r\",\n\t\tdescription: \"Rename session\",\n\t},\n\t\"app.session.delete\": {\n\t\tdefaultKeys: \"ctrl+d\",\n\t\tdescription: \"Delete session\",\n\t},\n\t\"app.session.deleteNoninvasive\": {\n\t\tdefaultKeys: \"ctrl+backspace\",\n\t\tdescription: \"Delete session when query is empty\",\n\t},\n\t\"app.models.save\": {\n\t\tdefaultKeys: \"ctrl+s\",\n\t\tdescription: \"Save model selection\",\n\t},\n\t\"app.models.enableAll\": {\n\t\tdefaultKeys: \"ctrl+a\",\n\t\tdescription: \"Enable all models\",\n\t},\n\t\"app.models.clearAll\": {\n\t\tdefaultKeys: \"ctrl+x\",\n\t\tdescription: \"Clear all models\",\n\t},\n\t\"app.models.toggleProvider\": {\n\t\tdefaultKeys: \"ctrl+p\",\n\t\tdescription: \"Toggle all models for provider\",\n\t},\n\t\"app.models.reorderUp\": {\n\t\tdefaultKeys: \"alt+up\",\n\t\tdescription: \"Move model up in order\",\n\t},\n\t\"app.models.reorderDown\": {\n\t\tdefaultKeys: \"alt+down\",\n\t\tdescription: \"Move model down in order\",\n\t},\n\t\"app.tree.filter.default\": {\n\t\tdefaultKeys: \"ctrl+d\",\n\t\tdescription: \"Tree filter: default view\",\n\t},\n\t\"app.tree.filter.noTools\": {\n\t\tdefaultKeys: \"ctrl+t\",\n\t\tdescription: \"Tree filter: hide tool results\",\n\t},\n\t\"app.tree.filter.userOnly\": {\n\t\tdefaultKeys: \"ctrl+u\",\n\t\tdescription: \"Tree filter: user messages only\",\n\t},\n\t\"app.tree.filter.labeledOnly\": {\n\t\tdefaultKeys: \"ctrl+l\",\n\t\tdescription: \"Tree filter: labeled entries only\",\n\t},\n\t\"app.tree.filter.all\": {\n\t\tdefaultKeys: \"ctrl+a\",\n\t\tdescription: \"Tree filter: show all entries\",\n\t},\n\t\"app.tree.filter.cycleForward\": {\n\t\tdefaultKeys: \"ctrl+o\",\n\t\tdescription: \"Tree filter: cycle forward\",\n\t},\n\t\"app.tree.filter.cycleBackward\": {\n\t\tdefaultKeys: \"shift+ctrl+o\",\n\t\tdescription: \"Tree filter: cycle backward\",\n\t},\n} as const satisfies KeybindingDefinitions;\n\nconst KEYBINDING_NAME_MIGRATIONS = {\n\tcursorUp: \"tui.editor.cursorUp\",\n\tcursorDown: \"tui.editor.cursorDown\",\n\tcursorLeft: \"tui.editor.cursorLeft\",\n\tcursorRight: \"tui.editor.cursorRight\",\n\tcursorWordLeft: \"tui.editor.cursorWordLeft\",\n\tcursorWordRight: \"tui.editor.cursorWordRight\",\n\tcursorLineStart: \"tui.editor.cursorLineStart\",\n\tcursorLineEnd: \"tui.editor.cursorLineEnd\",\n\tjumpForward: \"tui.editor.jumpForward\",\n\tjumpBackward: \"tui.editor.jumpBackward\",\n\tpageUp: \"tui.editor.pageUp\",\n\tpageDown: \"tui.editor.pageDown\",\n\tdeleteCharBackward: \"tui.editor.deleteCharBackward\",\n\tdeleteCharForward: \"tui.editor.deleteCharForward\",\n\tdeleteWordBackward: \"tui.editor.deleteWordBackward\",\n\tdeleteWordForward: \"tui.editor.deleteWordForward\",\n\tdeleteToLineStart: \"tui.editor.deleteToLineStart\",\n\tdeleteToLineEnd: \"tui.editor.deleteToLineEnd\",\n\tyank: \"tui.editor.yank\",\n\tyankPop: \"tui.editor.yankPop\",\n\tundo: \"tui.editor.undo\",\n\tnewLine: \"tui.input.newLine\",\n\tsubmit: \"tui.input.submit\",\n\ttab: \"tui.input.tab\",\n\tcopy: \"tui.input.copy\",\n\tselectUp: \"tui.select.up\",\n\tselectDown: \"tui.select.down\",\n\tselectPageUp: \"tui.select.pageUp\",\n\tselectPageDown: \"tui.select.pageDown\",\n\tselectConfirm: \"tui.select.confirm\",\n\tselectCancel: \"tui.select.cancel\",\n\tinterrupt: \"app.interrupt\",\n\tclear: \"app.clear\",\n\texit: \"app.exit\",\n\tsuspend: \"app.suspend\",\n\tcycleThinkingLevel: \"app.thinking.cycle\",\n\tcycleModelForward: \"app.model.cycleForward\",\n\tcycleModelBackward: \"app.model.cycleBackward\",\n\tselectModel: \"app.model.select\",\n\texpandTools: \"app.tools.expand\",\n\ttoggleThinking: \"app.thinking.toggle\",\n\ttoggleSessionNamedFilter: \"app.session.toggleNamedFilter\",\n\texternalEditor: \"app.editor.external\",\n\tfollowUp: \"app.message.followUp\",\n\tdequeue: \"app.message.dequeue\",\n\tpasteImage: \"app.clipboard.pasteImage\",\n\tnewSession: \"app.session.new\",\n\ttree: \"app.session.tree\",\n\tfork: \"app.session.fork\",\n\tresume: \"app.session.resume\",\n\ttreeFoldOrUp: \"app.tree.foldOrUp\",\n\ttreeUnfoldOrDown: \"app.tree.unfoldOrDown\",\n\ttreeEditLabel: \"app.tree.editLabel\",\n\ttreeToggleLabelTimestamp: \"app.tree.toggleLabelTimestamp\",\n\ttoggleSessionPath: \"app.session.togglePath\",\n\ttoggleSessionSort: \"app.session.toggleSort\",\n\trenameSession: \"app.session.rename\",\n\tdeleteSession: \"app.session.delete\",\n\tdeleteSessionNoninvasive: \"app.session.deleteNoninvasive\",\n} as const satisfies Record<string, Keybinding>;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isLegacyKeybindingName(key: string): key is keyof typeof KEYBINDING_NAME_MIGRATIONS {\n\treturn key in KEYBINDING_NAME_MIGRATIONS;\n}\n\nfunction toKeybindingsConfig(value: unknown): KeybindingsConfig {\n\tif (!isRecord(value)) return {};\n\n\tconst config: KeybindingsConfig = {};\n\tfor (const [key, binding] of Object.entries(value)) {\n\t\tif (typeof binding === \"string\") {\n\t\t\tconfig[key] = binding as KeyId;\n\t\t\tcontinue;\n\t\t}\n\t\tif (Array.isArray(binding) && binding.every((entry) => typeof entry === \"string\")) {\n\t\t\tconfig[key] = binding as KeyId[];\n\t\t}\n\t}\n\treturn config;\n}\n\nexport function migrateKeybindingsConfig(rawConfig: Record<string, unknown>): {\n\tconfig: Record<string, unknown>;\n\tmigrated: boolean;\n} {\n\tconst config: Record<string, unknown> = {};\n\tlet migrated = false;\n\n\tfor (const [key, value] of Object.entries(rawConfig)) {\n\t\tconst nextKey = isLegacyKeybindingName(key) ? KEYBINDING_NAME_MIGRATIONS[key] : key;\n\t\tif (nextKey !== key) {\n\t\t\tmigrated = true;\n\t\t}\n\t\tif (key !== nextKey && Object.hasOwn(rawConfig, nextKey)) {\n\t\t\tmigrated = true;\n\t\t\tcontinue;\n\t\t}\n\t\tconfig[nextKey] = value;\n\t}\n\n\treturn { config: orderKeybindingsConfig(config), migrated };\n}\n\nfunction orderKeybindingsConfig(config: Record<string, unknown>): Record<string, unknown> {\n\tconst ordered: Record<string, unknown> = {};\n\tfor (const keybinding of Object.keys(KEYBINDINGS)) {\n\t\tif (Object.hasOwn(config, keybinding)) {\n\t\t\tordered[keybinding] = config[keybinding];\n\t\t}\n\t}\n\n\tconst extras = Object.keys(config)\n\t\t.filter((key) => !Object.hasOwn(ordered, key))\n\t\t.sort();\n\tfor (const key of extras) {\n\t\tordered[key] = config[key];\n\t}\n\n\treturn ordered;\n}\n\nfunction loadRawConfig(path: string): Record<string, unknown> | undefined {\n\tif (!existsSync(path)) return undefined;\n\ttry {\n\t\tconst parsed = JSON.parse(readFileSync(path, \"utf-8\")) as unknown;\n\t\treturn isRecord(parsed) ? parsed : undefined;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nexport class KeybindingsManager extends TuiKeybindingsManager {\n\tprivate configPath: string | undefined;\n\n\tconstructor(userBindings: KeybindingsConfig = {}, configPath?: string) {\n\t\tsuper(KEYBINDINGS, userBindings);\n\t\tthis.configPath = configPath;\n\t}\n\n\tstatic create(agentDir: string = getAgentDir()): KeybindingsManager {\n\t\tconst configPath = join(agentDir, \"keybindings.json\");\n\t\tconst userBindings = KeybindingsManager.loadFromFile(configPath);\n\t\treturn new KeybindingsManager(userBindings, configPath);\n\t}\n\n\treload(): void {\n\t\tif (!this.configPath) return;\n\t\tthis.setUserBindings(KeybindingsManager.loadFromFile(this.configPath));\n\t}\n\n\tgetEffectiveConfig(): KeybindingsConfig {\n\t\treturn this.getResolvedBindings();\n\t}\n\n\tprivate static loadFromFile(path: string): KeybindingsConfig {\n\t\tconst rawConfig = loadRawConfig(path);\n\t\tif (!rawConfig) return {};\n\t\treturn toKeybindingsConfig(migrateKeybindingsConfig(rawConfig).config);\n\t}\n}\n\nexport type { Keybinding, KeyId, KeybindingsConfig };\n"]}
@@ -1,38 +1,19 @@
1
- export interface MCPServerConfig {
2
- command: string;
3
- args?: string[];
4
- env?: Record<string, string>;
5
- }
6
- interface MCPSimpleTool {
7
- name: string;
8
- description?: string;
9
- inputSchema: {
10
- type: string;
11
- properties?: Record<string, unknown>;
12
- required?: string[];
13
- };
14
- }
15
- interface MCPListToolsResult {
16
- tools: MCPSimpleTool[];
17
- }
18
- interface MCPCallToolResult {
19
- content: Array<{
20
- type: string;
21
- text?: string;
22
- data?: string;
23
- mimeType?: string;
24
- }>;
25
- isError?: boolean;
26
- }
1
+ import type { MCPCallToolResult, MCPListToolsResult, MCPServerConfig } from "./types.ts";
27
2
  export declare class MCPClient {
28
3
  private process;
29
4
  private requestId;
30
- private pending;
31
- connect(config: MCPServerConfig): Promise<void>;
32
- private send;
5
+ private pendingRequests;
6
+ private lineReader;
7
+ private config;
8
+ private errorLogs;
9
+ get errors(): readonly string[];
10
+ constructor(config: MCPServerConfig);
11
+ connect(): Promise<void>;
12
+ private sendRequest;
13
+ private handleLine;
14
+ private initialize;
33
15
  listTools(): Promise<MCPListToolsResult>;
34
16
  callTool(name: string, args: Record<string, unknown>): Promise<MCPCallToolResult>;
35
17
  disconnect(): Promise<void>;
36
18
  }
37
- export {};
38
19
  //# sourceMappingURL=client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/core/mcp/client.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,eAAe;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC7B;AAED,UAAU,aAAa;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;CACzF;AAED,UAAU,kBAAkB;IAC3B,KAAK,EAAE,aAAa,EAAE,CAAC;CACvB;AAED,UAAU,iBAAiB;IAC1B,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAClF,OAAO,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,qBAAa,SAAS;IACrB,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,OAAO,CAAoF;IAE7F,OAAO,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAqDpD;IAED,OAAO,CAAC,IAAI;IAUN,SAAS,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAE7C;IAEK,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAEtF;IAEK,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAYhC;CACD","sourcesContent":["import { type ChildProcess, spawn } from \"child_process\";\nimport { createInterface } from \"readline\";\n\nexport interface MCPServerConfig {\n\tcommand: string;\n\targs?: string[];\n\tenv?: Record<string, string>;\n}\n\ninterface MCPSimpleTool {\n\tname: string;\n\tdescription?: string;\n\tinputSchema: { type: string; properties?: Record<string, unknown>; required?: string[] };\n}\n\ninterface MCPListToolsResult {\n\ttools: MCPSimpleTool[];\n}\n\ninterface MCPCallToolResult {\n\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\tisError?: boolean;\n}\n\nexport class MCPClient {\n\tprivate process: ChildProcess | null = null;\n\tprivate requestId = 0;\n\tprivate pending = new Map<number, { resolve: (v: unknown) => void; reject: (e: Error) => void }>();\n\n\tasync connect(config: MCPServerConfig): Promise<void> {\n\t\tconst { command, args = [], env } = config;\n\t\tconst childEnv = env ? { ...process.env, ...env } : process.env;\n\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst proc = spawn(command, args, { env: childEnv, stdio: [\"pipe\", \"pipe\", \"pipe\"], shell: false });\n\t\t\tthis.process = proc;\n\n\t\t\tconst onError = (error: Error) => {\n\t\t\t\treject(new Error(`Failed to spawn MCP server \"${command}\": ${error.message}`));\n\t\t\t};\n\t\t\tproc.on(\"error\", onError);\n\t\t\tproc.once(\"spawn\", () => proc.removeListener(\"error\", onError));\n\n\t\t\tif (!proc.stdout) {\n\t\t\t\treject(new Error(`MCP server \"${command}\" has no stdout`));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst rl = createInterface({ input: proc.stdout, crlfDelay: Infinity });\n\t\t\trl.on(\"line\", (line: string) => {\n\t\t\t\ttry {\n\t\t\t\t\tconst res = JSON.parse(line);\n\t\t\t\t\tif (res.id !== undefined) {\n\t\t\t\t\t\tconst handler = this.pending.get(res.id);\n\t\t\t\t\t\tif (!handler) return;\n\t\t\t\t\t\tthis.pending.delete(res.id);\n\t\t\t\t\t\tif (res.error) {\n\t\t\t\t\t\t\thandler.reject(new Error(`MCP error: ${res.error.message} (code ${res.error.code})`));\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\thandler.resolve(res.result);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t// Non-JSON lines (stderr)\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tproc.on(\"exit\", (code) => {\n\t\t\t\tfor (const [, h] of this.pending) {\n\t\t\t\t\th.reject(new Error(`MCP server \"${command}\" exited with code ${code}`));\n\t\t\t\t}\n\t\t\t\tthis.pending.clear();\n\t\t\t});\n\n\t\t\tthis.send(\"initialize\", {\n\t\t\t\tprotocolVersion: \"2024-11-05\",\n\t\t\t\tcapabilities: {},\n\t\t\t\tclientInfo: { name: \"pi\", version: \"1.0.0\" },\n\t\t\t})\n\t\t\t\t.then(() => resolve())\n\t\t\t\t.catch(reject);\n\t\t});\n\t}\n\n\tprivate send(method: string, params?: Record<string, unknown>): Promise<unknown> {\n\t\tif (!this.process?.stdin) throw new Error(\"MCP client not connected\");\n\n\t\tconst id = ++this.requestId;\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tthis.pending.set(id, { resolve, reject });\n\t\t\tthis.process!.stdin!.write(`${JSON.stringify({ jsonrpc: \"2.0\", id, method, params })}\\n`);\n\t\t});\n\t}\n\n\tasync listTools(): Promise<MCPListToolsResult> {\n\t\treturn (await this.send(\"tools/list\")) as MCPListToolsResult;\n\t}\n\n\tasync callTool(name: string, args: Record<string, unknown>): Promise<MCPCallToolResult> {\n\t\treturn (await this.send(\"tools/call\", { name, arguments: args })) as MCPCallToolResult;\n\t}\n\n\tasync disconnect(): Promise<void> {\n\t\tconst proc = this.process;\n\t\tthis.process = null;\n\t\tthis.pending.clear();\n\t\tif (proc && !proc.killed) {\n\t\t\tproc.kill();\n\t\t\tawait new Promise<void>((resolve) => {\n\t\t\t\tif (proc.exitCode !== null) return resolve();\n\t\t\t\tproc.on(\"exit\", resolve);\n\t\t\t\tsetTimeout(resolve, 3000);\n\t\t\t});\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/core/mcp/client.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACX,iBAAiB,EAIjB,kBAAkB,EAClB,eAAe,EACf,MAAM,YAAY,CAAC;AAMpB,qBAAa,SAAS;IACrB,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,eAAe,CAA4F;IACnH,OAAO,CAAC,UAAU,CAA0B;IAC5C,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,SAAS,CAAgB;IAEjC,IAAI,MAAM,IAAI,SAAS,MAAM,EAAE,CAE9B;IAED,YAAY,MAAM,EAAE,eAAe,EAElC;IAEK,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAkD7B;YAEa,WAAW;IAoBzB,OAAO,CAAC,UAAU;YAmBJ,UAAU;IAQlB,SAAS,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAE7C;IAEK,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAKtF;IAEK,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CA2BhC;CACD","sourcesContent":["import { type ChildProcess, spawn } from \"child_process\";\nimport { createInterface, type Interface } from \"readline\";\nimport type {\n\tMCPCallToolResult,\n\tMCPInitializeResult,\n\tMCPJsonRpcRequest,\n\tMCPJsonRpcResponse,\n\tMCPListToolsResult,\n\tMCPServerConfig,\n} from \"./types.ts\";\n\nconst INITIALIZE_REQUEST = \"initialize\";\nconst TOOLS_LIST_REQUEST = \"tools/list\";\nconst TOOLS_CALL_REQUEST = \"tools/call\";\n\nexport class MCPClient {\n\tprivate process: ChildProcess | null = null;\n\tprivate requestId = 0;\n\tprivate pendingRequests = new Map<number, { resolve: (value: unknown) => void; reject: (error: Error) => void }>();\n\tprivate lineReader: Interface | null = null;\n\tprivate config: MCPServerConfig;\n\tprivate errorLogs: string[] = [];\n\n\tget errors(): readonly string[] {\n\t\treturn this.errorLogs;\n\t}\n\n\tconstructor(config: MCPServerConfig) {\n\t\tthis.config = config;\n\t}\n\n\tasync connect(): Promise<void> {\n\t\tconst { command, args = [], env } = this.config;\n\t\tconst childEnv = env ? { ...process.env, ...env } : process.env;\n\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tthis.process = spawn(command, args, {\n\t\t\t\tenv: childEnv,\n\t\t\t\tstdio: [\"pipe\", \"pipe\", \"pipe\"],\n\t\t\t\tshell: false,\n\t\t\t});\n\n\t\t\tconst onError = (error: Error) => {\n\t\t\t\treject(new Error(`Failed to spawn MCP server \"${command}\": ${error.message}`));\n\t\t\t};\n\n\t\t\tthis.process.on(\"error\", onError);\n\t\t\tthis.process.once(\"spawn\", () => {\n\t\t\t\tthis.process!.removeListener(\"error\", onError);\n\t\t\t});\n\n\t\t\tif (!this.process.stdout) {\n\t\t\t\treject(new Error(`MCP server \"${command}\" has no stdout`));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis.lineReader = createInterface({ input: this.process.stdout, crlfDelay: Infinity });\n\n\t\t\tthis.lineReader.on(\"line\", (line: string) => {\n\t\t\t\tthis.handleLine(line);\n\t\t\t});\n\n\t\t\tif (this.process.stderr) {\n\t\t\t\tthis.process.stderr.setEncoding(\"utf-8\");\n\t\t\t\tthis.process.stderr.on(\"data\", (data: string) => {\n\t\t\t\t\tthis.errorLogs.push(data);\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tthis.process.on(\"exit\", (code) => {\n\t\t\t\tconst pendingCopy = new Map(this.pendingRequests);\n\t\t\t\tthis.pendingRequests.clear();\n\t\t\t\tfor (const [, handler] of pendingCopy) {\n\t\t\t\t\thandler.reject(new Error(`MCP server \"${command}\" exited with code ${code}`));\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tthis.initialize()\n\t\t\t\t.then(() => resolve())\n\t\t\t\t.catch(reject);\n\t\t});\n\t}\n\n\tprivate async sendRequest(method: string, params?: Record<string, unknown>): Promise<unknown> {\n\t\tif (!this.process || !this.process.stdin) {\n\t\t\tthrow new Error(`MCP client not connected`);\n\t\t}\n\n\t\tconst id = ++this.requestId;\n\t\tconst request: MCPJsonRpcRequest = {\n\t\t\tjsonrpc: \"2.0\",\n\t\t\tid,\n\t\t\tmethod,\n\t\t\tparams,\n\t\t};\n\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tthis.pendingRequests.set(id, { resolve, reject });\n\t\t\tconst payload = JSON.stringify(request);\n\t\t\tthis.process!.stdin!.write(`${payload}\\n`);\n\t\t});\n\t}\n\n\tprivate handleLine(line: string): void {\n\t\ttry {\n\t\t\tconst response = JSON.parse(line) as MCPJsonRpcResponse;\n\t\t\tif (response.id !== undefined) {\n\t\t\t\tconst request = this.pendingRequests.get(response.id);\n\t\t\t\tif (request) {\n\t\t\t\t\tthis.pendingRequests.delete(response.id);\n\t\t\t\t\tif (response.error) {\n\t\t\t\t\t\trequest.reject(new Error(`MCP error: ${response.error.message} (code ${response.error.code})`));\n\t\t\t\t\t} else {\n\t\t\t\t\t\trequest.resolve(response.result);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {\n\t\t\t// Ignore non-JSON lines (stderr or informational messages)\n\t\t}\n\t}\n\n\tprivate async initialize(): Promise<MCPInitializeResult> {\n\t\treturn (await this.sendRequest(INITIALIZE_REQUEST, {\n\t\t\tprotocolVersion: \"2024-11-05\",\n\t\t\tcapabilities: {},\n\t\t\tclientInfo: { name: \"pi\", version: \"1.0.0\" },\n\t\t})) as MCPInitializeResult;\n\t}\n\n\tasync listTools(): Promise<MCPListToolsResult> {\n\t\treturn (await this.sendRequest(TOOLS_LIST_REQUEST)) as MCPListToolsResult;\n\t}\n\n\tasync callTool(name: string, args: Record<string, unknown>): Promise<MCPCallToolResult> {\n\t\treturn (await this.sendRequest(TOOLS_CALL_REQUEST, {\n\t\t\tname,\n\t\t\targuments: args,\n\t\t} as unknown as Record<string, unknown>)) as MCPCallToolResult;\n\t}\n\n\tasync disconnect(): Promise<void> {\n\t\tif (this.lineReader) {\n\t\t\tthis.lineReader.close();\n\t\t\tthis.lineReader = null;\n\t\t}\n\t\tif (this.process) {\n\t\t\tconst proc = this.process;\n\t\t\tthis.process = null;\n\t\t\tthis.pendingRequests.clear();\n\t\t\tif (!proc.killed) {\n\t\t\t\tproc.kill();\n\t\t\t\tawait new Promise<void>((resolve) => {\n\t\t\t\t\tconst onExit = () => {\n\t\t\t\t\t\tresolve();\n\t\t\t\t\t};\n\t\t\t\t\tproc.on(\"exit\", onExit);\n\t\t\t\t\tif (proc.exitCode !== null) {\n\t\t\t\t\t\tproc.removeListener(\"exit\", onExit);\n\t\t\t\t\t\tresolve();\n\t\t\t\t\t}\n\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\tproc.removeListener(\"exit\", onExit);\n\t\t\t\t\t\tresolve();\n\t\t\t\t\t}, 3000);\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
@@ -1,87 +1,142 @@
1
1
  import { spawn } from "child_process";
2
2
  import { createInterface } from "readline";
3
+ const INITIALIZE_REQUEST = "initialize";
4
+ const TOOLS_LIST_REQUEST = "tools/list";
5
+ const TOOLS_CALL_REQUEST = "tools/call";
3
6
  export class MCPClient {
4
7
  process = null;
5
8
  requestId = 0;
6
- pending = new Map();
7
- async connect(config) {
8
- const { command, args = [], env } = config;
9
+ pendingRequests = new Map();
10
+ lineReader = null;
11
+ config;
12
+ errorLogs = [];
13
+ get errors() {
14
+ return this.errorLogs;
15
+ }
16
+ constructor(config) {
17
+ this.config = config;
18
+ }
19
+ async connect() {
20
+ const { command, args = [], env } = this.config;
9
21
  const childEnv = env ? { ...process.env, ...env } : process.env;
10
22
  return new Promise((resolve, reject) => {
11
- const proc = spawn(command, args, { env: childEnv, stdio: ["pipe", "pipe", "pipe"], shell: false });
12
- this.process = proc;
23
+ this.process = spawn(command, args, {
24
+ env: childEnv,
25
+ stdio: ["pipe", "pipe", "pipe"],
26
+ shell: false,
27
+ });
13
28
  const onError = (error) => {
14
29
  reject(new Error(`Failed to spawn MCP server "${command}": ${error.message}`));
15
30
  };
16
- proc.on("error", onError);
17
- proc.once("spawn", () => proc.removeListener("error", onError));
18
- if (!proc.stdout) {
31
+ this.process.on("error", onError);
32
+ this.process.once("spawn", () => {
33
+ this.process.removeListener("error", onError);
34
+ });
35
+ if (!this.process.stdout) {
19
36
  reject(new Error(`MCP server "${command}" has no stdout`));
20
37
  return;
21
38
  }
22
- const rl = createInterface({ input: proc.stdout, crlfDelay: Infinity });
23
- rl.on("line", (line) => {
24
- try {
25
- const res = JSON.parse(line);
26
- if (res.id !== undefined) {
27
- const handler = this.pending.get(res.id);
28
- if (!handler)
29
- return;
30
- this.pending.delete(res.id);
31
- if (res.error) {
32
- handler.reject(new Error(`MCP error: ${res.error.message} (code ${res.error.code})`));
33
- }
34
- else {
35
- handler.resolve(res.result);
36
- }
37
- }
38
- }
39
- catch {
40
- // Non-JSON lines (stderr)
41
- }
39
+ this.lineReader = createInterface({ input: this.process.stdout, crlfDelay: Infinity });
40
+ this.lineReader.on("line", (line) => {
41
+ this.handleLine(line);
42
42
  });
43
- proc.on("exit", (code) => {
44
- for (const [, h] of this.pending) {
45
- h.reject(new Error(`MCP server "${command}" exited with code ${code}`));
43
+ if (this.process.stderr) {
44
+ this.process.stderr.setEncoding("utf-8");
45
+ this.process.stderr.on("data", (data) => {
46
+ this.errorLogs.push(data);
47
+ });
48
+ }
49
+ this.process.on("exit", (code) => {
50
+ const pendingCopy = new Map(this.pendingRequests);
51
+ this.pendingRequests.clear();
52
+ for (const [, handler] of pendingCopy) {
53
+ handler.reject(new Error(`MCP server "${command}" exited with code ${code}`));
46
54
  }
47
- this.pending.clear();
48
55
  });
49
- this.send("initialize", {
50
- protocolVersion: "2024-11-05",
51
- capabilities: {},
52
- clientInfo: { name: "pi", version: "1.0.0" },
53
- })
56
+ this.initialize()
54
57
  .then(() => resolve())
55
58
  .catch(reject);
56
59
  });
57
60
  }
58
- send(method, params) {
59
- if (!this.process?.stdin)
60
- throw new Error("MCP client not connected");
61
+ async sendRequest(method, params) {
62
+ if (!this.process || !this.process.stdin) {
63
+ throw new Error(`MCP client not connected`);
64
+ }
61
65
  const id = ++this.requestId;
66
+ const request = {
67
+ jsonrpc: "2.0",
68
+ id,
69
+ method,
70
+ params,
71
+ };
62
72
  return new Promise((resolve, reject) => {
63
- this.pending.set(id, { resolve, reject });
64
- this.process.stdin.write(`${JSON.stringify({ jsonrpc: "2.0", id, method, params })}\n`);
73
+ this.pendingRequests.set(id, { resolve, reject });
74
+ const payload = JSON.stringify(request);
75
+ this.process.stdin.write(`${payload}\n`);
65
76
  });
66
77
  }
78
+ handleLine(line) {
79
+ try {
80
+ const response = JSON.parse(line);
81
+ if (response.id !== undefined) {
82
+ const request = this.pendingRequests.get(response.id);
83
+ if (request) {
84
+ this.pendingRequests.delete(response.id);
85
+ if (response.error) {
86
+ request.reject(new Error(`MCP error: ${response.error.message} (code ${response.error.code})`));
87
+ }
88
+ else {
89
+ request.resolve(response.result);
90
+ }
91
+ }
92
+ }
93
+ }
94
+ catch {
95
+ // Ignore non-JSON lines (stderr or informational messages)
96
+ }
97
+ }
98
+ async initialize() {
99
+ return (await this.sendRequest(INITIALIZE_REQUEST, {
100
+ protocolVersion: "2024-11-05",
101
+ capabilities: {},
102
+ clientInfo: { name: "pi", version: "1.0.0" },
103
+ }));
104
+ }
67
105
  async listTools() {
68
- return (await this.send("tools/list"));
106
+ return (await this.sendRequest(TOOLS_LIST_REQUEST));
69
107
  }
70
108
  async callTool(name, args) {
71
- return (await this.send("tools/call", { name, arguments: args }));
109
+ return (await this.sendRequest(TOOLS_CALL_REQUEST, {
110
+ name,
111
+ arguments: args,
112
+ }));
72
113
  }
73
114
  async disconnect() {
74
- const proc = this.process;
75
- this.process = null;
76
- this.pending.clear();
77
- if (proc && !proc.killed) {
78
- proc.kill();
79
- await new Promise((resolve) => {
80
- if (proc.exitCode !== null)
81
- return resolve();
82
- proc.on("exit", resolve);
83
- setTimeout(resolve, 3000);
84
- });
115
+ if (this.lineReader) {
116
+ this.lineReader.close();
117
+ this.lineReader = null;
118
+ }
119
+ if (this.process) {
120
+ const proc = this.process;
121
+ this.process = null;
122
+ this.pendingRequests.clear();
123
+ if (!proc.killed) {
124
+ proc.kill();
125
+ await new Promise((resolve) => {
126
+ const onExit = () => {
127
+ resolve();
128
+ };
129
+ proc.on("exit", onExit);
130
+ if (proc.exitCode !== null) {
131
+ proc.removeListener("exit", onExit);
132
+ resolve();
133
+ }
134
+ setTimeout(() => {
135
+ proc.removeListener("exit", onExit);
136
+ resolve();
137
+ }, 3000);
138
+ });
139
+ }
85
140
  }
86
141
  }
87
142
  }
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../../../src/core/mcp/client.ts"],"names":[],"mappings":"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","sourcesContent":["import { type ChildProcess, spawn } from \"child_process\";\nimport { createInterface } from \"readline\";\n\nexport interface MCPServerConfig {\n\tcommand: string;\n\targs?: string[];\n\tenv?: Record<string, string>;\n}\n\ninterface MCPSimpleTool {\n\tname: string;\n\tdescription?: string;\n\tinputSchema: { type: string; properties?: Record<string, unknown>; required?: string[] };\n}\n\ninterface MCPListToolsResult {\n\ttools: MCPSimpleTool[];\n}\n\ninterface MCPCallToolResult {\n\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\tisError?: boolean;\n}\n\nexport class MCPClient {\n\tprivate process: ChildProcess | null = null;\n\tprivate requestId = 0;\n\tprivate pending = new Map<number, { resolve: (v: unknown) => void; reject: (e: Error) => void }>();\n\n\tasync connect(config: MCPServerConfig): Promise<void> {\n\t\tconst { command, args = [], env } = config;\n\t\tconst childEnv = env ? { ...process.env, ...env } : process.env;\n\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst proc = spawn(command, args, { env: childEnv, stdio: [\"pipe\", \"pipe\", \"pipe\"], shell: false });\n\t\t\tthis.process = proc;\n\n\t\t\tconst onError = (error: Error) => {\n\t\t\t\treject(new Error(`Failed to spawn MCP server \"${command}\": ${error.message}`));\n\t\t\t};\n\t\t\tproc.on(\"error\", onError);\n\t\t\tproc.once(\"spawn\", () => proc.removeListener(\"error\", onError));\n\n\t\t\tif (!proc.stdout) {\n\t\t\t\treject(new Error(`MCP server \"${command}\" has no stdout`));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst rl = createInterface({ input: proc.stdout, crlfDelay: Infinity });\n\t\t\trl.on(\"line\", (line: string) => {\n\t\t\t\ttry {\n\t\t\t\t\tconst res = JSON.parse(line);\n\t\t\t\t\tif (res.id !== undefined) {\n\t\t\t\t\t\tconst handler = this.pending.get(res.id);\n\t\t\t\t\t\tif (!handler) return;\n\t\t\t\t\t\tthis.pending.delete(res.id);\n\t\t\t\t\t\tif (res.error) {\n\t\t\t\t\t\t\thandler.reject(new Error(`MCP error: ${res.error.message} (code ${res.error.code})`));\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\thandler.resolve(res.result);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t// Non-JSON lines (stderr)\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tproc.on(\"exit\", (code) => {\n\t\t\t\tfor (const [, h] of this.pending) {\n\t\t\t\t\th.reject(new Error(`MCP server \"${command}\" exited with code ${code}`));\n\t\t\t\t}\n\t\t\t\tthis.pending.clear();\n\t\t\t});\n\n\t\t\tthis.send(\"initialize\", {\n\t\t\t\tprotocolVersion: \"2024-11-05\",\n\t\t\t\tcapabilities: {},\n\t\t\t\tclientInfo: { name: \"pi\", version: \"1.0.0\" },\n\t\t\t})\n\t\t\t\t.then(() => resolve())\n\t\t\t\t.catch(reject);\n\t\t});\n\t}\n\n\tprivate send(method: string, params?: Record<string, unknown>): Promise<unknown> {\n\t\tif (!this.process?.stdin) throw new Error(\"MCP client not connected\");\n\n\t\tconst id = ++this.requestId;\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tthis.pending.set(id, { resolve, reject });\n\t\t\tthis.process!.stdin!.write(`${JSON.stringify({ jsonrpc: \"2.0\", id, method, params })}\\n`);\n\t\t});\n\t}\n\n\tasync listTools(): Promise<MCPListToolsResult> {\n\t\treturn (await this.send(\"tools/list\")) as MCPListToolsResult;\n\t}\n\n\tasync callTool(name: string, args: Record<string, unknown>): Promise<MCPCallToolResult> {\n\t\treturn (await this.send(\"tools/call\", { name, arguments: args })) as MCPCallToolResult;\n\t}\n\n\tasync disconnect(): Promise<void> {\n\t\tconst proc = this.process;\n\t\tthis.process = null;\n\t\tthis.pending.clear();\n\t\tif (proc && !proc.killed) {\n\t\t\tproc.kill();\n\t\t\tawait new Promise<void>((resolve) => {\n\t\t\t\tif (proc.exitCode !== null) return resolve();\n\t\t\t\tproc.on(\"exit\", resolve);\n\t\t\t\tsetTimeout(resolve, 3000);\n\t\t\t});\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../../src/core/mcp/client.ts"],"names":[],"mappings":"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","sourcesContent":["import { type ChildProcess, spawn } from \"child_process\";\nimport { createInterface, type Interface } from \"readline\";\nimport type {\n\tMCPCallToolResult,\n\tMCPInitializeResult,\n\tMCPJsonRpcRequest,\n\tMCPJsonRpcResponse,\n\tMCPListToolsResult,\n\tMCPServerConfig,\n} from \"./types.ts\";\n\nconst INITIALIZE_REQUEST = \"initialize\";\nconst TOOLS_LIST_REQUEST = \"tools/list\";\nconst TOOLS_CALL_REQUEST = \"tools/call\";\n\nexport class MCPClient {\n\tprivate process: ChildProcess | null = null;\n\tprivate requestId = 0;\n\tprivate pendingRequests = new Map<number, { resolve: (value: unknown) => void; reject: (error: Error) => void }>();\n\tprivate lineReader: Interface | null = null;\n\tprivate config: MCPServerConfig;\n\tprivate errorLogs: string[] = [];\n\n\tget errors(): readonly string[] {\n\t\treturn this.errorLogs;\n\t}\n\n\tconstructor(config: MCPServerConfig) {\n\t\tthis.config = config;\n\t}\n\n\tasync connect(): Promise<void> {\n\t\tconst { command, args = [], env } = this.config;\n\t\tconst childEnv = env ? { ...process.env, ...env } : process.env;\n\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tthis.process = spawn(command, args, {\n\t\t\t\tenv: childEnv,\n\t\t\t\tstdio: [\"pipe\", \"pipe\", \"pipe\"],\n\t\t\t\tshell: false,\n\t\t\t});\n\n\t\t\tconst onError = (error: Error) => {\n\t\t\t\treject(new Error(`Failed to spawn MCP server \"${command}\": ${error.message}`));\n\t\t\t};\n\n\t\t\tthis.process.on(\"error\", onError);\n\t\t\tthis.process.once(\"spawn\", () => {\n\t\t\t\tthis.process!.removeListener(\"error\", onError);\n\t\t\t});\n\n\t\t\tif (!this.process.stdout) {\n\t\t\t\treject(new Error(`MCP server \"${command}\" has no stdout`));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis.lineReader = createInterface({ input: this.process.stdout, crlfDelay: Infinity });\n\n\t\t\tthis.lineReader.on(\"line\", (line: string) => {\n\t\t\t\tthis.handleLine(line);\n\t\t\t});\n\n\t\t\tif (this.process.stderr) {\n\t\t\t\tthis.process.stderr.setEncoding(\"utf-8\");\n\t\t\t\tthis.process.stderr.on(\"data\", (data: string) => {\n\t\t\t\t\tthis.errorLogs.push(data);\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tthis.process.on(\"exit\", (code) => {\n\t\t\t\tconst pendingCopy = new Map(this.pendingRequests);\n\t\t\t\tthis.pendingRequests.clear();\n\t\t\t\tfor (const [, handler] of pendingCopy) {\n\t\t\t\t\thandler.reject(new Error(`MCP server \"${command}\" exited with code ${code}`));\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tthis.initialize()\n\t\t\t\t.then(() => resolve())\n\t\t\t\t.catch(reject);\n\t\t});\n\t}\n\n\tprivate async sendRequest(method: string, params?: Record<string, unknown>): Promise<unknown> {\n\t\tif (!this.process || !this.process.stdin) {\n\t\t\tthrow new Error(`MCP client not connected`);\n\t\t}\n\n\t\tconst id = ++this.requestId;\n\t\tconst request: MCPJsonRpcRequest = {\n\t\t\tjsonrpc: \"2.0\",\n\t\t\tid,\n\t\t\tmethod,\n\t\t\tparams,\n\t\t};\n\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tthis.pendingRequests.set(id, { resolve, reject });\n\t\t\tconst payload = JSON.stringify(request);\n\t\t\tthis.process!.stdin!.write(`${payload}\\n`);\n\t\t});\n\t}\n\n\tprivate handleLine(line: string): void {\n\t\ttry {\n\t\t\tconst response = JSON.parse(line) as MCPJsonRpcResponse;\n\t\t\tif (response.id !== undefined) {\n\t\t\t\tconst request = this.pendingRequests.get(response.id);\n\t\t\t\tif (request) {\n\t\t\t\t\tthis.pendingRequests.delete(response.id);\n\t\t\t\t\tif (response.error) {\n\t\t\t\t\t\trequest.reject(new Error(`MCP error: ${response.error.message} (code ${response.error.code})`));\n\t\t\t\t\t} else {\n\t\t\t\t\t\trequest.resolve(response.result);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {\n\t\t\t// Ignore non-JSON lines (stderr or informational messages)\n\t\t}\n\t}\n\n\tprivate async initialize(): Promise<MCPInitializeResult> {\n\t\treturn (await this.sendRequest(INITIALIZE_REQUEST, {\n\t\t\tprotocolVersion: \"2024-11-05\",\n\t\t\tcapabilities: {},\n\t\t\tclientInfo: { name: \"pi\", version: \"1.0.0\" },\n\t\t})) as MCPInitializeResult;\n\t}\n\n\tasync listTools(): Promise<MCPListToolsResult> {\n\t\treturn (await this.sendRequest(TOOLS_LIST_REQUEST)) as MCPListToolsResult;\n\t}\n\n\tasync callTool(name: string, args: Record<string, unknown>): Promise<MCPCallToolResult> {\n\t\treturn (await this.sendRequest(TOOLS_CALL_REQUEST, {\n\t\t\tname,\n\t\t\targuments: args,\n\t\t} as unknown as Record<string, unknown>)) as MCPCallToolResult;\n\t}\n\n\tasync disconnect(): Promise<void> {\n\t\tif (this.lineReader) {\n\t\t\tthis.lineReader.close();\n\t\t\tthis.lineReader = null;\n\t\t}\n\t\tif (this.process) {\n\t\t\tconst proc = this.process;\n\t\t\tthis.process = null;\n\t\t\tthis.pendingRequests.clear();\n\t\t\tif (!proc.killed) {\n\t\t\t\tproc.kill();\n\t\t\t\tawait new Promise<void>((resolve) => {\n\t\t\t\t\tconst onExit = () => {\n\t\t\t\t\t\tresolve();\n\t\t\t\t\t};\n\t\t\t\t\tproc.on(\"exit\", onExit);\n\t\t\t\t\tif (proc.exitCode !== null) {\n\t\t\t\t\t\tproc.removeListener(\"exit\", onExit);\n\t\t\t\t\t\tresolve();\n\t\t\t\t\t}\n\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\tproc.removeListener(\"exit\", onExit);\n\t\t\t\t\t\tresolve();\n\t\t\t\t\t}, 3000);\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
@@ -1,3 +1,5 @@
1
- export { MCPClient, type MCPServerConfig } from "./client.ts";
1
+ export { MCPClient } from "./client.ts";
2
+ export type { McpServerTools } from "./manager.ts";
2
3
  export { MCPManager } from "./manager.ts";
4
+ export type { MCPCallToolContent, MCPCallToolImageContent, MCPCallToolResult, MCPCallToolTextContent, MCPServerConfig, MCPToolDefinition, } from "./types.ts";
3
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/mcp/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC","sourcesContent":["export { MCPClient, type MCPServerConfig } from \"./client.ts\";\nexport { MCPManager } from \"./manager.ts\";\n"]}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/mcp/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,YAAY,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,YAAY,EACX,kBAAkB,EAClB,uBAAuB,EACvB,iBAAiB,EACjB,sBAAsB,EACtB,eAAe,EACf,iBAAiB,GACjB,MAAM,YAAY,CAAC","sourcesContent":["export { MCPClient } from \"./client.ts\";\nexport type { McpServerTools } from \"./manager.ts\";\nexport { MCPManager } from \"./manager.ts\";\nexport type {\n\tMCPCallToolContent,\n\tMCPCallToolImageContent,\n\tMCPCallToolResult,\n\tMCPCallToolTextContent,\n\tMCPServerConfig,\n\tMCPToolDefinition,\n} from \"./types.ts\";\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/mcp/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAwB,MAAM,aAAa,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC","sourcesContent":["export { MCPClient, type MCPServerConfig } from \"./client.ts\";\nexport { MCPManager } from \"./manager.ts\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/mcp/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC","sourcesContent":["export { MCPClient } from \"./client.ts\";\nexport type { McpServerTools } from \"./manager.ts\";\nexport { MCPManager } from \"./manager.ts\";\nexport type {\n\tMCPCallToolContent,\n\tMCPCallToolImageContent,\n\tMCPCallToolResult,\n\tMCPCallToolTextContent,\n\tMCPServerConfig,\n\tMCPToolDefinition,\n} from \"./types.ts\";\n"]}
@@ -1,9 +1,15 @@
1
1
  import type { ToolDefinition } from "../extensions/types.ts";
2
- import { type MCPServerConfig } from "./client.ts";
2
+ import type { MCPServerConfig } from "./types.ts";
3
+ export interface McpServerTools {
4
+ serverName: string;
5
+ tools: ToolDefinition[];
6
+ }
3
7
  export declare class MCPManager {
8
+ private serverConfigs;
4
9
  private clients;
5
- private tools;
6
- start(serverConfigs: Record<string, MCPServerConfig>): Promise<void>;
10
+ private serverTools;
11
+ constructor(serverConfigs: Record<string, MCPServerConfig>);
12
+ start(): Promise<void>;
7
13
  getToolDefinitions(): ToolDefinition[];
8
14
  getServerNames(): string[];
9
15
  stop(): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../../src/core/mcp/manager.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,EAAa,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAyC9D,qBAAa,UAAU;IACtB,OAAO,CAAC,OAAO,CAAgC;IAC/C,OAAO,CAAC,KAAK,CAAuC;IAE9C,KAAK,CAAC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CA6CzE;IAED,kBAAkB,IAAI,cAAc,EAAE,CAErC;IAED,cAAc,IAAI,MAAM,EAAE,CAEzB;IAEK,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAa1B;CACD","sourcesContent":["import type { AgentToolResult } from \"@openeryc/pi-agent-core\";\nimport { Type } from \"typebox\";\nimport type { ToolDefinition } from \"../extensions/types.ts\";\nimport { MCPClient, type MCPServerConfig } from \"./client.ts\";\n\nfunction toTypeBox(jsonSchema: {\n\ttype: string;\n\tproperties?: Record<string, unknown>;\n\trequired?: string[];\n}): ReturnType<typeof Type.Object> {\n\tif (!jsonSchema.properties || Object.keys(jsonSchema.properties).length === 0) {\n\t\treturn Type.Object({});\n\t}\n\n\tconst required = new Set(jsonSchema.required ?? []);\n\tconst fields: Record<string, unknown> = {};\n\n\tfor (const [key, prop] of Object.entries(jsonSchema.properties)) {\n\t\tconst p = prop as { type?: string; description?: string; enum?: string[] };\n\t\tconst type = p.type ?? \"string\";\n\t\tconst desc = p.description ? { description: p.description } : {};\n\n\t\tlet field: unknown;\n\t\tswitch (type) {\n\t\t\tcase \"string\":\n\t\t\t\tfield = p.enum ? Type.Unsafe<string>({ type: \"string\", enum: p.enum, ...desc }) : Type.String(desc);\n\t\t\t\tbreak;\n\t\t\tcase \"number\":\n\t\t\tcase \"integer\":\n\t\t\t\tfield = Type.Number(desc);\n\t\t\t\tbreak;\n\t\t\tcase \"boolean\":\n\t\t\t\tfield = Type.Boolean(desc);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tfield = Type.Any(desc);\n\t\t}\n\n\t\tfields[key] = required.has(key) ? field : Type.Optional(field as never);\n\t}\n\n\treturn Type.Object(fields as Record<string, ReturnType<typeof Type.String>>);\n}\n\nexport class MCPManager {\n\tprivate clients = new Map<string, MCPClient>();\n\tprivate tools = new Map<string, ToolDefinition[]>();\n\n\tasync start(serverConfigs: Record<string, MCPServerConfig>): Promise<void> {\n\t\tfor (const [serverName, config] of Object.entries(serverConfigs)) {\n\t\t\ttry {\n\t\t\t\tconst client = new MCPClient();\n\t\t\t\tawait client.connect(config);\n\t\t\t\tconst { tools: mcpTools } = await client.listTools();\n\t\t\t\tthis.clients.set(serverName, client);\n\n\t\t\t\tconst defs: ToolDefinition[] = mcpTools.map((tool) => ({\n\t\t\t\t\tname: `mcp.${serverName}.${tool.name}`,\n\t\t\t\t\tlabel: `mcp.${serverName}.${tool.name}`,\n\t\t\t\t\tdescription: tool.description\n\t\t\t\t\t\t? `${tool.description} (from MCP server \"${serverName}\")`\n\t\t\t\t\t\t: `Tool from MCP server \"${serverName}\"`,\n\t\t\t\t\tpromptSnippet: `mcp.${serverName}.${tool.name}`,\n\t\t\t\t\tparameters: toTypeBox(tool.inputSchema),\n\t\t\t\t\trenderShell: \"default\" as const,\n\t\t\t\t\texecutionMode: \"sequential\" as const,\n\t\t\t\t\texecute: async (_id, params, _signal) => {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst result = await client.callTool(tool.name, params as Record<string, unknown>);\n\t\t\t\t\t\t\tconst text = result.content\n\t\t\t\t\t\t\t\t.map((item) => (item.type === \"text\" && item.text ? item.text : `[Image: ${item.mimeType}]`))\n\t\t\t\t\t\t\t\t.join(\"\\n\");\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\tcontent: [{ type: \"text\" as const, text }],\n\t\t\t\t\t\t\t\tdetails: result,\n\t\t\t\t\t\t\t} satisfies AgentToolResult<unknown>;\n\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\tconst msg = error instanceof Error ? error.message : String(error);\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\tcontent: [{ type: \"text\" as const, text: `MCP tool error: ${msg}` }],\n\t\t\t\t\t\t\t\tdetails: { error: msg },\n\t\t\t\t\t\t\t} satisfies AgentToolResult<unknown>;\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t}));\n\n\t\t\t\tthis.tools.set(serverName, defs);\n\t\t\t} catch (error) {\n\t\t\t\tconsole.warn(\n\t\t\t\t\t`Failed to connect to MCP server \"${serverName}\": ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tgetToolDefinitions(): ToolDefinition[] {\n\t\treturn Array.from(this.tools.values()).flat();\n\t}\n\n\tgetServerNames(): string[] {\n\t\treturn [...this.clients.keys()];\n\t}\n\n\tasync stop(): Promise<void> {\n\t\tconst pending = [...this.clients.entries()].map(async ([name, client]) => {\n\t\t\ttry {\n\t\t\t\tawait client.disconnect();\n\t\t\t} catch (error) {\n\t\t\t\tconsole.warn(\n\t\t\t\t\t`Error disconnecting MCP server \"${name}\": ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t\t);\n\t\t\t}\n\t\t});\n\t\tthis.clients.clear();\n\t\tthis.tools.clear();\n\t\tawait Promise.all(pending);\n\t}\n}\n"]}
1
+ {"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../../src/core/mcp/manager.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAE7D,OAAO,KAAK,EAAE,eAAe,EAAqB,MAAM,YAAY,CAAC;AAkErE,MAAM,WAAW,cAAc;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,cAAc,EAAE,CAAC;CACxB;AAED,qBAAa,UAAU;IACtB,OAAO,CAAC,aAAa,CAAkC;IACvD,OAAO,CAAC,OAAO,CAAgC;IAC/C,OAAO,CAAC,WAAW,CAAuC;IAE1D,YAAY,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,EAEzD;IAEK,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAmD3B;IAED,kBAAkB,IAAI,cAAc,EAAE,CAMrC;IAED,cAAc,IAAI,MAAM,EAAE,CAEzB;IAEK,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAc1B;CACD","sourcesContent":["import type { AgentToolResult } from \"@openeryc/pi-agent-core\";\nimport { Type } from \"typebox\";\nimport type { ToolDefinition } from \"../extensions/types.ts\";\nimport { MCPClient } from \"./client.ts\";\nimport type { MCPServerConfig, MCPToolDefinition } from \"./types.ts\";\n\nfunction jsonSchemaToTypeBox(schema: MCPToolDefinition[\"inputSchema\"]): ReturnType<typeof Type.Object> {\n\tconst properties: Record<string, unknown> = {};\n\n\tif (schema.properties) {\n\t\tfor (const [key, prop] of Object.entries(schema.properties)) {\n\t\t\tconst type = prop.type || \"string\";\n\t\t\tlet field: unknown;\n\n\t\t\tswitch (type) {\n\t\t\t\tcase \"string\":\n\t\t\t\t\tfield = prop.enum ? Type.Unsafe<string>({ type: \"string\", enum: prop.enum as string[] }) : Type.String();\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"number\":\n\t\t\t\tcase \"integer\":\n\t\t\t\t\tfield = Type.Number();\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"boolean\":\n\t\t\t\t\tfield = Type.Boolean();\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"array\":\n\t\t\t\t\tfield = Type.Array(Type.Any());\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"object\":\n\t\t\t\t\tfield = Type.Record(Type.String(), Type.Any());\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tfield = Type.Any();\n\t\t\t}\n\n\t\t\tif (prop.description) {\n\t\t\t\t(field as { description?: string }).description = prop.description;\n\t\t\t}\n\n\t\t\tproperties[key] = field;\n\t\t}\n\t}\n\n\tif (Object.keys(properties).length === 0) {\n\t\treturn Type.Object({});\n\t}\n\n\tconst required = new Set(schema.required ?? []);\n\tfor (const key of Object.keys(properties)) {\n\t\tif (!required.has(key)) {\n\t\t\tproperties[key] = Type.Optional(properties[key] as ReturnType<typeof Type.String>);\n\t\t}\n\t}\n\n\treturn Type.Object(properties as Record<string, ReturnType<typeof Type.String>>);\n}\n\nfunction formatToolResult(result: {\n\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n}): string {\n\treturn result.content\n\t\t.map((item) => {\n\t\t\tif (item.type === \"text\" && item.text !== undefined) {\n\t\t\t\treturn item.text;\n\t\t\t}\n\t\t\treturn `[Image: ${item.mimeType}]`;\n\t\t})\n\t\t.join(\"\\n\");\n}\n\nexport interface McpServerTools {\n\tserverName: string;\n\ttools: ToolDefinition[];\n}\n\nexport class MCPManager {\n\tprivate serverConfigs: Record<string, MCPServerConfig>;\n\tprivate clients = new Map<string, MCPClient>();\n\tprivate serverTools = new Map<string, ToolDefinition[]>();\n\n\tconstructor(serverConfigs: Record<string, MCPServerConfig>) {\n\t\tthis.serverConfigs = { ...serverConfigs };\n\t}\n\n\tasync start(): Promise<void> {\n\t\tfor (const [serverName, config] of Object.entries(this.serverConfigs)) {\n\t\t\ttry {\n\t\t\t\tconst client = new MCPClient(config);\n\t\t\t\tawait client.connect();\n\n\t\t\t\tconst toolsResult = await client.listTools();\n\t\t\t\tthis.clients.set(serverName, client);\n\n\t\t\t\tconst tools: ToolDefinition[] = [];\n\t\t\t\tfor (const tool of toolsResult.tools) {\n\t\t\t\t\tconst namespacedName = `mcp.${serverName}.${tool.name}`;\n\t\t\t\t\tconst description = tool.description\n\t\t\t\t\t\t? `${tool.description} (from MCP server \"${serverName}\")`\n\t\t\t\t\t\t: `Tool from MCP server \"${serverName}\"`;\n\n\t\t\t\t\ttools.push({\n\t\t\t\t\t\tname: namespacedName,\n\t\t\t\t\t\tlabel: namespacedName,\n\t\t\t\t\t\tdescription,\n\t\t\t\t\t\tpromptSnippet: namespacedName,\n\t\t\t\t\t\tparameters: jsonSchemaToTypeBox(tool.inputSchema),\n\t\t\t\t\t\trenderShell: \"default\",\n\t\t\t\t\t\texecutionMode: \"sequential\",\n\t\t\t\t\t\texecute: async (_toolCallId, params, _signal) => {\n\t\t\t\t\t\t\tconst result: AgentToolResult<unknown> = {\n\t\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: \"\" }],\n\t\t\t\t\t\t\t\tdetails: {},\n\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tconst mcpResult = await client.callTool(tool.name, params as Record<string, unknown>);\n\t\t\t\t\t\t\t\tresult.content = [{ type: \"text\", text: formatToolResult(mcpResult) }];\n\t\t\t\t\t\t\t\tresult.details = mcpResult;\n\t\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\t\tconst errMsg = error instanceof Error ? error.message : String(error);\n\t\t\t\t\t\t\t\tresult.content = [{ type: \"text\", text: `MCP tool error: ${errMsg}` }];\n\t\t\t\t\t\t\t\tresult.details = { error: errMsg };\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\treturn result;\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tthis.serverTools.set(serverName, tools);\n\t\t\t} catch (error) {\n\t\t\t\tconst errMsg = error instanceof Error ? error.message : String(error);\n\t\t\t\tconsole.warn(`Failed to connect to MCP server \"${serverName}\": ${errMsg}`);\n\t\t\t}\n\t\t}\n\t}\n\n\tgetToolDefinitions(): ToolDefinition[] {\n\t\tconst allTools: ToolDefinition[] = [];\n\t\tfor (const tools of this.serverTools.values()) {\n\t\t\tallTools.push(...tools);\n\t\t}\n\t\treturn allTools;\n\t}\n\n\tgetServerNames(): string[] {\n\t\treturn [...this.clients.keys()];\n\t}\n\n\tasync stop(): Promise<void> {\n\t\tconst disconnectPromises: Promise<void>[] = [];\n\t\tfor (const [name, client] of this.clients) {\n\t\t\tdisconnectPromises.push(\n\t\t\t\tclient.disconnect().catch((err) => {\n\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t`Error disconnecting from MCP server \"${name}\": ${err instanceof Error ? err.message : String(err)}`,\n\t\t\t\t\t);\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t\tthis.clients.clear();\n\t\tthis.serverTools.clear();\n\t\tawait Promise.all(disconnectPromises);\n\t}\n}\n"]}