@xagent-ai/cli 1.2.2 → 1.3.1

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 (602) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.md +38 -38
  2. package/.github/ISSUE_TEMPLATE/feature_request.md +20 -20
  3. package/.github/release.yml +76 -0
  4. package/.github/workflows/ci.yml +75 -0
  5. package/.github/workflows/release.yml +103 -0
  6. package/.gitmodules +3 -3
  7. package/README.md +326 -280
  8. package/README_CN.md +325 -279
  9. package/dist/agents.d.ts.map +1 -1
  10. package/dist/agents.js +7 -3
  11. package/dist/agents.js.map +1 -1
  12. package/dist/ai-client/factory.d.ts +40 -0
  13. package/dist/ai-client/factory.d.ts.map +1 -0
  14. package/dist/ai-client/factory.js +100 -0
  15. package/dist/ai-client/factory.js.map +1 -0
  16. package/dist/ai-client/index.d.ts +20 -0
  17. package/dist/ai-client/index.d.ts.map +1 -0
  18. package/dist/ai-client/index.js +49 -0
  19. package/dist/ai-client/index.js.map +1 -0
  20. package/dist/ai-client/providers/anthropic.d.ts +57 -0
  21. package/dist/ai-client/providers/anthropic.d.ts.map +1 -0
  22. package/dist/ai-client/providers/anthropic.js +406 -0
  23. package/dist/ai-client/providers/anthropic.js.map +1 -0
  24. package/dist/ai-client/providers/openai.d.ts +57 -0
  25. package/dist/ai-client/providers/openai.d.ts.map +1 -0
  26. package/dist/ai-client/providers/openai.js +290 -0
  27. package/dist/ai-client/providers/openai.js.map +1 -0
  28. package/dist/ai-client/providers/remote.d.ts +110 -0
  29. package/dist/ai-client/providers/remote.d.ts.map +1 -0
  30. package/dist/ai-client/providers/remote.js +352 -0
  31. package/dist/ai-client/providers/remote.js.map +1 -0
  32. package/dist/ai-client/registry.d.ts +51 -0
  33. package/dist/ai-client/registry.d.ts.map +1 -0
  34. package/dist/ai-client/registry.js +81 -0
  35. package/dist/ai-client/registry.js.map +1 -0
  36. package/dist/ai-client/types.d.ts +274 -0
  37. package/dist/ai-client/types.d.ts.map +1 -0
  38. package/dist/ai-client/types.js +90 -0
  39. package/dist/ai-client/types.js.map +1 -0
  40. package/dist/ai-client-factory.d.ts +62 -0
  41. package/dist/ai-client-factory.d.ts.map +1 -0
  42. package/dist/ai-client-factory.js +157 -0
  43. package/dist/ai-client-factory.js.map +1 -0
  44. package/dist/auth.d.ts +23 -1
  45. package/dist/auth.d.ts.map +1 -1
  46. package/dist/auth.js +164 -174
  47. package/dist/auth.js.map +1 -1
  48. package/dist/cancellation.d.ts +5 -4
  49. package/dist/cancellation.d.ts.map +1 -1
  50. package/dist/cancellation.js +53 -32
  51. package/dist/cancellation.js.map +1 -1
  52. package/dist/checkpoint.d.ts +2 -1
  53. package/dist/checkpoint.d.ts.map +1 -1
  54. package/dist/checkpoint.js +39 -6
  55. package/dist/checkpoint.js.map +1 -1
  56. package/dist/cli.js +742 -29
  57. package/dist/cli.js.map +1 -1
  58. package/dist/config.d.ts +10 -4
  59. package/dist/config.d.ts.map +1 -1
  60. package/dist/config.js +62 -25
  61. package/dist/config.js.map +1 -1
  62. package/dist/context-compressor.d.ts +82 -18
  63. package/dist/context-compressor.d.ts.map +1 -1
  64. package/dist/context-compressor.js +718 -154
  65. package/dist/context-compressor.js.map +1 -1
  66. package/dist/conversation.d.ts +1 -1
  67. package/dist/conversation.d.ts.map +1 -1
  68. package/dist/conversation.js +8 -7
  69. package/dist/conversation.js.map +1 -1
  70. package/dist/gui-subagent/action-parser/actionParser.d.ts.map +1 -1
  71. package/dist/gui-subagent/action-parser/actionParser.js +6 -4
  72. package/dist/gui-subagent/action-parser/actionParser.js.map +1 -1
  73. package/dist/gui-subagent/agent/gui-agent.d.ts +39 -2
  74. package/dist/gui-subagent/agent/gui-agent.d.ts.map +1 -1
  75. package/dist/gui-subagent/agent/gui-agent.js +189 -74
  76. package/dist/gui-subagent/agent/gui-agent.js.map +1 -1
  77. package/dist/gui-subagent/index.d.ts +23 -1
  78. package/dist/gui-subagent/index.d.ts.map +1 -1
  79. package/dist/gui-subagent/index.js +6 -0
  80. package/dist/gui-subagent/index.js.map +1 -1
  81. package/dist/gui-subagent/operator/base-operator.d.ts.map +1 -1
  82. package/dist/gui-subagent/operator/base-operator.js +0 -1
  83. package/dist/gui-subagent/operator/base-operator.js.map +1 -1
  84. package/dist/gui-subagent/operator/computer-operator.d.ts.map +1 -1
  85. package/dist/gui-subagent/operator/computer-operator.js +31 -8
  86. package/dist/gui-subagent/operator/computer-operator.js.map +1 -1
  87. package/dist/gui-subagent/types/actions.d.ts +1 -1
  88. package/dist/gui-subagent/types/actions.d.ts.map +1 -1
  89. package/dist/gui-subagent/types/actions.js +0 -1
  90. package/dist/gui-subagent/types/actions.js.map +1 -1
  91. package/dist/gui-subagent/types/operator.d.ts +1 -1
  92. package/dist/gui-subagent/types/operator.d.ts.map +1 -1
  93. package/dist/index.d.ts +1 -2
  94. package/dist/index.d.ts.map +1 -1
  95. package/dist/index.js +1 -2
  96. package/dist/index.js.map +1 -1
  97. package/dist/input-processor.d.ts.map +1 -1
  98. package/dist/input-processor.js +8 -5
  99. package/dist/input-processor.js.map +1 -1
  100. package/dist/logger.d.ts.map +1 -1
  101. package/dist/logger.js +1 -1
  102. package/dist/logger.js.map +1 -1
  103. package/dist/mcp.d.ts +7 -1
  104. package/dist/mcp.d.ts.map +1 -1
  105. package/dist/mcp.js +157 -49
  106. package/dist/mcp.js.map +1 -1
  107. package/dist/memory.d.ts.map +1 -1
  108. package/dist/memory.js +3 -3
  109. package/dist/memory.js.map +1 -1
  110. package/dist/output-util.d.ts +27 -0
  111. package/dist/output-util.d.ts.map +1 -0
  112. package/dist/output-util.js +74 -0
  113. package/dist/output-util.js.map +1 -0
  114. package/dist/retry.js +1 -1
  115. package/dist/retry.js.map +1 -1
  116. package/dist/ripgrep.d.ts +29 -0
  117. package/dist/ripgrep.d.ts.map +1 -0
  118. package/dist/ripgrep.js +294 -0
  119. package/dist/ripgrep.js.map +1 -0
  120. package/dist/sdk-output-adapter.d.ts +34 -1
  121. package/dist/sdk-output-adapter.d.ts.map +1 -1
  122. package/dist/sdk-output-adapter.js +67 -2
  123. package/dist/sdk-output-adapter.js.map +1 -1
  124. package/dist/sdk-session.d.ts.map +1 -1
  125. package/dist/sdk-session.js +2 -0
  126. package/dist/sdk-session.js.map +1 -1
  127. package/dist/session-manager.js +3 -3
  128. package/dist/session-manager.js.map +1 -1
  129. package/dist/session.d.ts +116 -6
  130. package/dist/session.d.ts.map +1 -1
  131. package/dist/session.js +1416 -448
  132. package/dist/session.js.map +1 -1
  133. package/dist/shell.d.ts +33 -0
  134. package/dist/shell.d.ts.map +1 -0
  135. package/dist/shell.js +126 -0
  136. package/dist/shell.js.map +1 -0
  137. package/dist/skill-installer.d.ts +38 -0
  138. package/dist/skill-installer.d.ts.map +1 -0
  139. package/dist/skill-installer.js +447 -0
  140. package/dist/skill-installer.js.map +1 -0
  141. package/dist/skill-invoker.d.ts +8 -2
  142. package/dist/skill-invoker.d.ts.map +1 -1
  143. package/dist/skill-invoker.js +36 -15
  144. package/dist/skill-invoker.js.map +1 -1
  145. package/dist/skill-loader.d.ts +8 -3
  146. package/dist/skill-loader.d.ts.map +1 -1
  147. package/dist/skill-loader.js +51 -48
  148. package/dist/skill-loader.js.map +1 -1
  149. package/dist/skill-manager.d.ts +85 -0
  150. package/dist/skill-manager.d.ts.map +1 -0
  151. package/dist/skill-manager.js +341 -0
  152. package/dist/skill-manager.js.map +1 -0
  153. package/dist/slash-commands.d.ts +39 -2
  154. package/dist/slash-commands.d.ts.map +1 -1
  155. package/dist/slash-commands.js +934 -305
  156. package/dist/slash-commands.js.map +1 -1
  157. package/dist/smart-approval.d.ts +20 -1
  158. package/dist/smart-approval.d.ts.map +1 -1
  159. package/dist/smart-approval.js +125 -56
  160. package/dist/smart-approval.js.map +1 -1
  161. package/dist/system-prompt-generator.d.ts +6 -0
  162. package/dist/system-prompt-generator.d.ts.map +1 -1
  163. package/dist/system-prompt-generator.js +86 -36
  164. package/dist/system-prompt-generator.js.map +1 -1
  165. package/dist/terminal.d.ts +28 -0
  166. package/dist/terminal.d.ts.map +1 -0
  167. package/dist/terminal.js +82 -0
  168. package/dist/terminal.js.map +1 -0
  169. package/dist/theme.d.ts.map +1 -1
  170. package/dist/theme.js +8 -7
  171. package/dist/theme.js.map +1 -1
  172. package/dist/tools.d.ts +38 -7
  173. package/dist/tools.d.ts.map +1 -1
  174. package/dist/tools.js +1249 -617
  175. package/dist/tools.js.map +1 -1
  176. package/dist/truncate.d.ts +55 -0
  177. package/dist/truncate.d.ts.map +1 -0
  178. package/dist/truncate.js +130 -0
  179. package/dist/truncate.js.map +1 -0
  180. package/dist/types.d.ts +84 -9
  181. package/dist/types.d.ts.map +1 -1
  182. package/dist/types.js +49 -0
  183. package/dist/types.js.map +1 -1
  184. package/dist/update.d.ts.map +1 -1
  185. package/dist/update.js +28 -36
  186. package/dist/update.js.map +1 -1
  187. package/dist/workflow.d.ts +5 -1
  188. package/dist/workflow.d.ts.map +1 -1
  189. package/dist/workflow.js +61 -49
  190. package/dist/workflow.js.map +1 -1
  191. package/docs/architecture/mcp-integration-guide.md +304 -194
  192. package/docs/architecture/overview.md +169 -169
  193. package/docs/architecture/tool-system-design.md +134 -134
  194. package/docs/cli/commands.md +349 -238
  195. package/docs/smart-mode.md +281 -281
  196. package/docs/third-party-models.md +440 -439
  197. package/find-skills/SKILL.md +133 -0
  198. package/package.json +91 -90
  199. package/scripts/install-ripgrep.js +241 -0
  200. package/src/agents.ts +7 -3
  201. package/src/ai-client/factory.ts +116 -0
  202. package/src/ai-client/index.ts +61 -0
  203. package/src/ai-client/providers/anthropic.ts +475 -0
  204. package/src/ai-client/providers/openai.ts +348 -0
  205. package/src/ai-client/providers/remote.ts +439 -0
  206. package/src/ai-client/registry.ts +97 -0
  207. package/src/ai-client/types.ts +364 -0
  208. package/src/ai-client-factory.ts +204 -0
  209. package/src/auth.ts +661 -614
  210. package/src/cancellation.ts +202 -176
  211. package/src/checkpoint.ts +255 -219
  212. package/src/cli.ts +1523 -743
  213. package/src/config.ts +341 -297
  214. package/src/context-compressor.ts +987 -290
  215. package/src/conversation.ts +290 -288
  216. package/src/gui-subagent/action-parser/actionParser.ts +318 -315
  217. package/src/gui-subagent/action-parser/constants.ts +14 -14
  218. package/src/gui-subagent/action-parser/index.ts +8 -8
  219. package/src/gui-subagent/action-parser/types.ts +31 -31
  220. package/src/gui-subagent/agent/gui-agent.ts +1234 -1089
  221. package/src/gui-subagent/agent/index.ts +5 -5
  222. package/src/gui-subagent/index.ts +185 -163
  223. package/src/gui-subagent/operator/base-operator.ts +244 -245
  224. package/src/gui-subagent/operator/computer-operator.ts +541 -520
  225. package/src/gui-subagent/operator/index.ts +6 -6
  226. package/src/gui-subagent/types/actions.ts +260 -262
  227. package/src/gui-subagent/types/index.ts +6 -6
  228. package/src/gui-subagent/types/operator.ts +106 -106
  229. package/src/gui-subagent/utils.ts +51 -51
  230. package/src/index.ts +17 -18
  231. package/src/input-processor.ts +8 -5
  232. package/src/logger.ts +436 -438
  233. package/src/mcp.ts +793 -682
  234. package/src/memory.ts +343 -344
  235. package/src/output-util.ts +80 -0
  236. package/src/retry.ts +1 -1
  237. package/src/ripgrep.ts +370 -0
  238. package/src/sdk-output-adapter.ts +842 -0
  239. package/src/sdk-session.ts +62 -0
  240. package/src/session-manager.ts +308 -308
  241. package/src/session.ts +1775 -573
  242. package/src/shell.ts +134 -0
  243. package/src/skill-installer.ts +518 -0
  244. package/src/skill-invoker.ts +959 -935
  245. package/src/skill-loader.ts +501 -496
  246. package/src/skill-manager.ts +385 -0
  247. package/src/slash-commands.ts +2189 -1389
  248. package/src/smart-approval.ts +193 -74
  249. package/src/system-prompt-generator.ts +91 -36
  250. package/src/terminal.ts +96 -0
  251. package/src/theme.ts +739 -738
  252. package/src/tools.ts +1790 -931
  253. package/src/truncate.ts +173 -0
  254. package/src/types.ts +337 -198
  255. package/src/update.ts +33 -40
  256. package/src/workflow.ts +521 -508
  257. package/test/cli-launch.test.ts +279 -0
  258. package/tsconfig.json +22 -22
  259. package/vitest.config.ts +21 -19
  260. package/dist/ai-client.d.ts +0 -86
  261. package/dist/ai-client.d.ts.map +0 -1
  262. package/dist/ai-client.js +0 -1372
  263. package/dist/ai-client.js.map +0 -1
  264. package/dist/gui-subagent/operator/browser-operator.d.ts +0 -36
  265. package/dist/gui-subagent/operator/browser-operator.d.ts.map +0 -1
  266. package/dist/gui-subagent/operator/browser-operator.js +0 -306
  267. package/dist/gui-subagent/operator/browser-operator.js.map +0 -1
  268. package/dist/gui-subagent/operator/desktop-operator.d.ts +0 -55
  269. package/dist/gui-subagent/operator/desktop-operator.d.ts.map +0 -1
  270. package/dist/gui-subagent/operator/desktop-operator.js +0 -527
  271. package/dist/gui-subagent/operator/desktop-operator.js.map +0 -1
  272. package/dist/hook.d.ts +0 -73
  273. package/dist/hook.d.ts.map +0 -1
  274. package/dist/hook.js +0 -156
  275. package/dist/hook.js.map +0 -1
  276. package/dist/input-history.d.ts +0 -24
  277. package/dist/input-history.d.ts.map +0 -1
  278. package/dist/input-history.js +0 -94
  279. package/dist/input-history.js.map +0 -1
  280. package/dist/keyboard-manager.d.ts +0 -151
  281. package/dist/keyboard-manager.d.ts.map +0 -1
  282. package/dist/keyboard-manager.js +0 -396
  283. package/dist/keyboard-manager.js.map +0 -1
  284. package/dist/print-system-prompt.d.ts +0 -2
  285. package/dist/print-system-prompt.d.ts.map +0 -1
  286. package/dist/print-system-prompt.js +0 -40
  287. package/dist/print-system-prompt.js.map +0 -1
  288. package/dist/remote-ai-client.d.ts +0 -104
  289. package/dist/remote-ai-client.d.ts.map +0 -1
  290. package/dist/remote-ai-client.js +0 -552
  291. package/dist/remote-ai-client.js.map +0 -1
  292. package/dist/sdk-session-v2.d.ts +0 -13
  293. package/dist/sdk-session-v2.d.ts.map +0 -1
  294. package/dist/sdk-session-v2.js +0 -46
  295. package/dist/sdk-session-v2.js.map +0 -1
  296. package/dist/test-boundary-conditions.d.ts.map +0 -1
  297. package/dist/test-boundary-conditions.js.map +0 -1
  298. package/dist/test-cancellation-fix.d.ts.map +0 -1
  299. package/dist/test-cancellation-fix.js.map +0 -1
  300. package/dist/test-input-history.d.ts.map +0 -1
  301. package/dist/test-input-history.js.map +0 -1
  302. package/dist/test-interaction-flow.d.ts.map +0 -1
  303. package/dist/test-interaction-flow.js.map +0 -1
  304. package/dist/test-quick.d.ts.map +0 -1
  305. package/dist/test-quick.js.map +0 -1
  306. package/dist/test-user-interaction.d.ts.map +0 -1
  307. package/dist/test-user-interaction.js.map +0 -1
  308. package/dist/tools/edit-diff.d.ts +0 -32
  309. package/dist/tools/edit-diff.d.ts.map +0 -1
  310. package/dist/tools/edit-diff.js +0 -185
  311. package/dist/tools/edit-diff.js.map +0 -1
  312. package/dist/tools/edit.d.ts +0 -11
  313. package/dist/tools/edit.d.ts.map +0 -1
  314. package/dist/tools/edit.js +0 -129
  315. package/dist/tools/edit.js.map +0 -1
  316. package/dist/unified-session.d.ts +0 -42
  317. package/dist/unified-session.d.ts.map +0 -1
  318. package/dist/unified-session.js +0 -271
  319. package/dist/unified-session.js.map +0 -1
  320. package/skills/.claude-plugin/marketplace.json +0 -45
  321. package/skills/README.md +0 -94
  322. package/skills/THIRD_PARTY_NOTICES.md +0 -405
  323. package/skills/skills/algorithmic-art/LICENSE.txt +0 -202
  324. package/skills/skills/algorithmic-art/SKILL.md +0 -405
  325. package/skills/skills/algorithmic-art/templates/generator_template.js +0 -223
  326. package/skills/skills/algorithmic-art/templates/viewer.html +0 -599
  327. package/skills/skills/brand-guidelines/LICENSE.txt +0 -202
  328. package/skills/skills/brand-guidelines/SKILL.md +0 -73
  329. package/skills/skills/canvas-design/LICENSE.txt +0 -202
  330. package/skills/skills/canvas-design/SKILL.md +0 -130
  331. package/skills/skills/canvas-design/canvas-fonts/ArsenalSC-OFL.txt +0 -93
  332. package/skills/skills/canvas-design/canvas-fonts/ArsenalSC-Regular.ttf +0 -0
  333. package/skills/skills/canvas-design/canvas-fonts/BigShoulders-Bold.ttf +0 -0
  334. package/skills/skills/canvas-design/canvas-fonts/BigShoulders-OFL.txt +0 -93
  335. package/skills/skills/canvas-design/canvas-fonts/BigShoulders-Regular.ttf +0 -0
  336. package/skills/skills/canvas-design/canvas-fonts/Boldonse-OFL.txt +0 -93
  337. package/skills/skills/canvas-design/canvas-fonts/Boldonse-Regular.ttf +0 -0
  338. package/skills/skills/canvas-design/canvas-fonts/BricolageGrotesque-Bold.ttf +0 -0
  339. package/skills/skills/canvas-design/canvas-fonts/BricolageGrotesque-OFL.txt +0 -93
  340. package/skills/skills/canvas-design/canvas-fonts/BricolageGrotesque-Regular.ttf +0 -0
  341. package/skills/skills/canvas-design/canvas-fonts/CrimsonPro-Bold.ttf +0 -0
  342. package/skills/skills/canvas-design/canvas-fonts/CrimsonPro-Italic.ttf +0 -0
  343. package/skills/skills/canvas-design/canvas-fonts/CrimsonPro-OFL.txt +0 -93
  344. package/skills/skills/canvas-design/canvas-fonts/CrimsonPro-Regular.ttf +0 -0
  345. package/skills/skills/canvas-design/canvas-fonts/DMMono-OFL.txt +0 -93
  346. package/skills/skills/canvas-design/canvas-fonts/DMMono-Regular.ttf +0 -0
  347. package/skills/skills/canvas-design/canvas-fonts/EricaOne-OFL.txt +0 -94
  348. package/skills/skills/canvas-design/canvas-fonts/EricaOne-Regular.ttf +0 -0
  349. package/skills/skills/canvas-design/canvas-fonts/GeistMono-Bold.ttf +0 -0
  350. package/skills/skills/canvas-design/canvas-fonts/GeistMono-OFL.txt +0 -93
  351. package/skills/skills/canvas-design/canvas-fonts/GeistMono-Regular.ttf +0 -0
  352. package/skills/skills/canvas-design/canvas-fonts/Gloock-OFL.txt +0 -93
  353. package/skills/skills/canvas-design/canvas-fonts/Gloock-Regular.ttf +0 -0
  354. package/skills/skills/canvas-design/canvas-fonts/IBMPlexMono-Bold.ttf +0 -0
  355. package/skills/skills/canvas-design/canvas-fonts/IBMPlexMono-OFL.txt +0 -93
  356. package/skills/skills/canvas-design/canvas-fonts/IBMPlexMono-Regular.ttf +0 -0
  357. package/skills/skills/canvas-design/canvas-fonts/IBMPlexSerif-Bold.ttf +0 -0
  358. package/skills/skills/canvas-design/canvas-fonts/IBMPlexSerif-BoldItalic.ttf +0 -0
  359. package/skills/skills/canvas-design/canvas-fonts/IBMPlexSerif-Italic.ttf +0 -0
  360. package/skills/skills/canvas-design/canvas-fonts/IBMPlexSerif-Regular.ttf +0 -0
  361. package/skills/skills/canvas-design/canvas-fonts/InstrumentSans-Bold.ttf +0 -0
  362. package/skills/skills/canvas-design/canvas-fonts/InstrumentSans-BoldItalic.ttf +0 -0
  363. package/skills/skills/canvas-design/canvas-fonts/InstrumentSans-Italic.ttf +0 -0
  364. package/skills/skills/canvas-design/canvas-fonts/InstrumentSans-OFL.txt +0 -93
  365. package/skills/skills/canvas-design/canvas-fonts/InstrumentSans-Regular.ttf +0 -0
  366. package/skills/skills/canvas-design/canvas-fonts/InstrumentSerif-Italic.ttf +0 -0
  367. package/skills/skills/canvas-design/canvas-fonts/InstrumentSerif-Regular.ttf +0 -0
  368. package/skills/skills/canvas-design/canvas-fonts/Italiana-OFL.txt +0 -93
  369. package/skills/skills/canvas-design/canvas-fonts/Italiana-Regular.ttf +0 -0
  370. package/skills/skills/canvas-design/canvas-fonts/JetBrainsMono-Bold.ttf +0 -0
  371. package/skills/skills/canvas-design/canvas-fonts/JetBrainsMono-OFL.txt +0 -93
  372. package/skills/skills/canvas-design/canvas-fonts/JetBrainsMono-Regular.ttf +0 -0
  373. package/skills/skills/canvas-design/canvas-fonts/Jura-Light.ttf +0 -0
  374. package/skills/skills/canvas-design/canvas-fonts/Jura-Medium.ttf +0 -0
  375. package/skills/skills/canvas-design/canvas-fonts/Jura-OFL.txt +0 -93
  376. package/skills/skills/canvas-design/canvas-fonts/LibreBaskerville-OFL.txt +0 -93
  377. package/skills/skills/canvas-design/canvas-fonts/LibreBaskerville-Regular.ttf +0 -0
  378. package/skills/skills/canvas-design/canvas-fonts/Lora-Bold.ttf +0 -0
  379. package/skills/skills/canvas-design/canvas-fonts/Lora-BoldItalic.ttf +0 -0
  380. package/skills/skills/canvas-design/canvas-fonts/Lora-Italic.ttf +0 -0
  381. package/skills/skills/canvas-design/canvas-fonts/Lora-OFL.txt +0 -93
  382. package/skills/skills/canvas-design/canvas-fonts/Lora-Regular.ttf +0 -0
  383. package/skills/skills/canvas-design/canvas-fonts/NationalPark-Bold.ttf +0 -0
  384. package/skills/skills/canvas-design/canvas-fonts/NationalPark-OFL.txt +0 -93
  385. package/skills/skills/canvas-design/canvas-fonts/NationalPark-Regular.ttf +0 -0
  386. package/skills/skills/canvas-design/canvas-fonts/NothingYouCouldDo-OFL.txt +0 -93
  387. package/skills/skills/canvas-design/canvas-fonts/NothingYouCouldDo-Regular.ttf +0 -0
  388. package/skills/skills/canvas-design/canvas-fonts/Outfit-Bold.ttf +0 -0
  389. package/skills/skills/canvas-design/canvas-fonts/Outfit-OFL.txt +0 -93
  390. package/skills/skills/canvas-design/canvas-fonts/Outfit-Regular.ttf +0 -0
  391. package/skills/skills/canvas-design/canvas-fonts/PixelifySans-Medium.ttf +0 -0
  392. package/skills/skills/canvas-design/canvas-fonts/PixelifySans-OFL.txt +0 -93
  393. package/skills/skills/canvas-design/canvas-fonts/PoiretOne-OFL.txt +0 -93
  394. package/skills/skills/canvas-design/canvas-fonts/PoiretOne-Regular.ttf +0 -0
  395. package/skills/skills/canvas-design/canvas-fonts/RedHatMono-Bold.ttf +0 -0
  396. package/skills/skills/canvas-design/canvas-fonts/RedHatMono-OFL.txt +0 -93
  397. package/skills/skills/canvas-design/canvas-fonts/RedHatMono-Regular.ttf +0 -0
  398. package/skills/skills/canvas-design/canvas-fonts/Silkscreen-OFL.txt +0 -93
  399. package/skills/skills/canvas-design/canvas-fonts/Silkscreen-Regular.ttf +0 -0
  400. package/skills/skills/canvas-design/canvas-fonts/SmoochSans-Medium.ttf +0 -0
  401. package/skills/skills/canvas-design/canvas-fonts/SmoochSans-OFL.txt +0 -93
  402. package/skills/skills/canvas-design/canvas-fonts/Tektur-Medium.ttf +0 -0
  403. package/skills/skills/canvas-design/canvas-fonts/Tektur-OFL.txt +0 -93
  404. package/skills/skills/canvas-design/canvas-fonts/Tektur-Regular.ttf +0 -0
  405. package/skills/skills/canvas-design/canvas-fonts/WorkSans-Bold.ttf +0 -0
  406. package/skills/skills/canvas-design/canvas-fonts/WorkSans-BoldItalic.ttf +0 -0
  407. package/skills/skills/canvas-design/canvas-fonts/WorkSans-Italic.ttf +0 -0
  408. package/skills/skills/canvas-design/canvas-fonts/WorkSans-OFL.txt +0 -93
  409. package/skills/skills/canvas-design/canvas-fonts/WorkSans-Regular.ttf +0 -0
  410. package/skills/skills/canvas-design/canvas-fonts/YoungSerif-OFL.txt +0 -93
  411. package/skills/skills/canvas-design/canvas-fonts/YoungSerif-Regular.ttf +0 -0
  412. package/skills/skills/doc-coauthoring/SKILL.md +0 -375
  413. package/skills/skills/docx/LICENSE.txt +0 -30
  414. package/skills/skills/docx/SKILL.md +0 -197
  415. package/skills/skills/docx/docx-js.md +0 -350
  416. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +0 -1499
  417. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +0 -146
  418. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +0 -1085
  419. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +0 -11
  420. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +0 -3081
  421. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +0 -23
  422. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +0 -185
  423. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +0 -287
  424. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +0 -1676
  425. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +0 -28
  426. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +0 -144
  427. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +0 -174
  428. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +0 -25
  429. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +0 -18
  430. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +0 -59
  431. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +0 -56
  432. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +0 -195
  433. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +0 -582
  434. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +0 -25
  435. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +0 -4439
  436. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +0 -570
  437. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +0 -509
  438. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +0 -12
  439. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +0 -108
  440. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +0 -96
  441. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +0 -3646
  442. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +0 -116
  443. package/skills/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +0 -42
  444. package/skills/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +0 -50
  445. package/skills/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +0 -49
  446. package/skills/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +0 -33
  447. package/skills/skills/docx/ooxml/schemas/mce/mc.xsd +0 -75
  448. package/skills/skills/docx/ooxml/schemas/microsoft/wml-2010.xsd +0 -560
  449. package/skills/skills/docx/ooxml/schemas/microsoft/wml-2012.xsd +0 -67
  450. package/skills/skills/docx/ooxml/schemas/microsoft/wml-2018.xsd +0 -14
  451. package/skills/skills/docx/ooxml/schemas/microsoft/wml-cex-2018.xsd +0 -20
  452. package/skills/skills/docx/ooxml/schemas/microsoft/wml-cid-2016.xsd +0 -13
  453. package/skills/skills/docx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +0 -4
  454. package/skills/skills/docx/ooxml/schemas/microsoft/wml-symex-2015.xsd +0 -8
  455. package/skills/skills/docx/ooxml/scripts/pack.py +0 -159
  456. package/skills/skills/docx/ooxml/scripts/unpack.py +0 -29
  457. package/skills/skills/docx/ooxml/scripts/validate.py +0 -69
  458. package/skills/skills/docx/ooxml/scripts/validation/__init__.py +0 -15
  459. package/skills/skills/docx/ooxml/scripts/validation/base.py +0 -951
  460. package/skills/skills/docx/ooxml/scripts/validation/docx.py +0 -274
  461. package/skills/skills/docx/ooxml/scripts/validation/pptx.py +0 -315
  462. package/skills/skills/docx/ooxml/scripts/validation/redlining.py +0 -279
  463. package/skills/skills/docx/ooxml.md +0 -610
  464. package/skills/skills/docx/scripts/__init__.py +0 -1
  465. package/skills/skills/docx/scripts/document.py +0 -1276
  466. package/skills/skills/docx/scripts/templates/comments.xml +0 -3
  467. package/skills/skills/docx/scripts/templates/commentsExtended.xml +0 -3
  468. package/skills/skills/docx/scripts/templates/commentsExtensible.xml +0 -3
  469. package/skills/skills/docx/scripts/templates/commentsIds.xml +0 -3
  470. package/skills/skills/docx/scripts/templates/people.xml +0 -3
  471. package/skills/skills/docx/scripts/utilities.py +0 -374
  472. package/skills/skills/frontend-design/LICENSE.txt +0 -177
  473. package/skills/skills/frontend-design/SKILL.md +0 -42
  474. package/skills/skills/internal-comms/LICENSE.txt +0 -202
  475. package/skills/skills/internal-comms/SKILL.md +0 -32
  476. package/skills/skills/internal-comms/examples/3p-updates.md +0 -47
  477. package/skills/skills/internal-comms/examples/company-newsletter.md +0 -65
  478. package/skills/skills/internal-comms/examples/faq-answers.md +0 -30
  479. package/skills/skills/internal-comms/examples/general-comms.md +0 -16
  480. package/skills/skills/mcp-builder/LICENSE.txt +0 -202
  481. package/skills/skills/mcp-builder/SKILL.md +0 -236
  482. package/skills/skills/mcp-builder/reference/evaluation.md +0 -602
  483. package/skills/skills/mcp-builder/reference/mcp_best_practices.md +0 -249
  484. package/skills/skills/mcp-builder/reference/node_mcp_server.md +0 -970
  485. package/skills/skills/mcp-builder/reference/python_mcp_server.md +0 -719
  486. package/skills/skills/mcp-builder/scripts/connections.py +0 -151
  487. package/skills/skills/mcp-builder/scripts/evaluation.py +0 -373
  488. package/skills/skills/mcp-builder/scripts/example_evaluation.xml +0 -22
  489. package/skills/skills/mcp-builder/scripts/requirements.txt +0 -2
  490. package/skills/skills/pdf/LICENSE.txt +0 -30
  491. package/skills/skills/pdf/SKILL.md +0 -294
  492. package/skills/skills/pdf/forms.md +0 -205
  493. package/skills/skills/pdf/reference.md +0 -612
  494. package/skills/skills/pdf/scripts/check_bounding_boxes.py +0 -70
  495. package/skills/skills/pdf/scripts/check_bounding_boxes_test.py +0 -226
  496. package/skills/skills/pdf/scripts/check_fillable_fields.py +0 -12
  497. package/skills/skills/pdf/scripts/convert_pdf_to_images.py +0 -35
  498. package/skills/skills/pdf/scripts/create_validation_image.py +0 -41
  499. package/skills/skills/pdf/scripts/extract_form_field_info.py +0 -152
  500. package/skills/skills/pdf/scripts/fill_fillable_fields.py +0 -114
  501. package/skills/skills/pdf/scripts/fill_pdf_form_with_annotations.py +0 -108
  502. package/skills/skills/pptx/LICENSE.txt +0 -30
  503. package/skills/skills/pptx/SKILL.md +0 -484
  504. package/skills/skills/pptx/html2pptx.md +0 -625
  505. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +0 -1499
  506. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +0 -146
  507. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +0 -1085
  508. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +0 -11
  509. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +0 -3081
  510. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +0 -23
  511. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +0 -185
  512. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +0 -287
  513. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +0 -1676
  514. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +0 -28
  515. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +0 -144
  516. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +0 -174
  517. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +0 -25
  518. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +0 -18
  519. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +0 -59
  520. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +0 -56
  521. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +0 -195
  522. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +0 -582
  523. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +0 -25
  524. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +0 -4439
  525. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +0 -570
  526. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +0 -509
  527. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +0 -12
  528. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +0 -108
  529. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +0 -96
  530. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +0 -3646
  531. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +0 -116
  532. package/skills/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +0 -42
  533. package/skills/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +0 -50
  534. package/skills/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +0 -49
  535. package/skills/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +0 -33
  536. package/skills/skills/pptx/ooxml/schemas/mce/mc.xsd +0 -75
  537. package/skills/skills/pptx/ooxml/schemas/microsoft/wml-2010.xsd +0 -560
  538. package/skills/skills/pptx/ooxml/schemas/microsoft/wml-2012.xsd +0 -67
  539. package/skills/skills/pptx/ooxml/schemas/microsoft/wml-2018.xsd +0 -14
  540. package/skills/skills/pptx/ooxml/schemas/microsoft/wml-cex-2018.xsd +0 -20
  541. package/skills/skills/pptx/ooxml/schemas/microsoft/wml-cid-2016.xsd +0 -13
  542. package/skills/skills/pptx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +0 -4
  543. package/skills/skills/pptx/ooxml/schemas/microsoft/wml-symex-2015.xsd +0 -8
  544. package/skills/skills/pptx/ooxml/scripts/pack.py +0 -159
  545. package/skills/skills/pptx/ooxml/scripts/unpack.py +0 -29
  546. package/skills/skills/pptx/ooxml/scripts/validate.py +0 -69
  547. package/skills/skills/pptx/ooxml/scripts/validation/__init__.py +0 -15
  548. package/skills/skills/pptx/ooxml/scripts/validation/base.py +0 -951
  549. package/skills/skills/pptx/ooxml/scripts/validation/docx.py +0 -274
  550. package/skills/skills/pptx/ooxml/scripts/validation/pptx.py +0 -315
  551. package/skills/skills/pptx/ooxml/scripts/validation/redlining.py +0 -279
  552. package/skills/skills/pptx/ooxml.md +0 -427
  553. package/skills/skills/pptx/scripts/html2pptx.js +0 -979
  554. package/skills/skills/pptx/scripts/inventory.py +0 -1020
  555. package/skills/skills/pptx/scripts/rearrange.py +0 -231
  556. package/skills/skills/pptx/scripts/replace.py +0 -385
  557. package/skills/skills/pptx/scripts/thumbnail.py +0 -450
  558. package/skills/skills/skill-creator/LICENSE.txt +0 -202
  559. package/skills/skills/skill-creator/SKILL.md +0 -356
  560. package/skills/skills/skill-creator/references/output-patterns.md +0 -82
  561. package/skills/skills/skill-creator/references/workflows.md +0 -28
  562. package/skills/skills/skill-creator/scripts/init_skill.py +0 -303
  563. package/skills/skills/skill-creator/scripts/package_skill.py +0 -110
  564. package/skills/skills/skill-creator/scripts/quick_validate.py +0 -95
  565. package/skills/skills/slack-gif-creator/LICENSE.txt +0 -202
  566. package/skills/skills/slack-gif-creator/SKILL.md +0 -254
  567. package/skills/skills/slack-gif-creator/core/easing.py +0 -234
  568. package/skills/skills/slack-gif-creator/core/frame_composer.py +0 -176
  569. package/skills/skills/slack-gif-creator/core/gif_builder.py +0 -269
  570. package/skills/skills/slack-gif-creator/core/validators.py +0 -136
  571. package/skills/skills/slack-gif-creator/requirements.txt +0 -4
  572. package/skills/skills/theme-factory/LICENSE.txt +0 -202
  573. package/skills/skills/theme-factory/SKILL.md +0 -59
  574. package/skills/skills/theme-factory/theme-showcase.pdf +0 -0
  575. package/skills/skills/theme-factory/themes/arctic-frost.md +0 -19
  576. package/skills/skills/theme-factory/themes/botanical-garden.md +0 -19
  577. package/skills/skills/theme-factory/themes/desert-rose.md +0 -19
  578. package/skills/skills/theme-factory/themes/forest-canopy.md +0 -19
  579. package/skills/skills/theme-factory/themes/golden-hour.md +0 -19
  580. package/skills/skills/theme-factory/themes/midnight-galaxy.md +0 -19
  581. package/skills/skills/theme-factory/themes/modern-minimalist.md +0 -19
  582. package/skills/skills/theme-factory/themes/ocean-depths.md +0 -19
  583. package/skills/skills/theme-factory/themes/sunset-boulevard.md +0 -19
  584. package/skills/skills/theme-factory/themes/tech-innovation.md +0 -19
  585. package/skills/skills/web-artifacts-builder/LICENSE.txt +0 -202
  586. package/skills/skills/web-artifacts-builder/SKILL.md +0 -74
  587. package/skills/skills/web-artifacts-builder/scripts/bundle-artifact.sh +0 -54
  588. package/skills/skills/web-artifacts-builder/scripts/init-artifact.sh +0 -322
  589. package/skills/skills/webapp-testing/LICENSE.txt +0 -202
  590. package/skills/skills/webapp-testing/SKILL.md +0 -96
  591. package/skills/skills/webapp-testing/examples/console_logging.py +0 -35
  592. package/skills/skills/webapp-testing/examples/element_discovery.py +0 -40
  593. package/skills/skills/webapp-testing/examples/static_html_automation.py +0 -33
  594. package/skills/skills/webapp-testing/scripts/with_server.py +0 -106
  595. package/skills/skills/xlsx/LICENSE.txt +0 -30
  596. package/skills/skills/xlsx/SKILL.md +0 -289
  597. package/skills/skills/xlsx/recalc.py +0 -178
  598. package/skills/spec/agent-skills-spec.md +0 -3
  599. package/skills/template/SKILL.md +0 -6
  600. package/src/ai-client.ts +0 -1560
  601. package/src/remote-ai-client.ts +0 -664
  602. /package/{.eslintrc.js → .eslintrc.cjs} +0 -0
@@ -1,9 +1,10 @@
1
- import inquirer from 'inquirer';
1
+ import { select, confirm, text } from '@clack/prompts';
2
2
  import chalk from 'chalk';
3
3
  import ora from 'ora';
4
4
  import fs from 'fs/promises';
5
5
  import path from 'path';
6
6
  import { ExecutionMode, AuthType } from './types.js';
7
+ import { fetchDefaultModels } from './ai-client/providers/remote.js';
7
8
  import { getToolRegistry } from './tools.js';
8
9
  import { getAgentManager } from './agents.js';
9
10
  import { getMemoryManager } from './memory.js';
@@ -11,10 +12,11 @@ import { getMCPManager } from './mcp.js';
11
12
  import { getCheckpointManager } from './checkpoint.js';
12
13
  import { getConfigManager } from './config.js';
13
14
  import { getLogger } from './logger.js';
14
- import { getContextCompressor } from './context-compressor.js';
15
+ import { getContextCompressor, } from './context-compressor.js';
15
16
  import { getConversationManager } from './conversation.js';
16
17
  import { icons, colors } from './theme.js';
17
- import { AuthService } from './auth.js';
18
+ import { ensureTtySane } from './terminal.js';
19
+ import { AuthService, selectAuthType, THIRD_PARTY_PROVIDERS, VLM_PROVIDERS } from './auth.js';
18
20
  const logger = getLogger();
19
21
  export class SlashCommandHandler {
20
22
  configManager;
@@ -27,6 +29,8 @@ export class SlashCommandHandler {
27
29
  conversationHistory = [];
28
30
  onClearCallback = null;
29
31
  onSystemPromptUpdate = null;
32
+ onConfigUpdate = null;
33
+ remoteAIClient = null; // Reference to InteractiveSession's remoteAIClient
30
34
  constructor() {
31
35
  this.configManager = getConfigManager(process.cwd());
32
36
  this.agentManager = getAgentManager(process.cwd());
@@ -36,6 +40,12 @@ export class SlashCommandHandler {
36
40
  this.contextCompressor = getContextCompressor();
37
41
  this.conversationManager = getConversationManager();
38
42
  }
43
+ /**
44
+ * Set remote AI client reference (called from InteractiveSession)
45
+ */
46
+ setRemoteAIClient(client) {
47
+ this.remoteAIClient = client;
48
+ }
39
49
  /**
40
50
  * Set callback for clearing conversation
41
51
  */
@@ -48,6 +58,12 @@ export class SlashCommandHandler {
48
58
  setSystemPromptUpdateCallback(callback) {
49
59
  this.onSystemPromptUpdate = callback;
50
60
  }
61
+ /**
62
+ * Set callback for config update (called after /auth changes config)
63
+ */
64
+ setConfigUpdateCallback(callback) {
65
+ this.onConfigUpdate = callback;
66
+ }
51
67
  /**
52
68
  * Set current conversation history (includes all user/assistant/tool messages)
53
69
  */
@@ -91,8 +107,11 @@ export class SlashCommandHandler {
91
107
  case 'mcp':
92
108
  await this.handleMcp(args);
93
109
  break;
94
- case 'vlm':
95
- await this.handleVlm();
110
+ case 'skill':
111
+ await this.handleSkill(args);
112
+ break;
113
+ case 'model':
114
+ await this.handleModel();
96
115
  break;
97
116
  case 'memory':
98
117
  await this.handleMemory(args);
@@ -118,9 +137,14 @@ export class SlashCommandHandler {
118
137
  case 'compress':
119
138
  await this.handleCompress(args);
120
139
  break;
140
+ case 'update':
141
+ await this.handleUpdate();
142
+ break;
121
143
  default:
122
144
  logger.warn(`Unknown command: /${command}`, 'Type /help for available commands');
123
145
  }
146
+ // Ensure stdin is in raw mode for proper input handling after @clack/prompts usage
147
+ ensureTtySane();
124
148
  return true;
125
149
  }
126
150
  async showHelp() {
@@ -128,7 +152,10 @@ export class SlashCommandHandler {
128
152
  console.log('');
129
153
  console.log(colors.primaryBright('╔════════════════════════════════════════════════════════════╗'));
130
154
  console.log(colors.primaryBright('║') + ' '.repeat(56) + colors.primaryBright('║'));
131
- console.log(' '.repeat(14) + colors.gradient('📚 XAGENT CLI Help') + ' '.repeat(31) + colors.primaryBright('║'));
155
+ console.log(' '.repeat(14) +
156
+ colors.gradient('📚 XAGENT CLI Help') +
157
+ ' '.repeat(31) +
158
+ colors.primaryBright('║'));
132
159
  console.log(colors.primaryBright('║') + ' '.repeat(56) + colors.primaryBright('║'));
133
160
  console.log(colors.primaryBright('╚════════════════════════════════════════════════════════════╝'));
134
161
  console.log('');
@@ -146,20 +173,20 @@ export class SlashCommandHandler {
146
173
  cmd: '/help [command]',
147
174
  desc: 'Show help information',
148
175
  detail: 'View all available commands or detailed description of specific command',
149
- example: '/help\n/help mode'
176
+ example: '/help\n/help mode',
150
177
  },
151
178
  {
152
179
  cmd: '/clear',
153
180
  desc: 'Clear conversation history',
154
181
  detail: 'Clear all conversation records of current session, start new conversation',
155
- example: '/clear'
182
+ example: '/clear',
156
183
  },
157
184
  {
158
185
  cmd: '/exit',
159
186
  desc: 'Exit program',
160
187
  detail: 'Safely exit XAGENT CLI',
161
- example: '/exit'
162
- }
188
+ example: '/exit',
189
+ },
163
190
  ]);
164
191
  // Project Management
165
192
  this.showHelpCategory('Project Management', [
@@ -167,14 +194,14 @@ export class SlashCommandHandler {
167
194
  cmd: '/init',
168
195
  desc: 'Initialize project context',
169
196
  detail: 'Create XAGENT.md file in current directory, used to store project context information',
170
- example: '/init'
197
+ example: '/init',
171
198
  },
172
199
  {
173
200
  cmd: '/memory [show|clear]',
174
201
  desc: 'Manage project memory',
175
202
  detail: 'View or clear memory (global, current, all, or filename)',
176
- example: '/memory show\n/memory clear\n/memory clear global\n/memory clear all'
177
- }
203
+ example: '/memory show\n/memory clear\n/memory clear global\n/memory clear all',
204
+ },
178
205
  ]);
179
206
  // Authentication & Configuration
180
207
  this.showHelpCategory('Authentication & Configuration', [
@@ -182,7 +209,7 @@ export class SlashCommandHandler {
182
209
  cmd: '/auth',
183
210
  desc: 'Configure authentication information',
184
211
  detail: 'Change or view current authentication configuration',
185
- example: '/auth'
212
+ example: '/auth',
186
213
  },
187
214
  {
188
215
  cmd: '/mode [mode]',
@@ -194,14 +221,14 @@ export class SlashCommandHandler {
194
221
  'accept_edits - Automatically accept edit operations',
195
222
  'plan - Plan before executing',
196
223
  'default - Safe execution, requires confirmation',
197
- 'smart - Smart approval (recommended)'
198
- ]
224
+ 'smart - Smart approval (recommended)',
225
+ ],
199
226
  },
200
227
  {
201
228
  cmd: '/think [on|off|display]',
202
229
  desc: 'Control thinking mode',
203
230
  detail: 'Enable/disable AI thinking process display',
204
- example: '/think on\n/think off\n/think display compact'
231
+ example: '/think on\n/think off\n/think display compact',
205
232
  },
206
233
  // {
207
234
  // cmd: '/language [zh|en]',
@@ -213,8 +240,8 @@ export class SlashCommandHandler {
213
240
  cmd: '/theme',
214
241
  desc: 'Switch theme',
215
242
  detail: 'Change UI theme style',
216
- example: '/theme'
217
- }
243
+ example: '/theme',
244
+ },
218
245
  ]);
219
246
  // Feature Extensions
220
247
  this.showHelpCategory('Feature Extensions', [
@@ -222,13 +249,19 @@ export class SlashCommandHandler {
222
249
  cmd: '/agents [list|online|install|remove]',
223
250
  desc: 'Manage sub-agents',
224
251
  detail: 'View, install or remove specialized AI sub-agents',
225
- example: '/agents list\n/agents online\n/agents install explore-agent'
252
+ example: '/agents list\n/agents online\n/agents install explore-agent',
226
253
  },
227
254
  {
228
255
  cmd: '/mcp [list|add|remove|refresh]',
229
256
  desc: 'Manage MCP servers',
230
257
  detail: 'Manage Model Context Protocol servers',
231
- example: '/mcp list\n/mcp add server-name'
258
+ example: '/mcp list\n/mcp add server-name',
259
+ },
260
+ {
261
+ cmd: '/skill [list|add|remove]',
262
+ desc: 'Manage skills',
263
+ detail: 'Install, list, or remove skills from ~/.xagent/skills',
264
+ example: '/skill list\n/skill add ./my-skill\n/skill add owner/repo\n/skill remove my-skill'
232
265
  },
233
266
  {
234
267
  cmd: '/vlm',
@@ -236,12 +269,18 @@ export class SlashCommandHandler {
236
269
  detail: 'Configure Vision-Language Model for browser/desktop automation',
237
270
  example: '/vlm'
238
271
  },
272
+ {
273
+ cmd: '/model',
274
+ desc: 'Configure LLM/VLM models',
275
+ detail: 'Configure or switch LLM and VLM models for remote mode',
276
+ example: '/model',
277
+ },
239
278
  {
240
279
  cmd: '/tools [verbose|simple]',
241
280
  desc: 'Manage tool display',
242
281
  detail: 'View available tools or switch tool call display mode',
243
- example: '/tools\n/tools verbose\n/tools simple'
244
- }
282
+ example: '/tools\n/tools verbose\n/tools simple',
283
+ },
245
284
  ]);
246
285
  // Advanced Features
247
286
  this.showHelpCategory('Advanced Features', [
@@ -249,26 +288,32 @@ export class SlashCommandHandler {
249
288
  cmd: '/restore',
250
289
  desc: 'Restore from checkpoint',
251
290
  detail: 'Restore conversation state from historical checkpoints',
252
- example: '/restore'
291
+ example: '/restore',
253
292
  },
254
293
  {
255
294
  cmd: '/compress [on|off|max_message|max_token|exec]',
256
295
  desc: 'Manage context compression',
257
296
  detail: 'Configure compression settings or execute compression manually',
258
- example: '/compress\n/compress exec\n/compress on\n/compress max_message 50\n/compress max_token 1500000'
297
+ example: '/compress\n/compress exec\n/compress on\n/compress max_message 50\n/compress max_token 1500000',
259
298
  },
260
299
  {
261
300
  cmd: '/stats',
262
301
  desc: 'Show session statistics',
263
302
  detail: 'View statistics information of current session',
264
- example: '/stats'
303
+ example: '/stats',
265
304
  },
266
305
  {
267
306
  cmd: '/about',
268
307
  desc: 'Show version information',
269
308
  detail: 'View version and related information of XAGENT CLI',
270
- example: '/about'
271
- }
309
+ example: '/about',
310
+ },
311
+ {
312
+ cmd: '/update',
313
+ desc: 'Check for updates',
314
+ detail: 'Check for new versions and update xAgent CLI',
315
+ example: '/update',
316
+ },
272
317
  ]);
273
318
  // Keyboard Shortcuts
274
319
  console.log('');
@@ -287,18 +332,18 @@ export class SlashCommandHandler {
287
332
  console.log(colors.primaryBright(title));
288
333
  console.log(colors.border(separator));
289
334
  console.log('');
290
- commands.forEach(cmd => {
335
+ commands.forEach((cmd) => {
291
336
  console.log(colors.primaryBright(` ${cmd.cmd}`));
292
337
  console.log(colors.textDim(` ${cmd.desc}`));
293
338
  console.log(colors.textMuted(` ${cmd.detail}`));
294
339
  if (cmd.modes) {
295
340
  console.log(colors.textDim(` Available modes:`));
296
- cmd.modes.forEach(mode => {
341
+ cmd.modes.forEach((mode) => {
297
342
  console.log(colors.textDim(` • ${mode}`));
298
343
  });
299
344
  }
300
345
  console.log(colors.accent(` Examples:`));
301
- cmd.example.split('\n').forEach(ex => {
346
+ cmd.example.split('\n').forEach((ex) => {
302
347
  console.log(colors.codeText(` ${ex}`));
303
348
  });
304
349
  console.log('');
@@ -317,9 +362,9 @@ export class SlashCommandHandler {
317
362
  async handleClear() {
318
363
  // Clear local conversation history
319
364
  this.conversationHistory = [];
320
- // Clear ConversationManager 中的当前对话
365
+ // Clear current conversation in ConversationManager
321
366
  await this.conversationManager.clearCurrentConversation();
322
- // Call callback to notify InteractiveSession 清空对话
367
+ // Call callback to notify InteractiveSession to clear conversation
323
368
  if (this.onClearCallback) {
324
369
  this.onClearCallback();
325
370
  }
@@ -331,37 +376,131 @@ export class SlashCommandHandler {
331
376
  }
332
377
  async handleAuth() {
333
378
  logger.section('Authentication Management');
334
- const { action } = await inquirer.prompt([
335
- {
336
- type: 'list',
337
- name: 'action',
338
- message: 'Select action:',
339
- choices: [
340
- { name: 'Change authentication method', value: 'change' },
341
- { name: 'Show current auth config', value: 'show' },
342
- { name: 'Back', value: 'back' }
343
- ]
344
- }
345
- ]);
379
+ // Show current authentication configuration
380
+ const authConfig = this.configManager.getAuthConfig();
381
+ const isRemote = authConfig.type === AuthType.OAUTH_XAGENT;
382
+ const currentType = isRemote ? 'xAgent (Remote)' : 'Third-party API (Local)';
383
+ console.log(chalk.cyan('\n📋 Current Authentication Configuration:\n'));
384
+ console.log(` ${chalk.yellow('Mode:')} ${currentType}`);
385
+ if (isRemote) {
386
+ // Remote mode: show remote_llmModelName and remote_vlmModelName
387
+ const llmModel = authConfig.remote_llmModelName || 'Not set';
388
+ const vlmModel = authConfig.remote_vlmModelName || 'Not set';
389
+ console.log(` ${chalk.yellow('LLM Model:')} ${llmModel}`);
390
+ console.log(` ${chalk.yellow('VLM Model:')} ${vlmModel}`);
391
+ }
392
+ else {
393
+ // Local mode: show modelName (LLM) and guiSubagentModel (VLM)
394
+ const llmModel = authConfig.modelName || 'Not set';
395
+ const vlmModel = this.configManager.get('guiSubagentModel') || 'Not set';
396
+ console.log(` ${chalk.yellow('LLM Model:')} ${llmModel}`);
397
+ console.log(` ${chalk.yellow('VLM Model:')} ${vlmModel}`);
398
+ }
399
+ console.log('');
400
+ const action = await select({
401
+ message: 'Select action:',
402
+ options: [
403
+ { value: 'switch', label: 'Switch authentication method' },
404
+ { value: 'back', label: 'Back' },
405
+ ],
406
+ });
346
407
  if (action === 'back') {
347
408
  return;
348
409
  }
349
- if (action === 'show') {
350
- const authConfig = this.configManager.getAuthConfig();
351
- logger.subsection('Current Authentication Configuration');
352
- console.log(JSON.stringify(authConfig, null, 2));
353
- }
354
- else if (action === 'change') {
355
- const { selectAuthType } = await inquirer.prompt([
356
- {
357
- type: 'confirm',
358
- name: 'selectAuthType',
359
- message: 'Do you want to change authentication type?',
360
- default: false
410
+ if (action === 'switch') {
411
+ // Use the same selection UI as initial setup
412
+ const confirmSwitch = await confirm({
413
+ message: `Switch from "${currentType}" to another authentication method?`,
414
+ });
415
+ if (confirmSwitch === false || confirmSwitch === undefined) {
416
+ return;
417
+ }
418
+ // Select authentication type (same as initial setup)
419
+ const authType = await selectAuthType();
420
+ if (authType === AuthType.OAUTH_XAGENT) {
421
+ // Switch to xAgent (Remote mode)
422
+ const authService = new AuthService({
423
+ type: AuthType.OAUTH_XAGENT,
424
+ apiKey: '',
425
+ baseUrl: '',
426
+ xagentApiBaseUrl: authConfig.xagentApiBaseUrl,
427
+ });
428
+ const success = await authService.authenticate();
429
+ if (success) {
430
+ const newAuthConfig = authService.getAuthConfig();
431
+ this.configManager.setAuthConfig({
432
+ selectedAuthType: newAuthConfig.type,
433
+ apiKey: newAuthConfig.apiKey,
434
+ refreshToken: newAuthConfig.refreshToken,
435
+ baseUrl: newAuthConfig.baseUrl,
436
+ modelName: '',
437
+ xagentApiBaseUrl: newAuthConfig.xagentApiBaseUrl,
438
+ guiSubagentModel: '',
439
+ guiSubagentBaseUrl: 'https://www.xagent-colife.net/v3',
440
+ guiSubagentApiKey: '',
441
+ });
442
+ // Set default remote model settings if not already set
443
+ // Fetch default models from /models/default endpoint
444
+ const webBaseUrl = newAuthConfig.xagentApiBaseUrl || 'https://www.xagent-colife.net';
445
+ let defaultLlmName = '';
446
+ let defaultVlmName = '';
447
+ try {
448
+ console.log(chalk.cyan('\n📊 Fetching default models from remote server...'));
449
+ const defaults = await fetchDefaultModels(newAuthConfig.apiKey || '', webBaseUrl);
450
+ if (defaults.llm?.name) {
451
+ defaultLlmName = defaults.llm.name;
452
+ console.log(chalk.cyan(` LLM Model: ${defaults.llm.name}`));
453
+ }
454
+ if (defaults.vlm?.name) {
455
+ defaultVlmName = defaults.vlm.name;
456
+ console.log(chalk.cyan(` VLM Model: ${defaults.vlm.name}`));
457
+ }
458
+ }
459
+ catch (error) {
460
+ console.log(chalk.yellow(` ⚠️ Failed to fetch default models: ${error.message}`));
461
+ console.log(chalk.yellow(' ⚠️ Use /model command to select models manually.'));
462
+ }
463
+ console.log('');
464
+ this.configManager.set('remote_llmModelName', defaultLlmName);
465
+ this.configManager.set('remote_vlmModelName', defaultVlmName);
466
+ this.configManager.save('global');
467
+ // Notify InteractiveSession to update aiClient config
468
+ if (this.onConfigUpdate) {
469
+ this.onConfigUpdate();
470
+ }
471
+ console.log(chalk.green('\n✅ Authentication switched to xAgent (Remote mode)!'));
472
+ // Removed: logging partial token for security
473
+ }
474
+ }
475
+ else {
476
+ // Switch to Third-party API (Local mode)
477
+ const authService = new AuthService({
478
+ type: AuthType.OPENAI_COMPATIBLE,
479
+ apiKey: '',
480
+ baseUrl: '',
481
+ modelName: '',
482
+ });
483
+ const success = await authService.authenticate();
484
+ if (success) {
485
+ const newAuthConfig = authService.getAuthConfig();
486
+ this.configManager.setAuthConfig({
487
+ selectedAuthType: newAuthConfig.type,
488
+ apiKey: newAuthConfig.apiKey,
489
+ baseUrl: newAuthConfig.baseUrl,
490
+ modelName: newAuthConfig.modelName,
491
+ xagentApiBaseUrl: '',
492
+ refreshToken: '',
493
+ guiSubagentModel: '',
494
+ guiSubagentBaseUrl: '',
495
+ guiSubagentApiKey: '',
496
+ });
497
+ this.configManager.save('global');
498
+ // Notify InteractiveSession to update aiClient config
499
+ if (this.onConfigUpdate) {
500
+ this.onConfigUpdate();
501
+ }
502
+ console.log(chalk.green('\n✅ Authentication switched to Third-party API (Local mode)!'));
361
503
  }
362
- ]);
363
- if (selectAuthType) {
364
- logger.warn('Please restart xAgent CLI and run /auth again', 'Authentication changes require restart');
365
504
  }
366
505
  }
367
506
  }
@@ -371,39 +510,36 @@ export class SlashCommandHandler {
371
510
  const currentAuthType = authConfig.type;
372
511
  if (currentAuthType !== AuthType.OAUTH_XAGENT) {
373
512
  console.log(chalk.yellow('\n⚠️ Current authentication type is not OAuth xAgent.'));
374
- const { proceed } = await inquirer.prompt([
375
- {
376
- type: 'confirm',
377
- name: 'proceed',
378
- message: 'Do you want to switch to OAuth xAgent authentication?',
379
- default: false
380
- }
381
- ]);
382
- if (!proceed) {
513
+ const proceed = await confirm({
514
+ message: 'Do you want to switch to OAuth xAgent authentication?',
515
+ });
516
+ if (proceed === false || proceed === undefined) {
383
517
  return;
384
518
  }
385
519
  // Switch to OAuth xAgent
386
- await this.configManager.setAuthConfig({
520
+ this.configManager.setAuthConfig({
387
521
  selectedAuthType: AuthType.OAUTH_XAGENT,
388
522
  apiKey: '',
389
523
  refreshToken: '',
390
- baseUrl: ''
524
+ baseUrl: '',
391
525
  });
392
- await this.configManager.save('global');
526
+ this.configManager.save('global');
393
527
  console.log(chalk.green('✅ Switched to OAuth xAgent authentication.'));
394
528
  }
395
529
  console.log(chalk.cyan('\n🔐 Starting OAuth xAgent login...'));
396
530
  console.log(chalk.gray(' A browser will open for you to complete authentication.\n'));
397
531
  try {
532
+ // Get xagentApiBaseUrl from config (respects XAGENT_BASE_URL env var)
533
+ const config = this.configManager.getAuthConfig();
398
534
  const authService = new AuthService({
399
535
  type: AuthType.OAUTH_XAGENT,
400
536
  apiKey: '',
401
537
  baseUrl: '',
402
- refreshToken: ''
538
+ refreshToken: '',
539
+ xagentApiBaseUrl: config.xagentApiBaseUrl,
403
540
  });
404
541
  const success = await authService.authenticate();
405
542
  if (success) {
406
- const newConfig = this.configManager.getAuthConfig();
407
543
  console.log(chalk.green('\n✅ Login successful!'));
408
544
  console.log(chalk.cyan(` Token saved to: ~/.xagent/settings.json`));
409
545
  console.log(chalk.gray(' You can now use xAgent CLI with remote AI services.\n'));
@@ -416,75 +552,320 @@ export class SlashCommandHandler {
416
552
  console.log(chalk.red(`\n❌ Login error: ${error.message || 'Unknown error'}`));
417
553
  }
418
554
  }
419
- async handleVlm() {
420
- logger.section('VLM Configuration for GUI Agent');
421
- // Show current VLM config
422
- const currentVlmConfig = {
423
- model: this.configManager.get('guiSubagentModel'),
424
- baseUrl: this.configManager.get('guiSubagentBaseUrl'),
425
- apiKey: this.configManager.get('guiSubagentApiKey') ? '***' : ''
426
- };
427
- console.log(chalk.cyan('\n📊 Current VLM Configuration:\n'));
428
- console.log(` Model: ${chalk.yellow(currentVlmConfig.model || 'Not configured')}`);
429
- console.log(` Base URL: ${chalk.yellow(currentVlmConfig.baseUrl || 'Not configured')}`);
430
- console.log(` API Key: ${chalk.yellow(currentVlmConfig.apiKey || 'Not configured')}`);
431
- console.log();
432
- const { action } = await inquirer.prompt([
433
- {
434
- type: 'list',
435
- name: 'action',
436
- message: 'Select action:',
437
- choices: [
438
- { name: 'Configure VLM', value: 'configure' },
439
- { name: 'Remove VLM configuration', value: 'remove' },
440
- { name: 'Back', value: 'back' }
441
- ]
442
- }
443
- ]);
444
- if (action === 'back') {
445
- return;
555
+ /**
556
+ * Handle /model command - Configure LLM/VLM models
557
+ * Supports both remote mode (xAgent) and local mode (third-party API)
558
+ */
559
+ async handleModel() {
560
+ const authConfig = this.configManager.getAuthConfig();
561
+ // Determine mode and show appropriate UI
562
+ if (authConfig.type === AuthType.OAUTH_XAGENT) {
563
+ // Remote mode - use backend models
564
+ await this.handleRemoteModel();
446
565
  }
447
- if (action === 'remove') {
448
- const { confirm } = await inquirer.prompt([
449
- {
450
- type: 'confirm',
451
- name: 'confirm',
452
- message: 'Are you sure you want to remove VLM configuration?',
453
- default: false
566
+ else {
567
+ // Local mode - configure third-party API directly
568
+ await this.handleLocalModel();
569
+ }
570
+ }
571
+ /**
572
+ * Handle /model command for remote mode - Configure models from backend
573
+ */
574
+ async handleRemoteModel() {
575
+ const authConfig = this.configManager.getAuthConfig();
576
+ // Auto-fetch default models if not set
577
+ let currentLlm = authConfig.remote_llmModelName;
578
+ let currentVlm = authConfig.remote_vlmModelName;
579
+ if (!currentLlm || !currentVlm) {
580
+ console.log(chalk.cyan('\n📊 Fetching default models from remote server...'));
581
+ // Try to use RemoteAIClient first, otherwise fetch directly
582
+ let defaults = null;
583
+ if (this.remoteAIClient) {
584
+ try {
585
+ defaults = await this.remoteAIClient.getDefaultModels();
586
+ }
587
+ catch (error) {
588
+ console.log(chalk.yellow(` ⚠️ Failed to get defaults from RemoteAIClient: ${error.message}`));
589
+ }
590
+ }
591
+ // If RemoteAIClient failed or not available, fetch directly
592
+ if (!defaults) {
593
+ try {
594
+ const webBaseUrl = authConfig.xagentApiBaseUrl || 'https://www.xagent-colife.net';
595
+ defaults = await fetchDefaultModels(authConfig.apiKey || '', webBaseUrl);
596
+ }
597
+ catch (error) {
598
+ console.log(chalk.yellow(` ⚠️ Failed to fetch default models: ${error.message}`));
599
+ }
600
+ }
601
+ if (defaults) {
602
+ if (!currentLlm && defaults.llm?.name) {
603
+ currentLlm = defaults.llm.name;
604
+ this.configManager.set('remote_llmModelName', currentLlm);
605
+ console.log(chalk.cyan(` Default LLM: ${defaults.llm.displayName || currentLlm}`));
606
+ }
607
+ if (!currentVlm && defaults.vlm?.name) {
608
+ currentVlm = defaults.vlm.name;
609
+ this.configManager.set('remote_vlmModelName', currentVlm);
610
+ console.log(chalk.cyan(` Default VLM: ${defaults.vlm.displayName || currentVlm}`));
454
611
  }
455
- ]);
456
- if (confirm) {
457
- await this.configManager.set('guiSubagentModel', '');
458
- await this.configManager.set('guiSubagentBaseUrl', '');
459
- await this.configManager.set('guiSubagentApiKey', '');
460
- await this.configManager.save('global');
461
- console.log(chalk.green('✅ VLM configuration removed successfully!'));
612
+ this.configManager.save('global');
462
613
  }
614
+ else {
615
+ console.log(chalk.yellow(' ⚠️ Use /auth to configure remote mode first.'));
616
+ return;
617
+ }
618
+ }
619
+ // Get RemoteAIClient instance (from InteractiveSession) for model selection
620
+ const remoteClient = this.remoteAIClient;
621
+ // Display current configuration
622
+ console.log(chalk.cyan('\n📊 Current Model Configuration:\n'));
623
+ console.log(` ${chalk.yellow('LLM Model:')} ${currentLlm || 'Not set'}`);
624
+ console.log(` ${chalk.yellow('VLM Model:')} ${currentVlm || 'Not set'}`);
625
+ console.log('');
626
+ // Main menu
627
+ const action = await select({
628
+ message: 'Select action:',
629
+ options: [
630
+ { value: 'llm', label: 'Change LLM model' },
631
+ { value: 'vlm', label: 'Change VLM model' },
632
+ { value: 'back', label: 'Back' },
633
+ ],
634
+ });
635
+ if (action === 'back' || typeof action === 'symbol') {
463
636
  return;
464
637
  }
465
- if (action === 'configure') {
466
- // Use AuthService to configure VLM
467
- const authService = new AuthService({
468
- type: 'openai_compatible',
469
- apiKey: '',
470
- baseUrl: '',
471
- modelName: ''
638
+ // Restore stdin raw mode after @clack/prompts interaction
639
+ ensureTtySane();
640
+ // Get and display provider list
641
+ try {
642
+ const models = await remoteClient.getRemoteModels();
643
+ const modelList = action === 'llm' ? models.llm : models.vlm;
644
+ if (modelList.length === 0) {
645
+ console.log(chalk.yellow('\n⚠️ No models available.'));
646
+ return;
647
+ }
648
+ // Build choice list
649
+ const choices = modelList.map((m) => ({
650
+ name: `${m.displayName} (${m.name})`,
651
+ value: m.name
652
+ }));
653
+ const selectedModel = await select({
654
+ message: action === 'llm' ? 'Select LLM Model:' : 'Select VLM Model:',
655
+ options: choices
472
656
  });
473
- const vlmConfig = await authService.configureAndValidateVLM();
474
- if (vlmConfig) {
475
- // Save VLM configuration
476
- await this.configManager.set('guiSubagentModel', vlmConfig.model);
477
- await this.configManager.set('guiSubagentBaseUrl', vlmConfig.baseUrl);
478
- await this.configManager.set('guiSubagentApiKey', vlmConfig.apiKey);
479
- await this.configManager.save('global');
480
- console.log(chalk.green('✅ VLM configuration saved successfully!'));
481
- console.log(chalk.cyan(` Model: ${vlmConfig.model}`));
482
- console.log(chalk.cyan(` Base URL: ${vlmConfig.baseUrl}`));
657
+ if (typeof selectedModel !== 'string') {
658
+ return;
659
+ }
660
+ const configKey = action === 'llm' ? 'remote_llmModelName' : 'remote_vlmModelName';
661
+ this.configManager.set(configKey, selectedModel);
662
+ this.configManager.save('global');
663
+ // Clear conversation history to avoid tool call ID conflicts between providers
664
+ if (this.onClearCallback) {
665
+ this.onClearCallback();
666
+ console.log(chalk.cyan(' Conversation cleared to avoid tool call ID conflicts between models.'));
667
+ }
668
+ // Notify InteractiveSession to update aiClient config
669
+ if (this.onConfigUpdate) {
670
+ this.onConfigUpdate();
671
+ }
672
+ console.log(chalk.green('\n✅ Model updated successfully!'));
673
+ console.log(` ${action === 'llm' ? 'LLM' : 'VLM'}: ${selectedModel}`);
674
+ }
675
+ catch (error) {
676
+ console.log(chalk.red(`\n❌ Failed to get models: ${error.message}`));
677
+ }
678
+ }
679
+ /**
680
+ * Handle /model command for local mode - Configure third-party API directly
681
+ * Reuses code from initial setup flow (authenticateWithOpenAICompatible and configureAndValidateVLM)
682
+ */
683
+ async handleLocalModel() {
684
+ // Display current configuration
685
+ const currentLlmModel = this.configManager.get('modelName') || this.configManager.getAuthConfig().modelName;
686
+ const currentVlmModel = this.configManager.get('guiSubagentModel');
687
+ console.log(chalk.cyan('\n📊 Current Local Model Configuration:\n'));
688
+ console.log(` ${chalk.yellow('LLM Model:')} ${currentLlmModel || 'Not set'}`);
689
+ console.log(` ${chalk.yellow('VLM Model:')} ${currentVlmModel || 'Not set'}`);
690
+ console.log('');
691
+ // Main menu - choose to configure LLM or VLM
692
+ const action = await select({
693
+ message: 'Select action:',
694
+ options: [
695
+ { value: 'llm', label: 'Change LLM (select provider and API)' },
696
+ { value: 'vlm', label: 'Change VLM (for GUI automation)' },
697
+ { value: 'back', label: 'Back' },
698
+ ],
699
+ });
700
+ if (action === 'back' || typeof action === 'symbol') {
701
+ return;
702
+ }
703
+ if (action === 'llm') {
704
+ await this.configureLocalLLM();
705
+ }
706
+ else if (action === 'vlm') {
707
+ await this.configureLocalVLM();
708
+ }
709
+ }
710
+ /**
711
+ * Configure LLM for local mode - Reuses authenticateWithOpenAICompatible logic
712
+ */
713
+ async configureLocalLLM() {
714
+ // THIRD_PARTY_PROVIDERS already imported at top level
715
+ const provider = await select({
716
+ message: 'Select third-party model provider:',
717
+ options: THIRD_PARTY_PROVIDERS.map((p) => ({
718
+ value: p,
719
+ label: `${p.name} - ${p.description}`,
720
+ })),
721
+ });
722
+ if (typeof provider === 'symbol') {
723
+ return;
724
+ }
725
+ const selectedProvider = provider;
726
+ let baseUrl = selectedProvider.baseUrl;
727
+ let modelName = selectedProvider.defaultModel;
728
+ if (selectedProvider.name === 'Custom') {
729
+ baseUrl = (await import('@clack/prompts').then(m => m.text({
730
+ message: 'Enter API Base URL:',
731
+ defaultValue: 'https://api.openai.com/v1',
732
+ validate: (value) => {
733
+ if (!value || value.trim().length === 0) {
734
+ return 'Base URL cannot be empty';
735
+ }
736
+ return undefined;
737
+ },
738
+ })));
739
+ modelName = (await import('@clack/prompts').then(m => m.text({
740
+ message: 'Enter model name:',
741
+ defaultValue: 'gpt-4',
742
+ validate: (value) => {
743
+ if (!value || value.trim().length === 0) {
744
+ return 'Model name cannot be empty';
745
+ }
746
+ return undefined;
747
+ },
748
+ })));
749
+ baseUrl = baseUrl.trim();
750
+ modelName = modelName.trim();
751
+ }
752
+ else {
753
+ console.log(chalk.cyan(`\nSelected: ${selectedProvider.name}`));
754
+ console.log(chalk.cyan(`API URL: ${baseUrl}`));
755
+ if (selectedProvider.models && selectedProvider.models.length > 0) {
756
+ console.log(chalk.cyan(`Available models: ${selectedProvider.models.join(', ')}`));
757
+ const selectedModel = await select({
758
+ message: 'Select model:',
759
+ options: selectedProvider.models.map((model) => ({
760
+ value: model,
761
+ label: model === selectedProvider.defaultModel ? `${model} (default)` : model,
762
+ })),
763
+ });
764
+ if (typeof selectedModel === 'symbol') {
765
+ return;
766
+ }
767
+ modelName = selectedModel;
483
768
  }
484
769
  else {
485
- console.log(chalk.red('❌ VLM configuration failed or cancelled'));
770
+ console.log(chalk.cyan(`Default model: ${modelName}`));
771
+ const confirmModel = (await import('@clack/prompts').then(m => m.text({
772
+ message: `Enter model name (press Enter to use default value ${modelName}):`,
773
+ defaultValue: modelName,
774
+ validate: (value) => {
775
+ if (!value || value.trim().length === 0) {
776
+ return 'Model name cannot be empty';
777
+ }
778
+ return undefined;
779
+ },
780
+ })));
781
+ modelName = confirmModel.trim();
486
782
  }
487
783
  }
784
+ const apiKey = (await import('@clack/prompts').then(m => m.password({
785
+ message: `Enter ${selectedProvider.name} API Key:`,
786
+ validate: (value) => {
787
+ if (!value || value.trim().length === 0) {
788
+ return 'API Key cannot be empty';
789
+ }
790
+ return undefined;
791
+ },
792
+ })));
793
+ // Update config
794
+ this.configManager.set('baseUrl', baseUrl);
795
+ this.configManager.set('apiKey', apiKey.trim());
796
+ this.configManager.set('modelName', modelName);
797
+ this.configManager.save('global');
798
+ console.log(chalk.green('\n✅ LLM configuration updated successfully!'));
799
+ console.log(chalk.cyan(` Provider: ${selectedProvider.name}`));
800
+ console.log(chalk.cyan(` Model: ${modelName}`));
801
+ console.log(chalk.cyan(` API URL: ${baseUrl}`));
802
+ // Clear conversation and notify config update
803
+ if (this.onClearCallback) {
804
+ this.onClearCallback();
805
+ }
806
+ if (this.onConfigUpdate) {
807
+ this.onConfigUpdate();
808
+ }
809
+ }
810
+ /**
811
+ * Configure VLM for local mode - Select provider and modelName (baseUrl from VLM_PROVIDERS)
812
+ */
813
+ async configureLocalVLM() {
814
+ // Get current VLM config
815
+ const currentModel = this.configManager.get('guiSubagentModel');
816
+ const currentBaseUrl = this.configManager.get('guiSubagentBaseUrl');
817
+ console.log(chalk.cyan('\n📊 Current VLM Configuration:\n'));
818
+ console.log(` ${chalk.yellow('Model:')} ${currentModel || 'Not set'}`);
819
+ console.log(` ${chalk.yellow('Base URL:')} ${currentBaseUrl || 'Not set'}`);
820
+ console.log('');
821
+ // Step 1: Select VLM provider
822
+ const provider = await select({
823
+ message: 'Select VLM provider:',
824
+ options: VLM_PROVIDERS.map((p) => ({
825
+ value: p,
826
+ label: `${p.name} - ${p.defaultModel}`,
827
+ })),
828
+ });
829
+ // User cancelled
830
+ if (typeof provider === 'symbol') {
831
+ return;
832
+ }
833
+ const selectedProvider = provider;
834
+ // Step 2: Select model from provider's models list
835
+ const model = await select({
836
+ message: 'Select VLM Model:',
837
+ options: selectedProvider.models.map((m) => ({
838
+ value: m,
839
+ label: m,
840
+ })),
841
+ });
842
+ // User cancelled
843
+ if (typeof model === 'symbol') {
844
+ return;
845
+ }
846
+ // Step 3: Get API Key
847
+ const apiKey = (await text({
848
+ message: `Enter ${selectedProvider.name} API Key:`,
849
+ validate: (value) => {
850
+ if (!value || value.trim().length === 0) {
851
+ return 'API Key cannot be empty';
852
+ }
853
+ return undefined;
854
+ },
855
+ }));
856
+ // Save configuration
857
+ this.configManager.set('guiSubagentModel', model);
858
+ this.configManager.set('guiSubagentBaseUrl', selectedProvider.baseUrl);
859
+ this.configManager.set('guiSubagentApiKey', apiKey);
860
+ this.configManager.save('global');
861
+ console.log(chalk.green('\n✅ VLM configuration updated successfully!'));
862
+ console.log(chalk.cyan(` Provider: ${selectedProvider.name}`));
863
+ console.log(chalk.cyan(` Model: ${model}`));
864
+ console.log(chalk.cyan(` Base URL: ${selectedProvider.baseUrl}`));
865
+ // Notify config update
866
+ if (this.onConfigUpdate) {
867
+ this.onConfigUpdate();
868
+ }
488
869
  }
489
870
  async handleMode(args) {
490
871
  const modes = Object.values(ExecutionMode);
@@ -493,7 +874,7 @@ export class SlashCommandHandler {
493
874
  const newMode = args[0].toLowerCase();
494
875
  if (modes.includes(newMode)) {
495
876
  this.configManager.setApprovalMode(newMode);
496
- await this.configManager.save('global');
877
+ this.configManager.save('global');
497
878
  console.log(chalk.green(`✅ Approval mode changed to: ${newMode}`));
498
879
  }
499
880
  else {
@@ -509,7 +890,7 @@ export class SlashCommandHandler {
509
890
  { mode: 'accept_edits', desc: 'Accept all edits automatically' },
510
891
  { mode: 'plan', desc: 'Plan before executing' },
511
892
  { mode: 'default', desc: 'Safe execution with confirmations' },
512
- { mode: 'smart', desc: 'Smart approval with intelligent security checks' }
893
+ { mode: 'smart', desc: 'Smart approval with intelligent security checks' },
513
894
  ];
514
895
  descriptions.forEach(({ mode, desc }) => {
515
896
  const current = mode === currentMode ? chalk.green(' [current]') : '';
@@ -526,13 +907,13 @@ export class SlashCommandHandler {
526
907
  if (action === 'on' || action === 'true' || action === '1') {
527
908
  thinkingConfig.enabled = true;
528
909
  this.configManager.setThinkingConfig(thinkingConfig);
529
- await this.configManager.save('global');
910
+ this.configManager.save('global');
530
911
  console.log(chalk.green('✅ Thinking mode enabled'));
531
912
  }
532
913
  else if (action === 'off' || action === 'false' || action === '0') {
533
914
  thinkingConfig.enabled = false;
534
915
  this.configManager.setThinkingConfig(thinkingConfig);
535
- await this.configManager.save('global');
916
+ this.configManager.save('global');
536
917
  console.log(chalk.green('✅ Thinking mode disabled'));
537
918
  }
538
919
  else if (action === 'display' && args[1]) {
@@ -540,9 +921,9 @@ export class SlashCommandHandler {
540
921
  const validModes = ['full', 'compact', 'indicator'];
541
922
  if (validModes.includes(displayMode)) {
542
923
  thinkingConfig.displayMode = displayMode;
543
- thinkingConfig.enabled = true; // Auto-enable when setting display mode
924
+ thinkingConfig.enabled = true;
544
925
  this.configManager.setThinkingConfig(thinkingConfig);
545
- await this.configManager.save('global');
926
+ this.configManager.save('global');
546
927
  console.log(chalk.green(`✅ Thinking display mode set to: ${displayMode}`));
547
928
  }
548
929
  else {
@@ -650,7 +1031,9 @@ export class SlashCommandHandler {
650
1031
  const status = isConnected ? chalk.green('✓ Connected') : chalk.red('✗ Disconnected');
651
1032
  const tools = server?.getToolNames() || [];
652
1033
  const transport = serverConfig?.transport || serverConfig?.type || 'unknown';
653
- const command = serverConfig?.command ? `${serverConfig.command} ${(serverConfig.args || []).join(' ')}` : serverConfig?.url || 'N/A';
1034
+ const command = serverConfig?.command
1035
+ ? `${serverConfig.command} ${(serverConfig.args || []).join(' ')}`
1036
+ : serverConfig?.url || 'N/A';
654
1037
  console.log('');
655
1038
  console.log(` ${chalk.cyan(serverName)} ${status}`);
656
1039
  console.log(` Transport: ${transport}`);
@@ -661,80 +1044,87 @@ export class SlashCommandHandler {
661
1044
  logger.info(`Total: ${serverConfigs.length} server(s)`);
662
1045
  }
663
1046
  async addMcpServerInteractive(serverName) {
664
- const { name, command, args: serverArgs, transport, url, authToken, headers } = await inquirer.prompt([
665
- {
666
- type: 'input',
667
- name: 'name',
668
- message: 'Enter MCP server name:',
669
- default: serverName,
670
- validate: (input) => {
671
- if (!input.trim()) {
672
- return 'Server name is required';
673
- }
674
- const servers = this.mcpManager.getAllServers();
675
- if (servers.some((s) => s.config?.name === input)) {
676
- return 'Server with this name already exists';
677
- }
678
- return true;
1047
+ const name = (await text({
1048
+ message: 'Enter MCP server name:',
1049
+ defaultValue: serverName,
1050
+ validate: (value) => {
1051
+ if (!value || !value.trim()) {
1052
+ return 'Server name is required';
679
1053
  }
1054
+ if (!/^[a-zA-Z0-9_-]+$/.test(value)) {
1055
+ return 'Server name must contain only alphanumeric characters, hyphens, and underscores';
1056
+ }
1057
+ const servers = this.mcpManager.getAllServers();
1058
+ if (servers.some((s) => s.config?.name === value)) {
1059
+ return 'Server with this name already exists';
1060
+ }
1061
+ return undefined;
680
1062
  },
681
- {
682
- type: 'list',
683
- name: 'transport',
684
- message: 'Select transport type:',
685
- choices: [
686
- { name: 'Stdio (stdin/stdout)', value: 'stdio' },
687
- { name: 'HTTP/SSE', value: 'sse' },
688
- { name: 'HTTP (POST)', value: 'http' }
689
- ],
690
- default: 'stdio'
691
- },
692
- {
693
- type: 'input',
694
- name: 'command',
1063
+ }));
1064
+ const transport = await select({
1065
+ message: 'Select transport type:',
1066
+ options: [
1067
+ { value: 'stdio', label: 'Stdio (stdin/stdout)' },
1068
+ { value: 'sse', label: 'HTTP/SSE' },
1069
+ { value: 'http', label: 'HTTP (POST)' },
1070
+ ],
1071
+ });
1072
+ if (typeof transport === 'symbol') {
1073
+ return;
1074
+ }
1075
+ let command = '';
1076
+ let serverArgs = [];
1077
+ let url = '';
1078
+ let authToken = '';
1079
+ let headers;
1080
+ if (transport === 'stdio') {
1081
+ command = (await text({
695
1082
  message: 'Enter command (for stdio transport):',
696
- when: (answers) => answers.transport === 'stdio',
697
- validate: (input) => input.trim() ? true : 'Command is required'
698
- },
699
- {
700
- type: 'input',
701
- name: 'args',
1083
+ validate: (value) => value && value.trim() ? undefined : 'Command is required',
1084
+ }));
1085
+ const argsInput = (await text({
702
1086
  message: 'Enter arguments (comma-separated, for stdio transport):',
703
- when: (answers) => answers.transport === 'stdio',
704
- filter: (input) => input ? input.split(',').map((a) => a.trim()) : []
705
- },
706
- {
707
- type: 'input',
708
- name: 'url',
1087
+ defaultValue: '',
1088
+ }));
1089
+ if (argsInput.trim()) {
1090
+ serverArgs = argsInput.split(',').map((a) => a.trim());
1091
+ }
1092
+ }
1093
+ else {
1094
+ url = (await text({
709
1095
  message: 'Enter server URL (for HTTP/SSE/HTTP transport):',
710
- when: (answers) => answers.transport === 'sse' || answers.transport === 'http',
711
- validate: (input) => input.trim() ? true : 'URL is required'
712
- },
713
- {
714
- type: 'password',
715
- name: 'authToken',
716
- message: 'Enter authentication token (optional):',
717
- when: (answers) => answers.transport === 'sse' || answers.transport === 'http'
718
- },
719
- {
720
- type: 'input',
721
- name: 'headers',
722
- message: 'Enter custom headers as JSON (optional, e.g., {"Authorization": "Bearer token"}):',
723
- when: (answers) => answers.transport === 'sse' || answers.transport === 'http',
724
- filter: (input) => {
725
- if (!input.trim())
726
- return undefined;
1096
+ validate: (value) => {
1097
+ if (!value || !value.trim()) {
1098
+ return 'URL is required';
1099
+ }
727
1100
  try {
728
- return JSON.parse(input);
1101
+ new URL(value);
1102
+ return undefined;
729
1103
  }
730
1104
  catch {
731
- return undefined;
1105
+ return 'Invalid URL format (e.g., https://example.com)';
732
1106
  }
1107
+ },
1108
+ }));
1109
+ authToken = (await text({
1110
+ message: 'Enter authentication token (optional):',
1111
+ defaultValue: '',
1112
+ }));
1113
+ const headersInput = (await text({
1114
+ message: 'Enter custom headers as JSON (optional, e.g., {"Authorization": "Bearer token"}):',
1115
+ defaultValue: '',
1116
+ }));
1117
+ if (headersInput.trim()) {
1118
+ try {
1119
+ headers = JSON.parse(headersInput);
1120
+ }
1121
+ catch {
1122
+ headers = undefined;
733
1123
  }
734
1124
  }
735
- ]);
1125
+ }
736
1126
  const config = {
737
- transport: transport
1127
+ transport: transport,
738
1128
  };
739
1129
  if (transport === 'stdio') {
740
1130
  config.command = command;
@@ -744,30 +1134,37 @@ export class SlashCommandHandler {
744
1134
  }
745
1135
  else {
746
1136
  config.url = url;
747
- if (authToken) {
748
- config.authToken = authToken;
1137
+ // Handle user input that mistakenly puts Bearer token in headers field
1138
+ // Detect pattern: headers looks like "Bearer xxx.yyy.zzz" (JWT token)
1139
+ let resolvedAuthToken = authToken;
1140
+ let resolvedHeaders = headers;
1141
+ if (headers && typeof headers === 'string' && !authToken) {
1142
+ const trimmedHeaders = headers.trim();
1143
+ if (trimmedHeaders.startsWith('Bearer ') && trimmedHeaders.split('.').length === 3) {
1144
+ // User mistakenly put token in headers field - extract it
1145
+ resolvedAuthToken = trimmedHeaders;
1146
+ resolvedHeaders = undefined;
1147
+ console.log('[MCP] Note: Detected Bearer token in headers field, moved to authToken');
1148
+ }
749
1149
  }
750
- if (headers) {
751
- config.headers = headers;
1150
+ if (resolvedAuthToken) {
1151
+ config.authToken = resolvedAuthToken;
1152
+ }
1153
+ if (resolvedHeaders) {
1154
+ config.headers = resolvedHeaders;
752
1155
  }
753
1156
  }
754
1157
  try {
755
- // Save to config file
756
1158
  this.configManager.addMcpServer(name, config);
757
- await this.configManager.save('global');
758
- // Register to MCP Manager
1159
+ this.configManager.save('global');
759
1160
  this.mcpManager.registerServer(name, config);
760
- // Connect to server (with error handling)
761
- let connected = false;
762
1161
  try {
763
1162
  await this.mcpManager.connectServer(name);
764
- connected = true;
765
1163
  }
766
1164
  catch (error) {
767
- // Connection failed - cleanup
768
1165
  this.mcpManager.disconnectServer(name);
769
1166
  this.configManager.removeMcpServer(name);
770
- await this.configManager.save('global');
1167
+ this.configManager.save('global');
771
1168
  throw new Error(`Connection failed: ${error.message}`);
772
1169
  }
773
1170
  // Register MCP tools with simple names
@@ -790,30 +1187,25 @@ export class SlashCommandHandler {
790
1187
  logger.warn('No MCP servers configured', 'Use /mcp add to add servers');
791
1188
  return;
792
1189
  }
793
- const serverNames = servers.map((s) => {
1190
+ const serverOptions = servers.map((s) => {
794
1191
  const tools = s.getToolNames();
795
1192
  const status = s.isServerConnected() ? '✓' : '✗';
796
1193
  return {
797
- name: `${status} ${s.config?.name || 'unknown'} (${tools.length} tools)`,
798
- value: s.config?.name
1194
+ value: s.config?.name,
1195
+ label: `${status} ${s.config?.name || 'unknown'} (${tools.length} tools)`,
799
1196
  };
800
1197
  });
801
- const { serverName } = await inquirer.prompt([
802
- {
803
- type: 'list',
804
- name: 'serverName',
805
- message: 'Select MCP server to remove:',
806
- choices: serverNames
807
- }
808
- ]);
1198
+ const serverName = (await select({
1199
+ message: 'Select MCP server to remove:',
1200
+ options: serverOptions,
1201
+ }));
1202
+ if (typeof serverName === 'symbol') {
1203
+ return;
1204
+ }
809
1205
  await this.removeMcpServer(serverName);
810
1206
  }
811
1207
  async removeMcpServer(serverName) {
812
1208
  try {
813
- // Get server info before disconnecting to notify LLM
814
- const server = this.mcpManager.getServer(serverName);
815
- const removedTools = server ? server.getToolNames() : [];
816
- const removedToolNames = removedTools.map((t) => `${serverName}__${t}`).join(', ');
817
1209
  // Disconnect
818
1210
  this.mcpManager.disconnectServer(serverName);
819
1211
  // Unregister MCP tools for this server
@@ -821,7 +1213,7 @@ export class SlashCommandHandler {
821
1213
  toolRegistry.unregisterMCPTools(serverName);
822
1214
  // Remove from config
823
1215
  this.configManager.removeMcpServer(serverName);
824
- await this.configManager.save('global');
1216
+ this.configManager.save('global');
825
1217
  // Update system prompt to reflect removed MCP tools
826
1218
  if (this.onSystemPromptUpdate) {
827
1219
  await this.onSystemPromptUpdate();
@@ -914,8 +1306,7 @@ export class SlashCommandHandler {
914
1306
  return;
915
1307
  }
916
1308
  // Clear specific file by filename or path
917
- const targetMemory = memoryFiles.find((m) => path.basename(m.path) === target ||
918
- m.path === target);
1309
+ const targetMemory = memoryFiles.find((m) => path.basename(m.path) === target || m.path === target);
919
1310
  if (targetMemory) {
920
1311
  try {
921
1312
  await fs.unlink(targetMemory.path);
@@ -949,22 +1340,20 @@ export class SlashCommandHandler {
949
1340
  logger.info(`Directory: ${memoriesDir}`);
950
1341
  console.log('');
951
1342
  memoryFiles.forEach((file) => {
952
- const level = file.level === 'global' ? chalk.blue('[global]') :
953
- file.level === 'project' ? chalk.green('[project]') :
954
- chalk.yellow('[subdirectory]');
1343
+ const level = file.level === 'global'
1344
+ ? chalk.blue('[global]')
1345
+ : file.level === 'project'
1346
+ ? chalk.green('[project]')
1347
+ : chalk.yellow('[subdirectory]');
955
1348
  logger.info(` ${level} ${path.basename(file.path)}`);
956
1349
  });
957
1350
  console.log('');
958
1351
  // logger.info('Usage: /memory clear [global|current|all|<filename>]');
959
1352
  }
960
1353
  async addMemory() {
961
- const { entry } = await inquirer.prompt([
962
- {
963
- type: 'editor',
964
- name: 'entry',
965
- message: 'Enter memory entry (opens editor):'
966
- }
967
- ]);
1354
+ const entry = (await text({
1355
+ message: 'Enter memory entry (opens editor):',
1356
+ }));
968
1357
  if (entry && entry.trim()) {
969
1358
  await this.memoryManager.addMemoryEntry(entry.trim());
970
1359
  console.log(chalk.green('✅ Memory entry added'));
@@ -1001,18 +1390,17 @@ export class SlashCommandHandler {
1001
1390
  }
1002
1391
  }
1003
1392
  else {
1004
- const choices = checkpoints.map((cp) => ({
1005
- name: `${new Date(cp.timestamp).toLocaleString()} - ${cp.description}`,
1006
- value: cp.id
1393
+ const checkpointOptions = checkpoints.map((cp) => ({
1394
+ value: cp.id,
1395
+ label: `${new Date(cp.timestamp).toLocaleString()} - ${cp.description}`,
1007
1396
  }));
1008
- const { checkpointId } = await inquirer.prompt([
1009
- {
1010
- type: 'list',
1011
- name: 'checkpointId',
1012
- message: 'Select checkpoint to restore:',
1013
- choices
1014
- }
1015
- ]);
1397
+ const checkpointId = await select({
1398
+ message: 'Select checkpoint to restore:',
1399
+ options: checkpointOptions,
1400
+ });
1401
+ if (typeof checkpointId === 'symbol') {
1402
+ return;
1403
+ }
1016
1404
  try {
1017
1405
  await this.checkpointManager.restoreCheckpoint(checkpointId);
1018
1406
  logger.success(`Checkpoint ${checkpointId} restored successfully!`);
@@ -1026,7 +1414,7 @@ export class SlashCommandHandler {
1026
1414
  const toolRegistry = getToolRegistry();
1027
1415
  const tools = toolRegistry.getAll();
1028
1416
  logger.section('Available Tools');
1029
- tools.forEach(tool => {
1417
+ tools.forEach((tool) => {
1030
1418
  logger.info(` ${tool.name}`);
1031
1419
  logger.info(` ${tool.description}`);
1032
1420
  });
@@ -1045,12 +1433,12 @@ export class SlashCommandHandler {
1045
1433
  const mode = args[0].toLowerCase();
1046
1434
  if (mode === 'verbose' || mode === 'detail' || mode === 'true' || mode === 'on') {
1047
1435
  this.configManager.set('showToolDetails', true);
1048
- await this.configManager.save('global');
1436
+ this.configManager.save('global');
1049
1437
  logger.success('Tool display mode switched to verbose mode', 'Will show complete tool call information');
1050
1438
  }
1051
1439
  else if (mode === 'simple' || mode === 'concise' || mode === 'false' || mode === 'off') {
1052
1440
  this.configManager.set('showToolDetails', false);
1053
- await this.configManager.save('global');
1441
+ this.configManager.save('global');
1054
1442
  logger.success('Tool display mode switched to simple mode', 'Only show tool execution status');
1055
1443
  }
1056
1444
  else {
@@ -1059,6 +1447,8 @@ export class SlashCommandHandler {
1059
1447
  }
1060
1448
  async handleStats() {
1061
1449
  logger.section('Session Statistics');
1450
+ const authConfig = this.configManager.getAuthConfig();
1451
+ logger.info(` Base URL: ${authConfig.baseUrl}`);
1062
1452
  logger.info(` Execution Mode: ${this.configManager.getExecutionMode()}`);
1063
1453
  logger.info(` Language: ${this.configManager.getLanguage()}`);
1064
1454
  logger.info(` Checkpointing: ${this.checkpointManager.isEnabled() ? 'Enabled' : 'Disabled'}`);
@@ -1069,17 +1459,16 @@ export class SlashCommandHandler {
1069
1459
  logger.warn('Theme switching not implemented yet', 'Check back later for updates');
1070
1460
  }
1071
1461
  async handleLanguage() {
1072
- const { language } = await inquirer.prompt([
1073
- {
1074
- type: 'list',
1075
- name: 'language',
1076
- message: 'Select language:',
1077
- choices: [
1078
- { name: 'Chinese', value: 'zh' },
1079
- { name: 'English', value: 'en' }
1080
- ]
1081
- }
1082
- ]);
1462
+ const language = (await select({
1463
+ message: 'Select language:',
1464
+ options: [
1465
+ { value: 'zh', label: 'Chinese' },
1466
+ { value: 'en', label: 'English' },
1467
+ ],
1468
+ }));
1469
+ if (typeof language === 'symbol') {
1470
+ return;
1471
+ }
1083
1472
  this.configManager.setLanguage(language);
1084
1473
  logger.success(`Language changed to: ${language === 'zh' ? 'Chinese' : 'English'}`, 'Restart CLI to apply changes');
1085
1474
  }
@@ -1091,6 +1480,45 @@ export class SlashCommandHandler {
1091
1480
  logger.link('Documentation', 'https://platform.xagent.cn/');
1092
1481
  logger.link('GitHub', 'https://github.com/xagent-ai/xagent-cli');
1093
1482
  }
1483
+ async handleUpdate() {
1484
+ const separator = icons.separator.repeat(Math.min(40, process.stdout.columns || 80));
1485
+ console.log('');
1486
+ console.log(colors.primaryBright(`${icons.rocket} Update Check`));
1487
+ console.log(colors.border(separator));
1488
+ console.log('');
1489
+ try {
1490
+ const { getUpdateManager } = await import('./update.js');
1491
+ const updateManager = getUpdateManager();
1492
+ const versionInfo = await updateManager.checkForUpdates();
1493
+ console.log(` ${icons.info} ${colors.textMuted('Current version:')} ${colors.primaryBright(versionInfo.currentVersion)}`);
1494
+ console.log(` ${icons.code} ${colors.textMuted('Latest version:')} ${colors.primaryBright(versionInfo.latestVersion)}`);
1495
+ console.log('');
1496
+ if (versionInfo.updateAvailable) {
1497
+ console.log(colors.success(` 📦 A new version is available!`));
1498
+ console.log('');
1499
+ if (versionInfo.releaseNotes) {
1500
+ console.log(colors.textMuted(' Release Notes:'));
1501
+ console.log(colors.textDim(` ${versionInfo.releaseNotes}`));
1502
+ console.log('');
1503
+ }
1504
+ const shouldUpdate = await confirm({
1505
+ message: 'Do you want to update now?',
1506
+ });
1507
+ if (shouldUpdate === true) {
1508
+ console.log('');
1509
+ await updateManager.autoUpdate();
1510
+ }
1511
+ }
1512
+ else {
1513
+ console.log(colors.success(` ✅ You are using the latest version`));
1514
+ console.log('');
1515
+ }
1516
+ }
1517
+ catch (error) {
1518
+ console.log(colors.error(` ❌ Failed to check for updates: ${error.message}`));
1519
+ console.log('');
1520
+ }
1521
+ }
1094
1522
  async handleCompress(args) {
1095
1523
  const config = this.configManager.getContextCompressionConfig();
1096
1524
  // If there are arguments, process config or execute
@@ -1106,15 +1534,11 @@ export class SlashCommandHandler {
1106
1534
  // Display current configuration
1107
1535
  console.log(chalk.cyan('\n📦 Context Compression:\n'));
1108
1536
  console.log(` Status: ${config.enabled ? chalk.green('Enabled') : chalk.red('Disabled')}`);
1109
- console.log(` Max Messages: ${chalk.yellow(config.maxMessages.toString())}`);
1110
- console.log(` Max Tokens: ${chalk.yellow(config.maxContextSize.toString())}`);
1111
1537
  console.log('');
1112
1538
  console.log(chalk.gray('Usage:'));
1113
1539
  console.log(chalk.gray(' /compress - Show current configuration'));
1114
1540
  console.log(chalk.gray(' /compress exec - Execute compression now'));
1115
1541
  console.log(chalk.gray(' /compress on|off - Enable/disable compression'));
1116
- console.log(chalk.gray(' /compress max_message <n> - Set max messages before compression'));
1117
- console.log(chalk.gray(' /compress max_token <n> - Set max tokens before compression'));
1118
1542
  console.log('');
1119
1543
  }
1120
1544
  async executeCompression(config) {
@@ -1133,7 +1557,7 @@ export class SlashCommandHandler {
1133
1557
  const spinner = ora({
1134
1558
  text: 'Compressing context...',
1135
1559
  spinner: 'dots',
1136
- color: 'cyan'
1560
+ color: 'cyan',
1137
1561
  }).start();
1138
1562
  try {
1139
1563
  const result = await this.contextCompressor.compressContext(messages, 'You are a helpful AI assistant.', config);
@@ -1159,56 +1583,241 @@ export class SlashCommandHandler {
1159
1583
  case 'on':
1160
1584
  config.enabled = true;
1161
1585
  this.configManager.setContextCompressionConfig(config);
1162
- await this.configManager.save('global');
1586
+ this.configManager.save('global');
1163
1587
  console.log(chalk.green('✅ Context compression enabled'));
1164
1588
  break;
1165
1589
  case 'off':
1166
1590
  config.enabled = false;
1167
1591
  this.configManager.setContextCompressionConfig(config);
1168
- await this.configManager.save('global');
1592
+ this.configManager.save('global');
1169
1593
  console.log(chalk.green('✅ Context compression disabled'));
1170
1594
  break;
1171
- case 'max_message':
1172
- if (args[1]) {
1173
- const maxMessages = parseInt(args[1], 10);
1174
- if (isNaN(maxMessages) || maxMessages < 1) {
1175
- console.log(chalk.red('❌ Invalid value for max_message. Must be a positive number.'));
1176
- return;
1177
- }
1178
- config.maxMessages = maxMessages;
1179
- this.configManager.setContextCompressionConfig(config);
1180
- await this.configManager.save('global');
1181
- console.log(chalk.green(`✅ Max messages set to: ${maxMessages}`));
1595
+ default:
1596
+ console.log(chalk.red(`❌ Unknown action: ${action}`));
1597
+ console.log(chalk.gray('Available actions: on, off, exec'));
1598
+ }
1599
+ }
1600
+ async handleSkill(args) {
1601
+ const os = await import('os');
1602
+ const path = await import('path');
1603
+ const { promises: fs } = await import('fs');
1604
+ const action = args[0] || 'list';
1605
+ const userSkillsPath = this.configManager.getUserSkillsPath() || path.join(os.homedir(), '.xagent', 'skills');
1606
+ switch (action) {
1607
+ case 'list':
1608
+ await this.listUserSkills(userSkillsPath, fs, path);
1609
+ break;
1610
+ case 'add':
1611
+ await this.addSkill(args[1], userSkillsPath, fs, path);
1612
+ break;
1613
+ case 'remove':
1614
+ await this.removeSkill(args[1], userSkillsPath, fs, path);
1615
+ break;
1616
+ default:
1617
+ console.log(chalk.cyan('\n🔧 Skills:\n'));
1618
+ console.log(` Skills directory: ${chalk.yellow(userSkillsPath)}\n`);
1619
+ console.log(chalk.gray('Available commands:'));
1620
+ console.log(chalk.gray(' /skill list - List installed skills'));
1621
+ console.log(chalk.gray(' /skill add <source> - Add a skill (local path or remote URL)'));
1622
+ console.log(chalk.gray(' /skill remove <name> - Remove a user-installed skill'));
1623
+ console.log();
1624
+ console.log(chalk.gray('Examples:'));
1625
+ console.log(chalk.gray(' /skill add ./my-skill - Local path'));
1626
+ console.log(chalk.gray(' /skill add owner/repo - GitHub shorthand'));
1627
+ console.log(chalk.gray(' /skill add https://github.com/owner/repo - GitHub URL'));
1628
+ console.log();
1629
+ }
1630
+ }
1631
+ async listUserSkills(userSkillsPath, fs, path) {
1632
+ console.log(chalk.cyan('\n🔧 Skills:\n'));
1633
+ try {
1634
+ const entries = await fs.readdir(userSkillsPath, { withFileTypes: true });
1635
+ const skills = entries.filter((e) => e.isDirectory());
1636
+ if (skills.length === 0) {
1637
+ console.log(chalk.gray(' No skills installed'));
1638
+ console.log(chalk.cyan('\n To add a skill, use:'));
1639
+ console.log(chalk.cyan(' /skill add <path-to-skill>\n'));
1640
+ return;
1641
+ }
1642
+ for (const skill of skills) {
1643
+ const skillPath = path.join(userSkillsPath, skill.name);
1644
+ const skillMdPath = path.join(skillPath, 'SKILL.md');
1645
+ try {
1646
+ const content = await fs.readFile(skillMdPath, 'utf-8');
1647
+ const nameMatch = content.match(/^name:\s*(.+)$/m);
1648
+ const descMatch = content.match(/^description:\s*(.+)$/m);
1649
+ const name = nameMatch ? nameMatch[1].trim() : skill.name;
1650
+ const description = descMatch ? descMatch[1].trim() : 'No description';
1651
+ console.log(` ${chalk.cyan('•')} ${chalk.yellow(name)}`);
1652
+ console.log(` ${chalk.gray(description)}`);
1653
+ console.log();
1654
+ }
1655
+ catch {
1656
+ console.log(` ${chalk.cyan('•')} ${chalk.yellow(skill.name)}`);
1657
+ console.log(` ${chalk.gray('(Missing SKILL.md)')}`);
1658
+ console.log();
1659
+ }
1660
+ }
1661
+ console.log(chalk.gray(` Skills directory: ${userSkillsPath}`));
1662
+ console.log();
1663
+ }
1664
+ catch (error) {
1665
+ if (error.code === 'ENOENT') {
1666
+ console.log(chalk.gray(' No skills installed'));
1667
+ console.log(chalk.cyan('\n To add a skill, use:'));
1668
+ console.log(chalk.cyan(' /skill add <path-to-skill>\n'));
1669
+ }
1670
+ else {
1671
+ console.log(chalk.red(` Error: ${error.message}`));
1672
+ }
1673
+ }
1674
+ }
1675
+ async addSkill(source, userSkillsPath, fs, path) {
1676
+ if (!source) {
1677
+ console.log(chalk.yellow('\n⚠️ Please specify a skill source'));
1678
+ console.log(chalk.cyan(' Usage: /skill add <source>\n'));
1679
+ console.log(chalk.gray(' Examples:'));
1680
+ console.log(chalk.gray(' /skill add ./my-skill - Local path'));
1681
+ console.log(chalk.gray(' /skill add owner/repo - GitHub shorthand'));
1682
+ console.log(chalk.gray(' /skill add https://github.com/owner/repo'));
1683
+ console.log();
1684
+ return;
1685
+ }
1686
+ const { parseSource, installSkill } = await import('./skill-installer.js');
1687
+ const parsed = parseSource(source.trim());
1688
+ const isLocal = parsed.type === 'local';
1689
+ if (isLocal) {
1690
+ // Local installation
1691
+ const resolvedPath = path.resolve(source);
1692
+ const skillName = path.basename(resolvedPath);
1693
+ const destPath = path.join(userSkillsPath, skillName);
1694
+ try {
1695
+ // Check if source exists
1696
+ await fs.access(resolvedPath);
1697
+ // Check if SKILL.md exists
1698
+ const skillMdPath = path.join(resolvedPath, 'SKILL.md');
1699
+ try {
1700
+ await fs.access(skillMdPath);
1701
+ }
1702
+ catch {
1703
+ console.log(chalk.red(`\n❌ SKILL.md not found in ${resolvedPath}`));
1704
+ console.log(chalk.gray(' Each skill must have a SKILL.md file\n'));
1705
+ return;
1706
+ }
1707
+ // Check if skill already exists
1708
+ try {
1709
+ await fs.access(destPath);
1710
+ console.log(chalk.yellow(`\n⚠️ Skill "${skillName}" already installed`));
1711
+ console.log(chalk.cyan(` Use: /skill remove ${skillName} to remove it first\n`));
1712
+ return;
1713
+ }
1714
+ catch {
1715
+ // Doesn't exist, proceed
1716
+ }
1717
+ // Ensure skills directory exists
1718
+ await fs.mkdir(userSkillsPath, { recursive: true });
1719
+ // Copy the skill
1720
+ await this.copyDirectory(resolvedPath, destPath);
1721
+ console.log(chalk.green('\n✅ Skill installed successfully'));
1722
+ console.log(chalk.gray(` Name: ${skillName}`));
1723
+ console.log(chalk.gray(` Location: ${destPath}`));
1724
+ console.log(chalk.gray(` Type: Local`));
1725
+ console.log();
1726
+ // Trigger system prompt update
1727
+ this.onSystemPromptUpdate?.();
1728
+ }
1729
+ catch (error) {
1730
+ if (error.code === 'ENOENT') {
1731
+ console.log(chalk.red(`\n❌ Skill not found: ${source}\n`));
1182
1732
  }
1183
1733
  else {
1184
- console.log(chalk.gray('Usage: /compress max_message <number>'));
1734
+ console.log(chalk.red(`\n❌ Error installing skill: ${error.message}\n`));
1185
1735
  }
1186
- break;
1187
- case 'max_token':
1188
- if (args[1]) {
1189
- const maxContextSize = parseInt(args[1], 10);
1190
- if (isNaN(maxContextSize) || maxContextSize < 1000) {
1191
- console.log(chalk.red('❌ Invalid value for max_token. Must be at least 1000.'));
1192
- return;
1193
- }
1194
- config.maxContextSize = maxContextSize;
1195
- this.configManager.setContextCompressionConfig(config);
1196
- await this.configManager.save('global');
1197
- console.log(chalk.green(`✅ Max tokens set to: ${maxContextSize}`));
1736
+ }
1737
+ }
1738
+ else {
1739
+ // Remote installation
1740
+ console.log(chalk.cyan('\n📦 Installing skill from remote source...\n'));
1741
+ console.log(chalk.gray(` Source: ${source}`));
1742
+ console.log(chalk.gray(` Type: Remote`));
1743
+ console.log();
1744
+ try {
1745
+ const result = await installSkill(source);
1746
+ if (result.success) {
1747
+ console.log(chalk.green('✅ Skill installed successfully'));
1748
+ console.log(chalk.gray(` Name: ${result.skillName}`));
1749
+ console.log(chalk.gray(` Location: ${result.skillPath}`));
1750
+ console.log(chalk.gray(' Type: Remote'));
1751
+ console.log();
1752
+ // Trigger system prompt update - skill is immediately available
1753
+ this.onSystemPromptUpdate?.();
1198
1754
  }
1199
1755
  else {
1200
- console.log(chalk.gray('Usage: /compress max_token <number>'));
1756
+ console.log(chalk.red(`\n❌ Failed to install skill: ${result.error}\n`));
1201
1757
  }
1202
- break;
1203
- default:
1204
- console.log(chalk.red(`❌ Unknown action: ${action}`));
1205
- console.log(chalk.gray('Available actions: on, off, max_message, max_token, exec'));
1758
+ }
1759
+ catch (error) {
1760
+ console.log(chalk.red(`\n❌ Error installing skill: ${error.message}\n`));
1761
+ }
1762
+ }
1763
+ }
1764
+ async removeSkill(skillName, userSkillsPath, fs, path) {
1765
+ if (!skillName) {
1766
+ console.log(chalk.yellow('\n⚠️ Please specify a skill name'));
1767
+ console.log(chalk.cyan(' Usage: /skill remove <skill-name>\n'));
1768
+ return;
1769
+ }
1770
+ // Protect find-skills from deletion
1771
+ if (skillName === 'find-skills') {
1772
+ console.log(chalk.red('\n❌ Cannot remove protected skill: find-skills'));
1773
+ console.log(chalk.gray(' find-skills is a built-in skill that helps you discover and install other skills.\n'));
1774
+ return;
1775
+ }
1776
+ const skillPath = path.join(userSkillsPath, skillName);
1777
+ try {
1778
+ await fs.access(skillPath);
1779
+ // Verify it's in skills path
1780
+ if (!skillPath.startsWith(userSkillsPath)) {
1781
+ console.log(chalk.red(`\n❌ Cannot remove skill outside user directory\n`));
1782
+ return;
1783
+ }
1784
+ // Remove the skill directory
1785
+ await fs.rm(skillPath, { recursive: true, force: true });
1786
+ console.log(chalk.green('\n✅ Skill removed successfully'));
1787
+ console.log();
1788
+ // Trigger system prompt update
1789
+ this.onSystemPromptUpdate?.();
1790
+ }
1791
+ catch (error) {
1792
+ if (error.code === 'ENOENT' || error.code === 'ENOENT') {
1793
+ console.log(chalk.yellow(`\n⚠️ Skill not found: ${skillName}\n`));
1794
+ }
1795
+ else {
1796
+ console.log(chalk.red(`\n❌ Error removing skill: ${error.message}\n`));
1797
+ }
1798
+ }
1799
+ }
1800
+ async copyDirectory(src, dest) {
1801
+ const entries = await fs.readdir(src, { withFileTypes: true });
1802
+ await fs.mkdir(dest, { recursive: true });
1803
+ for (const entry of entries) {
1804
+ // Skip node_modules to keep dependencies isolated
1805
+ // if (entry.name === 'node_modules') continue;
1806
+ const srcPath = path.join(src, entry.name);
1807
+ const destPath = path.join(dest, entry.name);
1808
+ if (entry.isDirectory()) {
1809
+ await this.copyDirectory(srcPath, destPath);
1810
+ }
1811
+ else if (entry.isFile()) {
1812
+ await fs.copyFile(srcPath, destPath);
1813
+ }
1206
1814
  }
1207
1815
  }
1208
1816
  }
1209
- export function parseInput(input) {
1817
+ export async function parseInput(input) {
1210
1818
  const inputs = [];
1211
1819
  let remaining = input;
1820
+ // Match @ followed by any non-whitespace sequence
1212
1821
  const fileRefRegex = /@([^\s]+)/g;
1213
1822
  let match;
1214
1823
  while ((match = fileRefRegex.exec(remaining)) !== null) {
@@ -1218,7 +1827,15 @@ export function parseInput(input) {
1218
1827
  if (beforeMatch.trim()) {
1219
1828
  inputs.push({ type: 'text', content: beforeMatch.trim() });
1220
1829
  }
1221
- inputs.push({ type: 'file', content: filePath });
1830
+ // Only treat as file reference if the file actually exists
1831
+ const exists = await fileExists(filePath);
1832
+ if (exists) {
1833
+ inputs.push({ type: 'file', content: filePath });
1834
+ }
1835
+ else {
1836
+ // Not a file, treat as regular text (preserving the @ symbol)
1837
+ inputs.push({ type: 'text', content: '@' + filePath });
1838
+ }
1222
1839
  remaining = afterMatch;
1223
1840
  }
1224
1841
  if (remaining.trim()) {
@@ -1231,6 +1848,18 @@ export function parseInput(input) {
1231
1848
  }
1232
1849
  return inputs;
1233
1850
  }
1851
+ // Helper function to check if a file path exists
1852
+ async function fileExists(filePath) {
1853
+ try {
1854
+ // Resolve to absolute path
1855
+ const absolutePath = path.resolve(filePath);
1856
+ await fs.access(absolutePath);
1857
+ return true;
1858
+ }
1859
+ catch {
1860
+ return false;
1861
+ }
1862
+ }
1234
1863
  export function detectImageInput(input) {
1235
1864
  return input.includes('[Pasted image') || input.includes('<image');
1236
1865
  }