@xagent-ai/cli 1.2.2 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (568) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.md +38 -38
  2. package/.github/ISSUE_TEMPLATE/feature_request.md +20 -20
  3. package/.github/workflows/ci.yml +72 -0
  4. package/.github/workflows/release.yml +109 -0
  5. package/.gitmodules +3 -3
  6. package/README.md +326 -280
  7. package/README_CN.md +325 -279
  8. package/dist/ai-client/factory.d.ts +52 -0
  9. package/dist/ai-client/factory.d.ts.map +1 -0
  10. package/dist/ai-client/factory.js +132 -0
  11. package/dist/ai-client/factory.js.map +1 -0
  12. package/dist/ai-client/index.d.ts +20 -0
  13. package/dist/ai-client/index.d.ts.map +1 -0
  14. package/dist/ai-client/index.js +49 -0
  15. package/dist/ai-client/index.js.map +1 -0
  16. package/dist/ai-client/providers/anthropic.d.ts +57 -0
  17. package/dist/ai-client/providers/anthropic.d.ts.map +1 -0
  18. package/dist/ai-client/providers/anthropic.js +400 -0
  19. package/dist/ai-client/providers/anthropic.js.map +1 -0
  20. package/dist/ai-client/providers/openai.d.ts +57 -0
  21. package/dist/ai-client/providers/openai.d.ts.map +1 -0
  22. package/dist/ai-client/providers/openai.js +286 -0
  23. package/dist/ai-client/providers/openai.js.map +1 -0
  24. package/dist/ai-client/providers/remote.d.ts +111 -0
  25. package/dist/ai-client/providers/remote.d.ts.map +1 -0
  26. package/dist/ai-client/providers/remote.js +351 -0
  27. package/dist/ai-client/providers/remote.js.map +1 -0
  28. package/dist/ai-client/registry.d.ts +51 -0
  29. package/dist/ai-client/registry.d.ts.map +1 -0
  30. package/dist/ai-client/registry.js +81 -0
  31. package/dist/ai-client/registry.js.map +1 -0
  32. package/dist/ai-client/types.d.ts +260 -0
  33. package/dist/ai-client/types.d.ts.map +1 -0
  34. package/dist/ai-client/types.js +73 -0
  35. package/dist/ai-client/types.js.map +1 -0
  36. package/dist/ai-client-factory.d.ts +62 -0
  37. package/dist/ai-client-factory.d.ts.map +1 -0
  38. package/dist/ai-client-factory.js +157 -0
  39. package/dist/ai-client-factory.js.map +1 -0
  40. package/dist/auth.d.ts +23 -1
  41. package/dist/auth.d.ts.map +1 -1
  42. package/dist/auth.js +160 -168
  43. package/dist/auth.js.map +1 -1
  44. package/dist/cancellation.d.ts +5 -4
  45. package/dist/cancellation.d.ts.map +1 -1
  46. package/dist/cancellation.js +55 -32
  47. package/dist/cancellation.js.map +1 -1
  48. package/dist/checkpoint.d.ts +1 -1
  49. package/dist/checkpoint.d.ts.map +1 -1
  50. package/dist/checkpoint.js +2 -2
  51. package/dist/checkpoint.js.map +1 -1
  52. package/dist/cli.js +626 -13
  53. package/dist/cli.js.map +1 -1
  54. package/dist/config.d.ts +10 -4
  55. package/dist/config.d.ts.map +1 -1
  56. package/dist/config.js +62 -25
  57. package/dist/config.js.map +1 -1
  58. package/dist/context-compressor.d.ts +81 -16
  59. package/dist/context-compressor.d.ts.map +1 -1
  60. package/dist/context-compressor.js +712 -153
  61. package/dist/context-compressor.js.map +1 -1
  62. package/dist/gui-subagent/action-parser/actionParser.d.ts.map +1 -1
  63. package/dist/gui-subagent/action-parser/actionParser.js +4 -2
  64. package/dist/gui-subagent/action-parser/actionParser.js.map +1 -1
  65. package/dist/gui-subagent/agent/gui-agent.d.ts +29 -2
  66. package/dist/gui-subagent/agent/gui-agent.d.ts.map +1 -1
  67. package/dist/gui-subagent/agent/gui-agent.js +87 -45
  68. package/dist/gui-subagent/agent/gui-agent.js.map +1 -1
  69. package/dist/gui-subagent/index.d.ts +16 -1
  70. package/dist/gui-subagent/index.d.ts.map +1 -1
  71. package/dist/gui-subagent/index.js +4 -0
  72. package/dist/gui-subagent/index.js.map +1 -1
  73. package/dist/gui-subagent/operator/base-operator.d.ts.map +1 -1
  74. package/dist/gui-subagent/operator/base-operator.js +0 -1
  75. package/dist/gui-subagent/operator/base-operator.js.map +1 -1
  76. package/dist/gui-subagent/operator/computer-operator.d.ts.map +1 -1
  77. package/dist/gui-subagent/operator/computer-operator.js +29 -8
  78. package/dist/gui-subagent/operator/computer-operator.js.map +1 -1
  79. package/dist/gui-subagent/types/actions.d.ts +1 -1
  80. package/dist/gui-subagent/types/actions.d.ts.map +1 -1
  81. package/dist/gui-subagent/types/actions.js +0 -1
  82. package/dist/gui-subagent/types/actions.js.map +1 -1
  83. package/dist/gui-subagent/types/operator.d.ts +1 -1
  84. package/dist/gui-subagent/types/operator.d.ts.map +1 -1
  85. package/dist/index.d.ts +1 -2
  86. package/dist/index.d.ts.map +1 -1
  87. package/dist/index.js +1 -2
  88. package/dist/index.js.map +1 -1
  89. package/dist/input-processor.d.ts.map +1 -1
  90. package/dist/input-processor.js +6 -3
  91. package/dist/input-processor.js.map +1 -1
  92. package/dist/mcp.d.ts +5 -0
  93. package/dist/mcp.d.ts.map +1 -1
  94. package/dist/mcp.js +81 -35
  95. package/dist/mcp.js.map +1 -1
  96. package/dist/ripgrep.d.ts +29 -0
  97. package/dist/ripgrep.d.ts.map +1 -0
  98. package/dist/ripgrep.js +292 -0
  99. package/dist/ripgrep.js.map +1 -0
  100. package/dist/session.d.ts +23 -7
  101. package/dist/session.d.ts.map +1 -1
  102. package/dist/session.js +624 -243
  103. package/dist/session.js.map +1 -1
  104. package/dist/shell.d.ts +33 -0
  105. package/dist/shell.d.ts.map +1 -0
  106. package/dist/shell.js +125 -0
  107. package/dist/shell.js.map +1 -0
  108. package/dist/skill-installer.d.ts +38 -0
  109. package/dist/skill-installer.d.ts.map +1 -0
  110. package/dist/skill-installer.js +447 -0
  111. package/dist/skill-installer.js.map +1 -0
  112. package/dist/skill-invoker.d.ts +7 -1
  113. package/dist/skill-invoker.d.ts.map +1 -1
  114. package/dist/skill-invoker.js +34 -13
  115. package/dist/skill-invoker.js.map +1 -1
  116. package/dist/skill-loader.d.ts +8 -3
  117. package/dist/skill-loader.d.ts.map +1 -1
  118. package/dist/skill-loader.js +46 -44
  119. package/dist/skill-loader.js.map +1 -1
  120. package/dist/skill-manager.d.ts +85 -0
  121. package/dist/skill-manager.d.ts.map +1 -0
  122. package/dist/skill-manager.js +340 -0
  123. package/dist/skill-manager.js.map +1 -0
  124. package/dist/slash-commands.d.ts +38 -1
  125. package/dist/slash-commands.d.ts.map +1 -1
  126. package/dist/slash-commands.js +912 -296
  127. package/dist/slash-commands.js.map +1 -1
  128. package/dist/smart-approval.d.ts.map +1 -1
  129. package/dist/smart-approval.js +67 -55
  130. package/dist/smart-approval.js.map +1 -1
  131. package/dist/system-prompt-generator.d.ts +6 -0
  132. package/dist/system-prompt-generator.d.ts.map +1 -1
  133. package/dist/system-prompt-generator.js +84 -34
  134. package/dist/system-prompt-generator.js.map +1 -1
  135. package/dist/terminal.d.ts +28 -0
  136. package/dist/terminal.d.ts.map +1 -0
  137. package/dist/terminal.js +82 -0
  138. package/dist/terminal.js.map +1 -0
  139. package/dist/tools.d.ts +23 -7
  140. package/dist/tools.d.ts.map +1 -1
  141. package/dist/tools.js +797 -437
  142. package/dist/tools.js.map +1 -1
  143. package/dist/truncate.d.ts +55 -0
  144. package/dist/truncate.d.ts.map +1 -0
  145. package/dist/truncate.js +130 -0
  146. package/dist/truncate.js.map +1 -0
  147. package/dist/types.d.ts +27 -9
  148. package/dist/types.d.ts.map +1 -1
  149. package/dist/update.d.ts.map +1 -1
  150. package/dist/update.js +17 -28
  151. package/dist/update.js.map +1 -1
  152. package/dist/workflow.d.ts +5 -1
  153. package/dist/workflow.d.ts.map +1 -1
  154. package/dist/workflow.js +60 -47
  155. package/dist/workflow.js.map +1 -1
  156. package/docs/architecture/mcp-integration-guide.md +304 -194
  157. package/docs/architecture/overview.md +169 -169
  158. package/docs/architecture/tool-system-design.md +134 -134
  159. package/docs/cli/commands.md +349 -238
  160. package/docs/smart-mode.md +281 -281
  161. package/docs/third-party-models.md +439 -439
  162. package/find-skills/SKILL.md +133 -0
  163. package/package.json +89 -90
  164. package/scripts/install-ripgrep.js +241 -0
  165. package/src/ai-client/factory.ts +151 -0
  166. package/src/ai-client/index.ts +61 -0
  167. package/src/ai-client/providers/anthropic.ts +466 -0
  168. package/src/ai-client/providers/openai.ts +342 -0
  169. package/src/ai-client/providers/remote.ts +436 -0
  170. package/src/ai-client/registry.ts +97 -0
  171. package/src/ai-client/types.ts +345 -0
  172. package/src/ai-client-factory.ts +204 -0
  173. package/src/auth.ts +663 -614
  174. package/src/cancellation.ts +205 -176
  175. package/src/checkpoint.ts +219 -219
  176. package/src/cli.ts +1406 -743
  177. package/src/config.ts +341 -297
  178. package/src/context-compressor.ts +982 -290
  179. package/src/conversation.ts +288 -288
  180. package/src/gui-subagent/action-parser/actionParser.ts +318 -315
  181. package/src/gui-subagent/action-parser/constants.ts +14 -14
  182. package/src/gui-subagent/action-parser/index.ts +8 -8
  183. package/src/gui-subagent/action-parser/types.ts +31 -31
  184. package/src/gui-subagent/agent/gui-agent.ts +1151 -1089
  185. package/src/gui-subagent/agent/index.ts +5 -5
  186. package/src/gui-subagent/index.ts +177 -163
  187. package/src/gui-subagent/operator/base-operator.ts +244 -245
  188. package/src/gui-subagent/operator/computer-operator.ts +540 -520
  189. package/src/gui-subagent/operator/index.ts +6 -6
  190. package/src/gui-subagent/types/actions.ts +260 -262
  191. package/src/gui-subagent/types/index.ts +6 -6
  192. package/src/gui-subagent/types/operator.ts +106 -106
  193. package/src/gui-subagent/utils.ts +51 -51
  194. package/src/index.ts +17 -18
  195. package/src/input-processor.ts +6 -3
  196. package/src/logger.ts +438 -438
  197. package/src/mcp.ts +730 -682
  198. package/src/memory.ts +344 -344
  199. package/src/ripgrep.ts +368 -0
  200. package/src/session-manager.ts +308 -308
  201. package/src/session.ts +948 -386
  202. package/src/shell.ts +133 -0
  203. package/src/skill-installer.ts +518 -0
  204. package/src/skill-invoker.ts +960 -935
  205. package/src/skill-loader.ts +501 -496
  206. package/src/skill-manager.ts +384 -0
  207. package/src/slash-commands.ts +2181 -1389
  208. package/src/smart-approval.ts +117 -73
  209. package/src/system-prompt-generator.ts +89 -34
  210. package/src/terminal.ts +96 -0
  211. package/src/theme.ts +738 -738
  212. package/src/tools.ts +1336 -773
  213. package/src/truncate.ts +173 -0
  214. package/src/types.ts +219 -198
  215. package/src/update.ts +22 -32
  216. package/src/workflow.ts +523 -508
  217. package/tsconfig.json +22 -22
  218. package/vitest.config.ts +19 -19
  219. package/dist/ai-client.d.ts +0 -86
  220. package/dist/ai-client.d.ts.map +0 -1
  221. package/dist/ai-client.js +0 -1372
  222. package/dist/ai-client.js.map +0 -1
  223. package/dist/gui-subagent/operator/browser-operator.d.ts +0 -36
  224. package/dist/gui-subagent/operator/browser-operator.d.ts.map +0 -1
  225. package/dist/gui-subagent/operator/browser-operator.js +0 -306
  226. package/dist/gui-subagent/operator/browser-operator.js.map +0 -1
  227. package/dist/gui-subagent/operator/desktop-operator.d.ts +0 -55
  228. package/dist/gui-subagent/operator/desktop-operator.d.ts.map +0 -1
  229. package/dist/gui-subagent/operator/desktop-operator.js +0 -527
  230. package/dist/gui-subagent/operator/desktop-operator.js.map +0 -1
  231. package/dist/hook.d.ts +0 -73
  232. package/dist/hook.d.ts.map +0 -1
  233. package/dist/hook.js +0 -156
  234. package/dist/hook.js.map +0 -1
  235. package/dist/input-history.d.ts +0 -24
  236. package/dist/input-history.d.ts.map +0 -1
  237. package/dist/input-history.js +0 -94
  238. package/dist/input-history.js.map +0 -1
  239. package/dist/keyboard-manager.d.ts +0 -151
  240. package/dist/keyboard-manager.d.ts.map +0 -1
  241. package/dist/keyboard-manager.js +0 -396
  242. package/dist/keyboard-manager.js.map +0 -1
  243. package/dist/print-system-prompt.d.ts +0 -2
  244. package/dist/print-system-prompt.d.ts.map +0 -1
  245. package/dist/print-system-prompt.js +0 -40
  246. package/dist/print-system-prompt.js.map +0 -1
  247. package/dist/remote-ai-client.d.ts +0 -104
  248. package/dist/remote-ai-client.d.ts.map +0 -1
  249. package/dist/remote-ai-client.js +0 -552
  250. package/dist/remote-ai-client.js.map +0 -1
  251. package/dist/sdk-output-adapter.d.ts +0 -232
  252. package/dist/sdk-output-adapter.d.ts.map +0 -1
  253. package/dist/sdk-output-adapter.js +0 -636
  254. package/dist/sdk-output-adapter.js.map +0 -1
  255. package/dist/sdk-session-v2.d.ts +0 -13
  256. package/dist/sdk-session-v2.d.ts.map +0 -1
  257. package/dist/sdk-session-v2.js +0 -46
  258. package/dist/sdk-session-v2.js.map +0 -1
  259. package/dist/sdk-session.d.ts +0 -13
  260. package/dist/sdk-session.d.ts.map +0 -1
  261. package/dist/sdk-session.js +0 -48
  262. package/dist/sdk-session.js.map +0 -1
  263. package/dist/test-boundary-conditions.d.ts.map +0 -1
  264. package/dist/test-boundary-conditions.js.map +0 -1
  265. package/dist/test-cancellation-fix.d.ts.map +0 -1
  266. package/dist/test-cancellation-fix.js.map +0 -1
  267. package/dist/test-input-history.d.ts.map +0 -1
  268. package/dist/test-input-history.js.map +0 -1
  269. package/dist/test-interaction-flow.d.ts.map +0 -1
  270. package/dist/test-interaction-flow.js.map +0 -1
  271. package/dist/test-quick.d.ts.map +0 -1
  272. package/dist/test-quick.js.map +0 -1
  273. package/dist/test-user-interaction.d.ts.map +0 -1
  274. package/dist/test-user-interaction.js.map +0 -1
  275. package/dist/tools/edit-diff.d.ts +0 -32
  276. package/dist/tools/edit-diff.d.ts.map +0 -1
  277. package/dist/tools/edit-diff.js +0 -185
  278. package/dist/tools/edit-diff.js.map +0 -1
  279. package/dist/tools/edit.d.ts +0 -11
  280. package/dist/tools/edit.d.ts.map +0 -1
  281. package/dist/tools/edit.js +0 -129
  282. package/dist/tools/edit.js.map +0 -1
  283. package/dist/unified-session.d.ts +0 -42
  284. package/dist/unified-session.d.ts.map +0 -1
  285. package/dist/unified-session.js +0 -271
  286. package/dist/unified-session.js.map +0 -1
  287. package/skills/.claude-plugin/marketplace.json +0 -45
  288. package/skills/README.md +0 -94
  289. package/skills/THIRD_PARTY_NOTICES.md +0 -405
  290. package/skills/skills/algorithmic-art/LICENSE.txt +0 -202
  291. package/skills/skills/algorithmic-art/SKILL.md +0 -405
  292. package/skills/skills/algorithmic-art/templates/generator_template.js +0 -223
  293. package/skills/skills/algorithmic-art/templates/viewer.html +0 -599
  294. package/skills/skills/brand-guidelines/LICENSE.txt +0 -202
  295. package/skills/skills/brand-guidelines/SKILL.md +0 -73
  296. package/skills/skills/canvas-design/LICENSE.txt +0 -202
  297. package/skills/skills/canvas-design/SKILL.md +0 -130
  298. package/skills/skills/canvas-design/canvas-fonts/ArsenalSC-OFL.txt +0 -93
  299. package/skills/skills/canvas-design/canvas-fonts/ArsenalSC-Regular.ttf +0 -0
  300. package/skills/skills/canvas-design/canvas-fonts/BigShoulders-Bold.ttf +0 -0
  301. package/skills/skills/canvas-design/canvas-fonts/BigShoulders-OFL.txt +0 -93
  302. package/skills/skills/canvas-design/canvas-fonts/BigShoulders-Regular.ttf +0 -0
  303. package/skills/skills/canvas-design/canvas-fonts/Boldonse-OFL.txt +0 -93
  304. package/skills/skills/canvas-design/canvas-fonts/Boldonse-Regular.ttf +0 -0
  305. package/skills/skills/canvas-design/canvas-fonts/BricolageGrotesque-Bold.ttf +0 -0
  306. package/skills/skills/canvas-design/canvas-fonts/BricolageGrotesque-OFL.txt +0 -93
  307. package/skills/skills/canvas-design/canvas-fonts/BricolageGrotesque-Regular.ttf +0 -0
  308. package/skills/skills/canvas-design/canvas-fonts/CrimsonPro-Bold.ttf +0 -0
  309. package/skills/skills/canvas-design/canvas-fonts/CrimsonPro-Italic.ttf +0 -0
  310. package/skills/skills/canvas-design/canvas-fonts/CrimsonPro-OFL.txt +0 -93
  311. package/skills/skills/canvas-design/canvas-fonts/CrimsonPro-Regular.ttf +0 -0
  312. package/skills/skills/canvas-design/canvas-fonts/DMMono-OFL.txt +0 -93
  313. package/skills/skills/canvas-design/canvas-fonts/DMMono-Regular.ttf +0 -0
  314. package/skills/skills/canvas-design/canvas-fonts/EricaOne-OFL.txt +0 -94
  315. package/skills/skills/canvas-design/canvas-fonts/EricaOne-Regular.ttf +0 -0
  316. package/skills/skills/canvas-design/canvas-fonts/GeistMono-Bold.ttf +0 -0
  317. package/skills/skills/canvas-design/canvas-fonts/GeistMono-OFL.txt +0 -93
  318. package/skills/skills/canvas-design/canvas-fonts/GeistMono-Regular.ttf +0 -0
  319. package/skills/skills/canvas-design/canvas-fonts/Gloock-OFL.txt +0 -93
  320. package/skills/skills/canvas-design/canvas-fonts/Gloock-Regular.ttf +0 -0
  321. package/skills/skills/canvas-design/canvas-fonts/IBMPlexMono-Bold.ttf +0 -0
  322. package/skills/skills/canvas-design/canvas-fonts/IBMPlexMono-OFL.txt +0 -93
  323. package/skills/skills/canvas-design/canvas-fonts/IBMPlexMono-Regular.ttf +0 -0
  324. package/skills/skills/canvas-design/canvas-fonts/IBMPlexSerif-Bold.ttf +0 -0
  325. package/skills/skills/canvas-design/canvas-fonts/IBMPlexSerif-BoldItalic.ttf +0 -0
  326. package/skills/skills/canvas-design/canvas-fonts/IBMPlexSerif-Italic.ttf +0 -0
  327. package/skills/skills/canvas-design/canvas-fonts/IBMPlexSerif-Regular.ttf +0 -0
  328. package/skills/skills/canvas-design/canvas-fonts/InstrumentSans-Bold.ttf +0 -0
  329. package/skills/skills/canvas-design/canvas-fonts/InstrumentSans-BoldItalic.ttf +0 -0
  330. package/skills/skills/canvas-design/canvas-fonts/InstrumentSans-Italic.ttf +0 -0
  331. package/skills/skills/canvas-design/canvas-fonts/InstrumentSans-OFL.txt +0 -93
  332. package/skills/skills/canvas-design/canvas-fonts/InstrumentSans-Regular.ttf +0 -0
  333. package/skills/skills/canvas-design/canvas-fonts/InstrumentSerif-Italic.ttf +0 -0
  334. package/skills/skills/canvas-design/canvas-fonts/InstrumentSerif-Regular.ttf +0 -0
  335. package/skills/skills/canvas-design/canvas-fonts/Italiana-OFL.txt +0 -93
  336. package/skills/skills/canvas-design/canvas-fonts/Italiana-Regular.ttf +0 -0
  337. package/skills/skills/canvas-design/canvas-fonts/JetBrainsMono-Bold.ttf +0 -0
  338. package/skills/skills/canvas-design/canvas-fonts/JetBrainsMono-OFL.txt +0 -93
  339. package/skills/skills/canvas-design/canvas-fonts/JetBrainsMono-Regular.ttf +0 -0
  340. package/skills/skills/canvas-design/canvas-fonts/Jura-Light.ttf +0 -0
  341. package/skills/skills/canvas-design/canvas-fonts/Jura-Medium.ttf +0 -0
  342. package/skills/skills/canvas-design/canvas-fonts/Jura-OFL.txt +0 -93
  343. package/skills/skills/canvas-design/canvas-fonts/LibreBaskerville-OFL.txt +0 -93
  344. package/skills/skills/canvas-design/canvas-fonts/LibreBaskerville-Regular.ttf +0 -0
  345. package/skills/skills/canvas-design/canvas-fonts/Lora-Bold.ttf +0 -0
  346. package/skills/skills/canvas-design/canvas-fonts/Lora-BoldItalic.ttf +0 -0
  347. package/skills/skills/canvas-design/canvas-fonts/Lora-Italic.ttf +0 -0
  348. package/skills/skills/canvas-design/canvas-fonts/Lora-OFL.txt +0 -93
  349. package/skills/skills/canvas-design/canvas-fonts/Lora-Regular.ttf +0 -0
  350. package/skills/skills/canvas-design/canvas-fonts/NationalPark-Bold.ttf +0 -0
  351. package/skills/skills/canvas-design/canvas-fonts/NationalPark-OFL.txt +0 -93
  352. package/skills/skills/canvas-design/canvas-fonts/NationalPark-Regular.ttf +0 -0
  353. package/skills/skills/canvas-design/canvas-fonts/NothingYouCouldDo-OFL.txt +0 -93
  354. package/skills/skills/canvas-design/canvas-fonts/NothingYouCouldDo-Regular.ttf +0 -0
  355. package/skills/skills/canvas-design/canvas-fonts/Outfit-Bold.ttf +0 -0
  356. package/skills/skills/canvas-design/canvas-fonts/Outfit-OFL.txt +0 -93
  357. package/skills/skills/canvas-design/canvas-fonts/Outfit-Regular.ttf +0 -0
  358. package/skills/skills/canvas-design/canvas-fonts/PixelifySans-Medium.ttf +0 -0
  359. package/skills/skills/canvas-design/canvas-fonts/PixelifySans-OFL.txt +0 -93
  360. package/skills/skills/canvas-design/canvas-fonts/PoiretOne-OFL.txt +0 -93
  361. package/skills/skills/canvas-design/canvas-fonts/PoiretOne-Regular.ttf +0 -0
  362. package/skills/skills/canvas-design/canvas-fonts/RedHatMono-Bold.ttf +0 -0
  363. package/skills/skills/canvas-design/canvas-fonts/RedHatMono-OFL.txt +0 -93
  364. package/skills/skills/canvas-design/canvas-fonts/RedHatMono-Regular.ttf +0 -0
  365. package/skills/skills/canvas-design/canvas-fonts/Silkscreen-OFL.txt +0 -93
  366. package/skills/skills/canvas-design/canvas-fonts/Silkscreen-Regular.ttf +0 -0
  367. package/skills/skills/canvas-design/canvas-fonts/SmoochSans-Medium.ttf +0 -0
  368. package/skills/skills/canvas-design/canvas-fonts/SmoochSans-OFL.txt +0 -93
  369. package/skills/skills/canvas-design/canvas-fonts/Tektur-Medium.ttf +0 -0
  370. package/skills/skills/canvas-design/canvas-fonts/Tektur-OFL.txt +0 -93
  371. package/skills/skills/canvas-design/canvas-fonts/Tektur-Regular.ttf +0 -0
  372. package/skills/skills/canvas-design/canvas-fonts/WorkSans-Bold.ttf +0 -0
  373. package/skills/skills/canvas-design/canvas-fonts/WorkSans-BoldItalic.ttf +0 -0
  374. package/skills/skills/canvas-design/canvas-fonts/WorkSans-Italic.ttf +0 -0
  375. package/skills/skills/canvas-design/canvas-fonts/WorkSans-OFL.txt +0 -93
  376. package/skills/skills/canvas-design/canvas-fonts/WorkSans-Regular.ttf +0 -0
  377. package/skills/skills/canvas-design/canvas-fonts/YoungSerif-OFL.txt +0 -93
  378. package/skills/skills/canvas-design/canvas-fonts/YoungSerif-Regular.ttf +0 -0
  379. package/skills/skills/doc-coauthoring/SKILL.md +0 -375
  380. package/skills/skills/docx/LICENSE.txt +0 -30
  381. package/skills/skills/docx/SKILL.md +0 -197
  382. package/skills/skills/docx/docx-js.md +0 -350
  383. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +0 -1499
  384. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +0 -146
  385. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +0 -1085
  386. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +0 -11
  387. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +0 -3081
  388. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +0 -23
  389. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +0 -185
  390. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +0 -287
  391. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +0 -1676
  392. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +0 -28
  393. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +0 -144
  394. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +0 -174
  395. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +0 -25
  396. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +0 -18
  397. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +0 -59
  398. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +0 -56
  399. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +0 -195
  400. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +0 -582
  401. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +0 -25
  402. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +0 -4439
  403. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +0 -570
  404. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +0 -509
  405. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +0 -12
  406. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +0 -108
  407. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +0 -96
  408. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +0 -3646
  409. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +0 -116
  410. package/skills/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +0 -42
  411. package/skills/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +0 -50
  412. package/skills/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +0 -49
  413. package/skills/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +0 -33
  414. package/skills/skills/docx/ooxml/schemas/mce/mc.xsd +0 -75
  415. package/skills/skills/docx/ooxml/schemas/microsoft/wml-2010.xsd +0 -560
  416. package/skills/skills/docx/ooxml/schemas/microsoft/wml-2012.xsd +0 -67
  417. package/skills/skills/docx/ooxml/schemas/microsoft/wml-2018.xsd +0 -14
  418. package/skills/skills/docx/ooxml/schemas/microsoft/wml-cex-2018.xsd +0 -20
  419. package/skills/skills/docx/ooxml/schemas/microsoft/wml-cid-2016.xsd +0 -13
  420. package/skills/skills/docx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +0 -4
  421. package/skills/skills/docx/ooxml/schemas/microsoft/wml-symex-2015.xsd +0 -8
  422. package/skills/skills/docx/ooxml/scripts/pack.py +0 -159
  423. package/skills/skills/docx/ooxml/scripts/unpack.py +0 -29
  424. package/skills/skills/docx/ooxml/scripts/validate.py +0 -69
  425. package/skills/skills/docx/ooxml/scripts/validation/__init__.py +0 -15
  426. package/skills/skills/docx/ooxml/scripts/validation/base.py +0 -951
  427. package/skills/skills/docx/ooxml/scripts/validation/docx.py +0 -274
  428. package/skills/skills/docx/ooxml/scripts/validation/pptx.py +0 -315
  429. package/skills/skills/docx/ooxml/scripts/validation/redlining.py +0 -279
  430. package/skills/skills/docx/ooxml.md +0 -610
  431. package/skills/skills/docx/scripts/__init__.py +0 -1
  432. package/skills/skills/docx/scripts/document.py +0 -1276
  433. package/skills/skills/docx/scripts/templates/comments.xml +0 -3
  434. package/skills/skills/docx/scripts/templates/commentsExtended.xml +0 -3
  435. package/skills/skills/docx/scripts/templates/commentsExtensible.xml +0 -3
  436. package/skills/skills/docx/scripts/templates/commentsIds.xml +0 -3
  437. package/skills/skills/docx/scripts/templates/people.xml +0 -3
  438. package/skills/skills/docx/scripts/utilities.py +0 -374
  439. package/skills/skills/frontend-design/LICENSE.txt +0 -177
  440. package/skills/skills/frontend-design/SKILL.md +0 -42
  441. package/skills/skills/internal-comms/LICENSE.txt +0 -202
  442. package/skills/skills/internal-comms/SKILL.md +0 -32
  443. package/skills/skills/internal-comms/examples/3p-updates.md +0 -47
  444. package/skills/skills/internal-comms/examples/company-newsletter.md +0 -65
  445. package/skills/skills/internal-comms/examples/faq-answers.md +0 -30
  446. package/skills/skills/internal-comms/examples/general-comms.md +0 -16
  447. package/skills/skills/mcp-builder/LICENSE.txt +0 -202
  448. package/skills/skills/mcp-builder/SKILL.md +0 -236
  449. package/skills/skills/mcp-builder/reference/evaluation.md +0 -602
  450. package/skills/skills/mcp-builder/reference/mcp_best_practices.md +0 -249
  451. package/skills/skills/mcp-builder/reference/node_mcp_server.md +0 -970
  452. package/skills/skills/mcp-builder/reference/python_mcp_server.md +0 -719
  453. package/skills/skills/mcp-builder/scripts/connections.py +0 -151
  454. package/skills/skills/mcp-builder/scripts/evaluation.py +0 -373
  455. package/skills/skills/mcp-builder/scripts/example_evaluation.xml +0 -22
  456. package/skills/skills/mcp-builder/scripts/requirements.txt +0 -2
  457. package/skills/skills/pdf/LICENSE.txt +0 -30
  458. package/skills/skills/pdf/SKILL.md +0 -294
  459. package/skills/skills/pdf/forms.md +0 -205
  460. package/skills/skills/pdf/reference.md +0 -612
  461. package/skills/skills/pdf/scripts/check_bounding_boxes.py +0 -70
  462. package/skills/skills/pdf/scripts/check_bounding_boxes_test.py +0 -226
  463. package/skills/skills/pdf/scripts/check_fillable_fields.py +0 -12
  464. package/skills/skills/pdf/scripts/convert_pdf_to_images.py +0 -35
  465. package/skills/skills/pdf/scripts/create_validation_image.py +0 -41
  466. package/skills/skills/pdf/scripts/extract_form_field_info.py +0 -152
  467. package/skills/skills/pdf/scripts/fill_fillable_fields.py +0 -114
  468. package/skills/skills/pdf/scripts/fill_pdf_form_with_annotations.py +0 -108
  469. package/skills/skills/pptx/LICENSE.txt +0 -30
  470. package/skills/skills/pptx/SKILL.md +0 -484
  471. package/skills/skills/pptx/html2pptx.md +0 -625
  472. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +0 -1499
  473. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +0 -146
  474. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +0 -1085
  475. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +0 -11
  476. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +0 -3081
  477. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +0 -23
  478. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +0 -185
  479. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +0 -287
  480. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +0 -1676
  481. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +0 -28
  482. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +0 -144
  483. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +0 -174
  484. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +0 -25
  485. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +0 -18
  486. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +0 -59
  487. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +0 -56
  488. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +0 -195
  489. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +0 -582
  490. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +0 -25
  491. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +0 -4439
  492. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +0 -570
  493. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +0 -509
  494. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +0 -12
  495. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +0 -108
  496. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +0 -96
  497. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +0 -3646
  498. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +0 -116
  499. package/skills/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +0 -42
  500. package/skills/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +0 -50
  501. package/skills/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +0 -49
  502. package/skills/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +0 -33
  503. package/skills/skills/pptx/ooxml/schemas/mce/mc.xsd +0 -75
  504. package/skills/skills/pptx/ooxml/schemas/microsoft/wml-2010.xsd +0 -560
  505. package/skills/skills/pptx/ooxml/schemas/microsoft/wml-2012.xsd +0 -67
  506. package/skills/skills/pptx/ooxml/schemas/microsoft/wml-2018.xsd +0 -14
  507. package/skills/skills/pptx/ooxml/schemas/microsoft/wml-cex-2018.xsd +0 -20
  508. package/skills/skills/pptx/ooxml/schemas/microsoft/wml-cid-2016.xsd +0 -13
  509. package/skills/skills/pptx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +0 -4
  510. package/skills/skills/pptx/ooxml/schemas/microsoft/wml-symex-2015.xsd +0 -8
  511. package/skills/skills/pptx/ooxml/scripts/pack.py +0 -159
  512. package/skills/skills/pptx/ooxml/scripts/unpack.py +0 -29
  513. package/skills/skills/pptx/ooxml/scripts/validate.py +0 -69
  514. package/skills/skills/pptx/ooxml/scripts/validation/__init__.py +0 -15
  515. package/skills/skills/pptx/ooxml/scripts/validation/base.py +0 -951
  516. package/skills/skills/pptx/ooxml/scripts/validation/docx.py +0 -274
  517. package/skills/skills/pptx/ooxml/scripts/validation/pptx.py +0 -315
  518. package/skills/skills/pptx/ooxml/scripts/validation/redlining.py +0 -279
  519. package/skills/skills/pptx/ooxml.md +0 -427
  520. package/skills/skills/pptx/scripts/html2pptx.js +0 -979
  521. package/skills/skills/pptx/scripts/inventory.py +0 -1020
  522. package/skills/skills/pptx/scripts/rearrange.py +0 -231
  523. package/skills/skills/pptx/scripts/replace.py +0 -385
  524. package/skills/skills/pptx/scripts/thumbnail.py +0 -450
  525. package/skills/skills/skill-creator/LICENSE.txt +0 -202
  526. package/skills/skills/skill-creator/SKILL.md +0 -356
  527. package/skills/skills/skill-creator/references/output-patterns.md +0 -82
  528. package/skills/skills/skill-creator/references/workflows.md +0 -28
  529. package/skills/skills/skill-creator/scripts/init_skill.py +0 -303
  530. package/skills/skills/skill-creator/scripts/package_skill.py +0 -110
  531. package/skills/skills/skill-creator/scripts/quick_validate.py +0 -95
  532. package/skills/skills/slack-gif-creator/LICENSE.txt +0 -202
  533. package/skills/skills/slack-gif-creator/SKILL.md +0 -254
  534. package/skills/skills/slack-gif-creator/core/easing.py +0 -234
  535. package/skills/skills/slack-gif-creator/core/frame_composer.py +0 -176
  536. package/skills/skills/slack-gif-creator/core/gif_builder.py +0 -269
  537. package/skills/skills/slack-gif-creator/core/validators.py +0 -136
  538. package/skills/skills/slack-gif-creator/requirements.txt +0 -4
  539. package/skills/skills/theme-factory/LICENSE.txt +0 -202
  540. package/skills/skills/theme-factory/SKILL.md +0 -59
  541. package/skills/skills/theme-factory/theme-showcase.pdf +0 -0
  542. package/skills/skills/theme-factory/themes/arctic-frost.md +0 -19
  543. package/skills/skills/theme-factory/themes/botanical-garden.md +0 -19
  544. package/skills/skills/theme-factory/themes/desert-rose.md +0 -19
  545. package/skills/skills/theme-factory/themes/forest-canopy.md +0 -19
  546. package/skills/skills/theme-factory/themes/golden-hour.md +0 -19
  547. package/skills/skills/theme-factory/themes/midnight-galaxy.md +0 -19
  548. package/skills/skills/theme-factory/themes/modern-minimalist.md +0 -19
  549. package/skills/skills/theme-factory/themes/ocean-depths.md +0 -19
  550. package/skills/skills/theme-factory/themes/sunset-boulevard.md +0 -19
  551. package/skills/skills/theme-factory/themes/tech-innovation.md +0 -19
  552. package/skills/skills/web-artifacts-builder/LICENSE.txt +0 -202
  553. package/skills/skills/web-artifacts-builder/SKILL.md +0 -74
  554. package/skills/skills/web-artifacts-builder/scripts/bundle-artifact.sh +0 -54
  555. package/skills/skills/web-artifacts-builder/scripts/init-artifact.sh +0 -322
  556. package/skills/skills/webapp-testing/LICENSE.txt +0 -202
  557. package/skills/skills/webapp-testing/SKILL.md +0 -96
  558. package/skills/skills/webapp-testing/examples/console_logging.py +0 -35
  559. package/skills/skills/webapp-testing/examples/element_discovery.py +0 -40
  560. package/skills/skills/webapp-testing/examples/static_html_automation.py +0 -33
  561. package/skills/skills/webapp-testing/scripts/with_server.py +0 -106
  562. package/skills/skills/xlsx/LICENSE.txt +0 -30
  563. package/skills/skills/xlsx/SKILL.md +0 -289
  564. package/skills/skills/xlsx/recalc.py +0 -178
  565. package/skills/spec/agent-skills-spec.md +0 -3
  566. package/skills/template/SKILL.md +0 -6
  567. package/src/ai-client.ts +0 -1560
  568. package/src/remote-ai-client.ts +0 -664
@@ -1,497 +1,502 @@
1
- import fs from 'fs/promises';
2
- import fsSync from 'fs';
3
- import path from 'path';
4
- import { fileURLToPath } from 'url';
5
- import { WorkflowConfig } from './workflow.js';
6
- import { getConfigManager } from './config.js';
7
-
8
- export interface SkillInfo {
9
- id: string;
10
- name: string;
11
- description: string;
12
- license: string;
13
- version: string;
14
- author: string;
15
- category: string;
16
- markdown: string;
17
- skillsPath: string;
18
- }
19
-
20
- export interface SkillLoaderConfig {
21
- skillsRootPath?: string;
22
- onError?: (error: SkillLoadError) => void;
23
- onWarning?: (warning: SkillLoadWarning) => void;
24
- }
25
-
26
- export interface SkillLoadError {
27
- skillId?: string;
28
- path: string;
29
- error: Error;
30
- phase: 'directory_read' | 'file_read' | 'parse_markdown';
31
- }
32
-
33
- export interface SkillLoadWarning {
34
- skillId?: string;
35
- path: string;
36
- warning: string;
37
- reason?: string;
38
- }
39
-
40
- export class SkillLoader {
41
- private skillsRootPath: string;
42
- private loadedSkills: Map<string, SkillInfo> = new Map();
43
- private skillDirectories: Map<string, string> = new Map(); // skillId -> path mapping
44
- private errorCallback?: (error: SkillLoadError) => void;
45
- private warningCallback?: (warning: SkillLoadWarning) => void;
46
- private loadStats: {
47
- totalFound: number;
48
- successfullyLoaded: number;
49
- failed: number;
50
- errors: SkillLoadError[];
51
- } = { totalFound: 0, successfullyLoaded: 0, failed: 0, errors: [] };
52
-
53
- constructor(config?: SkillLoaderConfig) {
54
- if (config?.skillsRootPath) {
55
- // Explicit path provided
56
- this.skillsRootPath = config.skillsRootPath;
57
- } else {
58
- // Try to get from config first
59
- const configManager = getConfigManager();
60
- const configuredPath = configManager.getSkillsPath();
61
-
62
- if (configuredPath) {
63
- this.skillsRootPath = configuredPath;
64
- } else {
65
- // Fallback: auto-detect from script location
66
- this.skillsRootPath = this.detectSkillsPath();
67
- }
68
- }
69
-
70
- // Set error and warning callbacks
71
- this.errorCallback = config?.onError;
72
- this.warningCallback = config?.onWarning;
73
- }
74
-
75
- private detectSkillsPath(): string {
76
- // Skills folder is always at {xagent_root}/skills/skills
77
- return path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', 'skills', 'skills');
78
- }
79
-
80
- async loadAllSkills(): Promise<SkillInfo[]> {
81
- const skills: SkillInfo[] = [];
82
-
83
- // Reset stats
84
- this.loadStats = { totalFound: 0, successfullyLoaded: 0, failed: 0, errors: [] };
85
-
86
- try {
87
- const categories = await fs.readdir(this.skillsRootPath, { withFileTypes: true });
88
-
89
- // First pass: discover all skill directories
90
- const skillDirs: { path: string; category: string }[] = [];
91
- for (const category of categories) {
92
- if (category.isDirectory()) {
93
- const categoryPath = path.join(this.skillsRootPath, category.name);
94
- skillDirs.push({ path: categoryPath, category: category.name });
95
- this.loadStats.totalFound++;
96
- }
97
- }
98
-
99
- // Second pass: load skills (can be parallelized)
100
- const loadPromises = skillDirs.map(async ({ path: skillPath, category }) => {
101
- const skillInfo = await this.loadSkillFromPath(skillPath, category);
102
- if (skillInfo) {
103
- this.loadedSkills.set(skillInfo.id, skillInfo);
104
- this.skillDirectories.set(skillInfo.id, skillPath);
105
- this.loadStats.successfullyLoaded++;
106
- return skillInfo;
107
- } else {
108
- this.loadStats.failed++;
109
- return null;
110
- }
111
- });
112
-
113
- const results = await Promise.all(loadPromises);
114
- for (const skill of results) {
115
- if (skill) skills.push(skill);
116
- }
117
-
118
- // Log summary if there were errors
119
- if (this.loadStats.failed > 0) {
120
- const errorMsg = `Loaded ${this.loadStats.successfullyLoaded}/${this.loadStats.totalFound} skills, ${this.loadStats.failed} failed`;
121
- if (this.warningCallback) {
122
- this.warningCallback({
123
- skillId: undefined,
124
- path: this.skillsRootPath,
125
- warning: errorMsg,
126
- reason: `${this.loadStats.errors.length} parsing errors`
127
- });
128
- } else {
129
- console.warn(`[SkillLoader] ${errorMsg}`);
130
- }
131
- }
132
-
133
- } catch (error) {
134
- const loadError: SkillLoadError = {
135
- skillId: undefined,
136
- path: this.skillsRootPath,
137
- error: error as Error,
138
- phase: 'directory_read'
139
- };
140
- this.loadStats.errors.push(loadError);
141
-
142
- if (this.errorCallback) {
143
- this.errorCallback(loadError);
144
- } else {
145
- console.error(`[SkillLoader] Failed to load skills from ${this.skillsRootPath}:`, error);
146
- }
147
- }
148
-
149
- return skills;
150
- }
151
-
152
- /**
153
- * Lazy load a single skill by ID - only loads when needed
154
- * This is the key optimization for on-demand loading
155
- */
156
- async loadSkill(skillId: string): Promise<SkillInfo | null> {
157
- // Return from cache if already loaded
158
- const cached = this.loadedSkills.get(skillId);
159
- if (cached) return cached;
160
-
161
- // Try to find and load the specific skill
162
- const skillPath = this.skillDirectories.get(skillId);
163
- if (skillPath) {
164
- const skillInfo = await this.loadSkillFromPath(skillPath, '');
165
- if (skillInfo) {
166
- this.loadedSkills.set(skillInfo.id, skillInfo);
167
- return skillInfo;
168
- }
169
- }
170
-
171
- // Fallback: search in skills root directory
172
- return this.loadSkillBySearching(skillId);
173
- }
174
-
175
- /**
176
- * Search for a skill by ID in the skills root directory
177
- */
178
- private async loadSkillBySearching(skillId: string): Promise<SkillInfo | null> {
179
- try {
180
- const categories = await fs.readdir(this.skillsRootPath, { withFileTypes: true });
181
-
182
- for (const category of categories) {
183
- if (category.isDirectory()) {
184
- const categoryPath = path.join(this.skillsRootPath, category.name);
185
- const skillMdPath = path.join(categoryPath, 'SKILL.md');
186
-
187
- try {
188
- const content = await fs.readFile(skillMdPath, 'utf-8');
189
- const parsed = this._parseSkillMarkdown(content);
190
-
191
- if (parsed.name === skillId) {
192
- this.skillDirectories.set(skillId, categoryPath);
193
- const skillInfo: SkillInfo = {
194
- id: parsed.name,
195
- name: parsed.name,
196
- description: parsed.description,
197
- license: parsed.license || 'Unknown',
198
- version: parsed.version || '1.0.0',
199
- author: parsed.author || 'Anonymous',
200
- category: category.name,
201
- markdown: content,
202
- skillsPath: categoryPath
203
- };
204
- this.loadedSkills.set(skillId, skillInfo);
205
- return skillInfo;
206
- }
207
- } catch {
208
- // Continue searching
209
- continue;
210
- }
211
- }
212
- }
213
- } catch (error) {
214
- const loadError: SkillLoadError = {
215
- skillId,
216
- path: this.skillsRootPath,
217
- error: error as Error,
218
- phase: 'directory_read'
219
- };
220
- this.handleError(loadError);
221
- }
222
-
223
- return null;
224
- }
225
-
226
- /**
227
- * Pre-discover skill directories without loading content
228
- * This allows faster subsequent lazy loading
229
- */
230
- async discoverSkills(): Promise<string[]> {
231
- const skillIds: string[] = [];
232
-
233
- try {
234
- const categories = await fs.readdir(this.skillsRootPath, { withFileTypes: true });
235
-
236
- for (const category of categories) {
237
- if (category.isDirectory()) {
238
- const categoryPath = path.join(this.skillsRootPath, category.name);
239
- const skillMdPath = path.join(categoryPath, 'SKILL.md');
240
-
241
- try {
242
- const content = await fs.readFile(skillMdPath, 'utf-8');
243
- const parsed = this._parseSkillMarkdown(content);
244
-
245
- if (parsed.name) {
246
- this.skillDirectories.set(parsed.name, categoryPath);
247
-
248
- // Also populate loadedSkills so getSkill() can find it
249
- const skillInfo: SkillInfo = {
250
- id: parsed.name,
251
- name: parsed.name,
252
- description: parsed.description || '',
253
- license: parsed.license || 'Unknown',
254
- version: parsed.version || '1.0.0',
255
- author: parsed.author || 'Anonymous',
256
- category: category.name,
257
- markdown: content,
258
- skillsPath: categoryPath
259
- };
260
- this.loadedSkills.set(parsed.name, skillInfo);
261
-
262
- skillIds.push(parsed.name);
263
- }
264
- } catch (error) {
265
- const loadError: SkillLoadError = {
266
- skillId: undefined,
267
- path: categoryPath,
268
- error: error as Error,
269
- phase: 'file_read'
270
- };
271
- this.handleError(loadError);
272
- }
273
- }
274
- }
275
- } catch (error) {
276
- const loadError: SkillLoadError = {
277
- skillId: undefined,
278
- path: this.skillsRootPath,
279
- error: error as Error,
280
- phase: 'directory_read'
281
- };
282
- this.handleError(loadError);
283
- }
284
-
285
- return skillIds;
286
- }
287
-
288
- /**
289
- * Get load statistics
290
- */
291
- getLoadStats(): { totalFound: number; successfullyLoaded: number; failed: number; errors: SkillLoadError[] } {
292
- return { ...this.loadStats };
293
- }
294
-
295
- /**
296
- * Handle error with callback or console
297
- */
298
- private handleError(error: SkillLoadError): void {
299
- this.loadStats.errors.push(error);
300
-
301
- if (this.errorCallback) {
302
- this.errorCallback(error);
303
- } else {
304
- console.error(`[SkillLoader] Error loading skill from ${error.path}:`, error.error.message);
305
- }
306
- }
307
-
308
- private async loadSkillFromPath(skillPath: string, category: string): Promise<SkillInfo | null> {
309
- const skillMdPath = path.join(skillPath, 'SKILL.md');
310
-
311
- try {
312
- const content = await fs.readFile(skillMdPath, 'utf-8');
313
- const parsed = this._parseSkillMarkdown(content);
314
-
315
- if (!parsed.name) {
316
- const warning: SkillLoadWarning = {
317
- skillId: undefined,
318
- path: skillPath,
319
- warning: 'SKILL.md missing required "name" field',
320
- reason: 'Cannot determine skill ID'
321
- };
322
- if (this.warningCallback) {
323
- this.warningCallback(warning);
324
- } else {
325
- console.warn(`[SkillLoader] Warning: ${warning.warning} in ${skillPath}`);
326
- }
327
- return null;
328
- }
329
-
330
- return {
331
- id: parsed.name,
332
- name: parsed.name,
333
- description: parsed.description,
334
- license: parsed.license || 'Unknown',
335
- version: parsed.version || '1.0.0',
336
- author: parsed.author || 'Anonymous',
337
- category: category,
338
- markdown: content,
339
- skillsPath: skillPath
340
- };
341
- } catch (error) {
342
- const loadError: SkillLoadError = {
343
- skillId: undefined,
344
- path: skillPath,
345
- error: error as Error,
346
- phase: 'file_read'
347
- };
348
- this.handleError(loadError);
349
- return null;
350
- }
351
- }
352
-
353
- private _parseSkillMarkdown(content: string): { name: string; description: string; license?: string; version?: string; author?: string } {
354
- const result = {
355
- name: '',
356
- description: '',
357
- license: undefined as string | undefined,
358
- version: undefined as string | undefined,
359
- author: undefined as string | undefined
360
- };
361
-
362
- // Normalize line endings to LF for consistent parsing
363
- const normalizedContent = content.replace(/\r\n/g, '\n');
364
-
365
- // Try to extract frontmatter - support both formats:
366
- // 1. Standard YAML: ---name: docx...--- 2. No opening ---: name: docx...
367
- let frontmatter = '';
368
- let contentStart = 0;
369
-
370
- const frontmatterMatch = normalizedContent.match(/^---\n([\s\S]*?)\n---/);
371
- if (frontmatterMatch) {
372
- // Standard format with --- at start and end
373
- frontmatter = frontmatterMatch[1];
374
- contentStart = frontmatterMatch[0].length;
375
- } else {
376
- // Check for format without opening --- (just YAML at the start)
377
- const yamlMatch = normalizedContent.match(/^([\s\S]*?)\n---/);
378
- if (yamlMatch) {
379
- frontmatter = yamlMatch[1];
380
- contentStart = yamlMatch[0].length;
381
- }
382
- }
383
-
384
- if (frontmatter) {
385
- const lines = frontmatter.split('\n');
386
-
387
- let currentKey = '';
388
- let currentValue = '';
389
-
390
- for (const line of lines) {
391
- const keyValueMatch = line.match(/^(\w+):\s*(.*)$/);
392
-
393
- if (keyValueMatch) {
394
- // Save previous key-value pair
395
- if (currentKey) {
396
- let value = currentValue.trim();
397
- // Remove quotes if present
398
- value = value.replace(/^["']|["']$/g, '');
399
-
400
- if (currentKey === 'name') result.name = value;
401
- else if (currentKey === 'description') result.description = value;
402
- else if (currentKey === 'license') result.license = value;
403
- else if (currentKey === 'version') result.version = value;
404
- else if (currentKey === 'author') result.author = value;
405
- }
406
-
407
- currentKey = keyValueMatch[1];
408
- currentValue = keyValueMatch[2];
409
- } else if (currentKey && line.trim()) {
410
- // Continuation of previous value
411
- currentValue += ' ' + line.trim();
412
- }
413
- }
414
-
415
- // Save last key-value pair
416
- if (currentKey) {
417
- let value = currentValue.trim();
418
- value = value.replace(/^["']|["']$/g, '');
419
-
420
- if (currentKey === 'name') result.name = value;
421
- else if (currentKey === 'description') result.description = value;
422
- else if (currentKey === 'license') result.license = value;
423
- else if (currentKey === 'version') result.version = value;
424
- else if (currentKey === 'author') result.author = value;
425
- }
426
- }
427
-
428
- return result;
429
- }
430
-
431
- getSkill(skillId: string): SkillInfo | undefined {
432
- return this.loadedSkills.get(skillId);
433
- }
434
-
435
- /**
436
- * Get the directory path for a skill
437
- */
438
- getSkillDirectory(skillId: string): string | undefined {
439
- return this.skillDirectories.get(skillId);
440
- }
441
-
442
- /**
443
- * Public method to parse skill markdown frontmatter
444
- */
445
- parseSkillMarkdown(content: string): { name: string; description: string; license?: string; version?: string; author?: string } {
446
- return this._parseSkillMarkdown(content);
447
- }
448
-
449
- listSkills(): SkillInfo[] {
450
- return Array.from(this.loadedSkills.values());
451
- }
452
-
453
- async convertToWorkflow(skillId: string): Promise<WorkflowConfig | null> {
454
- const skill = this.getSkill(skillId);
455
- if (!skill) return null;
456
-
457
- return {
458
- id: skill.id,
459
- name: skill.name,
460
- description: skill.description,
461
- version: skill.version,
462
- author: skill.author,
463
- agents: [],
464
- commands: {},
465
- mcpServers: {},
466
- xagentMd: skill.markdown,
467
- files: {}
468
- };
469
- }
470
-
471
- async convertAllToWorkflows(): Promise<WorkflowConfig[]> {
472
- const workflows: WorkflowConfig[] = [];
473
-
474
- for (const skill of this.loadedSkills.values()) {
475
- const workflow = await this.convertToWorkflow(skill.id);
476
- if (workflow) {
477
- workflows.push(workflow);
478
- }
479
- }
480
-
481
- return workflows;
482
- }
483
- }
484
-
485
- let skillLoaderInstance: SkillLoader | null = null;
486
-
487
- export function getSkillLoader(config?: SkillLoaderConfig): SkillLoader {
488
- if (!skillLoaderInstance) {
489
- skillLoaderInstance = new SkillLoader(config);
490
- }
491
- return skillLoaderInstance;
492
- }
493
-
494
- export async function loadSkillsFromFolder(skillsPath: string): Promise<SkillInfo[]> {
495
- const loader = new SkillLoader({ skillsRootPath: skillsPath });
496
- return await loader.loadAllSkills();
1
+ import fs from 'fs/promises';
2
+ import fsSync from 'fs';
3
+ import path from 'path';
4
+ import { fileURLToPath } from 'url';
5
+ import { WorkflowConfig } from './workflow.js';
6
+ import { getConfigManager } from './config.js';
7
+
8
+ export interface SkillInfo {
9
+ id: string;
10
+ name: string;
11
+ description: string;
12
+ license: string;
13
+ version: string;
14
+ author: string;
15
+ category: string;
16
+ markdown: string;
17
+ skillsPath: string;
18
+ }
19
+
20
+ export interface SkillLoaderConfig {
21
+ /** User-installed skills path (~/.xagent/skills) */
22
+ userSkillsRootPath?: string;
23
+ onError?: (error: SkillLoadError) => void;
24
+ onWarning?: (warning: SkillLoadWarning) => void;
25
+ }
26
+
27
+ export interface SkillLoadError {
28
+ skillId?: string;
29
+ path: string;
30
+ error: Error;
31
+ phase: 'directory_read' | 'file_read' | 'parse_markdown';
32
+ }
33
+
34
+ export interface SkillLoadWarning {
35
+ skillId?: string;
36
+ path: string;
37
+ warning: string;
38
+ reason?: string;
39
+ }
40
+
41
+ export class SkillLoader {
42
+ private skillsRootPath: string;
43
+ private loadedSkills: Map<string, SkillInfo> = new Map();
44
+ private skillDirectories: Map<string, string> = new Map(); // skillId -> path mapping
45
+ private errorCallback?: (error: SkillLoadError) => void;
46
+ private warningCallback?: (warning: SkillLoadWarning) => void;
47
+ private loadStats: {
48
+ totalFound: number;
49
+ successfullyLoaded: number;
50
+ failed: number;
51
+ errors: SkillLoadError[];
52
+ } = { totalFound: 0, successfullyLoaded: 0, failed: 0, errors: [] };
53
+
54
+ constructor(config?: SkillLoaderConfig) {
55
+ // All skills are loaded from user directory (default: ~/.xagent/skills)
56
+ // Built-in skills are copied to user directory during initialization
57
+ if (config?.userSkillsRootPath) {
58
+ this.skillsRootPath = config.userSkillsRootPath;
59
+ } else {
60
+ const configManager = getConfigManager();
61
+ const userPath = configManager.getUserSkillsPath();
62
+ this.skillsRootPath = userPath || path.join(require('os').homedir(), '.xagent', 'skills');
63
+ }
64
+ }
65
+ async loadAllSkills(): Promise<SkillInfo[]> {
66
+ const skills: SkillInfo[] = [];
67
+
68
+ // Reset stats
69
+ this.loadStats = { totalFound: 0, successfullyLoaded: 0, failed: 0, errors: [] };
70
+
71
+ try {
72
+ const categories = await fs.readdir(this.skillsRootPath, { withFileTypes: true });
73
+
74
+ // First pass: discover all skill directories
75
+ const skillDirs: { path: string; category: string }[] = [];
76
+ for (const category of categories) {
77
+ if (category.isDirectory()) {
78
+ const categoryPath = path.join(this.skillsRootPath, category.name);
79
+ skillDirs.push({ path: categoryPath, category: category.name });
80
+ this.loadStats.totalFound++;
81
+ }
82
+ }
83
+
84
+ // Second pass: load skills (can be parallelized)
85
+ const loadPromises = skillDirs.map(async ({ path: skillPath, category }) => {
86
+ const skillInfo = await this.loadSkillFromPath(skillPath, category);
87
+ if (skillInfo) {
88
+ this.loadedSkills.set(skillInfo.id, skillInfo);
89
+ this.skillDirectories.set(skillInfo.id, skillPath);
90
+ this.loadStats.successfullyLoaded++;
91
+ return skillInfo;
92
+ } else {
93
+ this.loadStats.failed++;
94
+ return null;
95
+ }
96
+ });
97
+
98
+ const results = await Promise.all(loadPromises);
99
+ for (const skill of results) {
100
+ if (skill) skills.push(skill);
101
+ }
102
+
103
+ } catch (error) {
104
+ const loadError: SkillLoadError = {
105
+ skillId: undefined,
106
+ path: this.skillsRootPath,
107
+ error: error as Error,
108
+ phase: 'directory_read'
109
+ };
110
+ this.loadStats.errors.push(loadError);
111
+
112
+ if (this.errorCallback) {
113
+ this.errorCallback(loadError);
114
+ } else {
115
+ console.error(`[SkillLoader] Failed to load skills from ${this.skillsRootPath}:`, error);
116
+ }
117
+ }
118
+
119
+ // Log summary if there were errors
120
+ if (this.loadStats.failed > 0) {
121
+ const errorMsg = `Loaded ${this.loadStats.successfullyLoaded}/${this.loadStats.totalFound} skills, ${this.loadStats.failed} failed`;
122
+ if (this.warningCallback) {
123
+ this.warningCallback({
124
+ skillId: undefined,
125
+ path: this.skillsRootPath,
126
+ warning: errorMsg,
127
+ reason: `${this.loadStats.errors.length} parsing errors`
128
+ });
129
+ } else {
130
+ console.warn(`[SkillLoader] ${errorMsg}`);
131
+ }
132
+ }
133
+
134
+ return skills;
135
+ }
136
+
137
+ /**
138
+ * Lazy load a single skill by ID - only loads when needed
139
+ * This is the key optimization for on-demand loading
140
+ */
141
+ async loadSkill(skillId: string): Promise<SkillInfo | null> {
142
+ // Return from cache if already loaded
143
+ const cached = this.loadedSkills.get(skillId);
144
+ if (cached) return cached;
145
+
146
+ // Try to find and load the specific skill
147
+ const skillPath = this.skillDirectories.get(skillId);
148
+ if (skillPath) {
149
+ const skillInfo = await this.loadSkillFromPath(skillPath, '');
150
+ if (skillInfo) {
151
+ this.loadedSkills.set(skillInfo.id, skillInfo);
152
+ return skillInfo;
153
+ }
154
+ }
155
+
156
+ // Fallback: search in skills root directory
157
+ return this.loadSkillBySearching(skillId);
158
+ }
159
+
160
+ /**
161
+ * Search for a skill by ID in the skills root directories
162
+ */
163
+ private async loadSkillBySearching(skillId: string): Promise<SkillInfo | null> {
164
+ // Unified approach: only search in user skills directory
165
+ const skillsRootPath = this.skillsRootPath;
166
+
167
+ try {
168
+ const categories = await fs.readdir(skillsRootPath, { withFileTypes: true });
169
+
170
+ for (const category of categories) {
171
+ if (category.isDirectory()) {
172
+ const categoryPath = path.join(skillsRootPath, category.name);
173
+ const skillMdPath = path.join(categoryPath, 'SKILL.md');
174
+
175
+ try {
176
+ const content = await fs.readFile(skillMdPath, 'utf-8');
177
+ const parsed = this._parseSkillMarkdown(content);
178
+
179
+ if (parsed.name === skillId) {
180
+ this.skillDirectories.set(skillId, categoryPath);
181
+ const skillInfo: SkillInfo = {
182
+ id: parsed.name,
183
+ name: parsed.name,
184
+ description: parsed.description,
185
+ license: parsed.license || 'Unknown',
186
+ version: parsed.version || '1.0.0',
187
+ author: parsed.author || 'Anonymous',
188
+ category: category.name,
189
+ markdown: content,
190
+ skillsPath: categoryPath
191
+ };
192
+ this.loadedSkills.set(skillId, skillInfo);
193
+ return skillInfo;
194
+ }
195
+ } catch {
196
+ // Continue searching
197
+ continue;
198
+ }
199
+ }
200
+ }
201
+ } catch (error) {
202
+ const loadError: SkillLoadError = {
203
+ skillId,
204
+ path: skillsRootPath,
205
+ error: error as Error,
206
+ phase: 'directory_read'
207
+ };
208
+ this.handleError(loadError);
209
+ }
210
+
211
+ return null;
212
+ }
213
+
214
+ /**
215
+ * Pre-discover skill directories without loading content
216
+ * This allows faster subsequent lazy loading
217
+ */
218
+ async discoverSkills(): Promise<string[]> {
219
+ const skillIds: string[] = [];
220
+
221
+ // Unified approach: only scan user skills directory
222
+ const skillsRootPath = this.skillsRootPath;
223
+
224
+ try {
225
+ const categories = await fs.readdir(skillsRootPath, { withFileTypes: true });
226
+
227
+ for (const category of categories) {
228
+ if (category.isDirectory()) {
229
+ const categoryPath = path.join(skillsRootPath, category.name);
230
+ const skillMdPath = path.join(categoryPath, 'SKILL.md');
231
+
232
+ try {
233
+ const content = await fs.readFile(skillMdPath, 'utf-8');
234
+ const parsed = this._parseSkillMarkdown(content);
235
+
236
+ if (parsed.name) {
237
+ this.skillDirectories.set(parsed.name, categoryPath);
238
+
239
+ // Also populate loadedSkills so getSkill() can find it
240
+ const skillInfo: SkillInfo = {
241
+ id: parsed.name,
242
+ name: parsed.name,
243
+ description: parsed.description || '',
244
+ license: parsed.license || 'Unknown',
245
+ version: parsed.version || '1.0.0',
246
+ author: parsed.author || 'Anonymous',
247
+ category: category.name,
248
+ markdown: content,
249
+ skillsPath: categoryPath
250
+ };
251
+ this.loadedSkills.set(parsed.name, skillInfo);
252
+
253
+ skillIds.push(parsed.name);
254
+ }
255
+ } catch (error) {
256
+ const loadError: SkillLoadError = {
257
+ skillId: undefined,
258
+ path: categoryPath,
259
+ error: error as Error,
260
+ phase: 'file_read'
261
+ };
262
+ this.handleError(loadError);
263
+ }
264
+ }
265
+ }
266
+ } catch (error) {
267
+ const loadError: SkillLoadError = {
268
+ skillId: undefined,
269
+ path: skillsRootPath,
270
+ error: error as Error,
271
+ phase: 'directory_read'
272
+ };
273
+ this.handleError(loadError);
274
+ }
275
+
276
+ return skillIds;
277
+ }
278
+
279
+ /**
280
+ * Get load statistics
281
+ */
282
+ getLoadStats(): { totalFound: number; successfullyLoaded: number; failed: number; errors: SkillLoadError[] } {
283
+ return { ...this.loadStats };
284
+ }
285
+
286
+ /**
287
+ * Handle error with callback or console
288
+ */
289
+ private handleError(error: SkillLoadError): void {
290
+ this.loadStats.errors.push(error);
291
+
292
+ if (this.errorCallback) {
293
+ this.errorCallback(error);
294
+ } else {
295
+ console.error(`[SkillLoader] Error loading skill from ${error.path}:`, error.error.message);
296
+ }
297
+ }
298
+
299
+ private async loadSkillFromPath(skillPath: string, category: string): Promise<SkillInfo | null> {
300
+ const skillMdPath = path.join(skillPath, 'SKILL.md');
301
+
302
+ try {
303
+ const content = await fs.readFile(skillMdPath, 'utf-8');
304
+ const parsed = this._parseSkillMarkdown(content);
305
+
306
+ if (!parsed.name) {
307
+ const warning: SkillLoadWarning = {
308
+ skillId: undefined,
309
+ path: skillPath,
310
+ warning: 'SKILL.md missing required "name" field',
311
+ reason: 'Cannot determine skill ID'
312
+ };
313
+ if (this.warningCallback) {
314
+ this.warningCallback(warning);
315
+ } else {
316
+ console.warn(`[SkillLoader] Warning: ${warning.warning} in ${skillPath}`);
317
+ }
318
+ return null;
319
+ }
320
+
321
+ return {
322
+ id: parsed.name,
323
+ name: parsed.name,
324
+ description: parsed.description,
325
+ license: parsed.license || 'Unknown',
326
+ version: parsed.version || '1.0.0',
327
+ author: parsed.author || 'Anonymous',
328
+ category: category,
329
+ markdown: content,
330
+ skillsPath: skillPath
331
+ };
332
+ } catch (error) {
333
+ const loadError: SkillLoadError = {
334
+ skillId: undefined,
335
+ path: skillPath,
336
+ error: error as Error,
337
+ phase: 'file_read'
338
+ };
339
+ this.handleError(loadError);
340
+ return null;
341
+ }
342
+ }
343
+
344
+ private _parseSkillMarkdown(content: string): { name: string; description: string; license?: string; version?: string; author?: string } {
345
+ const result = {
346
+ name: '',
347
+ description: '',
348
+ license: undefined as string | undefined,
349
+ version: undefined as string | undefined,
350
+ author: undefined as string | undefined
351
+ };
352
+
353
+ // Normalize line endings to LF for consistent parsing
354
+ const normalizedContent = content.replace(/\r\n/g, '\n');
355
+
356
+ // Try to extract frontmatter - support both formats:
357
+ // 1. Standard YAML: ---name: docx...--- 2. No opening ---: name: docx...
358
+ let frontmatter = '';
359
+ let contentStart = 0;
360
+
361
+ const frontmatterMatch = normalizedContent.match(/^---\n([\s\S]*?)\n---/);
362
+ if (frontmatterMatch) {
363
+ // Standard format with --- at start and end
364
+ frontmatter = frontmatterMatch[1];
365
+ contentStart = frontmatterMatch[0].length;
366
+ } else {
367
+ // Check for format without opening --- (just YAML at the start)
368
+ const yamlMatch = normalizedContent.match(/^([\s\S]*?)\n---/);
369
+ if (yamlMatch) {
370
+ frontmatter = yamlMatch[1];
371
+ contentStart = yamlMatch[0].length;
372
+ }
373
+ }
374
+
375
+ if (frontmatter) {
376
+ const lines = frontmatter.split('\n');
377
+
378
+ let currentKey = '';
379
+ let currentValue = '';
380
+
381
+ for (const line of lines) {
382
+ const keyValueMatch = line.match(/^(\w+):\s*(.*)$/);
383
+
384
+ if (keyValueMatch) {
385
+ // Save previous key-value pair
386
+ if (currentKey) {
387
+ let value = currentValue.trim();
388
+ // Remove quotes if present
389
+ value = value.replace(/^["']|["']$/g, '');
390
+
391
+ if (currentKey === 'name') result.name = value;
392
+ else if (currentKey === 'description') result.description = value;
393
+ else if (currentKey === 'license') result.license = value;
394
+ else if (currentKey === 'version') result.version = value;
395
+ else if (currentKey === 'author') result.author = value;
396
+ }
397
+
398
+ currentKey = keyValueMatch[1];
399
+ currentValue = keyValueMatch[2];
400
+ } else if (currentKey && line.trim()) {
401
+ // Continuation of previous value
402
+ currentValue += ' ' + line.trim();
403
+ }
404
+ }
405
+
406
+ // Save last key-value pair
407
+ if (currentKey) {
408
+ let value = currentValue.trim();
409
+ value = value.replace(/^["']|["']$/g, '');
410
+
411
+ if (currentKey === 'name') result.name = value;
412
+ else if (currentKey === 'description') result.description = value;
413
+ else if (currentKey === 'license') result.license = value;
414
+ else if (currentKey === 'version') result.version = value;
415
+ else if (currentKey === 'author') result.author = value;
416
+ }
417
+ }
418
+
419
+ return result;
420
+ }
421
+
422
+ getSkill(skillId: string): SkillInfo | undefined {
423
+ return this.loadedSkills.get(skillId);
424
+ }
425
+
426
+ /**
427
+ * Get the directory path for a skill
428
+ */
429
+ getSkillDirectory(skillId: string): string | undefined {
430
+ return this.skillDirectories.get(skillId);
431
+ }
432
+
433
+ /**
434
+ * Public method to parse skill markdown frontmatter
435
+ */
436
+ parseSkillMarkdown(content: string): { name: string; description: string; license?: string; version?: string; author?: string } {
437
+ return this._parseSkillMarkdown(content);
438
+ }
439
+
440
+ listSkills(): SkillInfo[] {
441
+ return Array.from(this.loadedSkills.values());
442
+ }
443
+
444
+ async convertToWorkflow(skillId: string): Promise<WorkflowConfig | null> {
445
+ const skill = this.getSkill(skillId);
446
+ if (!skill) return null;
447
+
448
+ return {
449
+ id: skill.id,
450
+ name: skill.name,
451
+ description: skill.description,
452
+ version: skill.version,
453
+ author: skill.author,
454
+ agents: [],
455
+ commands: {},
456
+ mcpServers: {},
457
+ xagentMd: skill.markdown,
458
+ files: {}
459
+ };
460
+ }
461
+
462
+ async convertAllToWorkflows(): Promise<WorkflowConfig[]> {
463
+ const workflows: WorkflowConfig[] = [];
464
+
465
+ for (const skill of this.loadedSkills.values()) {
466
+ const workflow = await this.convertToWorkflow(skill.id);
467
+ if (workflow) {
468
+ workflows.push(workflow);
469
+ }
470
+ }
471
+
472
+ return workflows;
473
+ }
474
+ }
475
+
476
+ let skillLoaderInstance: SkillLoader | null = null;
477
+
478
+ export function getSkillLoader(config?: SkillLoaderConfig): SkillLoader {
479
+ // Always use the same user skills directory to avoid cache pollution
480
+ // Built-in skills are copied to user directory during initialization
481
+ const unifiedConfig: SkillLoaderConfig = {
482
+ userSkillsRootPath: config?.userSkillsRootPath
483
+ };
484
+
485
+ if (!skillLoaderInstance) {
486
+ skillLoaderInstance = new SkillLoader(unifiedConfig);
487
+ }
488
+ return skillLoaderInstance;
489
+ }
490
+
491
+ /**
492
+ * Force reset the skill loader instance (for testing or critical reload)
493
+ * WARNING: This clears all cached skills!
494
+ */
495
+ export function resetSkillLoader(): void {
496
+ skillLoaderInstance = null;
497
+ }
498
+
499
+ export async function loadSkillsFromFolder(skillsPath: string): Promise<SkillInfo[]> {
500
+ const loader = new SkillLoader({ userSkillsRootPath: skillsPath });
501
+ return await loader.loadAllSkills();
497
502
  }