@xagent-ai/cli 1.2.2 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (602) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.md +38 -38
  2. package/.github/ISSUE_TEMPLATE/feature_request.md +20 -20
  3. package/.github/release.yml +76 -0
  4. package/.github/workflows/ci.yml +75 -0
  5. package/.github/workflows/release.yml +103 -0
  6. package/.gitmodules +3 -3
  7. package/README.md +326 -280
  8. package/README_CN.md +325 -279
  9. package/dist/agents.d.ts.map +1 -1
  10. package/dist/agents.js +7 -3
  11. package/dist/agents.js.map +1 -1
  12. package/dist/ai-client/factory.d.ts +40 -0
  13. package/dist/ai-client/factory.d.ts.map +1 -0
  14. package/dist/ai-client/factory.js +100 -0
  15. package/dist/ai-client/factory.js.map +1 -0
  16. package/dist/ai-client/index.d.ts +20 -0
  17. package/dist/ai-client/index.d.ts.map +1 -0
  18. package/dist/ai-client/index.js +49 -0
  19. package/dist/ai-client/index.js.map +1 -0
  20. package/dist/ai-client/providers/anthropic.d.ts +57 -0
  21. package/dist/ai-client/providers/anthropic.d.ts.map +1 -0
  22. package/dist/ai-client/providers/anthropic.js +406 -0
  23. package/dist/ai-client/providers/anthropic.js.map +1 -0
  24. package/dist/ai-client/providers/openai.d.ts +57 -0
  25. package/dist/ai-client/providers/openai.d.ts.map +1 -0
  26. package/dist/ai-client/providers/openai.js +290 -0
  27. package/dist/ai-client/providers/openai.js.map +1 -0
  28. package/dist/ai-client/providers/remote.d.ts +110 -0
  29. package/dist/ai-client/providers/remote.d.ts.map +1 -0
  30. package/dist/ai-client/providers/remote.js +352 -0
  31. package/dist/ai-client/providers/remote.js.map +1 -0
  32. package/dist/ai-client/registry.d.ts +51 -0
  33. package/dist/ai-client/registry.d.ts.map +1 -0
  34. package/dist/ai-client/registry.js +81 -0
  35. package/dist/ai-client/registry.js.map +1 -0
  36. package/dist/ai-client/types.d.ts +274 -0
  37. package/dist/ai-client/types.d.ts.map +1 -0
  38. package/dist/ai-client/types.js +90 -0
  39. package/dist/ai-client/types.js.map +1 -0
  40. package/dist/ai-client-factory.d.ts +62 -0
  41. package/dist/ai-client-factory.d.ts.map +1 -0
  42. package/dist/ai-client-factory.js +157 -0
  43. package/dist/ai-client-factory.js.map +1 -0
  44. package/dist/auth.d.ts +23 -1
  45. package/dist/auth.d.ts.map +1 -1
  46. package/dist/auth.js +164 -174
  47. package/dist/auth.js.map +1 -1
  48. package/dist/cancellation.d.ts +5 -4
  49. package/dist/cancellation.d.ts.map +1 -1
  50. package/dist/cancellation.js +53 -32
  51. package/dist/cancellation.js.map +1 -1
  52. package/dist/checkpoint.d.ts +2 -1
  53. package/dist/checkpoint.d.ts.map +1 -1
  54. package/dist/checkpoint.js +39 -6
  55. package/dist/checkpoint.js.map +1 -1
  56. package/dist/cli.js +742 -29
  57. package/dist/cli.js.map +1 -1
  58. package/dist/config.d.ts +10 -4
  59. package/dist/config.d.ts.map +1 -1
  60. package/dist/config.js +62 -25
  61. package/dist/config.js.map +1 -1
  62. package/dist/context-compressor.d.ts +82 -18
  63. package/dist/context-compressor.d.ts.map +1 -1
  64. package/dist/context-compressor.js +718 -154
  65. package/dist/context-compressor.js.map +1 -1
  66. package/dist/conversation.d.ts +1 -1
  67. package/dist/conversation.d.ts.map +1 -1
  68. package/dist/conversation.js +8 -7
  69. package/dist/conversation.js.map +1 -1
  70. package/dist/gui-subagent/action-parser/actionParser.d.ts.map +1 -1
  71. package/dist/gui-subagent/action-parser/actionParser.js +6 -4
  72. package/dist/gui-subagent/action-parser/actionParser.js.map +1 -1
  73. package/dist/gui-subagent/agent/gui-agent.d.ts +39 -2
  74. package/dist/gui-subagent/agent/gui-agent.d.ts.map +1 -1
  75. package/dist/gui-subagent/agent/gui-agent.js +189 -74
  76. package/dist/gui-subagent/agent/gui-agent.js.map +1 -1
  77. package/dist/gui-subagent/index.d.ts +23 -1
  78. package/dist/gui-subagent/index.d.ts.map +1 -1
  79. package/dist/gui-subagent/index.js +6 -0
  80. package/dist/gui-subagent/index.js.map +1 -1
  81. package/dist/gui-subagent/operator/base-operator.d.ts.map +1 -1
  82. package/dist/gui-subagent/operator/base-operator.js +0 -1
  83. package/dist/gui-subagent/operator/base-operator.js.map +1 -1
  84. package/dist/gui-subagent/operator/computer-operator.d.ts.map +1 -1
  85. package/dist/gui-subagent/operator/computer-operator.js +31 -8
  86. package/dist/gui-subagent/operator/computer-operator.js.map +1 -1
  87. package/dist/gui-subagent/types/actions.d.ts +1 -1
  88. package/dist/gui-subagent/types/actions.d.ts.map +1 -1
  89. package/dist/gui-subagent/types/actions.js +0 -1
  90. package/dist/gui-subagent/types/actions.js.map +1 -1
  91. package/dist/gui-subagent/types/operator.d.ts +1 -1
  92. package/dist/gui-subagent/types/operator.d.ts.map +1 -1
  93. package/dist/index.d.ts +1 -2
  94. package/dist/index.d.ts.map +1 -1
  95. package/dist/index.js +1 -2
  96. package/dist/index.js.map +1 -1
  97. package/dist/input-processor.d.ts.map +1 -1
  98. package/dist/input-processor.js +8 -5
  99. package/dist/input-processor.js.map +1 -1
  100. package/dist/logger.d.ts.map +1 -1
  101. package/dist/logger.js +1 -1
  102. package/dist/logger.js.map +1 -1
  103. package/dist/mcp.d.ts +7 -1
  104. package/dist/mcp.d.ts.map +1 -1
  105. package/dist/mcp.js +157 -49
  106. package/dist/mcp.js.map +1 -1
  107. package/dist/memory.d.ts.map +1 -1
  108. package/dist/memory.js +3 -3
  109. package/dist/memory.js.map +1 -1
  110. package/dist/output-util.d.ts +27 -0
  111. package/dist/output-util.d.ts.map +1 -0
  112. package/dist/output-util.js +74 -0
  113. package/dist/output-util.js.map +1 -0
  114. package/dist/retry.js +1 -1
  115. package/dist/retry.js.map +1 -1
  116. package/dist/ripgrep.d.ts +29 -0
  117. package/dist/ripgrep.d.ts.map +1 -0
  118. package/dist/ripgrep.js +294 -0
  119. package/dist/ripgrep.js.map +1 -0
  120. package/dist/sdk-output-adapter.d.ts +34 -1
  121. package/dist/sdk-output-adapter.d.ts.map +1 -1
  122. package/dist/sdk-output-adapter.js +67 -2
  123. package/dist/sdk-output-adapter.js.map +1 -1
  124. package/dist/sdk-session.d.ts.map +1 -1
  125. package/dist/sdk-session.js +2 -0
  126. package/dist/sdk-session.js.map +1 -1
  127. package/dist/session-manager.js +3 -3
  128. package/dist/session-manager.js.map +1 -1
  129. package/dist/session.d.ts +116 -6
  130. package/dist/session.d.ts.map +1 -1
  131. package/dist/session.js +1416 -448
  132. package/dist/session.js.map +1 -1
  133. package/dist/shell.d.ts +33 -0
  134. package/dist/shell.d.ts.map +1 -0
  135. package/dist/shell.js +126 -0
  136. package/dist/shell.js.map +1 -0
  137. package/dist/skill-installer.d.ts +38 -0
  138. package/dist/skill-installer.d.ts.map +1 -0
  139. package/dist/skill-installer.js +447 -0
  140. package/dist/skill-installer.js.map +1 -0
  141. package/dist/skill-invoker.d.ts +8 -2
  142. package/dist/skill-invoker.d.ts.map +1 -1
  143. package/dist/skill-invoker.js +36 -15
  144. package/dist/skill-invoker.js.map +1 -1
  145. package/dist/skill-loader.d.ts +8 -3
  146. package/dist/skill-loader.d.ts.map +1 -1
  147. package/dist/skill-loader.js +51 -48
  148. package/dist/skill-loader.js.map +1 -1
  149. package/dist/skill-manager.d.ts +85 -0
  150. package/dist/skill-manager.d.ts.map +1 -0
  151. package/dist/skill-manager.js +341 -0
  152. package/dist/skill-manager.js.map +1 -0
  153. package/dist/slash-commands.d.ts +39 -2
  154. package/dist/slash-commands.d.ts.map +1 -1
  155. package/dist/slash-commands.js +934 -305
  156. package/dist/slash-commands.js.map +1 -1
  157. package/dist/smart-approval.d.ts +20 -1
  158. package/dist/smart-approval.d.ts.map +1 -1
  159. package/dist/smart-approval.js +125 -56
  160. package/dist/smart-approval.js.map +1 -1
  161. package/dist/system-prompt-generator.d.ts +6 -0
  162. package/dist/system-prompt-generator.d.ts.map +1 -1
  163. package/dist/system-prompt-generator.js +86 -36
  164. package/dist/system-prompt-generator.js.map +1 -1
  165. package/dist/terminal.d.ts +28 -0
  166. package/dist/terminal.d.ts.map +1 -0
  167. package/dist/terminal.js +82 -0
  168. package/dist/terminal.js.map +1 -0
  169. package/dist/theme.d.ts.map +1 -1
  170. package/dist/theme.js +8 -7
  171. package/dist/theme.js.map +1 -1
  172. package/dist/tools.d.ts +38 -7
  173. package/dist/tools.d.ts.map +1 -1
  174. package/dist/tools.js +1249 -617
  175. package/dist/tools.js.map +1 -1
  176. package/dist/truncate.d.ts +55 -0
  177. package/dist/truncate.d.ts.map +1 -0
  178. package/dist/truncate.js +130 -0
  179. package/dist/truncate.js.map +1 -0
  180. package/dist/types.d.ts +84 -9
  181. package/dist/types.d.ts.map +1 -1
  182. package/dist/types.js +49 -0
  183. package/dist/types.js.map +1 -1
  184. package/dist/update.d.ts.map +1 -1
  185. package/dist/update.js +28 -36
  186. package/dist/update.js.map +1 -1
  187. package/dist/workflow.d.ts +5 -1
  188. package/dist/workflow.d.ts.map +1 -1
  189. package/dist/workflow.js +61 -49
  190. package/dist/workflow.js.map +1 -1
  191. package/docs/architecture/mcp-integration-guide.md +304 -194
  192. package/docs/architecture/overview.md +169 -169
  193. package/docs/architecture/tool-system-design.md +134 -134
  194. package/docs/cli/commands.md +349 -238
  195. package/docs/smart-mode.md +281 -281
  196. package/docs/third-party-models.md +440 -439
  197. package/find-skills/SKILL.md +133 -0
  198. package/package.json +91 -90
  199. package/scripts/install-ripgrep.js +241 -0
  200. package/src/agents.ts +7 -3
  201. package/src/ai-client/factory.ts +116 -0
  202. package/src/ai-client/index.ts +61 -0
  203. package/src/ai-client/providers/anthropic.ts +475 -0
  204. package/src/ai-client/providers/openai.ts +348 -0
  205. package/src/ai-client/providers/remote.ts +439 -0
  206. package/src/ai-client/registry.ts +97 -0
  207. package/src/ai-client/types.ts +364 -0
  208. package/src/ai-client-factory.ts +204 -0
  209. package/src/auth.ts +661 -614
  210. package/src/cancellation.ts +202 -176
  211. package/src/checkpoint.ts +255 -219
  212. package/src/cli.ts +1523 -743
  213. package/src/config.ts +341 -297
  214. package/src/context-compressor.ts +987 -290
  215. package/src/conversation.ts +290 -288
  216. package/src/gui-subagent/action-parser/actionParser.ts +318 -315
  217. package/src/gui-subagent/action-parser/constants.ts +14 -14
  218. package/src/gui-subagent/action-parser/index.ts +8 -8
  219. package/src/gui-subagent/action-parser/types.ts +31 -31
  220. package/src/gui-subagent/agent/gui-agent.ts +1234 -1089
  221. package/src/gui-subagent/agent/index.ts +5 -5
  222. package/src/gui-subagent/index.ts +185 -163
  223. package/src/gui-subagent/operator/base-operator.ts +244 -245
  224. package/src/gui-subagent/operator/computer-operator.ts +541 -520
  225. package/src/gui-subagent/operator/index.ts +6 -6
  226. package/src/gui-subagent/types/actions.ts +260 -262
  227. package/src/gui-subagent/types/index.ts +6 -6
  228. package/src/gui-subagent/types/operator.ts +106 -106
  229. package/src/gui-subagent/utils.ts +51 -51
  230. package/src/index.ts +17 -18
  231. package/src/input-processor.ts +8 -5
  232. package/src/logger.ts +436 -438
  233. package/src/mcp.ts +793 -682
  234. package/src/memory.ts +343 -344
  235. package/src/output-util.ts +80 -0
  236. package/src/retry.ts +1 -1
  237. package/src/ripgrep.ts +370 -0
  238. package/src/sdk-output-adapter.ts +842 -0
  239. package/src/sdk-session.ts +62 -0
  240. package/src/session-manager.ts +308 -308
  241. package/src/session.ts +1775 -573
  242. package/src/shell.ts +134 -0
  243. package/src/skill-installer.ts +518 -0
  244. package/src/skill-invoker.ts +959 -935
  245. package/src/skill-loader.ts +501 -496
  246. package/src/skill-manager.ts +385 -0
  247. package/src/slash-commands.ts +2189 -1389
  248. package/src/smart-approval.ts +193 -74
  249. package/src/system-prompt-generator.ts +91 -36
  250. package/src/terminal.ts +96 -0
  251. package/src/theme.ts +739 -738
  252. package/src/tools.ts +1790 -931
  253. package/src/truncate.ts +173 -0
  254. package/src/types.ts +337 -198
  255. package/src/update.ts +33 -40
  256. package/src/workflow.ts +521 -508
  257. package/test/cli-launch.test.ts +279 -0
  258. package/tsconfig.json +22 -22
  259. package/vitest.config.ts +21 -19
  260. package/dist/ai-client.d.ts +0 -86
  261. package/dist/ai-client.d.ts.map +0 -1
  262. package/dist/ai-client.js +0 -1372
  263. package/dist/ai-client.js.map +0 -1
  264. package/dist/gui-subagent/operator/browser-operator.d.ts +0 -36
  265. package/dist/gui-subagent/operator/browser-operator.d.ts.map +0 -1
  266. package/dist/gui-subagent/operator/browser-operator.js +0 -306
  267. package/dist/gui-subagent/operator/browser-operator.js.map +0 -1
  268. package/dist/gui-subagent/operator/desktop-operator.d.ts +0 -55
  269. package/dist/gui-subagent/operator/desktop-operator.d.ts.map +0 -1
  270. package/dist/gui-subagent/operator/desktop-operator.js +0 -527
  271. package/dist/gui-subagent/operator/desktop-operator.js.map +0 -1
  272. package/dist/hook.d.ts +0 -73
  273. package/dist/hook.d.ts.map +0 -1
  274. package/dist/hook.js +0 -156
  275. package/dist/hook.js.map +0 -1
  276. package/dist/input-history.d.ts +0 -24
  277. package/dist/input-history.d.ts.map +0 -1
  278. package/dist/input-history.js +0 -94
  279. package/dist/input-history.js.map +0 -1
  280. package/dist/keyboard-manager.d.ts +0 -151
  281. package/dist/keyboard-manager.d.ts.map +0 -1
  282. package/dist/keyboard-manager.js +0 -396
  283. package/dist/keyboard-manager.js.map +0 -1
  284. package/dist/print-system-prompt.d.ts +0 -2
  285. package/dist/print-system-prompt.d.ts.map +0 -1
  286. package/dist/print-system-prompt.js +0 -40
  287. package/dist/print-system-prompt.js.map +0 -1
  288. package/dist/remote-ai-client.d.ts +0 -104
  289. package/dist/remote-ai-client.d.ts.map +0 -1
  290. package/dist/remote-ai-client.js +0 -552
  291. package/dist/remote-ai-client.js.map +0 -1
  292. package/dist/sdk-session-v2.d.ts +0 -13
  293. package/dist/sdk-session-v2.d.ts.map +0 -1
  294. package/dist/sdk-session-v2.js +0 -46
  295. package/dist/sdk-session-v2.js.map +0 -1
  296. package/dist/test-boundary-conditions.d.ts.map +0 -1
  297. package/dist/test-boundary-conditions.js.map +0 -1
  298. package/dist/test-cancellation-fix.d.ts.map +0 -1
  299. package/dist/test-cancellation-fix.js.map +0 -1
  300. package/dist/test-input-history.d.ts.map +0 -1
  301. package/dist/test-input-history.js.map +0 -1
  302. package/dist/test-interaction-flow.d.ts.map +0 -1
  303. package/dist/test-interaction-flow.js.map +0 -1
  304. package/dist/test-quick.d.ts.map +0 -1
  305. package/dist/test-quick.js.map +0 -1
  306. package/dist/test-user-interaction.d.ts.map +0 -1
  307. package/dist/test-user-interaction.js.map +0 -1
  308. package/dist/tools/edit-diff.d.ts +0 -32
  309. package/dist/tools/edit-diff.d.ts.map +0 -1
  310. package/dist/tools/edit-diff.js +0 -185
  311. package/dist/tools/edit-diff.js.map +0 -1
  312. package/dist/tools/edit.d.ts +0 -11
  313. package/dist/tools/edit.d.ts.map +0 -1
  314. package/dist/tools/edit.js +0 -129
  315. package/dist/tools/edit.js.map +0 -1
  316. package/dist/unified-session.d.ts +0 -42
  317. package/dist/unified-session.d.ts.map +0 -1
  318. package/dist/unified-session.js +0 -271
  319. package/dist/unified-session.js.map +0 -1
  320. package/skills/.claude-plugin/marketplace.json +0 -45
  321. package/skills/README.md +0 -94
  322. package/skills/THIRD_PARTY_NOTICES.md +0 -405
  323. package/skills/skills/algorithmic-art/LICENSE.txt +0 -202
  324. package/skills/skills/algorithmic-art/SKILL.md +0 -405
  325. package/skills/skills/algorithmic-art/templates/generator_template.js +0 -223
  326. package/skills/skills/algorithmic-art/templates/viewer.html +0 -599
  327. package/skills/skills/brand-guidelines/LICENSE.txt +0 -202
  328. package/skills/skills/brand-guidelines/SKILL.md +0 -73
  329. package/skills/skills/canvas-design/LICENSE.txt +0 -202
  330. package/skills/skills/canvas-design/SKILL.md +0 -130
  331. package/skills/skills/canvas-design/canvas-fonts/ArsenalSC-OFL.txt +0 -93
  332. package/skills/skills/canvas-design/canvas-fonts/ArsenalSC-Regular.ttf +0 -0
  333. package/skills/skills/canvas-design/canvas-fonts/BigShoulders-Bold.ttf +0 -0
  334. package/skills/skills/canvas-design/canvas-fonts/BigShoulders-OFL.txt +0 -93
  335. package/skills/skills/canvas-design/canvas-fonts/BigShoulders-Regular.ttf +0 -0
  336. package/skills/skills/canvas-design/canvas-fonts/Boldonse-OFL.txt +0 -93
  337. package/skills/skills/canvas-design/canvas-fonts/Boldonse-Regular.ttf +0 -0
  338. package/skills/skills/canvas-design/canvas-fonts/BricolageGrotesque-Bold.ttf +0 -0
  339. package/skills/skills/canvas-design/canvas-fonts/BricolageGrotesque-OFL.txt +0 -93
  340. package/skills/skills/canvas-design/canvas-fonts/BricolageGrotesque-Regular.ttf +0 -0
  341. package/skills/skills/canvas-design/canvas-fonts/CrimsonPro-Bold.ttf +0 -0
  342. package/skills/skills/canvas-design/canvas-fonts/CrimsonPro-Italic.ttf +0 -0
  343. package/skills/skills/canvas-design/canvas-fonts/CrimsonPro-OFL.txt +0 -93
  344. package/skills/skills/canvas-design/canvas-fonts/CrimsonPro-Regular.ttf +0 -0
  345. package/skills/skills/canvas-design/canvas-fonts/DMMono-OFL.txt +0 -93
  346. package/skills/skills/canvas-design/canvas-fonts/DMMono-Regular.ttf +0 -0
  347. package/skills/skills/canvas-design/canvas-fonts/EricaOne-OFL.txt +0 -94
  348. package/skills/skills/canvas-design/canvas-fonts/EricaOne-Regular.ttf +0 -0
  349. package/skills/skills/canvas-design/canvas-fonts/GeistMono-Bold.ttf +0 -0
  350. package/skills/skills/canvas-design/canvas-fonts/GeistMono-OFL.txt +0 -93
  351. package/skills/skills/canvas-design/canvas-fonts/GeistMono-Regular.ttf +0 -0
  352. package/skills/skills/canvas-design/canvas-fonts/Gloock-OFL.txt +0 -93
  353. package/skills/skills/canvas-design/canvas-fonts/Gloock-Regular.ttf +0 -0
  354. package/skills/skills/canvas-design/canvas-fonts/IBMPlexMono-Bold.ttf +0 -0
  355. package/skills/skills/canvas-design/canvas-fonts/IBMPlexMono-OFL.txt +0 -93
  356. package/skills/skills/canvas-design/canvas-fonts/IBMPlexMono-Regular.ttf +0 -0
  357. package/skills/skills/canvas-design/canvas-fonts/IBMPlexSerif-Bold.ttf +0 -0
  358. package/skills/skills/canvas-design/canvas-fonts/IBMPlexSerif-BoldItalic.ttf +0 -0
  359. package/skills/skills/canvas-design/canvas-fonts/IBMPlexSerif-Italic.ttf +0 -0
  360. package/skills/skills/canvas-design/canvas-fonts/IBMPlexSerif-Regular.ttf +0 -0
  361. package/skills/skills/canvas-design/canvas-fonts/InstrumentSans-Bold.ttf +0 -0
  362. package/skills/skills/canvas-design/canvas-fonts/InstrumentSans-BoldItalic.ttf +0 -0
  363. package/skills/skills/canvas-design/canvas-fonts/InstrumentSans-Italic.ttf +0 -0
  364. package/skills/skills/canvas-design/canvas-fonts/InstrumentSans-OFL.txt +0 -93
  365. package/skills/skills/canvas-design/canvas-fonts/InstrumentSans-Regular.ttf +0 -0
  366. package/skills/skills/canvas-design/canvas-fonts/InstrumentSerif-Italic.ttf +0 -0
  367. package/skills/skills/canvas-design/canvas-fonts/InstrumentSerif-Regular.ttf +0 -0
  368. package/skills/skills/canvas-design/canvas-fonts/Italiana-OFL.txt +0 -93
  369. package/skills/skills/canvas-design/canvas-fonts/Italiana-Regular.ttf +0 -0
  370. package/skills/skills/canvas-design/canvas-fonts/JetBrainsMono-Bold.ttf +0 -0
  371. package/skills/skills/canvas-design/canvas-fonts/JetBrainsMono-OFL.txt +0 -93
  372. package/skills/skills/canvas-design/canvas-fonts/JetBrainsMono-Regular.ttf +0 -0
  373. package/skills/skills/canvas-design/canvas-fonts/Jura-Light.ttf +0 -0
  374. package/skills/skills/canvas-design/canvas-fonts/Jura-Medium.ttf +0 -0
  375. package/skills/skills/canvas-design/canvas-fonts/Jura-OFL.txt +0 -93
  376. package/skills/skills/canvas-design/canvas-fonts/LibreBaskerville-OFL.txt +0 -93
  377. package/skills/skills/canvas-design/canvas-fonts/LibreBaskerville-Regular.ttf +0 -0
  378. package/skills/skills/canvas-design/canvas-fonts/Lora-Bold.ttf +0 -0
  379. package/skills/skills/canvas-design/canvas-fonts/Lora-BoldItalic.ttf +0 -0
  380. package/skills/skills/canvas-design/canvas-fonts/Lora-Italic.ttf +0 -0
  381. package/skills/skills/canvas-design/canvas-fonts/Lora-OFL.txt +0 -93
  382. package/skills/skills/canvas-design/canvas-fonts/Lora-Regular.ttf +0 -0
  383. package/skills/skills/canvas-design/canvas-fonts/NationalPark-Bold.ttf +0 -0
  384. package/skills/skills/canvas-design/canvas-fonts/NationalPark-OFL.txt +0 -93
  385. package/skills/skills/canvas-design/canvas-fonts/NationalPark-Regular.ttf +0 -0
  386. package/skills/skills/canvas-design/canvas-fonts/NothingYouCouldDo-OFL.txt +0 -93
  387. package/skills/skills/canvas-design/canvas-fonts/NothingYouCouldDo-Regular.ttf +0 -0
  388. package/skills/skills/canvas-design/canvas-fonts/Outfit-Bold.ttf +0 -0
  389. package/skills/skills/canvas-design/canvas-fonts/Outfit-OFL.txt +0 -93
  390. package/skills/skills/canvas-design/canvas-fonts/Outfit-Regular.ttf +0 -0
  391. package/skills/skills/canvas-design/canvas-fonts/PixelifySans-Medium.ttf +0 -0
  392. package/skills/skills/canvas-design/canvas-fonts/PixelifySans-OFL.txt +0 -93
  393. package/skills/skills/canvas-design/canvas-fonts/PoiretOne-OFL.txt +0 -93
  394. package/skills/skills/canvas-design/canvas-fonts/PoiretOne-Regular.ttf +0 -0
  395. package/skills/skills/canvas-design/canvas-fonts/RedHatMono-Bold.ttf +0 -0
  396. package/skills/skills/canvas-design/canvas-fonts/RedHatMono-OFL.txt +0 -93
  397. package/skills/skills/canvas-design/canvas-fonts/RedHatMono-Regular.ttf +0 -0
  398. package/skills/skills/canvas-design/canvas-fonts/Silkscreen-OFL.txt +0 -93
  399. package/skills/skills/canvas-design/canvas-fonts/Silkscreen-Regular.ttf +0 -0
  400. package/skills/skills/canvas-design/canvas-fonts/SmoochSans-Medium.ttf +0 -0
  401. package/skills/skills/canvas-design/canvas-fonts/SmoochSans-OFL.txt +0 -93
  402. package/skills/skills/canvas-design/canvas-fonts/Tektur-Medium.ttf +0 -0
  403. package/skills/skills/canvas-design/canvas-fonts/Tektur-OFL.txt +0 -93
  404. package/skills/skills/canvas-design/canvas-fonts/Tektur-Regular.ttf +0 -0
  405. package/skills/skills/canvas-design/canvas-fonts/WorkSans-Bold.ttf +0 -0
  406. package/skills/skills/canvas-design/canvas-fonts/WorkSans-BoldItalic.ttf +0 -0
  407. package/skills/skills/canvas-design/canvas-fonts/WorkSans-Italic.ttf +0 -0
  408. package/skills/skills/canvas-design/canvas-fonts/WorkSans-OFL.txt +0 -93
  409. package/skills/skills/canvas-design/canvas-fonts/WorkSans-Regular.ttf +0 -0
  410. package/skills/skills/canvas-design/canvas-fonts/YoungSerif-OFL.txt +0 -93
  411. package/skills/skills/canvas-design/canvas-fonts/YoungSerif-Regular.ttf +0 -0
  412. package/skills/skills/doc-coauthoring/SKILL.md +0 -375
  413. package/skills/skills/docx/LICENSE.txt +0 -30
  414. package/skills/skills/docx/SKILL.md +0 -197
  415. package/skills/skills/docx/docx-js.md +0 -350
  416. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +0 -1499
  417. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +0 -146
  418. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +0 -1085
  419. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +0 -11
  420. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +0 -3081
  421. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +0 -23
  422. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +0 -185
  423. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +0 -287
  424. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +0 -1676
  425. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +0 -28
  426. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +0 -144
  427. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +0 -174
  428. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +0 -25
  429. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +0 -18
  430. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +0 -59
  431. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +0 -56
  432. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +0 -195
  433. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +0 -582
  434. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +0 -25
  435. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +0 -4439
  436. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +0 -570
  437. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +0 -509
  438. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +0 -12
  439. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +0 -108
  440. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +0 -96
  441. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +0 -3646
  442. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +0 -116
  443. package/skills/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +0 -42
  444. package/skills/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +0 -50
  445. package/skills/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +0 -49
  446. package/skills/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +0 -33
  447. package/skills/skills/docx/ooxml/schemas/mce/mc.xsd +0 -75
  448. package/skills/skills/docx/ooxml/schemas/microsoft/wml-2010.xsd +0 -560
  449. package/skills/skills/docx/ooxml/schemas/microsoft/wml-2012.xsd +0 -67
  450. package/skills/skills/docx/ooxml/schemas/microsoft/wml-2018.xsd +0 -14
  451. package/skills/skills/docx/ooxml/schemas/microsoft/wml-cex-2018.xsd +0 -20
  452. package/skills/skills/docx/ooxml/schemas/microsoft/wml-cid-2016.xsd +0 -13
  453. package/skills/skills/docx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +0 -4
  454. package/skills/skills/docx/ooxml/schemas/microsoft/wml-symex-2015.xsd +0 -8
  455. package/skills/skills/docx/ooxml/scripts/pack.py +0 -159
  456. package/skills/skills/docx/ooxml/scripts/unpack.py +0 -29
  457. package/skills/skills/docx/ooxml/scripts/validate.py +0 -69
  458. package/skills/skills/docx/ooxml/scripts/validation/__init__.py +0 -15
  459. package/skills/skills/docx/ooxml/scripts/validation/base.py +0 -951
  460. package/skills/skills/docx/ooxml/scripts/validation/docx.py +0 -274
  461. package/skills/skills/docx/ooxml/scripts/validation/pptx.py +0 -315
  462. package/skills/skills/docx/ooxml/scripts/validation/redlining.py +0 -279
  463. package/skills/skills/docx/ooxml.md +0 -610
  464. package/skills/skills/docx/scripts/__init__.py +0 -1
  465. package/skills/skills/docx/scripts/document.py +0 -1276
  466. package/skills/skills/docx/scripts/templates/comments.xml +0 -3
  467. package/skills/skills/docx/scripts/templates/commentsExtended.xml +0 -3
  468. package/skills/skills/docx/scripts/templates/commentsExtensible.xml +0 -3
  469. package/skills/skills/docx/scripts/templates/commentsIds.xml +0 -3
  470. package/skills/skills/docx/scripts/templates/people.xml +0 -3
  471. package/skills/skills/docx/scripts/utilities.py +0 -374
  472. package/skills/skills/frontend-design/LICENSE.txt +0 -177
  473. package/skills/skills/frontend-design/SKILL.md +0 -42
  474. package/skills/skills/internal-comms/LICENSE.txt +0 -202
  475. package/skills/skills/internal-comms/SKILL.md +0 -32
  476. package/skills/skills/internal-comms/examples/3p-updates.md +0 -47
  477. package/skills/skills/internal-comms/examples/company-newsletter.md +0 -65
  478. package/skills/skills/internal-comms/examples/faq-answers.md +0 -30
  479. package/skills/skills/internal-comms/examples/general-comms.md +0 -16
  480. package/skills/skills/mcp-builder/LICENSE.txt +0 -202
  481. package/skills/skills/mcp-builder/SKILL.md +0 -236
  482. package/skills/skills/mcp-builder/reference/evaluation.md +0 -602
  483. package/skills/skills/mcp-builder/reference/mcp_best_practices.md +0 -249
  484. package/skills/skills/mcp-builder/reference/node_mcp_server.md +0 -970
  485. package/skills/skills/mcp-builder/reference/python_mcp_server.md +0 -719
  486. package/skills/skills/mcp-builder/scripts/connections.py +0 -151
  487. package/skills/skills/mcp-builder/scripts/evaluation.py +0 -373
  488. package/skills/skills/mcp-builder/scripts/example_evaluation.xml +0 -22
  489. package/skills/skills/mcp-builder/scripts/requirements.txt +0 -2
  490. package/skills/skills/pdf/LICENSE.txt +0 -30
  491. package/skills/skills/pdf/SKILL.md +0 -294
  492. package/skills/skills/pdf/forms.md +0 -205
  493. package/skills/skills/pdf/reference.md +0 -612
  494. package/skills/skills/pdf/scripts/check_bounding_boxes.py +0 -70
  495. package/skills/skills/pdf/scripts/check_bounding_boxes_test.py +0 -226
  496. package/skills/skills/pdf/scripts/check_fillable_fields.py +0 -12
  497. package/skills/skills/pdf/scripts/convert_pdf_to_images.py +0 -35
  498. package/skills/skills/pdf/scripts/create_validation_image.py +0 -41
  499. package/skills/skills/pdf/scripts/extract_form_field_info.py +0 -152
  500. package/skills/skills/pdf/scripts/fill_fillable_fields.py +0 -114
  501. package/skills/skills/pdf/scripts/fill_pdf_form_with_annotations.py +0 -108
  502. package/skills/skills/pptx/LICENSE.txt +0 -30
  503. package/skills/skills/pptx/SKILL.md +0 -484
  504. package/skills/skills/pptx/html2pptx.md +0 -625
  505. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +0 -1499
  506. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +0 -146
  507. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +0 -1085
  508. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +0 -11
  509. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +0 -3081
  510. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +0 -23
  511. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +0 -185
  512. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +0 -287
  513. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +0 -1676
  514. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +0 -28
  515. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +0 -144
  516. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +0 -174
  517. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +0 -25
  518. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +0 -18
  519. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +0 -59
  520. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +0 -56
  521. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +0 -195
  522. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +0 -582
  523. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +0 -25
  524. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +0 -4439
  525. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +0 -570
  526. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +0 -509
  527. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +0 -12
  528. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +0 -108
  529. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +0 -96
  530. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +0 -3646
  531. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +0 -116
  532. package/skills/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +0 -42
  533. package/skills/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +0 -50
  534. package/skills/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +0 -49
  535. package/skills/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +0 -33
  536. package/skills/skills/pptx/ooxml/schemas/mce/mc.xsd +0 -75
  537. package/skills/skills/pptx/ooxml/schemas/microsoft/wml-2010.xsd +0 -560
  538. package/skills/skills/pptx/ooxml/schemas/microsoft/wml-2012.xsd +0 -67
  539. package/skills/skills/pptx/ooxml/schemas/microsoft/wml-2018.xsd +0 -14
  540. package/skills/skills/pptx/ooxml/schemas/microsoft/wml-cex-2018.xsd +0 -20
  541. package/skills/skills/pptx/ooxml/schemas/microsoft/wml-cid-2016.xsd +0 -13
  542. package/skills/skills/pptx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +0 -4
  543. package/skills/skills/pptx/ooxml/schemas/microsoft/wml-symex-2015.xsd +0 -8
  544. package/skills/skills/pptx/ooxml/scripts/pack.py +0 -159
  545. package/skills/skills/pptx/ooxml/scripts/unpack.py +0 -29
  546. package/skills/skills/pptx/ooxml/scripts/validate.py +0 -69
  547. package/skills/skills/pptx/ooxml/scripts/validation/__init__.py +0 -15
  548. package/skills/skills/pptx/ooxml/scripts/validation/base.py +0 -951
  549. package/skills/skills/pptx/ooxml/scripts/validation/docx.py +0 -274
  550. package/skills/skills/pptx/ooxml/scripts/validation/pptx.py +0 -315
  551. package/skills/skills/pptx/ooxml/scripts/validation/redlining.py +0 -279
  552. package/skills/skills/pptx/ooxml.md +0 -427
  553. package/skills/skills/pptx/scripts/html2pptx.js +0 -979
  554. package/skills/skills/pptx/scripts/inventory.py +0 -1020
  555. package/skills/skills/pptx/scripts/rearrange.py +0 -231
  556. package/skills/skills/pptx/scripts/replace.py +0 -385
  557. package/skills/skills/pptx/scripts/thumbnail.py +0 -450
  558. package/skills/skills/skill-creator/LICENSE.txt +0 -202
  559. package/skills/skills/skill-creator/SKILL.md +0 -356
  560. package/skills/skills/skill-creator/references/output-patterns.md +0 -82
  561. package/skills/skills/skill-creator/references/workflows.md +0 -28
  562. package/skills/skills/skill-creator/scripts/init_skill.py +0 -303
  563. package/skills/skills/skill-creator/scripts/package_skill.py +0 -110
  564. package/skills/skills/skill-creator/scripts/quick_validate.py +0 -95
  565. package/skills/skills/slack-gif-creator/LICENSE.txt +0 -202
  566. package/skills/skills/slack-gif-creator/SKILL.md +0 -254
  567. package/skills/skills/slack-gif-creator/core/easing.py +0 -234
  568. package/skills/skills/slack-gif-creator/core/frame_composer.py +0 -176
  569. package/skills/skills/slack-gif-creator/core/gif_builder.py +0 -269
  570. package/skills/skills/slack-gif-creator/core/validators.py +0 -136
  571. package/skills/skills/slack-gif-creator/requirements.txt +0 -4
  572. package/skills/skills/theme-factory/LICENSE.txt +0 -202
  573. package/skills/skills/theme-factory/SKILL.md +0 -59
  574. package/skills/skills/theme-factory/theme-showcase.pdf +0 -0
  575. package/skills/skills/theme-factory/themes/arctic-frost.md +0 -19
  576. package/skills/skills/theme-factory/themes/botanical-garden.md +0 -19
  577. package/skills/skills/theme-factory/themes/desert-rose.md +0 -19
  578. package/skills/skills/theme-factory/themes/forest-canopy.md +0 -19
  579. package/skills/skills/theme-factory/themes/golden-hour.md +0 -19
  580. package/skills/skills/theme-factory/themes/midnight-galaxy.md +0 -19
  581. package/skills/skills/theme-factory/themes/modern-minimalist.md +0 -19
  582. package/skills/skills/theme-factory/themes/ocean-depths.md +0 -19
  583. package/skills/skills/theme-factory/themes/sunset-boulevard.md +0 -19
  584. package/skills/skills/theme-factory/themes/tech-innovation.md +0 -19
  585. package/skills/skills/web-artifacts-builder/LICENSE.txt +0 -202
  586. package/skills/skills/web-artifacts-builder/SKILL.md +0 -74
  587. package/skills/skills/web-artifacts-builder/scripts/bundle-artifact.sh +0 -54
  588. package/skills/skills/web-artifacts-builder/scripts/init-artifact.sh +0 -322
  589. package/skills/skills/webapp-testing/LICENSE.txt +0 -202
  590. package/skills/skills/webapp-testing/SKILL.md +0 -96
  591. package/skills/skills/webapp-testing/examples/console_logging.py +0 -35
  592. package/skills/skills/webapp-testing/examples/element_discovery.py +0 -40
  593. package/skills/skills/webapp-testing/examples/static_html_automation.py +0 -33
  594. package/skills/skills/webapp-testing/scripts/with_server.py +0 -106
  595. package/skills/skills/xlsx/LICENSE.txt +0 -30
  596. package/skills/skills/xlsx/SKILL.md +0 -289
  597. package/skills/skills/xlsx/recalc.py +0 -178
  598. package/skills/spec/agent-skills-spec.md +0 -3
  599. package/skills/template/SKILL.md +0 -6
  600. package/src/ai-client.ts +0 -1560
  601. package/src/remote-ai-client.ts +0 -664
  602. /package/{.eslintrc.js → .eslintrc.cjs} +0 -0
@@ -1,935 +1,959 @@
1
- import fs from 'fs/promises';
2
- import path from 'path';
3
- import os from 'os';
4
- import { getSkillLoader, SkillInfo, SkillLoader } from './skill-loader.js';
5
- import { getToolRegistry } from './tools.js';
6
- import { ExecutionMode, Tool } from './types.js';
7
- import { getConfigManager } from './config.js';
8
-
9
- // Re-export SkillInfo for other modules
10
- export type { SkillInfo };
11
-
12
- /**
13
- * Track skill execution history for tracking failures
14
- */
15
- export class SkillExecutionHistory {
16
- private history: Map<string, number> = new Map();
17
-
18
- /**
19
- * Get failure count for a task
20
- */
21
- getFailureCount(taskKey: string): number {
22
- return this.history.get(taskKey) || 0;
23
- }
24
-
25
- /**
26
- * Increment failure count for a task
27
- */
28
- incrementFailure(taskKey: string): number {
29
- const count = this.getFailureCount(taskKey) + 1;
30
- this.history.set(taskKey, count);
31
- return count;
32
- }
33
-
34
- /**
35
- * Reset failure count for a task (e.g., after success)
36
- */
37
- reset(taskKey: string): void {
38
- this.history.delete(taskKey);
39
- }
40
-
41
- /**
42
- * Check if threshold reached
43
- */
44
- shouldUseFallback(taskKey: string, threshold: number = 2): boolean {
45
- return this.getFailureCount(taskKey) >= threshold;
46
- }
47
- }
48
-
49
- // Singleton execution history
50
- const executionHistory = new SkillExecutionHistory();
51
-
52
- export function getExecutionHistory(): SkillExecutionHistory {
53
- return executionHistory;
54
- }
55
-
56
- export interface SkillExecutionParams {
57
- skillId: string;
58
- taskDescription: string;
59
- inputFile?: string;
60
- outputFile?: string;
61
- options?: Record<string, any>;
62
- /** Task ID for workspace directory naming */
63
- taskId?: string;
64
- }
65
-
66
- /**
67
- * Execution step interface - tells Agent what to do next
68
- */
69
- export interface ExecutionStep {
70
- step: number;
71
- action: string;
72
- description: string;
73
- command?: string;
74
- file?: string;
75
- reason: string;
76
- }
77
-
78
- /**
79
- * Skill execution result - contains guidance and next actions
80
- */
81
- export interface SkillExecutionResult {
82
- success: boolean;
83
- output?: string;
84
- error?: string;
85
- files?: string[];
86
- /** Tells Agent what to do next */
87
- nextSteps?: ExecutionStep[];
88
- /** Skill type for determining if manual execution is needed */
89
- requiresManualExecution?: boolean;
90
- /** Workspace directory used, for cleanup */
91
- workspaceDir?: string;
92
- /** Files to preserve (relative paths), skipped during cleanup */
93
- preserveFiles?: string[];
94
- }
95
-
96
- export interface SkillMatcherResult {
97
- skill: SkillInfo;
98
- confidence: number;
99
- matchedKeywords: string[];
100
- category: string;
101
- }
102
-
103
- // ============================================================
104
- // Workspace Utility Functions
105
- // ============================================================
106
-
107
- /**
108
- * Get workspace directory path
109
- * @param taskId Task ID for creating unique workspace directory
110
- * @returns Absolute path to workspace directory
111
- */
112
- export function getWorkspaceDir(taskId: string): string {
113
- // Try to get from config first
114
- try {
115
- const configManager = getConfigManager();
116
- const config = configManager.getSettings?.();
117
- if (config?.workspacePath) {
118
- return path.join(config.workspacePath, taskId);
119
- }
120
- } catch {
121
- // Config not available, use default
122
- }
123
-
124
- // Default to ~/.xagent/workspace
125
- return path.join(os.homedir(), '.xagent', 'workspace', taskId);
126
- }
127
-
128
- /**
129
- * Get base workspace directory (without task-id)
130
- */
131
- export function getBaseWorkspaceDir(): string {
132
- try {
133
- const configManager = getConfigManager();
134
- const config = configManager.getSettings?.();
135
- if (config?.workspacePath) {
136
- return config.workspacePath;
137
- }
138
- } catch {
139
- // Config not available, use default
140
- }
141
-
142
- return path.join(os.homedir(), '.xagent', 'workspace');
143
- }
144
-
145
- /**
146
- * Get workspace directory description for AI
147
- * Returns the actual workspace path from config, or default path
148
- */
149
- export function getWorkspaceDescription(): string {
150
- try {
151
- const configManager = getConfigManager();
152
- const config = configManager.getSettings?.();
153
- if (config?.workspacePath) {
154
- return config.workspacePath;
155
- }
156
- } catch {
157
- // Config not available, use default
158
- }
159
-
160
- return path.join(os.homedir(), '.xagent', 'workspace');
161
- }
162
-
163
- /**
164
- * Ensure workspace directory exists
165
- * @param workspaceDir Workspace directory path
166
- */
167
- export async function ensureWorkspaceDir(workspaceDir: string): Promise<void> {
168
- await fs.mkdir(workspaceDir, { recursive: true });
169
- }
170
-
171
- /**
172
- * Clean up workspace directory
173
- * @param workspaceDir Workspace directory path
174
- * @param preserveFiles Files to preserve (relative paths)
175
- */
176
- export async function cleanupWorkspace(workspaceDir: string, preserveFiles: string[] = []): Promise<void> {
177
- try {
178
- const entries = await fs.readdir(workspaceDir, { withFileTypes: true });
179
-
180
- for (const entry of entries) {
181
- const fullPath = path.join(workspaceDir, entry.name);
182
-
183
- // Skip files to preserve
184
- if (preserveFiles.includes(entry.name)) {
185
- continue;
186
- }
187
-
188
- if (entry.isDirectory()) {
189
- // Recursively delete subdirectories
190
- await fs.rm(fullPath, { recursive: true, force: true });
191
- } else {
192
- // Delete files
193
- await fs.unlink(fullPath);
194
- }
195
- }
196
- } catch (error: any) {
197
- if (error.code !== 'ENOENT') {
198
- console.warn(`Workspace cleanup failed: ${error.message}`);
199
- }
200
- }
201
- }
202
-
203
- /**
204
- * Determine if workspace should be auto-cleaned based on ExecutionMode
205
- * @param executionMode Execution mode
206
- * @returns Whether auto-cleanup should happen
207
- */
208
- export function shouldAutoCleanup(executionMode: ExecutionMode): boolean {
209
- // YOLO mode: fully automatic, clean up directly
210
- if (executionMode === ExecutionMode.YOLO) {
211
- return true;
212
- }
213
- // Other modes require user confirmation
214
- return false;
215
- }
216
-
217
- /**
218
- * Generate cleanup prompt message
219
- * @param workspaceDir Workspace directory path
220
- */
221
- export async function getCleanupInfo(workspaceDir: string): Promise<{ files: string[]; totalSize: string }> {
222
- try {
223
- const entries = await fs.readdir(workspaceDir, { withFileTypes: true });
224
- const files: string[] = [];
225
-
226
- for (const entry of entries) {
227
- files.push(entry.name);
228
- }
229
-
230
- // Calculate total size
231
- let totalSize = 0;
232
- for (const entry of entries) {
233
- if (entry.isFile()) {
234
- const stats = await fs.stat(path.join(workspaceDir, entry.name));
235
- totalSize += stats.size;
236
- }
237
- }
238
-
239
- const formatSize = (bytes: number): string => {
240
- if (bytes < 1024) return `${bytes} B`;
241
- if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(2)} KB`;
242
- return `${(bytes / (1024 * 1024)).toFixed(2)} MB`;
243
- };
244
-
245
- return { files, totalSize: formatSize(totalSize) };
246
- } catch {
247
- return { files: [], totalSize: '0 B' };
248
- }
249
- }
250
-
251
- // ============================================================
252
- // Shared Content Extraction Utilities
253
- // ============================================================
254
-
255
- /**
256
- * Remove Markdown formatting (bold, italic, etc.)
257
- */
258
- export function stripMarkdown(text: string): string {
259
- return text
260
- .replace(/\*\*(.+?)\*\*/g, '$1') // Remove bold **
261
- .replace(/\*(.+?)\*/g, '$1') // Remove italic *
262
- .replace(/`(.+?)`/g, '$1') // Remove inline code `
263
- .trim();
264
- }
265
-
266
- /**
267
- * Extract content related to keywords (for SKILL.md content matching)
268
- * @param content SKILL.md full content
269
- * @param keywords Keyword list
270
- * @param maxLength Maximum return length
271
- * @returns Extracted relevant content
272
- */
273
- export function extractContent(content: string, keywords: string[], maxLength: number = 5000): string {
274
- const lines = content.split('\n');
275
- const relevantLines: string[] = [];
276
- let inRelevantSection = false;
277
- let sectionDepth = 0;
278
- let found = false;
279
-
280
- for (let i = 0; i < lines.length; i++) {
281
- const line = lines[i];
282
-
283
- // Detect headings
284
- if (line.match(/^#{1,6}\s/)) {
285
- const strippedLine = stripMarkdown(line);
286
- const lowerLine = strippedLine.toLowerCase();
287
-
288
- // Check if contains keywords
289
- const hasKeyword = keywords.some(kw => lowerLine.includes(kw.toLowerCase()));
290
-
291
- if (hasKeyword) {
292
- inRelevantSection = true;
293
- found = true;
294
- sectionDepth = line.match(/^(#+)/)?.[1].length || 1;
295
- } else if (inRelevantSection) {
296
- // Check if same level or higher heading (end current section)
297
- const currentDepth = line.match(/^(#+)/)?.[1].length || 1;
298
- if (currentDepth <= sectionDepth) {
299
- inRelevantSection = false;
300
- }
301
- }
302
- }
303
-
304
- if (inRelevantSection || found) {
305
- relevantLines.push(line);
306
- }
307
-
308
- // Limit content length
309
- if (relevantLines.join('\n').length > maxLength) {
310
- relevantLines.push('\n...(content truncated for brevity)...');
311
- break;
312
- }
313
- }
314
-
315
- if (relevantLines.length > 0) {
316
- return relevantLines.join('\n').trim();
317
- }
318
-
319
- // If still not found, return first 100 lines
320
- return lines.slice(0, 100).join('\n').trim() + '\n\n...(See SKILL.md for full instructions)';
321
- }
322
-
323
- /**
324
- * Read SKILL.md and extract relevant content based on task
325
- */
326
- export async function readSkillContent(skillPath: string, keywords: string[], maxLength: number = 5000): Promise<string> {
327
- const skillMdPath = path.join(skillPath, 'SKILL.md');
328
- const content = await fs.readFile(skillMdPath, 'utf-8');
329
- return extractContent(content, keywords, maxLength);
330
- }
331
-
332
- // ============================================================
333
- // SKILL Trigger Keywords Mapping
334
- // ============================================================
335
-
336
- // NOTE: SKILL_TRIGGERS is disabled for experiment purposes.
337
- // Let the LLM decide which skill to use based on system prompt information.
338
-
339
- // interface SkillTrigger {
340
- // skillId: string;
341
- // keywords: string[];
342
- // category: string;
343
- // }
344
-
345
- // export const SKILL_TRIGGERS: Record<string, SkillTrigger> = {
346
- // docx: {
347
- // skillId: 'docx',
348
- // keywords: [
349
- // 'word document', 'docx', 'microsoft word', 'create word', 'edit word',
350
- // 'create .docx', '.docx file', 'word file', 'document creation',
351
- // 'word editing', 'tracked changes', 'comments'
352
- // ],
353
- // category: 'Document Processing'
354
- // },
355
- // pdf: {
356
- // skillId: 'pdf',
357
- // keywords: [
358
- // 'pdf', 'create pdf', 'edit pdf', 'pdf document', 'pdf file',
359
- // 'extract pdf', 'merge pdf', 'split pdf', 'pdf form', 'manipulate pdf'
360
- // ],
361
- // category: 'Document Processing'
362
- // },
363
- // pptx: {
364
- // skillId: 'pptx',
365
- // keywords: [
366
- // 'powerpoint', 'ppt', 'pptx', 'presentation', 'slide',
367
- // 'create presentation', 'edit powerpoint', 'create slides',
368
- // 'powerpoint file', 'presentation file'
369
- // ],
370
- // category: 'Document Processing'
371
- // },
372
- // xlsx: {
373
- // skillId: 'xlsx',
374
- // keywords: [
375
- // 'excel', 'spreadsheet', 'xlsx', 'create excel', 'edit spreadsheet',
376
- // 'excel file', 'spreadsheet file', 'formulas', 'data analysis'
377
- // ],
378
- // category: 'Spreadsheet & Data'
379
- // },
380
- // frontend_design: {
381
- // skillId: 'frontend-design',
382
- // keywords: [
383
- // 'web page', 'website', 'web app', 'frontend', 'ui', 'user interface',
384
- // 'create website', 'build website', 'web component', 'html css',
385
- // 'landing page', 'dashboard', 'react', 'vue', 'web interface'
386
- // ],
387
- // category: 'Frontend & Web Development'
388
- // },
389
- // web_artifacts_builder: {
390
- // skillId: 'web-artifacts-builder',
391
- // keywords: [
392
- // 'complex react', 'react artifact', 'stateful artifact', 'routing',
393
- // 'web artifact', 'interactive artifact', 'web-based tool'
394
- // ],
395
- // category: 'Frontend & Web Development'
396
- // },
397
- // webapp_testing: {
398
- // skillId: 'webapp-testing',
399
- // keywords: [
400
- // 'test web', 'web testing', 'browser test', 'playwright', 'e2e test',
401
- // 'frontend test', 'capture screenshot', 'verify web'
402
- // ],
403
- // category: 'Frontend & Web Development'
404
- // },
405
- // canvas_design: {
406
- // skillId: 'canvas-design',
407
- // keywords: [
408
- // 'poster', 'artwork', 'visual art', 'canvas', 'design art',
409
- // 'create poster', 'create artwork', 'visual design', 'graphic art'
410
- // ],
411
- // category: 'Visual & Creative Design'
412
- // },
413
- // algorithmic_art: {
414
- // skillId: 'algorithmic-art',
415
- // keywords: [
416
- // 'generative art', 'algorithmic art', 'p5.js', 'particle system',
417
- // 'flow field', 'creative coding', 'code art'
418
- // ],
419
- // category: 'Visual & Creative Design'
420
- // },
421
- // theme_factory: {
422
- // skillId: 'theme-factory',
423
- // keywords: [
424
- // 'theme', 'color scheme', 'font theme', 'styling theme',
425
- // 'consistent theme', 'apply theme', 'theme colors'
426
- // ],
427
- // category: 'Visual & Creative Design'
428
- // },
429
- // brand_guidelines: {
430
- // skillId: 'brand-guidelines',
431
- // keywords: [
432
- // 'brand colors', 'brand guidelines', 'anthropic brand',
433
- // 'official brand', 'brand styling'
434
- // ],
435
- // category: 'Visual & Creative Design'
436
- // },
437
- // slack_gif_creator: {
438
- // skillId: 'slack-gif-creator',
439
- // keywords: [
440
- // 'slack gif', 'animated gif', 'gif for slack', 'slack animation'
441
- // ],
442
- // category: 'Visual & Creative Design'
443
- // },
444
- // mcp_builder: {
445
- // skillId: 'mcp-builder',
446
- // keywords: [
447
- // 'mcp server', 'model context protocol', 'create mcp',
448
- // 'mcp integration', 'external api integration'
449
- // ],
450
- // category: 'Development & Integration'
451
- // },
452
- // skill_creator: {
453
- // skillId: 'skill-creator',
454
- // keywords: [
455
- // 'create skill', 'new skill', 'skill development',
456
- // 'extend capabilities', 'custom skill'
457
- // ],
458
- // category: 'Development & Integration'
459
- // },
460
- // doc_coauthoring: {
461
- // skillId: 'doc-coauthoring',
462
- // keywords: [
463
- // 'documentation', 'technical docs', 'write documentation',
464
- // 'coauthor', 'doc writing', 'technical writing'
465
- // ],
466
- // category: 'Communication & Documentation'
467
- // }
468
- // };
469
-
470
- // ============================================================
471
- // SkillInvoker Main Class
472
- // ============================================================
473
-
474
- export class SkillInvoker {
475
- private skillLoader: SkillLoader;
476
- private initialized: boolean = false;
477
- private skillCache: Map<string, SkillInfo> = new Map(); // Stores metadata only
478
- private skillContentCache: Map<string, string> = new Map(); // Stores full SKILL.md content
479
-
480
- constructor(skillLoader?: SkillLoader) {
481
- this.skillLoader = skillLoader || getSkillLoader();
482
- }
483
-
484
- async initialize(): Promise<void> {
485
- if (this.initialized) return;
486
-
487
- // Use discoverSkills to only discover directories without loading full content
488
- const skillIds = await this.skillLoader.discoverSkills();
489
-
490
- // Create minimal SkillInfo objects with metadata only
491
- for (const skillId of skillIds) {
492
- const skillPath = this.skillLoader.getSkillDirectory?.(skillId) || '';
493
- const skillInfo: SkillInfo = {
494
- id: skillId,
495
- name: skillId,
496
- description: '', // Will be loaded lazily
497
- license: 'Unknown',
498
- version: '1.0.0',
499
- author: 'Anonymous',
500
- category: '',
501
- markdown: '', // Full content loaded lazily
502
- skillsPath: skillPath
503
- };
504
- this.skillCache.set(skillId, skillInfo);
505
- }
506
-
507
- this.initialized = true;
508
- }
509
-
510
- /**
511
- * Load skill metadata (name, description, category) from SKILL.md frontmatter
512
- * This is called lazily when skill details are needed
513
- */
514
- async loadSkillMetadata(skillId: string): Promise<void> {
515
- const skill = this.skillCache.get(skillId);
516
- if (!skill) return;
517
-
518
- // Check if metadata already loaded
519
- if (skill.description && skill.category) return;
520
-
521
- const skillPath = skill.skillsPath;
522
- const skillMdPath = path.join(skillPath, 'SKILL.md');
523
-
524
- try {
525
- const content = await fs.readFile(skillMdPath, 'utf-8');
526
- const parsed = this.skillLoader.parseSkillMarkdown(content);
527
-
528
- skill.name = parsed.name || skillId;
529
- skill.description = parsed.description || '';
530
- skill.license = parsed.license || 'Unknown';
531
- skill.version = parsed.version || '1.0.0';
532
- skill.author = parsed.author || 'Anonymous';
533
-
534
- // Extract category from path
535
- const pathParts = skillPath.split(path.sep);
536
- const skillsIndex = pathParts.findIndex(p => p === 'skills');
537
- if (skillsIndex >= 0 && pathParts.length > skillsIndex + 1) {
538
- skill.category = pathParts[skillsIndex + 1];
539
- }
540
-
541
- skill.markdown = content; // Now we have the full content
542
- this.skillContentCache.set(skillId, content);
543
- } catch (error) {
544
- console.warn(`[SkillInvoker] Failed to load metadata for skill ${skillId}:`, error);
545
- }
546
- }
547
-
548
- /**
549
- * Get list of all available skills (with metadata)
550
- */
551
- async listAvailableSkills(): Promise<SkillInfo[]> {
552
- await this.initialize();
553
-
554
- // Load metadata for all skills if not already loaded
555
- for (const skillId of this.skillCache.keys()) {
556
- await this.loadSkillMetadata(skillId);
557
- }
558
-
559
- return Array.from(this.skillCache.values());
560
- }
561
-
562
- /**
563
- * Match the most relevant skill based on user input
564
- * NOTE: SKILL_TRIGGERS disabled. Let LLM decide based on system prompt.
565
- * Returns null to indicate no explicit match - LLM should use its own judgment.
566
- */
567
- async matchSkill(userInput: string): Promise<SkillMatcherResult | null> {
568
- // SKILL_TRIGGERS is disabled for experiment purposes.
569
- // The LLM should decide which skill to use based on system prompt information.
570
- return null;
571
- }
572
-
573
- /**
574
- * Get skill details
575
- */
576
- async getSkillDetails(skillId: string): Promise<SkillInfo | null> {
577
- await this.initialize();
578
- return this.skillLoader.getSkill(skillId) || null;
579
- }
580
-
581
- /**
582
- * Execute skill
583
- */
584
- async executeSkill(params: SkillExecutionParams): Promise<SkillExecutionResult> {
585
- // Ensure initialized
586
- await this.initialize();
587
-
588
- // Load skill metadata if not already loaded
589
- await this.loadSkillMetadata(params.skillId);
590
-
591
- const skill = this.skillCache.get(params.skillId);
592
-
593
- if (!skill) {
594
- return {
595
- success: false,
596
- error: `Skill not found: ${params.skillId}`
597
- };
598
- }
599
-
600
- // Generate task ID (if not provided)
601
- const taskId = params.taskId || `${params.skillId}-${Date.now()}`;
602
-
603
- try {
604
- // Execute based on skillId
605
- const executor = this.getSkillExecutor(skill.id);
606
- const result = await executor.execute(skill, { ...params, taskId });
607
-
608
- // Add workspaceDir to result
609
- if (result.success && result.nextSteps && result.nextSteps.length > 0) {
610
- result.workspaceDir = getWorkspaceDir(taskId);
611
- await ensureWorkspaceDir(result.workspaceDir);
612
- }
613
-
614
- return result;
615
- } catch (error: any) {
616
- return {
617
- success: false,
618
- error: error.message
619
- };
620
- }
621
- }
622
-
623
- /**
624
- * Clean up workspace based on execution result
625
- * @param result Skill execution result
626
- * @param executionMode Execution mode
627
- * @returns Whether cleanup was performed
628
- */
629
- async cleanupAfterExecution(result: SkillExecutionResult, executionMode: ExecutionMode): Promise<boolean> {
630
- if (!result.workspaceDir) {
631
- return false;
632
- }
633
-
634
- // YOLO mode: auto cleanup
635
- if (executionMode === ExecutionMode.YOLO) {
636
- await cleanupWorkspace(result.workspaceDir, result.preserveFiles || []);
637
- return true;
638
- }
639
-
640
- // Other modes: don't auto cleanup, let user decide
641
- return false;
642
- }
643
-
644
- /**
645
- * Get cleanup prompt (for asking user)
646
- */
647
- async getCleanupPrompt(result: SkillExecutionResult): Promise<string | null> {
648
- if (!result.workspaceDir) {
649
- return null;
650
- }
651
-
652
- const info = await getCleanupInfo(result.workspaceDir);
653
- if (info.files.length === 0) {
654
- return null;
655
- }
656
-
657
- return `Task completed! Workspace directory contains the following files:\n` +
658
- `📁 ${result.workspaceDir}\n` +
659
- `Files: ${info.files.join(', ')}\n` +
660
- `Size: ${info.totalSize}\n\n` +
661
- `Do you want to clean up these temporary files?`;
662
- }
663
-
664
- /**
665
- * Get executor for skill
666
- * Unified dynamic approach - all skills use GenericSkillExecutor
667
- */
668
- private getSkillExecutor(skillId: string): SkillExecutor {
669
- return new GenericSkillExecutor();
670
- }
671
-
672
- // ============================================================================
673
- // Remote Mode Tool Support Methods
674
- // ============================================================================
675
-
676
- /**
677
- * Check if it's a Skill tool
678
- * Used for remote mode tool execution
679
- */
680
- isSkillTool(toolName: string): boolean {
681
- // Check if it's a skill ID in cache
682
- return this.skillCache.has(toolName);
683
- }
684
-
685
- /**
686
- * Get all Skill definitions (for syncing to remote server)
687
- * NOTE: triggers field is empty since SKILL_TRIGGERS is disabled
688
- */
689
- getAllSkillDefinitions(): Array<{
690
- id: string;
691
- name: string;
692
- description: string;
693
- category: string;
694
- triggers: string[];
695
- }> {
696
- const definitions: Array<{
697
- id: string;
698
- name: string;
699
- description: string;
700
- category: string;
701
- triggers: string[];
702
- }> = [];
703
-
704
- for (const skill of this.skillCache.values()) {
705
- definitions.push({
706
- id: skill.id,
707
- name: skill.name,
708
- description: skill.description,
709
- category: skill.category,
710
- triggers: [] // SKILL_TRIGGERS disabled - LLM decides based on description
711
- });
712
- }
713
-
714
- return definitions;
715
- }
716
-
717
- /**
718
- * Execute Skill tool (for remote mode tool execution)
719
- * @param toolName - Tool name (skillId)
720
- * @param params - Tool parameters
721
- * @returns Execution result
722
- */
723
- async executeSkillTool(
724
- toolName: string,
725
- params: Record<string, any>
726
- ): Promise<{ success: boolean; result?: any; error?: string }> {
727
- // Check if skill exists in cache
728
- if (!this.skillCache.has(toolName)) {
729
- return { success: false, error: `Skill not found: ${toolName}` };
730
- }
731
-
732
- try {
733
- const result = await this.executeSkill({
734
- skillId: toolName,
735
- taskDescription: params.taskDescription || params.description || '',
736
- inputFile: params.inputFile,
737
- outputFile: params.outputFile,
738
- options: params.options || {}
739
- });
740
-
741
- return { success: result.success, result };
742
- } catch (error: any) {
743
- return { success: false, error: error.message };
744
- }
745
- }
746
-
747
- /**
748
- * Get all available Skill ID list
749
- * NOTE: SKILL_TRIGGERS disabled - return all skill IDs from cache
750
- */
751
- getAvailableSkillIds(): string[] {
752
- return Array.from(this.skillCache.keys());
753
- }
754
- }
755
-
756
- // ============================================================
757
- // Skill Executor Interface and Implementation
758
- // ============================================================
759
-
760
- interface SkillExecutor {
761
- execute(skill: SkillInfo, params: SkillExecutionParams): Promise<SkillExecutionResult>;
762
- }
763
-
764
- /**
765
- * Generic Skill Executor - Unified dynamic approach for all skills
766
- */
767
- class GenericSkillExecutor implements SkillExecutor {
768
- async execute(skill: SkillInfo, params: SkillExecutionParams): Promise<SkillExecutionResult> {
769
- const outputMessages: string[] = [];
770
- const files: string[] = [];
771
- const nextSteps: ExecutionStep[] = [];
772
-
773
- outputMessages.push(`## ${skill.name} Skill - Execution Guide\n`);
774
- outputMessages.push(`**Task**: ${params.taskDescription}\n`);
775
-
776
- try {
777
- // Generate task ID
778
- const taskId = params.taskId || `${skill.id}-${Date.now()}`;
779
-
780
- // Read complete skill documentation
781
- const skillPath = skill.skillsPath;
782
- const skillMdPath = path.join(skillPath, 'SKILL.md');
783
- files.push(skillMdPath);
784
-
785
- // Read SKILL.md content
786
- const skillContent = await fs.readFile(skillMdPath, 'utf-8');
787
-
788
- // Extract relevant content based on task type and generate execution steps
789
- const taskContent = await this.extractRelevantContent(skill, params, skillContent, nextSteps, taskId);
790
- outputMessages.push(taskContent);
791
-
792
- // Add input/output files to list if they exist
793
- if (params.inputFile) files.push(params.inputFile);
794
- if (params.outputFile) files.push(params.outputFile);
795
-
796
- return {
797
- success: true,
798
- output: outputMessages.join('\n'),
799
- files: files,
800
- nextSteps: nextSteps,
801
- requiresManualExecution: true
802
- };
803
- } catch (error: any) {
804
- return {
805
- success: false,
806
- error: error.message
807
- };
808
- }
809
- }
810
-
811
- /**
812
- * Extract relevant skill content dynamically
813
- */
814
- private async extractRelevantContent(
815
- skill: SkillInfo,
816
- params: SkillExecutionParams,
817
- fullContent: string,
818
- nextSteps: ExecutionStep[],
819
- taskId: string
820
- ): Promise<string> {
821
- const workspaceBase = getWorkspaceDescription();
822
- const taskWorkspace = `${workspaceBase}/${taskId}`;
823
-
824
- // Dynamically discover files in skill directory
825
- const skillPath = skill.skillsPath;
826
- let allFiles: string[] = [];
827
-
828
- try {
829
- const entries = await fs.readdir(skillPath, { withFileTypes: true });
830
- for (const entry of entries) {
831
- const fullPath = path.join(skillPath, entry.name);
832
- if (entry.isFile()) {
833
- allFiles.push(fullPath);
834
- } else if (entry.isDirectory()) {
835
- // Recursively list files in subdirectories (limited depth)
836
- const subEntries = await fs.readdir(fullPath, { withFileTypes: true });
837
- for (const subEntry of subEntries) {
838
- if (subEntry.isFile()) {
839
- allFiles.push(path.join(fullPath, subEntry.name));
840
- }
841
- }
842
- }
843
- }
844
- } catch {
845
- // Fallback to just SKILL.md if directory can't be read
846
- allFiles = [path.join(skillPath, 'SKILL.md')];
847
- }
848
-
849
- // Step 1: Read SKILL.md first
850
- const skillMdPathOnly = path.join(skillPath, 'SKILL.md');
851
- nextSteps.push({
852
- step: 1,
853
- action: 'Read SKILL.md to understand the skill workflow',
854
- description: `Read: ${skillMdPathOnly}`,
855
- reason: 'Understand the skill workflow and best practices from the main documentation'
856
- });
857
-
858
- // Step 2: Explore skill directory and read reference files if needed (optional)
859
- nextSteps.push({
860
- step: 2,
861
- action: 'Explore skill directory and read reference files (if needed)',
862
- description: `Explore: ${skillPath}`,
863
- reason: 'Discover available reference files and read them based on SKILL.md guidance'
864
- });
865
-
866
- nextSteps.push({
867
- step: 3,
868
- action: 'Analyze documentation, verify data/content completeness, and design approach',
869
- description: `For content creation: ensure all info/materials collected. For info retrieval: ensure all required data retrieved. Then design execution plan for: ${taskWorkspace}`,
870
- reason: 'Review requirements, verify data/content completeness, fill gaps if needed, then plan execution based on the documentation'
871
- });
872
-
873
- nextSteps.push({
874
- step: 4,
875
- action: 'Execute your plan',
876
- description: 'Create workspace, write code, run scripts, verify output',
877
- reason: 'Execute the task using your own understanding'
878
- });
879
-
880
- return `### Skill Execution\n\n` +
881
- `**Your task**: ${params.taskDescription}\n\n` +
882
- `**Step 1**: Read SKILL.md to understand the skill workflow\n` +
883
- ` - read_file: ${skillMdPathOnly}\n\n` +
884
- `**Step 2**: Explore skill directory and read reference files (if needed)\n` +
885
- ` - ListDirectory(path="${skillPath}")\n` +
886
- ` - read_file relevant .md and script files as needed\n\n` +
887
- `Then analyze the documentation and create your own execution plan.\n\n` +
888
- `**Workspace**: \`${taskWorkspace}\`\n\n` +
889
- `**⚠️ Windows Path Execution**: Use absolute paths, NOT \`cd && command\`:\n` +
890
- ` - ✅ Correct: \`node "${taskWorkspace}/script.js"\`\n` +
891
- ` - ❌ Wrong: \`cd "${taskWorkspace}" && node script.js\` (fails in PowerShell 5.1)\n` +
892
- ` - ✅ Correct: \`python "${taskWorkspace}/script.py"\`\n\n` +
893
- `**📦 Dependency Management**:\n` +
894
- ` - BashTool automatically sets NODE_PATH when executing, scripts can use require() directly\n` +
895
- ` - Correct: Bash(command="node script.js", cwd="${taskWorkspace}")\n` +
896
- ` - ❌ Wrong: cd "${taskWorkspace}" && node script.js (loses NODE_PATH!)\n` +
897
- ` - If script needs to run by user manually, pass NODE_PATH in command:\n` +
898
- ` Windows: set NODE_PATH=xAgent/node_modules/path && node script.js\n` +
899
- ` Linux/Mac: NODE_PATH=xAgent/node_modules/path node script.js\n\n` +
900
- `**🧹 Cleanup**: Delete all intermediate/temporary files when task completes:\n` +
901
- ` - Remove: all files generated during the task\n` +
902
- ` - Keep: Only the final output file (output.pptx/docx/xlsx/pdf)\n\n` +
903
- `**Instructions**: read_file the documentation, understand the API, and create your own execution plan.\n` +
904
- `**If you encounter issues**: Explain what went wrong and suggest a different approach.\n`;
905
- }
906
- }
907
- // ============================================================
908
- // ============================================================
909
-
910
- /**
911
- * Execute skill - LLM analyzes SKILL.md and generates its own steps
912
- * @param skill Skill to execute
913
- * @param params Execution parameters
914
- * @returns Execution result with guidance
915
- */
916
- export async function executeSkill(
917
- skill: SkillInfo,
918
- params: SkillExecutionParams
919
- ): Promise<SkillExecutionResult> {
920
- const executor = new GenericSkillExecutor();
921
- return executor.execute(skill, params);
922
- }
923
-
924
- // ============================================================
925
- // Singleton Instance and Exports
926
- // ============================================================
927
-
928
- let skillInvokerInstance: SkillInvoker | null = null;
929
-
930
- export function getSkillInvoker(): SkillInvoker {
931
- if (!skillInvokerInstance) {
932
- skillInvokerInstance = new SkillInvoker();
933
- }
934
- return skillInvokerInstance;
935
- }
1
+ import fs from 'fs/promises';
2
+ import path from 'path';
3
+ import os from 'os';
4
+ import { getSkillLoader, SkillInfo, SkillLoader } from './skill-loader.js';
5
+ import { ExecutionMode } from './types.js';
6
+ import { getConfigManager } from './config.js';
7
+
8
+ // Re-export SkillInfo for other modules
9
+ export type { SkillInfo };
10
+
11
+ /**
12
+ * Track skill execution history for tracking failures
13
+ */
14
+ export class SkillExecutionHistory {
15
+ private history: Map<string, number> = new Map();
16
+
17
+ /**
18
+ * Get failure count for a task
19
+ */
20
+ getFailureCount(taskKey: string): number {
21
+ return this.history.get(taskKey) || 0;
22
+ }
23
+
24
+ /**
25
+ * Increment failure count for a task
26
+ */
27
+ incrementFailure(taskKey: string): number {
28
+ const count = this.getFailureCount(taskKey) + 1;
29
+ this.history.set(taskKey, count);
30
+ return count;
31
+ }
32
+
33
+ /**
34
+ * Reset failure count for a task (e.g., after success)
35
+ */
36
+ reset(taskKey: string): void {
37
+ this.history.delete(taskKey);
38
+ }
39
+
40
+ /**
41
+ * Check if threshold reached
42
+ */
43
+ shouldUseFallback(taskKey: string, threshold: number = 2): boolean {
44
+ return this.getFailureCount(taskKey) >= threshold;
45
+ }
46
+ }
47
+
48
+ // Singleton execution history
49
+ const executionHistory = new SkillExecutionHistory();
50
+
51
+ export function getExecutionHistory(): SkillExecutionHistory {
52
+ return executionHistory;
53
+ }
54
+
55
+ export interface SkillExecutionParams {
56
+ skillId: string;
57
+ taskDescription: string;
58
+ inputFile?: string;
59
+ outputFile?: string;
60
+ options?: Record<string, any>;
61
+ /** Task ID for workspace directory naming */
62
+ taskId?: string;
63
+ }
64
+
65
+ /**
66
+ * Execution step interface - tells Agent what to do next
67
+ */
68
+ export interface ExecutionStep {
69
+ step: number;
70
+ action: string;
71
+ description: string;
72
+ command?: string;
73
+ file?: string;
74
+ reason: string;
75
+ }
76
+
77
+ /**
78
+ * Skill execution result - contains guidance and next actions
79
+ */
80
+ export interface SkillExecutionResult {
81
+ success: boolean;
82
+ output?: string;
83
+ error?: string;
84
+ files?: string[];
85
+ /** Tells Agent what to do next */
86
+ nextSteps?: ExecutionStep[];
87
+ /** Skill type for determining if manual execution is needed */
88
+ requiresManualExecution?: boolean;
89
+ /** Workspace directory used, for cleanup */
90
+ workspaceDir?: string;
91
+ /** Files to preserve (relative paths), skipped during cleanup */
92
+ preserveFiles?: string[];
93
+ /** Skill directory path - for dependency management and file operations */
94
+ skillPath?: string;
95
+ }
96
+
97
+ export interface SkillMatcherResult {
98
+ skill: SkillInfo;
99
+ confidence: number;
100
+ matchedKeywords: string[];
101
+ category: string;
102
+ }
103
+
104
+ // ============================================================
105
+ // Workspace Utility Functions
106
+ // ============================================================
107
+
108
+ /**
109
+ * Get workspace directory path
110
+ * @param taskId Task ID for creating unique workspace directory
111
+ * @returns Absolute path to workspace directory
112
+ */
113
+ export function getWorkspaceDir(taskId: string): string {
114
+ // Try to get from config first
115
+ try {
116
+ const configManager = getConfigManager();
117
+ const config = configManager.getSettings?.();
118
+ if (config?.workspacePath) {
119
+ return path.join(config.workspacePath, taskId);
120
+ }
121
+ } catch {
122
+ // Config not available, use default
123
+ }
124
+
125
+ // Default to ~/.xagent/workspace
126
+ return path.join(os.homedir(), '.xagent', 'workspace', taskId);
127
+ }
128
+
129
+ /**
130
+ * Get base workspace directory (without task-id)
131
+ */
132
+ export function getBaseWorkspaceDir(): string {
133
+ try {
134
+ const configManager = getConfigManager();
135
+ const config = configManager.getSettings?.();
136
+ if (config?.workspacePath) {
137
+ return config.workspacePath;
138
+ }
139
+ } catch {
140
+ // Config not available, use default
141
+ }
142
+
143
+ return path.join(os.homedir(), '.xagent', 'workspace');
144
+ }
145
+
146
+ /**
147
+ * Get workspace directory description for AI
148
+ * Returns the actual workspace path from config, or default path
149
+ */
150
+ export function getWorkspaceDescription(): string {
151
+ try {
152
+ const configManager = getConfigManager();
153
+ const config = configManager.getSettings?.();
154
+ if (config?.workspacePath) {
155
+ return config.workspacePath;
156
+ }
157
+ } catch {
158
+ // Config not available, use default
159
+ }
160
+
161
+ return path.join(os.homedir(), '.xagent', 'workspace');
162
+ }
163
+
164
+ /**
165
+ * Ensure workspace directory exists
166
+ * @param workspaceDir Workspace directory path
167
+ */
168
+ export async function ensureWorkspaceDir(workspaceDir: string): Promise<void> {
169
+ await fs.mkdir(workspaceDir, { recursive: true });
170
+ }
171
+
172
+ /**
173
+ * Clean up workspace directory
174
+ * @param workspaceDir Workspace directory path
175
+ * @param preserveFiles Files to preserve (relative paths)
176
+ */
177
+ export async function cleanupWorkspace(workspaceDir: string, preserveFiles: string[] = []): Promise<void> {
178
+ try {
179
+ const entries = await fs.readdir(workspaceDir, { withFileTypes: true });
180
+
181
+ for (const entry of entries) {
182
+ const fullPath = path.join(workspaceDir, entry.name);
183
+
184
+ // Skip files to preserve
185
+ if (preserveFiles.includes(entry.name)) {
186
+ continue;
187
+ }
188
+
189
+ if (entry.isDirectory()) {
190
+ // Recursively delete subdirectories
191
+ await fs.rm(fullPath, { recursive: true, force: true });
192
+ } else {
193
+ // Delete files
194
+ await fs.unlink(fullPath);
195
+ }
196
+ }
197
+ } catch (error: any) {
198
+ if (error.code !== 'ENOENT') {
199
+ console.warn(`Workspace cleanup failed: ${error.message}`);
200
+ }
201
+ }
202
+ }
203
+
204
+ /**
205
+ * Determine if workspace should be auto-cleaned based on ExecutionMode
206
+ * @param executionMode Execution mode
207
+ * @returns Whether auto-cleanup should happen
208
+ */
209
+ export function shouldAutoCleanup(executionMode: ExecutionMode): boolean {
210
+ // YOLO mode: fully automatic, clean up directly
211
+ if (executionMode === ExecutionMode.YOLO) {
212
+ return true;
213
+ }
214
+ // Other modes require user confirmation
215
+ return false;
216
+ }
217
+
218
+ /**
219
+ * Generate cleanup prompt message
220
+ * @param workspaceDir Workspace directory path
221
+ */
222
+ export async function getCleanupInfo(workspaceDir: string): Promise<{ files: string[]; totalSize: string }> {
223
+ try {
224
+ const entries = await fs.readdir(workspaceDir, { withFileTypes: true });
225
+ const files: string[] = [];
226
+
227
+ for (const entry of entries) {
228
+ files.push(entry.name);
229
+ }
230
+
231
+ // Calculate total size
232
+ let totalSize = 0;
233
+ for (const entry of entries) {
234
+ if (entry.isFile()) {
235
+ const stats = await fs.stat(path.join(workspaceDir, entry.name));
236
+ totalSize += stats.size;
237
+ }
238
+ }
239
+
240
+ const formatSize = (bytes: number): string => {
241
+ if (bytes < 1024) return `${bytes} B`;
242
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(2)} KB`;
243
+ return `${(bytes / (1024 * 1024)).toFixed(2)} MB`;
244
+ };
245
+
246
+ return { files, totalSize: formatSize(totalSize) };
247
+ } catch {
248
+ return { files: [], totalSize: '0 B' };
249
+ }
250
+ }
251
+
252
+ // ============================================================
253
+ // Shared Content Extraction Utilities
254
+ // ============================================================
255
+
256
+ /**
257
+ * Remove Markdown formatting (bold, italic, etc.)
258
+ */
259
+ export function stripMarkdown(text: string): string {
260
+ return text
261
+ .replace(/\*\*(.+?)\*\*/g, '$1') // Remove bold **
262
+ .replace(/\*(.+?)\*/g, '$1') // Remove italic *
263
+ .replace(/`(.+?)`/g, '$1') // Remove inline code `
264
+ .trim();
265
+ }
266
+
267
+ /**
268
+ * Extract content related to keywords (for SKILL.md content matching)
269
+ * @param content SKILL.md full content
270
+ * @param keywords Keyword list
271
+ * @param maxLength Maximum return length
272
+ * @returns Extracted relevant content
273
+ */
274
+ export function extractContent(content: string, keywords: string[], maxLength: number = 5000): string {
275
+ const lines = content.split('\n');
276
+ const relevantLines: string[] = [];
277
+ let inRelevantSection = false;
278
+ let sectionDepth = 0;
279
+ let found = false;
280
+
281
+ for (let i = 0; i < lines.length; i++) {
282
+ const line = lines[i];
283
+
284
+ // Detect headings
285
+ if (line.match(/^#{1,6}\s/)) {
286
+ const strippedLine = stripMarkdown(line);
287
+ const lowerLine = strippedLine.toLowerCase();
288
+
289
+ // Check if contains keywords
290
+ const hasKeyword = keywords.some(kw => lowerLine.includes(kw.toLowerCase()));
291
+
292
+ if (hasKeyword) {
293
+ inRelevantSection = true;
294
+ found = true;
295
+ sectionDepth = line.match(/^(#+)/)?.[1].length || 1;
296
+ } else if (inRelevantSection) {
297
+ // Check if same level or higher heading (end current section)
298
+ const currentDepth = line.match(/^(#+)/)?.[1].length || 1;
299
+ if (currentDepth <= sectionDepth) {
300
+ inRelevantSection = false;
301
+ }
302
+ }
303
+ }
304
+
305
+ if (inRelevantSection || found) {
306
+ relevantLines.push(line);
307
+ }
308
+
309
+ // Limit content length
310
+ if (relevantLines.join('\n').length > maxLength) {
311
+ relevantLines.push('\n...(content truncated for brevity)...');
312
+ break;
313
+ }
314
+ }
315
+
316
+ if (relevantLines.length > 0) {
317
+ return relevantLines.join('\n').trim();
318
+ }
319
+
320
+ // If still not found, return first 100 lines
321
+ return lines.slice(0, 100).join('\n').trim() + '\n\n...(See SKILL.md for full instructions)';
322
+ }
323
+
324
+ /**
325
+ * Read SKILL.md and extract relevant content based on task
326
+ */
327
+ export async function readSkillContent(skillPath: string, keywords: string[], maxLength: number = 5000): Promise<string> {
328
+ const skillMdPath = path.join(skillPath, 'SKILL.md');
329
+ const content = await fs.readFile(skillMdPath, 'utf-8');
330
+ return extractContent(content, keywords, maxLength);
331
+ }
332
+
333
+ // ============================================================
334
+ // SKILL Trigger Keywords Mapping
335
+ // ============================================================
336
+
337
+ // NOTE: SKILL_TRIGGERS is disabled for experiment purposes.
338
+ // Let the LLM decide which skill to use based on system prompt information.
339
+
340
+ // interface SkillTrigger {
341
+ // skillId: string;
342
+ // keywords: string[];
343
+ // category: string;
344
+ // }
345
+
346
+ // export const SKILL_TRIGGERS: Record<string, SkillTrigger> = {
347
+ // docx: {
348
+ // skillId: 'docx',
349
+ // keywords: [
350
+ // 'word document', 'docx', 'microsoft word', 'create word', 'edit word',
351
+ // 'create .docx', '.docx file', 'word file', 'document creation',
352
+ // 'word editing', 'tracked changes', 'comments'
353
+ // ],
354
+ // category: 'Document Processing'
355
+ // },
356
+ // pdf: {
357
+ // skillId: 'pdf',
358
+ // keywords: [
359
+ // 'pdf', 'create pdf', 'edit pdf', 'pdf document', 'pdf file',
360
+ // 'extract pdf', 'merge pdf', 'split pdf', 'pdf form', 'manipulate pdf'
361
+ // ],
362
+ // category: 'Document Processing'
363
+ // },
364
+ // pptx: {
365
+ // skillId: 'pptx',
366
+ // keywords: [
367
+ // 'powerpoint', 'ppt', 'pptx', 'presentation', 'slide',
368
+ // 'create presentation', 'edit powerpoint', 'create slides',
369
+ // 'powerpoint file', 'presentation file'
370
+ // ],
371
+ // category: 'Document Processing'
372
+ // },
373
+ // xlsx: {
374
+ // skillId: 'xlsx',
375
+ // keywords: [
376
+ // 'excel', 'spreadsheet', 'xlsx', 'create excel', 'edit spreadsheet',
377
+ // 'excel file', 'spreadsheet file', 'formulas', 'data analysis'
378
+ // ],
379
+ // category: 'Spreadsheet & Data'
380
+ // },
381
+ // frontend_design: {
382
+ // skillId: 'frontend-design',
383
+ // keywords: [
384
+ // 'web page', 'website', 'web app', 'frontend', 'ui', 'user interface',
385
+ // 'create website', 'build website', 'web component', 'html css',
386
+ // 'landing page', 'dashboard', 'react', 'vue', 'web interface'
387
+ // ],
388
+ // category: 'Frontend & Web Development'
389
+ // },
390
+ // web_artifacts_builder: {
391
+ // skillId: 'web-artifacts-builder',
392
+ // keywords: [
393
+ // 'complex react', 'react artifact', 'stateful artifact', 'routing',
394
+ // 'web artifact', 'interactive artifact', 'web-based tool'
395
+ // ],
396
+ // category: 'Frontend & Web Development'
397
+ // },
398
+ // webapp_testing: {
399
+ // skillId: 'webapp-testing',
400
+ // keywords: [
401
+ // 'test web', 'web testing', 'browser test', 'playwright', 'e2e test',
402
+ // 'frontend test', 'capture screenshot', 'verify web'
403
+ // ],
404
+ // category: 'Frontend & Web Development'
405
+ // },
406
+ // canvas_design: {
407
+ // skillId: 'canvas-design',
408
+ // keywords: [
409
+ // 'poster', 'artwork', 'visual art', 'canvas', 'design art',
410
+ // 'create poster', 'create artwork', 'visual design', 'graphic art'
411
+ // ],
412
+ // category: 'Visual & Creative Design'
413
+ // },
414
+ // algorithmic_art: {
415
+ // skillId: 'algorithmic-art',
416
+ // keywords: [
417
+ // 'generative art', 'algorithmic art', 'p5.js', 'particle system',
418
+ // 'flow field', 'creative coding', 'code art'
419
+ // ],
420
+ // category: 'Visual & Creative Design'
421
+ // },
422
+ // theme_factory: {
423
+ // skillId: 'theme-factory',
424
+ // keywords: [
425
+ // 'theme', 'color scheme', 'font theme', 'styling theme',
426
+ // 'consistent theme', 'apply theme', 'theme colors'
427
+ // ],
428
+ // category: 'Visual & Creative Design'
429
+ // },
430
+ // brand_guidelines: {
431
+ // skillId: 'brand-guidelines',
432
+ // keywords: [
433
+ // 'brand colors', 'brand guidelines', 'anthropic brand',
434
+ // 'official brand', 'brand styling'
435
+ // ],
436
+ // category: 'Visual & Creative Design'
437
+ // },
438
+ // slack_gif_creator: {
439
+ // skillId: 'slack-gif-creator',
440
+ // keywords: [
441
+ // 'slack gif', 'animated gif', 'gif for slack', 'slack animation'
442
+ // ],
443
+ // category: 'Visual & Creative Design'
444
+ // },
445
+ // mcp_builder: {
446
+ // skillId: 'mcp-builder',
447
+ // keywords: [
448
+ // 'mcp server', 'model context protocol', 'create mcp',
449
+ // 'mcp integration', 'external api integration'
450
+ // ],
451
+ // category: 'Development & Integration'
452
+ // },
453
+ // skill_creator: {
454
+ // skillId: 'skill-creator',
455
+ // keywords: [
456
+ // 'create skill', 'new skill', 'skill development',
457
+ // 'extend capabilities', 'custom skill'
458
+ // ],
459
+ // category: 'Development & Integration'
460
+ // },
461
+ // doc_coauthoring: {
462
+ // skillId: 'doc-coauthoring',
463
+ // keywords: [
464
+ // 'documentation', 'technical docs', 'write documentation',
465
+ // 'coauthor', 'doc writing', 'technical writing'
466
+ // ],
467
+ // category: 'Communication & Documentation'
468
+ // }
469
+ // };
470
+
471
+ // ============================================================
472
+ // SkillInvoker Main Class
473
+ // ============================================================
474
+
475
+ export class SkillInvoker {
476
+ private skillLoader: SkillLoader;
477
+ private initialized: boolean = false;
478
+ private skillCache: Map<string, SkillInfo> = new Map(); // Stores metadata only
479
+ // private skillContentCache: Map<string, string> = new Map(); // Stores full SKILL.md content - UNUSED
480
+
481
+ constructor(skillLoader?: SkillLoader) {
482
+ this.skillLoader = skillLoader || getSkillLoader();
483
+ }
484
+
485
+ async initialize(): Promise<void> {
486
+ if (this.initialized) return;
487
+
488
+ // Use discoverSkills to only discover directories without loading full content
489
+ const skillIds = await this.skillLoader.discoverSkills();
490
+
491
+ // Create minimal SkillInfo objects with metadata only
492
+ for (const skillId of skillIds) {
493
+ const skillPath = this.skillLoader.getSkillDirectory?.(skillId) || '';
494
+ const skillInfo: SkillInfo = {
495
+ id: skillId,
496
+ name: skillId,
497
+ description: '', // Will be loaded lazily
498
+ license: 'Unknown',
499
+ version: '1.0.0',
500
+ author: 'Anonymous',
501
+ category: '',
502
+ markdown: '', // Full content loaded lazily
503
+ skillsPath: skillPath
504
+ };
505
+ this.skillCache.set(skillId, skillInfo);
506
+ }
507
+
508
+ this.initialized = true;
509
+ }
510
+
511
+ /**
512
+ * Load skill metadata (name, description, category) from SKILL.md frontmatter
513
+ * This is called lazily when skill details are needed
514
+ */
515
+ async loadSkillMetadata(skillId: string): Promise<void> {
516
+ const skill = this.skillCache.get(skillId);
517
+ if (!skill) return;
518
+
519
+ // Check if metadata already loaded
520
+ if (skill.description && skill.category) return;
521
+
522
+ const skillPath = skill.skillsPath;
523
+ const skillMdPath = path.join(skillPath, 'SKILL.md');
524
+
525
+ try {
526
+ const content = await fs.readFile(skillMdPath, 'utf-8');
527
+ const parsed = this.skillLoader.parseSkillMarkdown(content);
528
+
529
+ skill.name = parsed.name || skillId;
530
+ skill.description = parsed.description || '';
531
+ skill.license = parsed.license || 'Unknown';
532
+ skill.version = parsed.version || '1.0.0';
533
+ skill.author = parsed.author || 'Anonymous';
534
+
535
+ // Extract category from path
536
+ const pathParts = skillPath.split(path.sep);
537
+ const skillsIndex = pathParts.findIndex(p => p === 'skills');
538
+ if (skillsIndex >= 0 && pathParts.length > skillsIndex + 1) {
539
+ skill.category = pathParts[skillsIndex + 1];
540
+ }
541
+
542
+ skill.markdown = content; // Now we have the full content
543
+ // this.skillContentCache.set(skillId, content); // UNUSED
544
+ } catch (error) {
545
+ console.warn(`[SkillInvoker] Failed to load metadata for skill ${skillId}:`, error);
546
+ }
547
+ }
548
+
549
+ /**
550
+ * Get list of all available skills (with metadata)
551
+ */
552
+ async listAvailableSkills(): Promise<SkillInfo[]> {
553
+ await this.initialize();
554
+
555
+ // Load metadata for all skills if not already loaded
556
+ for (const skillId of this.skillCache.keys()) {
557
+ await this.loadSkillMetadata(skillId);
558
+ }
559
+
560
+ return Array.from(this.skillCache.values());
561
+ }
562
+
563
+ /**
564
+ * Reload all skills (e.g., after adding/removing a skill via CLI)
565
+ * Clears the cache and re-discovers all skills
566
+ */
567
+ async reload(): Promise<void> {
568
+ // Reset initialization state to allow re-discovery
569
+ this.initialized = false;
570
+ this.skillCache.clear();
571
+
572
+ // Re-initialize
573
+ await this.initialize();
574
+ }
575
+
576
+ /**
577
+ * Match the most relevant skill based on user input
578
+ * NOTE: SKILL_TRIGGERS disabled. Let LLM decide based on system prompt.
579
+ * Returns null to indicate no explicit match - LLM should use its own judgment.
580
+ */
581
+ async matchSkill(_userInput: string): Promise<SkillMatcherResult | null> {
582
+ // SKILL_TRIGGERS is disabled for experiment purposes.
583
+ // The LLM should decide which skill to use based on system prompt information.
584
+ return null;
585
+ }
586
+
587
+ /**
588
+ * Get skill details
589
+ */
590
+ async getSkillDetails(skillId: string): Promise<SkillInfo | null> {
591
+ await this.initialize();
592
+ return this.skillLoader.getSkill(skillId) || null;
593
+ }
594
+
595
+ /**
596
+ * Execute skill
597
+ */
598
+ async executeSkill(params: SkillExecutionParams): Promise<SkillExecutionResult> {
599
+ // Ensure initialized
600
+ await this.initialize();
601
+
602
+ // Load skill metadata if not already loaded
603
+ await this.loadSkillMetadata(params.skillId);
604
+
605
+ const skill = this.skillCache.get(params.skillId);
606
+
607
+ if (!skill) {
608
+ return {
609
+ success: false,
610
+ error: `Skill not found: ${params.skillId}`
611
+ };
612
+ }
613
+
614
+ // Generate task ID (if not provided)
615
+ const taskId = params.taskId || `${params.skillId}-${Date.now()}`;
616
+
617
+ try {
618
+ // Execute based on skillId
619
+ const executor = this.getSkillExecutor(skill.id);
620
+ const result = await executor.execute(skill, { ...params, taskId });
621
+
622
+ // Add skillPath and workspaceDir to result (delay creation until actually needed)
623
+ if (result.success) {
624
+ // Get skillPath directly from skillDirectories (more reliable)
625
+ result.skillPath = this.skillLoader.getSkillDirectory?.(params.skillId) || skill.skillsPath || '';
626
+ if (result.nextSteps && result.nextSteps.length > 0) {
627
+ result.workspaceDir = getWorkspaceDir(taskId);
628
+ // Don't pre-create workspace - only create when actually used by LLM
629
+ }
630
+ }
631
+
632
+ return result;
633
+ } catch (error: any) {
634
+ return {
635
+ success: false,
636
+ error: error.message
637
+ };
638
+ }
639
+ }
640
+
641
+ /**
642
+ * Clean up workspace based on execution result
643
+ * @param result Skill execution result
644
+ * @param executionMode Execution mode
645
+ * @returns Whether cleanup was performed
646
+ */
647
+ async cleanupAfterExecution(result: SkillExecutionResult, executionMode: ExecutionMode): Promise<boolean> {
648
+ if (!result.workspaceDir) {
649
+ return false;
650
+ }
651
+
652
+ // YOLO mode: auto cleanup
653
+ if (executionMode === ExecutionMode.YOLO) {
654
+ await cleanupWorkspace(result.workspaceDir, result.preserveFiles || []);
655
+ return true;
656
+ }
657
+
658
+ // Other modes: don't auto cleanup, let user decide
659
+ return false;
660
+ }
661
+
662
+ /**
663
+ * Get cleanup prompt (for asking user)
664
+ */
665
+ async getCleanupPrompt(result: SkillExecutionResult): Promise<string | null> {
666
+ if (!result.workspaceDir) {
667
+ return null;
668
+ }
669
+
670
+ const info = await getCleanupInfo(result.workspaceDir);
671
+ if (info.files.length === 0) {
672
+ return null;
673
+ }
674
+
675
+ return `Task completed! Workspace directory contains the following files:\n` +
676
+ `📁 ${result.workspaceDir}\n` +
677
+ `Files: ${info.files.join(', ')}\n` +
678
+ `Size: ${info.totalSize}\n\n` +
679
+ `Do you want to clean up these temporary files?`;
680
+ }
681
+
682
+ /**
683
+ * Get executor for skill
684
+ * Unified dynamic approach - all skills use GenericSkillExecutor
685
+ */
686
+ private getSkillExecutor(_skillId: string): SkillExecutor {
687
+ return new GenericSkillExecutor();
688
+ }
689
+
690
+ // ============================================================================
691
+ // Remote Mode Tool Support Methods
692
+ // ============================================================================
693
+
694
+ /**
695
+ * Check if it's a Skill tool
696
+ * Used for remote mode tool execution
697
+ */
698
+ isSkillTool(toolName: string): boolean {
699
+ // Check if it's a skill ID in cache
700
+ return this.skillCache.has(toolName);
701
+ }
702
+
703
+ /**
704
+ * Get all Skill definitions (for syncing to remote server)
705
+ * NOTE: triggers field is empty since SKILL_TRIGGERS is disabled
706
+ */
707
+ getAllSkillDefinitions(): Array<{
708
+ id: string;
709
+ name: string;
710
+ description: string;
711
+ category: string;
712
+ triggers: string[];
713
+ }> {
714
+ const definitions: Array<{
715
+ id: string;
716
+ name: string;
717
+ description: string;
718
+ category: string;
719
+ triggers: string[];
720
+ }> = [];
721
+
722
+ for (const skill of this.skillCache.values()) {
723
+ definitions.push({
724
+ id: skill.id,
725
+ name: skill.name,
726
+ description: skill.description,
727
+ category: skill.category,
728
+ triggers: [] // SKILL_TRIGGERS disabled - LLM decides based on description
729
+ });
730
+ }
731
+
732
+ return definitions;
733
+ }
734
+
735
+ /**
736
+ * Execute Skill tool (for remote mode tool execution)
737
+ * @param toolName - Tool name (skillId)
738
+ * @param params - Tool parameters
739
+ * @returns Execution result
740
+ */
741
+ async executeSkillTool(
742
+ toolName: string,
743
+ params: Record<string, any>
744
+ ): Promise<{ success: boolean; result?: any; error?: string }> {
745
+ // Check if skill exists in cache
746
+ if (!this.skillCache.has(toolName)) {
747
+ return { success: false, error: `Skill not found: ${toolName}` };
748
+ }
749
+
750
+ try {
751
+ const result = await this.executeSkill({
752
+ skillId: toolName,
753
+ taskDescription: params.taskDescription || params.description || '',
754
+ inputFile: params.inputFile,
755
+ outputFile: params.outputFile,
756
+ options: params.options || {}
757
+ });
758
+
759
+ return { success: result.success, result };
760
+ } catch (error: any) {
761
+ return { success: false, error: error.message };
762
+ }
763
+ }
764
+
765
+ /**
766
+ * Get all available Skill ID list
767
+ * NOTE: SKILL_TRIGGERS disabled - return all skill IDs from cache
768
+ */
769
+ getAvailableSkillIds(): string[] {
770
+ return Array.from(this.skillCache.keys());
771
+ }
772
+ }
773
+
774
+ // ============================================================
775
+ // Skill Executor Interface and Implementation
776
+ // ============================================================
777
+
778
+ interface SkillExecutor {
779
+ execute(skill: SkillInfo, params: SkillExecutionParams): Promise<SkillExecutionResult>;
780
+ }
781
+
782
+ /**
783
+ * Generic Skill Executor - Unified dynamic approach for all skills
784
+ */
785
+ class GenericSkillExecutor implements SkillExecutor {
786
+ async execute(skill: SkillInfo, params: SkillExecutionParams): Promise<SkillExecutionResult> {
787
+ const outputMessages: string[] = [];
788
+ const files: string[] = [];
789
+ const nextSteps: ExecutionStep[] = [];
790
+
791
+ outputMessages.push(`## ${skill.name} Skill - Execution Guide\n`);
792
+ outputMessages.push(`**Task**: ${params.taskDescription}\n`);
793
+
794
+ try {
795
+ // Generate task ID
796
+ const taskId = params.taskId || `${skill.id}-${Date.now()}`;
797
+
798
+ // Read complete skill documentation
799
+ const skillPath = skill.skillsPath;
800
+ const skillMdPath = path.join(skillPath, 'SKILL.md');
801
+ files.push(skillMdPath);
802
+
803
+ // Read SKILL.md content
804
+ const skillContent = await fs.readFile(skillMdPath, 'utf-8');
805
+
806
+ // Extract relevant content based on task type and generate execution steps
807
+ const taskContent = await this.extractRelevantContent(skill, params, skillContent, nextSteps, taskId);
808
+ outputMessages.push(taskContent);
809
+
810
+ // Add input/output files to list if they exist
811
+ if (params.inputFile) files.push(params.inputFile);
812
+ if (params.outputFile) files.push(params.outputFile);
813
+
814
+ return {
815
+ success: true,
816
+ output: outputMessages.join('\n'),
817
+ files: files,
818
+ nextSteps: nextSteps,
819
+ requiresManualExecution: true
820
+ };
821
+ } catch (error: any) {
822
+ return {
823
+ success: false,
824
+ error: error.message
825
+ };
826
+ }
827
+ }
828
+
829
+ /**
830
+ * Extract relevant skill content dynamically
831
+ */
832
+ private async extractRelevantContent(
833
+ skill: SkillInfo,
834
+ params: SkillExecutionParams,
835
+ fullContent: string,
836
+ nextSteps: ExecutionStep[],
837
+ taskId: string
838
+ ): Promise<string> {
839
+ const workspaceBase = getWorkspaceDescription();
840
+ const taskWorkspace = `${workspaceBase}/${taskId}`;
841
+
842
+ // Dynamically discover files in skill directory
843
+ const skillPath = skill.skillsPath;
844
+ let allFiles: string[] = [];
845
+
846
+ try {
847
+ const entries = await fs.readdir(skillPath, { withFileTypes: true });
848
+ for (const entry of entries) {
849
+ const fullPath = path.join(skillPath, entry.name);
850
+ if (entry.isFile()) {
851
+ allFiles.push(fullPath);
852
+ } else if (entry.isDirectory()) {
853
+ // Recursively list files in subdirectories (limited depth)
854
+ const subEntries = await fs.readdir(fullPath, { withFileTypes: true });
855
+ for (const subEntry of subEntries) {
856
+ if (subEntry.isFile()) {
857
+ allFiles.push(path.join(fullPath, subEntry.name));
858
+ }
859
+ }
860
+ }
861
+ }
862
+ } catch {
863
+ // Fallback to just SKILL.md if directory can't be read
864
+ allFiles = [path.join(skillPath, 'SKILL.md')];
865
+ }
866
+
867
+ // Step 1: Read SKILL.md first
868
+ const skillMdPathOnly = path.join(skillPath, 'SKILL.md');
869
+ nextSteps.push({
870
+ step: 1,
871
+ action: 'Read SKILL.md to understand the skill workflow',
872
+ description: `Read: ${skillMdPathOnly}`,
873
+ reason: 'Understand the skill workflow and best practices from the main documentation'
874
+ });
875
+
876
+ // Step 2: Explore skill directory and read reference files if needed (optional)
877
+ nextSteps.push({
878
+ step: 2,
879
+ action: 'Explore skill directory and read reference files (if needed)',
880
+ description: `Explore: ${skillPath}`,
881
+ reason: 'Discover available reference files and read them based on SKILL.md guidance'
882
+ });
883
+
884
+ nextSteps.push({
885
+ step: 3,
886
+ action: 'Analyze documentation, verify data/content completeness, and design approach',
887
+ description: `For content creation: ensure all info/materials collected. For info retrieval: ensure all required data retrieved. Then design execution plan for: ${taskWorkspace}`,
888
+ reason: 'Review requirements, verify data/content completeness, fill gaps if needed, then plan execution based on the documentation'
889
+ });
890
+
891
+ nextSteps.push({
892
+ step: 4,
893
+ action: 'Execute your plan',
894
+ description: 'Create workspace, write code, run scripts, verify output',
895
+ reason: 'Execute the task using your own understanding'
896
+ });
897
+
898
+ return `### Skill Execution\n\n` +
899
+ `**Your task**: ${params.taskDescription}\n\n` +
900
+ `**Step 1**: Read SKILL.md to understand the skill workflow\n` +
901
+ ` - read_file: ${skillMdPathOnly}\n\n` +
902
+ `**Step 2**: Explore skill directory and read reference files (if needed)\n` +
903
+ ` - ListDirectory(path="${skillPath}")\n` +
904
+ ` - read_file relevant .md and script files as needed\n\n` +
905
+ `Then analyze the documentation and create your own execution plan.\n\n` +
906
+ `**Workspace**: \`${taskWorkspace}\`\n\n` +
907
+ `**⚠️ Windows Path Execution**: Use absolute paths, NOT \`cd && command\`:\n` +
908
+ ` - ✅ Correct: \`node "${taskWorkspace}/script.js"\`\n` +
909
+ ` - ❌ Wrong: \`cd "${taskWorkspace}" && node script.js\` (fails in PowerShell 5.1)\n` +
910
+ ` - ✅ Correct: \`python "${taskWorkspace}/script.py"\`\n\n` +
911
+ `**📦 Dependency Management**:\n` +
912
+ ` - Use \`skillPath\` parameter to install dependencies to skill's node_modules (persists across invocations)\n` +
913
+ ` - Correct: Bash(command="npm install <package>", skillPath="${skillPath}")\n` +
914
+ ` - Correct: Bash(command="npm install", skillPath="${skillPath}")\n` +
915
+ ` - Dependencies are saved to: <userSkillsPath>/<skillName>/node_modules\n` +
916
+ ` - 💡 Tip: Install once, reuse forever - no need to reinstall on each call!\n` +
917
+ ` - After install, scripts can use require() directly with NODE_PATH auto-set\n` +
918
+ ` - NODE_PATH precedence: skill's node_modules > xAgent's node_modules\n` +
919
+ ` - Manual execution (Windows): set "NODE_PATH=${skillPath}/node_modules;<xAgentPath>/node_modules" && node script.js\n` +
920
+ ` - Manual execution (Linux/Mac): NODE_PATH=${skillPath}/node_modules:${process.cwd()}/node_modules node script.js\n` +
921
+ ` - ⚠️ If skillPath approach fails (module not found errors): Install directly in workspace\n` +
922
+ ` Priority: skill's node_modules > workspace's node_modules > xAgent's node_modules\n\n` +
923
+ `**🧹 Cleanup**: Delete all intermediate/temporary files when task completes:\n` +
924
+ ` - Remove: all files generated during the task\n` +
925
+ ` - Keep: Only the final output file (output.pptx/docx/xlsx/pdf or other file format required by user)\n` +
926
+ ` - ⚠️ If user needs to check results or make adjustments: RETAIN intermediate/temporary files for debugging\n\n` +
927
+ `**Instructions**: read_file the documentation, understand the API, and create your own execution plan.\n` +
928
+ `**If you encounter issues**: Explain what went wrong and suggest a different approach.\n`;
929
+ }
930
+ }
931
+ // ============================================================
932
+ // ============================================================
933
+
934
+ /**
935
+ * Execute skill - LLM analyzes SKILL.md and generates its own steps
936
+ * @param skill Skill to execute
937
+ * @param params Execution parameters
938
+ * @returns Execution result with guidance
939
+ */
940
+ export async function executeSkill(
941
+ skill: SkillInfo,
942
+ params: SkillExecutionParams
943
+ ): Promise<SkillExecutionResult> {
944
+ const executor = new GenericSkillExecutor();
945
+ return executor.execute(skill, params);
946
+ }
947
+
948
+ // ============================================================
949
+ // Singleton Instance and Exports
950
+ // ============================================================
951
+
952
+ let skillInvokerInstance: SkillInvoker | null = null;
953
+
954
+ export function getSkillInvoker(): SkillInvoker {
955
+ if (!skillInvokerInstance) {
956
+ skillInvokerInstance = new SkillInvoker();
957
+ }
958
+ return skillInvokerInstance;
959
+ }