@xopcai/xopc 0.0.29 → 0.0.31

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 (632) hide show
  1. package/dist/extensions/telegram/src/adapters/config-surface.js +3 -1
  2. package/dist/extensions/telegram/src/adapters/config-surface.js.map +1 -1
  3. package/dist/extensions/telegram/src/adapters/onboard-cli.js +23 -21
  4. package/dist/extensions/telegram/src/adapters/onboard-cli.js.map +1 -1
  5. package/dist/extensions/telegram/src/adapters/setup-wizard.js +3 -4
  6. package/dist/extensions/telegram/src/adapters/setup-wizard.js.map +1 -1
  7. package/dist/extensions/telegram/src/config-schema.d.ts +0 -1
  8. package/dist/extensions/telegram/src/config-schema.js +17 -4
  9. package/dist/extensions/telegram/src/config-schema.js.map +1 -1
  10. package/dist/extensions/telegram/src/plugin.js +4 -17
  11. package/dist/extensions/telegram/src/plugin.js.map +1 -1
  12. package/dist/extensions/telegram/xopc.extension.json +1 -1
  13. package/dist/extensions/weixin/src/cdn/upload.js +1 -1
  14. package/dist/extensions/weixin/src/media/data-url.js +1 -1
  15. package/dist/extensions/weixin/src/messaging/process-message.js +1 -1
  16. package/dist/gateway/static/root/assets/agents-3u63Fw2Y.js +216 -0
  17. package/dist/gateway/static/root/assets/agents-3u63Fw2Y.js.map +1 -0
  18. package/dist/gateway/static/root/assets/{apps-page-Bmq19MS-.js → apps-page-CWegY6Kp.js} +2 -2
  19. package/dist/gateway/static/root/assets/{apps-page-Bmq19MS-.js.map → apps-page-CWegY6Kp.js.map} +1 -1
  20. package/dist/gateway/static/root/assets/channels-settings-CiyeXcTK.js +9 -0
  21. package/dist/gateway/static/root/assets/channels-settings-CiyeXcTK.js.map +1 -0
  22. package/dist/gateway/static/root/assets/cron-api-_j_79Zf5.js +3 -0
  23. package/dist/gateway/static/root/assets/cron-api-_j_79Zf5.js.map +1 -0
  24. package/dist/gateway/static/root/assets/cron-page-S86YNTtI.js +2 -0
  25. package/dist/gateway/static/root/assets/cron-page-S86YNTtI.js.map +1 -0
  26. package/dist/gateway/static/root/assets/dist-D0jxbvuz.js +2 -0
  27. package/dist/gateway/static/root/assets/{dist--p2HQ2QF.js.map → dist-D0jxbvuz.js.map} +1 -1
  28. package/dist/gateway/static/root/assets/{extension-debug-page-DwHCB_6T.js → extension-debug-page-DB630cW8.js} +2 -2
  29. package/dist/gateway/static/root/assets/{extension-debug-page-DwHCB_6T.js.map → extension-debug-page-DB630cW8.js.map} +1 -1
  30. package/dist/gateway/static/root/assets/{extension-page-BsYwQIex.js → extension-page-CnoPUBul.js} +2 -2
  31. package/dist/gateway/static/root/assets/{extension-page-BsYwQIex.js.map → extension-page-CnoPUBul.js.map} +1 -1
  32. package/dist/gateway/static/root/assets/{extension-settings-page-nsisEgjB.js → extension-settings-page-BsiOkvBe.js} +2 -2
  33. package/dist/gateway/static/root/assets/{extension-settings-page-nsisEgjB.js.map → extension-settings-page-BsiOkvBe.js.map} +1 -1
  34. package/dist/gateway/static/root/assets/{index-CR8zUHGR.js → index-DHLmAIQl.js} +63 -63
  35. package/dist/gateway/static/root/assets/{index-CR8zUHGR.js.map → index-DHLmAIQl.js.map} +1 -1
  36. package/dist/gateway/static/root/assets/index-DoPwy4aU.css +1 -0
  37. package/dist/gateway/static/root/assets/logs-page-Bndhenn2.js +2 -0
  38. package/dist/gateway/static/root/assets/logs-page-Bndhenn2.js.map +1 -0
  39. package/dist/gateway/static/root/assets/sessions-page-Q201-_lP.js +2 -0
  40. package/dist/gateway/static/root/assets/{sessions-page-Be5kIGl_.js.map → sessions-page-Q201-_lP.js.map} +1 -1
  41. package/dist/gateway/static/root/assets/settings-page-Cw75fpc6.js +2 -0
  42. package/dist/gateway/static/root/assets/settings-page-Cw75fpc6.js.map +1 -0
  43. package/dist/gateway/static/root/assets/skills-page-CVwEzD_J.js +3 -0
  44. package/dist/gateway/static/root/assets/skills-page-CVwEzD_J.js.map +1 -0
  45. package/dist/gateway/static/root/index.html +2 -2
  46. package/dist/package.js +1 -1
  47. package/dist/src/agent/agent-manager.d.ts +5 -7
  48. package/dist/src/agent/agent-manager.js +21 -19
  49. package/dist/src/agent/agent-manager.js.map +1 -1
  50. package/dist/src/agent/ipc/inbox.js +4 -2
  51. package/dist/src/agent/ipc/inbox.js.map +1 -1
  52. package/dist/src/agent/memory/dreaming/short-term-store.js +1 -1
  53. package/dist/src/agent/memory/dreaming/utils.js +1 -1
  54. package/dist/src/agent/orchestration/agent-orchestrator.js +1 -1
  55. package/dist/src/agent/prompt/service-prompt-builder.js +0 -2
  56. package/dist/src/agent/prompt/service-prompt-builder.js.map +1 -1
  57. package/dist/src/agent/prompt/system-prompt.d.ts +0 -2
  58. package/dist/src/agent/prompt/system-prompt.js +3 -17
  59. package/dist/src/agent/prompt/system-prompt.js.map +1 -1
  60. package/dist/src/agent/service/btw-query.d.ts +16 -0
  61. package/dist/src/agent/service/btw-query.js +88 -0
  62. package/dist/src/agent/service/btw-query.js.map +1 -0
  63. package/dist/src/agent/service/build-direct-message-content.d.ts +30 -0
  64. package/dist/src/agent/service/build-direct-message-content.js +75 -0
  65. package/dist/src/agent/service/build-direct-message-content.js.map +1 -0
  66. package/dist/src/agent/service/parse-outbound-session-key.d.ts +8 -0
  67. package/dist/src/agent/service/parse-outbound-session-key.js +41 -0
  68. package/dist/src/agent/service/parse-outbound-session-key.js.map +1 -0
  69. package/dist/src/agent/service/process-direct-one-shot.d.ts +34 -0
  70. package/dist/src/agent/service/process-direct-one-shot.js +67 -0
  71. package/dist/src/agent/service/process-direct-one-shot.js.map +1 -0
  72. package/dist/src/agent/service/process-direct-streaming.js +12 -1
  73. package/dist/src/agent/service/process-direct-streaming.js.map +1 -1
  74. package/dist/src/agent/service/reconcile-dreaming-cron.d.ts +6 -0
  75. package/dist/src/agent/service/reconcile-dreaming-cron.js +70 -0
  76. package/dist/src/agent/service/reconcile-dreaming-cron.js.map +1 -0
  77. package/dist/src/agent/service/session-context-report.d.ts +19 -0
  78. package/dist/src/agent/service/session-context-report.js +47 -0
  79. package/dist/src/agent/service/session-context-report.js.map +1 -0
  80. package/dist/src/agent/service/webchat-tts.d.ts +28 -0
  81. package/dist/src/agent/service/webchat-tts.js +73 -0
  82. package/dist/src/agent/service/webchat-tts.js.map +1 -0
  83. package/dist/src/agent/service.d.ts +8 -12
  84. package/dist/src/agent/service.js +74 -379
  85. package/dist/src/agent/service.js.map +1 -1
  86. package/dist/src/agent/skills/config.js +4 -3
  87. package/dist/src/agent/skills/config.js.map +1 -1
  88. package/dist/src/agent/skills/format-skills-prompt.d.ts +0 -2
  89. package/dist/src/agent/skills/format-skills-prompt.js +3 -24
  90. package/dist/src/agent/skills/format-skills-prompt.js.map +1 -1
  91. package/dist/src/agent/skills/hub-lock.js +4 -5
  92. package/dist/src/agent/skills/hub-lock.js.map +1 -1
  93. package/dist/src/agent/skills/index.js +9 -21
  94. package/dist/src/agent/skills/index.js.map +1 -1
  95. package/dist/src/agent/skills/marketplace/adapter.types.d.ts +17 -0
  96. package/dist/src/agent/skills/marketplace/adapter.types.js +1 -0
  97. package/dist/src/agent/skills/marketplace/adapters/skillhub/adapter.d.ts +2 -0
  98. package/dist/src/agent/skills/marketplace/adapters/skillhub/adapter.js +292 -0
  99. package/dist/src/agent/skills/marketplace/adapters/skillhub/adapter.js.map +1 -0
  100. package/dist/src/agent/skills/marketplace/adapters/skillhub/ecosystem-client.d.ts +73 -0
  101. package/dist/src/agent/skills/marketplace/adapters/skillhub/ecosystem-client.js +200 -0
  102. package/dist/src/agent/skills/marketplace/adapters/skillhub/ecosystem-client.js.map +1 -0
  103. package/dist/src/agent/skills/marketplace/adapters/skillhub/registry-client.d.ts +137 -0
  104. package/dist/src/agent/skills/marketplace/adapters/skillhub/registry-client.js +217 -0
  105. package/dist/src/agent/skills/marketplace/adapters/skillhub/registry-client.js.map +1 -0
  106. package/dist/src/agent/skills/marketplace/adapters/skillhub/skillhub-fetch-cache.d.ts +12 -0
  107. package/dist/src/agent/skills/marketplace/adapters/skillhub/skillhub-fetch-cache.js +90 -0
  108. package/dist/src/agent/skills/marketplace/adapters/skillhub/skillhub-fetch-cache.js.map +1 -0
  109. package/dist/src/agent/skills/marketplace/adapters/store/adapter.d.ts +2 -0
  110. package/dist/src/agent/skills/marketplace/adapters/store/adapter.js +35 -0
  111. package/dist/src/agent/skills/marketplace/adapters/store/adapter.js.map +1 -0
  112. package/dist/src/agent/skills/marketplace/adapters/store/store-api-client.d.ts +124 -0
  113. package/dist/src/agent/skills/{skills-store-client.js → marketplace/adapters/store/store-api-client.js} +4 -3
  114. package/dist/src/agent/skills/marketplace/adapters/store/store-api-client.js.map +1 -0
  115. package/dist/src/agent/skills/marketplace/resolve-adapter.d.ts +6 -0
  116. package/dist/src/agent/skills/marketplace/resolve-adapter.js +26 -0
  117. package/dist/src/agent/skills/marketplace/resolve-adapter.js.map +1 -0
  118. package/dist/src/agent/skills/parse-skill-metadata.d.ts +5 -0
  119. package/dist/src/agent/skills/parse-skill-metadata.js +27 -0
  120. package/dist/src/agent/skills/parse-skill-metadata.js.map +1 -0
  121. package/dist/src/agent/skills/skill-markdown-preview-from-raw.d.ts +6 -0
  122. package/dist/src/agent/skills/skill-markdown-preview-from-raw.js +64 -0
  123. package/dist/src/agent/skills/skill-markdown-preview-from-raw.js.map +1 -0
  124. package/dist/src/agent/skills/skill-view-path.d.ts +17 -1
  125. package/dist/src/agent/skills/skill-view-path.js +66 -3
  126. package/dist/src/agent/skills/skill-view-path.js.map +1 -1
  127. package/dist/src/agent/skills/skills-marketplace.d.ts +21 -0
  128. package/dist/src/agent/skills/skills-marketplace.js +18 -0
  129. package/dist/src/agent/skills/skills-marketplace.js.map +1 -0
  130. package/dist/src/agent/skills/test-framework.d.ts +0 -1
  131. package/dist/src/agent/skills/test-framework.js +2 -20
  132. package/dist/src/agent/skills/test-framework.js.map +1 -1
  133. package/dist/src/agent/skills/types.d.ts +12 -6
  134. package/dist/src/agent/tools/dreaming-tool.js +1 -1
  135. package/dist/src/agent/tools/image-generate-tool.js +2 -2
  136. package/dist/src/auth/credentials.js +8 -6
  137. package/dist/src/auth/credentials.js.map +1 -1
  138. package/dist/src/auth/profiles/store.js +5 -3
  139. package/dist/src/auth/profiles/store.js.map +1 -1
  140. package/dist/src/channels/manager.js +1 -1
  141. package/dist/src/channels/outbound/persist-store.js +4 -4
  142. package/dist/src/channels/outbound/persist-store.js.map +1 -1
  143. package/dist/src/cli/commands/config.js +8 -6
  144. package/dist/src/cli/commands/config.js.map +1 -1
  145. package/dist/src/cli/commands/doctor/checks/channel-config.js +3 -4
  146. package/dist/src/cli/commands/doctor/checks/channel-config.js.map +1 -1
  147. package/dist/src/cli/commands/init.js +4 -2
  148. package/dist/src/cli/commands/init.js.map +1 -1
  149. package/dist/src/config/loader.js +3 -1
  150. package/dist/src/config/loader.js.map +1 -1
  151. package/dist/src/config/models-json.js +4 -5
  152. package/dist/src/config/models-json.js.map +1 -1
  153. package/dist/src/config/schema.d.ts +12 -4
  154. package/dist/src/config/schema.js +31 -5
  155. package/dist/src/config/schema.js.map +1 -1
  156. package/dist/src/cron/persistence.d.ts +1 -3
  157. package/dist/src/cron/persistence.js +6 -17
  158. package/dist/src/cron/persistence.js.map +1 -1
  159. package/dist/src/cron/validation.js +1 -1
  160. package/dist/src/cron/validation.js.map +1 -1
  161. package/dist/src/extensions/activation-context.js +0 -1
  162. package/dist/src/extensions/activation-context.js.map +1 -1
  163. package/dist/src/extensions/lockfile.js +4 -2
  164. package/dist/src/extensions/lockfile.js.map +1 -1
  165. package/dist/src/gateway/auth.d.ts +0 -9
  166. package/dist/src/gateway/auth.js +1 -12
  167. package/dist/src/gateway/auth.js.map +1 -1
  168. package/dist/src/gateway/hono/lib/config-payload.d.ts +1 -1
  169. package/dist/src/gateway/hono/lib/extension-store.js +4 -4
  170. package/dist/src/gateway/hono/lib/extension-store.js.map +1 -1
  171. package/dist/src/gateway/hono/routes/channels.js +5 -3
  172. package/dist/src/gateway/hono/routes/channels.js.map +1 -1
  173. package/dist/src/gateway/hono/routes/commands-skills.js +28 -3
  174. package/dist/src/gateway/hono/routes/commands-skills.js.map +1 -1
  175. package/dist/src/gateway/hono/routes/config.js +23 -2
  176. package/dist/src/gateway/hono/routes/config.js.map +1 -1
  177. package/dist/src/gateway/hono/routes/sessions.js +124 -2
  178. package/dist/src/gateway/hono/routes/sessions.js.map +1 -1
  179. package/dist/src/gateway/hono/sse.js +9 -2
  180. package/dist/src/gateway/hono/sse.js.map +1 -1
  181. package/dist/src/gateway/index.js +2 -2
  182. package/dist/src/gateway/lock.js +1 -1
  183. package/dist/src/gateway/service/run-gateway-agent.d.ts +37 -0
  184. package/dist/src/gateway/service/run-gateway-agent.js +163 -0
  185. package/dist/src/gateway/service/run-gateway-agent.js.map +1 -0
  186. package/dist/src/gateway/service/save-webchat-user-message.d.ts +9 -0
  187. package/dist/src/gateway/service/save-webchat-user-message.js +34 -0
  188. package/dist/src/gateway/service/save-webchat-user-message.js.map +1 -0
  189. package/dist/src/gateway/service/session-chat-ids.d.ts +9 -0
  190. package/dist/src/gateway/service/session-chat-ids.js +33 -0
  191. package/dist/src/gateway/service/session-chat-ids.js.map +1 -0
  192. package/dist/src/gateway/service/sse-hub.d.ts +10 -0
  193. package/dist/src/gateway/service/sse-hub.js +55 -0
  194. package/dist/src/gateway/service/sse-hub.js.map +1 -0
  195. package/dist/src/gateway/service/types.d.ts +9 -0
  196. package/dist/src/gateway/service/types.js +1 -0
  197. package/dist/src/gateway/service.d.ts +42 -33
  198. package/dist/src/gateway/service.js +92 -246
  199. package/dist/src/gateway/service.js.map +1 -1
  200. package/dist/src/infra/update-lock.js +4 -2
  201. package/dist/src/infra/update-lock.js.map +1 -1
  202. package/dist/src/infra/update-startup.js +5 -14
  203. package/dist/src/infra/update-startup.js.map +1 -1
  204. package/dist/src/infra/write-file-atomic.d.ts +18 -0
  205. package/dist/src/infra/write-file-atomic.js +115 -0
  206. package/dist/src/infra/write-file-atomic.js.map +1 -0
  207. package/dist/src/session/abort-cutoff.d.ts +6 -0
  208. package/dist/src/session/abort-cutoff.js +10 -0
  209. package/dist/src/session/abort-cutoff.js.map +1 -0
  210. package/dist/src/session/compaction-checkpoints.d.ts +8 -0
  211. package/dist/src/session/compaction-checkpoints.js +21 -0
  212. package/dist/src/session/compaction-checkpoints.js.map +1 -0
  213. package/dist/src/session/config-store.js +4 -2
  214. package/dist/src/session/config-store.js.map +1 -1
  215. package/dist/src/session/index.d.ts +8 -1
  216. package/dist/src/session/index.js +7 -1
  217. package/dist/src/session/manager.d.ts +26 -1
  218. package/dist/src/session/manager.js +39 -2
  219. package/dist/src/session/manager.js.map +1 -1
  220. package/dist/src/session/patch-metadata.d.ts +12 -0
  221. package/dist/src/session/patch-metadata.js +23 -0
  222. package/dist/src/session/patch-metadata.js.map +1 -0
  223. package/dist/src/session/search-index.d.ts +2 -0
  224. package/dist/src/session/search-index.js +30 -2
  225. package/dist/src/session/search-index.js.map +1 -1
  226. package/dist/src/session/session-context-for-llm.d.ts +32 -0
  227. package/dist/src/session/session-context-for-llm.js +60 -0
  228. package/dist/src/session/session-context-for-llm.js.map +1 -0
  229. package/dist/src/session/store.d.ts +53 -2
  230. package/dist/src/session/store.js +427 -145
  231. package/dist/src/session/store.js.map +1 -1
  232. package/dist/src/session/strip-webchat-early-save.d.ts +5 -0
  233. package/dist/src/session/strip-webchat-early-save.js +17 -0
  234. package/dist/src/session/strip-webchat-early-save.js.map +1 -0
  235. package/dist/src/session/transcript-format.d.ts +46 -0
  236. package/dist/src/session/transcript-format.js +88 -0
  237. package/dist/src/session/transcript-format.js.map +1 -0
  238. package/dist/src/session/types.d.ts +37 -0
  239. package/dist/src/session/types.js.map +1 -1
  240. package/dist/src/utils/logger/log-store.js +4 -3
  241. package/dist/src/utils/logger/log-store.js.map +1 -1
  242. package/dist/src/voice/tts/merge-config.js +0 -1
  243. package/dist/src/voice/tts/merge-config.js.map +1 -1
  244. package/dist/src/voice/tts/service.js +1 -2
  245. package/dist/src/voice/tts/service.js.map +1 -1
  246. package/package.json +1 -1
  247. package/skills/business/company-values/SKILL-zh.md +80 -0
  248. package/skills/business/company-values/SKILL.md +80 -0
  249. package/skills/business/find-community/SKILL-zh.md +50 -0
  250. package/skills/business/find-community/SKILL.md +50 -0
  251. package/skills/business/first-customers/SKILL-zh.md +76 -0
  252. package/skills/business/first-customers/SKILL.md +76 -0
  253. package/skills/business/grow-sustainably/SKILL-zh.md +92 -0
  254. package/skills/business/grow-sustainably/SKILL.md +92 -0
  255. package/skills/business/marketing-plan/SKILL-zh.md +100 -0
  256. package/skills/business/marketing-plan/SKILL.md +100 -0
  257. package/skills/business/minimalist-review/SKILL-zh.md +82 -0
  258. package/skills/business/minimalist-review/SKILL.md +82 -0
  259. package/skills/business/mvp/SKILL-zh.md +81 -0
  260. package/skills/business/mvp/SKILL.md +81 -0
  261. package/skills/business/pricing/SKILL-zh.md +64 -0
  262. package/skills/business/pricing/SKILL.md +64 -0
  263. package/skills/business/processize/SKILL-zh.md +91 -0
  264. package/skills/business/processize/SKILL.md +91 -0
  265. package/skills/business/validate-idea/SKILL-zh.md +68 -0
  266. package/skills/business/validate-idea/SKILL.md +68 -0
  267. package/skills/{skill-creator → creative/algorithmic-art}/LICENSE.txt +1 -1
  268. package/skills/creative/algorithmic-art/SKILL-zh.md +405 -0
  269. package/skills/creative/algorithmic-art/SKILL.md +405 -0
  270. package/skills/creative/algorithmic-art/templates/generator_template.js +223 -0
  271. package/skills/creative/algorithmic-art/templates/viewer.html +599 -0
  272. package/skills/creative/canvas-design/LICENSE.txt +202 -0
  273. package/skills/creative/canvas-design/SKILL-zh.md +130 -0
  274. package/skills/creative/canvas-design/SKILL.md +130 -0
  275. package/skills/creative/canvas-design/canvas-fonts/ArsenalSC-OFL.txt +93 -0
  276. package/skills/creative/canvas-design/canvas-fonts/ArsenalSC-Regular.ttf +0 -0
  277. package/skills/creative/canvas-design/canvas-fonts/BigShoulders-Bold.ttf +0 -0
  278. package/skills/creative/canvas-design/canvas-fonts/BigShoulders-OFL.txt +93 -0
  279. package/skills/creative/canvas-design/canvas-fonts/BigShoulders-Regular.ttf +0 -0
  280. package/skills/creative/canvas-design/canvas-fonts/Boldonse-OFL.txt +93 -0
  281. package/skills/creative/canvas-design/canvas-fonts/Boldonse-Regular.ttf +0 -0
  282. package/skills/creative/canvas-design/canvas-fonts/BricolageGrotesque-Bold.ttf +0 -0
  283. package/skills/creative/canvas-design/canvas-fonts/BricolageGrotesque-OFL.txt +93 -0
  284. package/skills/creative/canvas-design/canvas-fonts/BricolageGrotesque-Regular.ttf +0 -0
  285. package/skills/creative/canvas-design/canvas-fonts/CrimsonPro-Bold.ttf +0 -0
  286. package/skills/creative/canvas-design/canvas-fonts/CrimsonPro-Italic.ttf +0 -0
  287. package/skills/creative/canvas-design/canvas-fonts/CrimsonPro-OFL.txt +93 -0
  288. package/skills/creative/canvas-design/canvas-fonts/CrimsonPro-Regular.ttf +0 -0
  289. package/skills/creative/canvas-design/canvas-fonts/DMMono-OFL.txt +93 -0
  290. package/skills/creative/canvas-design/canvas-fonts/DMMono-Regular.ttf +0 -0
  291. package/skills/creative/canvas-design/canvas-fonts/EricaOne-OFL.txt +94 -0
  292. package/skills/creative/canvas-design/canvas-fonts/EricaOne-Regular.ttf +0 -0
  293. package/skills/creative/canvas-design/canvas-fonts/GeistMono-Bold.ttf +0 -0
  294. package/skills/creative/canvas-design/canvas-fonts/GeistMono-OFL.txt +93 -0
  295. package/skills/creative/canvas-design/canvas-fonts/GeistMono-Regular.ttf +0 -0
  296. package/skills/creative/canvas-design/canvas-fonts/Gloock-OFL.txt +93 -0
  297. package/skills/creative/canvas-design/canvas-fonts/Gloock-Regular.ttf +0 -0
  298. package/skills/creative/canvas-design/canvas-fonts/IBMPlexMono-Bold.ttf +0 -0
  299. package/skills/creative/canvas-design/canvas-fonts/IBMPlexMono-OFL.txt +93 -0
  300. package/skills/creative/canvas-design/canvas-fonts/IBMPlexMono-Regular.ttf +0 -0
  301. package/skills/creative/canvas-design/canvas-fonts/IBMPlexSerif-Bold.ttf +0 -0
  302. package/skills/creative/canvas-design/canvas-fonts/IBMPlexSerif-BoldItalic.ttf +0 -0
  303. package/skills/creative/canvas-design/canvas-fonts/IBMPlexSerif-Italic.ttf +0 -0
  304. package/skills/creative/canvas-design/canvas-fonts/IBMPlexSerif-Regular.ttf +0 -0
  305. package/skills/creative/canvas-design/canvas-fonts/InstrumentSans-Bold.ttf +0 -0
  306. package/skills/creative/canvas-design/canvas-fonts/InstrumentSans-BoldItalic.ttf +0 -0
  307. package/skills/creative/canvas-design/canvas-fonts/InstrumentSans-Italic.ttf +0 -0
  308. package/skills/creative/canvas-design/canvas-fonts/InstrumentSans-OFL.txt +93 -0
  309. package/skills/creative/canvas-design/canvas-fonts/InstrumentSans-Regular.ttf +0 -0
  310. package/skills/creative/canvas-design/canvas-fonts/InstrumentSerif-Italic.ttf +0 -0
  311. package/skills/creative/canvas-design/canvas-fonts/InstrumentSerif-Regular.ttf +0 -0
  312. package/skills/creative/canvas-design/canvas-fonts/Italiana-OFL.txt +93 -0
  313. package/skills/creative/canvas-design/canvas-fonts/Italiana-Regular.ttf +0 -0
  314. package/skills/creative/canvas-design/canvas-fonts/JetBrainsMono-Bold.ttf +0 -0
  315. package/skills/creative/canvas-design/canvas-fonts/JetBrainsMono-OFL.txt +93 -0
  316. package/skills/creative/canvas-design/canvas-fonts/JetBrainsMono-Regular.ttf +0 -0
  317. package/skills/creative/canvas-design/canvas-fonts/Jura-Light.ttf +0 -0
  318. package/skills/creative/canvas-design/canvas-fonts/Jura-Medium.ttf +0 -0
  319. package/skills/creative/canvas-design/canvas-fonts/Jura-OFL.txt +93 -0
  320. package/skills/creative/canvas-design/canvas-fonts/LibreBaskerville-OFL.txt +93 -0
  321. package/skills/creative/canvas-design/canvas-fonts/LibreBaskerville-Regular.ttf +0 -0
  322. package/skills/creative/canvas-design/canvas-fonts/Lora-Bold.ttf +0 -0
  323. package/skills/creative/canvas-design/canvas-fonts/Lora-BoldItalic.ttf +0 -0
  324. package/skills/creative/canvas-design/canvas-fonts/Lora-Italic.ttf +0 -0
  325. package/skills/creative/canvas-design/canvas-fonts/Lora-OFL.txt +93 -0
  326. package/skills/creative/canvas-design/canvas-fonts/Lora-Regular.ttf +0 -0
  327. package/skills/creative/canvas-design/canvas-fonts/NationalPark-Bold.ttf +0 -0
  328. package/skills/creative/canvas-design/canvas-fonts/NationalPark-OFL.txt +93 -0
  329. package/skills/creative/canvas-design/canvas-fonts/NationalPark-Regular.ttf +0 -0
  330. package/skills/creative/canvas-design/canvas-fonts/NothingYouCouldDo-OFL.txt +93 -0
  331. package/skills/creative/canvas-design/canvas-fonts/NothingYouCouldDo-Regular.ttf +0 -0
  332. package/skills/creative/canvas-design/canvas-fonts/Outfit-Bold.ttf +0 -0
  333. package/skills/creative/canvas-design/canvas-fonts/Outfit-OFL.txt +93 -0
  334. package/skills/creative/canvas-design/canvas-fonts/Outfit-Regular.ttf +0 -0
  335. package/skills/creative/canvas-design/canvas-fonts/PixelifySans-Medium.ttf +0 -0
  336. package/skills/creative/canvas-design/canvas-fonts/PixelifySans-OFL.txt +93 -0
  337. package/skills/creative/canvas-design/canvas-fonts/PoiretOne-OFL.txt +93 -0
  338. package/skills/creative/canvas-design/canvas-fonts/PoiretOne-Regular.ttf +0 -0
  339. package/skills/creative/canvas-design/canvas-fonts/RedHatMono-Bold.ttf +0 -0
  340. package/skills/creative/canvas-design/canvas-fonts/RedHatMono-OFL.txt +93 -0
  341. package/skills/creative/canvas-design/canvas-fonts/RedHatMono-Regular.ttf +0 -0
  342. package/skills/creative/canvas-design/canvas-fonts/Silkscreen-OFL.txt +93 -0
  343. package/skills/creative/canvas-design/canvas-fonts/Silkscreen-Regular.ttf +0 -0
  344. package/skills/creative/canvas-design/canvas-fonts/SmoochSans-Medium.ttf +0 -0
  345. package/skills/creative/canvas-design/canvas-fonts/SmoochSans-OFL.txt +93 -0
  346. package/skills/creative/canvas-design/canvas-fonts/Tektur-Medium.ttf +0 -0
  347. package/skills/creative/canvas-design/canvas-fonts/Tektur-OFL.txt +93 -0
  348. package/skills/creative/canvas-design/canvas-fonts/Tektur-Regular.ttf +0 -0
  349. package/skills/creative/canvas-design/canvas-fonts/WorkSans-Bold.ttf +0 -0
  350. package/skills/creative/canvas-design/canvas-fonts/WorkSans-BoldItalic.ttf +0 -0
  351. package/skills/creative/canvas-design/canvas-fonts/WorkSans-Italic.ttf +0 -0
  352. package/skills/creative/canvas-design/canvas-fonts/WorkSans-OFL.txt +93 -0
  353. package/skills/creative/canvas-design/canvas-fonts/WorkSans-Regular.ttf +0 -0
  354. package/skills/creative/canvas-design/canvas-fonts/YoungSerif-OFL.txt +93 -0
  355. package/skills/creative/canvas-design/canvas-fonts/YoungSerif-Regular.ttf +0 -0
  356. package/skills/creative/frontend-design/LICENSE.txt +177 -0
  357. package/skills/creative/frontend-design/SKILL-zh.md +42 -0
  358. package/skills/creative/frontend-design/SKILL.md +42 -0
  359. package/skills/creative/theme-factory/LICENSE.txt +202 -0
  360. package/skills/creative/theme-factory/SKILL-zh.md +59 -0
  361. package/skills/creative/theme-factory/SKILL.md +59 -0
  362. package/skills/creative/theme-factory/theme-showcase.pdf +0 -0
  363. package/skills/creative/theme-factory/themes/arctic-frost.md +19 -0
  364. package/skills/creative/theme-factory/themes/botanical-garden.md +19 -0
  365. package/skills/creative/theme-factory/themes/desert-rose.md +19 -0
  366. package/skills/creative/theme-factory/themes/forest-canopy.md +19 -0
  367. package/skills/creative/theme-factory/themes/golden-hour.md +19 -0
  368. package/skills/creative/theme-factory/themes/midnight-galaxy.md +19 -0
  369. package/skills/creative/theme-factory/themes/modern-minimalist.md +19 -0
  370. package/skills/creative/theme-factory/themes/ocean-depths.md +19 -0
  371. package/skills/creative/theme-factory/themes/sunset-boulevard.md +19 -0
  372. package/skills/creative/theme-factory/themes/tech-innovation.md +19 -0
  373. package/skills/creative/web-artifacts-builder/LICENSE.txt +202 -0
  374. package/skills/creative/web-artifacts-builder/SKILL-zh.md +74 -0
  375. package/skills/creative/web-artifacts-builder/SKILL.md +74 -0
  376. package/skills/creative/web-artifacts-builder/scripts/bundle-artifact.sh +54 -0
  377. package/skills/creative/web-artifacts-builder/scripts/init-artifact.sh +322 -0
  378. package/skills/creative/web-artifacts-builder/scripts/shadcn-components.tar.gz +0 -0
  379. package/skills/documents/doc-coauthoring/SKILL-zh.md +375 -0
  380. package/skills/documents/doc-coauthoring/SKILL.md +375 -0
  381. package/skills/documents/docx/SKILL-zh.md +590 -0
  382. package/skills/{docx → documents/docx}/SKILL.md +11 -11
  383. package/skills/{docx → documents/docx}/scripts/comment.py +2 -2
  384. package/skills/{docx → documents/docx}/scripts/office/helpers/simplify_redlines.py +1 -1
  385. package/skills/{docx → documents/docx}/scripts/office/pack.py +2 -2
  386. package/skills/{xlsx → documents/docx}/scripts/office/validate.py +2 -2
  387. package/skills/{xlsx → documents/docx}/scripts/office/validators/redlining.py +1 -1
  388. package/skills/documents/pdf/SKILL-zh.md +314 -0
  389. package/skills/documents/pptx/SKILL-zh.md +232 -0
  390. package/skills/{pptx → documents/pptx}/editing.md +3 -3
  391. package/skills/{pptx → documents/pptx}/scripts/office/helpers/simplify_redlines.py +1 -1
  392. package/skills/{xlsx → documents/pptx}/scripts/office/pack.py +2 -2
  393. package/skills/{pptx → documents/pptx}/scripts/office/validate.py +2 -2
  394. package/skills/{docx → documents/pptx}/scripts/office/validators/redlining.py +1 -1
  395. package/skills/documents/xlsx/SKILL-zh.md +292 -0
  396. package/skills/{xlsx → documents/xlsx}/scripts/office/helpers/simplify_redlines.py +1 -1
  397. package/skills/{pptx → documents/xlsx}/scripts/office/pack.py +2 -2
  398. package/skills/{docx → documents/xlsx}/scripts/office/validate.py +2 -2
  399. package/skills/{pptx → documents/xlsx}/scripts/office/validators/redlining.py +1 -1
  400. package/skills/meta/skill-creator/LICENSE.txt +202 -0
  401. package/skills/meta/skill-creator/SKILL-zh.md +483 -0
  402. package/skills/{skill-creator → meta/skill-creator}/SKILL.md +0 -1
  403. package/skills/tools/find-skills/SKILL-zh.md +440 -0
  404. package/skills/tools/github/SKILL-zh.md +48 -0
  405. package/skills/tools/internal-comms/LICENSE.txt +202 -0
  406. package/skills/tools/internal-comms/SKILL-zh.md +32 -0
  407. package/skills/tools/internal-comms/SKILL.md +32 -0
  408. package/skills/tools/internal-comms/examples/3p-updates.md +47 -0
  409. package/skills/tools/internal-comms/examples/company-newsletter.md +65 -0
  410. package/skills/tools/internal-comms/examples/faq-answers.md +30 -0
  411. package/skills/tools/internal-comms/examples/general-comms.md +16 -0
  412. package/skills/tools/summarize/SKILL-zh.md +47 -0
  413. package/skills/tools/weather/SKILL-zh.md +46 -0
  414. package/skills/tools/webapp-testing/LICENSE.txt +202 -0
  415. package/skills/tools/webapp-testing/SKILL-zh.md +96 -0
  416. package/skills/tools/webapp-testing/SKILL.md +96 -0
  417. package/skills/tools/webapp-testing/examples/console_logging.py +35 -0
  418. package/skills/tools/webapp-testing/examples/element_discovery.py +40 -0
  419. package/skills/tools/webapp-testing/examples/static_html_automation.py +33 -0
  420. package/skills/tools/webapp-testing/scripts/with_server.py +106 -0
  421. package/dist/gateway/static/root/assets/agents-CkgFSiCY.js +0 -216
  422. package/dist/gateway/static/root/assets/agents-CkgFSiCY.js.map +0 -1
  423. package/dist/gateway/static/root/assets/channels-settings-CE7jrdkO.js +0 -9
  424. package/dist/gateway/static/root/assets/channels-settings-CE7jrdkO.js.map +0 -1
  425. package/dist/gateway/static/root/assets/cron-page-BpPPcykJ.js +0 -2
  426. package/dist/gateway/static/root/assets/cron-page-BpPPcykJ.js.map +0 -1
  427. package/dist/gateway/static/root/assets/cron-utils-N1PqD2DB.js +0 -3
  428. package/dist/gateway/static/root/assets/cron-utils-N1PqD2DB.js.map +0 -1
  429. package/dist/gateway/static/root/assets/dist--p2HQ2QF.js +0 -2
  430. package/dist/gateway/static/root/assets/index-Dnfha4O2.css +0 -1
  431. package/dist/gateway/static/root/assets/logs-page-CQwdV_Xw.js +0 -2
  432. package/dist/gateway/static/root/assets/logs-page-CQwdV_Xw.js.map +0 -1
  433. package/dist/gateway/static/root/assets/sessions-page-Be5kIGl_.js +0 -2
  434. package/dist/gateway/static/root/assets/settings-page-PodSlNwr.js +0 -2
  435. package/dist/gateway/static/root/assets/settings-page-PodSlNwr.js.map +0 -1
  436. package/dist/gateway/static/root/assets/skills-page-Clg8deH0.js +0 -3
  437. package/dist/gateway/static/root/assets/skills-page-Clg8deH0.js.map +0 -1
  438. package/dist/src/agent/skills/skills-store-client.d.ts +0 -66
  439. package/dist/src/agent/skills/skills-store-client.js.map +0 -1
  440. package/dist/src/stt/index.d.ts +0 -1
  441. package/dist/src/stt/index.js +0 -8
  442. /package/skills/{docx → documents/docx}/LICENSE.txt +0 -0
  443. /package/skills/{docx → documents/docx}/scripts/__init__.py +0 -0
  444. /package/skills/{docx → documents/docx}/scripts/accept_changes.py +0 -0
  445. /package/skills/{docx → documents/docx}/scripts/office/helpers/__init__.py +0 -0
  446. /package/skills/{docx → documents/docx}/scripts/office/helpers/merge_runs.py +0 -0
  447. /package/skills/{docx → documents/docx}/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +0 -0
  448. /package/skills/{docx → documents/docx}/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +0 -0
  449. /package/skills/{docx → documents/docx}/scripts/office/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +0 -0
  450. /package/skills/{docx → documents/docx}/scripts/office/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +0 -0
  451. /package/skills/{docx → documents/docx}/scripts/office/schemas/ISO-IEC29500-4_2016/dml-main.xsd +0 -0
  452. /package/skills/{docx → documents/docx}/scripts/office/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +0 -0
  453. /package/skills/{docx → documents/docx}/scripts/office/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +0 -0
  454. /package/skills/{docx → documents/docx}/scripts/office/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +0 -0
  455. /package/skills/{docx → documents/docx}/scripts/office/schemas/ISO-IEC29500-4_2016/pml.xsd +0 -0
  456. /package/skills/{docx → documents/docx}/scripts/office/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +0 -0
  457. /package/skills/{docx → documents/docx}/scripts/office/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +0 -0
  458. /package/skills/{docx → documents/docx}/scripts/office/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +0 -0
  459. /package/skills/{docx → documents/docx}/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +0 -0
  460. /package/skills/{docx → documents/docx}/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +0 -0
  461. /package/skills/{docx → documents/docx}/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +0 -0
  462. /package/skills/{docx → documents/docx}/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +0 -0
  463. /package/skills/{docx → documents/docx}/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +0 -0
  464. /package/skills/{docx → documents/docx}/scripts/office/schemas/ISO-IEC29500-4_2016/shared-math.xsd +0 -0
  465. /package/skills/{docx → documents/docx}/scripts/office/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +0 -0
  466. /package/skills/{docx → documents/docx}/scripts/office/schemas/ISO-IEC29500-4_2016/sml.xsd +0 -0
  467. /package/skills/{docx → documents/docx}/scripts/office/schemas/ISO-IEC29500-4_2016/vml-main.xsd +0 -0
  468. /package/skills/{docx → documents/docx}/scripts/office/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +0 -0
  469. /package/skills/{docx → documents/docx}/scripts/office/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +0 -0
  470. /package/skills/{docx → documents/docx}/scripts/office/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +0 -0
  471. /package/skills/{docx → documents/docx}/scripts/office/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +0 -0
  472. /package/skills/{docx → documents/docx}/scripts/office/schemas/ISO-IEC29500-4_2016/wml.xsd +0 -0
  473. /package/skills/{docx → documents/docx}/scripts/office/schemas/ISO-IEC29500-4_2016/xml.xsd +0 -0
  474. /package/skills/{docx → documents/docx}/scripts/office/schemas/ecma/fouth-edition/opc-contentTypes.xsd +0 -0
  475. /package/skills/{docx → documents/docx}/scripts/office/schemas/ecma/fouth-edition/opc-coreProperties.xsd +0 -0
  476. /package/skills/{docx → documents/docx}/scripts/office/schemas/ecma/fouth-edition/opc-digSig.xsd +0 -0
  477. /package/skills/{docx → documents/docx}/scripts/office/schemas/ecma/fouth-edition/opc-relationships.xsd +0 -0
  478. /package/skills/{docx → documents/docx}/scripts/office/schemas/mce/mc.xsd +0 -0
  479. /package/skills/{docx → documents/docx}/scripts/office/schemas/microsoft/wml-2010.xsd +0 -0
  480. /package/skills/{docx → documents/docx}/scripts/office/schemas/microsoft/wml-2012.xsd +0 -0
  481. /package/skills/{docx → documents/docx}/scripts/office/schemas/microsoft/wml-2018.xsd +0 -0
  482. /package/skills/{docx → documents/docx}/scripts/office/schemas/microsoft/wml-cex-2018.xsd +0 -0
  483. /package/skills/{docx → documents/docx}/scripts/office/schemas/microsoft/wml-cid-2016.xsd +0 -0
  484. /package/skills/{docx → documents/docx}/scripts/office/schemas/microsoft/wml-sdtdatahash-2020.xsd +0 -0
  485. /package/skills/{docx → documents/docx}/scripts/office/schemas/microsoft/wml-symex-2015.xsd +0 -0
  486. /package/skills/{docx → documents/docx}/scripts/office/soffice.py +0 -0
  487. /package/skills/{docx → documents/docx}/scripts/office/unpack.py +0 -0
  488. /package/skills/{docx → documents/docx}/scripts/office/validators/__init__.py +0 -0
  489. /package/skills/{docx → documents/docx}/scripts/office/validators/base.py +0 -0
  490. /package/skills/{docx → documents/docx}/scripts/office/validators/docx.py +0 -0
  491. /package/skills/{docx → documents/docx}/scripts/office/validators/pptx.py +0 -0
  492. /package/skills/{docx → documents/docx}/scripts/templates/comments.xml +0 -0
  493. /package/skills/{docx → documents/docx}/scripts/templates/commentsExtended.xml +0 -0
  494. /package/skills/{docx → documents/docx}/scripts/templates/commentsExtensible.xml +0 -0
  495. /package/skills/{docx → documents/docx}/scripts/templates/commentsIds.xml +0 -0
  496. /package/skills/{docx → documents/docx}/scripts/templates/people.xml +0 -0
  497. /package/skills/{pdf → documents/pdf}/LICENSE.txt +0 -0
  498. /package/skills/{pdf → documents/pdf}/SKILL.md +0 -0
  499. /package/skills/{pdf → documents/pdf}/forms.md +0 -0
  500. /package/skills/{pdf → documents/pdf}/reference.md +0 -0
  501. /package/skills/{pdf → documents/pdf}/scripts/check_bounding_boxes.py +0 -0
  502. /package/skills/{pdf → documents/pdf}/scripts/check_fillable_fields.py +0 -0
  503. /package/skills/{pdf → documents/pdf}/scripts/convert_pdf_to_images.py +0 -0
  504. /package/skills/{pdf → documents/pdf}/scripts/create_validation_image.py +0 -0
  505. /package/skills/{pdf → documents/pdf}/scripts/extract_form_field_info.py +0 -0
  506. /package/skills/{pdf → documents/pdf}/scripts/extract_form_structure.py +0 -0
  507. /package/skills/{pdf → documents/pdf}/scripts/fill_fillable_fields.py +0 -0
  508. /package/skills/{pdf → documents/pdf}/scripts/fill_pdf_form_with_annotations.py +0 -0
  509. /package/skills/{pptx → documents/pptx}/LICENSE.txt +0 -0
  510. /package/skills/{pptx → documents/pptx}/SKILL.md +0 -0
  511. /package/skills/{pptx → documents/pptx}/pptxgenjs.md +0 -0
  512. /package/skills/{pptx → documents/pptx}/scripts/__init__.py +0 -0
  513. /package/skills/{pptx → documents/pptx}/scripts/add_slide.py +0 -0
  514. /package/skills/{pptx → documents/pptx}/scripts/clean.py +0 -0
  515. /package/skills/{pptx → documents/pptx}/scripts/office/helpers/__init__.py +0 -0
  516. /package/skills/{pptx → documents/pptx}/scripts/office/helpers/merge_runs.py +0 -0
  517. /package/skills/{pptx → documents/pptx}/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +0 -0
  518. /package/skills/{pptx → documents/pptx}/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +0 -0
  519. /package/skills/{pptx → documents/pptx}/scripts/office/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +0 -0
  520. /package/skills/{pptx → documents/pptx}/scripts/office/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +0 -0
  521. /package/skills/{pptx → documents/pptx}/scripts/office/schemas/ISO-IEC29500-4_2016/dml-main.xsd +0 -0
  522. /package/skills/{pptx → documents/pptx}/scripts/office/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +0 -0
  523. /package/skills/{pptx → documents/pptx}/scripts/office/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +0 -0
  524. /package/skills/{pptx → documents/pptx}/scripts/office/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +0 -0
  525. /package/skills/{pptx → documents/pptx}/scripts/office/schemas/ISO-IEC29500-4_2016/pml.xsd +0 -0
  526. /package/skills/{pptx → documents/pptx}/scripts/office/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +0 -0
  527. /package/skills/{pptx → documents/pptx}/scripts/office/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +0 -0
  528. /package/skills/{pptx → documents/pptx}/scripts/office/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +0 -0
  529. /package/skills/{pptx → documents/pptx}/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +0 -0
  530. /package/skills/{pptx → documents/pptx}/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +0 -0
  531. /package/skills/{pptx → documents/pptx}/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +0 -0
  532. /package/skills/{pptx → documents/pptx}/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +0 -0
  533. /package/skills/{pptx → documents/pptx}/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +0 -0
  534. /package/skills/{pptx → documents/pptx}/scripts/office/schemas/ISO-IEC29500-4_2016/shared-math.xsd +0 -0
  535. /package/skills/{pptx → documents/pptx}/scripts/office/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +0 -0
  536. /package/skills/{pptx → documents/pptx}/scripts/office/schemas/ISO-IEC29500-4_2016/sml.xsd +0 -0
  537. /package/skills/{pptx → documents/pptx}/scripts/office/schemas/ISO-IEC29500-4_2016/vml-main.xsd +0 -0
  538. /package/skills/{pptx → documents/pptx}/scripts/office/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +0 -0
  539. /package/skills/{pptx → documents/pptx}/scripts/office/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +0 -0
  540. /package/skills/{pptx → documents/pptx}/scripts/office/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +0 -0
  541. /package/skills/{pptx → documents/pptx}/scripts/office/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +0 -0
  542. /package/skills/{pptx → documents/pptx}/scripts/office/schemas/ISO-IEC29500-4_2016/wml.xsd +0 -0
  543. /package/skills/{pptx → documents/pptx}/scripts/office/schemas/ISO-IEC29500-4_2016/xml.xsd +0 -0
  544. /package/skills/{pptx → documents/pptx}/scripts/office/schemas/ecma/fouth-edition/opc-contentTypes.xsd +0 -0
  545. /package/skills/{pptx → documents/pptx}/scripts/office/schemas/ecma/fouth-edition/opc-coreProperties.xsd +0 -0
  546. /package/skills/{pptx → documents/pptx}/scripts/office/schemas/ecma/fouth-edition/opc-digSig.xsd +0 -0
  547. /package/skills/{pptx → documents/pptx}/scripts/office/schemas/ecma/fouth-edition/opc-relationships.xsd +0 -0
  548. /package/skills/{pptx → documents/pptx}/scripts/office/schemas/mce/mc.xsd +0 -0
  549. /package/skills/{pptx → documents/pptx}/scripts/office/schemas/microsoft/wml-2010.xsd +0 -0
  550. /package/skills/{pptx → documents/pptx}/scripts/office/schemas/microsoft/wml-2012.xsd +0 -0
  551. /package/skills/{pptx → documents/pptx}/scripts/office/schemas/microsoft/wml-2018.xsd +0 -0
  552. /package/skills/{pptx → documents/pptx}/scripts/office/schemas/microsoft/wml-cex-2018.xsd +0 -0
  553. /package/skills/{pptx → documents/pptx}/scripts/office/schemas/microsoft/wml-cid-2016.xsd +0 -0
  554. /package/skills/{pptx → documents/pptx}/scripts/office/schemas/microsoft/wml-sdtdatahash-2020.xsd +0 -0
  555. /package/skills/{pptx → documents/pptx}/scripts/office/schemas/microsoft/wml-symex-2015.xsd +0 -0
  556. /package/skills/{pptx → documents/pptx}/scripts/office/soffice.py +0 -0
  557. /package/skills/{pptx → documents/pptx}/scripts/office/unpack.py +0 -0
  558. /package/skills/{pptx → documents/pptx}/scripts/office/validators/__init__.py +0 -0
  559. /package/skills/{pptx → documents/pptx}/scripts/office/validators/base.py +0 -0
  560. /package/skills/{pptx → documents/pptx}/scripts/office/validators/docx.py +0 -0
  561. /package/skills/{pptx → documents/pptx}/scripts/office/validators/pptx.py +0 -0
  562. /package/skills/{pptx → documents/pptx}/scripts/thumbnail.py +0 -0
  563. /package/skills/{xlsx → documents/xlsx}/LICENSE.txt +0 -0
  564. /package/skills/{xlsx → documents/xlsx}/SKILL.md +0 -0
  565. /package/skills/{skill-creator/scripts → documents/xlsx/scripts/office/helpers}/__init__.py +0 -0
  566. /package/skills/{xlsx → documents/xlsx}/scripts/office/helpers/merge_runs.py +0 -0
  567. /package/skills/{xlsx → documents/xlsx}/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +0 -0
  568. /package/skills/{xlsx → documents/xlsx}/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +0 -0
  569. /package/skills/{xlsx → documents/xlsx}/scripts/office/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +0 -0
  570. /package/skills/{xlsx → documents/xlsx}/scripts/office/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +0 -0
  571. /package/skills/{xlsx → documents/xlsx}/scripts/office/schemas/ISO-IEC29500-4_2016/dml-main.xsd +0 -0
  572. /package/skills/{xlsx → documents/xlsx}/scripts/office/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +0 -0
  573. /package/skills/{xlsx → documents/xlsx}/scripts/office/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +0 -0
  574. /package/skills/{xlsx → documents/xlsx}/scripts/office/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +0 -0
  575. /package/skills/{xlsx → documents/xlsx}/scripts/office/schemas/ISO-IEC29500-4_2016/pml.xsd +0 -0
  576. /package/skills/{xlsx → documents/xlsx}/scripts/office/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +0 -0
  577. /package/skills/{xlsx → documents/xlsx}/scripts/office/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +0 -0
  578. /package/skills/{xlsx → documents/xlsx}/scripts/office/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +0 -0
  579. /package/skills/{xlsx → documents/xlsx}/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +0 -0
  580. /package/skills/{xlsx → documents/xlsx}/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +0 -0
  581. /package/skills/{xlsx → documents/xlsx}/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +0 -0
  582. /package/skills/{xlsx → documents/xlsx}/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +0 -0
  583. /package/skills/{xlsx → documents/xlsx}/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +0 -0
  584. /package/skills/{xlsx → documents/xlsx}/scripts/office/schemas/ISO-IEC29500-4_2016/shared-math.xsd +0 -0
  585. /package/skills/{xlsx → documents/xlsx}/scripts/office/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +0 -0
  586. /package/skills/{xlsx → documents/xlsx}/scripts/office/schemas/ISO-IEC29500-4_2016/sml.xsd +0 -0
  587. /package/skills/{xlsx → documents/xlsx}/scripts/office/schemas/ISO-IEC29500-4_2016/vml-main.xsd +0 -0
  588. /package/skills/{xlsx → documents/xlsx}/scripts/office/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +0 -0
  589. /package/skills/{xlsx → documents/xlsx}/scripts/office/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +0 -0
  590. /package/skills/{xlsx → documents/xlsx}/scripts/office/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +0 -0
  591. /package/skills/{xlsx → documents/xlsx}/scripts/office/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +0 -0
  592. /package/skills/{xlsx → documents/xlsx}/scripts/office/schemas/ISO-IEC29500-4_2016/wml.xsd +0 -0
  593. /package/skills/{xlsx → documents/xlsx}/scripts/office/schemas/ISO-IEC29500-4_2016/xml.xsd +0 -0
  594. /package/skills/{xlsx → documents/xlsx}/scripts/office/schemas/ecma/fouth-edition/opc-contentTypes.xsd +0 -0
  595. /package/skills/{xlsx → documents/xlsx}/scripts/office/schemas/ecma/fouth-edition/opc-coreProperties.xsd +0 -0
  596. /package/skills/{xlsx → documents/xlsx}/scripts/office/schemas/ecma/fouth-edition/opc-digSig.xsd +0 -0
  597. /package/skills/{xlsx → documents/xlsx}/scripts/office/schemas/ecma/fouth-edition/opc-relationships.xsd +0 -0
  598. /package/skills/{xlsx → documents/xlsx}/scripts/office/schemas/mce/mc.xsd +0 -0
  599. /package/skills/{xlsx → documents/xlsx}/scripts/office/schemas/microsoft/wml-2010.xsd +0 -0
  600. /package/skills/{xlsx → documents/xlsx}/scripts/office/schemas/microsoft/wml-2012.xsd +0 -0
  601. /package/skills/{xlsx → documents/xlsx}/scripts/office/schemas/microsoft/wml-2018.xsd +0 -0
  602. /package/skills/{xlsx → documents/xlsx}/scripts/office/schemas/microsoft/wml-cex-2018.xsd +0 -0
  603. /package/skills/{xlsx → documents/xlsx}/scripts/office/schemas/microsoft/wml-cid-2016.xsd +0 -0
  604. /package/skills/{xlsx → documents/xlsx}/scripts/office/schemas/microsoft/wml-sdtdatahash-2020.xsd +0 -0
  605. /package/skills/{xlsx → documents/xlsx}/scripts/office/schemas/microsoft/wml-symex-2015.xsd +0 -0
  606. /package/skills/{xlsx → documents/xlsx}/scripts/office/soffice.py +0 -0
  607. /package/skills/{xlsx → documents/xlsx}/scripts/office/unpack.py +0 -0
  608. /package/skills/{xlsx → documents/xlsx}/scripts/office/validators/__init__.py +0 -0
  609. /package/skills/{xlsx → documents/xlsx}/scripts/office/validators/base.py +0 -0
  610. /package/skills/{xlsx → documents/xlsx}/scripts/office/validators/docx.py +0 -0
  611. /package/skills/{xlsx → documents/xlsx}/scripts/office/validators/pptx.py +0 -0
  612. /package/skills/{xlsx → documents/xlsx}/scripts/recalc.py +0 -0
  613. /package/skills/{skill-creator → meta/skill-creator}/agents/analyzer.md +0 -0
  614. /package/skills/{skill-creator → meta/skill-creator}/agents/comparator.md +0 -0
  615. /package/skills/{skill-creator → meta/skill-creator}/agents/grader.md +0 -0
  616. /package/skills/{skill-creator → meta/skill-creator}/assets/eval_review.html +0 -0
  617. /package/skills/{skill-creator → meta/skill-creator}/eval-viewer/generate_review.py +0 -0
  618. /package/skills/{skill-creator → meta/skill-creator}/eval-viewer/viewer.html +0 -0
  619. /package/skills/{skill-creator → meta/skill-creator}/references/schemas.md +0 -0
  620. /package/skills/{xlsx/scripts/office/helpers → meta/skill-creator/scripts}/__init__.py +0 -0
  621. /package/skills/{skill-creator → meta/skill-creator}/scripts/aggregate_benchmark.py +0 -0
  622. /package/skills/{skill-creator → meta/skill-creator}/scripts/generate_report.py +0 -0
  623. /package/skills/{skill-creator → meta/skill-creator}/scripts/improve_description.py +0 -0
  624. /package/skills/{skill-creator → meta/skill-creator}/scripts/package_skill.py +0 -0
  625. /package/skills/{skill-creator → meta/skill-creator}/scripts/quick_validate.py +0 -0
  626. /package/skills/{skill-creator → meta/skill-creator}/scripts/run_eval.py +0 -0
  627. /package/skills/{skill-creator → meta/skill-creator}/scripts/run_loop.py +0 -0
  628. /package/skills/{skill-creator → meta/skill-creator}/scripts/utils.py +0 -0
  629. /package/skills/{find-skills → tools/find-skills}/SKILL.md +0 -0
  630. /package/skills/{github → tools/github}/SKILL.md +0 -0
  631. /package/skills/{summarize → tools/summarize}/SKILL.md +0 -0
  632. /package/skills/{weather → tools/weather}/SKILL.md +0 -0
@@ -1,8 +1,13 @@
1
- import { resolve, sep } from "path";
2
- import { existsSync, realpathSync } from "fs";
1
+ import { parseFrontmatter } from "../../markdown/frontmatter.js";
2
+ import { parseSkillToolConditions } from "./skill-tool-gating.js";
3
+ import { parseRequiredEnvVarNames } from "./required-env-vars.js";
4
+ import { parseSkillMetadata } from "./parse-skill-metadata.js";
5
+ import { join, resolve, sep } from "path";
6
+ import { existsSync, readFileSync, realpathSync } from "fs";
3
7
  //#region src/agent/skills/skill-view-path.ts
4
8
  /**
5
9
  * Resolve safe paths for skill_view: only SKILL.md (default) or files under allowlisted subdirs.
10
+ * Also provides localized SKILL.md resolution for multi-language display.
6
11
  */
7
12
  const ALLOWED_TOP = new Set([
8
13
  "references",
@@ -66,7 +71,65 @@ function resolveSkillReadablePath(skill, subPath) {
66
71
  };
67
72
  }
68
73
  }
74
+ /**
75
+ * Resolve a localized SKILL.md for display (e.g. SKILL-zh.md, SKILL-en.md).
76
+ * Falls back to the base SKILL.md content if no localized file exists.
77
+ *
78
+ * This is the **display** path — execution always reads the base SKILL.md.
79
+ */
80
+ function resolveLocalizedSkillMarkdown(skill, lang) {
81
+ if (!lang) return null;
82
+ const normalizedLang = lang.split(/[-_]/)[0]?.toLowerCase();
83
+ if (!normalizedLang || normalizedLang === "en") return null;
84
+ const localizedPath = join(skill.baseDir, `SKILL-${normalizedLang}.md`);
85
+ if (!existsSync(localizedPath)) return null;
86
+ try {
87
+ const { frontmatter, content } = parseFrontmatter(readFileSync(localizedPath, "utf-8"));
88
+ const fm = frontmatter;
89
+ const name = typeof fm.name === "string" && fm.name.trim() || skill.name;
90
+ const description = (typeof fm.description === "string" ? fm.description.trim() : "") || skill.description;
91
+ const metadata = parseSkillMetadata(fm);
92
+ if (!metadata.name.trim()) metadata.name = name;
93
+ if (!metadata.description.trim()) metadata.description = description;
94
+ const toolConditions = parseSkillToolConditions(fm);
95
+ const requiredEnvVarNames = parseRequiredEnvVarNames(fm);
96
+ return {
97
+ name,
98
+ description,
99
+ bodyMarkdown: content.trim(),
100
+ disableModelInvocation: skill.disableModelInvocation,
101
+ metadata,
102
+ toolConditions,
103
+ requiredEnvVarNames: requiredEnvVarNames.length > 0 ? requiredEnvVarNames : void 0
104
+ };
105
+ } catch {
106
+ return null;
107
+ }
108
+ }
109
+ /**
110
+ * Lightweight localized name/description lookup (frontmatter only) for list views.
111
+ * Reuses the same SKILL-{lang}.md resolution as {@link resolveLocalizedSkillMarkdown}.
112
+ */
113
+ function resolveLocalizedSkillMeta(skill, lang) {
114
+ const normalizedLang = lang.split(/[-_]/)[0]?.toLowerCase();
115
+ if (!normalizedLang || normalizedLang === "en") return null;
116
+ const localizedPath = join(skill.baseDir, `SKILL-${normalizedLang}.md`);
117
+ if (!existsSync(localizedPath)) return null;
118
+ try {
119
+ const { frontmatter } = parseFrontmatter(readFileSync(localizedPath, "utf-8"));
120
+ const fm = frontmatter;
121
+ const name = typeof fm.name === "string" && fm.name.trim() ? fm.name.trim() : void 0;
122
+ const description = typeof fm.description === "string" && fm.description.trim() ? fm.description.trim() : void 0;
123
+ if (!name && !description) return null;
124
+ return {
125
+ name: name ?? skill.name,
126
+ description: description ?? skill.description
127
+ };
128
+ } catch {
129
+ return null;
130
+ }
131
+ }
69
132
  //#endregion
70
- export { resolveSkillReadablePath };
133
+ export { resolveLocalizedSkillMarkdown, resolveLocalizedSkillMeta, resolveSkillReadablePath };
71
134
 
72
135
  //# sourceMappingURL=skill-view-path.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"skill-view-path.js","names":[],"sources":["../../../../src/agent/skills/skill-view-path.ts"],"sourcesContent":["/**\n * Resolve safe paths for skill_view: only SKILL.md (default) or files under allowlisted subdirs.\n */\n\nimport { existsSync, realpathSync } from 'fs';\nimport { resolve, sep } from 'path';\n\nimport type { Skill } from './types.js';\n\nconst ALLOWED_TOP = new Set(['references', 'templates', 'scripts', 'assets']);\n\nexport type ResolveSkillFileResult =\n | { ok: true; absolutePath: string }\n | { ok: false; error: string };\n\nfunction isSkillMdSegment(p: string): boolean {\n const s = p.trim();\n return s === 'SKILL.md' || s.toLowerCase() === 'skill.md';\n}\n\nfunction isInsideDir(dirReal: string, fileReal: string): boolean {\n const prefix = dirReal.endsWith(sep) ? dirReal : dirReal + sep;\n return fileReal === dirReal || fileReal.startsWith(prefix);\n}\n\n/**\n * Resolve a readable file path for {@link skill}. Empty or SKILL.md → main SKILL.md file.\n * Other paths must live under references/, templates/, scripts/, or assets/.\n */\nexport function resolveSkillReadablePath(\n skill: Skill,\n subPath: string | undefined,\n): ResolveSkillFileResult {\n const base = skill.baseDir;\n const trimmed = subPath?.trim() ?? '';\n\n let target: string;\n if (!trimmed || trimmed === '.' || isSkillMdSegment(trimmed)) {\n target = skill.filePath;\n } else {\n const norm = trimmed.replace(/\\\\/g, '/');\n if (norm.includes('..')) {\n return { ok: false, error: 'Invalid path: path traversal is not allowed.' };\n }\n if (norm.startsWith('/') || /^[A-Za-z]:/.test(norm)) {\n return {\n ok: false,\n error: 'Invalid path: use a path relative to the skill directory.',\n };\n }\n const first = norm.split('/').filter(Boolean)[0] ?? '';\n if (!ALLOWED_TOP.has(first)) {\n return {\n ok: false,\n error: `Invalid path: must be under references/, templates/, scripts/, or assets/ (or omit path for SKILL.md).`,\n };\n }\n target = resolve(base, norm);\n }\n\n try {\n const baseReal = realpathSync(base);\n if (!existsSync(target)) {\n return { ok: false, error: `File not found: ${trimmed || 'SKILL.md'}` };\n }\n const targetReal = realpathSync(target);\n if (!isInsideDir(baseReal, targetReal)) {\n return { ok: false, error: 'Resolved path escapes the skill directory.' };\n }\n return { ok: true, absolutePath: targetReal };\n } catch (e) {\n return { ok: false, error: e instanceof Error ? e.message : String(e) };\n }\n}\n"],"mappings":";;;;;;AASA,MAAM,cAAc,IAAI,IAAI;CAAC;CAAc;CAAa;CAAW;CAAS,CAAC;AAM7E,SAAS,iBAAiB,GAAoB;CAC5C,MAAM,IAAI,EAAE,MAAM;AAClB,QAAO,MAAM,cAAc,EAAE,aAAa,KAAK;;AAGjD,SAAS,YAAY,SAAiB,UAA2B;CAC/D,MAAM,SAAS,QAAQ,SAAS,IAAI,GAAG,UAAU,UAAU;AAC3D,QAAO,aAAa,WAAW,SAAS,WAAW,OAAO;;;;;;AAO5D,SAAgB,yBACd,OACA,SACwB;CACxB,MAAM,OAAO,MAAM;CACnB,MAAM,UAAU,SAAS,MAAM,IAAI;CAEnC,IAAI;AACJ,KAAI,CAAC,WAAW,YAAY,OAAO,iBAAiB,QAAQ,CAC1D,UAAS,MAAM;MACV;EACL,MAAM,OAAO,QAAQ,QAAQ,OAAO,IAAI;AACxC,MAAI,KAAK,SAAS,KAAK,CACrB,QAAO;GAAE,IAAI;GAAO,OAAO;GAAgD;AAE7E,MAAI,KAAK,WAAW,IAAI,IAAI,aAAa,KAAK,KAAK,CACjD,QAAO;GACL,IAAI;GACJ,OAAO;GACR;EAEH,MAAM,QAAQ,KAAK,MAAM,IAAI,CAAC,OAAO,QAAQ,CAAC,MAAM;AACpD,MAAI,CAAC,YAAY,IAAI,MAAM,CACzB,QAAO;GACL,IAAI;GACJ,OAAO;GACR;AAEH,WAAS,QAAQ,MAAM,KAAK;;AAG9B,KAAI;EACF,MAAM,WAAW,aAAa,KAAK;AACnC,MAAI,CAAC,WAAW,OAAO,CACrB,QAAO;GAAE,IAAI;GAAO,OAAO,mBAAmB,WAAW;GAAc;EAEzE,MAAM,aAAa,aAAa,OAAO;AACvC,MAAI,CAAC,YAAY,UAAU,WAAW,CACpC,QAAO;GAAE,IAAI;GAAO,OAAO;GAA8C;AAE3E,SAAO;GAAE,IAAI;GAAM,cAAc;GAAY;UACtC,GAAG;AACV,SAAO;GAAE,IAAI;GAAO,OAAO,aAAa,QAAQ,EAAE,UAAU,OAAO,EAAE;GAAE"}
1
+ {"version":3,"file":"skill-view-path.js","names":[],"sources":["../../../../src/agent/skills/skill-view-path.ts"],"sourcesContent":["/**\n * Resolve safe paths for skill_view: only SKILL.md (default) or files under allowlisted subdirs.\n * Also provides localized SKILL.md resolution for multi-language display.\n */\n\nimport { existsSync, readFileSync, realpathSync } from 'fs';\nimport { join, resolve, sep } from 'path';\n\nimport { parseFrontmatter } from '../../markdown/frontmatter.js';\nimport { parseRequiredEnvVarNames } from './required-env-vars.js';\nimport { parseSkillMetadata } from './parse-skill-metadata.js';\nimport { parseSkillToolConditions } from './skill-tool-gating.js';\nimport type { Skill, SkillMarkdownPreviewPayload } from './types.js';\n\nconst ALLOWED_TOP = new Set(['references', 'templates', 'scripts', 'assets']);\n\nexport type ResolveSkillFileResult =\n | { ok: true; absolutePath: string }\n | { ok: false; error: string };\n\nfunction isSkillMdSegment(p: string): boolean {\n const s = p.trim();\n return s === 'SKILL.md' || s.toLowerCase() === 'skill.md';\n}\n\nfunction isInsideDir(dirReal: string, fileReal: string): boolean {\n const prefix = dirReal.endsWith(sep) ? dirReal : dirReal + sep;\n return fileReal === dirReal || fileReal.startsWith(prefix);\n}\n\n/**\n * Resolve a readable file path for {@link skill}. Empty or SKILL.md → main SKILL.md file.\n * Other paths must live under references/, templates/, scripts/, or assets/.\n */\nexport function resolveSkillReadablePath(\n skill: Skill,\n subPath: string | undefined,\n): ResolveSkillFileResult {\n const base = skill.baseDir;\n const trimmed = subPath?.trim() ?? '';\n\n let target: string;\n if (!trimmed || trimmed === '.' || isSkillMdSegment(trimmed)) {\n target = skill.filePath;\n } else {\n const norm = trimmed.replace(/\\\\/g, '/');\n if (norm.includes('..')) {\n return { ok: false, error: 'Invalid path: path traversal is not allowed.' };\n }\n if (norm.startsWith('/') || /^[A-Za-z]:/.test(norm)) {\n return {\n ok: false,\n error: 'Invalid path: use a path relative to the skill directory.',\n };\n }\n const first = norm.split('/').filter(Boolean)[0] ?? '';\n if (!ALLOWED_TOP.has(first)) {\n return {\n ok: false,\n error: `Invalid path: must be under references/, templates/, scripts/, or assets/ (or omit path for SKILL.md).`,\n };\n }\n target = resolve(base, norm);\n }\n\n try {\n const baseReal = realpathSync(base);\n if (!existsSync(target)) {\n return { ok: false, error: `File not found: ${trimmed || 'SKILL.md'}` };\n }\n const targetReal = realpathSync(target);\n if (!isInsideDir(baseReal, targetReal)) {\n return { ok: false, error: 'Resolved path escapes the skill directory.' };\n }\n return { ok: true, absolutePath: targetReal };\n } catch (e) {\n return { ok: false, error: e instanceof Error ? e.message : String(e) };\n }\n}\n\n/**\n * Resolve a localized SKILL.md for display (e.g. SKILL-zh.md, SKILL-en.md).\n * Falls back to the base SKILL.md content if no localized file exists.\n *\n * This is the **display** path — execution always reads the base SKILL.md.\n */\nexport function resolveLocalizedSkillMarkdown(\n skill: Skill,\n lang?: string,\n): SkillMarkdownPreviewPayload | null {\n if (!lang) {\n return null; // caller should fall back to skill.content\n }\n\n // Normalize: prefer two-letter code\n const normalizedLang = lang.split(/[-_]/)[0]?.toLowerCase();\n if (!normalizedLang || normalizedLang === 'en') {\n return null; // 'en' is the base SKILL.md\n }\n\n const localizedPath = join(skill.baseDir, `SKILL-${normalizedLang}.md`);\n if (!existsSync(localizedPath)) {\n return null;\n }\n\n try {\n const rawContent = readFileSync(localizedPath, 'utf-8');\n const { frontmatter, content } = parseFrontmatter(rawContent);\n const fm = frontmatter as Record<string, unknown>;\n\n const name = (typeof fm.name === 'string' && fm.name.trim()) || skill.name;\n const descFromFm = typeof fm.description === 'string' ? fm.description.trim() : '';\n const description = descFromFm || skill.description;\n const metadata = parseSkillMetadata(fm);\n if (!metadata.name.trim()) metadata.name = name;\n if (!metadata.description.trim()) metadata.description = description;\n\n const toolConditions = parseSkillToolConditions(fm);\n const requiredEnvVarNames = parseRequiredEnvVarNames(fm);\n\n return {\n name,\n description,\n bodyMarkdown: content.trim(),\n disableModelInvocation: skill.disableModelInvocation,\n metadata,\n toolConditions,\n requiredEnvVarNames: requiredEnvVarNames.length > 0 ? requiredEnvVarNames : undefined,\n };\n } catch {\n return null; // parse error → fall back\n }\n}\n\n/**\n * Lightweight localized name/description lookup (frontmatter only) for list views.\n * Reuses the same SKILL-{lang}.md resolution as {@link resolveLocalizedSkillMarkdown}.\n */\nexport function resolveLocalizedSkillMeta(\n skill: Skill,\n lang: string,\n): { name: string; description: string } | null {\n const normalizedLang = lang.split(/[-_]/)[0]?.toLowerCase();\n if (!normalizedLang || normalizedLang === 'en') return null;\n\n const localizedPath = join(skill.baseDir, `SKILL-${normalizedLang}.md`);\n if (!existsSync(localizedPath)) return null;\n\n try {\n const rawContent = readFileSync(localizedPath, 'utf-8');\n const { frontmatter } = parseFrontmatter(rawContent);\n const fm = frontmatter as Record<string, unknown>;\n const name = typeof fm.name === 'string' && fm.name.trim() ? fm.name.trim() : undefined;\n const description =\n typeof fm.description === 'string' && fm.description.trim() ? fm.description.trim() : undefined;\n if (!name && !description) return null;\n return {\n name: name ?? skill.name,\n description: description ?? skill.description,\n };\n } catch {\n return null;\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Skills marketplace facade: delegates to a {@link SkillsMarketplaceAdapter}
3
+ * (store.xopc.ai or SkillHub).
4
+ */
5
+ import type { Config } from '../../config/schema.js';
6
+ import { getMarketplaceAdapter, getMarketplaceProviderDisplayName, resolveSkillsMarketplaceProvider } from './marketplace/resolve-adapter.js';
7
+ import type { MarketplaceCategoryOption, SkillsStoreListParams, UnifiedMarketplaceListResponse, UnifiedMarketplacePackageDetail } from './marketplace/adapters/store/store-api-client.js';
8
+ export type { SkillsMarketplaceAdapter } from './marketplace/adapter.types.js';
9
+ export type { SkillsMarketplaceProvider } from './marketplace/adapters/store/store-api-client.js';
10
+ export { getMarketplaceAdapter, getMarketplaceProviderDisplayName, resolveSkillsMarketplaceProvider };
11
+ export type { MarketplaceCategoryOption, MarketplacePackageDetail, SkillsStoreListParams, SkillsStoreListResponse, UnifiedMarketplaceListResponse, UnifiedMarketplacePackageDetail, } from './marketplace/adapters/store/store-api-client.js';
12
+ export declare function listMarketplaceCategories(config: Config): Promise<{
13
+ items: MarketplaceCategoryOption[];
14
+ }>;
15
+ export declare function listMarketplacePackages(config: Config, params: SkillsStoreListParams): Promise<UnifiedMarketplaceListResponse>;
16
+ export declare function getMarketplacePackageDetail(config: Config, packageName: string): Promise<UnifiedMarketplacePackageDetail>;
17
+ export declare function downloadFromMarketplace(config: Config, packageName: string, version?: string): Promise<{
18
+ buffer: Buffer;
19
+ skillId: string;
20
+ version: string;
21
+ }>;
@@ -0,0 +1,18 @@
1
+ import { getMarketplaceAdapter, getMarketplaceProviderDisplayName, resolveSkillsMarketplaceProvider } from "./marketplace/resolve-adapter.js";
2
+ //#region src/agent/skills/skills-marketplace.ts
3
+ async function listMarketplaceCategories(config) {
4
+ return { items: await getMarketplaceAdapter(config).listCategories(config) };
5
+ }
6
+ async function listMarketplacePackages(config, params) {
7
+ return getMarketplaceAdapter(config).listPackages(config, params);
8
+ }
9
+ async function getMarketplacePackageDetail(config, packageName) {
10
+ return getMarketplaceAdapter(config).getPackageDetail(config, packageName);
11
+ }
12
+ async function downloadFromMarketplace(config, packageName, version) {
13
+ return getMarketplaceAdapter(config).downloadPackage(config, packageName, version);
14
+ }
15
+ //#endregion
16
+ export { downloadFromMarketplace, getMarketplaceAdapter, getMarketplacePackageDetail, getMarketplaceProviderDisplayName, listMarketplaceCategories, listMarketplacePackages, resolveSkillsMarketplaceProvider };
17
+
18
+ //# sourceMappingURL=skills-marketplace.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skills-marketplace.js","names":[],"sources":["../../../../src/agent/skills/skills-marketplace.ts"],"sourcesContent":["/**\n * Skills marketplace facade: delegates to a {@link SkillsMarketplaceAdapter}\n * (store.xopc.ai or SkillHub).\n */\n\nimport type { Config } from '../../config/schema.js';\nimport {\n getMarketplaceAdapter,\n getMarketplaceProviderDisplayName,\n resolveSkillsMarketplaceProvider,\n} from './marketplace/resolve-adapter.js';\nimport type {\n MarketplaceCategoryOption,\n SkillsStoreListParams,\n UnifiedMarketplaceListResponse,\n UnifiedMarketplacePackageDetail,\n} from './marketplace/adapters/store/store-api-client.js';\n\nexport type { SkillsMarketplaceAdapter } from './marketplace/adapter.types.js';\nexport type { SkillsMarketplaceProvider } from './marketplace/adapters/store/store-api-client.js';\nexport { getMarketplaceAdapter, getMarketplaceProviderDisplayName, resolveSkillsMarketplaceProvider };\nexport type {\n MarketplaceCategoryOption,\n MarketplacePackageDetail,\n SkillsStoreListParams,\n SkillsStoreListResponse,\n UnifiedMarketplaceListResponse,\n UnifiedMarketplacePackageDetail,\n} from './marketplace/adapters/store/store-api-client.js';\n\nexport async function listMarketplaceCategories(\n config: Config,\n): Promise<{ items: MarketplaceCategoryOption[] }> {\n const items = await getMarketplaceAdapter(config).listCategories(config);\n return { items };\n}\n\nexport async function listMarketplacePackages(\n config: Config,\n params: SkillsStoreListParams,\n): Promise<UnifiedMarketplaceListResponse> {\n return getMarketplaceAdapter(config).listPackages(config, params);\n}\n\nexport async function getMarketplacePackageDetail(\n config: Config,\n packageName: string,\n): Promise<UnifiedMarketplacePackageDetail> {\n return getMarketplaceAdapter(config).getPackageDetail(config, packageName);\n}\n\nexport async function downloadFromMarketplace(\n config: Config,\n packageName: string,\n version?: string,\n): Promise<{ buffer: Buffer; skillId: string; version: string }> {\n return getMarketplaceAdapter(config).downloadPackage(config, packageName, version);\n}\n"],"mappings":";;AA8BA,eAAsB,0BACpB,QACiD;AAEjD,QAAO,EAAE,OAAA,MADW,sBAAsB,OAAO,CAAC,eAAe,OAAO,EACxD;;AAGlB,eAAsB,wBACpB,QACA,QACyC;AACzC,QAAO,sBAAsB,OAAO,CAAC,aAAa,QAAQ,OAAO;;AAGnE,eAAsB,4BACpB,QACA,aAC0C;AAC1C,QAAO,sBAAsB,OAAO,CAAC,iBAAiB,QAAQ,YAAY;;AAG5E,eAAsB,wBACpB,QACA,aACA,SAC+D;AAC/D,QAAO,sBAAsB,OAAO,CAAC,gBAAgB,QAAQ,aAAa,QAAQ"}
@@ -68,7 +68,6 @@ export declare class SkillTestFramework {
68
68
  * Test code examples
69
69
  */
70
70
  testExamples(content: string, _skillDir: string): Promise<TestResult>;
71
- private extractMetadata;
72
71
  private validateInstallSpec;
73
72
  private extractCodeBlocks;
74
73
  private validateShellSyntax;
@@ -2,6 +2,7 @@ import { createLogger } from "../../utils/logger/index.js";
2
2
  import { init_logger } from "../../utils/logger.js";
3
3
  import { parseFrontmatter } from "../../markdown/frontmatter.js";
4
4
  import { hasBinary, init_installer } from "./installer.js";
5
+ import { parseSkillMetadata } from "./parse-skill-metadata.js";
5
6
  import { scanSkillDirectory } from "./scanner.js";
6
7
  import { basename, join, relative } from "path";
7
8
  import { existsSync, readFileSync, readdirSync } from "fs";
@@ -41,7 +42,7 @@ var SkillTestFramework = class {
41
42
  results.push(parseResult);
42
43
  if (parseResult.status === "fail") return this.createReport(skillDir, results);
43
44
  const { frontmatter } = parseFrontmatter(readFileSync(skillMdPath, "utf-8"));
44
- const metadata = this.extractMetadata(frontmatter);
45
+ const metadata = parseSkillMetadata(frontmatter);
45
46
  if (!this.options.skipDeps) {
46
47
  const depsResult = await this.testDependencies(metadata);
47
48
  results.push(depsResult);
@@ -269,25 +270,6 @@ var SkillTestFramework = class {
269
270
  duration: Date.now() - startTime
270
271
  };
271
272
  }
272
- extractMetadata(frontmatter) {
273
- const xopcMeta = frontmatter.metadata?.xopc;
274
- const metadata = {
275
- name: frontmatter.name || "",
276
- description: frontmatter.description || "",
277
- emoji: xopcMeta?.emoji || frontmatter.emoji || void 0,
278
- homepage: frontmatter.homepage || void 0,
279
- os: xopcMeta?.os || frontmatter.os || void 0,
280
- requires: xopcMeta?.requires || frontmatter.requires || void 0,
281
- install: xopcMeta?.install || frontmatter.install || void 0
282
- };
283
- if (xopcMeta) metadata.xopc = {
284
- emoji: xopcMeta.emoji || void 0,
285
- requires: xopcMeta.requires || void 0,
286
- install: xopcMeta.install || void 0,
287
- os: xopcMeta.os || void 0
288
- };
289
- return metadata;
290
- }
291
273
  validateInstallSpec(spec) {
292
274
  switch (spec.kind) {
293
275
  case "brew":
@@ -1 +1 @@
1
- {"version":3,"file":"test-framework.js","names":[],"sources":["../../../../src/agent/skills/test-framework.ts"],"sourcesContent":["/**\n * Skill Test Framework\n * \n * Comprehensive testing framework for skills.\n * Validates SKILL.md format, dependencies, security, and examples.\n */\n\nimport { existsSync, readFileSync, readdirSync } from 'fs';\nimport { basename, join, relative } from 'path';\nimport { createLogger } from '../../utils/logger.js';\nimport { parseFrontmatter } from '../../markdown/frontmatter.js';\nimport { scanSkillDirectory } from './scanner.js';\nimport { hasBinary } from './installer.js';\nimport type { SkillMetadata, SkillInstallSpec, SkillRequires } from './types.js';\n\nconst log = createLogger('SkillTestFramework');\n\n// ============================================================================\n// Test Result Types\n// ============================================================================\n\nexport type TestStatus = 'pass' | 'fail' | 'warn' | 'skip';\n\nexport interface TestResult {\n name: string;\n status: TestStatus;\n message?: string;\n details?: string[];\n duration?: number;\n}\n\nexport interface SkillTestReport {\n skillName: string;\n skillPath: string;\n timestamp: number;\n results: TestResult[];\n summary: {\n total: number;\n passed: number;\n failed: number;\n warnings: number;\n skipped: number;\n };\n passed: boolean;\n}\n\nexport interface TestOptions {\n /** Skip security tests */\n skipSecurity?: boolean;\n /** Skip dependency tests */\n skipDeps?: boolean;\n /** Skip example tests */\n skipExamples?: boolean;\n /** Strict mode - fail on warnings */\n strict?: boolean;\n /** Timeout for example tests (ms) */\n exampleTimeout?: number;\n /** Working directory for example tests */\n cwd?: string;\n}\n\n// ============================================================================\n// Test Framework Core\n// ============================================================================\n\nexport class SkillTestFramework {\n private options: TestOptions;\n\n constructor(options: TestOptions = {}) {\n this.options = {\n skipSecurity: false,\n skipDeps: false,\n skipExamples: false,\n strict: false,\n exampleTimeout: 10000,\n cwd: process.cwd(),\n ...options,\n };\n }\n\n /**\n * Run all tests for a skill\n */\n async testSkill(skillDir: string): Promise<SkillTestReport> {\n const results: TestResult[] = [];\n\n log.info({ skillDir }, 'Testing skill');\n\n // Validate skill directory\n if (!existsSync(skillDir)) {\n return this.createFailureReport(skillDir, 'Skill directory not found');\n }\n\n const skillMdPath = join(skillDir, 'SKILL.md');\n if (!existsSync(skillMdPath)) {\n return this.createFailureReport(skillDir, 'SKILL.md not found');\n }\n\n // Parse SKILL.md\n const parseResult = this.testSkillMdFormat(skillMdPath);\n results.push(parseResult);\n\n if (parseResult.status === 'fail') {\n return this.createReport(skillDir, results);\n }\n\n const { frontmatter } = parseFrontmatter(readFileSync(skillMdPath, 'utf-8'));\n const metadata = this.extractMetadata(frontmatter);\n\n // Run dependency tests\n if (!this.options.skipDeps) {\n const depsResult = await this.testDependencies(metadata);\n results.push(depsResult);\n }\n\n // Run security tests\n if (!this.options.skipSecurity) {\n const securityResult = await this.testSecurity(skillDir);\n results.push(securityResult);\n }\n\n // Run metadata tests\n const metadataResult = this.testMetadata(metadata, skillDir);\n results.push(metadataResult);\n\n // Run example tests\n if (!this.options.skipExamples) {\n const content = readFileSync(skillMdPath, 'utf-8');\n const examplesResult = await this.testExamples(content, skillDir);\n results.push(examplesResult);\n }\n\n return this.createReport(skillDir, results);\n }\n\n /**\n * Test SKILL.md format\n */\n testSkillMdFormat(filePath: string): TestResult {\n const startTime = Date.now();\n const details: string[] = [];\n\n try {\n const content = readFileSync(filePath, 'utf-8');\n\n // Check for frontmatter\n if (!content.startsWith('---')) {\n return {\n name: 'SKILL.md format',\n status: 'fail',\n message: 'Missing YAML frontmatter',\n duration: Date.now() - startTime,\n };\n }\n\n const { frontmatter } = parseFrontmatter(content);\n\n // Required fields\n const requiredFields = ['name', 'description'];\n for (const field of requiredFields) {\n if (!frontmatter[field]) {\n details.push(`Missing required field: ${field}`);\n }\n }\n\n if (details.length > 0) {\n return {\n name: 'SKILL.md format',\n status: 'fail',\n message: 'Missing required frontmatter fields',\n details,\n duration: Date.now() - startTime,\n };\n }\n\n // Validate field types\n if (typeof frontmatter.name !== 'string') {\n return {\n name: 'SKILL.md format',\n status: 'fail',\n message: 'Field \"name\" must be a string',\n duration: Date.now() - startTime,\n };\n }\n\n if (typeof frontmatter.description !== 'string') {\n return {\n name: 'SKILL.md format',\n status: 'fail',\n message: 'Field \"description\" must be a string',\n duration: Date.now() - startTime,\n };\n }\n\n // Check for content after frontmatter\n const { content: bodyContent } = parseFrontmatter(content);\n if (!bodyContent || bodyContent.length < 10) {\n return {\n name: 'SKILL.md format',\n status: 'warn',\n message: 'SKILL.md body is too short',\n details: ['Consider adding more detailed documentation'],\n duration: Date.now() - startTime,\n };\n }\n\n return {\n name: 'SKILL.md format',\n status: 'pass',\n message: 'Valid SKILL.md format',\n duration: Date.now() - startTime,\n };\n } catch (err) {\n return {\n name: 'SKILL.md format',\n status: 'fail',\n message: err instanceof Error ? err.message : 'Failed to parse SKILL.md',\n duration: Date.now() - startTime,\n };\n }\n }\n\n /**\n * Test dependencies\n */\n async testDependencies(metadata: SkillMetadata): Promise<TestResult> {\n const startTime = Date.now();\n const details: string[] = [];\n let hasWarnings = false;\n let hasFailures = false;\n\n const requires = metadata.xopc?.requires;\n\n if (!requires) {\n return {\n name: 'Dependencies',\n status: 'skip',\n message: 'No dependencies declared',\n duration: Date.now() - startTime,\n };\n }\n\n // Check required binaries\n if (requires.bins) {\n for (const bin of requires.bins) {\n const available = hasBinary(bin);\n if (!available) {\n details.push(`Missing required binary: ${bin}`);\n hasFailures = true;\n } else {\n details.push(`Found binary: ${bin}`);\n }\n }\n }\n\n // Check anyBins (OR condition)\n if (requires.anyBins) {\n const hasAny = requires.anyBins.some(bin => hasBinary(bin));\n if (!hasAny) {\n details.push(`Missing binaries (need one of): ${requires.anyBins.join(', ')}`);\n hasFailures = true;\n } else {\n details.push(`Found at least one binary from: ${requires.anyBins.join(', ')}`);\n }\n }\n\n // Check install specs\n const installSpecs = metadata.xopc?.install;\n if (installSpecs && installSpecs.length > 0) {\n details.push(`Available installers: ${installSpecs.map(s => s.kind).join(', ')}`);\n \n // Validate install specs\n for (const spec of installSpecs) {\n const installCheck = this.validateInstallSpec(spec);\n if (installCheck.status === 'fail') {\n details.push(installCheck.message);\n hasWarnings = true;\n }\n }\n }\n\n return {\n name: 'Dependencies',\n status: hasFailures ? 'fail' : hasWarnings ? 'warn' : 'pass',\n message: hasFailures ? 'Missing dependencies' : hasWarnings ? 'Dependency warnings' : 'All dependencies satisfied',\n details,\n duration: Date.now() - startTime,\n };\n }\n\n /**\n * Test security\n */\n async testSecurity(skillDir: string): Promise<TestResult> {\n const startTime = Date.now();\n\n try {\n const summary = await scanSkillDirectory(skillDir);\n\n const details: string[] = [\n `Critical: ${summary.critical}`,\n `Warnings: ${summary.warn}`,\n `Info: ${summary.info}`,\n ];\n\n if (summary.critical > 0) {\n return {\n name: 'Security',\n status: 'fail',\n message: 'Critical security issues found',\n details: [\n ...details,\n ...summary.findings\n .filter(f => f.severity === 'critical')\n .map(f => `${f.message} at ${relative(skillDir, f.file)}:${f.line}`),\n ],\n duration: Date.now() - startTime,\n };\n }\n\n if (summary.warn > 0) {\n return {\n name: 'Security',\n status: 'warn',\n message: 'Security warnings found',\n details: [\n ...details,\n ...summary.findings\n .filter(f => f.severity === 'warning')\n .map(f => `${f.message} at ${relative(skillDir, f.file)}:${f.line}`),\n ],\n duration: Date.now() - startTime,\n };\n }\n\n return {\n name: 'Security',\n status: 'pass',\n message: 'No security issues',\n details,\n duration: Date.now() - startTime,\n };\n } catch (err) {\n return {\n name: 'Security',\n status: 'fail',\n message: err instanceof Error ? err.message : 'Security scan failed',\n duration: Date.now() - startTime,\n };\n }\n }\n\n /**\n * Test metadata\n */\n testMetadata(metadata: SkillMetadata, _skillDir: string): TestResult {\n const startTime = Date.now();\n const details: string[] = [];\n let hasWarnings = false;\n\n // Check for emoji\n const emoji = metadata.xopc?.emoji;\n if (emoji) {\n details.push(`Emoji: ${emoji}`);\n } else {\n details.push('No emoji defined (recommended)');\n hasWarnings = true;\n }\n\n // Check for homepage\n if (metadata.homepage) {\n details.push(`Homepage: ${metadata.homepage}`);\n } else {\n details.push('No homepage defined (recommended)');\n hasWarnings = true;\n }\n\n // Check for OS restrictions\n const os = metadata.xopc?.os;\n if (os) {\n details.push(`Supported OS: ${os.join(', ')}`);\n }\n\n // Check for install specs\n const installSpecs = metadata.xopc?.install;\n if (installSpecs && installSpecs.length > 0) {\n details.push(`Installers: ${installSpecs.length} defined`);\n }\n\n return {\n name: 'Metadata',\n status: hasWarnings ? 'warn' : 'pass',\n message: hasWarnings ? 'Metadata could be improved' : 'Complete metadata',\n details,\n duration: Date.now() - startTime,\n };\n }\n\n /**\n * Test code examples\n */\n async testExamples(content: string, _skillDir: string): Promise<TestResult> {\n const startTime = Date.now();\n const details: string[] = [];\n let hasFailures = false;\n\n // Extract code blocks\n const codeBlocks = this.extractCodeBlocks(content);\n \n if (codeBlocks.length === 0) {\n return {\n name: 'Examples',\n status: 'warn',\n message: 'No code examples found',\n details: ['Consider adding usage examples'],\n duration: Date.now() - startTime,\n };\n }\n\n details.push(`Found ${codeBlocks.length} code block(s)`);\n\n // Test shell command examples (basic validation)\n const shellCommands = codeBlocks.filter(block => {\n const lang = block.language?.toLowerCase();\n return lang === 'bash' || lang === 'sh' || lang === 'shell';\n });\n\n if (shellCommands.length > 0) {\n details.push(`Shell examples: ${shellCommands.length}`);\n \n // Validate command syntax (basic check)\n for (const cmd of shellCommands) {\n const syntaxCheck = this.validateShellSyntax(cmd.code);\n if (!syntaxCheck.valid) {\n details.push(`Invalid syntax: ${syntaxCheck.error}`);\n hasFailures = true;\n }\n }\n }\n\n return {\n name: 'Examples',\n status: hasFailures ? 'fail' : 'pass',\n message: hasFailures ? 'Invalid examples found' : 'Examples validated',\n details,\n duration: Date.now() - startTime,\n };\n }\n\n // ============================================================================\n // Helper Methods\n // ============================================================================\n\n private extractMetadata(frontmatter: Record<string, unknown>): SkillMetadata {\n // Only support metadata.xopc nested structure\n const meta = frontmatter.metadata as Record<string, unknown> | undefined;\n const xopcMeta = meta?.xopc as Record<string, unknown> | undefined;\n \n const metadata: SkillMetadata = {\n name: frontmatter.name as string || '',\n description: frontmatter.description as string || '',\n emoji: xopcMeta?.emoji as string || frontmatter.emoji as string || undefined,\n homepage: frontmatter.homepage as string || undefined,\n os: xopcMeta?.os as Array<'darwin' | 'linux' | 'win32'> || frontmatter.os as Array<'darwin' | 'linux' | 'win32'> || undefined,\n requires: xopcMeta?.requires as SkillRequires || frontmatter.requires as SkillRequires || undefined,\n install: xopcMeta?.install as SkillInstallSpec[] || frontmatter.install as SkillInstallSpec[] || undefined,\n };\n\n // Store xopc metadata for reference\n if (xopcMeta) {\n metadata.xopc = {\n emoji: xopcMeta.emoji as string || undefined,\n requires: xopcMeta.requires as SkillRequires || undefined,\n install: xopcMeta.install as SkillInstallSpec[] || undefined,\n os: xopcMeta.os as Array<'darwin' | 'linux' | 'win32'> || undefined,\n };\n }\n\n return metadata;\n }\n\n private validateInstallSpec(spec: SkillInstallSpec): TestResult {\n switch (spec.kind) {\n case 'brew':\n if (!spec.formula) {\n return {\n name: 'Install spec',\n status: 'fail',\n message: 'Brew installer missing \"formula\" field',\n };\n }\n break;\n case 'pnpm':\n case 'npm':\n case 'yarn':\n case 'bun':\n if (!spec.package) {\n return {\n name: 'Install spec',\n status: 'fail',\n message: 'Node installer missing \"package\" field',\n };\n }\n break;\n case 'go':\n if (!spec.module) {\n return {\n name: 'Install spec',\n status: 'fail',\n message: 'Go installer missing \"module\" field',\n };\n }\n break;\n case 'uv':\n if (!spec.package) {\n return {\n name: 'Install spec',\n status: 'fail',\n message: 'UV installer missing \"package\" field',\n };\n }\n break;\n }\n return { name: 'Install spec', status: 'pass' };\n }\n\n private extractCodeBlocks(content: string): Array<{ language: string; code: string }> {\n const blocks: Array<{ language: string; code: string }> = [];\n const regex = /```(\\w+)?\\n([\\s\\S]*?)```/g;\n let match;\n\n while ((match = regex.exec(content)) !== null) {\n blocks.push({\n language: match[1] || 'text',\n code: match[2].trim(),\n });\n }\n\n return blocks;\n }\n\n private validateShellSyntax(code: string): { valid: boolean; error?: string } {\n // Basic validation - check for common syntax errors\n const lines = code.split('\\n').filter(line => line.trim() && !line.trim().startsWith('#'));\n \n for (const line of lines) {\n // Check for unclosed quotes\n const singleQuotes = (line.match(/'/g) || []).length;\n const doubleQuotes = (line.match(/\"/g) || []).length;\n \n if (singleQuotes % 2 !== 0) {\n return { valid: false, error: 'Unclosed single quote' };\n }\n if (doubleQuotes % 2 !== 0) {\n return { valid: false, error: 'Unclosed double quote' };\n }\n \n // Check for unclosed parentheses/brackets\n const openParens = (line.match(/\\(/g) || []).length;\n const closeParens = (line.match(/\\)/g) || []).length;\n if (openParens !== closeParens) {\n return { valid: false, error: 'Mismatched parentheses' };\n }\n }\n\n return { valid: true };\n }\n\n private createReport(skillDir: string, results: TestResult[]): SkillTestReport {\n const summary = {\n total: results.length,\n passed: results.filter(r => r.status === 'pass').length,\n failed: results.filter(r => r.status === 'fail').length,\n warnings: results.filter(r => r.status === 'warn').length,\n skipped: results.filter(r => r.status === 'skip').length,\n };\n\n const passed = summary.failed === 0 && (this.options.strict ? summary.warnings === 0 : true);\n\n return {\n skillName: basename(skillDir),\n skillPath: skillDir,\n timestamp: Date.now(),\n results,\n summary,\n passed,\n };\n }\n\n private createFailureReport(skillDir: string, message: string): SkillTestReport {\n return {\n skillName: basename(skillDir),\n skillPath: skillDir,\n timestamp: Date.now(),\n results: [{\n name: 'Validation',\n status: 'fail',\n message,\n }],\n summary: {\n total: 1,\n passed: 0,\n failed: 1,\n warnings: 0,\n skipped: 0,\n },\n passed: false,\n };\n }\n}\n\n// ============================================================================\n// Test Runner\n// ============================================================================\n\nexport interface TestRunnerOptions extends TestOptions {\n /** Skills directory to test */\n skillsDir: string;\n /** Output format */\n format?: 'text' | 'json' | 'tap';\n /** Verbose output */\n verbose?: boolean;\n}\n\nexport class SkillTestRunner {\n private options: TestRunnerOptions;\n private framework: SkillTestFramework;\n\n constructor(options: TestRunnerOptions) {\n this.options = options;\n this.framework = new SkillTestFramework(options);\n }\n\n async run(): Promise<{ reports: SkillTestReport[]; passed: boolean }> {\n const reports: SkillTestReport[] = [];\n const skillsDir = this.options.skillsDir;\n\n log.info({ skillsDir }, 'Running skill tests');\n\n // Find all skill directories\n const skillDirs = this.findSkillDirectories(skillsDir);\n\n for (const skillDir of skillDirs) {\n const report = await this.framework.testSkill(skillDir);\n reports.push(report);\n }\n\n const allPassed = reports.every(r => r.passed);\n\n return { reports, passed: allPassed };\n }\n\n private findSkillDirectories(skillsDir: string): string[] {\n const dirs: string[] = [];\n\n try {\n const entries = readdirSync(skillsDir, { withFileTypes: true });\n \n for (const entry of entries) {\n if (entry.isDirectory() && !entry.name.startsWith('.')) {\n const skillDir = join(skillsDir, entry.name);\n const skillMdPath = join(skillDir, 'SKILL.md');\n \n if (existsSync(skillMdPath)) {\n dirs.push(skillDir);\n }\n }\n }\n } catch (err) {\n log.warn({ error: err }, 'Failed to scan skills directory');\n }\n\n return dirs;\n }\n}\n\n/**\n * Format test results as text\n */\nexport function formatTestResults(reports: SkillTestReport[], verbose = false): string {\n const lines: string[] = [];\n \n for (const report of reports) {\n const icon = report.passed ? '✅' : '❌';\n lines.push(`\\n${icon} ${report.skillName}`);\n lines.push('─'.repeat(50));\n\n for (const result of report.results) {\n const statusIcon = result.status === 'pass' ? '✓' : result.status === 'fail' ? '✗' : result.status === 'warn' ? '⚠' : '○';\n lines.push(` ${statusIcon} ${result.name}: ${result.message || ''}`);\n \n if (verbose && result.details) {\n for (const detail of result.details) {\n lines.push(` ${detail}`);\n }\n }\n }\n\n lines.push(` Summary: ${report.summary.passed}/${report.summary.total} passed`);\n if (report.summary.failed > 0) {\n lines.push(` Failed: ${report.summary.failed}`);\n }\n if (report.summary.warnings > 0) {\n lines.push(` Warnings: ${report.summary.warnings}`);\n }\n }\n\n const totalTests = reports.reduce((sum, r) => sum + r.summary.total, 0);\n const totalPassed = reports.reduce((sum, r) => sum + r.summary.passed, 0);\n const totalFailed = reports.reduce((sum, r) => sum + r.summary.failed, 0);\n const totalWarnings = reports.reduce((sum, r) => sum + r.summary.warnings, 0);\n\n lines.push('\\n' + '='.repeat(50));\n lines.push(`Total: ${totalTests} tests, ${totalPassed} passed, ${totalFailed} failed, ${totalWarnings} warnings`);\n \n const allPassed = reports.every(r => r.passed);\n lines.push(`Result: ${allPassed ? '✅ PASSED' : '❌ FAILED'}`);\n\n return lines.join('\\n');\n}\n\n/**\n * Format test results as JSON\n */\nexport function formatTestResultsJson(reports: SkillTestReport[]): string {\n return JSON.stringify({\n timestamp: new Date().toISOString(),\n totalSkills: reports.length,\n passedSkills: reports.filter(r => r.passed).length,\n reports,\n }, null, 2);\n}\n\n/**\n * Format test results as TAP (Test Anything Protocol)\n */\nexport function formatTestResultsTap(reports: SkillTestReport[]): string {\n const lines: string[] = [];\n let testNum = 1;\n\n lines.push(`TAP version 13`);\n lines.push(`1..${reports.reduce((sum, r) => sum + r.results.length, 0)}`);\n\n for (const report of reports) {\n for (const result of report.results) {\n const status = result.status === 'pass' ? 'ok' : 'not ok';\n const testId = testNum++;\n lines.push(`${status} ${testId} - ${report.skillName}: ${result.name}`);\n \n if (result.status === 'fail' && result.message) {\n lines.push(` ---`);\n lines.push(` message: ${result.message}`);\n lines.push(` ...`);\n }\n }\n }\n\n return lines.join('\\n');\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"test-framework.js","names":[],"sources":["../../../../src/agent/skills/test-framework.ts"],"sourcesContent":["/**\n * Skill Test Framework\n * \n * Comprehensive testing framework for skills.\n * Validates SKILL.md format, dependencies, security, and examples.\n */\n\nimport { existsSync, readFileSync, readdirSync } from 'fs';\nimport { basename, join, relative } from 'path';\nimport { createLogger } from '../../utils/logger.js';\nimport { parseFrontmatter } from '../../markdown/frontmatter.js';\nimport { parseSkillMetadata } from './parse-skill-metadata.js';\nimport { scanSkillDirectory } from './scanner.js';\nimport { hasBinary } from './installer.js';\nimport type { SkillMetadata, SkillInstallSpec } from './types.js';\n\nconst log = createLogger('SkillTestFramework');\n\n// ============================================================================\n// Test Result Types\n// ============================================================================\n\nexport type TestStatus = 'pass' | 'fail' | 'warn' | 'skip';\n\nexport interface TestResult {\n name: string;\n status: TestStatus;\n message?: string;\n details?: string[];\n duration?: number;\n}\n\nexport interface SkillTestReport {\n skillName: string;\n skillPath: string;\n timestamp: number;\n results: TestResult[];\n summary: {\n total: number;\n passed: number;\n failed: number;\n warnings: number;\n skipped: number;\n };\n passed: boolean;\n}\n\nexport interface TestOptions {\n /** Skip security tests */\n skipSecurity?: boolean;\n /** Skip dependency tests */\n skipDeps?: boolean;\n /** Skip example tests */\n skipExamples?: boolean;\n /** Strict mode - fail on warnings */\n strict?: boolean;\n /** Timeout for example tests (ms) */\n exampleTimeout?: number;\n /** Working directory for example tests */\n cwd?: string;\n}\n\n// ============================================================================\n// Test Framework Core\n// ============================================================================\n\nexport class SkillTestFramework {\n private options: TestOptions;\n\n constructor(options: TestOptions = {}) {\n this.options = {\n skipSecurity: false,\n skipDeps: false,\n skipExamples: false,\n strict: false,\n exampleTimeout: 10000,\n cwd: process.cwd(),\n ...options,\n };\n }\n\n /**\n * Run all tests for a skill\n */\n async testSkill(skillDir: string): Promise<SkillTestReport> {\n const results: TestResult[] = [];\n\n log.info({ skillDir }, 'Testing skill');\n\n // Validate skill directory\n if (!existsSync(skillDir)) {\n return this.createFailureReport(skillDir, 'Skill directory not found');\n }\n\n const skillMdPath = join(skillDir, 'SKILL.md');\n if (!existsSync(skillMdPath)) {\n return this.createFailureReport(skillDir, 'SKILL.md not found');\n }\n\n // Parse SKILL.md\n const parseResult = this.testSkillMdFormat(skillMdPath);\n results.push(parseResult);\n\n if (parseResult.status === 'fail') {\n return this.createReport(skillDir, results);\n }\n\n const { frontmatter } = parseFrontmatter(readFileSync(skillMdPath, 'utf-8'));\n const metadata = parseSkillMetadata(frontmatter);\n\n // Run dependency tests\n if (!this.options.skipDeps) {\n const depsResult = await this.testDependencies(metadata);\n results.push(depsResult);\n }\n\n // Run security tests\n if (!this.options.skipSecurity) {\n const securityResult = await this.testSecurity(skillDir);\n results.push(securityResult);\n }\n\n // Run metadata tests\n const metadataResult = this.testMetadata(metadata, skillDir);\n results.push(metadataResult);\n\n // Run example tests\n if (!this.options.skipExamples) {\n const content = readFileSync(skillMdPath, 'utf-8');\n const examplesResult = await this.testExamples(content, skillDir);\n results.push(examplesResult);\n }\n\n return this.createReport(skillDir, results);\n }\n\n /**\n * Test SKILL.md format\n */\n testSkillMdFormat(filePath: string): TestResult {\n const startTime = Date.now();\n const details: string[] = [];\n\n try {\n const content = readFileSync(filePath, 'utf-8');\n\n // Check for frontmatter\n if (!content.startsWith('---')) {\n return {\n name: 'SKILL.md format',\n status: 'fail',\n message: 'Missing YAML frontmatter',\n duration: Date.now() - startTime,\n };\n }\n\n const { frontmatter } = parseFrontmatter(content);\n\n // Required fields\n const requiredFields = ['name', 'description'];\n for (const field of requiredFields) {\n if (!frontmatter[field]) {\n details.push(`Missing required field: ${field}`);\n }\n }\n\n if (details.length > 0) {\n return {\n name: 'SKILL.md format',\n status: 'fail',\n message: 'Missing required frontmatter fields',\n details,\n duration: Date.now() - startTime,\n };\n }\n\n // Validate field types\n if (typeof frontmatter.name !== 'string') {\n return {\n name: 'SKILL.md format',\n status: 'fail',\n message: 'Field \"name\" must be a string',\n duration: Date.now() - startTime,\n };\n }\n\n if (typeof frontmatter.description !== 'string') {\n return {\n name: 'SKILL.md format',\n status: 'fail',\n message: 'Field \"description\" must be a string',\n duration: Date.now() - startTime,\n };\n }\n\n // Check for content after frontmatter\n const { content: bodyContent } = parseFrontmatter(content);\n if (!bodyContent || bodyContent.length < 10) {\n return {\n name: 'SKILL.md format',\n status: 'warn',\n message: 'SKILL.md body is too short',\n details: ['Consider adding more detailed documentation'],\n duration: Date.now() - startTime,\n };\n }\n\n return {\n name: 'SKILL.md format',\n status: 'pass',\n message: 'Valid SKILL.md format',\n duration: Date.now() - startTime,\n };\n } catch (err) {\n return {\n name: 'SKILL.md format',\n status: 'fail',\n message: err instanceof Error ? err.message : 'Failed to parse SKILL.md',\n duration: Date.now() - startTime,\n };\n }\n }\n\n /**\n * Test dependencies\n */\n async testDependencies(metadata: SkillMetadata): Promise<TestResult> {\n const startTime = Date.now();\n const details: string[] = [];\n let hasWarnings = false;\n let hasFailures = false;\n\n const requires = metadata.xopc?.requires;\n\n if (!requires) {\n return {\n name: 'Dependencies',\n status: 'skip',\n message: 'No dependencies declared',\n duration: Date.now() - startTime,\n };\n }\n\n // Check required binaries\n if (requires.bins) {\n for (const bin of requires.bins) {\n const available = hasBinary(bin);\n if (!available) {\n details.push(`Missing required binary: ${bin}`);\n hasFailures = true;\n } else {\n details.push(`Found binary: ${bin}`);\n }\n }\n }\n\n // Check anyBins (OR condition)\n if (requires.anyBins) {\n const hasAny = requires.anyBins.some(bin => hasBinary(bin));\n if (!hasAny) {\n details.push(`Missing binaries (need one of): ${requires.anyBins.join(', ')}`);\n hasFailures = true;\n } else {\n details.push(`Found at least one binary from: ${requires.anyBins.join(', ')}`);\n }\n }\n\n // Check install specs\n const installSpecs = metadata.xopc?.install;\n if (installSpecs && installSpecs.length > 0) {\n details.push(`Available installers: ${installSpecs.map(s => s.kind).join(', ')}`);\n \n // Validate install specs\n for (const spec of installSpecs) {\n const installCheck = this.validateInstallSpec(spec);\n if (installCheck.status === 'fail') {\n details.push(installCheck.message);\n hasWarnings = true;\n }\n }\n }\n\n return {\n name: 'Dependencies',\n status: hasFailures ? 'fail' : hasWarnings ? 'warn' : 'pass',\n message: hasFailures ? 'Missing dependencies' : hasWarnings ? 'Dependency warnings' : 'All dependencies satisfied',\n details,\n duration: Date.now() - startTime,\n };\n }\n\n /**\n * Test security\n */\n async testSecurity(skillDir: string): Promise<TestResult> {\n const startTime = Date.now();\n\n try {\n const summary = await scanSkillDirectory(skillDir);\n\n const details: string[] = [\n `Critical: ${summary.critical}`,\n `Warnings: ${summary.warn}`,\n `Info: ${summary.info}`,\n ];\n\n if (summary.critical > 0) {\n return {\n name: 'Security',\n status: 'fail',\n message: 'Critical security issues found',\n details: [\n ...details,\n ...summary.findings\n .filter(f => f.severity === 'critical')\n .map(f => `${f.message} at ${relative(skillDir, f.file)}:${f.line}`),\n ],\n duration: Date.now() - startTime,\n };\n }\n\n if (summary.warn > 0) {\n return {\n name: 'Security',\n status: 'warn',\n message: 'Security warnings found',\n details: [\n ...details,\n ...summary.findings\n .filter(f => f.severity === 'warning')\n .map(f => `${f.message} at ${relative(skillDir, f.file)}:${f.line}`),\n ],\n duration: Date.now() - startTime,\n };\n }\n\n return {\n name: 'Security',\n status: 'pass',\n message: 'No security issues',\n details,\n duration: Date.now() - startTime,\n };\n } catch (err) {\n return {\n name: 'Security',\n status: 'fail',\n message: err instanceof Error ? err.message : 'Security scan failed',\n duration: Date.now() - startTime,\n };\n }\n }\n\n /**\n * Test metadata\n */\n testMetadata(metadata: SkillMetadata, _skillDir: string): TestResult {\n const startTime = Date.now();\n const details: string[] = [];\n let hasWarnings = false;\n\n // Check for emoji\n const emoji = metadata.xopc?.emoji;\n if (emoji) {\n details.push(`Emoji: ${emoji}`);\n } else {\n details.push('No emoji defined (recommended)');\n hasWarnings = true;\n }\n\n // Check for homepage\n if (metadata.homepage) {\n details.push(`Homepage: ${metadata.homepage}`);\n } else {\n details.push('No homepage defined (recommended)');\n hasWarnings = true;\n }\n\n // Check for OS restrictions\n const os = metadata.xopc?.os;\n if (os) {\n details.push(`Supported OS: ${os.join(', ')}`);\n }\n\n // Check for install specs\n const installSpecs = metadata.xopc?.install;\n if (installSpecs && installSpecs.length > 0) {\n details.push(`Installers: ${installSpecs.length} defined`);\n }\n\n return {\n name: 'Metadata',\n status: hasWarnings ? 'warn' : 'pass',\n message: hasWarnings ? 'Metadata could be improved' : 'Complete metadata',\n details,\n duration: Date.now() - startTime,\n };\n }\n\n /**\n * Test code examples\n */\n async testExamples(content: string, _skillDir: string): Promise<TestResult> {\n const startTime = Date.now();\n const details: string[] = [];\n let hasFailures = false;\n\n // Extract code blocks\n const codeBlocks = this.extractCodeBlocks(content);\n \n if (codeBlocks.length === 0) {\n return {\n name: 'Examples',\n status: 'warn',\n message: 'No code examples found',\n details: ['Consider adding usage examples'],\n duration: Date.now() - startTime,\n };\n }\n\n details.push(`Found ${codeBlocks.length} code block(s)`);\n\n // Test shell command examples (basic validation)\n const shellCommands = codeBlocks.filter(block => {\n const lang = block.language?.toLowerCase();\n return lang === 'bash' || lang === 'sh' || lang === 'shell';\n });\n\n if (shellCommands.length > 0) {\n details.push(`Shell examples: ${shellCommands.length}`);\n \n // Validate command syntax (basic check)\n for (const cmd of shellCommands) {\n const syntaxCheck = this.validateShellSyntax(cmd.code);\n if (!syntaxCheck.valid) {\n details.push(`Invalid syntax: ${syntaxCheck.error}`);\n hasFailures = true;\n }\n }\n }\n\n return {\n name: 'Examples',\n status: hasFailures ? 'fail' : 'pass',\n message: hasFailures ? 'Invalid examples found' : 'Examples validated',\n details,\n duration: Date.now() - startTime,\n };\n }\n\n // ============================================================================\n // Helper Methods\n // ============================================================================\n\n private validateInstallSpec(spec: SkillInstallSpec): TestResult {\n switch (spec.kind) {\n case 'brew':\n if (!spec.formula) {\n return {\n name: 'Install spec',\n status: 'fail',\n message: 'Brew installer missing \"formula\" field',\n };\n }\n break;\n case 'pnpm':\n case 'npm':\n case 'yarn':\n case 'bun':\n if (!spec.package) {\n return {\n name: 'Install spec',\n status: 'fail',\n message: 'Node installer missing \"package\" field',\n };\n }\n break;\n case 'go':\n if (!spec.module) {\n return {\n name: 'Install spec',\n status: 'fail',\n message: 'Go installer missing \"module\" field',\n };\n }\n break;\n case 'uv':\n if (!spec.package) {\n return {\n name: 'Install spec',\n status: 'fail',\n message: 'UV installer missing \"package\" field',\n };\n }\n break;\n }\n return { name: 'Install spec', status: 'pass' };\n }\n\n private extractCodeBlocks(content: string): Array<{ language: string; code: string }> {\n const blocks: Array<{ language: string; code: string }> = [];\n const regex = /```(\\w+)?\\n([\\s\\S]*?)```/g;\n let match;\n\n while ((match = regex.exec(content)) !== null) {\n blocks.push({\n language: match[1] || 'text',\n code: match[2].trim(),\n });\n }\n\n return blocks;\n }\n\n private validateShellSyntax(code: string): { valid: boolean; error?: string } {\n // Basic validation - check for common syntax errors\n const lines = code.split('\\n').filter(line => line.trim() && !line.trim().startsWith('#'));\n \n for (const line of lines) {\n // Check for unclosed quotes\n const singleQuotes = (line.match(/'/g) || []).length;\n const doubleQuotes = (line.match(/\"/g) || []).length;\n \n if (singleQuotes % 2 !== 0) {\n return { valid: false, error: 'Unclosed single quote' };\n }\n if (doubleQuotes % 2 !== 0) {\n return { valid: false, error: 'Unclosed double quote' };\n }\n \n // Check for unclosed parentheses/brackets\n const openParens = (line.match(/\\(/g) || []).length;\n const closeParens = (line.match(/\\)/g) || []).length;\n if (openParens !== closeParens) {\n return { valid: false, error: 'Mismatched parentheses' };\n }\n }\n\n return { valid: true };\n }\n\n private createReport(skillDir: string, results: TestResult[]): SkillTestReport {\n const summary = {\n total: results.length,\n passed: results.filter(r => r.status === 'pass').length,\n failed: results.filter(r => r.status === 'fail').length,\n warnings: results.filter(r => r.status === 'warn').length,\n skipped: results.filter(r => r.status === 'skip').length,\n };\n\n const passed = summary.failed === 0 && (this.options.strict ? summary.warnings === 0 : true);\n\n return {\n skillName: basename(skillDir),\n skillPath: skillDir,\n timestamp: Date.now(),\n results,\n summary,\n passed,\n };\n }\n\n private createFailureReport(skillDir: string, message: string): SkillTestReport {\n return {\n skillName: basename(skillDir),\n skillPath: skillDir,\n timestamp: Date.now(),\n results: [{\n name: 'Validation',\n status: 'fail',\n message,\n }],\n summary: {\n total: 1,\n passed: 0,\n failed: 1,\n warnings: 0,\n skipped: 0,\n },\n passed: false,\n };\n }\n}\n\n// ============================================================================\n// Test Runner\n// ============================================================================\n\nexport interface TestRunnerOptions extends TestOptions {\n /** Skills directory to test */\n skillsDir: string;\n /** Output format */\n format?: 'text' | 'json' | 'tap';\n /** Verbose output */\n verbose?: boolean;\n}\n\nexport class SkillTestRunner {\n private options: TestRunnerOptions;\n private framework: SkillTestFramework;\n\n constructor(options: TestRunnerOptions) {\n this.options = options;\n this.framework = new SkillTestFramework(options);\n }\n\n async run(): Promise<{ reports: SkillTestReport[]; passed: boolean }> {\n const reports: SkillTestReport[] = [];\n const skillsDir = this.options.skillsDir;\n\n log.info({ skillsDir }, 'Running skill tests');\n\n // Find all skill directories\n const skillDirs = this.findSkillDirectories(skillsDir);\n\n for (const skillDir of skillDirs) {\n const report = await this.framework.testSkill(skillDir);\n reports.push(report);\n }\n\n const allPassed = reports.every(r => r.passed);\n\n return { reports, passed: allPassed };\n }\n\n private findSkillDirectories(skillsDir: string): string[] {\n const dirs: string[] = [];\n\n try {\n const entries = readdirSync(skillsDir, { withFileTypes: true });\n \n for (const entry of entries) {\n if (entry.isDirectory() && !entry.name.startsWith('.')) {\n const skillDir = join(skillsDir, entry.name);\n const skillMdPath = join(skillDir, 'SKILL.md');\n \n if (existsSync(skillMdPath)) {\n dirs.push(skillDir);\n }\n }\n }\n } catch (err) {\n log.warn({ error: err }, 'Failed to scan skills directory');\n }\n\n return dirs;\n }\n}\n\n/**\n * Format test results as text\n */\nexport function formatTestResults(reports: SkillTestReport[], verbose = false): string {\n const lines: string[] = [];\n \n for (const report of reports) {\n const icon = report.passed ? '✅' : '❌';\n lines.push(`\\n${icon} ${report.skillName}`);\n lines.push('─'.repeat(50));\n\n for (const result of report.results) {\n const statusIcon = result.status === 'pass' ? '✓' : result.status === 'fail' ? '✗' : result.status === 'warn' ? '⚠' : '○';\n lines.push(` ${statusIcon} ${result.name}: ${result.message || ''}`);\n \n if (verbose && result.details) {\n for (const detail of result.details) {\n lines.push(` ${detail}`);\n }\n }\n }\n\n lines.push(` Summary: ${report.summary.passed}/${report.summary.total} passed`);\n if (report.summary.failed > 0) {\n lines.push(` Failed: ${report.summary.failed}`);\n }\n if (report.summary.warnings > 0) {\n lines.push(` Warnings: ${report.summary.warnings}`);\n }\n }\n\n const totalTests = reports.reduce((sum, r) => sum + r.summary.total, 0);\n const totalPassed = reports.reduce((sum, r) => sum + r.summary.passed, 0);\n const totalFailed = reports.reduce((sum, r) => sum + r.summary.failed, 0);\n const totalWarnings = reports.reduce((sum, r) => sum + r.summary.warnings, 0);\n\n lines.push('\\n' + '='.repeat(50));\n lines.push(`Total: ${totalTests} tests, ${totalPassed} passed, ${totalFailed} failed, ${totalWarnings} warnings`);\n \n const allPassed = reports.every(r => r.passed);\n lines.push(`Result: ${allPassed ? '✅ PASSED' : '❌ FAILED'}`);\n\n return lines.join('\\n');\n}\n\n/**\n * Format test results as JSON\n */\nexport function formatTestResultsJson(reports: SkillTestReport[]): string {\n return JSON.stringify({\n timestamp: new Date().toISOString(),\n totalSkills: reports.length,\n passedSkills: reports.filter(r => r.passed).length,\n reports,\n }, null, 2);\n}\n\n/**\n * Format test results as TAP (Test Anything Protocol)\n */\nexport function formatTestResultsTap(reports: SkillTestReport[]): string {\n const lines: string[] = [];\n let testNum = 1;\n\n lines.push(`TAP version 13`);\n lines.push(`1..${reports.reduce((sum, r) => sum + r.results.length, 0)}`);\n\n for (const report of reports) {\n for (const result of report.results) {\n const status = result.status === 'pass' ? 'ok' : 'not ok';\n const testId = testNum++;\n lines.push(`${status} ${testId} - ${report.skillName}: ${result.name}`);\n \n if (result.status === 'fail' && result.message) {\n lines.push(` ---`);\n lines.push(` message: ${result.message}`);\n lines.push(` ...`);\n }\n }\n }\n\n return lines.join('\\n');\n}\n"],"mappings":"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"}
@@ -98,13 +98,7 @@ export interface SkillsLimitsConfig {
98
98
  /** Max size (bytes) for SKILL.md file */
99
99
  maxSkillFileBytes?: number;
100
100
  }
101
- export type SkillsPromptStyle = 'metadata-only' | 'legacy-with-paths';
102
101
  export interface SkillsConfig {
103
- /**
104
- * How `<available_skills>` is rendered. Default: metadata-only (Hermes-style: no disk paths;
105
- * use `skills_list` / `skill_view`). Legacy mode exposes SKILL.md paths for `read_file`.
106
- */
107
- promptStyle?: SkillsPromptStyle;
108
102
  /** Bundled skill allowlist */
109
103
  allowBundled?: string[];
110
104
  /** Load configuration */
@@ -130,6 +124,8 @@ export interface Skill {
130
124
  name: string;
131
125
  /** Skill description */
132
126
  description: string;
127
+ /** Category derived from parent directory (e.g. skills/creative/algorithmic-art → 'creative') */
128
+ category?: string;
133
129
  /** Path to SKILL.md file */
134
130
  filePath: string;
135
131
  /** Base directory of the skill */
@@ -149,6 +145,16 @@ export interface Skill {
149
145
  /** Raw content of SKILL.md */
150
146
  content: string;
151
147
  }
148
+ /** GET /api/skills/:name/content — body without YAML frontmatter plus parsed metadata for the gateway console. */
149
+ export interface SkillMarkdownPreviewPayload {
150
+ name: string;
151
+ description: string;
152
+ bodyMarkdown: string;
153
+ disableModelInvocation: boolean;
154
+ metadata: SkillMetadata;
155
+ toolConditions?: SkillToolConditions;
156
+ requiredEnvVarNames?: string[];
157
+ }
152
158
  export interface SkillEntry {
153
159
  skill: Skill;
154
160
  metadata: SkillMetadata;
@@ -4,8 +4,8 @@ import { SHORT_TERM_PROMOTION_LOCK_RELATIVE, SHORT_TERM_RECALL_STORE_RELATIVE }
4
4
  import { loadDreamingStore, saveDreamingStore } from "../memory/dreaming/short-term-store.js";
5
5
  import { resolveDreamingConfig } from "../memory/dreaming/config.js";
6
6
  import path from "node:path";
7
- import { Type } from "@sinclair/typebox";
8
7
  import fs from "node:fs/promises";
8
+ import { Type } from "@sinclair/typebox";
9
9
  //#region src/agent/tools/dreaming-tool.ts
10
10
  init_logger();
11
11
  const log = createLogger("DreamingTool");
@@ -3,9 +3,9 @@ import { applyImageGenerationModelConfigDefaults } from "../image/image-helpers.
3
3
  import { DASHSCOPE_DEFAULT_IMAGE_MODEL, OPENAI_DEFAULT_IMAGE_MODEL } from "../image/generation/constants.js";
4
4
  import { generateImage, listImageGenerationProvidersSummary } from "../image/generation/runtime.js";
5
5
  import path from "node:path";
6
- import { Type } from "@sinclair/typebox";
7
- import { mkdir, writeFile } from "node:fs/promises";
8
6
  import { randomBytes } from "node:crypto";
7
+ import { mkdir, writeFile } from "node:fs/promises";
8
+ import { Type } from "@sinclair/typebox";
9
9
  //#region src/agent/tools/image-generate-tool.ts
10
10
  const DEFAULT_COUNT = 1;
11
11
  const MAX_COUNT = 4;
@@ -2,9 +2,10 @@ import { __esmMin } from "../../_virtual/_rolldown/runtime.js";
2
2
  import { createLogger } from "../utils/logger/index.js";
3
3
  import { init_logger } from "../utils/logger.js";
4
4
  import { init_paths, resolveAgentAuthProfilesPath, resolveAuthProfilesPath, resolveCredentialsDir, resolveOAuthPath } from "../config/paths.js";
5
+ import { init_write_file_atomic, writeTextAtomic } from "../infra/write-file-atomic.js";
5
6
  import { getApiKeyFromEnv, init_env_keys } from "../providers/env-keys.js";
6
7
  import { dirname, join } from "path";
7
- import { mkdir, readFile, writeFile } from "fs/promises";
8
+ import { mkdir, readFile } from "fs/promises";
8
9
  //#region src/auth/credentials.ts
9
10
  function getCredentialResolver(options) {
10
11
  return new CredentialResolver(options);
@@ -17,6 +18,7 @@ async function hasCredentials(provider, options) {
17
18
  }
18
19
  var log, CredentialResolver;
19
20
  var init_credentials = __esmMin((() => {
21
+ init_write_file_atomic();
20
22
  init_logger();
21
23
  init_env_keys();
22
24
  init_paths();
@@ -179,7 +181,7 @@ var init_credentials = __esmMin((() => {
179
181
  provider: normalizedProvider,
180
182
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
181
183
  };
182
- await writeFile(oauthPath, JSON.stringify(fullToken, null, 2), "utf-8");
184
+ await writeTextAtomic(oauthPath, JSON.stringify(fullToken, null, 2));
183
185
  log.info({ provider }, "Saved OAuth token");
184
186
  }
185
187
  async loadFromAgentCredentials(provider) {
@@ -246,7 +248,7 @@ var init_credentials = __esmMin((() => {
246
248
  await mkdir(dirname(path), { recursive: true });
247
249
  const file = await this.loadAuthProfilesFile();
248
250
  file.profiles[profileId] = profile;
249
- await writeFile(path, JSON.stringify(file, null, 2), "utf-8");
251
+ await writeTextAtomic(path, JSON.stringify(file, null, 2));
250
252
  }
251
253
  async saveAgentAuthProfile(profileId, profile) {
252
254
  if (!this.agentId || !this.appConfig) throw new Error("Agent ID and appConfig required for agent-private profiles");
@@ -254,20 +256,20 @@ var init_credentials = __esmMin((() => {
254
256
  await mkdir(dirname(path), { recursive: true });
255
257
  const file = await this.loadAgentAuthProfilesFile();
256
258
  file.profiles[profileId] = profile;
257
- await writeFile(path, JSON.stringify(file, null, 2), "utf-8");
259
+ await writeTextAtomic(path, JSON.stringify(file, null, 2));
258
260
  }
259
261
  async deleteGlobalAuthProfile(profileId) {
260
262
  const path = resolveAuthProfilesPath();
261
263
  const file = await this.loadAuthProfilesFile();
262
264
  delete file.profiles[profileId];
263
- await writeFile(path, JSON.stringify(file, null, 2), "utf-8");
265
+ await writeTextAtomic(path, JSON.stringify(file, null, 2));
264
266
  }
265
267
  async deleteAgentAuthProfile(profileId) {
266
268
  if (!this.agentId || !this.appConfig) throw new Error("Agent ID and appConfig required for agent-private profiles");
267
269
  const path = resolveAgentAuthProfilesPath(this.appConfig, this.agentId);
268
270
  const file = await this.loadAgentAuthProfilesFile();
269
271
  delete file.profiles[profileId];
270
- await writeFile(path, JSON.stringify(file, null, 2), "utf-8");
272
+ await writeTextAtomic(path, JSON.stringify(file, null, 2));
271
273
  }
272
274
  };
273
275
  }));
@@ -1 +1 @@
1
- {"version":3,"file":"credentials.js","names":[],"sources":["../../../src/auth/credentials.ts"],"sourcesContent":["import { readFile, writeFile, mkdir } from 'fs/promises';\nimport { join, dirname } from 'path';\nimport { createLogger } from '../utils/logger.js';\nimport { getApiKeyFromEnv } from '../providers/env-keys.js';\nimport {\n resolveCredentialsDir,\n resolveAuthProfilesPath,\n resolveAgentAuthProfilesPath,\n resolveOAuthPath,\n} from '../config/paths.js';\nimport type { Config } from '../config/schema.js';\n\nconst log = createLogger('Credentials');\n\n// ============================================\n// Types\n// ============================================\n\nexport type CredentialType = 'api_key' | 'oauth';\n\nexport interface ApiKeyProfile {\n type: 'api_key';\n provider: string;\n profileName?: string;\n envVar?: string | null;\n key: string | null;\n}\n\nexport interface OAuthToken {\n type: 'oauth';\n provider: string;\n access: string;\n refresh?: string;\n expiresAt?: number;\n scope?: string[];\n createdAt: string;\n updatedAt: string;\n}\n\nexport type CredentialProfile = ApiKeyProfile;\n\nexport interface AuthProfilesFile {\n version: number;\n profiles: Record<string, ApiKeyProfile>;\n}\n\n// ============================================\n// Credential Resolver\n// ============================================\n\nexport interface CredentialResolverOptions {\n stateDir?: string;\n /** When set, per-agent auth profiles are read from `resolveAgentAuthProfilesPath(appConfig, agentId)`. */\n agentId?: string;\n /** Required when `agentId` is set. */\n appConfig?: Config;\n}\n\nexport class CredentialResolver {\n private readonly credentialsDir: string;\n private readonly agentId?: string;\n private readonly appConfig?: Config;\n\n constructor(options: CredentialResolverOptions = {}) {\n this.credentialsDir = options.stateDir\n ? join(options.stateDir, 'credentials')\n : resolveCredentialsDir();\n this.agentId = options.agentId;\n this.appConfig = options.appConfig;\n if (this.agentId && !this.appConfig) {\n throw new Error('CredentialResolver: appConfig is required when agentId is set');\n }\n }\n\n /**\n * Resolve API key for a provider\n * Priority: Agent private > Global > OAuth > Environment\n */\n async resolveApiKey(provider: string): Promise<string | null> {\n const normalizedProvider = provider.toLowerCase();\n\n // 1. Try agent private credentials\n if (this.agentId) {\n const agentKey = await this.loadFromAgentCredentials(normalizedProvider);\n if (agentKey) {\n log.debug({ provider, source: 'agent' }, 'Resolved API key from agent credentials');\n return agentKey;\n }\n }\n\n // 2. Try global credentials\n const globalKey = await this.loadFromGlobalCredentials(normalizedProvider);\n if (globalKey) {\n log.debug({ provider, source: 'global' }, 'Resolved API key from global credentials');\n return globalKey;\n }\n\n // 3. Try OAuth token (convert to Bearer)\n const oauthToken = await this.loadOAuthToken(normalizedProvider);\n if (oauthToken) {\n log.debug({ provider, source: 'oauth' }, 'Resolved API key from OAuth token');\n return oauthToken.access;\n }\n\n // 4. Environment variables (see `src/providers/env-keys.ts`)\n const envKey = getApiKeyFromEnv(normalizedProvider);\n if (envKey) {\n log.debug({ provider, source: 'env' }, 'Resolved API key from environment');\n return envKey;\n }\n\n log.debug({ provider }, 'No API key found');\n return null;\n }\n\n /**\n * Check if a provider has credentials configured\n */\n async hasCredentials(provider: string): Promise<boolean> {\n const key = await this.resolveApiKey(provider);\n return key !== null;\n }\n\n /**\n * Which step in {@link resolveApiKey} would supply the key (no secret material).\n */\n async resolveApiKeySource(\n provider: string,\n ): Promise<'agent' | 'global' | 'oauth' | 'env' | null> {\n const normalizedProvider = provider.toLowerCase();\n\n if (this.agentId) {\n const agentKey = await this.loadFromAgentCredentials(normalizedProvider);\n if (agentKey) return 'agent';\n }\n\n const globalKey = await this.loadFromGlobalCredentials(normalizedProvider);\n if (globalKey) return 'global';\n\n const oauthToken = await this.loadOAuthToken(normalizedProvider);\n if (oauthToken) return 'oauth';\n\n if (getApiKeyFromEnv(normalizedProvider)) return 'env';\n\n return null;\n }\n\n /**\n * List all available credential profiles\n */\n async listProfiles(): Promise<Array<ApiKeyProfile & { id: string; source: 'agent' | 'global' }>> {\n const profiles: Array<ApiKeyProfile & { id: string; source: 'agent' | 'global' }> = [];\n\n // Global profiles\n const globalProfiles = await this.loadAuthProfilesFile();\n for (const [id, profile] of Object.entries(globalProfiles.profiles)) {\n profiles.push({ ...profile, id, source: 'global' });\n }\n\n // Agent private profiles\n if (this.agentId) {\n const agentProfiles = await this.loadAgentAuthProfilesFile();\n for (const [id, profile] of Object.entries(agentProfiles.profiles)) {\n profiles.push({ ...profile, id, source: 'agent' });\n }\n }\n\n return profiles;\n }\n\n /**\n * Save an API key profile\n */\n async saveApiKey(\n provider: string,\n key: string,\n options: {\n profileName?: string;\n envVar?: string | null;\n agentPrivate?: boolean;\n } = {}\n ): Promise<void> {\n const normalizedProvider = provider.toLowerCase();\n const profileId = options.profileName\n ? `${normalizedProvider}:${options.profileName}`\n : `${normalizedProvider}:default`;\n\n const profile: ApiKeyProfile = {\n type: 'api_key',\n provider: normalizedProvider,\n profileName: options.profileName,\n envVar: options.envVar ?? null,\n key,\n };\n\n if (options.agentPrivate && this.agentId) {\n await this.saveAgentAuthProfile(profileId, profile);\n } else {\n await this.saveGlobalAuthProfile(profileId, profile);\n }\n\n log.info({ provider, profileId, agentPrivate: options.agentPrivate }, 'Saved API key');\n }\n\n /**\n * Delete a credential profile\n */\n async deleteProfile(profileId: string, options: { agentPrivate?: boolean } = {}): Promise<void> {\n if (options.agentPrivate && this.agentId) {\n await this.deleteAgentAuthProfile(profileId);\n } else {\n await this.deleteGlobalAuthProfile(profileId);\n }\n\n log.info({ profileId, agentPrivate: options.agentPrivate }, 'Deleted credential profile');\n }\n\n /**\n * Load OAuth token for a provider\n */\n async loadOAuthToken(provider: string): Promise<OAuthToken | null> {\n const normalizedProvider = provider.toLowerCase();\n const oauthPath = resolveOAuthPath(normalizedProvider);\n\n try {\n const content = await readFile(oauthPath, 'utf-8');\n const token = JSON.parse(content) as OAuthToken;\n\n // Check if token is expired\n if (token.expiresAt && token.expiresAt < Date.now()) {\n log.warn({ provider, expiresAt: token.expiresAt }, 'OAuth token is expired');\n // TODO: Implement token refresh\n return null;\n }\n\n return token;\n } catch {\n return null;\n }\n }\n\n /**\n * Save OAuth token for a provider\n */\n async saveOAuthToken(provider: string, token: Omit<OAuthToken, 'type' | 'provider' | 'updatedAt'>): Promise<void> {\n const normalizedProvider = provider.toLowerCase();\n const oauthPath = resolveOAuthPath(normalizedProvider);\n\n await mkdir(dirname(oauthPath), { recursive: true });\n\n const fullToken: OAuthToken = {\n ...token,\n type: 'oauth',\n provider: normalizedProvider,\n updatedAt: new Date().toISOString(),\n };\n\n await writeFile(oauthPath, JSON.stringify(fullToken, null, 2), 'utf-8');\n log.info({ provider }, 'Saved OAuth token');\n }\n\n // ============================================\n // Private Methods\n // ============================================\n\n private async loadFromAgentCredentials(provider: string): Promise<string | null> {\n if (!this.agentId) return null;\n\n const profiles = await this.loadAgentAuthProfilesFile();\n const profile = this.findProfileForProvider(profiles, provider);\n\n if (!profile) return null;\n if (profile.envVar) return this.loadFromEnv(profile.envVar) ?? profile.key;\n return profile.key;\n }\n\n private async loadFromGlobalCredentials(provider: string): Promise<string | null> {\n const profiles = await this.loadAuthProfilesFile();\n const profile = this.findProfileForProvider(profiles, provider);\n\n if (!profile) return null;\n if (profile.envVar) return this.loadFromEnv(profile.envVar) ?? profile.key;\n return profile.key;\n }\n\n private loadFromEnv(envVarName: string): string | null {\n return process.env[envVarName] || null;\n }\n\n private findProfileForProvider(\n file: AuthProfilesFile,\n provider: string\n ): ApiKeyProfile | null {\n const normalizedProvider = provider.toLowerCase();\n\n // Look for exact match first\n for (const [, profile] of Object.entries(file.profiles)) {\n if (profile.provider === normalizedProvider) {\n return profile;\n }\n }\n\n return null;\n }\n\n private async loadAuthProfilesFile(): Promise<AuthProfilesFile> {\n const path = resolveAuthProfilesPath();\n\n try {\n const content = await readFile(path, 'utf-8');\n const data = JSON.parse(content);\n return {\n version: data.version || 1,\n profiles: data.profiles || {},\n };\n } catch {\n return { version: 2, profiles: {} };\n }\n }\n\n private async loadAgentAuthProfilesFile(): Promise<AuthProfilesFile> {\n if (!this.agentId || !this.appConfig) return { version: 2, profiles: {} };\n\n const path = resolveAgentAuthProfilesPath(this.appConfig, this.agentId);\n\n try {\n const content = await readFile(path, 'utf-8');\n const data = JSON.parse(content);\n return {\n version: data.version || 1,\n profiles: data.profiles || {},\n };\n } catch {\n return { version: 2, profiles: {} };\n }\n }\n\n private async saveGlobalAuthProfile(profileId: string, profile: ApiKeyProfile): Promise<void> {\n const path = resolveAuthProfilesPath();\n await mkdir(dirname(path), { recursive: true });\n\n const file = await this.loadAuthProfilesFile();\n file.profiles[profileId] = profile;\n\n await writeFile(path, JSON.stringify(file, null, 2), 'utf-8');\n }\n\n private async saveAgentAuthProfile(profileId: string, profile: ApiKeyProfile): Promise<void> {\n if (!this.agentId || !this.appConfig) throw new Error('Agent ID and appConfig required for agent-private profiles');\n\n const path = resolveAgentAuthProfilesPath(this.appConfig, this.agentId);\n await mkdir(dirname(path), { recursive: true });\n\n const file = await this.loadAgentAuthProfilesFile();\n file.profiles[profileId] = profile;\n\n await writeFile(path, JSON.stringify(file, null, 2), 'utf-8');\n }\n\n private async deleteGlobalAuthProfile(profileId: string): Promise<void> {\n const path = resolveAuthProfilesPath();\n const file = await this.loadAuthProfilesFile();\n\n delete file.profiles[profileId];\n\n await writeFile(path, JSON.stringify(file, null, 2), 'utf-8');\n }\n\n private async deleteAgentAuthProfile(profileId: string): Promise<void> {\n if (!this.agentId || !this.appConfig) throw new Error('Agent ID and appConfig required for agent-private profiles');\n\n const path = resolveAgentAuthProfilesPath(this.appConfig, this.agentId);\n const file = await this.loadAgentAuthProfilesFile();\n\n delete file.profiles[profileId];\n\n await writeFile(path, JSON.stringify(file, null, 2), 'utf-8');\n }\n}\n\n// ============================================\n// Convenience Functions\n// ============================================\n\nlet defaultResolver: CredentialResolver | null = null;\n\nexport function getCredentialResolver(options?: CredentialResolverOptions): CredentialResolver {\n if (!defaultResolver || options) {\n return new CredentialResolver(options);\n }\n return defaultResolver;\n}\n\nexport async function resolveApiKey(provider: string, options?: CredentialResolverOptions): Promise<string | null> {\n const resolver = getCredentialResolver(options);\n return resolver.resolveApiKey(provider);\n}\n\nexport async function hasCredentials(provider: string, options?: CredentialResolverOptions): Promise<boolean> {\n const resolver = getCredentialResolver(options);\n return resolver.hasCredentials(provider);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"credentials.js","names":[],"sources":["../../../src/auth/credentials.ts"],"sourcesContent":["import { readFile, mkdir } from 'fs/promises';\nimport { writeTextAtomic } from '../infra/write-file-atomic.js';\nimport { join, dirname } from 'path';\nimport { createLogger } from '../utils/logger.js';\nimport { getApiKeyFromEnv } from '../providers/env-keys.js';\nimport {\n resolveCredentialsDir,\n resolveAuthProfilesPath,\n resolveAgentAuthProfilesPath,\n resolveOAuthPath,\n} from '../config/paths.js';\nimport type { Config } from '../config/schema.js';\n\nconst log = createLogger('Credentials');\n\n// ============================================\n// Types\n// ============================================\n\nexport type CredentialType = 'api_key' | 'oauth';\n\nexport interface ApiKeyProfile {\n type: 'api_key';\n provider: string;\n profileName?: string;\n envVar?: string | null;\n key: string | null;\n}\n\nexport interface OAuthToken {\n type: 'oauth';\n provider: string;\n access: string;\n refresh?: string;\n expiresAt?: number;\n scope?: string[];\n createdAt: string;\n updatedAt: string;\n}\n\nexport type CredentialProfile = ApiKeyProfile;\n\nexport interface AuthProfilesFile {\n version: number;\n profiles: Record<string, ApiKeyProfile>;\n}\n\n// ============================================\n// Credential Resolver\n// ============================================\n\nexport interface CredentialResolverOptions {\n stateDir?: string;\n /** When set, per-agent auth profiles are read from `resolveAgentAuthProfilesPath(appConfig, agentId)`. */\n agentId?: string;\n /** Required when `agentId` is set. */\n appConfig?: Config;\n}\n\nexport class CredentialResolver {\n private readonly credentialsDir: string;\n private readonly agentId?: string;\n private readonly appConfig?: Config;\n\n constructor(options: CredentialResolverOptions = {}) {\n this.credentialsDir = options.stateDir\n ? join(options.stateDir, 'credentials')\n : resolveCredentialsDir();\n this.agentId = options.agentId;\n this.appConfig = options.appConfig;\n if (this.agentId && !this.appConfig) {\n throw new Error('CredentialResolver: appConfig is required when agentId is set');\n }\n }\n\n /**\n * Resolve API key for a provider\n * Priority: Agent private > Global > OAuth > Environment\n */\n async resolveApiKey(provider: string): Promise<string | null> {\n const normalizedProvider = provider.toLowerCase();\n\n // 1. Try agent private credentials\n if (this.agentId) {\n const agentKey = await this.loadFromAgentCredentials(normalizedProvider);\n if (agentKey) {\n log.debug({ provider, source: 'agent' }, 'Resolved API key from agent credentials');\n return agentKey;\n }\n }\n\n // 2. Try global credentials\n const globalKey = await this.loadFromGlobalCredentials(normalizedProvider);\n if (globalKey) {\n log.debug({ provider, source: 'global' }, 'Resolved API key from global credentials');\n return globalKey;\n }\n\n // 3. Try OAuth token (convert to Bearer)\n const oauthToken = await this.loadOAuthToken(normalizedProvider);\n if (oauthToken) {\n log.debug({ provider, source: 'oauth' }, 'Resolved API key from OAuth token');\n return oauthToken.access;\n }\n\n // 4. Environment variables (see `src/providers/env-keys.ts`)\n const envKey = getApiKeyFromEnv(normalizedProvider);\n if (envKey) {\n log.debug({ provider, source: 'env' }, 'Resolved API key from environment');\n return envKey;\n }\n\n log.debug({ provider }, 'No API key found');\n return null;\n }\n\n /**\n * Check if a provider has credentials configured\n */\n async hasCredentials(provider: string): Promise<boolean> {\n const key = await this.resolveApiKey(provider);\n return key !== null;\n }\n\n /**\n * Which step in {@link resolveApiKey} would supply the key (no secret material).\n */\n async resolveApiKeySource(\n provider: string,\n ): Promise<'agent' | 'global' | 'oauth' | 'env' | null> {\n const normalizedProvider = provider.toLowerCase();\n\n if (this.agentId) {\n const agentKey = await this.loadFromAgentCredentials(normalizedProvider);\n if (agentKey) return 'agent';\n }\n\n const globalKey = await this.loadFromGlobalCredentials(normalizedProvider);\n if (globalKey) return 'global';\n\n const oauthToken = await this.loadOAuthToken(normalizedProvider);\n if (oauthToken) return 'oauth';\n\n if (getApiKeyFromEnv(normalizedProvider)) return 'env';\n\n return null;\n }\n\n /**\n * List all available credential profiles\n */\n async listProfiles(): Promise<Array<ApiKeyProfile & { id: string; source: 'agent' | 'global' }>> {\n const profiles: Array<ApiKeyProfile & { id: string; source: 'agent' | 'global' }> = [];\n\n // Global profiles\n const globalProfiles = await this.loadAuthProfilesFile();\n for (const [id, profile] of Object.entries(globalProfiles.profiles)) {\n profiles.push({ ...profile, id, source: 'global' });\n }\n\n // Agent private profiles\n if (this.agentId) {\n const agentProfiles = await this.loadAgentAuthProfilesFile();\n for (const [id, profile] of Object.entries(agentProfiles.profiles)) {\n profiles.push({ ...profile, id, source: 'agent' });\n }\n }\n\n return profiles;\n }\n\n /**\n * Save an API key profile\n */\n async saveApiKey(\n provider: string,\n key: string,\n options: {\n profileName?: string;\n envVar?: string | null;\n agentPrivate?: boolean;\n } = {}\n ): Promise<void> {\n const normalizedProvider = provider.toLowerCase();\n const profileId = options.profileName\n ? `${normalizedProvider}:${options.profileName}`\n : `${normalizedProvider}:default`;\n\n const profile: ApiKeyProfile = {\n type: 'api_key',\n provider: normalizedProvider,\n profileName: options.profileName,\n envVar: options.envVar ?? null,\n key,\n };\n\n if (options.agentPrivate && this.agentId) {\n await this.saveAgentAuthProfile(profileId, profile);\n } else {\n await this.saveGlobalAuthProfile(profileId, profile);\n }\n\n log.info({ provider, profileId, agentPrivate: options.agentPrivate }, 'Saved API key');\n }\n\n /**\n * Delete a credential profile\n */\n async deleteProfile(profileId: string, options: { agentPrivate?: boolean } = {}): Promise<void> {\n if (options.agentPrivate && this.agentId) {\n await this.deleteAgentAuthProfile(profileId);\n } else {\n await this.deleteGlobalAuthProfile(profileId);\n }\n\n log.info({ profileId, agentPrivate: options.agentPrivate }, 'Deleted credential profile');\n }\n\n /**\n * Load OAuth token for a provider\n */\n async loadOAuthToken(provider: string): Promise<OAuthToken | null> {\n const normalizedProvider = provider.toLowerCase();\n const oauthPath = resolveOAuthPath(normalizedProvider);\n\n try {\n const content = await readFile(oauthPath, 'utf-8');\n const token = JSON.parse(content) as OAuthToken;\n\n // Check if token is expired\n if (token.expiresAt && token.expiresAt < Date.now()) {\n log.warn({ provider, expiresAt: token.expiresAt }, 'OAuth token is expired');\n // TODO: Implement token refresh\n return null;\n }\n\n return token;\n } catch {\n return null;\n }\n }\n\n /**\n * Save OAuth token for a provider\n */\n async saveOAuthToken(provider: string, token: Omit<OAuthToken, 'type' | 'provider' | 'updatedAt'>): Promise<void> {\n const normalizedProvider = provider.toLowerCase();\n const oauthPath = resolveOAuthPath(normalizedProvider);\n\n await mkdir(dirname(oauthPath), { recursive: true });\n\n const fullToken: OAuthToken = {\n ...token,\n type: 'oauth',\n provider: normalizedProvider,\n updatedAt: new Date().toISOString(),\n };\n\n await writeTextAtomic(oauthPath, JSON.stringify(fullToken, null, 2));\n log.info({ provider }, 'Saved OAuth token');\n }\n\n // ============================================\n // Private Methods\n // ============================================\n\n private async loadFromAgentCredentials(provider: string): Promise<string | null> {\n if (!this.agentId) return null;\n\n const profiles = await this.loadAgentAuthProfilesFile();\n const profile = this.findProfileForProvider(profiles, provider);\n\n if (!profile) return null;\n if (profile.envVar) return this.loadFromEnv(profile.envVar) ?? profile.key;\n return profile.key;\n }\n\n private async loadFromGlobalCredentials(provider: string): Promise<string | null> {\n const profiles = await this.loadAuthProfilesFile();\n const profile = this.findProfileForProvider(profiles, provider);\n\n if (!profile) return null;\n if (profile.envVar) return this.loadFromEnv(profile.envVar) ?? profile.key;\n return profile.key;\n }\n\n private loadFromEnv(envVarName: string): string | null {\n return process.env[envVarName] || null;\n }\n\n private findProfileForProvider(\n file: AuthProfilesFile,\n provider: string\n ): ApiKeyProfile | null {\n const normalizedProvider = provider.toLowerCase();\n\n // Look for exact match first\n for (const [, profile] of Object.entries(file.profiles)) {\n if (profile.provider === normalizedProvider) {\n return profile;\n }\n }\n\n return null;\n }\n\n private async loadAuthProfilesFile(): Promise<AuthProfilesFile> {\n const path = resolveAuthProfilesPath();\n\n try {\n const content = await readFile(path, 'utf-8');\n const data = JSON.parse(content);\n return {\n version: data.version || 1,\n profiles: data.profiles || {},\n };\n } catch {\n return { version: 2, profiles: {} };\n }\n }\n\n private async loadAgentAuthProfilesFile(): Promise<AuthProfilesFile> {\n if (!this.agentId || !this.appConfig) return { version: 2, profiles: {} };\n\n const path = resolveAgentAuthProfilesPath(this.appConfig, this.agentId);\n\n try {\n const content = await readFile(path, 'utf-8');\n const data = JSON.parse(content);\n return {\n version: data.version || 1,\n profiles: data.profiles || {},\n };\n } catch {\n return { version: 2, profiles: {} };\n }\n }\n\n private async saveGlobalAuthProfile(profileId: string, profile: ApiKeyProfile): Promise<void> {\n const path = resolveAuthProfilesPath();\n await mkdir(dirname(path), { recursive: true });\n\n const file = await this.loadAuthProfilesFile();\n file.profiles[profileId] = profile;\n\n await writeTextAtomic(path, JSON.stringify(file, null, 2));\n }\n\n private async saveAgentAuthProfile(profileId: string, profile: ApiKeyProfile): Promise<void> {\n if (!this.agentId || !this.appConfig) throw new Error('Agent ID and appConfig required for agent-private profiles');\n\n const path = resolveAgentAuthProfilesPath(this.appConfig, this.agentId);\n await mkdir(dirname(path), { recursive: true });\n\n const file = await this.loadAgentAuthProfilesFile();\n file.profiles[profileId] = profile;\n\n await writeTextAtomic(path, JSON.stringify(file, null, 2));\n }\n\n private async deleteGlobalAuthProfile(profileId: string): Promise<void> {\n const path = resolveAuthProfilesPath();\n const file = await this.loadAuthProfilesFile();\n\n delete file.profiles[profileId];\n\n await writeTextAtomic(path, JSON.stringify(file, null, 2));\n }\n\n private async deleteAgentAuthProfile(profileId: string): Promise<void> {\n if (!this.agentId || !this.appConfig) throw new Error('Agent ID and appConfig required for agent-private profiles');\n\n const path = resolveAgentAuthProfilesPath(this.appConfig, this.agentId);\n const file = await this.loadAgentAuthProfilesFile();\n\n delete file.profiles[profileId];\n\n await writeTextAtomic(path, JSON.stringify(file, null, 2));\n }\n}\n\n// ============================================\n// Convenience Functions\n// ============================================\n\nlet defaultResolver: CredentialResolver | null = null;\n\nexport function getCredentialResolver(options?: CredentialResolverOptions): CredentialResolver {\n if (!defaultResolver || options) {\n return new CredentialResolver(options);\n }\n return defaultResolver;\n}\n\nexport async function resolveApiKey(provider: string, options?: CredentialResolverOptions): Promise<string | null> {\n const resolver = getCredentialResolver(options);\n return resolver.resolveApiKey(provider);\n}\n\nexport async function hasCredentials(provider: string, options?: CredentialResolverOptions): Promise<boolean> {\n const resolver = getCredentialResolver(options);\n return resolver.hasCredentials(provider);\n}\n"],"mappings":";;;;;;;;;AAmYA,SAAgB,sBAAsB,SAAyD;AAE3F,QAAO,IAAI,mBAAmB,QAAQ;;AAK1C,eAAsB,cAAc,UAAkB,SAA6D;AAEjH,QADiB,sBAAsB,QACxB,CAAC,cAAc,SAAS;;AAGzC,eAAsB,eAAe,UAAkB,SAAuD;AAE5G,QADiB,sBAAsB,QACxB,CAAC,eAAe,SAAS;;;;yBAhZsB;cAEd;gBACU;aAMhC;AAGtB,OAAM,aAAa,cAAc;AA8C1B,sBAAb,MAAgC;EAC9B;EACA;EACA;EAEA,YAAY,UAAqC,EAAE,EAAE;AACnD,QAAK,iBAAiB,QAAQ,WAC1B,KAAK,QAAQ,UAAU,cAAc,GACrC,uBAAuB;AAC3B,QAAK,UAAU,QAAQ;AACvB,QAAK,YAAY,QAAQ;AACzB,OAAI,KAAK,WAAW,CAAC,KAAK,UACxB,OAAM,IAAI,MAAM,gEAAgE;;;;;;EAQpF,MAAM,cAAc,UAA0C;GAC5D,MAAM,qBAAqB,SAAS,aAAa;AAGjD,OAAI,KAAK,SAAS;IAChB,MAAM,WAAW,MAAM,KAAK,yBAAyB,mBAAmB;AACxE,QAAI,UAAU;AACZ,SAAI,MAAM;MAAE;MAAU,QAAQ;MAAS,EAAE,0CAA0C;AACnF,YAAO;;;GAKX,MAAM,YAAY,MAAM,KAAK,0BAA0B,mBAAmB;AAC1E,OAAI,WAAW;AACb,QAAI,MAAM;KAAE;KAAU,QAAQ;KAAU,EAAE,2CAA2C;AACrF,WAAO;;GAIT,MAAM,aAAa,MAAM,KAAK,eAAe,mBAAmB;AAChE,OAAI,YAAY;AACd,QAAI,MAAM;KAAE;KAAU,QAAQ;KAAS,EAAE,oCAAoC;AAC7E,WAAO,WAAW;;GAIpB,MAAM,SAAS,iBAAiB,mBAAmB;AACnD,OAAI,QAAQ;AACV,QAAI,MAAM;KAAE;KAAU,QAAQ;KAAO,EAAE,oCAAoC;AAC3E,WAAO;;AAGT,OAAI,MAAM,EAAE,UAAU,EAAE,mBAAmB;AAC3C,UAAO;;;;;EAMT,MAAM,eAAe,UAAoC;AAEvD,UAAO,MADW,KAAK,cAAc,SAAS,KAC/B;;;;;EAMjB,MAAM,oBACJ,UACsD;GACtD,MAAM,qBAAqB,SAAS,aAAa;AAEjD,OAAI,KAAK;QAEH,MADmB,KAAK,yBAAyB,mBAAmB,CAC1D,QAAO;;AAIvB,OAAI,MADoB,KAAK,0BAA0B,mBAAmB,CAC3D,QAAO;AAGtB,OAAI,MADqB,KAAK,eAAe,mBAAmB,CAChD,QAAO;AAEvB,OAAI,iBAAiB,mBAAmB,CAAE,QAAO;AAEjD,UAAO;;;;;EAMT,MAAM,eAA2F;GAC/F,MAAM,WAA8E,EAAE;GAGtF,MAAM,iBAAiB,MAAM,KAAK,sBAAsB;AACxD,QAAK,MAAM,CAAC,IAAI,YAAY,OAAO,QAAQ,eAAe,SAAS,CACjE,UAAS,KAAK;IAAE,GAAG;IAAS;IAAI,QAAQ;IAAU,CAAC;AAIrD,OAAI,KAAK,SAAS;IAChB,MAAM,gBAAgB,MAAM,KAAK,2BAA2B;AAC5D,SAAK,MAAM,CAAC,IAAI,YAAY,OAAO,QAAQ,cAAc,SAAS,CAChE,UAAS,KAAK;KAAE,GAAG;KAAS;KAAI,QAAQ;KAAS,CAAC;;AAItD,UAAO;;;;;EAMT,MAAM,WACJ,UACA,KACA,UAII,EAAE,EACS;GACf,MAAM,qBAAqB,SAAS,aAAa;GACjD,MAAM,YAAY,QAAQ,cACtB,GAAG,mBAAmB,GAAG,QAAQ,gBACjC,GAAG,mBAAmB;GAE1B,MAAM,UAAyB;IAC7B,MAAM;IACN,UAAU;IACV,aAAa,QAAQ;IACrB,QAAQ,QAAQ,UAAU;IAC1B;IACD;AAED,OAAI,QAAQ,gBAAgB,KAAK,QAC/B,OAAM,KAAK,qBAAqB,WAAW,QAAQ;OAEnD,OAAM,KAAK,sBAAsB,WAAW,QAAQ;AAGtD,OAAI,KAAK;IAAE;IAAU;IAAW,cAAc,QAAQ;IAAc,EAAE,gBAAgB;;;;;EAMxF,MAAM,cAAc,WAAmB,UAAsC,EAAE,EAAiB;AAC9F,OAAI,QAAQ,gBAAgB,KAAK,QAC/B,OAAM,KAAK,uBAAuB,UAAU;OAE5C,OAAM,KAAK,wBAAwB,UAAU;AAG/C,OAAI,KAAK;IAAE;IAAW,cAAc,QAAQ;IAAc,EAAE,6BAA6B;;;;;EAM3F,MAAM,eAAe,UAA8C;GAEjE,MAAM,YAAY,iBADS,SAAS,aACiB,CAAC;AAEtD,OAAI;IACF,MAAM,UAAU,MAAM,SAAS,WAAW,QAAQ;IAClD,MAAM,QAAQ,KAAK,MAAM,QAAQ;AAGjC,QAAI,MAAM,aAAa,MAAM,YAAY,KAAK,KAAK,EAAE;AACnD,SAAI,KAAK;MAAE;MAAU,WAAW,MAAM;MAAW,EAAE,yBAAyB;AAE5E,YAAO;;AAGT,WAAO;WACD;AACN,WAAO;;;;;;EAOX,MAAM,eAAe,UAAkB,OAA2E;GAChH,MAAM,qBAAqB,SAAS,aAAa;GACjD,MAAM,YAAY,iBAAiB,mBAAmB;AAEtD,SAAM,MAAM,QAAQ,UAAU,EAAE,EAAE,WAAW,MAAM,CAAC;GAEpD,MAAM,YAAwB;IAC5B,GAAG;IACH,MAAM;IACN,UAAU;IACV,4BAAW,IAAI,MAAM,EAAC,aAAa;IACpC;AAED,SAAM,gBAAgB,WAAW,KAAK,UAAU,WAAW,MAAM,EAAE,CAAC;AACpE,OAAI,KAAK,EAAE,UAAU,EAAE,oBAAoB;;EAO7C,MAAc,yBAAyB,UAA0C;AAC/E,OAAI,CAAC,KAAK,QAAS,QAAO;GAE1B,MAAM,WAAW,MAAM,KAAK,2BAA2B;GACvD,MAAM,UAAU,KAAK,uBAAuB,UAAU,SAAS;AAE/D,OAAI,CAAC,QAAS,QAAO;AACrB,OAAI,QAAQ,OAAQ,QAAO,KAAK,YAAY,QAAQ,OAAO,IAAI,QAAQ;AACvE,UAAO,QAAQ;;EAGjB,MAAc,0BAA0B,UAA0C;GAChF,MAAM,WAAW,MAAM,KAAK,sBAAsB;GAClD,MAAM,UAAU,KAAK,uBAAuB,UAAU,SAAS;AAE/D,OAAI,CAAC,QAAS,QAAO;AACrB,OAAI,QAAQ,OAAQ,QAAO,KAAK,YAAY,QAAQ,OAAO,IAAI,QAAQ;AACvE,UAAO,QAAQ;;EAGjB,YAAoB,YAAmC;AACrD,UAAO,QAAQ,IAAI,eAAe;;EAGpC,uBACE,MACA,UACsB;GACtB,MAAM,qBAAqB,SAAS,aAAa;AAGjD,QAAK,MAAM,GAAG,YAAY,OAAO,QAAQ,KAAK,SAAS,CACrD,KAAI,QAAQ,aAAa,mBACvB,QAAO;AAIX,UAAO;;EAGT,MAAc,uBAAkD;GAC9D,MAAM,OAAO,yBAAyB;AAEtC,OAAI;IACF,MAAM,UAAU,MAAM,SAAS,MAAM,QAAQ;IAC7C,MAAM,OAAO,KAAK,MAAM,QAAQ;AAChC,WAAO;KACL,SAAS,KAAK,WAAW;KACzB,UAAU,KAAK,YAAY,EAAE;KAC9B;WACK;AACN,WAAO;KAAE,SAAS;KAAG,UAAU,EAAE;KAAE;;;EAIvC,MAAc,4BAAuD;AACnE,OAAI,CAAC,KAAK,WAAW,CAAC,KAAK,UAAW,QAAO;IAAE,SAAS;IAAG,UAAU,EAAE;IAAE;GAEzE,MAAM,OAAO,6BAA6B,KAAK,WAAW,KAAK,QAAQ;AAEvE,OAAI;IACF,MAAM,UAAU,MAAM,SAAS,MAAM,QAAQ;IAC7C,MAAM,OAAO,KAAK,MAAM,QAAQ;AAChC,WAAO;KACL,SAAS,KAAK,WAAW;KACzB,UAAU,KAAK,YAAY,EAAE;KAC9B;WACK;AACN,WAAO;KAAE,SAAS;KAAG,UAAU,EAAE;KAAE;;;EAIvC,MAAc,sBAAsB,WAAmB,SAAuC;GAC5F,MAAM,OAAO,yBAAyB;AACtC,SAAM,MAAM,QAAQ,KAAK,EAAE,EAAE,WAAW,MAAM,CAAC;GAE/C,MAAM,OAAO,MAAM,KAAK,sBAAsB;AAC9C,QAAK,SAAS,aAAa;AAE3B,SAAM,gBAAgB,MAAM,KAAK,UAAU,MAAM,MAAM,EAAE,CAAC;;EAG5D,MAAc,qBAAqB,WAAmB,SAAuC;AAC3F,OAAI,CAAC,KAAK,WAAW,CAAC,KAAK,UAAW,OAAM,IAAI,MAAM,6DAA6D;GAEnH,MAAM,OAAO,6BAA6B,KAAK,WAAW,KAAK,QAAQ;AACvE,SAAM,MAAM,QAAQ,KAAK,EAAE,EAAE,WAAW,MAAM,CAAC;GAE/C,MAAM,OAAO,MAAM,KAAK,2BAA2B;AACnD,QAAK,SAAS,aAAa;AAE3B,SAAM,gBAAgB,MAAM,KAAK,UAAU,MAAM,MAAM,EAAE,CAAC;;EAG5D,MAAc,wBAAwB,WAAkC;GACtE,MAAM,OAAO,yBAAyB;GACtC,MAAM,OAAO,MAAM,KAAK,sBAAsB;AAE9C,UAAO,KAAK,SAAS;AAErB,SAAM,gBAAgB,MAAM,KAAK,UAAU,MAAM,MAAM,EAAE,CAAC;;EAG5D,MAAc,uBAAuB,WAAkC;AACrE,OAAI,CAAC,KAAK,WAAW,CAAC,KAAK,UAAW,OAAM,IAAI,MAAM,6DAA6D;GAEnH,MAAM,OAAO,6BAA6B,KAAK,WAAW,KAAK,QAAQ;GACvE,MAAM,OAAO,MAAM,KAAK,2BAA2B;AAEnD,UAAO,KAAK,SAAS;AAErB,SAAM,gBAAgB,MAAM,KAAK,UAAU,MAAM,MAAM,EAAE,CAAC"}