@xagent-ai/cli 1.2.2 → 1.3.0

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 (568) 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/workflows/ci.yml +72 -0
  4. package/.github/workflows/release.yml +109 -0
  5. package/.gitmodules +3 -3
  6. package/README.md +326 -280
  7. package/README_CN.md +325 -279
  8. package/dist/ai-client/factory.d.ts +52 -0
  9. package/dist/ai-client/factory.d.ts.map +1 -0
  10. package/dist/ai-client/factory.js +132 -0
  11. package/dist/ai-client/factory.js.map +1 -0
  12. package/dist/ai-client/index.d.ts +20 -0
  13. package/dist/ai-client/index.d.ts.map +1 -0
  14. package/dist/ai-client/index.js +49 -0
  15. package/dist/ai-client/index.js.map +1 -0
  16. package/dist/ai-client/providers/anthropic.d.ts +57 -0
  17. package/dist/ai-client/providers/anthropic.d.ts.map +1 -0
  18. package/dist/ai-client/providers/anthropic.js +400 -0
  19. package/dist/ai-client/providers/anthropic.js.map +1 -0
  20. package/dist/ai-client/providers/openai.d.ts +57 -0
  21. package/dist/ai-client/providers/openai.d.ts.map +1 -0
  22. package/dist/ai-client/providers/openai.js +286 -0
  23. package/dist/ai-client/providers/openai.js.map +1 -0
  24. package/dist/ai-client/providers/remote.d.ts +111 -0
  25. package/dist/ai-client/providers/remote.d.ts.map +1 -0
  26. package/dist/ai-client/providers/remote.js +351 -0
  27. package/dist/ai-client/providers/remote.js.map +1 -0
  28. package/dist/ai-client/registry.d.ts +51 -0
  29. package/dist/ai-client/registry.d.ts.map +1 -0
  30. package/dist/ai-client/registry.js +81 -0
  31. package/dist/ai-client/registry.js.map +1 -0
  32. package/dist/ai-client/types.d.ts +260 -0
  33. package/dist/ai-client/types.d.ts.map +1 -0
  34. package/dist/ai-client/types.js +73 -0
  35. package/dist/ai-client/types.js.map +1 -0
  36. package/dist/ai-client-factory.d.ts +62 -0
  37. package/dist/ai-client-factory.d.ts.map +1 -0
  38. package/dist/ai-client-factory.js +157 -0
  39. package/dist/ai-client-factory.js.map +1 -0
  40. package/dist/auth.d.ts +23 -1
  41. package/dist/auth.d.ts.map +1 -1
  42. package/dist/auth.js +160 -168
  43. package/dist/auth.js.map +1 -1
  44. package/dist/cancellation.d.ts +5 -4
  45. package/dist/cancellation.d.ts.map +1 -1
  46. package/dist/cancellation.js +55 -32
  47. package/dist/cancellation.js.map +1 -1
  48. package/dist/checkpoint.d.ts +1 -1
  49. package/dist/checkpoint.d.ts.map +1 -1
  50. package/dist/checkpoint.js +2 -2
  51. package/dist/checkpoint.js.map +1 -1
  52. package/dist/cli.js +626 -13
  53. package/dist/cli.js.map +1 -1
  54. package/dist/config.d.ts +10 -4
  55. package/dist/config.d.ts.map +1 -1
  56. package/dist/config.js +62 -25
  57. package/dist/config.js.map +1 -1
  58. package/dist/context-compressor.d.ts +81 -16
  59. package/dist/context-compressor.d.ts.map +1 -1
  60. package/dist/context-compressor.js +712 -153
  61. package/dist/context-compressor.js.map +1 -1
  62. package/dist/gui-subagent/action-parser/actionParser.d.ts.map +1 -1
  63. package/dist/gui-subagent/action-parser/actionParser.js +4 -2
  64. package/dist/gui-subagent/action-parser/actionParser.js.map +1 -1
  65. package/dist/gui-subagent/agent/gui-agent.d.ts +29 -2
  66. package/dist/gui-subagent/agent/gui-agent.d.ts.map +1 -1
  67. package/dist/gui-subagent/agent/gui-agent.js +87 -45
  68. package/dist/gui-subagent/agent/gui-agent.js.map +1 -1
  69. package/dist/gui-subagent/index.d.ts +16 -1
  70. package/dist/gui-subagent/index.d.ts.map +1 -1
  71. package/dist/gui-subagent/index.js +4 -0
  72. package/dist/gui-subagent/index.js.map +1 -1
  73. package/dist/gui-subagent/operator/base-operator.d.ts.map +1 -1
  74. package/dist/gui-subagent/operator/base-operator.js +0 -1
  75. package/dist/gui-subagent/operator/base-operator.js.map +1 -1
  76. package/dist/gui-subagent/operator/computer-operator.d.ts.map +1 -1
  77. package/dist/gui-subagent/operator/computer-operator.js +29 -8
  78. package/dist/gui-subagent/operator/computer-operator.js.map +1 -1
  79. package/dist/gui-subagent/types/actions.d.ts +1 -1
  80. package/dist/gui-subagent/types/actions.d.ts.map +1 -1
  81. package/dist/gui-subagent/types/actions.js +0 -1
  82. package/dist/gui-subagent/types/actions.js.map +1 -1
  83. package/dist/gui-subagent/types/operator.d.ts +1 -1
  84. package/dist/gui-subagent/types/operator.d.ts.map +1 -1
  85. package/dist/index.d.ts +1 -2
  86. package/dist/index.d.ts.map +1 -1
  87. package/dist/index.js +1 -2
  88. package/dist/index.js.map +1 -1
  89. package/dist/input-processor.d.ts.map +1 -1
  90. package/dist/input-processor.js +6 -3
  91. package/dist/input-processor.js.map +1 -1
  92. package/dist/mcp.d.ts +5 -0
  93. package/dist/mcp.d.ts.map +1 -1
  94. package/dist/mcp.js +81 -35
  95. package/dist/mcp.js.map +1 -1
  96. package/dist/ripgrep.d.ts +29 -0
  97. package/dist/ripgrep.d.ts.map +1 -0
  98. package/dist/ripgrep.js +292 -0
  99. package/dist/ripgrep.js.map +1 -0
  100. package/dist/session.d.ts +23 -7
  101. package/dist/session.d.ts.map +1 -1
  102. package/dist/session.js +624 -243
  103. package/dist/session.js.map +1 -1
  104. package/dist/shell.d.ts +33 -0
  105. package/dist/shell.d.ts.map +1 -0
  106. package/dist/shell.js +125 -0
  107. package/dist/shell.js.map +1 -0
  108. package/dist/skill-installer.d.ts +38 -0
  109. package/dist/skill-installer.d.ts.map +1 -0
  110. package/dist/skill-installer.js +447 -0
  111. package/dist/skill-installer.js.map +1 -0
  112. package/dist/skill-invoker.d.ts +7 -1
  113. package/dist/skill-invoker.d.ts.map +1 -1
  114. package/dist/skill-invoker.js +34 -13
  115. package/dist/skill-invoker.js.map +1 -1
  116. package/dist/skill-loader.d.ts +8 -3
  117. package/dist/skill-loader.d.ts.map +1 -1
  118. package/dist/skill-loader.js +46 -44
  119. package/dist/skill-loader.js.map +1 -1
  120. package/dist/skill-manager.d.ts +85 -0
  121. package/dist/skill-manager.d.ts.map +1 -0
  122. package/dist/skill-manager.js +340 -0
  123. package/dist/skill-manager.js.map +1 -0
  124. package/dist/slash-commands.d.ts +38 -1
  125. package/dist/slash-commands.d.ts.map +1 -1
  126. package/dist/slash-commands.js +912 -296
  127. package/dist/slash-commands.js.map +1 -1
  128. package/dist/smart-approval.d.ts.map +1 -1
  129. package/dist/smart-approval.js +67 -55
  130. package/dist/smart-approval.js.map +1 -1
  131. package/dist/system-prompt-generator.d.ts +6 -0
  132. package/dist/system-prompt-generator.d.ts.map +1 -1
  133. package/dist/system-prompt-generator.js +84 -34
  134. package/dist/system-prompt-generator.js.map +1 -1
  135. package/dist/terminal.d.ts +28 -0
  136. package/dist/terminal.d.ts.map +1 -0
  137. package/dist/terminal.js +82 -0
  138. package/dist/terminal.js.map +1 -0
  139. package/dist/tools.d.ts +23 -7
  140. package/dist/tools.d.ts.map +1 -1
  141. package/dist/tools.js +797 -437
  142. package/dist/tools.js.map +1 -1
  143. package/dist/truncate.d.ts +55 -0
  144. package/dist/truncate.d.ts.map +1 -0
  145. package/dist/truncate.js +130 -0
  146. package/dist/truncate.js.map +1 -0
  147. package/dist/types.d.ts +27 -9
  148. package/dist/types.d.ts.map +1 -1
  149. package/dist/update.d.ts.map +1 -1
  150. package/dist/update.js +17 -28
  151. package/dist/update.js.map +1 -1
  152. package/dist/workflow.d.ts +5 -1
  153. package/dist/workflow.d.ts.map +1 -1
  154. package/dist/workflow.js +60 -47
  155. package/dist/workflow.js.map +1 -1
  156. package/docs/architecture/mcp-integration-guide.md +304 -194
  157. package/docs/architecture/overview.md +169 -169
  158. package/docs/architecture/tool-system-design.md +134 -134
  159. package/docs/cli/commands.md +349 -238
  160. package/docs/smart-mode.md +281 -281
  161. package/docs/third-party-models.md +439 -439
  162. package/find-skills/SKILL.md +133 -0
  163. package/package.json +89 -90
  164. package/scripts/install-ripgrep.js +241 -0
  165. package/src/ai-client/factory.ts +151 -0
  166. package/src/ai-client/index.ts +61 -0
  167. package/src/ai-client/providers/anthropic.ts +466 -0
  168. package/src/ai-client/providers/openai.ts +342 -0
  169. package/src/ai-client/providers/remote.ts +436 -0
  170. package/src/ai-client/registry.ts +97 -0
  171. package/src/ai-client/types.ts +345 -0
  172. package/src/ai-client-factory.ts +204 -0
  173. package/src/auth.ts +663 -614
  174. package/src/cancellation.ts +205 -176
  175. package/src/checkpoint.ts +219 -219
  176. package/src/cli.ts +1406 -743
  177. package/src/config.ts +341 -297
  178. package/src/context-compressor.ts +982 -290
  179. package/src/conversation.ts +288 -288
  180. package/src/gui-subagent/action-parser/actionParser.ts +318 -315
  181. package/src/gui-subagent/action-parser/constants.ts +14 -14
  182. package/src/gui-subagent/action-parser/index.ts +8 -8
  183. package/src/gui-subagent/action-parser/types.ts +31 -31
  184. package/src/gui-subagent/agent/gui-agent.ts +1151 -1089
  185. package/src/gui-subagent/agent/index.ts +5 -5
  186. package/src/gui-subagent/index.ts +177 -163
  187. package/src/gui-subagent/operator/base-operator.ts +244 -245
  188. package/src/gui-subagent/operator/computer-operator.ts +540 -520
  189. package/src/gui-subagent/operator/index.ts +6 -6
  190. package/src/gui-subagent/types/actions.ts +260 -262
  191. package/src/gui-subagent/types/index.ts +6 -6
  192. package/src/gui-subagent/types/operator.ts +106 -106
  193. package/src/gui-subagent/utils.ts +51 -51
  194. package/src/index.ts +17 -18
  195. package/src/input-processor.ts +6 -3
  196. package/src/logger.ts +438 -438
  197. package/src/mcp.ts +730 -682
  198. package/src/memory.ts +344 -344
  199. package/src/ripgrep.ts +368 -0
  200. package/src/session-manager.ts +308 -308
  201. package/src/session.ts +948 -386
  202. package/src/shell.ts +133 -0
  203. package/src/skill-installer.ts +518 -0
  204. package/src/skill-invoker.ts +960 -935
  205. package/src/skill-loader.ts +501 -496
  206. package/src/skill-manager.ts +384 -0
  207. package/src/slash-commands.ts +2181 -1389
  208. package/src/smart-approval.ts +117 -73
  209. package/src/system-prompt-generator.ts +89 -34
  210. package/src/terminal.ts +96 -0
  211. package/src/theme.ts +738 -738
  212. package/src/tools.ts +1336 -773
  213. package/src/truncate.ts +173 -0
  214. package/src/types.ts +219 -198
  215. package/src/update.ts +22 -32
  216. package/src/workflow.ts +523 -508
  217. package/tsconfig.json +22 -22
  218. package/vitest.config.ts +19 -19
  219. package/dist/ai-client.d.ts +0 -86
  220. package/dist/ai-client.d.ts.map +0 -1
  221. package/dist/ai-client.js +0 -1372
  222. package/dist/ai-client.js.map +0 -1
  223. package/dist/gui-subagent/operator/browser-operator.d.ts +0 -36
  224. package/dist/gui-subagent/operator/browser-operator.d.ts.map +0 -1
  225. package/dist/gui-subagent/operator/browser-operator.js +0 -306
  226. package/dist/gui-subagent/operator/browser-operator.js.map +0 -1
  227. package/dist/gui-subagent/operator/desktop-operator.d.ts +0 -55
  228. package/dist/gui-subagent/operator/desktop-operator.d.ts.map +0 -1
  229. package/dist/gui-subagent/operator/desktop-operator.js +0 -527
  230. package/dist/gui-subagent/operator/desktop-operator.js.map +0 -1
  231. package/dist/hook.d.ts +0 -73
  232. package/dist/hook.d.ts.map +0 -1
  233. package/dist/hook.js +0 -156
  234. package/dist/hook.js.map +0 -1
  235. package/dist/input-history.d.ts +0 -24
  236. package/dist/input-history.d.ts.map +0 -1
  237. package/dist/input-history.js +0 -94
  238. package/dist/input-history.js.map +0 -1
  239. package/dist/keyboard-manager.d.ts +0 -151
  240. package/dist/keyboard-manager.d.ts.map +0 -1
  241. package/dist/keyboard-manager.js +0 -396
  242. package/dist/keyboard-manager.js.map +0 -1
  243. package/dist/print-system-prompt.d.ts +0 -2
  244. package/dist/print-system-prompt.d.ts.map +0 -1
  245. package/dist/print-system-prompt.js +0 -40
  246. package/dist/print-system-prompt.js.map +0 -1
  247. package/dist/remote-ai-client.d.ts +0 -104
  248. package/dist/remote-ai-client.d.ts.map +0 -1
  249. package/dist/remote-ai-client.js +0 -552
  250. package/dist/remote-ai-client.js.map +0 -1
  251. package/dist/sdk-output-adapter.d.ts +0 -232
  252. package/dist/sdk-output-adapter.d.ts.map +0 -1
  253. package/dist/sdk-output-adapter.js +0 -636
  254. package/dist/sdk-output-adapter.js.map +0 -1
  255. package/dist/sdk-session-v2.d.ts +0 -13
  256. package/dist/sdk-session-v2.d.ts.map +0 -1
  257. package/dist/sdk-session-v2.js +0 -46
  258. package/dist/sdk-session-v2.js.map +0 -1
  259. package/dist/sdk-session.d.ts +0 -13
  260. package/dist/sdk-session.d.ts.map +0 -1
  261. package/dist/sdk-session.js +0 -48
  262. package/dist/sdk-session.js.map +0 -1
  263. package/dist/test-boundary-conditions.d.ts.map +0 -1
  264. package/dist/test-boundary-conditions.js.map +0 -1
  265. package/dist/test-cancellation-fix.d.ts.map +0 -1
  266. package/dist/test-cancellation-fix.js.map +0 -1
  267. package/dist/test-input-history.d.ts.map +0 -1
  268. package/dist/test-input-history.js.map +0 -1
  269. package/dist/test-interaction-flow.d.ts.map +0 -1
  270. package/dist/test-interaction-flow.js.map +0 -1
  271. package/dist/test-quick.d.ts.map +0 -1
  272. package/dist/test-quick.js.map +0 -1
  273. package/dist/test-user-interaction.d.ts.map +0 -1
  274. package/dist/test-user-interaction.js.map +0 -1
  275. package/dist/tools/edit-diff.d.ts +0 -32
  276. package/dist/tools/edit-diff.d.ts.map +0 -1
  277. package/dist/tools/edit-diff.js +0 -185
  278. package/dist/tools/edit-diff.js.map +0 -1
  279. package/dist/tools/edit.d.ts +0 -11
  280. package/dist/tools/edit.d.ts.map +0 -1
  281. package/dist/tools/edit.js +0 -129
  282. package/dist/tools/edit.js.map +0 -1
  283. package/dist/unified-session.d.ts +0 -42
  284. package/dist/unified-session.d.ts.map +0 -1
  285. package/dist/unified-session.js +0 -271
  286. package/dist/unified-session.js.map +0 -1
  287. package/skills/.claude-plugin/marketplace.json +0 -45
  288. package/skills/README.md +0 -94
  289. package/skills/THIRD_PARTY_NOTICES.md +0 -405
  290. package/skills/skills/algorithmic-art/LICENSE.txt +0 -202
  291. package/skills/skills/algorithmic-art/SKILL.md +0 -405
  292. package/skills/skills/algorithmic-art/templates/generator_template.js +0 -223
  293. package/skills/skills/algorithmic-art/templates/viewer.html +0 -599
  294. package/skills/skills/brand-guidelines/LICENSE.txt +0 -202
  295. package/skills/skills/brand-guidelines/SKILL.md +0 -73
  296. package/skills/skills/canvas-design/LICENSE.txt +0 -202
  297. package/skills/skills/canvas-design/SKILL.md +0 -130
  298. package/skills/skills/canvas-design/canvas-fonts/ArsenalSC-OFL.txt +0 -93
  299. package/skills/skills/canvas-design/canvas-fonts/ArsenalSC-Regular.ttf +0 -0
  300. package/skills/skills/canvas-design/canvas-fonts/BigShoulders-Bold.ttf +0 -0
  301. package/skills/skills/canvas-design/canvas-fonts/BigShoulders-OFL.txt +0 -93
  302. package/skills/skills/canvas-design/canvas-fonts/BigShoulders-Regular.ttf +0 -0
  303. package/skills/skills/canvas-design/canvas-fonts/Boldonse-OFL.txt +0 -93
  304. package/skills/skills/canvas-design/canvas-fonts/Boldonse-Regular.ttf +0 -0
  305. package/skills/skills/canvas-design/canvas-fonts/BricolageGrotesque-Bold.ttf +0 -0
  306. package/skills/skills/canvas-design/canvas-fonts/BricolageGrotesque-OFL.txt +0 -93
  307. package/skills/skills/canvas-design/canvas-fonts/BricolageGrotesque-Regular.ttf +0 -0
  308. package/skills/skills/canvas-design/canvas-fonts/CrimsonPro-Bold.ttf +0 -0
  309. package/skills/skills/canvas-design/canvas-fonts/CrimsonPro-Italic.ttf +0 -0
  310. package/skills/skills/canvas-design/canvas-fonts/CrimsonPro-OFL.txt +0 -93
  311. package/skills/skills/canvas-design/canvas-fonts/CrimsonPro-Regular.ttf +0 -0
  312. package/skills/skills/canvas-design/canvas-fonts/DMMono-OFL.txt +0 -93
  313. package/skills/skills/canvas-design/canvas-fonts/DMMono-Regular.ttf +0 -0
  314. package/skills/skills/canvas-design/canvas-fonts/EricaOne-OFL.txt +0 -94
  315. package/skills/skills/canvas-design/canvas-fonts/EricaOne-Regular.ttf +0 -0
  316. package/skills/skills/canvas-design/canvas-fonts/GeistMono-Bold.ttf +0 -0
  317. package/skills/skills/canvas-design/canvas-fonts/GeistMono-OFL.txt +0 -93
  318. package/skills/skills/canvas-design/canvas-fonts/GeistMono-Regular.ttf +0 -0
  319. package/skills/skills/canvas-design/canvas-fonts/Gloock-OFL.txt +0 -93
  320. package/skills/skills/canvas-design/canvas-fonts/Gloock-Regular.ttf +0 -0
  321. package/skills/skills/canvas-design/canvas-fonts/IBMPlexMono-Bold.ttf +0 -0
  322. package/skills/skills/canvas-design/canvas-fonts/IBMPlexMono-OFL.txt +0 -93
  323. package/skills/skills/canvas-design/canvas-fonts/IBMPlexMono-Regular.ttf +0 -0
  324. package/skills/skills/canvas-design/canvas-fonts/IBMPlexSerif-Bold.ttf +0 -0
  325. package/skills/skills/canvas-design/canvas-fonts/IBMPlexSerif-BoldItalic.ttf +0 -0
  326. package/skills/skills/canvas-design/canvas-fonts/IBMPlexSerif-Italic.ttf +0 -0
  327. package/skills/skills/canvas-design/canvas-fonts/IBMPlexSerif-Regular.ttf +0 -0
  328. package/skills/skills/canvas-design/canvas-fonts/InstrumentSans-Bold.ttf +0 -0
  329. package/skills/skills/canvas-design/canvas-fonts/InstrumentSans-BoldItalic.ttf +0 -0
  330. package/skills/skills/canvas-design/canvas-fonts/InstrumentSans-Italic.ttf +0 -0
  331. package/skills/skills/canvas-design/canvas-fonts/InstrumentSans-OFL.txt +0 -93
  332. package/skills/skills/canvas-design/canvas-fonts/InstrumentSans-Regular.ttf +0 -0
  333. package/skills/skills/canvas-design/canvas-fonts/InstrumentSerif-Italic.ttf +0 -0
  334. package/skills/skills/canvas-design/canvas-fonts/InstrumentSerif-Regular.ttf +0 -0
  335. package/skills/skills/canvas-design/canvas-fonts/Italiana-OFL.txt +0 -93
  336. package/skills/skills/canvas-design/canvas-fonts/Italiana-Regular.ttf +0 -0
  337. package/skills/skills/canvas-design/canvas-fonts/JetBrainsMono-Bold.ttf +0 -0
  338. package/skills/skills/canvas-design/canvas-fonts/JetBrainsMono-OFL.txt +0 -93
  339. package/skills/skills/canvas-design/canvas-fonts/JetBrainsMono-Regular.ttf +0 -0
  340. package/skills/skills/canvas-design/canvas-fonts/Jura-Light.ttf +0 -0
  341. package/skills/skills/canvas-design/canvas-fonts/Jura-Medium.ttf +0 -0
  342. package/skills/skills/canvas-design/canvas-fonts/Jura-OFL.txt +0 -93
  343. package/skills/skills/canvas-design/canvas-fonts/LibreBaskerville-OFL.txt +0 -93
  344. package/skills/skills/canvas-design/canvas-fonts/LibreBaskerville-Regular.ttf +0 -0
  345. package/skills/skills/canvas-design/canvas-fonts/Lora-Bold.ttf +0 -0
  346. package/skills/skills/canvas-design/canvas-fonts/Lora-BoldItalic.ttf +0 -0
  347. package/skills/skills/canvas-design/canvas-fonts/Lora-Italic.ttf +0 -0
  348. package/skills/skills/canvas-design/canvas-fonts/Lora-OFL.txt +0 -93
  349. package/skills/skills/canvas-design/canvas-fonts/Lora-Regular.ttf +0 -0
  350. package/skills/skills/canvas-design/canvas-fonts/NationalPark-Bold.ttf +0 -0
  351. package/skills/skills/canvas-design/canvas-fonts/NationalPark-OFL.txt +0 -93
  352. package/skills/skills/canvas-design/canvas-fonts/NationalPark-Regular.ttf +0 -0
  353. package/skills/skills/canvas-design/canvas-fonts/NothingYouCouldDo-OFL.txt +0 -93
  354. package/skills/skills/canvas-design/canvas-fonts/NothingYouCouldDo-Regular.ttf +0 -0
  355. package/skills/skills/canvas-design/canvas-fonts/Outfit-Bold.ttf +0 -0
  356. package/skills/skills/canvas-design/canvas-fonts/Outfit-OFL.txt +0 -93
  357. package/skills/skills/canvas-design/canvas-fonts/Outfit-Regular.ttf +0 -0
  358. package/skills/skills/canvas-design/canvas-fonts/PixelifySans-Medium.ttf +0 -0
  359. package/skills/skills/canvas-design/canvas-fonts/PixelifySans-OFL.txt +0 -93
  360. package/skills/skills/canvas-design/canvas-fonts/PoiretOne-OFL.txt +0 -93
  361. package/skills/skills/canvas-design/canvas-fonts/PoiretOne-Regular.ttf +0 -0
  362. package/skills/skills/canvas-design/canvas-fonts/RedHatMono-Bold.ttf +0 -0
  363. package/skills/skills/canvas-design/canvas-fonts/RedHatMono-OFL.txt +0 -93
  364. package/skills/skills/canvas-design/canvas-fonts/RedHatMono-Regular.ttf +0 -0
  365. package/skills/skills/canvas-design/canvas-fonts/Silkscreen-OFL.txt +0 -93
  366. package/skills/skills/canvas-design/canvas-fonts/Silkscreen-Regular.ttf +0 -0
  367. package/skills/skills/canvas-design/canvas-fonts/SmoochSans-Medium.ttf +0 -0
  368. package/skills/skills/canvas-design/canvas-fonts/SmoochSans-OFL.txt +0 -93
  369. package/skills/skills/canvas-design/canvas-fonts/Tektur-Medium.ttf +0 -0
  370. package/skills/skills/canvas-design/canvas-fonts/Tektur-OFL.txt +0 -93
  371. package/skills/skills/canvas-design/canvas-fonts/Tektur-Regular.ttf +0 -0
  372. package/skills/skills/canvas-design/canvas-fonts/WorkSans-Bold.ttf +0 -0
  373. package/skills/skills/canvas-design/canvas-fonts/WorkSans-BoldItalic.ttf +0 -0
  374. package/skills/skills/canvas-design/canvas-fonts/WorkSans-Italic.ttf +0 -0
  375. package/skills/skills/canvas-design/canvas-fonts/WorkSans-OFL.txt +0 -93
  376. package/skills/skills/canvas-design/canvas-fonts/WorkSans-Regular.ttf +0 -0
  377. package/skills/skills/canvas-design/canvas-fonts/YoungSerif-OFL.txt +0 -93
  378. package/skills/skills/canvas-design/canvas-fonts/YoungSerif-Regular.ttf +0 -0
  379. package/skills/skills/doc-coauthoring/SKILL.md +0 -375
  380. package/skills/skills/docx/LICENSE.txt +0 -30
  381. package/skills/skills/docx/SKILL.md +0 -197
  382. package/skills/skills/docx/docx-js.md +0 -350
  383. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +0 -1499
  384. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +0 -146
  385. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +0 -1085
  386. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +0 -11
  387. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +0 -3081
  388. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +0 -23
  389. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +0 -185
  390. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +0 -287
  391. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +0 -1676
  392. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +0 -28
  393. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +0 -144
  394. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +0 -174
  395. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +0 -25
  396. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +0 -18
  397. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +0 -59
  398. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +0 -56
  399. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +0 -195
  400. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +0 -582
  401. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +0 -25
  402. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +0 -4439
  403. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +0 -570
  404. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +0 -509
  405. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +0 -12
  406. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +0 -108
  407. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +0 -96
  408. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +0 -3646
  409. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +0 -116
  410. package/skills/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +0 -42
  411. package/skills/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +0 -50
  412. package/skills/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +0 -49
  413. package/skills/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +0 -33
  414. package/skills/skills/docx/ooxml/schemas/mce/mc.xsd +0 -75
  415. package/skills/skills/docx/ooxml/schemas/microsoft/wml-2010.xsd +0 -560
  416. package/skills/skills/docx/ooxml/schemas/microsoft/wml-2012.xsd +0 -67
  417. package/skills/skills/docx/ooxml/schemas/microsoft/wml-2018.xsd +0 -14
  418. package/skills/skills/docx/ooxml/schemas/microsoft/wml-cex-2018.xsd +0 -20
  419. package/skills/skills/docx/ooxml/schemas/microsoft/wml-cid-2016.xsd +0 -13
  420. package/skills/skills/docx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +0 -4
  421. package/skills/skills/docx/ooxml/schemas/microsoft/wml-symex-2015.xsd +0 -8
  422. package/skills/skills/docx/ooxml/scripts/pack.py +0 -159
  423. package/skills/skills/docx/ooxml/scripts/unpack.py +0 -29
  424. package/skills/skills/docx/ooxml/scripts/validate.py +0 -69
  425. package/skills/skills/docx/ooxml/scripts/validation/__init__.py +0 -15
  426. package/skills/skills/docx/ooxml/scripts/validation/base.py +0 -951
  427. package/skills/skills/docx/ooxml/scripts/validation/docx.py +0 -274
  428. package/skills/skills/docx/ooxml/scripts/validation/pptx.py +0 -315
  429. package/skills/skills/docx/ooxml/scripts/validation/redlining.py +0 -279
  430. package/skills/skills/docx/ooxml.md +0 -610
  431. package/skills/skills/docx/scripts/__init__.py +0 -1
  432. package/skills/skills/docx/scripts/document.py +0 -1276
  433. package/skills/skills/docx/scripts/templates/comments.xml +0 -3
  434. package/skills/skills/docx/scripts/templates/commentsExtended.xml +0 -3
  435. package/skills/skills/docx/scripts/templates/commentsExtensible.xml +0 -3
  436. package/skills/skills/docx/scripts/templates/commentsIds.xml +0 -3
  437. package/skills/skills/docx/scripts/templates/people.xml +0 -3
  438. package/skills/skills/docx/scripts/utilities.py +0 -374
  439. package/skills/skills/frontend-design/LICENSE.txt +0 -177
  440. package/skills/skills/frontend-design/SKILL.md +0 -42
  441. package/skills/skills/internal-comms/LICENSE.txt +0 -202
  442. package/skills/skills/internal-comms/SKILL.md +0 -32
  443. package/skills/skills/internal-comms/examples/3p-updates.md +0 -47
  444. package/skills/skills/internal-comms/examples/company-newsletter.md +0 -65
  445. package/skills/skills/internal-comms/examples/faq-answers.md +0 -30
  446. package/skills/skills/internal-comms/examples/general-comms.md +0 -16
  447. package/skills/skills/mcp-builder/LICENSE.txt +0 -202
  448. package/skills/skills/mcp-builder/SKILL.md +0 -236
  449. package/skills/skills/mcp-builder/reference/evaluation.md +0 -602
  450. package/skills/skills/mcp-builder/reference/mcp_best_practices.md +0 -249
  451. package/skills/skills/mcp-builder/reference/node_mcp_server.md +0 -970
  452. package/skills/skills/mcp-builder/reference/python_mcp_server.md +0 -719
  453. package/skills/skills/mcp-builder/scripts/connections.py +0 -151
  454. package/skills/skills/mcp-builder/scripts/evaluation.py +0 -373
  455. package/skills/skills/mcp-builder/scripts/example_evaluation.xml +0 -22
  456. package/skills/skills/mcp-builder/scripts/requirements.txt +0 -2
  457. package/skills/skills/pdf/LICENSE.txt +0 -30
  458. package/skills/skills/pdf/SKILL.md +0 -294
  459. package/skills/skills/pdf/forms.md +0 -205
  460. package/skills/skills/pdf/reference.md +0 -612
  461. package/skills/skills/pdf/scripts/check_bounding_boxes.py +0 -70
  462. package/skills/skills/pdf/scripts/check_bounding_boxes_test.py +0 -226
  463. package/skills/skills/pdf/scripts/check_fillable_fields.py +0 -12
  464. package/skills/skills/pdf/scripts/convert_pdf_to_images.py +0 -35
  465. package/skills/skills/pdf/scripts/create_validation_image.py +0 -41
  466. package/skills/skills/pdf/scripts/extract_form_field_info.py +0 -152
  467. package/skills/skills/pdf/scripts/fill_fillable_fields.py +0 -114
  468. package/skills/skills/pdf/scripts/fill_pdf_form_with_annotations.py +0 -108
  469. package/skills/skills/pptx/LICENSE.txt +0 -30
  470. package/skills/skills/pptx/SKILL.md +0 -484
  471. package/skills/skills/pptx/html2pptx.md +0 -625
  472. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +0 -1499
  473. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +0 -146
  474. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +0 -1085
  475. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +0 -11
  476. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +0 -3081
  477. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +0 -23
  478. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +0 -185
  479. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +0 -287
  480. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +0 -1676
  481. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +0 -28
  482. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +0 -144
  483. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +0 -174
  484. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +0 -25
  485. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +0 -18
  486. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +0 -59
  487. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +0 -56
  488. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +0 -195
  489. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +0 -582
  490. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +0 -25
  491. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +0 -4439
  492. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +0 -570
  493. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +0 -509
  494. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +0 -12
  495. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +0 -108
  496. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +0 -96
  497. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +0 -3646
  498. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +0 -116
  499. package/skills/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +0 -42
  500. package/skills/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +0 -50
  501. package/skills/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +0 -49
  502. package/skills/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +0 -33
  503. package/skills/skills/pptx/ooxml/schemas/mce/mc.xsd +0 -75
  504. package/skills/skills/pptx/ooxml/schemas/microsoft/wml-2010.xsd +0 -560
  505. package/skills/skills/pptx/ooxml/schemas/microsoft/wml-2012.xsd +0 -67
  506. package/skills/skills/pptx/ooxml/schemas/microsoft/wml-2018.xsd +0 -14
  507. package/skills/skills/pptx/ooxml/schemas/microsoft/wml-cex-2018.xsd +0 -20
  508. package/skills/skills/pptx/ooxml/schemas/microsoft/wml-cid-2016.xsd +0 -13
  509. package/skills/skills/pptx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +0 -4
  510. package/skills/skills/pptx/ooxml/schemas/microsoft/wml-symex-2015.xsd +0 -8
  511. package/skills/skills/pptx/ooxml/scripts/pack.py +0 -159
  512. package/skills/skills/pptx/ooxml/scripts/unpack.py +0 -29
  513. package/skills/skills/pptx/ooxml/scripts/validate.py +0 -69
  514. package/skills/skills/pptx/ooxml/scripts/validation/__init__.py +0 -15
  515. package/skills/skills/pptx/ooxml/scripts/validation/base.py +0 -951
  516. package/skills/skills/pptx/ooxml/scripts/validation/docx.py +0 -274
  517. package/skills/skills/pptx/ooxml/scripts/validation/pptx.py +0 -315
  518. package/skills/skills/pptx/ooxml/scripts/validation/redlining.py +0 -279
  519. package/skills/skills/pptx/ooxml.md +0 -427
  520. package/skills/skills/pptx/scripts/html2pptx.js +0 -979
  521. package/skills/skills/pptx/scripts/inventory.py +0 -1020
  522. package/skills/skills/pptx/scripts/rearrange.py +0 -231
  523. package/skills/skills/pptx/scripts/replace.py +0 -385
  524. package/skills/skills/pptx/scripts/thumbnail.py +0 -450
  525. package/skills/skills/skill-creator/LICENSE.txt +0 -202
  526. package/skills/skills/skill-creator/SKILL.md +0 -356
  527. package/skills/skills/skill-creator/references/output-patterns.md +0 -82
  528. package/skills/skills/skill-creator/references/workflows.md +0 -28
  529. package/skills/skills/skill-creator/scripts/init_skill.py +0 -303
  530. package/skills/skills/skill-creator/scripts/package_skill.py +0 -110
  531. package/skills/skills/skill-creator/scripts/quick_validate.py +0 -95
  532. package/skills/skills/slack-gif-creator/LICENSE.txt +0 -202
  533. package/skills/skills/slack-gif-creator/SKILL.md +0 -254
  534. package/skills/skills/slack-gif-creator/core/easing.py +0 -234
  535. package/skills/skills/slack-gif-creator/core/frame_composer.py +0 -176
  536. package/skills/skills/slack-gif-creator/core/gif_builder.py +0 -269
  537. package/skills/skills/slack-gif-creator/core/validators.py +0 -136
  538. package/skills/skills/slack-gif-creator/requirements.txt +0 -4
  539. package/skills/skills/theme-factory/LICENSE.txt +0 -202
  540. package/skills/skills/theme-factory/SKILL.md +0 -59
  541. package/skills/skills/theme-factory/theme-showcase.pdf +0 -0
  542. package/skills/skills/theme-factory/themes/arctic-frost.md +0 -19
  543. package/skills/skills/theme-factory/themes/botanical-garden.md +0 -19
  544. package/skills/skills/theme-factory/themes/desert-rose.md +0 -19
  545. package/skills/skills/theme-factory/themes/forest-canopy.md +0 -19
  546. package/skills/skills/theme-factory/themes/golden-hour.md +0 -19
  547. package/skills/skills/theme-factory/themes/midnight-galaxy.md +0 -19
  548. package/skills/skills/theme-factory/themes/modern-minimalist.md +0 -19
  549. package/skills/skills/theme-factory/themes/ocean-depths.md +0 -19
  550. package/skills/skills/theme-factory/themes/sunset-boulevard.md +0 -19
  551. package/skills/skills/theme-factory/themes/tech-innovation.md +0 -19
  552. package/skills/skills/web-artifacts-builder/LICENSE.txt +0 -202
  553. package/skills/skills/web-artifacts-builder/SKILL.md +0 -74
  554. package/skills/skills/web-artifacts-builder/scripts/bundle-artifact.sh +0 -54
  555. package/skills/skills/web-artifacts-builder/scripts/init-artifact.sh +0 -322
  556. package/skills/skills/webapp-testing/LICENSE.txt +0 -202
  557. package/skills/skills/webapp-testing/SKILL.md +0 -96
  558. package/skills/skills/webapp-testing/examples/console_logging.py +0 -35
  559. package/skills/skills/webapp-testing/examples/element_discovery.py +0 -40
  560. package/skills/skills/webapp-testing/examples/static_html_automation.py +0 -33
  561. package/skills/skills/webapp-testing/scripts/with_server.py +0 -106
  562. package/skills/skills/xlsx/LICENSE.txt +0 -30
  563. package/skills/skills/xlsx/SKILL.md +0 -289
  564. package/skills/skills/xlsx/recalc.py +0 -178
  565. package/skills/spec/agent-skills-spec.md +0 -3
  566. package/skills/template/SKILL.md +0 -6
  567. package/src/ai-client.ts +0 -1560
  568. package/src/remote-ai-client.ts +0 -664
package/dist/session.js CHANGED
@@ -5,11 +5,18 @@ import axios from 'axios';
5
5
  import crypto from 'crypto';
6
6
  import ora from 'ora';
7
7
  import { createRequire } from 'module';
8
+ import path from 'path';
9
+ import { fileURLToPath } from 'url';
10
+ import fs from 'fs';
11
+ import fsPromises from 'fs/promises';
12
+ import os from 'os';
8
13
  const require = createRequire(import.meta.url);
9
14
  const packageJson = require('../package.json');
10
- import { ExecutionMode, AuthType } from './types.js';
11
- import { AIClient, detectThinkingKeywords, getThinkingTokens } from './ai-client.js';
12
- import { RemoteAIClient, TokenInvalidError } from './remote-ai-client.js';
15
+ import { ExecutionMode, AuthType, } from './types.js';
16
+ import { createAIClient } from './ai-client-factory.js';
17
+ import { detectThinkingKeywords, getThinkingTokens } from './ai-client/types.js';
18
+ import { TokenInvalidError } from './ai-client/types.js';
19
+ import { fetchDefaultModels } from './ai-client/providers/remote.js';
13
20
  import { getConfigManager } from './config.js';
14
21
  import { AuthService, selectAuthType } from './auth.js';
15
22
  import { getToolRegistry } from './tools.js';
@@ -21,10 +28,11 @@ import { getConversationManager } from './conversation.js';
21
28
  import { getSessionManager } from './session-manager.js';
22
29
  import { SlashCommandHandler, parseInput } from './slash-commands.js';
23
30
  import { SystemPromptGenerator } from './system-prompt-generator.js';
24
- import { theme, icons, colors, styleHelpers, renderMarkdown, renderDiff, renderLines } from './theme.js';
31
+ import { theme, icons, colors, styleHelpers, renderMarkdown, renderDiff, renderLines, } from './theme.js';
25
32
  import { getCancellationManager } from './cancellation.js';
26
- import { getContextCompressor } from './context-compressor.js';
33
+ import { getContextCompressor, } from './context-compressor.js';
27
34
  import { getLogger } from './logger.js';
35
+ import { ensureTtySane, setupEscKeyHandler } from './terminal.js';
28
36
  const logger = getLogger();
29
37
  export class InteractiveSession {
30
38
  conversationManager;
@@ -33,7 +41,7 @@ export class InteractiveSession {
33
41
  aiClient = null;
34
42
  remoteAIClient = null;
35
43
  conversation = [];
36
- toolCalls = [];
44
+ tool_calls = [];
37
45
  executionMode;
38
46
  slashCommandHandler;
39
47
  configManager;
@@ -53,7 +61,7 @@ export class InteractiveSession {
53
61
  constructor(indentLevel = 0) {
54
62
  this.rl = readline.createInterface({
55
63
  input: process.stdin,
56
- output: process.stdout
64
+ output: process.stdout,
57
65
  });
58
66
  this.configManager = getConfigManager(process.cwd());
59
67
  this.agentManager = getAgentManager(process.cwd());
@@ -66,7 +74,7 @@ export class InteractiveSession {
66
74
  // Register /clear callback, clear local conversation when clearing dialogue
67
75
  this.slashCommandHandler.setClearCallback(() => {
68
76
  this.conversation = [];
69
- this.toolCalls = [];
77
+ this.tool_calls = [];
70
78
  this.currentTaskId = null;
71
79
  this.taskCompleted = false;
72
80
  this.isFirstApiCall = true;
@@ -76,6 +84,10 @@ export class InteractiveSession {
76
84
  this.slashCommandHandler.setSystemPromptUpdateCallback(async () => {
77
85
  await this.updateSystemPrompt();
78
86
  });
87
+ // Register config update callback, update aiClient config when /auth changes config
88
+ this.slashCommandHandler.setConfigUpdateCallback(() => {
89
+ this.updateAiClientConfig();
90
+ });
79
91
  this.executionMode = ExecutionMode.DEFAULT;
80
92
  this.cancellationManager = getCancellationManager();
81
93
  this.indentLevel = indentLevel;
@@ -88,6 +100,32 @@ export class InteractiveSession {
88
100
  setAIClient(aiClient) {
89
101
  this.aiClient = aiClient;
90
102
  }
103
+ /**
104
+ * Update aiClient config when /auth changes config (called from callback)
105
+ */
106
+ updateAiClientConfig() {
107
+ const authConfig = this.configManager.getAuthConfig();
108
+ const isRemote = authConfig.type === AuthType.OAUTH_XAGENT;
109
+ if (isRemote) {
110
+ // Already in remote mode, no change needed
111
+ if (this.remoteAIClient !== null) {
112
+ return;
113
+ }
114
+ // Switch to remote: clear local client, create remote client
115
+ this.aiClient = null;
116
+ this.remoteAIClient = createAIClient(authConfig);
117
+ }
118
+ else {
119
+ // Already in local mode, no change needed
120
+ if (this.aiClient !== null) {
121
+ return;
122
+ }
123
+ // Switch to local: clear remote client, create local client
124
+ this.remoteAIClient = null;
125
+ this.aiClient = createAIClient(authConfig);
126
+ }
127
+ this.slashCommandHandler.setRemoteAIClient(this.remoteAIClient);
128
+ }
91
129
  setExecutionMode(mode) {
92
130
  this.executionMode = mode;
93
131
  }
@@ -95,25 +133,68 @@ export class InteractiveSession {
95
133
  * Update system prompt to reflect MCP changes (called after add/remove MCP)
96
134
  */
97
135
  async updateSystemPrompt() {
136
+ // Reload skills to pick up any newly added/removed skills
137
+ // First reset the SkillLoader to clear all cached skills
138
+ const { resetSkillLoader } = await import('./skill-loader.js');
139
+ resetSkillLoader();
140
+ // Then reload the skill invoker
141
+ const skillInvoker = (await import('./skill-invoker.js')).getSkillInvoker();
142
+ await skillInvoker.reload();
98
143
  const toolRegistry = getToolRegistry();
99
144
  const promptGenerator = new SystemPromptGenerator(toolRegistry, this.executionMode, undefined, this.mcpManager);
100
145
  // Use the current agent's original system prompt as base
101
146
  const baseSystemPrompt = this.currentAgent?.systemPrompt || 'You are xAgent, an AI-powered CLI tool.';
102
147
  const newSystemPrompt = await promptGenerator.generateEnhancedSystemPrompt(baseSystemPrompt);
103
148
  // Replace old system prompt with new one
104
- this.conversation = this.conversation.filter(msg => msg.role !== 'system');
149
+ this.conversation = this.conversation.filter((msg) => msg.role !== 'system');
105
150
  this.conversation.unshift({
106
151
  role: 'system',
107
152
  content: newSystemPrompt,
108
- timestamp: Date.now()
153
+ timestamp: Date.now(),
109
154
  });
110
155
  // Sync to slashCommandHandler
111
156
  this.slashCommandHandler.setConversationHistory(this.conversation);
112
157
  }
158
+ /**
159
+ * Watch for skill updates from CLI and update system prompt accordingly
160
+ */
161
+ startSkillUpdateWatcher() {
162
+ const SKILL_STATE_FILE = '.skill-state.json';
163
+ const configManager = getConfigManager();
164
+ const userSkillsPath = configManager.getUserSkillsPath();
165
+ const stateFilePath = userSkillsPath
166
+ ? path.join(userSkillsPath, SKILL_STATE_FILE)
167
+ : null;
168
+ if (!stateFilePath) {
169
+ return; // No user skills path configured
170
+ }
171
+ let lastUpdateTime = 0;
172
+ // Check for updates every 2 seconds
173
+ const checkInterval = setInterval(async () => {
174
+ try {
175
+ const { existsSync, readFileSync } = await import('fs');
176
+ if (existsSync(stateFilePath)) {
177
+ const content = readFileSync(stateFilePath, 'utf-8');
178
+ const state = JSON.parse(content);
179
+ if (state.lastSkillUpdate && state.lastSkillUpdate > lastUpdateTime) {
180
+ lastUpdateTime = state.lastSkillUpdate;
181
+ // Update system prompt with new skills
182
+ await this.updateSystemPrompt();
183
+ console.log(colors.textMuted(' 🔄 Skills updated from CLI'));
184
+ }
185
+ }
186
+ }
187
+ catch (error) {
188
+ // Silent fail - watcher is optional
189
+ }
190
+ }, 2000);
191
+ // Clean up on session end
192
+ this._skillWatcherInterval = checkInterval;
193
+ }
113
194
  setAgent(agent) {
114
195
  this.currentAgent = agent;
115
196
  }
116
- async start() {
197
+ async start(initializedCount = 0) {
117
198
  // Set this session as the singleton for access from other modules
118
199
  setSingletonSession(this);
119
200
  // Initialize taskId for GUI operations
@@ -122,25 +203,43 @@ export class InteractiveSession {
122
203
  console.log('');
123
204
  console.log(colors.gradient('╔════════════════════════════════════════════════════════════╗'));
124
205
  console.log(colors.gradient('║') + ' '.repeat(58) + colors.gradient(' ║'));
125
- console.log(colors.gradient('║') + ' '.repeat(13) + '🤖 ' + colors.gradient('XAGENT CLI') + ' '.repeat(32) + colors.gradient(' ║'));
126
- console.log(colors.gradient('║') + ' '.repeat(16) + colors.textMuted(`v${packageJson.version}`) + ' '.repeat(36) + colors.gradient(' ║'));
206
+ console.log(colors.gradient('║') +
207
+ ' '.repeat(13) +
208
+ '🤖 ' +
209
+ colors.gradient('XAGENT CLI') +
210
+ ' '.repeat(32) +
211
+ colors.gradient(' ║'));
212
+ console.log(colors.gradient('║') +
213
+ ' '.repeat(16) +
214
+ colors.textMuted(`v${packageJson.version}`) +
215
+ ' '.repeat(36) +
216
+ colors.gradient(' ║'));
127
217
  console.log(colors.gradient('║') + ' '.repeat(58) + colors.gradient(' ║'));
128
218
  console.log(colors.gradient('╚════════════════════════════════════════════════════════════╝'));
129
219
  console.log(colors.textMuted(' AI-powered command-line assistant'));
220
+ // Show initialization message if skills were initialized
221
+ if (initializedCount > 0) {
222
+ console.log(colors.textMuted(` ✨ Initialized ${initializedCount} built-in skills`));
223
+ }
130
224
  console.log('');
131
225
  await this.initialize();
132
226
  this.showWelcomeMessage();
227
+ // Start watching for skill updates from CLI
228
+ this.startSkillUpdateWatcher();
229
+ // Set up ESC key handler using the terminal module
230
+ // This avoids conflicts with readline and provides clean ESC detection
231
+ let escCleanup;
232
+ if (process.stdin.isTTY) {
233
+ escCleanup = setupEscKeyHandler(() => {
234
+ if (this._isOperationInProgress) {
235
+ // An operation is running, let it be cancelled
236
+ this.cancellationManager.cancel();
237
+ }
238
+ // No operation running, ignore ESC
239
+ });
240
+ }
133
241
  // Track if an operation is in progress
134
242
  this._isOperationInProgress = false;
135
- // Listen for ESC cancellation - only cancel operations, don't exit the program
136
- const cancelHandler = () => {
137
- if (this._isOperationInProgress) {
138
- // An operation is running, let it be cancelled
139
- return;
140
- }
141
- // No operation running, ignore ESC or show a message
142
- };
143
- this.cancellationManager.on('cancelled', cancelHandler);
144
243
  this.promptLoop();
145
244
  // Keep the promise pending until shutdown
146
245
  return new Promise((resolve) => {
@@ -159,7 +258,7 @@ export class InteractiveSession {
159
258
  frameIndex = (frameIndex + 1) % frames.length;
160
259
  }, 120);
161
260
  logger.debug('[SESSION] 调用 configManager.load()...');
162
- await this.configManager.load();
261
+ this.configManager.load();
163
262
  logger.debug('[SESSION] Config loaded');
164
263
  let authConfig = this.configManager.getAuthConfig();
165
264
  let selectedAuthType = this.configManager.get('selectedAuthType');
@@ -186,9 +285,8 @@ export class InteractiveSession {
186
285
  clearInterval(refreshInterval);
187
286
  process.stdout.write('\r' + ' '.repeat(50) + '\r');
188
287
  if (newToken) {
189
- // Save new token and persist
190
- await this.configManager.set('apiKey', newToken);
191
- await this.configManager.save('global');
288
+ this.configManager.set('apiKey', newToken);
289
+ this.configManager.save('global');
192
290
  authConfig.apiKey = newToken;
193
291
  isValid = true;
194
292
  }
@@ -198,20 +296,18 @@ export class InteractiveSession {
198
296
  console.log(colors.warning('Your xAgent session has expired or is not configured'));
199
297
  console.log(colors.info('Please select an authentication method to continue.'));
200
298
  console.log('');
201
- // Clear invalid credentials and persist
202
- // Note: Do NOT overwrite selectedAuthType - let user re-select their preferred auth method
203
- await this.configManager.set('apiKey', '');
204
- await this.configManager.set('refreshToken', '');
205
- await this.configManager.save('global');
206
- await this.configManager.load();
299
+ this.configManager.set('apiKey', '');
300
+ this.configManager.set('refreshToken', '');
301
+ this.configManager.save('global');
302
+ this.configManager.load();
207
303
  authConfig = this.configManager.getAuthConfig();
208
304
  await this.setupAuthentication();
209
305
  authConfig = this.configManager.getAuthConfig();
210
- // Recreate readline interface after inquirer
306
+ // Recreate readline interface after interactive prompt
211
307
  this.rl.close();
212
308
  this.rl = readline.createInterface({
213
309
  input: process.stdin,
214
- output: process.stdout
310
+ output: process.stdout,
215
311
  });
216
312
  this.rl.on('close', () => {
217
313
  // readline closed
@@ -226,11 +322,11 @@ export class InteractiveSession {
226
322
  authConfig = this.configManager.getAuthConfig();
227
323
  selectedAuthType = this.configManager.get('selectedAuthType');
228
324
  logger.debug('[SESSION] selectedAuthType (after setup):', String(selectedAuthType));
229
- // Recreate readline interface after inquirer
325
+ // Recreate readline interface after interactive prompt
230
326
  this.rl.close();
231
327
  this.rl = readline.createInterface({
232
328
  input: process.stdin,
233
- output: process.stdout
329
+ output: process.stdout,
234
330
  });
235
331
  this.rl.on('close', () => {
236
332
  // readline closed
@@ -241,21 +337,42 @@ export class InteractiveSession {
241
337
  process.stdout.write('\r' + ' '.repeat(50) + '\r');
242
338
  }
243
339
  // For OPENAI_COMPATIBLE with API key, skip validation and proceed directly
244
- this.aiClient = new AIClient(authConfig);
245
- this.contextCompressor.setAIClient(this.aiClient);
246
- // Initialize remote AI client for OAuth XAGENT mode
247
- logger.debug('[SESSION] Final selectedAuthType:', String(selectedAuthType));
248
- logger.debug('[SESSION] Creating RemoteAIClient?', String(selectedAuthType === AuthType.OAUTH_XAGENT));
340
+ // Initialize AI clients and set contextCompressor appropriately
249
341
  if (selectedAuthType === AuthType.OAUTH_XAGENT) {
250
- const webBaseUrl = authConfig.xagentApiBaseUrl || 'https://www.xagent-colife.net';
251
- // In OAuth XAGENT mode, we still pass apiKey (can be empty or used for other purposes)
252
- this.remoteAIClient = new RemoteAIClient(authConfig.apiKey || '', webBaseUrl, authConfig.showAIDebugInfo);
342
+ // Remote mode: fetch default models if not set
343
+ const currentLlm = this.configManager.get('remote_llmModelName');
344
+ const currentVlm = this.configManager.get('remote_vlmModelName');
345
+ if (!currentLlm || !currentVlm) {
346
+ const webBaseUrl = authConfig.xagentApiBaseUrl || 'https://www.xagent-colife.net';
347
+ try {
348
+ const defaults = await fetchDefaultModels(authConfig.apiKey || '', webBaseUrl);
349
+ if (!currentLlm && defaults.llm?.name) {
350
+ this.configManager.set('remote_llmModelName', defaults.llm.name);
351
+ }
352
+ if (!currentVlm && defaults.vlm?.name) {
353
+ this.configManager.set('remote_vlmModelName', defaults.vlm.name);
354
+ }
355
+ this.configManager.save('global');
356
+ }
357
+ catch (error) {
358
+ logger.debug('[SESSION] Failed to fetch default models:', error.message);
359
+ }
360
+ }
361
+ // Remote mode: create RemoteAIClient and use it for context compression
362
+ this.remoteAIClient = createAIClient(authConfig);
363
+ this.contextCompressor.setAIClient(this.remoteAIClient);
253
364
  logger.debug('[DEBUG Initialize] RemoteAIClient created successfully');
254
365
  }
255
366
  else {
367
+ // Local mode: create local AIClient
368
+ this.aiClient = createAIClient(authConfig);
369
+ this.contextCompressor.setAIClient(this.aiClient);
256
370
  logger.debug('[DEBUG Initialize] RemoteAIClient NOT created (not OAuth XAGENT mode)');
257
371
  }
258
- this.executionMode = this.configManager.getApprovalMode() || this.configManager.getExecutionMode();
372
+ // Sync remoteAIClient reference to slashCommandHandler for /provider command
373
+ this.slashCommandHandler.setRemoteAIClient(this.remoteAIClient);
374
+ this.executionMode =
375
+ this.configManager.getApprovalMode() || this.configManager.getExecutionMode();
259
376
  await this.agentManager.loadAgents();
260
377
  await this.memoryManager.loadMemory();
261
378
  await this.conversationManager.initialize();
@@ -292,7 +409,7 @@ export class InteractiveSession {
292
409
  this.checkpointManager = getCheckpointManager(process.cwd(), checkpointingConfig.enabled, checkpointingConfig.maxCheckpoints);
293
410
  await this.checkpointManager.initialize();
294
411
  }
295
- this.currentAgent = this.agentManager.getAgent('general-purpose');
412
+ this.currentAgent = this.agentManager.getAgent('general-purpose') ?? null;
296
413
  console.log(colors.success('✔ Initialization complete'));
297
414
  }
298
415
  catch (error) {
@@ -315,11 +432,11 @@ export class InteractiveSession {
315
432
  logger.debug('[SESSION] Sending validation request to:', url);
316
433
  const response = await axios.get(url, {
317
434
  headers: {
318
- 'Authorization': `Bearer ${apiKey}`,
319
- 'Content-Type': 'application/json'
435
+ Authorization: `Bearer ${apiKey}`,
436
+ 'Content-Type': 'application/json',
320
437
  },
321
438
  httpsAgent,
322
- timeout: 10000
439
+ timeout: 10000,
323
440
  });
324
441
  logger.debug('[SESSION] Validation response status:', String(response.status));
325
442
  return response.status === 200;
@@ -341,7 +458,7 @@ export class InteractiveSession {
341
458
  const httpsAgent = new https.Agent({ rejectUnauthorized: false });
342
459
  const response = await axios.post(url, { refreshToken }, {
343
460
  httpsAgent,
344
- timeout: 10000
461
+ timeout: 10000,
345
462
  });
346
463
  if (response.status === 200) {
347
464
  const data = response.data;
@@ -363,11 +480,14 @@ export class InteractiveSession {
363
480
  console.log('');
364
481
  const authType = await selectAuthType();
365
482
  this.configManager.set('selectedAuthType', authType);
483
+ // Get xagentApiBaseUrl from config (respects XAGENT_BASE_URL env var)
484
+ const config = this.configManager.getAuthConfig();
366
485
  const authService = new AuthService({
367
486
  type: authType,
368
487
  apiKey: '',
369
488
  baseUrl: '',
370
- modelName: ''
489
+ modelName: '',
490
+ xagentApiBaseUrl: config.xagentApiBaseUrl,
371
491
  });
372
492
  const success = await authService.authenticate();
373
493
  if (!success) {
@@ -377,16 +497,29 @@ export class InteractiveSession {
377
497
  process.exit(1);
378
498
  }
379
499
  const authConfig = authService.getAuthConfig();
500
+ // Clear modelName for remote mode
501
+ if (authType === AuthType.OAUTH_XAGENT) {
502
+ authConfig.modelName = '';
503
+ }
380
504
  // VLM configuration is optional - only show for non-OAuth (local) mode
381
505
  // Remote mode uses backend VLM configuration
382
506
  if (authType !== AuthType.OAUTH_XAGENT) {
383
507
  console.log('');
384
508
  console.log(colors.info(`${icons.info} VLM configuration is optional.`));
385
- console.log(colors.info(`You can configure it later using the /vlm command if needed.`));
509
+ console.log(colors.info(`You can configure it later using the /model command if needed.`));
386
510
  console.log('');
387
511
  }
388
- // Save LLM config only, skip VLM for now
389
- await this.configManager.setAuthConfig(authConfig);
512
+ this.configManager.setAuthConfig(authConfig);
513
+ // Set default remote model settings if not already set
514
+ if (authType === AuthType.OAUTH_XAGENT) {
515
+ if (!this.configManager.get('remote_llmModelName')) {
516
+ this.configManager.set('remote_llmModelName', '');
517
+ }
518
+ if (!this.configManager.get('remote_vlmModelName')) {
519
+ this.configManager.set('remote_vlmModelName', '');
520
+ }
521
+ this.configManager.save('global');
522
+ }
390
523
  }
391
524
  showWelcomeMessage() {
392
525
  const language = this.configManager.getLanguage();
@@ -410,28 +543,28 @@ export class InteractiveSession {
410
543
  [ExecutionMode.YOLO]: {
411
544
  color: colors.error,
412
545
  icon: icons.fire,
413
- description: 'Execute commands without confirmation'
546
+ description: 'Execute commands without confirmation',
414
547
  },
415
548
  [ExecutionMode.ACCEPT_EDITS]: {
416
549
  color: colors.warning,
417
550
  icon: icons.check,
418
- description: 'Accept all edits automatically'
551
+ description: 'Accept all edits automatically',
419
552
  },
420
553
  [ExecutionMode.PLAN]: {
421
554
  color: colors.info,
422
555
  icon: icons.brain,
423
- description: 'Plan before executing'
556
+ description: 'Plan before executing',
424
557
  },
425
558
  [ExecutionMode.DEFAULT]: {
426
559
  color: colors.success,
427
560
  icon: icons.bolt,
428
- description: 'Safe execution with confirmations'
561
+ description: 'Safe execution with confirmations',
429
562
  },
430
563
  [ExecutionMode.SMART]: {
431
564
  color: colors.primaryBright,
432
565
  icon: icons.sparkles,
433
- description: 'Smart approval with intelligent security checks'
434
- }
566
+ description: 'Smart approval with intelligent security checks',
567
+ },
435
568
  };
436
569
  const config = modeConfig[this.executionMode];
437
570
  const modeName = this.executionMode;
@@ -439,6 +572,26 @@ export class InteractiveSession {
439
572
  console.log(` ${config.color(config.icon)} ${styleHelpers.text.bold(config.color(modeName))}`);
440
573
  console.log(` ${colors.textDim(` ${config.description}`)}`);
441
574
  console.log('');
575
+ this.showRemoteModelInfo();
576
+ }
577
+ showRemoteModelInfo() {
578
+ const authConfig = this.configManager.getAuthConfig();
579
+ const isRemote = authConfig.type === AuthType.OAUTH_XAGENT;
580
+ if (isRemote) {
581
+ const llmModel = authConfig.remote_llmModelName || colors.textMuted('Not set');
582
+ const vlmModel = authConfig.remote_vlmModelName || colors.textMuted('Not set');
583
+ console.log(colors.textMuted(`${icons.brain} Remote Models:`));
584
+ console.log(` ${colors.primaryBright(icons.arrowRight)} ${colors.info('LLM:')} ${llmModel}`);
585
+ console.log(` ${colors.primaryBright(icons.arrowRight)} ${colors.info('VLM:')} ${vlmModel}`);
586
+ }
587
+ else {
588
+ const modelName = authConfig.modelName || colors.textMuted('Not set');
589
+ const guiSubagentModel = this.configManager.get('guiSubagentModel') || colors.textMuted('Not set');
590
+ console.log(colors.textMuted(`${icons.brain} Local Models:`));
591
+ console.log(` ${colors.primaryBright(icons.arrowRight)} ${colors.info('LLM:')} ${modelName}`);
592
+ console.log(` ${colors.primaryBright(icons.arrowRight)} ${colors.info('VLM:')} ${guiSubagentModel}`);
593
+ }
594
+ console.log('');
442
595
  }
443
596
  async promptLoop() {
444
597
  // Check if we're shutting down
@@ -449,15 +602,12 @@ export class InteractiveSession {
449
602
  if (this.rl) {
450
603
  this.rl.close();
451
604
  }
452
- // Enable raw mode BEFORE emitKeypressEvents for better ESC detection
453
- if (process.stdin.isTTY) {
454
- process.stdin.setRawMode(true);
455
- }
456
- process.stdin.resume();
457
- readline.emitKeypressEvents(process.stdin);
605
+ // Ensure TTY is in proper state for input handling
606
+ // This handles any state left by @clack/prompts or other interactions
607
+ ensureTtySane();
458
608
  this.rl = readline.createInterface({
459
609
  input: process.stdin,
460
- output: process.stdout
610
+ output: process.stdout,
461
611
  });
462
612
  const prompt = `${colors.primaryBright('❯')} `;
463
613
  this.rl.question(prompt, async (input) => {
@@ -481,7 +631,8 @@ export class InteractiveSession {
481
631
  if (trimmedInput.startsWith('/')) {
482
632
  const handled = await this.slashCommandHandler.handleCommand(trimmedInput);
483
633
  if (handled) {
484
- this.executionMode = this.configManager.getApprovalMode() || this.configManager.getExecutionMode();
634
+ this.executionMode =
635
+ this.configManager.getApprovalMode() || this.configManager.getExecutionMode();
485
636
  // Sync conversation history to slashCommandHandler
486
637
  this.slashCommandHandler.setConversationHistory(this.conversation);
487
638
  }
@@ -513,9 +664,9 @@ export class InteractiveSession {
513
664
  }
514
665
  async processUserMessage(message, agent) {
515
666
  const inputs = parseInput(message);
516
- const textInput = inputs.find(i => i.type === 'text');
517
- const fileInputs = inputs.filter(i => i.type === 'file');
518
- const commandInput = inputs.find(i => i.type === 'command');
667
+ const textInput = inputs.find((i) => i.type === 'text');
668
+ const fileInputs = inputs.filter((i) => i.type === 'file');
669
+ const commandInput = inputs.find((i) => i.type === 'command');
519
670
  if (commandInput) {
520
671
  await this.executeShellCommand(commandInput.content);
521
672
  return;
@@ -538,7 +689,7 @@ export class InteractiveSession {
538
689
  type: 'text',
539
690
  content: userContent,
540
691
  rawInput: message,
541
- timestamp: Date.now()
692
+ timestamp: Date.now(),
542
693
  };
543
694
  await this.sessionManager.addInput(sessionInput);
544
695
  // Calculate thinking tokens based on config and user input
@@ -552,25 +703,19 @@ export class InteractiveSession {
552
703
  const userMessage = {
553
704
  role: 'user',
554
705
  content: userContent,
555
- timestamp: Date.now()
706
+ timestamp: Date.now(),
556
707
  };
557
- // Save last user message for recovery after compression
558
- const lastUserMessage = userMessage;
559
708
  this.conversation.push(userMessage);
560
709
  await this.conversationManager.addMessage(userMessage);
561
- // Check if context compression is needed
562
- await this.checkAndCompressContext(lastUserMessage);
563
710
  // Use remote AI client if available (OAuth XAGENT mode)
564
711
  const currentSelectedAuthType = this.configManager.get('selectedAuthType');
565
- logger.debug('[DEBUG processUserMessage] remoteAIClient exists:', !!this.remoteAIClient ? 'true' : 'false');
566
- logger.debug('[DEBUG processUserMessage] selectedAuthType:', String(currentSelectedAuthType));
567
- logger.debug('[DEBUG processUserMessage] AuthType.OAUTH_XAGENT:', String(AuthType.OAUTH_XAGENT));
712
+ logger.debug(`[DEBUG] processUserMessage: remoteAIClient exists=${!!this.remoteAIClient}, selectedAuthType=${currentSelectedAuthType}`);
568
713
  if (this.remoteAIClient) {
569
- logger.debug('[DEBUG processUserMessage] Using generateRemoteResponse');
714
+ logger.debug('[DEBUG] Using generateRemoteResponse (remote mode)');
570
715
  await this.generateRemoteResponse(thinkingTokens);
571
716
  }
572
717
  else {
573
- logger.debug('[DEBUG processUserMessage] Using generateResponse (local mode)');
718
+ logger.debug('[DEBUG] Using generateResponse (local mode)');
574
719
  await this.generateResponse(thinkingTokens);
575
720
  }
576
721
  }
@@ -615,52 +760,68 @@ export class InteractiveSession {
615
760
  /**
616
761
  * Check and compress conversation context
617
762
  */
618
- async checkAndCompressContext(lastUserMessage) {
763
+ async checkAndCompressContext() {
619
764
  const compressionConfig = this.configManager.getContextCompressionConfig();
620
765
  if (!compressionConfig.enabled) {
621
766
  return;
622
767
  }
623
- const { needsCompression, reason } = this.contextCompressor.needsCompression(this.conversation, compressionConfig);
624
- if (needsCompression) {
625
- const indent = this.getIndent();
626
- console.log('');
627
- console.log(`${indent}${colors.warning(`${icons.brain} Context compression triggered: ${reason}`)}`);
628
- const toolRegistry = getToolRegistry();
629
- const baseSystemPrompt = this.currentAgent?.systemPrompt || 'You are a helpful AI assistant.';
630
- const systemPromptGenerator = new SystemPromptGenerator(toolRegistry, this.executionMode);
631
- const enhancedSystemPrompt = await systemPromptGenerator.generateEnhancedSystemPrompt(baseSystemPrompt);
632
- const result = await this.contextCompressor.compressContext(this.conversation, enhancedSystemPrompt, compressionConfig);
633
- if (result.wasCompressed) {
634
- this.conversation = result.compressedMessages;
635
- // console.log(`${indent}${colors.success(`✓ Compressed ${result.originalMessageCount} messages to ${result.compressedMessageCount} messages`)}`);
636
- console.log(`${indent}${colors.textMuted(`✓ Size: ${result.originalSize} ${result.compressedSize} chars (${Math.round((1 - result.compressedSize / result.originalSize) * 100)}% reduction)`)}`);
637
- // Display compressed summary content
638
- const summaryMessage = result.compressedMessages.find(m => m.role === 'assistant');
639
- if (summaryMessage && summaryMessage.content) {
640
- const maxPreviewLength = 800;
641
- let summaryContent = summaryMessage.content;
642
- const isTruncated = summaryContent.length > maxPreviewLength;
643
- if (isTruncated) {
644
- summaryContent = summaryContent.substring(0, maxPreviewLength) + '\n...';
645
- }
646
- console.log('');
647
- console.log(`${indent}${theme.predefinedStyles.title(`${icons.sparkles} Conversation Summary`)}`);
648
- const separator = icons.separator.repeat(Math.min(60, process.stdout.columns || 80) - indent.length * 2);
649
- console.log(`${indent}${colors.border(separator)}`);
650
- const renderedSummary = renderMarkdown(summaryContent, (process.stdout.columns || 80) - indent.length * 4);
651
- console.log(`${indent}${theme.predefinedStyles.dim(renderedSummary).replace(/^/gm, indent)}`);
652
- if (isTruncated) {
653
- console.log(`${indent}${colors.textMuted(`(... ${summaryMessage.content.length - maxPreviewLength} more chars hidden)`)}`);
654
- }
655
- console.log(`${indent}${colors.border(separator)}`);
768
+ const indent = this.getIndent();
769
+ const currentTokens = this.contextCompressor.estimateContextTokens(this.conversation);
770
+ const currentMessages = this.conversation.length;
771
+ const { needsCompression, reason, tokenCount } = this.contextCompressor.needsCompression(this.conversation, compressionConfig);
772
+ if (!needsCompression) {
773
+ return;
774
+ }
775
+ // Extract threshold and contextWindow from reason
776
+ const thresholdMatch = reason.match(/budget\s*\((\d+)/);
777
+ const contextWindowMatch = reason.match(/contextWindow:\s*(\d+)/);
778
+ const threshold = thresholdMatch ? parseInt(thresholdMatch[1], 10) : 0;
779
+ const contextWindow = contextWindowMatch ? parseInt(contextWindowMatch[1], 10) : 0;
780
+ console.log('');
781
+ console.log(`${indent}${colors.success(`${icons.sparkles} Compressing context (${currentMessages} msgs, ${tokenCount.toLocaleString()} > ${threshold.toLocaleString()}/${contextWindow.toLocaleString()} tokens, ${Math.round((tokenCount / contextWindow) * 100)}% of context window)...`)}`);
782
+ const toolRegistry = getToolRegistry();
783
+ const baseSystemPrompt = this.currentAgent?.systemPrompt || 'You are a helpful AI assistant.';
784
+ const systemPromptGenerator = new SystemPromptGenerator(toolRegistry, this.executionMode);
785
+ const enhancedSystemPrompt = await systemPromptGenerator.generateEnhancedSystemPrompt(baseSystemPrompt);
786
+ const result = await this.contextCompressor.compressContext(this.conversation, enhancedSystemPrompt, compressionConfig);
787
+ if (result.wasCompressed) {
788
+ this.conversation = result.compressedMessages;
789
+ const reductionPercent = Math.round((1 - result.compressedSize / result.originalSize) * 100);
790
+ console.log(`${indent}${colors.success(`${icons.success} Compressed ${result.originalMessageCount} → ${result.compressedMessageCount} messages (${reductionPercent}% smaller)`)}`);
791
+ // Summary is embedded in first user message, look for it
792
+ // The format is: "[Conversation Summary - X messages compressed]\n\n${summary}"
793
+ let summaryMessage = result.compressedMessages.find((m) => m.role === 'user' && m.content.includes('[Conversation Summary'));
794
+ if (summaryMessage) {
795
+ // Extract summary content after the header
796
+ const match = summaryMessage.content.match(/\[Conversation Summary.*?\]:\n\n(.+)/s);
797
+ if (match) {
798
+ summaryMessage = {
799
+ role: 'assistant',
800
+ content: match[1],
801
+ timestamp: summaryMessage.timestamp,
802
+ };
656
803
  }
657
- // Restore user messages after compression, ensuring user message exists for API calls
658
- if (lastUserMessage) {
659
- this.conversation.push(lastUserMessage);
804
+ }
805
+ if (summaryMessage && summaryMessage.content) {
806
+ const maxPreviewLength = 800;
807
+ let summaryContent = summaryMessage.content;
808
+ const isTruncated = summaryContent.length > maxPreviewLength;
809
+ if (isTruncated) {
810
+ summaryContent = summaryContent.substring(0, maxPreviewLength) + '\n...';
660
811
  }
661
- // Sync compressed conversation history to slashCommandHandler
662
- this.slashCommandHandler.setConversationHistory(this.conversation);
812
+ console.log('');
813
+ console.log(`${indent}${theme.predefinedStyles.title(`${icons.sparkles} Conversation Summary`)}`);
814
+ const separator = icons.separator.repeat(Math.min(60, process.stdout.columns || 80) - indent.length * 2);
815
+ console.log(`${indent}${colors.border(separator)}`);
816
+ const renderedSummary = renderMarkdown(summaryContent, (process.stdout.columns || 80) - indent.length * 4);
817
+ console.log(`${indent}${theme.predefinedStyles.dim(renderedSummary).replace(/^/gm, indent)}`);
818
+ if (isTruncated) {
819
+ console.log(`${indent}${colors.textMuted(`(... ${summaryMessage.content.length - maxPreviewLength} more chars hidden)`)}`);
820
+ }
821
+ console.log(`${indent}${colors.border(separator)}`);
663
822
  }
823
+ // Sync compressed conversation history to slashCommandHandler
824
+ this.slashCommandHandler.setConversationHistory(this.conversation);
664
825
  }
665
826
  }
666
827
  async executeShellCommand(command) {
@@ -683,15 +844,15 @@ export class InteractiveSession {
683
844
  tool: 'Bash',
684
845
  params: { command },
685
846
  result,
686
- timestamp: Date.now()
847
+ timestamp: Date.now(),
687
848
  };
688
- this.toolCalls.push(toolCall);
849
+ this.tool_calls.push(toolCall);
689
850
  // Record command execution to session manager
690
851
  await this.sessionManager.addInput({
691
852
  type: 'command',
692
853
  content: command,
693
854
  rawInput: command,
694
- timestamp: Date.now()
855
+ timestamp: Date.now(),
695
856
  });
696
857
  await this.sessionManager.addOutput({
697
858
  role: 'tool',
@@ -699,7 +860,7 @@ export class InteractiveSession {
699
860
  toolName: 'Bash',
700
861
  toolParams: { command },
701
862
  toolResult: result,
702
- timestamp: Date.now()
863
+ timestamp: Date.now(),
703
864
  });
704
865
  }
705
866
  catch (error) {
@@ -727,8 +888,19 @@ export class InteractiveSession {
727
888
  createRemoteCaller(taskId, status) {
728
889
  const client = this.remoteAIClient;
729
890
  return {
730
- chatCompletion: (messages, options) => client.chatCompletion(messages, { ...options, taskId, status }),
731
- isRemote: true
891
+ chatCompletion: (messages, options) => {
892
+ // Must fetch authConfig inside the closure, otherwise it captures stale config
893
+ const authConfig = this.configManager.getAuthConfig();
894
+ logger.debug(`[DEBUG] createRemoteCaller: llmModelName=${authConfig.remote_llmModelName}, vlmModelName=${authConfig.remote_vlmModelName}`);
895
+ return client.chatCompletion(messages, {
896
+ ...options,
897
+ taskId,
898
+ status: options.isFirstApiCall ? 'begin' : 'continue',
899
+ llmModelName: authConfig.remote_llmModelName,
900
+ vlmModelName: authConfig.remote_vlmModelName
901
+ });
902
+ },
903
+ isRemote: true,
732
904
  };
733
905
  }
734
906
  /**
@@ -738,32 +910,22 @@ export class InteractiveSession {
738
910
  const client = this.aiClient;
739
911
  return {
740
912
  chatCompletion: (messages, options) => client.chatCompletion(messages, options),
741
- isRemote: false
913
+ isRemote: false,
742
914
  };
743
915
  }
744
- async generateResponse(thinkingTokens = 0, customAIClient, existingTaskId) {
916
+ async generateResponse(thinkingTokens = 0, _customAIClient, existingTaskId) {
745
917
  // Use existing taskId or create new one for this user interaction
746
918
  // If taskId already exists (e.g., from tool calls), reuse it
747
919
  const taskId = existingTaskId || this.currentTaskId || crypto.randomUUID();
748
920
  this.currentTaskId = taskId;
749
- this.isFirstApiCall = true;
750
- // Determine status based on whether this is the first API call
921
+ // isFirstApiCall is reset in generateRemoteResponse for new tasks
922
+ // For continuation calls (existingTaskId provided), keep previous value
923
+ // Use unified LLM Caller with taskId (automatically selects local or remote mode)
751
924
  const status = this.isFirstApiCall ? 'begin' : 'continue';
752
- // Use custom AI client if provided, otherwise use default logic
753
- let chatCompletion;
754
- let isRemote = false;
755
- if (customAIClient) {
756
- // Custom client (used by remote mode) - pass taskId and status
757
- chatCompletion = (messages, options) => customAIClient.chatCompletion(messages, { ...options, taskId, status });
758
- isRemote = true;
759
- }
760
- else {
761
- // Use unified LLM Caller with taskId (automatically selects local or remote mode)
762
- const caller = this.createLLMCaller(taskId, status);
763
- chatCompletion = caller.chatCompletion;
764
- isRemote = caller.isRemote;
765
- }
766
- if (!isRemote && !this.aiClient && !customAIClient) {
925
+ const caller = this.createLLMCaller(taskId, status);
926
+ const chatCompletion = caller.chatCompletion;
927
+ const isRemote = caller.isRemote;
928
+ if (!isRemote && !this.aiClient) {
767
929
  console.log(colors.error('AI client not initialized'));
768
930
  return;
769
931
  }
@@ -790,29 +952,29 @@ export class InteractiveSession {
790
952
  const toolDefinitions = toolRegistry.getToolDefinitions();
791
953
  // Available tools for this session
792
954
  const availableTools = this.executionMode !== ExecutionMode.DEFAULT && allowedToolNames.length > 0
793
- ? toolDefinitions.filter((tool) => allowedToolNames.includes(tool.function.name))
955
+ ? toolDefinitions.filter((tool) => typeof tool.function?.name === 'string' &&
956
+ allowedToolNames.includes(tool.function.name))
794
957
  : toolDefinitions;
795
- const baseSystemPrompt = this.currentAgent?.systemPrompt;
958
+ const baseSystemPrompt = this.currentAgent?.systemPrompt ?? '';
796
959
  const systemPromptGenerator = new SystemPromptGenerator(toolRegistry, this.executionMode, undefined, this.mcpManager);
797
960
  const enhancedSystemPrompt = await systemPromptGenerator.generateEnhancedSystemPrompt(baseSystemPrompt);
798
961
  const messages = [
799
962
  { role: 'system', content: `${enhancedSystemPrompt}\n\n${memory}`, timestamp: Date.now() },
800
- ...this.conversation
963
+ ...this.conversation,
801
964
  ];
802
965
  const operationId = `ai-response-${Date.now()}`;
803
966
  const response = await this.cancellationManager.withCancellation(chatCompletion(messages, {
804
967
  tools: availableTools,
805
968
  toolChoice: availableTools.length > 0 ? 'auto' : 'none',
806
- thinkingTokens
969
+ thinkingTokens,
970
+ isFirstApiCall: this.isFirstApiCall,
807
971
  }), operationId);
808
972
  // Mark that first API call is complete
809
973
  this.isFirstApiCall = false;
810
974
  clearInterval(spinnerInterval);
811
975
  process.stdout.write('\r' + ' '.repeat(process.stdout.columns || 80) + '\r'); // Clear spinner line
812
976
  const assistantMessage = response.choices[0].message;
813
- const content = typeof assistantMessage.content === 'string'
814
- ? assistantMessage.content
815
- : '';
977
+ const content = typeof assistantMessage.content === 'string' ? assistantMessage.content : '';
816
978
  const reasoningContent = assistantMessage.reasoning_content || '';
817
979
  // Display reasoning content if available and thinking mode is enabled
818
980
  if (reasoningContent && this.configManager.getThinkingConfig().enabled) {
@@ -829,22 +991,25 @@ export class InteractiveSession {
829
991
  role: 'assistant',
830
992
  content,
831
993
  timestamp: Date.now(),
832
- reasoningContent,
833
- toolCalls: assistantMessage.tool_calls
994
+ reasoning_content: reasoningContent,
995
+ tool_calls: assistantMessage.tool_calls,
834
996
  });
835
997
  // Record output to session manager
836
998
  await this.sessionManager.addOutput({
837
999
  role: 'assistant',
838
1000
  content,
839
1001
  timestamp: Date.now(),
840
- reasoningContent,
841
- toolCalls: assistantMessage.tool_calls
1002
+ reasoning_content: reasoningContent,
1003
+ tool_calls: assistantMessage.tool_calls,
842
1004
  });
843
1005
  if (assistantMessage.tool_calls) {
844
1006
  await this.handleToolCalls(assistantMessage.tool_calls);
845
1007
  }
1008
+ else {
1009
+ await this.checkAndCompressContext();
1010
+ }
846
1011
  if (this.checkpointManager.isEnabled()) {
847
- await this.checkpointManager.createCheckpoint(`Response generated at ${new Date().toLocaleString()}`, [...this.conversation], [...this.toolCalls]);
1012
+ await this.checkpointManager.createCheckpoint(`Response generated at ${new Date().toLocaleString()}`, [...this.conversation], [...this.tool_calls]);
848
1013
  }
849
1014
  // Operation completed successfully, clear the flag
850
1015
  this._isOperationInProgress = false;
@@ -855,16 +1020,18 @@ export class InteractiveSession {
855
1020
  // Clear the operation flag
856
1021
  this._isOperationInProgress = false;
857
1022
  if (error.message === 'Operation cancelled by user') {
858
- // Mark task as cancelled
1023
+ // Notify backend to cancel the task
859
1024
  if (this.remoteAIClient && this.currentTaskId) {
860
- await this.remoteAIClient.cancelTask(this.currentTaskId).catch(() => { });
1025
+ await this.remoteAIClient.cancelTask?.(this.currentTaskId).catch(() => { });
861
1026
  }
862
1027
  return;
863
1028
  }
864
- // Mark task as cancelled when error occurs (发送 status: 'cancel')
865
- logger.debug(`[Session] Task failed: taskId=${this.currentTaskId}, error: ${error.message}`);
1029
+ // Distinguish error types: timeout vs other failures
1030
+ const isTimeout = error.message.includes('timeout') || error.message.includes('Timeout');
1031
+ const failureReason = isTimeout ? 'timeout' : 'failure';
1032
+ logger.debug(`[Session] Task failed: taskId=${this.currentTaskId}, error: ${error.message}, reason: ${failureReason}`);
866
1033
  if (this.remoteAIClient && this.currentTaskId) {
867
- await this.remoteAIClient.cancelTask(this.currentTaskId).catch(() => { });
1034
+ await this.remoteAIClient.failTask?.(this.currentTaskId, failureReason).catch(() => { });
868
1035
  }
869
1036
  console.log(colors.error(`Error: ${error.message}`));
870
1037
  }
@@ -881,12 +1048,10 @@ export class InteractiveSession {
881
1048
  const taskId = existingTaskId || crypto.randomUUID();
882
1049
  this.currentTaskId = taskId;
883
1050
  logger.debug(`[Session] generateRemoteResponse: taskId=${taskId}, existingTaskId=${!!existingTaskId}`);
884
- // Reset isFirstApiCall for new task, keep true for continuation
885
- if (!existingTaskId) {
886
- this.isFirstApiCall = true;
887
- }
888
- // Determine status based on whether this is the first API call
889
- const status = this.isFirstApiCall ? 'begin' : 'continue';
1051
+ // Each new user message is a fresh task - always set isFirstApiCall = true
1052
+ // This ensures status is 'begin' for every user message
1053
+ this.isFirstApiCall = true;
1054
+ const status = 'begin';
890
1055
  logger.debug(`[Session] Status for this call: ${status}, isFirstApiCall=${this.isFirstApiCall}`);
891
1056
  // Check if remote client is available
892
1057
  if (!this.remoteAIClient) {
@@ -894,18 +1059,23 @@ export class InteractiveSession {
894
1059
  return;
895
1060
  }
896
1061
  try {
897
- // Reuse generateResponse with remote client, pass taskId to avoid generating new one
898
- await this.generateResponse(thinkingTokens, this.remoteAIClient, taskId);
1062
+ // Use unified generateResponse without passing customAIClient,
1063
+ // let createLLMCaller handle remote/local selection
1064
+ await this.generateResponse(thinkingTokens, undefined, taskId);
899
1065
  // Mark task as completed (发送 status: 'end')
900
1066
  logger.debug(`[Session] Task completed: taskId=${this.currentTaskId}`);
901
- if (this.currentTaskId) {
902
- await this.remoteAIClient.completeTask(this.currentTaskId);
1067
+ if (this.remoteAIClient && this.currentTaskId) {
1068
+ await this.remoteAIClient.completeTask?.(this.currentTaskId);
903
1069
  }
904
1070
  }
905
1071
  catch (error) {
906
1072
  // Clear the operation flag
907
1073
  this._isOperationInProgress = false;
908
1074
  if (error.message === 'Operation cancelled by user') {
1075
+ // Notify backend to cancel the task
1076
+ if (this.remoteAIClient && this.currentTaskId) {
1077
+ await this.remoteAIClient.cancelTask?.(this.currentTaskId).catch(() => { });
1078
+ }
909
1079
  return;
910
1080
  }
911
1081
  // Handle token invalid error - trigger re-authentication
@@ -915,46 +1085,48 @@ export class InteractiveSession {
915
1085
  console.log(colors.info('Your browser session has been logged out. Please log in again.'));
916
1086
  console.log('');
917
1087
  // Clear invalid credentials and persist
918
- await this.configManager.set('apiKey', '');
919
- await this.configManager.set('refreshToken', '');
920
- await this.configManager.save('global');
1088
+ this.configManager.set('apiKey', '');
1089
+ this.configManager.set('refreshToken', '');
1090
+ this.configManager.save('global');
921
1091
  logger.debug('[DEBUG generateRemoteResponse] Cleared invalid credentials, starting re-authentication...');
922
1092
  // Re-authenticate
923
1093
  await this.setupAuthentication();
924
1094
  // Reload config to ensure we have the latest authConfig
925
- logger.debug('[DEBUG generateRemoteResponse] Re-authentication completed, reloading config...');
926
- await this.configManager.load();
1095
+ this.configManager.load();
927
1096
  const authConfig = this.configManager.getAuthConfig();
928
1097
  logger.debug('[DEBUG generateRemoteResponse] After re-auth:');
929
1098
  logger.debug(' - authConfig.apiKey exists:', !!authConfig.apiKey ? 'true' : 'false');
930
- // Recreate readline interface after inquirer
1099
+ // Recreate readline interface after interactive prompt
931
1100
  this.rl.close();
932
1101
  this.rl = readline.createInterface({
933
1102
  input: process.stdin,
934
- output: process.stdout
1103
+ output: process.stdout,
935
1104
  });
936
1105
  this.rl.on('close', () => {
937
1106
  logger.debug('DEBUG: readline interface closed');
938
1107
  });
939
1108
  // Reinitialize RemoteAIClient with new token
940
1109
  if (authConfig.apiKey) {
941
- const webBaseUrl = authConfig.xagentApiBaseUrl || 'https://www.xagent-colife.net';
942
1110
  logger.debug('[DEBUG generateRemoteResponse] Reinitializing RemoteAIClient with new token');
943
- this.remoteAIClient = new RemoteAIClient(authConfig.apiKey, webBaseUrl, authConfig.showAIDebugInfo);
1111
+ this.remoteAIClient = createAIClient(authConfig);
944
1112
  }
945
1113
  else {
946
1114
  logger.debug('[DEBUG generateRemoteResponse] WARNING: No apiKey after re-authentication!');
947
1115
  }
1116
+ // Sync remoteAIClient reference to slashCommandHandler for /provider command
1117
+ this.slashCommandHandler.setRemoteAIClient(this.remoteAIClient);
948
1118
  // Retry the current operation
949
1119
  console.log('');
950
1120
  console.log(colors.info('Retrying with new authentication...'));
951
1121
  console.log('');
952
1122
  return this.generateRemoteResponse(thinkingTokens);
953
1123
  }
954
- // Mark task as cancelled when error occurs (发送 status: 'cancel')
955
- logger.debug(`[Session] Task failed: taskId=${this.currentTaskId}, error: ${error.message}`);
1124
+ // Distinguish error types: timeout vs other failures
1125
+ const isTimeout = error.message.includes('timeout') || error.message.includes('Timeout');
1126
+ const failureReason = isTimeout ? 'timeout' : 'failure';
1127
+ logger.debug(`[Session] Task failed: taskId=${this.currentTaskId}, error: ${error.message}, reason: ${failureReason}`);
956
1128
  if (this.remoteAIClient && this.currentTaskId) {
957
- await this.remoteAIClient.cancelTask(this.currentTaskId).catch(() => { });
1129
+ await this.remoteAIClient.failTask?.(this.currentTaskId, failureReason).catch(() => { });
958
1130
  }
959
1131
  console.log(colors.error(`Error: ${error.message}`));
960
1132
  return;
@@ -991,32 +1163,50 @@ export class InteractiveSession {
991
1163
  }
992
1164
  }
993
1165
  // Execute all tools in parallel
994
- const results = await toolRegistry.executeAll(preparedToolCalls.map(tc => ({ name: tc.name, params: tc.params })), this.executionMode);
995
- // Process results and maintain order
1166
+ const results = await toolRegistry.executeAll(preparedToolCalls.map((tc) => ({ name: tc.name, params: tc.params })), this.executionMode);
1167
+ // Create a map to store results by tool call index to maintain original order
1168
+ const resultsByIndex = new Map();
1169
+ const usedIndices = new Set();
1170
+ for (const result of results) {
1171
+ // Find the first unused original index in preparedToolCalls that matches the tool name
1172
+ const originalIndex = preparedToolCalls.findIndex((tc, idx) => tc.name === result.tool && !usedIndices.has(idx));
1173
+ if (originalIndex !== -1) {
1174
+ usedIndices.add(originalIndex);
1175
+ resultsByIndex.set(originalIndex, result);
1176
+ }
1177
+ }
1178
+ // Process results in the original tool_calls order (critical for Anthropic format APIs)
996
1179
  let hasError = false;
997
- for (const { tool, result, error } of results) {
998
- const toolCall = preparedToolCalls.find(tc => tc.name === tool);
999
- if (!toolCall)
1000
- continue;
1001
- const { params } = toolCall;
1180
+ for (let i = 0; i < preparedToolCalls.length; i++) {
1181
+ const toolCall = preparedToolCalls[i];
1182
+ const { name: tool, params } = toolCall;
1183
+ const resultData = resultsByIndex.get(i);
1184
+ const result = resultData?.result;
1185
+ const error = resultData?.error;
1002
1186
  if (error) {
1003
1187
  if (error === 'Operation cancelled by user') {
1188
+ // Notify backend to cancel the task
1189
+ if (this.remoteAIClient && this.currentTaskId) {
1190
+ await this.remoteAIClient.cancelTask?.(this.currentTaskId).catch(() => { });
1191
+ }
1192
+ // 清理 conversation 中未完成的 tool_call
1193
+ this.cleanupIncompleteToolCalls();
1004
1194
  this._isOperationInProgress = false;
1005
1195
  return;
1006
1196
  }
1007
1197
  hasError = true;
1008
1198
  console.log('');
1009
1199
  console.log(`${indent}${colors.error(`${icons.cross} Tool Error: ${tool} - ${error}`)}`);
1010
- // 添加详细的错误信息,包含工具名称和参数,便于 AI 理解和修正
1200
+ // Add detailed error info including tool name and params for AI understanding and correction
1011
1201
  this.conversation.push({
1012
1202
  role: 'tool',
1013
1203
  content: JSON.stringify({
1014
1204
  name: tool,
1015
1205
  parameters: params,
1016
- error: error
1206
+ error: error,
1017
1207
  }),
1018
1208
  tool_call_id: toolCall.id,
1019
- timestamp: Date.now()
1209
+ timestamp: Date.now(),
1020
1210
  });
1021
1211
  }
1022
1212
  else {
@@ -1054,7 +1244,10 @@ export class InteractiveSession {
1054
1244
  // Show edit result with diff
1055
1245
  console.log('');
1056
1246
  const diffOutput = renderDiff(result.diff);
1057
- const indentedDiff = diffOutput.split('\n').map(line => `${displayIndent} ${line}`).join('\n');
1247
+ const indentedDiff = diffOutput
1248
+ .split('\n')
1249
+ .map((line) => `${displayIndent} ${line}`)
1250
+ .join('\n');
1058
1251
  console.log(`${indentedDiff}`);
1059
1252
  }
1060
1253
  else if (hasFilePreview) {
@@ -1074,7 +1267,8 @@ export class InteractiveSession {
1074
1267
  // Special handling for task tool (subagent) - show friendly summary
1075
1268
  console.log('');
1076
1269
  const subagentType = params.subagent_type;
1077
- const subagentName = params.description || (params.prompt ? params.prompt.substring(0, 50).replace(/\n/g, ' ') : 'Unknown task');
1270
+ const subagentName = params.description ||
1271
+ (params.prompt ? params.prompt.substring(0, 50).replace(/\n/g, ' ') : 'Unknown task');
1078
1272
  if (result?.success) {
1079
1273
  console.log(`${displayIndent}${colors.success(`${icons.check} ${subagentType}: Completed`)}`);
1080
1274
  console.log(`${displayIndent}${colors.textDim(` Task: ${subagentName}`)}`);
@@ -1192,7 +1386,10 @@ export class InteractiveSession {
1192
1386
  const resultPreview = typeof result === 'string' ? result : JSON.stringify(result, null, 2);
1193
1387
  const truncatedPreview = resultPreview.length > 200 ? resultPreview.substring(0, 200) + '...' : resultPreview;
1194
1388
  // Indent the preview
1195
- const indentedPreview = truncatedPreview.split('\n').map(line => `${displayIndent} ${line}`).join('\n');
1389
+ const indentedPreview = truncatedPreview
1390
+ .split('\n')
1391
+ .map((line) => `${displayIndent} ${line}`)
1392
+ .join('\n');
1196
1393
  console.log(`${indentedPreview}`);
1197
1394
  }
1198
1395
  else {
@@ -1202,9 +1399,9 @@ export class InteractiveSession {
1202
1399
  tool,
1203
1400
  params,
1204
1401
  result,
1205
- timestamp: Date.now()
1402
+ timestamp: Date.now(),
1206
1403
  };
1207
- this.toolCalls.push(toolCallRecord);
1404
+ this.tool_calls.push(toolCallRecord);
1208
1405
  // Record tool output to session manager
1209
1406
  await this.sessionManager.addOutput({
1210
1407
  role: 'tool',
@@ -1212,77 +1409,104 @@ export class InteractiveSession {
1212
1409
  toolName: tool,
1213
1410
  toolParams: params,
1214
1411
  toolResult: result,
1215
- timestamp: Date.now()
1412
+ timestamp: Date.now(),
1216
1413
  });
1217
- // 统一消息格式,包含工具名称和参数
1414
+ // Unified message format with tool name and params
1415
+ // Format: OpenAI-compatible tool result with plain text content
1218
1416
  this.conversation.push({
1219
1417
  role: 'tool',
1220
- content: JSON.stringify({
1221
- name: tool,
1222
- parameters: params,
1223
- result: result
1224
- }),
1418
+ content: typeof result === 'string' ? result : JSON.stringify(result, null, 2),
1225
1419
  tool_call_id: toolCall.id,
1226
- timestamp: Date.now()
1420
+ timestamp: Date.now(),
1227
1421
  });
1228
1422
  }
1229
1423
  }
1230
1424
  // Logic: Only skip returning results to main agent when user explicitly cancelled (ESC)
1231
1425
  // For all other cases (success, failure, errors), always return results for further processing
1232
- const guiSubagentCancelled = preparedToolCalls.some(tc => tc.name === 'task' && tc.params?.subagent_type === 'gui-subagent' && results.some(r => r.tool === 'task' && r.result?.cancelled === true));
1426
+ const guiSubagentCancelled = preparedToolCalls.some((tc) => tc.name === 'task' &&
1427
+ tc.params?.subagent_type === 'gui-subagent' &&
1428
+ results.some((r) => r.tool === 'task' && r.result?.cancelled === true));
1233
1429
  // If GUI agent was cancelled by user, don't continue generating response
1234
1430
  // This avoids wasting API calls and tokens on cancelled tasks
1235
1431
  if (guiSubagentCancelled) {
1236
- console.log('');
1237
- console.log(`${indent}${colors.textMuted('GUI task cancelled by user')}`);
1238
1432
  this._isOperationInProgress = false;
1239
1433
  return;
1240
1434
  }
1241
- // Handle errors and completion based on whether onComplete callback is provided
1242
- if (hasError) {
1243
- this._isOperationInProgress = false;
1244
- // 不再抛出异常,而是将错误结果返回给 AI,让 AI 决定如何处理
1245
- // 这样可以避免工具错误导致程序退出
1246
- }
1247
- // Continue based on mode - 统一处理,无论是否有错误
1435
+ // Continue based on mode - unified handling for both success and error cases
1248
1436
  if (onComplete) {
1437
+ await this.checkAndCompressContext();
1249
1438
  // Remote mode: use provided callback
1250
1439
  await onComplete();
1251
1440
  }
1252
1441
  else {
1442
+ await this.checkAndCompressContext();
1253
1443
  // Local mode: default behavior - continue with generateResponse
1254
1444
  await this.generateResponse();
1255
1445
  }
1256
1446
  }
1447
+ /**
1448
+ * Clean up incomplete tool calls from conversation after cancellation
1449
+ * This removes assistant messages with tool_calls that don't have corresponding tool_results
1450
+ */
1451
+ async cleanupIncompleteToolCalls() {
1452
+ // 从后往前找到包含 tool_calls 的 assistant 消息
1453
+ for (let i = this.conversation.length - 1; i >= 0; i--) {
1454
+ const msg = this.conversation[i];
1455
+ if (msg.role === 'assistant' && msg.tool_calls?.length) {
1456
+ // 收集所有 tool_call IDs
1457
+ const allToolCallIds = new Set(msg.tool_calls.map((tc) => tc.id));
1458
+ // 找出哪些 tool_call IDs 已经有对应的 tool_result
1459
+ const completedToolCallIds = new Set();
1460
+ for (let k = i + 1; k < this.conversation.length; k++) {
1461
+ const resultMsg = this.conversation[k];
1462
+ if (resultMsg.role === 'tool' && resultMsg.tool_call_id) {
1463
+ completedToolCallIds.add(resultMsg.tool_call_id);
1464
+ }
1465
+ else if (resultMsg.role === 'user' || resultMsg.role === 'assistant') {
1466
+ break; // 遇到下一个角色消息就停止
1467
+ }
1468
+ }
1469
+ // 找出未完成的 tool_call IDs
1470
+ const incompleteToolCallIds = [...allToolCallIds].filter(id => !completedToolCallIds.has(id));
1471
+ // 如果所有 tool_call 都已完成,不需要清理
1472
+ if (incompleteToolCallIds.length === 0) {
1473
+ break;
1474
+ }
1475
+ // 只移除未完成的 tool_call,不移除已完成的 tool_result
1476
+ msg.tool_calls = msg.tool_calls.filter((tc) => !incompleteToolCallIds.includes(tc.id));
1477
+ break;
1478
+ }
1479
+ }
1480
+ }
1257
1481
  /**
1258
1482
  * Get user-friendly description for tool
1259
1483
  */
1260
1484
  getToolDescription(toolName, params) {
1261
1485
  const descriptions = {
1262
- 'Read': (p) => `Read file: ${this.truncatePath(p.filePath)}`,
1263
- 'Write': (p) => `Write file: ${this.truncatePath(p.filePath)}`,
1264
- 'Grep': (p) => `Search text: "${p.pattern}"`,
1265
- 'Bash': (p) => `Execute command: ${this.truncateCommand(p.command)}`,
1266
- 'ListDirectory': (p) => `List directory: ${this.truncatePath(p.path || '.')}`,
1267
- 'SearchFiles': (p) => `Search files: ${p.pattern}`,
1268
- 'DeleteFile': (p) => `Delete file: ${this.truncatePath(p.filePath)}`,
1269
- 'CreateDirectory': (p) => `Create directory: ${this.truncatePath(p.dirPath)}`,
1270
- 'Edit': (p) => `Edit text: ${this.truncatePath(p.file_path)}`,
1271
- 'web_search': (p) => `Web search: "${p.query}"`,
1272
- 'todo_write': () => `Update todo list`,
1273
- 'todo_read': () => `Read todo list`,
1274
- 'task': (p) => `Launch subtask: ${p.description}`,
1275
- 'ReadBashOutput': (p) => `Read task output: ${p.task_id}`,
1276
- 'web_fetch': () => `Fetch web content`,
1277
- 'ask_user_question': () => `Ask user`,
1278
- 'save_memory': () => `Save memory`,
1279
- 'exit_plan_mode': () => `Complete plan`,
1280
- 'xml_escape': (p) => `XML escape: ${this.truncatePath(p.file_path)}`,
1281
- 'image_read': (p) => `Read image: ${this.truncatePath(p.image_input)}`,
1486
+ Read: (p) => `Read file: ${this.truncatePath(p.filePath)}`,
1487
+ Write: (p) => `Write file: ${this.truncatePath(p.filePath)}`,
1488
+ Grep: (p) => `Search text: "${p.pattern}"`,
1489
+ Bash: (p) => `Execute command: ${this.truncateCommand(p.command)}`,
1490
+ ListDirectory: (p) => `List directory: ${this.truncatePath(p.path || '.')}`,
1491
+ SearchFiles: (p) => `Search files: ${p.pattern}`,
1492
+ DeleteFile: (p) => `Delete file: ${this.truncatePath(p.filePath)}`,
1493
+ CreateDirectory: (p) => `Create directory: ${this.truncatePath(p.dirPath)}`,
1494
+ Edit: (p) => `Edit text: ${this.truncatePath(p.file_path)}`,
1495
+ web_search: (p) => `Web search: "${p.query}"`,
1496
+ todo_write: () => `Update todo list`,
1497
+ todo_read: () => `Read todo list`,
1498
+ task: (p) => `Launch subtask: ${p.description}`,
1499
+ ReadBashOutput: (p) => `Read task output: ${p.task_id}`,
1500
+ web_fetch: () => `Fetch web content`,
1501
+ ask_user_question: () => `Ask user`,
1502
+ save_memory: () => `Save memory`,
1503
+ exit_plan_mode: () => `Complete plan`,
1504
+ xml_escape: (p) => `XML escape: ${this.truncatePath(p.file_path)}`,
1505
+ image_read: (p) => `Read image: ${this.truncatePath(p.image_input)}`,
1282
1506
  // 'Skill': (p) => `Execute skill: ${p.skill}`,
1283
1507
  // 'ListSkills': () => `List available skills`,
1284
1508
  // 'GetSkillDetails': (p) => `Get skill details: ${p.skill}`,
1285
- 'InvokeSkill': (p) => `Invoke skill: ${p.skillId} - ${this.truncatePath(p.taskDescription || '', 40)}`
1509
+ InvokeSkill: (p) => `Invoke skill: ${p.skillId} - ${this.truncatePath(p.taskDescription || '', 40)}`,
1286
1510
  };
1287
1511
  const getDescription = descriptions[toolName];
1288
1512
  return getDescription ? getDescription(params) : `Execute tool: ${toolName}`;
@@ -1315,10 +1539,10 @@ export class InteractiveSession {
1315
1539
  return `${indent}${colors.textMuted('No tasks')}`;
1316
1540
  }
1317
1541
  const statusConfig = {
1318
- 'pending': { icon: icons.circle, color: colors.textMuted, label: 'Pending' },
1319
- 'in_progress': { icon: icons.loading, color: colors.warning, label: 'In Progress' },
1320
- 'completed': { icon: icons.success, color: colors.success, label: 'Completed' },
1321
- 'failed': { icon: icons.error, color: colors.error, label: 'Failed' }
1542
+ pending: { icon: icons.circle, color: colors.textMuted, label: 'Pending' },
1543
+ in_progress: { icon: icons.loading, color: colors.warning, label: 'In Progress' },
1544
+ completed: { icon: icons.success, color: colors.success, label: 'Completed' },
1545
+ failed: { icon: icons.error, color: colors.error, label: 'Failed' },
1322
1546
  };
1323
1547
  const lines = [];
1324
1548
  for (const todo of todos) {
@@ -1431,7 +1655,155 @@ export class InteractiveSession {
1431
1655
  return this.currentTaskId;
1432
1656
  }
1433
1657
  }
1658
+ /**
1659
+ * Clean up stale temporary workspaces from previous sessions.
1660
+ * Called at startup to ensure no leftover temp files accumulate.
1661
+ */
1662
+ async function cleanupStaleWorkspaces() {
1663
+ try {
1664
+ const configManager = getConfigManager();
1665
+ const workspacePath = configManager.getWorkspacePath();
1666
+ // Use default workspace path if workspacePath is empty or undefined
1667
+ const effectiveWorkspacePath = (workspacePath && workspacePath.trim())
1668
+ ? workspacePath
1669
+ : os.homedir();
1670
+ const baseWorkspaceDir = path.join(effectiveWorkspacePath, '.xagent', 'workspace');
1671
+ // First, verify the workspace directory exists before attempting cleanup
1672
+ try {
1673
+ const stats = await fsPromises.stat(baseWorkspaceDir);
1674
+ if (!stats.isDirectory()) {
1675
+ return; // Not a directory, skip cleanup
1676
+ }
1677
+ }
1678
+ catch {
1679
+ // Directory doesn't exist - nothing to clean
1680
+ return;
1681
+ }
1682
+ try {
1683
+ const entries = await fsPromises.readdir(baseWorkspaceDir, { withFileTypes: true });
1684
+ let cleanedCount = 0;
1685
+ for (const entry of entries) {
1686
+ if (entry.isDirectory()) {
1687
+ const fullPath = path.join(baseWorkspaceDir, entry.name);
1688
+ try {
1689
+ await fsPromises.rm(fullPath, { recursive: true, force: true });
1690
+ cleanedCount++;
1691
+ }
1692
+ catch {
1693
+ // Skip directories that can't be removed (in use or permission issues)
1694
+ }
1695
+ }
1696
+ }
1697
+ if (cleanedCount > 0) {
1698
+ console.log(colors.textDim(`🧹 Cleaned up ${cleanedCount} stale workspace(s)`));
1699
+ }
1700
+ }
1701
+ catch {
1702
+ // Can't read directory - skip cleanup
1703
+ }
1704
+ }
1705
+ catch {
1706
+ // Config not available - skip cleanup
1707
+ }
1708
+ }
1709
+ /**
1710
+ * Initialize built-in skills on first run.
1711
+ * Checks if user skills directory is empty or doesn't exist,
1712
+ * then copies all built-in skills including the protected find-skills.
1713
+ * @returns Number of skills initialized, or 0 if no initialization was needed.
1714
+ */
1715
+ async function initializeSkillsOnDemand() {
1716
+ const __filename = fileURLToPath(import.meta.url);
1717
+ const __dirname = path.dirname(__filename);
1718
+ // Get user skills directory (respects OS-specific paths)
1719
+ const configManager = getConfigManager();
1720
+ const userSkillsPath = configManager.getUserSkillsPath() || path.join(os.homedir(), '.xagent', 'skills');
1721
+ // Check if user skills directory exists and has skills
1722
+ let hasSkills = false;
1723
+ try {
1724
+ const entries = await fsPromises.readdir(userSkillsPath, { withFileTypes: true });
1725
+ hasSkills = entries.some(e => e.isDirectory());
1726
+ }
1727
+ catch {
1728
+ hasSkills = false;
1729
+ }
1730
+ // If skills already exist, skip initialization
1731
+ if (hasSkills) {
1732
+ return 0;
1733
+ }
1734
+ // Ensure user skills directory exists
1735
+ await fsPromises.mkdir(userSkillsPath, { recursive: true });
1736
+ // Define skill source directories
1737
+ const builtinSkillsDir = path.join(__dirname, '..', 'skills', 'skills');
1738
+ const findSkillsDir = path.join(__dirname, '..', 'find-skills');
1739
+ const skillsToInstall = [];
1740
+ // Add find-skills from root directory
1741
+ if (fs.existsSync(findSkillsDir) && fs.existsSync(path.join(findSkillsDir, 'SKILL.md'))) {
1742
+ skillsToInstall.push({ source: findSkillsDir, name: 'find-skills' });
1743
+ }
1744
+ // Add skills from skills/skills directory
1745
+ if (fs.existsSync(builtinSkillsDir)) {
1746
+ const entries = fs.readdirSync(builtinSkillsDir, { withFileTypes: true });
1747
+ for (const entry of entries) {
1748
+ if (entry.isDirectory()) {
1749
+ const skillPath = path.join(builtinSkillsDir, entry.name);
1750
+ if (fs.existsSync(path.join(skillPath, 'SKILL.md'))) {
1751
+ skillsToInstall.push({ source: skillPath, name: entry.name });
1752
+ }
1753
+ }
1754
+ }
1755
+ }
1756
+ if (skillsToInstall.length === 0) {
1757
+ return 0;
1758
+ }
1759
+ // Create user skills directory (already done above, but ensure it exists)
1760
+ await fsPromises.mkdir(userSkillsPath, { recursive: true });
1761
+ // Copy all skills
1762
+ for (const { source, name } of skillsToInstall) {
1763
+ const destPath = path.join(userSkillsPath, name);
1764
+ if (!fs.existsSync(destPath)) {
1765
+ await copyDirectoryRecursiveAsync(source, destPath);
1766
+ }
1767
+ }
1768
+ return skillsToInstall.length;
1769
+ }
1770
+ // Synchronous version (kept for backwards compatibility)
1771
+ function copyDirectoryRecursive(src, dest) {
1772
+ if (!fs.existsSync(dest)) {
1773
+ fs.mkdirSync(dest, { recursive: true });
1774
+ }
1775
+ const entries = fs.readdirSync(src, { withFileTypes: true });
1776
+ for (const entry of entries) {
1777
+ const srcPath = path.join(src, entry.name);
1778
+ const destPath = path.join(dest, entry.name);
1779
+ if (entry.isDirectory()) {
1780
+ copyDirectoryRecursive(srcPath, destPath);
1781
+ }
1782
+ else if (entry.isFile()) {
1783
+ fs.copyFileSync(srcPath, destPath);
1784
+ }
1785
+ }
1786
+ }
1787
+ // Asynchronous version for concurrent-safe initialization
1788
+ async function copyDirectoryRecursiveAsync(src, dest) {
1789
+ await fsPromises.mkdir(dest, { recursive: true });
1790
+ const entries = await fsPromises.readdir(src, { withFileTypes: true });
1791
+ for (const entry of entries) {
1792
+ const srcPath = path.join(src, entry.name);
1793
+ const destPath = path.join(dest, entry.name);
1794
+ if (entry.isDirectory()) {
1795
+ await copyDirectoryRecursiveAsync(srcPath, destPath);
1796
+ }
1797
+ else if (entry.isFile()) {
1798
+ await fsPromises.copyFile(srcPath, destPath);
1799
+ }
1800
+ }
1801
+ }
1434
1802
  export async function startInteractiveSession() {
1803
+ // Clean up any leftover temp workspaces from previous sessions
1804
+ await cleanupStaleWorkspaces();
1805
+ // Initialize built-in skills on first run (silent, returns count)
1806
+ const initializedCount = await initializeSkillsOnDemand();
1435
1807
  const session = new InteractiveSession();
1436
1808
  // Flag to control shutdown
1437
1809
  session._isShuttingDown = false;
@@ -1467,6 +1839,15 @@ export async function startInteractiveSession() {
1467
1839
  // Force exit
1468
1840
  process.exit(0);
1469
1841
  });
1842
+ await session.start(initializedCount);
1843
+ // Check for updates on startup
1844
+ try {
1845
+ const { checkUpdatesOnStartup } = await import('./update.js');
1846
+ await checkUpdatesOnStartup();
1847
+ }
1848
+ catch (error) {
1849
+ // Silently ignore update check failures
1850
+ }
1470
1851
  await session.start();
1471
1852
  }
1472
1853
  // Singleton session instance for access from other modules