@rudderhq/server 0.2.5-canary.8 → 0.2.5

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 (309) hide show
  1. package/dist/bootstrap/plugin-host-runtime.d.ts +39 -39
  2. package/dist/bundled-plugins/plugin-linear/dist/worker.js +101 -147
  3. package/dist/bundled-plugins/plugin-linear/dist/worker.js.map +2 -2
  4. package/dist/bundled-plugins/plugin-linear/package.json +1 -1
  5. package/dist/routes/access-onboarding.helpers.d.ts +142 -0
  6. package/dist/routes/access-onboarding.helpers.d.ts.map +1 -0
  7. package/dist/routes/access-onboarding.helpers.js +762 -0
  8. package/dist/routes/access-onboarding.helpers.js.map +1 -0
  9. package/dist/routes/access.d.ts +2 -48
  10. package/dist/routes/access.d.ts.map +1 -1
  11. package/dist/routes/access.helpers.d.ts +109 -0
  12. package/dist/routes/access.helpers.d.ts.map +1 -0
  13. package/dist/routes/access.helpers.js +460 -0
  14. package/dist/routes/access.helpers.js.map +1 -0
  15. package/dist/routes/access.js +6 -1218
  16. package/dist/routes/access.js.map +1 -1
  17. package/dist/routes/agents.d.ts.map +1 -1
  18. package/dist/routes/agents.js +55 -1057
  19. package/dist/routes/agents.js.map +1 -1
  20. package/dist/routes/agents.management-routes.d.ts +12 -0
  21. package/dist/routes/agents.management-routes.d.ts.map +1 -0
  22. package/dist/routes/agents.management-routes.js +1067 -0
  23. package/dist/routes/agents.management-routes.js.map +1 -0
  24. package/dist/routes/chats.d.ts.map +1 -1
  25. package/dist/routes/chats.js +42 -652
  26. package/dist/routes/chats.js.map +1 -1
  27. package/dist/routes/chats.stream-routes.d.ts +12 -0
  28. package/dist/routes/chats.stream-routes.d.ts.map +1 -0
  29. package/dist/routes/chats.stream-routes.js +666 -0
  30. package/dist/routes/chats.stream-routes.js.map +1 -0
  31. package/dist/routes/issues.comments-attachments.d.ts +12 -0
  32. package/dist/routes/issues.comments-attachments.d.ts.map +1 -0
  33. package/dist/routes/issues.comments-attachments.js +511 -0
  34. package/dist/routes/issues.comments-attachments.js.map +1 -0
  35. package/dist/routes/issues.d.ts.map +1 -1
  36. package/dist/routes/issues.js +43 -1128
  37. package/dist/routes/issues.js.map +1 -1
  38. package/dist/routes/issues.mutations.d.ts +12 -0
  39. package/dist/routes/issues.mutations.d.ts.map +1 -0
  40. package/dist/routes/issues.mutations.js +635 -0
  41. package/dist/routes/issues.mutations.js.map +1 -0
  42. package/dist/routes/plugins.d.ts.map +1 -1
  43. package/dist/routes/plugins.js +14 -694
  44. package/dist/routes/plugins.js.map +1 -1
  45. package/dist/routes/plugins.operations-routes.d.ts +28 -0
  46. package/dist/routes/plugins.operations-routes.d.ts.map +1 -0
  47. package/dist/routes/plugins.operations-routes.js +720 -0
  48. package/dist/routes/plugins.operations-routes.js.map +1 -0
  49. package/dist/services/access.d.ts +21 -21
  50. package/dist/services/activity.d.ts +19 -19
  51. package/dist/services/agents.d.ts +158 -158
  52. package/dist/services/approvals.d.ts +29 -29
  53. package/dist/services/assets.d.ts +8 -8
  54. package/dist/services/automations.d.ts +41 -27
  55. package/dist/services/automations.d.ts.map +1 -1
  56. package/dist/services/automations.js +287 -110
  57. package/dist/services/automations.js.map +1 -1
  58. package/dist/services/automations.scheduler.d.ts +9 -0
  59. package/dist/services/automations.scheduler.d.ts.map +1 -0
  60. package/dist/services/automations.scheduler.js +101 -0
  61. package/dist/services/automations.scheduler.js.map +1 -0
  62. package/dist/services/board-auth.d.ts +32 -32
  63. package/dist/services/calendar.d.ts +26 -26
  64. package/dist/services/chat-assistant.d.ts +3 -47
  65. package/dist/services/chat-assistant.d.ts.map +1 -1
  66. package/dist/services/chat-assistant.helpers.d.ts +156 -0
  67. package/dist/services/chat-assistant.helpers.d.ts.map +1 -0
  68. package/dist/services/chat-assistant.helpers.js +862 -0
  69. package/dist/services/chat-assistant.helpers.js.map +1 -0
  70. package/dist/services/chat-assistant.js +2 -861
  71. package/dist/services/chat-assistant.js.map +1 -1
  72. package/dist/services/chats.d.ts +149 -247
  73. package/dist/services/chats.d.ts.map +1 -1
  74. package/dist/services/chats.helpers.d.ts +117 -0
  75. package/dist/services/chats.helpers.d.ts.map +1 -0
  76. package/dist/services/chats.helpers.js +285 -0
  77. package/dist/services/chats.helpers.js.map +1 -0
  78. package/dist/services/chats.js +6 -286
  79. package/dist/services/chats.js.map +1 -1
  80. package/dist/services/costs.d.ts +8 -8
  81. package/dist/services/finance.d.ts +18 -18
  82. package/dist/services/goals.d.ts +30 -30
  83. package/dist/services/heartbeat.d.ts +3 -1
  84. package/dist/services/heartbeat.d.ts.map +1 -1
  85. package/dist/services/heartbeat.js +3 -1
  86. package/dist/services/heartbeat.js.map +1 -1
  87. package/dist/services/issue-approvals.d.ts +4 -4
  88. package/dist/services/issue-review-wakeup.d.ts +3 -3
  89. package/dist/services/issues.comments-attachments.d.ts +141 -0
  90. package/dist/services/issues.comments-attachments.d.ts.map +1 -0
  91. package/dist/services/issues.comments-attachments.js +313 -0
  92. package/dist/services/issues.comments-attachments.js.map +1 -0
  93. package/dist/services/issues.d.ts +205 -256
  94. package/dist/services/issues.d.ts.map +1 -1
  95. package/dist/services/issues.helpers.d.ts +87 -0
  96. package/dist/services/issues.helpers.d.ts.map +1 -0
  97. package/dist/services/issues.helpers.js +270 -0
  98. package/dist/services/issues.helpers.js.map +1 -0
  99. package/dist/services/issues.js +5 -569
  100. package/dist/services/issues.js.map +1 -1
  101. package/dist/services/knowledge-portability/organization-portability.core.d.ts +210 -0
  102. package/dist/services/knowledge-portability/organization-portability.core.d.ts.map +1 -0
  103. package/dist/services/knowledge-portability/organization-portability.core.js +997 -0
  104. package/dist/services/knowledge-portability/organization-portability.core.js.map +1 -0
  105. package/dist/services/knowledge-portability/organization-portability.d.ts +6 -28
  106. package/dist/services/knowledge-portability/organization-portability.d.ts.map +1 -1
  107. package/dist/services/knowledge-portability/organization-portability.export.d.ts +24 -0
  108. package/dist/services/knowledge-portability/organization-portability.export.d.ts.map +1 -0
  109. package/dist/services/knowledge-portability/organization-portability.export.js +607 -0
  110. package/dist/services/knowledge-portability/organization-portability.export.js.map +1 -0
  111. package/dist/services/knowledge-portability/organization-portability.files.d.ts +69 -0
  112. package/dist/services/knowledge-portability/organization-portability.files.d.ts.map +1 -0
  113. package/dist/services/knowledge-portability/organization-portability.files.js +597 -0
  114. package/dist/services/knowledge-portability/organization-portability.files.js.map +1 -0
  115. package/dist/services/knowledge-portability/organization-portability.import.d.ts +31 -0
  116. package/dist/services/knowledge-portability/organization-portability.import.d.ts.map +1 -0
  117. package/dist/services/knowledge-portability/organization-portability.import.js +575 -0
  118. package/dist/services/knowledge-portability/organization-portability.import.js.map +1 -0
  119. package/dist/services/knowledge-portability/organization-portability.js +37 -3848
  120. package/dist/services/knowledge-portability/organization-portability.js.map +1 -1
  121. package/dist/services/knowledge-portability/organization-portability.package.d.ts +72 -0
  122. package/dist/services/knowledge-portability/organization-portability.package.d.ts.map +1 -0
  123. package/dist/services/knowledge-portability/organization-portability.package.js +749 -0
  124. package/dist/services/knowledge-portability/organization-portability.package.js.map +1 -0
  125. package/dist/services/knowledge-portability/organization-portability.preview.d.ts +18 -0
  126. package/dist/services/knowledge-portability/organization-portability.preview.d.ts.map +1 -0
  127. package/dist/services/knowledge-portability/organization-portability.preview.js +333 -0
  128. package/dist/services/knowledge-portability/organization-portability.preview.js.map +1 -0
  129. package/dist/services/knowledge-portability/organization-portability.resolve-source.d.ts +4 -0
  130. package/dist/services/knowledge-portability/organization-portability.resolve-source.d.ts.map +1 -0
  131. package/dist/services/knowledge-portability/organization-portability.resolve-source.js +86 -0
  132. package/dist/services/knowledge-portability/organization-portability.resolve-source.js.map +1 -0
  133. package/dist/services/knowledge-portability/organization-skills.catalog.d.ts +221 -0
  134. package/dist/services/knowledge-portability/organization-skills.catalog.d.ts.map +1 -0
  135. package/dist/services/knowledge-portability/organization-skills.catalog.js +999 -0
  136. package/dist/services/knowledge-portability/organization-skills.catalog.js.map +1 -0
  137. package/dist/services/knowledge-portability/organization-skills.d.ts +4 -75
  138. package/dist/services/knowledge-portability/organization-skills.d.ts.map +1 -1
  139. package/dist/services/knowledge-portability/organization-skills.js +11 -2008
  140. package/dist/services/knowledge-portability/organization-skills.js.map +1 -1
  141. package/dist/services/knowledge-portability/organization-skills.scans.d.ts +16 -0
  142. package/dist/services/knowledge-portability/organization-skills.scans.d.ts.map +1 -0
  143. package/dist/services/knowledge-portability/organization-skills.scans.js +300 -0
  144. package/dist/services/knowledge-portability/organization-skills.scans.js.map +1 -0
  145. package/dist/services/knowledge-portability/organization-skills.sources.d.ts +68 -0
  146. package/dist/services/knowledge-portability/organization-skills.sources.d.ts.map +1 -0
  147. package/dist/services/knowledge-portability/organization-skills.sources.js +728 -0
  148. package/dist/services/knowledge-portability/organization-skills.sources.js.map +1 -0
  149. package/dist/services/messenger.d.ts +2 -2
  150. package/dist/services/messenger.js +2 -2
  151. package/dist/services/messenger.js.map +1 -1
  152. package/dist/services/organization-skills.d.ts +3 -1
  153. package/dist/services/organization-skills.d.ts.map +1 -1
  154. package/dist/services/organization-skills.js +3 -1
  155. package/dist/services/organization-skills.js.map +1 -1
  156. package/dist/services/orgs.d.ts +9 -9
  157. package/dist/services/plugin-loader.core.d.ts +14 -0
  158. package/dist/services/plugin-loader.core.d.ts.map +1 -0
  159. package/dist/services/plugin-loader.core.js +905 -0
  160. package/dist/services/plugin-loader.core.js.map +1 -0
  161. package/dist/services/plugin-loader.d.ts +3 -440
  162. package/dist/services/plugin-loader.d.ts.map +1 -1
  163. package/dist/services/plugin-loader.helpers.d.ts +468 -0
  164. package/dist/services/plugin-loader.helpers.d.ts.map +1 -0
  165. package/dist/services/plugin-loader.helpers.js +263 -0
  166. package/dist/services/plugin-loader.helpers.js.map +1 -0
  167. package/dist/services/plugin-loader.js +3 -1191
  168. package/dist/services/plugin-loader.js.map +1 -1
  169. package/dist/services/plugin-loader.worker-paths.d.ts +7 -0
  170. package/dist/services/plugin-loader.worker-paths.d.ts.map +1 -0
  171. package/dist/services/plugin-loader.worker-paths.js +85 -0
  172. package/dist/services/plugin-loader.worker-paths.js.map +1 -0
  173. package/dist/services/plugin-registry.d.ts +123 -123
  174. package/dist/services/projects.d.ts +8 -8
  175. package/dist/services/runtime-kernel/heartbeat.core.d.ts +725 -0
  176. package/dist/services/runtime-kernel/heartbeat.core.d.ts.map +1 -0
  177. package/dist/services/runtime-kernel/heartbeat.core.js +525 -0
  178. package/dist/services/runtime-kernel/heartbeat.core.js.map +1 -0
  179. package/dist/services/runtime-kernel/heartbeat.d.ts +38 -259
  180. package/dist/services/runtime-kernel/heartbeat.d.ts.map +1 -1
  181. package/dist/services/runtime-kernel/heartbeat.execute.d.ts +5 -0
  182. package/dist/services/runtime-kernel/heartbeat.execute.d.ts.map +1 -0
  183. package/dist/services/runtime-kernel/heartbeat.execute.js +1052 -0
  184. package/dist/services/runtime-kernel/heartbeat.execute.js.map +1 -0
  185. package/dist/services/runtime-kernel/heartbeat.js +50 -4142
  186. package/dist/services/runtime-kernel/heartbeat.js.map +1 -1
  187. package/dist/services/runtime-kernel/heartbeat.misc.d.ts +30 -0
  188. package/dist/services/runtime-kernel/heartbeat.misc.d.ts.map +1 -0
  189. package/dist/services/runtime-kernel/heartbeat.misc.js +483 -0
  190. package/dist/services/runtime-kernel/heartbeat.misc.js.map +1 -0
  191. package/dist/services/runtime-kernel/heartbeat.recovery.d.ts +38 -0
  192. package/dist/services/runtime-kernel/heartbeat.recovery.d.ts.map +1 -0
  193. package/dist/services/runtime-kernel/heartbeat.recovery.js +605 -0
  194. package/dist/services/runtime-kernel/heartbeat.recovery.js.map +1 -0
  195. package/dist/services/runtime-kernel/heartbeat.release.d.ts +6 -0
  196. package/dist/services/runtime-kernel/heartbeat.release.d.ts.map +1 -0
  197. package/dist/services/runtime-kernel/heartbeat.release.js +398 -0
  198. package/dist/services/runtime-kernel/heartbeat.release.js.map +1 -0
  199. package/dist/services/runtime-kernel/heartbeat.sessions.d.ts +229 -0
  200. package/dist/services/runtime-kernel/heartbeat.sessions.d.ts.map +1 -0
  201. package/dist/services/runtime-kernel/heartbeat.sessions.js +708 -0
  202. package/dist/services/runtime-kernel/heartbeat.sessions.js.map +1 -0
  203. package/dist/services/runtime-kernel/heartbeat.wakeup.d.ts +5 -0
  204. package/dist/services/runtime-kernel/heartbeat.wakeup.d.ts.map +1 -0
  205. package/dist/services/runtime-kernel/heartbeat.wakeup.js +552 -0
  206. package/dist/services/runtime-kernel/heartbeat.wakeup.js.map +1 -0
  207. package/dist/services/secrets.d.ts +25 -25
  208. package/dist/services/sidebar-badges.js +1 -1
  209. package/dist/services/sidebar-badges.js.map +1 -1
  210. package/dist/services/workspace-runtime.comments.d.ts +6 -0
  211. package/dist/services/workspace-runtime.comments.d.ts.map +1 -0
  212. package/dist/services/workspace-runtime.comments.js +17 -0
  213. package/dist/services/workspace-runtime.comments.js.map +1 -0
  214. package/dist/services/workspace-runtime.d.ts +4 -163
  215. package/dist/services/workspace-runtime.d.ts.map +1 -1
  216. package/dist/services/workspace-runtime.helpers.d.ts +163 -0
  217. package/dist/services/workspace-runtime.helpers.d.ts.map +1 -0
  218. package/dist/services/workspace-runtime.helpers.js +360 -0
  219. package/dist/services/workspace-runtime.helpers.js.map +1 -0
  220. package/dist/services/workspace-runtime.js +4 -1236
  221. package/dist/services/workspace-runtime.js.map +1 -1
  222. package/dist/services/workspace-runtime.lifecycle.d.ts +35 -0
  223. package/dist/services/workspace-runtime.lifecycle.d.ts.map +1 -0
  224. package/dist/services/workspace-runtime.lifecycle.js +266 -0
  225. package/dist/services/workspace-runtime.lifecycle.js.map +1 -0
  226. package/dist/services/workspace-runtime.services.d.ts +140 -0
  227. package/dist/services/workspace-runtime.services.d.ts.map +1 -0
  228. package/dist/services/workspace-runtime.services.js +606 -0
  229. package/dist/services/workspace-runtime.services.js.map +1 -0
  230. package/package.json +21 -15
  231. package/ui-dist/assets/{_basePickBy-DeCw-kw3.js → _basePickBy-N8I9ml5Y.js} +1 -1
  232. package/ui-dist/assets/{_baseUniq-CVepsVZm.js → _baseUniq-BuSlpRSQ.js} +1 -1
  233. package/ui-dist/assets/{arc-QifRrkx2.js → arc-qX-dPyA1.js} +1 -1
  234. package/ui-dist/assets/{architectureDiagram-2XIMDMQ5-CT4me0hw.js → architectureDiagram-2XIMDMQ5-DhjkbXsp.js} +1 -1
  235. package/ui-dist/assets/{blockDiagram-WCTKOSBZ-uD6J91MI.js → blockDiagram-WCTKOSBZ-JS-tTu3J.js} +1 -1
  236. package/ui-dist/assets/{c4Diagram-IC4MRINW-D2GM2pzG.js → c4Diagram-IC4MRINW-4DqwCWIx.js} +1 -1
  237. package/ui-dist/assets/channel-CccCW5_a.js +1 -0
  238. package/ui-dist/assets/{chunk-4BX2VUAB-D8pPrlss.js → chunk-4BX2VUAB-T37SqBpp.js} +1 -1
  239. package/ui-dist/assets/{chunk-55IACEB6-CHF68vwj.js → chunk-55IACEB6-BSj9hdqK.js} +1 -1
  240. package/ui-dist/assets/{chunk-FMBD7UC4-CKmGUf9X.js → chunk-FMBD7UC4-Dkrlh0Wk.js} +1 -1
  241. package/ui-dist/assets/{chunk-JSJVCQXG-CTBCV-7X.js → chunk-JSJVCQXG-C0ZE3QdB.js} +1 -1
  242. package/ui-dist/assets/{chunk-KX2RTZJC-DV5XzGob.js → chunk-KX2RTZJC-DOZQM9gW.js} +1 -1
  243. package/ui-dist/assets/{chunk-NQ4KR5QH-B7diT0e4.js → chunk-NQ4KR5QH-5Yr3U2k8.js} +1 -1
  244. package/ui-dist/assets/{chunk-QZHKN3VN-BphcSb1i.js → chunk-QZHKN3VN-CvKTufwF.js} +1 -1
  245. package/ui-dist/assets/{chunk-WL4C6EOR-Bs_jQBMG.js → chunk-WL4C6EOR-IoEM0jyx.js} +1 -1
  246. package/ui-dist/assets/classDiagram-VBA2DB6C-JKk4tCW2.js +1 -0
  247. package/ui-dist/assets/classDiagram-v2-RAHNMMFH-JKk4tCW2.js +1 -0
  248. package/ui-dist/assets/clone-Onaweg8D.js +1 -0
  249. package/ui-dist/assets/{cose-bilkent-S5V4N54A-BxfO0pV9.js → cose-bilkent-S5V4N54A-CTvr1OFj.js} +1 -1
  250. package/ui-dist/assets/{dagre-KLK3FWXG-BiDkAX-Z.js → dagre-KLK3FWXG-UZ-SNjVK.js} +1 -1
  251. package/ui-dist/assets/{diagram-E7M64L7V-Btz_oxkC.js → diagram-E7M64L7V-D7RAN0Hr.js} +1 -1
  252. package/ui-dist/assets/{diagram-IFDJBPK2-Cdp8lQxJ.js → diagram-IFDJBPK2-B4LViaFR.js} +1 -1
  253. package/ui-dist/assets/{diagram-P4PSJMXO-DuTbeAS1.js → diagram-P4PSJMXO-CY1be7ak.js} +1 -1
  254. package/ui-dist/assets/{erDiagram-INFDFZHY-CzoQlOwo.js → erDiagram-INFDFZHY-Dca0KkvJ.js} +1 -1
  255. package/ui-dist/assets/{flowDiagram-PKNHOUZH-Diz_MWi3.js → flowDiagram-PKNHOUZH-i-qMvfwg.js} +1 -1
  256. package/ui-dist/assets/{ganttDiagram-A5KZAMGK-CWeGI1E-.js → ganttDiagram-A5KZAMGK-Wxq2lhbh.js} +1 -1
  257. package/ui-dist/assets/{gitGraphDiagram-K3NZZRJ6-C3QhZnAN.js → gitGraphDiagram-K3NZZRJ6-DwzgPlAY.js} +1 -1
  258. package/ui-dist/assets/{graph-KQH4eaLv.js → graph-BAqf89Tz.js} +1 -1
  259. package/ui-dist/assets/{index-CkEEsJ_9.js → index-4eCzaLuY.js} +1 -1
  260. package/ui-dist/assets/{index-DCOA92Vt.js → index-8uu-nKqK.js} +1 -1
  261. package/ui-dist/assets/{index-DtsZnqcf.js → index-B-1NEcI_.js} +1 -1
  262. package/ui-dist/assets/{index-BvGpil9e.js → index-B0b_3Eu5.js} +1 -1
  263. package/ui-dist/assets/{index-BMhxh9sB.js → index-B8v0eZjP.js} +1 -1
  264. package/ui-dist/assets/{index-aKvEm2pJ.js → index-BN7Moj3u.js} +1 -1
  265. package/ui-dist/assets/{index-iJyjaIGd.js → index-BSpxh3cY.js} +1 -1
  266. package/ui-dist/assets/{index-DhRKQjzu.js → index-BY44RIi9.js} +1 -1
  267. package/ui-dist/assets/{index-Z4rTzdcL.js → index-BhyQJhdZ.js} +1 -1
  268. package/ui-dist/assets/{index-DBxBUiZC.js → index-BkPL_iGU.js} +1 -1
  269. package/ui-dist/assets/{index-CsSppW5U.js → index-BsPfoHXS.js} +1 -1
  270. package/ui-dist/assets/{index-B8J1oewY.js → index-BstW7nmv.js} +1 -1
  271. package/ui-dist/assets/{index-CVZYu_kq.js → index-BwB67Zyz.js} +1 -1
  272. package/ui-dist/assets/index-C2peSkmT.css +1 -0
  273. package/ui-dist/assets/{index-Djz3PL1M.js → index-C3ktOsS_.js} +1 -1
  274. package/ui-dist/assets/{index-BMZfWLwr.js → index-CMyABlS-.js} +1 -1
  275. package/ui-dist/assets/{index-Cqdw7Lnc.js → index-CyBJ8ujC.js} +1 -1
  276. package/ui-dist/assets/{index-Ctp_0y5X.js → index-DAxM2W3O.js} +1 -1
  277. package/ui-dist/assets/{index-_jGthZ-1.js → index-DVZXPmhk.js} +1 -1
  278. package/ui-dist/assets/{index-CBLnbZVL.js → index-Dc19uAyw.js} +1 -1
  279. package/ui-dist/assets/index-DzHrwZu1.js +1511 -0
  280. package/ui-dist/assets/{index-ChTjk1gO.js → index-LJuf53Ye.js} +1 -1
  281. package/ui-dist/assets/{index-wXEAD8rI.js → index-Ugw5VWWz.js} +1 -1
  282. package/ui-dist/assets/{index-ciyPUpT9.js → index-YGraEFR7.js} +1 -1
  283. package/ui-dist/assets/{infoDiagram-LFFYTUFH-DbMzKsuw.js → infoDiagram-LFFYTUFH-jLmDtFVR.js} +1 -1
  284. package/ui-dist/assets/{ishikawaDiagram-PHBUUO56-CcKXcf2V.js → ishikawaDiagram-PHBUUO56-6OGMyLT8.js} +1 -1
  285. package/ui-dist/assets/{journeyDiagram-4ABVD52K-BY2GuHyR.js → journeyDiagram-4ABVD52K-yQjl6E0t.js} +1 -1
  286. package/ui-dist/assets/{kanban-definition-K7BYSVSG-BlZWM0Uz.js → kanban-definition-K7BYSVSG-DkdCeQlS.js} +1 -1
  287. package/ui-dist/assets/{layout-qHGAYgRY.js → layout-CqSYvZ_w.js} +1 -1
  288. package/ui-dist/assets/{linear-BigkGXbh.js → linear-B8xGZaoi.js} +1 -1
  289. package/ui-dist/assets/{mermaid.core-DZ099nW4.js → mermaid.core-AKL_cdyk.js} +4 -4
  290. package/ui-dist/assets/{mindmap-definition-YRQLILUH-CElDqDe0.js → mindmap-definition-YRQLILUH-Zr-dXC0x.js} +1 -1
  291. package/ui-dist/assets/{pieDiagram-SKSYHLDU-I2LDYrgm.js → pieDiagram-SKSYHLDU-BvDAU-Nk.js} +1 -1
  292. package/ui-dist/assets/{quadrantDiagram-337W2JSQ-D-U35edU.js → quadrantDiagram-337W2JSQ-Dn9kM62o.js} +1 -1
  293. package/ui-dist/assets/{requirementDiagram-Z7DCOOCP-FAWtaOKe.js → requirementDiagram-Z7DCOOCP-GIsIh7Sd.js} +1 -1
  294. package/ui-dist/assets/{sankeyDiagram-WA2Y5GQK-CzFHHNNh.js → sankeyDiagram-WA2Y5GQK-CUCuBkuf.js} +1 -1
  295. package/ui-dist/assets/{sequenceDiagram-2WXFIKYE-Cy-UViPL.js → sequenceDiagram-2WXFIKYE-MDpUY2HM.js} +1 -1
  296. package/ui-dist/assets/{stateDiagram-RAJIS63D-BEdt3CLl.js → stateDiagram-RAJIS63D-BymMpuUU.js} +1 -1
  297. package/ui-dist/assets/stateDiagram-v2-FVOUBMTO-Bi2oCU6d.js +1 -0
  298. package/ui-dist/assets/{timeline-definition-YZTLITO2-YD1e-WHS.js → timeline-definition-YZTLITO2-B6ofPhhy.js} +1 -1
  299. package/ui-dist/assets/{treemap-KZPCXAKY-BnqlVkAC.js → treemap-KZPCXAKY-DnLO6w1l.js} +1 -1
  300. package/ui-dist/assets/{vennDiagram-LZ73GAT5-f4WCy3o6.js → vennDiagram-LZ73GAT5-D0MyZIDl.js} +1 -1
  301. package/ui-dist/assets/{xychartDiagram-JWTSCODW-CWA35znA.js → xychartDiagram-JWTSCODW-rADY1iUG.js} +1 -1
  302. package/ui-dist/index.html +2 -2
  303. package/ui-dist/assets/channel-BV7st2TW.js +0 -1
  304. package/ui-dist/assets/classDiagram-VBA2DB6C-Cw_xj5ie.js +0 -1
  305. package/ui-dist/assets/classDiagram-v2-RAHNMMFH-Cw_xj5ie.js +0 -1
  306. package/ui-dist/assets/clone-DGshofUt.js +0 -1
  307. package/ui-dist/assets/index-Ded0dPwB.css +0 -1
  308. package/ui-dist/assets/index-Jhxth516.js +0 -1510
  309. package/ui-dist/assets/stateDiagram-v2-FVOUBMTO-cW7aES_v.js +0 -1
@@ -1,1732 +1,27 @@
1
- import { createHash } from "node:crypto";
2
1
  import { promises as fs } from "node:fs";
3
- import os from "node:os";
4
2
  import path from "node:path";
5
- import { fileURLToPath } from "node:url";
6
3
  import { and, asc, eq } from "drizzle-orm";
7
4
  import { agents as agentRows, organizationSkills } from "@rudderhq/db";
8
5
  import { readRudderSkillSyncPreference, writeRudderSkillSyncPreference } from "@rudderhq/agent-runtime-utils/server-utils";
9
- import { readSkillMetadataFromPath } from "@rudderhq/agent-runtime-utils/server-utils";
10
- import { RUDDER_BUNDLED_SKILL_SLUGS, getBundledRudderSkillSlug, isCanonicalBundledRudderSkillKey, normalizeAgentUrlKey, resolveOrganizationSkillReference, toBundledRudderSkillKey, } from "@rudderhq/shared";
11
- import { resolveAgentSkillsDir, resolveOrganizationSkillsDir, resolveOrganizationWorkspaceRoot, } from "../../home-paths.js";
6
+ import { RUDDER_BUNDLED_SKILL_SLUGS, getBundledRudderSkillSlug, toBundledRudderSkillKey, } from "@rudderhq/shared";
7
+ import { resolveAgentSkillsDir, resolveOrganizationWorkspaceRoot, } from "../../home-paths.js";
12
8
  import { conflict, notFound, unprocessable } from "../../errors.js";
13
9
  import { agentEnabledSkillsService } from "../agent-enabled-skills.js";
14
10
  import { agentService } from "../agents.js";
15
11
  import { projectService } from "../projects.js";
16
- const skillInventoryRefreshPromises = new Map();
17
- const CANONICAL_BUNDLED_SKILL_KEYS = new Set(RUDDER_BUNDLED_SKILL_SLUGS.map((slug) => `rudder/${slug}`));
18
- const COMMUNITY_PRESET_SKILLS = [
19
- {
20
- slug: "deep-research",
21
- source: "repo",
22
- },
23
- {
24
- slug: "software-product-advisor",
25
- source: "repo",
26
- },
27
- ];
28
- const COMMUNITY_PRESET_SKILL_SLUGS = COMMUNITY_PRESET_SKILLS.map((preset) => preset.slug);
29
- const BUNDLED_SELECTION_PREFIX = "bundled:";
30
- const ORGANIZATION_SELECTION_PREFIX = "org:";
31
- const AGENT_SELECTION_PREFIX = "agent:";
32
- const GLOBAL_SELECTION_PREFIX = "global:";
33
- const ADAPTER_SELECTION_PREFIX = "adapter:";
34
- const AGENT_SKILL_SOURCE_CLASS_ORDER = {
35
- bundled: 0,
36
- organization: 1,
37
- agent_home: 2,
38
- global: 3,
39
- adapter_home: 4,
40
- };
41
- const ADAPTER_SKILL_HOME_DEFINITIONS = {
42
- claude_local: {
43
- mode: "ephemeral",
44
- label: "Adapter skill",
45
- locationLabel: "~/.claude/skills",
46
- resolveRoot: (config) => path.join(resolveConfiguredHomeDir(config), ".claude", "skills"),
47
- },
48
- opencode_local: {
49
- mode: "ephemeral",
50
- label: "Adapter skill",
51
- locationLabel: "~/.claude/skills",
52
- resolveRoot: (config) => path.join(resolveConfiguredHomeDir(config), ".claude", "skills"),
53
- },
54
- codex_local: {
55
- mode: "persistent",
56
- label: "Adapter skill",
57
- locationLabel: "~/.codex/skills",
58
- resolveRoot: (config) => path.join(resolveConfiguredCodexHomeDir(config), "skills"),
59
- },
60
- cursor: {
61
- mode: "persistent",
62
- label: "Adapter skill",
63
- locationLabel: "~/.cursor/skills",
64
- resolveRoot: (config) => path.join(resolveConfiguredHomeDir(config), ".cursor", "skills"),
65
- },
66
- gemini_local: {
67
- mode: "persistent",
68
- label: "Adapter skill",
69
- locationLabel: "~/.gemini/skills",
70
- resolveRoot: (config) => path.join(resolveConfiguredHomeDir(config), ".gemini", "skills"),
71
- },
72
- pi_local: {
73
- mode: "persistent",
74
- label: "Adapter skill",
75
- locationLabel: "~/.pi/agent/skills",
76
- resolveRoot: (config) => path.join(resolveConfiguredHomeDir(config), ".pi", "agent", "skills"),
77
- },
78
- };
79
- const PROJECT_SCAN_DIRECTORY_ROOTS = [
80
- "skills",
81
- "skills/.curated",
82
- "skills/.experimental",
83
- "skills/.system",
84
- ".agents/skills",
85
- ".agent/skills",
86
- ".augment/skills",
87
- ".claude/skills",
88
- ".codebuddy/skills",
89
- ".commandcode/skills",
90
- ".continue/skills",
91
- ".cortex/skills",
92
- ".crush/skills",
93
- ".factory/skills",
94
- ".goose/skills",
95
- ".junie/skills",
96
- ".iflow/skills",
97
- ".kilocode/skills",
98
- ".kiro/skills",
99
- ".kode/skills",
100
- ".mcpjam/skills",
101
- ".vibe/skills",
102
- ".mux/skills",
103
- ".openhands/skills",
104
- ".pi/skills",
105
- ".qoder/skills",
106
- ".qwen/skills",
107
- ".roo/skills",
108
- ".trae/skills",
109
- ".windsurf/skills",
110
- ".zencoder/skills",
111
- ".neovate/skills",
112
- ".pochi/skills",
113
- ".adal/skills",
114
- ];
115
- const PROJECT_ROOT_SKILL_SUBDIRECTORIES = [
116
- "references",
117
- "scripts",
118
- "assets",
119
- ];
120
- function asString(value) {
121
- if (typeof value !== "string")
122
- return null;
123
- const trimmed = value.trim();
124
- return trimmed.length > 0 ? trimmed : null;
125
- }
126
- function normalizeSkillDescription(value) {
127
- const description = asString(value);
128
- if (!description)
129
- return null;
130
- return /^[>|][+-]?$/.test(description) ? null : description;
131
- }
132
- function isPlainRecord(value) {
133
- return typeof value === "object" && value !== null && !Array.isArray(value);
134
- }
135
- function resolveConfigEnvRecord(config) {
136
- return isPlainRecord(config.env) ? config.env : {};
137
- }
138
- function resolveConfiguredHomeDir(config) {
139
- const env = resolveConfigEnvRecord(config);
140
- const configuredHome = asString(env.HOME);
141
- return configuredHome ? path.resolve(configuredHome) : os.homedir();
142
- }
143
- function resolveConfiguredCodexHomeDir(config) {
144
- const env = resolveConfigEnvRecord(config);
145
- const configuredCodexHome = asString(env.CODEX_HOME);
146
- return configuredCodexHome
147
- ? path.resolve(configuredCodexHome)
148
- : path.join(resolveConfiguredHomeDir(config), ".codex");
149
- }
150
- function normalizePortablePath(input) {
151
- const parts = [];
152
- for (const segment of input.replace(/\\/g, "/").replace(/^\.\/+/, "").replace(/^\/+/, "").split("/")) {
153
- if (!segment || segment === ".")
154
- continue;
155
- if (segment === "..") {
156
- if (parts.length > 0)
157
- parts.pop();
158
- continue;
159
- }
160
- parts.push(segment);
161
- }
162
- return parts.join("/");
163
- }
164
- function normalizePackageFileMap(files) {
165
- const out = {};
166
- for (const [rawPath, content] of Object.entries(files)) {
167
- const nextPath = normalizePortablePath(rawPath);
168
- if (!nextPath)
169
- continue;
170
- out[nextPath] = content;
171
- }
172
- return out;
173
- }
174
- function normalizeSkillSlug(value) {
175
- return value ? normalizeAgentUrlKey(value) ?? null : null;
176
- }
177
- function normalizeSkillKey(value) {
178
- if (!value)
179
- return null;
180
- const segments = value
181
- .split("/")
182
- .map((segment) => normalizeSkillSlug(segment))
183
- .filter((segment) => Boolean(segment));
184
- return segments.length > 0 ? segments.join("/") : null;
185
- }
186
- function isBundledRudderSourceKind(value) {
187
- return value === "rudder_bundled" || value === "paperclip_bundled";
188
- }
189
- function isBundledRudderSkillKey(value) {
190
- return isCanonicalBundledRudderSkillKey(value);
191
- }
192
- function buildBundledSelectionKey(skillKey) {
193
- return `${BUNDLED_SELECTION_PREFIX}${skillKey}`;
194
- }
195
- function buildOrganizationSelectionKey(skillKey) {
196
- return `${ORGANIZATION_SELECTION_PREFIX}${skillKey}`;
197
- }
198
- function buildAgentSelectionKey(slug) {
199
- return `${AGENT_SELECTION_PREFIX}${slug}`;
200
- }
201
- function buildGlobalSelectionKey(slug) {
202
- return `${GLOBAL_SELECTION_PREFIX}${slug}`;
203
- }
204
- function buildAdapterSelectionKey(agentRuntimeType, slug) {
205
- return `${ADAPTER_SELECTION_PREFIX}${agentRuntimeType}:${slug}`;
206
- }
207
- function parseSelectionKey(selectionKey) {
208
- const trimmed = selectionKey.trim();
209
- if (!trimmed) {
210
- return { sourceClass: null, orgKey: null, slug: null, agentRuntimeType: null };
211
- }
212
- if (trimmed.startsWith(BUNDLED_SELECTION_PREFIX)) {
213
- const orgKey = trimmed.slice(BUNDLED_SELECTION_PREFIX.length).trim();
214
- return {
215
- sourceClass: "bundled",
216
- orgKey: orgKey || null,
217
- slug: normalizeSkillSlug(orgKey.split("/").pop() ?? null),
218
- agentRuntimeType: null,
219
- };
220
- }
221
- if (trimmed.startsWith(ORGANIZATION_SELECTION_PREFIX)) {
222
- const orgKey = trimmed.slice(ORGANIZATION_SELECTION_PREFIX.length).trim();
223
- return {
224
- sourceClass: "organization",
225
- orgKey: orgKey || null,
226
- slug: normalizeSkillSlug(orgKey.split("/").pop() ?? null),
227
- agentRuntimeType: null,
228
- };
229
- }
230
- if (trimmed.startsWith(AGENT_SELECTION_PREFIX)) {
231
- const slug = normalizeSkillSlug(trimmed.slice(AGENT_SELECTION_PREFIX.length));
232
- return {
233
- sourceClass: "agent_home",
234
- orgKey: null,
235
- slug,
236
- agentRuntimeType: null,
237
- };
238
- }
239
- if (trimmed.startsWith(GLOBAL_SELECTION_PREFIX)) {
240
- const slug = normalizeSkillSlug(trimmed.slice(GLOBAL_SELECTION_PREFIX.length));
241
- return {
242
- sourceClass: "global",
243
- orgKey: null,
244
- slug,
245
- agentRuntimeType: null,
246
- };
247
- }
248
- if (trimmed.startsWith(ADAPTER_SELECTION_PREFIX)) {
249
- const payload = trimmed.slice(ADAPTER_SELECTION_PREFIX.length);
250
- const delimiter = payload.indexOf(":");
251
- if (delimiter <= 0) {
252
- return { sourceClass: "adapter_home", orgKey: null, slug: null, agentRuntimeType: null };
253
- }
254
- return {
255
- sourceClass: "adapter_home",
256
- orgKey: null,
257
- slug: normalizeSkillSlug(payload.slice(delimiter + 1)),
258
- agentRuntimeType: payload.slice(0, delimiter).trim() || null,
259
- };
260
- }
261
- return { sourceClass: null, orgKey: null, slug: null, agentRuntimeType: null };
262
- }
263
- function normalizeSelectionRef(reference, skills, orgId, agentRuntimeType) {
264
- const trimmed = reference.trim();
265
- if (!trimmed)
266
- return null;
267
- const parsedSelection = parseSelectionKey(trimmed);
268
- if (parsedSelection.sourceClass === "bundled") {
269
- return parsedSelection.orgKey ? buildBundledSelectionKey(parsedSelection.orgKey) : null;
270
- }
271
- if (parsedSelection.sourceClass === "organization") {
272
- return parsedSelection.orgKey ? buildOrganizationSelectionKey(parsedSelection.orgKey) : null;
273
- }
274
- if (parsedSelection.sourceClass === "agent_home") {
275
- return parsedSelection.slug ? buildAgentSelectionKey(parsedSelection.slug) : null;
276
- }
277
- if (parsedSelection.sourceClass === "global") {
278
- return parsedSelection.slug ? buildGlobalSelectionKey(parsedSelection.slug) : null;
279
- }
280
- if (parsedSelection.sourceClass === "adapter_home") {
281
- if (!parsedSelection.slug || !parsedSelection.agentRuntimeType)
282
- return null;
283
- return buildAdapterSelectionKey(parsedSelection.agentRuntimeType, parsedSelection.slug);
284
- }
285
- const orgMatch = resolveSkillReference(skills, trimmed, orgId);
286
- if (orgMatch.skill) {
287
- if (isBundledRudderSkillKey(orgMatch.skill.key)) {
288
- return buildBundledSelectionKey(orgMatch.skill.key);
289
- }
290
- return buildOrganizationSelectionKey(orgMatch.skill.key);
291
- }
292
- const bundledSlug = getBundledRudderSkillSlug(trimmed);
293
- if (bundledSlug) {
294
- const bundledKey = toBundledRudderSkillKey(bundledSlug);
295
- return bundledKey ? buildBundledSelectionKey(bundledKey) : null;
296
- }
297
- const normalizedSlug = normalizeSkillSlug(trimmed);
298
- if (!normalizedSlug)
299
- return null;
300
- return buildAdapterSelectionKey(agentRuntimeType, normalizedSlug);
301
- }
302
- async function discoverLocalSkillDirectories(root) {
303
- const discovered = new Set();
304
- for (const candidateRoot of [root, path.join(root, "skills")]) {
305
- const candidateStat = await statPath(candidateRoot);
306
- if (!candidateStat?.isDirectory())
307
- continue;
308
- const entries = await fs.readdir(candidateRoot, { withFileTypes: true }).catch(() => []);
309
- for (const entry of entries) {
310
- if (!entry.isDirectory())
311
- continue;
312
- const skillDir = path.resolve(candidateRoot, entry.name);
313
- if (!(await statPath(path.join(skillDir, "SKILL.md")))?.isFile())
314
- continue;
315
- discovered.add(skillDir);
316
- }
317
- }
318
- return Array.from(discovered).sort((left, right) => left.localeCompare(right));
319
- }
320
- async function readDiscoveredSkillEntries(orgId, root, selectionKeyForSlug, options) {
321
- const out = [];
322
- const seenSelectionKeys = new Set();
323
- for (const skillDir of await discoverLocalSkillDirectories(root)) {
324
- const slug = normalizeSkillSlug(path.basename(skillDir));
325
- if (!slug)
326
- continue;
327
- const selectionKey = selectionKeyForSlug(slug);
328
- if (seenSelectionKeys.has(selectionKey))
329
- continue;
330
- seenSelectionKeys.add(selectionKey);
331
- const metadata = await readSkillMetadataFromPath(skillDir).catch(() => ({ name: null, description: null }));
332
- out.push({
333
- key: slug,
334
- selectionKey,
335
- runtimeName: slug,
336
- description: metadata.description ?? null,
337
- desired: false,
338
- configurable: true,
339
- alwaysEnabled: false,
340
- managed: false,
341
- state: "external",
342
- sourceClass: options.sourceClass,
343
- origin: "user_installed",
344
- originLabel: options.originLabel,
345
- locationLabel: options.locationLabel,
346
- readOnly: false,
347
- sourcePath: skillDir,
348
- targetPath: null,
349
- workspaceEditPath: resolveWorkspaceEditPath(orgId, skillDir),
350
- detail: null,
351
- organizationSkillKey: null,
352
- runtimeSourcePath: skillDir,
353
- });
354
- }
355
- return out;
356
- }
357
- function buildDraftSkillMarkdown(input) {
358
- return (input.markdown?.trim().length
359
- ? input.markdown
360
- : [
361
- "---",
362
- `name: ${input.name}`,
363
- ...(input.description?.trim() ? [`description: ${input.description.trim()}`] : []),
364
- "---",
365
- "",
366
- `# ${input.name}`,
367
- "",
368
- input.description?.trim() ? input.description.trim() : "Describe what this skill does.",
369
- "",
370
- ].join("\n"));
371
- }
372
- function buildAgentPrivateSkillEntry(orgId, slug, skillDir, description) {
373
- return {
374
- key: slug,
375
- selectionKey: buildAgentSelectionKey(slug),
376
- runtimeName: slug,
377
- description,
378
- desired: false,
379
- configurable: true,
380
- alwaysEnabled: false,
381
- managed: false,
382
- state: "external",
383
- sourceClass: "agent_home",
384
- origin: "user_installed",
385
- originLabel: "Agent skill",
386
- locationLabel: "AGENT_HOME/skills",
387
- readOnly: false,
388
- sourcePath: skillDir,
389
- targetPath: null,
390
- workspaceEditPath: resolveWorkspaceEditPath(orgId, skillDir),
391
- detail: "Installed, not enabled. Future runs will not load it until enabled.",
392
- organizationSkillKey: null,
393
- runtimeSourcePath: skillDir,
394
- };
395
- }
396
- export function normalizeGitHubSkillDirectory(value, fallback) {
397
- const normalized = normalizePortablePath(value ?? "");
398
- if (!normalized)
399
- return normalizePortablePath(fallback);
400
- if (path.posix.basename(normalized).toLowerCase() === "skill.md") {
401
- return normalizePortablePath(path.posix.dirname(normalized));
402
- }
403
- return normalized;
404
- }
405
- export function listStaleBundledSkillIds(existingSkills, currentBundledKeys) {
406
- const currentKeysSet = new Set(currentBundledKeys.map((key) => {
407
- const bundledKey = toBundledRudderSkillKey(getBundledRudderSkillSlug(key));
408
- return bundledKey ?? key;
409
- }));
410
- return existingSkills
411
- .filter((skill) => {
412
- const sourceKind = skill.metadata?.sourceKind;
413
- if (sourceKind !== "rudder_bundled" && sourceKind !== "paperclip_bundled") {
414
- return false;
415
- }
416
- const canonicalKey = toBundledRudderSkillKey(getBundledRudderSkillSlug(skill.key)) ?? skill.key;
417
- return !currentKeysSet.has(canonicalKey);
418
- })
419
- .map((skill) => skill.id);
420
- }
421
- export function listStaleCommunityPresetSkillIds(existingSkills, currentCommunityPresetKeys) {
422
- const currentKeysSet = new Set(currentCommunityPresetKeys);
423
- return existingSkills
424
- .filter((skill) => skill.metadata?.sourceKind === "community_preset")
425
- .filter((skill) => !currentKeysSet.has(skill.key))
426
- .map((skill) => skill.id);
427
- }
428
- function hashSkillValue(value) {
429
- return createHash("sha256").update(value).digest("hex").slice(0, 10);
430
- }
431
- function uniqueSkillSlug(baseSlug, usedSlugs) {
432
- if (!usedSlugs.has(baseSlug))
433
- return baseSlug;
434
- let attempt = 2;
435
- let candidate = `${baseSlug}-${attempt}`;
436
- while (usedSlugs.has(candidate)) {
437
- attempt += 1;
438
- candidate = `${baseSlug}-${attempt}`;
439
- }
440
- return candidate;
441
- }
442
- function uniqueImportedSkillKey(orgId, baseSlug, usedKeys) {
443
- const initial = `organization/${orgId}/${baseSlug}`;
444
- if (!usedKeys.has(initial))
445
- return initial;
446
- let attempt = 2;
447
- let candidate = `organization/${orgId}/${baseSlug}-${attempt}`;
448
- while (usedKeys.has(candidate)) {
449
- attempt += 1;
450
- candidate = `organization/${orgId}/${baseSlug}-${attempt}`;
451
- }
452
- return candidate;
453
- }
454
- function buildSkillRuntimeName(key, slug) {
455
- if (getBundledRudderSkillSlug(key))
456
- return slug;
457
- return `${slug}--${hashSkillValue(key)}`;
458
- }
459
- function readCanonicalSkillKey(frontmatter, metadata) {
460
- const direct = normalizeSkillKey(asString(frontmatter.key)
461
- ?? asString(frontmatter.skillKey)
462
- ?? asString(metadata?.skillKey)
463
- ?? asString(metadata?.canonicalKey)
464
- ?? asString(metadata?.rudderSkillKey));
465
- if (direct)
466
- return direct;
467
- const rudder = isPlainRecord(metadata?.rudder) ? metadata?.rudder : null;
468
- return normalizeSkillKey(asString(rudder?.skillKey)
469
- ?? asString(rudder?.key));
470
- }
471
- function deriveCanonicalSkillKey(orgId, input) {
472
- const slug = normalizeSkillSlug(input.slug) ?? "skill";
473
- const metadata = isPlainRecord(input.metadata) ? input.metadata : null;
474
- const sourceKind = asString(metadata?.sourceKind);
475
- const explicitKey = readCanonicalSkillKey({}, metadata);
476
- if (explicitKey) {
477
- if (isBundledRudderSourceKind(sourceKind)) {
478
- return toBundledRudderSkillKey(getBundledRudderSkillSlug(explicitKey) ?? slug) ?? explicitKey;
479
- }
480
- return explicitKey;
481
- }
482
- if (isBundledRudderSourceKind(sourceKind)) {
483
- return toBundledRudderSkillKey(slug) ?? `rudder/${slug}`;
484
- }
485
- if (sourceKind === "community_preset") {
486
- return `organization/${orgId}/${slug}`;
487
- }
488
- const owner = normalizeSkillSlug(asString(metadata?.owner));
489
- const repo = normalizeSkillSlug(asString(metadata?.repo));
490
- if ((input.sourceType === "github" || input.sourceType === "skills_sh" || sourceKind === "github" || sourceKind === "skills_sh") && owner && repo) {
491
- return `${owner}/${repo}/${slug}`;
492
- }
493
- if (input.sourceType === "url" || sourceKind === "url") {
494
- const locator = asString(input.sourceLocator);
495
- if (locator) {
496
- try {
497
- const url = new URL(locator);
498
- const host = normalizeSkillSlug(url.host) ?? "url";
499
- return `url/${host}/${hashSkillValue(locator)}/${slug}`;
500
- }
501
- catch {
502
- return `url/unknown/${hashSkillValue(locator)}/${slug}`;
503
- }
504
- }
505
- }
506
- if (input.sourceType === "local_path") {
507
- if (sourceKind === "managed_local") {
508
- return `organization/${orgId}/${slug}`;
509
- }
510
- const locator = asString(input.sourceLocator);
511
- if (locator) {
512
- return `local/${hashSkillValue(path.resolve(locator))}/${slug}`;
513
- }
514
- }
515
- return `organization/${orgId}/${slug}`;
516
- }
517
- function classifyInventoryKind(relativePath) {
518
- const normalized = normalizePortablePath(relativePath).toLowerCase();
519
- if (normalized.endsWith("/skill.md") || normalized === "skill.md")
520
- return "skill";
521
- if (normalized.startsWith("references/"))
522
- return "reference";
523
- if (normalized.startsWith("scripts/"))
524
- return "script";
525
- if (normalized.startsWith("assets/"))
526
- return "asset";
527
- if (normalized.endsWith(".md"))
528
- return "markdown";
529
- const fileName = path.posix.basename(normalized);
530
- if (fileName.endsWith(".sh")
531
- || fileName.endsWith(".js")
532
- || fileName.endsWith(".mjs")
533
- || fileName.endsWith(".cjs")
534
- || fileName.endsWith(".ts")
535
- || fileName.endsWith(".py")
536
- || fileName.endsWith(".rb")
537
- || fileName.endsWith(".bash")) {
538
- return "script";
539
- }
540
- if (fileName.endsWith(".png")
541
- || fileName.endsWith(".jpg")
542
- || fileName.endsWith(".jpeg")
543
- || fileName.endsWith(".gif")
544
- || fileName.endsWith(".svg")
545
- || fileName.endsWith(".webp")
546
- || fileName.endsWith(".pdf")) {
547
- return "asset";
548
- }
549
- return "other";
550
- }
551
- function deriveTrustLevel(fileInventory) {
552
- if (fileInventory.some((entry) => entry.kind === "script"))
553
- return "scripts_executables";
554
- if (fileInventory.some((entry) => entry.kind === "asset" || entry.kind === "other"))
555
- return "assets";
556
- return "markdown_only";
557
- }
558
- function prepareYamlLines(raw) {
559
- return raw
560
- .split("\n")
561
- .map((line) => ({
562
- indent: line.match(/^ */)?.[0].length ?? 0,
563
- content: line.trim(),
564
- }))
565
- .filter((line) => line.content.length > 0 && !line.content.startsWith("#"));
566
- }
567
- function parseYamlScalar(rawValue) {
568
- const trimmed = rawValue.trim();
569
- if (trimmed === "")
570
- return "";
571
- if (trimmed === "null" || trimmed === "~")
572
- return null;
573
- if (trimmed === "true")
574
- return true;
575
- if (trimmed === "false")
576
- return false;
577
- if (trimmed === "[]")
578
- return [];
579
- if (trimmed === "{}")
580
- return {};
581
- if (/^-?\d+(\.\d+)?$/.test(trimmed))
582
- return Number(trimmed);
583
- if (trimmed.startsWith("\"") || trimmed.startsWith("[") || trimmed.startsWith("{")) {
584
- try {
585
- return JSON.parse(trimmed);
586
- }
587
- catch {
588
- return trimmed;
589
- }
590
- }
591
- return trimmed;
592
- }
593
- function parseYamlBlockScalar(lines, startIndex, indentLevel, style) {
594
- const parts = [];
595
- let index = startIndex;
596
- while (index < lines.length) {
597
- const line = lines[index];
598
- if (line.indent < indentLevel)
599
- break;
600
- parts.push(line.content);
601
- index += 1;
602
- }
603
- if (style === ">") {
604
- return { value: parts.join(" "), nextIndex: index };
605
- }
606
- return { value: parts.join("\n"), nextIndex: index };
607
- }
608
- function parseYamlBlock(lines, startIndex, indentLevel) {
609
- let index = startIndex;
610
- while (index < lines.length && lines[index].content.length === 0)
611
- index += 1;
612
- if (index >= lines.length || lines[index].indent < indentLevel) {
613
- return { value: {}, nextIndex: index };
614
- }
615
- const isArray = lines[index].indent === indentLevel && lines[index].content.startsWith("-");
616
- if (isArray) {
617
- const values = [];
618
- while (index < lines.length) {
619
- const line = lines[index];
620
- if (line.indent < indentLevel)
621
- break;
622
- if (line.indent !== indentLevel || !line.content.startsWith("-"))
623
- break;
624
- const remainder = line.content.slice(1).trim();
625
- index += 1;
626
- if (!remainder) {
627
- const nested = parseYamlBlock(lines, index, indentLevel + 2);
628
- values.push(nested.value);
629
- index = nested.nextIndex;
630
- continue;
631
- }
632
- const inlineObjectSeparator = remainder.indexOf(":");
633
- if (inlineObjectSeparator > 0 &&
634
- !remainder.startsWith("\"") &&
635
- !remainder.startsWith("{") &&
636
- !remainder.startsWith("[")) {
637
- const key = remainder.slice(0, inlineObjectSeparator).trim();
638
- const rawValue = remainder.slice(inlineObjectSeparator + 1).trim();
639
- const nextObject = {
640
- [key]: parseYamlScalar(rawValue),
641
- };
642
- if (index < lines.length && lines[index].indent > indentLevel) {
643
- const nested = parseYamlBlock(lines, index, indentLevel + 2);
644
- if (isPlainRecord(nested.value)) {
645
- Object.assign(nextObject, nested.value);
646
- }
647
- index = nested.nextIndex;
648
- }
649
- values.push(nextObject);
650
- continue;
651
- }
652
- values.push(parseYamlScalar(remainder));
653
- }
654
- return { value: values, nextIndex: index };
655
- }
656
- const record = {};
657
- while (index < lines.length) {
658
- const line = lines[index];
659
- if (line.indent < indentLevel)
660
- break;
661
- if (line.indent !== indentLevel) {
662
- index += 1;
663
- continue;
664
- }
665
- const separatorIndex = line.content.indexOf(":");
666
- if (separatorIndex <= 0) {
667
- index += 1;
668
- continue;
669
- }
670
- const key = line.content.slice(0, separatorIndex).trim();
671
- const remainder = line.content.slice(separatorIndex + 1).trim();
672
- index += 1;
673
- if (/^[>|][+-]?$/.test(remainder)) {
674
- const blockScalar = parseYamlBlockScalar(lines, index, indentLevel + 2, remainder.startsWith(">") ? ">" : "|");
675
- record[key] = blockScalar.value;
676
- index = blockScalar.nextIndex;
677
- continue;
678
- }
679
- if (!remainder) {
680
- const nested = parseYamlBlock(lines, index, indentLevel + 2);
681
- record[key] = nested.value;
682
- index = nested.nextIndex;
683
- continue;
684
- }
685
- record[key] = parseYamlScalar(remainder);
686
- }
687
- return { value: record, nextIndex: index };
688
- }
689
- function parseYamlFrontmatter(raw) {
690
- const prepared = prepareYamlLines(raw);
691
- if (prepared.length === 0)
692
- return {};
693
- const parsed = parseYamlBlock(prepared, 0, prepared[0].indent);
694
- return isPlainRecord(parsed.value) ? parsed.value : {};
695
- }
696
- function parseFrontmatterMarkdown(raw) {
697
- const normalized = raw.replace(/\r\n/g, "\n");
698
- if (!normalized.startsWith("---\n")) {
699
- return { frontmatter: {}, body: normalized.trim() };
700
- }
701
- const closing = normalized.indexOf("\n---\n", 4);
702
- if (closing < 0) {
703
- return { frontmatter: {}, body: normalized.trim() };
704
- }
705
- const frontmatterRaw = normalized.slice(4, closing).trim();
706
- const body = normalized.slice(closing + 5).trim();
707
- return {
708
- frontmatter: parseYamlFrontmatter(frontmatterRaw),
709
- body,
710
- };
711
- }
712
- async function fetchText(url) {
713
- const response = await fetch(url);
714
- if (!response.ok) {
715
- throw unprocessable(`Failed to fetch ${url}: ${response.status}`);
716
- }
717
- return response.text();
718
- }
719
- async function fetchJson(url) {
720
- const response = await fetch(url, {
721
- headers: {
722
- accept: "application/vnd.github+json",
723
- },
724
- });
725
- if (!response.ok) {
726
- throw unprocessable(`Failed to fetch ${url}: ${response.status}`);
727
- }
728
- return response.json();
729
- }
730
- async function resolveGitHubDefaultBranch(owner, repo) {
731
- const response = await fetchJson(`https://api.github.com/repos/${owner}/${repo}`);
732
- return asString(response.default_branch) ?? "main";
733
- }
734
- async function resolveGitHubCommitSha(owner, repo, ref) {
735
- const response = await fetchJson(`https://api.github.com/repos/${owner}/${repo}/commits/${encodeURIComponent(ref)}`);
736
- const sha = asString(response.sha);
737
- if (!sha) {
738
- throw unprocessable(`Failed to resolve GitHub ref ${ref}`);
739
- }
740
- return sha;
741
- }
742
- function parseGitHubSourceUrl(rawUrl) {
743
- const url = new URL(rawUrl);
744
- if (url.hostname !== "github.com") {
745
- throw unprocessable("GitHub source must use github.com URL");
746
- }
747
- const parts = url.pathname.split("/").filter(Boolean);
748
- if (parts.length < 2) {
749
- throw unprocessable("Invalid GitHub URL");
750
- }
751
- const owner = parts[0];
752
- const repo = parts[1].replace(/\.git$/i, "");
753
- let ref = "main";
754
- let basePath = "";
755
- let filePath = null;
756
- let explicitRef = false;
757
- if (parts[2] === "tree") {
758
- ref = parts[3] ?? "main";
759
- basePath = parts.slice(4).join("/");
760
- explicitRef = true;
761
- }
762
- else if (parts[2] === "blob") {
763
- ref = parts[3] ?? "main";
764
- filePath = parts.slice(4).join("/");
765
- basePath = filePath ? path.posix.dirname(filePath) : "";
766
- explicitRef = true;
767
- }
768
- return { owner, repo, ref, basePath, filePath, explicitRef };
769
- }
770
- async function resolveGitHubPinnedRef(parsed) {
771
- if (/^[0-9a-f]{40}$/i.test(parsed.ref.trim())) {
772
- return {
773
- pinnedRef: parsed.ref,
774
- trackingRef: parsed.explicitRef ? parsed.ref : null,
775
- };
776
- }
777
- const trackingRef = parsed.explicitRef
778
- ? parsed.ref
779
- : await resolveGitHubDefaultBranch(parsed.owner, parsed.repo);
780
- const pinnedRef = await resolveGitHubCommitSha(parsed.owner, parsed.repo, trackingRef);
781
- return { pinnedRef, trackingRef };
782
- }
783
- function resolveRawGitHubUrl(owner, repo, ref, filePath) {
784
- return `https://raw.githubusercontent.com/${owner}/${repo}/${ref}/${filePath.replace(/^\/+/, "")}`;
785
- }
786
- function extractCommandTokens(raw) {
787
- const matches = raw.match(/"[^"]*"|'[^']*'|\S+/g) ?? [];
788
- return matches.map((token) => token.replace(/^['"]|['"]$/g, ""));
789
- }
790
- export function parseSkillImportSourceInput(rawInput) {
791
- const trimmed = rawInput.trim();
792
- if (!trimmed) {
793
- throw unprocessable("Skill source is required.");
794
- }
795
- const warnings = [];
796
- let source = trimmed;
797
- let requestedSkillSlug = null;
798
- if (/^npx\s+skills\s+add\s+/i.test(trimmed)) {
799
- const tokens = extractCommandTokens(trimmed);
800
- const addIndex = tokens.findIndex((token, index) => token === "add"
801
- && index > 0
802
- && tokens[index - 1]?.toLowerCase() === "skills");
803
- if (addIndex >= 0) {
804
- source = tokens[addIndex + 1] ?? "";
805
- for (let index = addIndex + 2; index < tokens.length; index += 1) {
806
- const token = tokens[index];
807
- if (token === "--skill") {
808
- requestedSkillSlug = normalizeSkillSlug(tokens[index + 1] ?? null);
809
- index += 1;
810
- continue;
811
- }
812
- if (token.startsWith("--skill=")) {
813
- requestedSkillSlug = normalizeSkillSlug(token.slice("--skill=".length));
814
- }
815
- }
816
- }
817
- }
818
- const normalizedSource = source.trim();
819
- if (!normalizedSource) {
820
- throw unprocessable("Skill source is required.");
821
- }
822
- // Key-style imports (org/repo/skill) originate from the skills.sh registry
823
- if (!/^https?:\/\//i.test(normalizedSource) && /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/.test(normalizedSource)) {
824
- const [owner, repo, skillSlugRaw] = normalizedSource.split("/");
825
- return {
826
- resolvedSource: `https://github.com/${owner}/${repo}`,
827
- requestedSkillSlug: normalizeSkillSlug(skillSlugRaw),
828
- originalSkillsShUrl: `https://skills.sh/${owner}/${repo}/${skillSlugRaw}`,
829
- warnings,
830
- };
831
- }
832
- if (!/^https?:\/\//i.test(normalizedSource) && /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/.test(normalizedSource)) {
833
- return {
834
- resolvedSource: `https://github.com/${normalizedSource}`,
835
- requestedSkillSlug,
836
- originalSkillsShUrl: null,
837
- warnings,
838
- };
839
- }
840
- // Detect skills.sh URLs and resolve to GitHub: https://skills.sh/org/repo/skill → org/repo/skill key
841
- const skillsShMatch = normalizedSource.match(/^https?:\/\/(?:www\.)?skills\.sh\/([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+)(?:\/([A-Za-z0-9_.-]+))?(?:[?#].*)?$/i);
842
- if (skillsShMatch) {
843
- const [, owner, repo, skillSlugRaw] = skillsShMatch;
844
- return {
845
- resolvedSource: `https://github.com/${owner}/${repo}`,
846
- requestedSkillSlug: skillSlugRaw ? normalizeSkillSlug(skillSlugRaw) : requestedSkillSlug,
847
- originalSkillsShUrl: normalizedSource,
848
- warnings,
849
- };
850
- }
851
- return {
852
- resolvedSource: normalizedSource,
853
- requestedSkillSlug,
854
- originalSkillsShUrl: null,
855
- warnings,
856
- };
857
- }
858
- function resolveBundledSkillsRoot() {
859
- const moduleDir = path.dirname(fileURLToPath(import.meta.url));
860
- return [
861
- path.resolve(moduleDir, "../../../resources/bundled-skills"),
862
- path.resolve(process.cwd(), "server/resources/bundled-skills"),
863
- ];
864
- }
865
- async function readCommunityPresetFallbackImport(orgId, slug, skillKey, sourceUrl) {
866
- for (const skillsRoot of resolveCommunityPresetSkillsRoot()) {
867
- const stats = await fs.stat(skillsRoot).catch(() => null);
868
- if (!stats?.isDirectory())
869
- continue;
870
- const skillDir = path.join(skillsRoot, slug);
871
- const skillStats = await fs.stat(skillDir).catch(() => null);
872
- if (!skillStats?.isDirectory())
873
- continue;
874
- const imported = await readLocalSkillImportFromDirectory(orgId, skillDir, {
875
- metadata: {
876
- sourceKind: "community_preset",
877
- skillKey,
878
- },
879
- }).catch(() => null);
880
- if (!imported)
881
- continue;
882
- return {
883
- ...imported,
884
- key: skillKey,
885
- slug,
886
- sourceType: "github",
887
- sourceLocator: sourceUrl,
888
- sourceRef: imported.sourceRef ?? null,
889
- metadata: {
890
- ...(imported.metadata ?? {}),
891
- sourceKind: "community_preset",
892
- skillKey,
893
- },
894
- };
895
- }
896
- return null;
897
- }
898
- function resolveCommunityPresetSkillsRoot() {
899
- const moduleDir = path.dirname(fileURLToPath(import.meta.url));
900
- return [
901
- path.resolve(moduleDir, "../../../resources/community-skills"),
902
- path.resolve(process.cwd(), "server/resources/community-skills"),
903
- ];
904
- }
905
- function matchesRequestedSkill(relativeSkillPath, requestedSkillSlug) {
906
- if (!requestedSkillSlug)
907
- return true;
908
- const skillDir = path.posix.dirname(relativeSkillPath);
909
- return normalizeSkillSlug(path.posix.basename(skillDir)) === requestedSkillSlug;
910
- }
911
- function deriveImportedSkillSlug(frontmatter, fallback) {
912
- return normalizeSkillSlug(asString(frontmatter.slug))
913
- ?? normalizeSkillSlug(asString(frontmatter.name))
914
- ?? normalizeAgentUrlKey(fallback)
915
- ?? "skill";
916
- }
917
- function deriveImportedSkillSource(frontmatter, fallbackSlug) {
918
- const metadata = isPlainRecord(frontmatter.metadata) ? frontmatter.metadata : null;
919
- const canonicalKey = readCanonicalSkillKey(frontmatter, metadata);
920
- const rawSources = metadata && Array.isArray(metadata.sources) ? metadata.sources : [];
921
- const sourceEntry = rawSources.find((entry) => isPlainRecord(entry));
922
- const kind = asString(sourceEntry?.kind);
923
- if (kind === "github-dir" || kind === "github-file") {
924
- const repo = asString(sourceEntry?.repo);
925
- const repoPath = asString(sourceEntry?.path);
926
- const commit = asString(sourceEntry?.commit);
927
- const trackingRef = asString(sourceEntry?.trackingRef);
928
- const url = asString(sourceEntry?.url)
929
- ?? (repo
930
- ? `https://github.com/${repo}${repoPath ? `/tree/${trackingRef ?? commit ?? "main"}/${repoPath}` : ""}`
931
- : null);
932
- const [owner, repoName] = (repo ?? "").split("/");
933
- if (repo && owner && repoName) {
934
- return {
935
- sourceType: "github",
936
- sourceLocator: url,
937
- sourceRef: commit,
938
- metadata: {
939
- ...(canonicalKey ? { skillKey: canonicalKey } : {}),
940
- sourceKind: "github",
941
- owner,
942
- repo: repoName,
943
- ref: commit,
944
- trackingRef,
945
- repoSkillDir: repoPath ?? `skills/${fallbackSlug}`,
946
- },
947
- };
948
- }
949
- }
950
- if (kind === "url") {
951
- const url = asString(sourceEntry?.url) ?? asString(sourceEntry?.rawUrl);
952
- if (url) {
953
- return {
954
- sourceType: "url",
955
- sourceLocator: url,
956
- sourceRef: null,
957
- metadata: {
958
- ...(canonicalKey ? { skillKey: canonicalKey } : {}),
959
- sourceKind: "url",
960
- },
961
- };
962
- }
963
- }
964
- return {
965
- sourceType: "catalog",
966
- sourceLocator: null,
967
- sourceRef: null,
968
- metadata: {
969
- ...(canonicalKey ? { skillKey: canonicalKey } : {}),
970
- sourceKind: "catalog",
971
- },
972
- };
973
- }
974
- function readInlineSkillImports(orgId, files) {
975
- const normalizedFiles = normalizePackageFileMap(files);
976
- const skillPaths = Object.keys(normalizedFiles).filter((entry) => path.posix.basename(entry).toLowerCase() === "skill.md");
977
- const imports = [];
978
- for (const skillPath of skillPaths) {
979
- const dir = path.posix.dirname(skillPath);
980
- const skillDir = dir === "." ? "" : dir;
981
- const slugFallback = path.posix.basename(skillDir || path.posix.dirname(skillPath));
982
- const markdown = normalizedFiles[skillPath];
983
- const parsed = parseFrontmatterMarkdown(markdown);
984
- const slug = deriveImportedSkillSlug(parsed.frontmatter, slugFallback);
985
- const source = deriveImportedSkillSource(parsed.frontmatter, slug);
986
- const inventory = Object.keys(normalizedFiles)
987
- .filter((entry) => entry === skillPath || (skillDir ? entry.startsWith(`${skillDir}/`) : false))
988
- .map((entry) => {
989
- const relative = entry === skillPath ? "SKILL.md" : entry.slice(skillDir.length + 1);
990
- return {
991
- path: normalizePortablePath(relative),
992
- kind: classifyInventoryKind(relative),
993
- };
994
- })
995
- .sort((left, right) => left.path.localeCompare(right.path));
996
- imports.push({
997
- key: "",
998
- slug,
999
- name: asString(parsed.frontmatter.name) ?? slug,
1000
- description: normalizeSkillDescription(parsed.frontmatter.description),
1001
- markdown,
1002
- packageDir: skillDir,
1003
- sourceType: source.sourceType,
1004
- sourceLocator: source.sourceLocator,
1005
- sourceRef: source.sourceRef,
1006
- trustLevel: deriveTrustLevel(inventory),
1007
- compatibility: "compatible",
1008
- fileInventory: inventory,
1009
- metadata: source.metadata,
1010
- });
1011
- imports[imports.length - 1].key = deriveCanonicalSkillKey(orgId, imports[imports.length - 1]);
1012
- }
1013
- return imports;
1014
- }
1015
- async function walkLocalFiles(root, current, out) {
1016
- const entries = await fs.readdir(current, { withFileTypes: true });
1017
- for (const entry of entries) {
1018
- if (entry.name === ".git" || entry.name === "node_modules")
1019
- continue;
1020
- const absolutePath = path.join(current, entry.name);
1021
- if (entry.isDirectory()) {
1022
- await walkLocalFiles(root, absolutePath, out);
1023
- continue;
1024
- }
1025
- if (!entry.isFile())
1026
- continue;
1027
- out.push(normalizePortablePath(path.relative(root, absolutePath)));
1028
- }
1029
- }
1030
- async function statPath(targetPath) {
1031
- return fs.stat(targetPath).catch(() => null);
1032
- }
1033
- async function collectLocalSkillInventory(skillDir, mode = "full") {
1034
- const skillFilePath = path.join(skillDir, "SKILL.md");
1035
- const skillFileStat = await statPath(skillFilePath);
1036
- if (!skillFileStat?.isFile()) {
1037
- throw unprocessable(`No SKILL.md file was found in ${skillDir}.`);
1038
- }
1039
- const allFiles = new Set(["SKILL.md"]);
1040
- if (mode === "full") {
1041
- const discoveredFiles = [];
1042
- await walkLocalFiles(skillDir, skillDir, discoveredFiles);
1043
- for (const relativePath of discoveredFiles) {
1044
- allFiles.add(relativePath);
1045
- }
1046
- }
1047
- else {
1048
- for (const relativeDir of PROJECT_ROOT_SKILL_SUBDIRECTORIES) {
1049
- const absoluteDir = path.join(skillDir, relativeDir);
1050
- const dirStat = await statPath(absoluteDir);
1051
- if (!dirStat?.isDirectory())
1052
- continue;
1053
- const discoveredFiles = [];
1054
- await walkLocalFiles(skillDir, absoluteDir, discoveredFiles);
1055
- for (const relativePath of discoveredFiles) {
1056
- allFiles.add(relativePath);
1057
- }
1058
- }
1059
- }
1060
- return Array.from(allFiles)
1061
- .map((relativePath) => ({
1062
- path: normalizePortablePath(relativePath),
1063
- kind: classifyInventoryKind(relativePath),
1064
- }))
1065
- .sort((left, right) => left.path.localeCompare(right.path));
1066
- }
1067
- export async function readLocalSkillImportFromDirectory(orgId, skillDir, options) {
1068
- const resolvedSkillDir = path.resolve(skillDir);
1069
- const skillFilePath = path.join(resolvedSkillDir, "SKILL.md");
1070
- const markdown = await fs.readFile(skillFilePath, "utf8");
1071
- const parsed = parseFrontmatterMarkdown(markdown);
1072
- const slug = deriveImportedSkillSlug(parsed.frontmatter, path.basename(resolvedSkillDir));
1073
- const parsedMetadata = isPlainRecord(parsed.frontmatter.metadata) ? parsed.frontmatter.metadata : null;
1074
- const skillKey = readCanonicalSkillKey(parsed.frontmatter, parsedMetadata);
1075
- const metadata = {
1076
- ...(skillKey ? { skillKey } : {}),
1077
- ...(parsedMetadata ?? {}),
1078
- sourceKind: "local_path",
1079
- ...(options?.metadata ?? {}),
1080
- };
1081
- const inventory = await collectLocalSkillInventory(resolvedSkillDir, options?.inventoryMode ?? "full");
1082
- return {
1083
- key: deriveCanonicalSkillKey(orgId, {
1084
- slug,
1085
- sourceType: "local_path",
1086
- sourceLocator: resolvedSkillDir,
1087
- metadata,
1088
- }),
1089
- slug,
1090
- name: asString(parsed.frontmatter.name) ?? slug,
1091
- description: normalizeSkillDescription(parsed.frontmatter.description),
1092
- markdown,
1093
- packageDir: resolvedSkillDir,
1094
- sourceType: "local_path",
1095
- sourceLocator: resolvedSkillDir,
1096
- sourceRef: null,
1097
- trustLevel: deriveTrustLevel(inventory),
1098
- compatibility: "compatible",
1099
- fileInventory: inventory,
1100
- metadata,
1101
- };
1102
- }
1103
- export async function discoverProjectWorkspaceSkillDirectories(target) {
1104
- const discovered = new Map();
1105
- const rootSkillPath = path.join(target.workspaceCwd, "SKILL.md");
1106
- if ((await statPath(rootSkillPath))?.isFile()) {
1107
- discovered.set(path.resolve(target.workspaceCwd), "project_root");
1108
- }
1109
- for (const relativeRoot of PROJECT_SCAN_DIRECTORY_ROOTS) {
1110
- const absoluteRoot = path.join(target.workspaceCwd, relativeRoot);
1111
- const rootStat = await statPath(absoluteRoot);
1112
- if (!rootStat?.isDirectory())
1113
- continue;
1114
- const entries = await fs.readdir(absoluteRoot, { withFileTypes: true }).catch(() => []);
1115
- for (const entry of entries) {
1116
- if (!entry.isDirectory())
1117
- continue;
1118
- const absoluteSkillDir = path.resolve(absoluteRoot, entry.name);
1119
- if (!(await statPath(path.join(absoluteSkillDir, "SKILL.md")))?.isFile())
1120
- continue;
1121
- discovered.set(absoluteSkillDir, "full");
1122
- }
1123
- }
1124
- return Array.from(discovered.entries())
1125
- .map(([skillDir, inventoryMode]) => ({ skillDir, inventoryMode }))
1126
- .sort((left, right) => left.skillDir.localeCompare(right.skillDir));
1127
- }
1128
- async function readLocalSkillImports(orgId, sourcePath) {
1129
- const resolvedPath = path.resolve(sourcePath);
1130
- const stat = await fs.stat(resolvedPath).catch(() => null);
1131
- if (!stat) {
1132
- throw unprocessable(`Skill source path does not exist: ${sourcePath}`);
1133
- }
1134
- if (stat.isFile()) {
1135
- if (path.basename(resolvedPath).toLowerCase() !== "skill.md") {
1136
- throw unprocessable("Local skill imports must point at SKILL.md or a directory that contains skill folders.");
1137
- }
1138
- return [await readLocalSkillImportFromDirectory(orgId, path.dirname(resolvedPath))];
1139
- }
1140
- const discovered = new Set();
1141
- if ((await statPath(path.join(resolvedPath, "SKILL.md")))?.isFile()) {
1142
- discovered.add(resolvedPath);
1143
- }
1144
- for (const candidateRoot of [resolvedPath, path.join(resolvedPath, "skills")]) {
1145
- const candidateStat = await statPath(candidateRoot);
1146
- if (!candidateStat?.isDirectory())
1147
- continue;
1148
- const entries = await fs.readdir(candidateRoot, { withFileTypes: true }).catch(() => []);
1149
- for (const entry of entries) {
1150
- if (!entry.isDirectory())
1151
- continue;
1152
- const skillDir = path.join(candidateRoot, entry.name);
1153
- if ((await statPath(path.join(skillDir, "SKILL.md")))?.isFile()) {
1154
- discovered.add(path.resolve(skillDir));
1155
- }
1156
- }
1157
- }
1158
- if (discovered.size === 0) {
1159
- throw unprocessable("No SKILL.md files were found in the provided path.");
1160
- }
1161
- return Promise.all(Array.from(discovered)
1162
- .sort((left, right) => left.localeCompare(right))
1163
- .map((skillDir) => readLocalSkillImportFromDirectory(orgId, skillDir)));
1164
- }
1165
- async function readUrlSkillImports(orgId, sourceUrl, requestedSkillSlug = null) {
1166
- const url = sourceUrl.trim();
1167
- const warnings = [];
1168
- if (url.includes("github.com/")) {
1169
- const parsed = parseGitHubSourceUrl(url);
1170
- const { pinnedRef, trackingRef } = await resolveGitHubPinnedRef(parsed);
1171
- let ref = pinnedRef;
1172
- const tree = await fetchJson(`https://api.github.com/repos/${parsed.owner}/${parsed.repo}/git/trees/${ref}?recursive=1`).catch(() => {
1173
- throw unprocessable(`Failed to read GitHub tree for ${url}`);
1174
- });
1175
- const allPaths = (tree.tree ?? [])
1176
- .filter((entry) => entry.type === "blob")
1177
- .map((entry) => entry.path)
1178
- .filter((entry) => typeof entry === "string");
1179
- const basePrefix = parsed.basePath ? `${parsed.basePath.replace(/^\/+|\/+$/g, "")}/` : "";
1180
- const scopedPaths = basePrefix
1181
- ? allPaths.filter((entry) => entry.startsWith(basePrefix))
1182
- : allPaths;
1183
- const relativePaths = scopedPaths.map((entry) => basePrefix ? entry.slice(basePrefix.length) : entry);
1184
- const filteredPaths = parsed.filePath
1185
- ? relativePaths.filter((entry) => entry === path.posix.relative(parsed.basePath || ".", parsed.filePath))
1186
- : relativePaths;
1187
- const skillPaths = filteredPaths.filter((entry) => path.posix.basename(entry).toLowerCase() === "skill.md");
1188
- if (skillPaths.length === 0) {
1189
- throw unprocessable("No SKILL.md files were found in the provided GitHub source.");
1190
- }
1191
- const skills = [];
1192
- for (const relativeSkillPath of skillPaths) {
1193
- const repoSkillPath = basePrefix ? `${basePrefix}${relativeSkillPath}` : relativeSkillPath;
1194
- const markdown = await fetchText(resolveRawGitHubUrl(parsed.owner, parsed.repo, ref, repoSkillPath));
1195
- const parsedMarkdown = parseFrontmatterMarkdown(markdown);
1196
- const skillDir = path.posix.dirname(relativeSkillPath);
1197
- const slug = deriveImportedSkillSlug(parsedMarkdown.frontmatter, path.posix.basename(skillDir));
1198
- const skillKey = readCanonicalSkillKey(parsedMarkdown.frontmatter, isPlainRecord(parsedMarkdown.frontmatter.metadata) ? parsedMarkdown.frontmatter.metadata : null);
1199
- if (requestedSkillSlug && !matchesRequestedSkill(relativeSkillPath, requestedSkillSlug) && slug !== requestedSkillSlug) {
1200
- continue;
1201
- }
1202
- const metadata = {
1203
- ...(skillKey ? { skillKey } : {}),
1204
- sourceKind: "github",
1205
- owner: parsed.owner,
1206
- repo: parsed.repo,
1207
- ref: ref,
1208
- trackingRef,
1209
- repoSkillDir: normalizeGitHubSkillDirectory(basePrefix ? `${basePrefix}${skillDir}` : skillDir, slug),
1210
- };
1211
- const inventory = filteredPaths
1212
- .filter((entry) => entry === relativeSkillPath || entry.startsWith(`${skillDir}/`))
1213
- .map((entry) => ({
1214
- path: entry === relativeSkillPath ? "SKILL.md" : entry.slice(skillDir.length + 1),
1215
- kind: classifyInventoryKind(entry === relativeSkillPath ? "SKILL.md" : entry.slice(skillDir.length + 1)),
1216
- }))
1217
- .sort((left, right) => left.path.localeCompare(right.path));
1218
- skills.push({
1219
- key: deriveCanonicalSkillKey(orgId, {
1220
- slug,
1221
- sourceType: "github",
1222
- sourceLocator: sourceUrl,
1223
- metadata,
1224
- }),
1225
- slug,
1226
- name: asString(parsedMarkdown.frontmatter.name) ?? slug,
1227
- description: normalizeSkillDescription(parsedMarkdown.frontmatter.description),
1228
- markdown,
1229
- sourceType: "github",
1230
- sourceLocator: sourceUrl,
1231
- sourceRef: ref,
1232
- trustLevel: deriveTrustLevel(inventory),
1233
- compatibility: "compatible",
1234
- fileInventory: inventory,
1235
- metadata,
1236
- });
1237
- }
1238
- if (skills.length === 0) {
1239
- throw unprocessable(requestedSkillSlug
1240
- ? `Skill ${requestedSkillSlug} was not found in the provided GitHub source.`
1241
- : "No SKILL.md files were found in the provided GitHub source.");
1242
- }
1243
- return { skills, warnings };
1244
- }
1245
- if (url.startsWith("http://") || url.startsWith("https://")) {
1246
- const markdown = await fetchText(url);
1247
- const parsedMarkdown = parseFrontmatterMarkdown(markdown);
1248
- const urlObj = new URL(url);
1249
- const fileName = path.posix.basename(urlObj.pathname);
1250
- const slug = deriveImportedSkillSlug(parsedMarkdown.frontmatter, fileName.replace(/\.md$/i, ""));
1251
- const skillKey = readCanonicalSkillKey(parsedMarkdown.frontmatter, isPlainRecord(parsedMarkdown.frontmatter.metadata) ? parsedMarkdown.frontmatter.metadata : null);
1252
- const metadata = {
1253
- ...(skillKey ? { skillKey } : {}),
1254
- sourceKind: "url",
1255
- };
1256
- const inventory = [{ path: "SKILL.md", kind: "skill" }];
1257
- return {
1258
- skills: [{
1259
- key: deriveCanonicalSkillKey(orgId, {
1260
- slug,
1261
- sourceType: "url",
1262
- sourceLocator: url,
1263
- metadata,
1264
- }),
1265
- slug,
1266
- name: asString(parsedMarkdown.frontmatter.name) ?? slug,
1267
- description: normalizeSkillDescription(parsedMarkdown.frontmatter.description),
1268
- markdown,
1269
- sourceType: "url",
1270
- sourceLocator: url,
1271
- sourceRef: null,
1272
- trustLevel: deriveTrustLevel(inventory),
1273
- compatibility: "compatible",
1274
- fileInventory: inventory,
1275
- metadata,
1276
- }],
1277
- warnings,
1278
- };
1279
- }
1280
- throw unprocessable("Unsupported skill source. Use a local path or URL.");
1281
- }
1282
- function toCompanySkill(row) {
1283
- return {
1284
- ...row,
1285
- description: row.description ?? null,
1286
- sourceType: row.sourceType,
1287
- sourceLocator: row.sourceLocator ?? null,
1288
- sourceRef: row.sourceRef ?? null,
1289
- trustLevel: row.trustLevel,
1290
- compatibility: row.compatibility,
1291
- fileInventory: Array.isArray(row.fileInventory)
1292
- ? row.fileInventory.flatMap((entry) => {
1293
- if (!isPlainRecord(entry))
1294
- return [];
1295
- return [{
1296
- path: String(entry.path ?? ""),
1297
- kind: String(entry.kind ?? "other"),
1298
- }];
1299
- })
1300
- : [],
1301
- metadata: isPlainRecord(row.metadata) ? row.metadata : null,
1302
- };
1303
- }
1304
- function serializeFileInventory(fileInventory) {
1305
- return fileInventory.map((entry) => ({
1306
- path: entry.path,
1307
- kind: entry.kind,
1308
- }));
1309
- }
1310
- function getSkillMeta(skill) {
1311
- return isPlainRecord(skill.metadata) ? skill.metadata : {};
1312
- }
1313
- function resolveSkillReference(skills, reference, orgId) {
1314
- const trimmed = reference.trim();
1315
- if (!trimmed) {
1316
- return { skill: null, ambiguous: false };
1317
- }
1318
- const byId = skills.find((skill) => skill.id === trimmed);
1319
- if (byId) {
1320
- return { skill: byId, ambiguous: false };
1321
- }
1322
- return resolveOrganizationSkillReference(skills, trimmed, { orgId });
1323
- }
1324
- function resolveRequestedSkillKeysOrThrow(skills, requestedReferences, orgId) {
1325
- const missing = new Set();
1326
- const ambiguous = new Set();
1327
- const resolved = new Set();
1328
- for (const reference of requestedReferences) {
1329
- const trimmed = reference.trim();
1330
- if (!trimmed)
1331
- continue;
1332
- const match = resolveSkillReference(skills, trimmed, orgId);
1333
- if (match.skill) {
1334
- resolved.add(match.skill.key);
1335
- continue;
1336
- }
1337
- if (match.ambiguous) {
1338
- ambiguous.add(trimmed);
1339
- continue;
1340
- }
1341
- missing.add(trimmed);
1342
- }
1343
- if (ambiguous.size > 0 || missing.size > 0) {
1344
- const problems = [];
1345
- if (ambiguous.size > 0) {
1346
- problems.push(`ambiguous references: ${Array.from(ambiguous).sort().join(", ")}`);
1347
- }
1348
- if (missing.size > 0) {
1349
- problems.push(`unknown references: ${Array.from(missing).sort().join(", ")}`);
1350
- }
1351
- throw unprocessable(`Invalid organization skill selection (${problems.join("; ")}).`);
1352
- }
1353
- return Array.from(resolved);
1354
- }
1355
- function resolveDesiredSkillKeys(skills, config, orgId) {
1356
- const preference = readRudderSkillSyncPreference(config);
1357
- return Array.from(new Set(preference.desiredSkills
1358
- .map((reference) => {
1359
- const resolved = resolveSkillReference(skills, reference, orgId).skill?.key;
1360
- if (resolved)
1361
- return resolved;
1362
- const bundledKey = toBundledRudderSkillKey(getBundledRudderSkillSlug(reference));
1363
- return bundledKey ?? normalizeSkillKey(reference);
1364
- })
1365
- .filter((value) => Boolean(value))));
1366
- }
1367
- function getRequiredBundledSkillKeys(skills) {
1368
- const availableKeys = new Set(skills.map((skill) => skill.key));
1369
- return RUDDER_BUNDLED_SKILL_SLUGS
1370
- .map((slug) => `rudder/${slug}`)
1371
- .filter((key) => availableKeys.has(key));
1372
- }
1373
- function sortUniqueSkillKeys(skillKeys) {
1374
- return Array.from(new Set(skillKeys
1375
- .map((value) => value.trim())
1376
- .filter(Boolean))).sort((left, right) => left.localeCompare(right));
1377
- }
1378
- function sortUniqueSelectionRefs(selectionRefs) {
1379
- return Array.from(new Set(selectionRefs
1380
- .map((value) => value.trim())
1381
- .filter(Boolean))).sort((left, right) => left.localeCompare(right));
1382
- }
1383
- function arraysEqual(left, right) {
1384
- if (left === right)
1385
- return true;
1386
- if (left.length !== right.length)
1387
- return false;
1388
- return left.every((value, index) => value === right[index]);
1389
- }
1390
- function buildMissingSelectionEntry(selectionKey, agentRuntimeType) {
1391
- const parsed = parseSelectionKey(selectionKey);
1392
- const key = parsed.slug ?? parsed.orgKey ?? selectionKey;
1393
- const runtimeTypeMismatch = parsed.sourceClass === "adapter_home"
1394
- && parsed.agentRuntimeType
1395
- && parsed.agentRuntimeType !== agentRuntimeType;
1396
- const locationLabel = (() => {
1397
- if (parsed.sourceClass === "agent_home")
1398
- return "AGENT_HOME/skills";
1399
- if (parsed.sourceClass === "global")
1400
- return "~/.agents/skills";
1401
- if (parsed.sourceClass === "adapter_home" && parsed.agentRuntimeType) {
1402
- return ADAPTER_SKILL_HOME_DEFINITIONS[parsed.agentRuntimeType]?.locationLabel ?? null;
1403
- }
1404
- return null;
1405
- })();
1406
- const detail = runtimeTypeMismatch
1407
- ? `This adapter-specific skill was saved for ${parsed.agentRuntimeType} and is unavailable on ${agentRuntimeType}.`
1408
- : "Rudder cannot find this enabled skill in the current Rudder-owned catalog.";
1409
- return {
1410
- key,
1411
- selectionKey,
1412
- runtimeName: parsed.slug ?? key,
1413
- description: null,
1414
- desired: true,
1415
- configurable: parsed.sourceClass !== "bundled",
1416
- alwaysEnabled: parsed.sourceClass === "bundled",
1417
- managed: parsed.sourceClass === "bundled" || parsed.sourceClass === "organization",
1418
- state: "missing",
1419
- sourceClass: parsed.sourceClass ?? "adapter_home",
1420
- origin: "external_unknown",
1421
- originLabel: runtimeTypeMismatch ? "Unavailable for this runtime" : "Unavailable",
1422
- locationLabel,
1423
- readOnly: parsed.sourceClass === "bundled",
1424
- sourcePath: null,
1425
- targetPath: null,
1426
- detail,
1427
- organizationSkillKey: parsed.orgKey ?? null,
1428
- runtimeSourcePath: null,
1429
- };
1430
- }
1431
- function applyDesiredSelectionsToCatalog(entries, desiredSelectionRefs, agentRuntimeType) {
1432
- const desiredSet = new Set(desiredSelectionRefs);
1433
- const warnings = [];
1434
- const out = entries.map((entry) => {
1435
- const desired = entry.alwaysEnabled || desiredSet.has(entry.selectionKey);
1436
- const state = entry.alwaysEnabled
1437
- ? "configured"
1438
- : desired
1439
- ? "configured"
1440
- : entry.sourceClass === "agent_home" || entry.sourceClass === "global" || entry.sourceClass === "adapter_home"
1441
- ? "external"
1442
- : "available";
1443
- return {
1444
- ...entry,
1445
- desired,
1446
- state,
1447
- detail: desired
1448
- ? entry.alwaysEnabled
1449
- ? (entry.detail ?? "Always loaded by Rudder for every agent run.")
1450
- : "Enabled for this agent and loaded on the next run."
1451
- : (entry.detail ?? null),
1452
- };
1453
- });
1454
- const knownSelectionKeys = new Set(out.map((entry) => entry.selectionKey));
1455
- for (const selectionKey of desiredSelectionRefs) {
1456
- if (knownSelectionKeys.has(selectionKey))
1457
- continue;
1458
- warnings.push(`Enabled skill "${selectionKey}" is no longer available in the current skill catalog.`);
1459
- out.push(buildMissingSelectionEntry(selectionKey, agentRuntimeType));
1460
- }
1461
- out.sort((left, right) => {
1462
- const orderDelta = AGENT_SKILL_SOURCE_CLASS_ORDER[left.sourceClass] - AGENT_SKILL_SOURCE_CLASS_ORDER[right.sourceClass];
1463
- if (orderDelta !== 0)
1464
- return orderDelta;
1465
- return left.key.localeCompare(right.key) || left.selectionKey.localeCompare(right.selectionKey);
1466
- });
1467
- const conflictGroups = new Map();
1468
- for (const entry of out) {
1469
- if (!entry.desired || entry.alwaysEnabled)
1470
- continue;
1471
- const existing = conflictGroups.get(entry.key) ?? [];
1472
- existing.push(entry.selectionKey);
1473
- conflictGroups.set(entry.key, existing);
1474
- }
1475
- for (const [skillKey, selectionKeys] of conflictGroups.entries()) {
1476
- if (selectionKeys.length <= 1)
1477
- continue;
1478
- warnings.push(`Enabled skill collision for "${skillKey}": ${selectionKeys.join(", ")}`);
1479
- }
1480
- return {
1481
- desiredSkills: sortUniqueSelectionRefs(desiredSelectionRefs),
1482
- entries: out,
1483
- warnings,
1484
- };
1485
- }
1486
- function stripBundledRequiredSkillKeys(skillKeys) {
1487
- return sortUniqueSkillKeys(skillKeys).filter((skillKey) => !isBundledRudderSkillKey(skillKey));
1488
- }
1489
- function mergeRequiredBundledSkillKeys(skills, skillKeys) {
1490
- return sortUniqueSkillKeys([
1491
- ...stripBundledRequiredSkillKeys(skillKeys),
1492
- ...getRequiredBundledSkillKeys(skills),
1493
- ]);
1494
- }
1495
- function normalizeSkillDirectory(skill) {
1496
- if ((skill.sourceType !== "local_path" && skill.sourceType !== "catalog") || !skill.sourceLocator)
1497
- return null;
1498
- const resolved = path.resolve(skill.sourceLocator);
1499
- if (path.basename(resolved).toLowerCase() === "skill.md") {
1500
- return path.dirname(resolved);
1501
- }
1502
- return resolved;
1503
- }
1504
- function normalizeSourceLocatorDirectory(sourceLocator) {
1505
- if (!sourceLocator)
1506
- return null;
1507
- const resolved = path.resolve(sourceLocator);
1508
- return path.basename(resolved).toLowerCase() === "skill.md" ? path.dirname(resolved) : resolved;
1509
- }
1510
- export async function findMissingLocalSkillIds(skills) {
1511
- const missingIds = [];
1512
- for (const skill of skills) {
1513
- if (skill.sourceType !== "local_path")
1514
- continue;
1515
- const skillDir = normalizeSourceLocatorDirectory(skill.sourceLocator);
1516
- if (!skillDir) {
1517
- missingIds.push(skill.id);
1518
- continue;
1519
- }
1520
- const skillDirStat = await statPath(skillDir);
1521
- const skillFileStat = await statPath(path.join(skillDir, "SKILL.md"));
1522
- if (!skillDirStat?.isDirectory() || !skillFileStat?.isFile()) {
1523
- missingIds.push(skill.id);
1524
- }
1525
- }
1526
- return missingIds;
1527
- }
1528
- function resolveManagedSkillsRoot(orgId) {
1529
- return resolveOrganizationSkillsDir(orgId);
1530
- }
1531
- function resolveWorkspaceEditPath(orgId, sourcePath) {
1532
- if (!sourcePath)
1533
- return null;
1534
- const workspaceRoot = path.resolve(resolveOrganizationWorkspaceRoot(orgId));
1535
- const skillDir = path.resolve(sourcePath);
1536
- const entryFilePath = path.resolve(skillDir, "SKILL.md");
1537
- const relativePath = path.relative(workspaceRoot, entryFilePath);
1538
- if (relativePath.startsWith("..") || path.isAbsolute(relativePath)) {
1539
- return null;
1540
- }
1541
- return normalizePortablePath(relativePath);
1542
- }
1543
- function resolveLocalSkillFilePath(skill, relativePath) {
1544
- const normalized = normalizePortablePath(relativePath);
1545
- const skillDir = normalizeSkillDirectory(skill);
1546
- if (skillDir) {
1547
- return path.resolve(skillDir, normalized);
1548
- }
1549
- if (!skill.sourceLocator)
1550
- return null;
1551
- const fallbackRoot = path.resolve(skill.sourceLocator);
1552
- const directPath = path.resolve(fallbackRoot, normalized);
1553
- return directPath;
1554
- }
1555
- function inferLanguageFromPath(filePath) {
1556
- const fileName = path.posix.basename(filePath).toLowerCase();
1557
- if (fileName === "skill.md" || fileName.endsWith(".md"))
1558
- return "markdown";
1559
- if (fileName.endsWith(".ts"))
1560
- return "typescript";
1561
- if (fileName.endsWith(".tsx"))
1562
- return "tsx";
1563
- if (fileName.endsWith(".js"))
1564
- return "javascript";
1565
- if (fileName.endsWith(".jsx"))
1566
- return "jsx";
1567
- if (fileName.endsWith(".json"))
1568
- return "json";
1569
- if (fileName.endsWith(".yml") || fileName.endsWith(".yaml"))
1570
- return "yaml";
1571
- if (fileName.endsWith(".sh"))
1572
- return "bash";
1573
- if (fileName.endsWith(".py"))
1574
- return "python";
1575
- if (fileName.endsWith(".html"))
1576
- return "html";
1577
- if (fileName.endsWith(".css"))
1578
- return "css";
1579
- return null;
1580
- }
1581
- function isMarkdownPath(filePath) {
1582
- const fileName = path.posix.basename(filePath).toLowerCase();
1583
- return fileName === "skill.md" || fileName.endsWith(".md");
1584
- }
1585
- function deriveSkillSourceInfo(skill) {
1586
- const metadata = getSkillMeta(skill);
1587
- const localSkillDir = normalizeSkillDirectory(skill);
1588
- if (isBundledRudderSourceKind(asString(metadata.sourceKind))) {
1589
- return {
1590
- editable: false,
1591
- editableReason: "Bundled Rudder skills are read-only.",
1592
- sourceLabel: "Bundled by Rudder",
1593
- sourceBadge: "rudder",
1594
- sourcePath: null,
1595
- };
1596
- }
1597
- if (asString(metadata.sourceKind) === "community_preset") {
1598
- return {
1599
- editable: false,
1600
- editableReason: "Community preset skills are read-only.",
1601
- sourceLabel: "Community preset",
1602
- sourceBadge: "community",
1603
- sourcePath: null,
1604
- };
1605
- }
1606
- if (skill.sourceType === "skills_sh") {
1607
- const owner = asString(metadata.owner) ?? null;
1608
- const repo = asString(metadata.repo) ?? null;
1609
- return {
1610
- editable: false,
1611
- editableReason: "Skills.sh-managed skills are read-only.",
1612
- sourceLabel: skill.sourceLocator ?? (owner && repo ? `${owner}/${repo}` : null),
1613
- sourceBadge: "skills_sh",
1614
- sourcePath: null,
1615
- };
1616
- }
1617
- if (skill.sourceType === "github") {
1618
- const owner = asString(metadata.owner) ?? null;
1619
- const repo = asString(metadata.repo) ?? null;
1620
- return {
1621
- editable: false,
1622
- editableReason: "Remote GitHub skills are read-only. Fork or import locally to edit them.",
1623
- sourceLabel: owner && repo ? `${owner}/${repo}` : skill.sourceLocator,
1624
- sourceBadge: "github",
1625
- sourcePath: null,
1626
- };
1627
- }
1628
- if (skill.sourceType === "url") {
1629
- return {
1630
- editable: false,
1631
- editableReason: "URL-based skills are read-only. Save them locally to edit them.",
1632
- sourceLabel: skill.sourceLocator,
1633
- sourceBadge: "url",
1634
- sourcePath: null,
1635
- };
1636
- }
1637
- if (skill.sourceType === "local_path") {
1638
- const managedRoot = resolveManagedSkillsRoot(skill.orgId);
1639
- const projectName = asString(metadata.projectName);
1640
- const workspaceName = asString(metadata.workspaceName);
1641
- const isProjectScan = metadata.sourceKind === "project_scan";
1642
- if (localSkillDir && localSkillDir.startsWith(managedRoot)) {
1643
- return {
1644
- editable: true,
1645
- editableReason: null,
1646
- sourceLabel: "Rudder workspace",
1647
- sourceBadge: "rudder",
1648
- sourcePath: managedRoot,
1649
- };
1650
- }
1651
- return {
1652
- editable: true,
1653
- editableReason: null,
1654
- sourceLabel: isProjectScan
1655
- ? [projectName, workspaceName].filter((value) => Boolean(value)).join(" / ")
1656
- || skill.sourceLocator
1657
- : skill.sourceLocator,
1658
- sourceBadge: "local",
1659
- sourcePath: null,
1660
- };
1661
- }
1662
- return {
1663
- editable: false,
1664
- editableReason: "This skill source is read-only.",
1665
- sourceLabel: skill.sourceLocator,
1666
- sourceBadge: "catalog",
1667
- sourcePath: null,
1668
- };
1669
- }
1670
- function enrichSkill(skill, attachedAgentCount, usedByAgents = []) {
1671
- const source = deriveSkillSourceInfo(skill);
1672
- return {
1673
- ...skill,
1674
- attachedAgentCount,
1675
- usedByAgents,
1676
- ...source,
1677
- workspaceEditPath: resolveWorkspaceEditPath(skill.orgId, normalizeSkillDirectory(skill)),
1678
- };
1679
- }
1680
- function toCompanySkillListItem(skill, attachedAgentCount) {
1681
- const source = deriveSkillSourceInfo(skill);
1682
- return {
1683
- id: skill.id,
1684
- orgId: skill.orgId,
1685
- key: skill.key,
1686
- slug: skill.slug,
1687
- name: skill.name,
1688
- description: skill.description,
1689
- sourceType: skill.sourceType,
1690
- sourceLocator: skill.sourceLocator,
1691
- sourceRef: skill.sourceRef,
1692
- trustLevel: skill.trustLevel,
1693
- compatibility: skill.compatibility,
1694
- fileInventory: skill.fileInventory,
1695
- createdAt: skill.createdAt,
1696
- updatedAt: skill.updatedAt,
1697
- attachedAgentCount,
1698
- editable: source.editable,
1699
- editableReason: source.editableReason,
1700
- sourceLabel: source.sourceLabel,
1701
- sourceBadge: source.sourceBadge,
1702
- sourcePath: source.sourcePath,
1703
- workspaceEditPath: resolveWorkspaceEditPath(skill.orgId, normalizeSkillDirectory(skill)),
1704
- };
1705
- }
1706
- function compareOrganizationSkillListItems(left, right) {
1707
- const leftBundledSlug = getBundledRudderSkillSlug(left.key);
1708
- const rightBundledSlug = getBundledRudderSkillSlug(right.key);
1709
- if (leftBundledSlug && rightBundledSlug) {
1710
- const leftIndex = RUDDER_BUNDLED_SKILL_SLUGS.findIndex((slug) => slug === leftBundledSlug);
1711
- const rightIndex = RUDDER_BUNDLED_SKILL_SLUGS.findIndex((slug) => slug === rightBundledSlug);
1712
- if (leftIndex !== rightIndex)
1713
- return leftIndex - rightIndex;
1714
- }
1715
- else if (leftBundledSlug) {
1716
- return -1;
1717
- }
1718
- else if (rightBundledSlug) {
1719
- return 1;
1720
- }
1721
- const byName = left.name.localeCompare(right.name, undefined, { sensitivity: "base" });
1722
- if (byName !== 0)
1723
- return byName;
1724
- return left.key.localeCompare(right.key, undefined, { sensitivity: "base" });
1725
- }
12
+ import { ADAPTER_SKILL_HOME_DEFINITIONS, CANONICAL_BUNDLED_SKILL_KEYS, COMMUNITY_PRESET_SKILLS, COMMUNITY_PRESET_SKILL_SLUGS, applyDesiredSelectionsToCatalog, arraysEqual, asString, buildAdapterSelectionKey, buildAgentPrivateSkillEntry, buildAgentSelectionKey, buildBundledSelectionKey, buildDraftSkillMarkdown, buildGlobalSelectionKey, buildOrganizationSelectionKey, buildSkillRuntimeName, compareOrganizationSkillListItems, deriveCanonicalSkillKey, deriveSkillSourceInfo, enrichSkill, findMissingLocalSkillIds, getRequiredBundledSkillKeys, getSkillMeta, inferLanguageFromPath, isBundledRudderSkillKey, isBundledRudderSourceKind, isMarkdownPath, isPlainRecord, listStaleBundledSkillIds, listStaleCommunityPresetSkillIds, normalizeGitHubSkillDirectory, normalizePackageFileMap, normalizePortablePath, normalizeSelectionRef, normalizeSkillDescription, normalizeSkillDirectory, normalizeSkillSlug, parseSelectionKey, readDiscoveredSkillEntries, resolveConfiguredHomeDir, resolveLocalSkillFilePath, resolveManagedSkillsRoot, resolveRequestedSkillKeysOrThrow, resolveWorkspaceEditPath, serializeFileInventory, skillInventoryRefreshPromises, sortUniqueSelectionRefs, statPath, toCompanySkill, toCompanySkillListItem, uniqueImportedSkillKey, uniqueSkillSlug, } from "./organization-skills.catalog.js";
13
+ import { fetchText, parseFrontmatterMarkdown, parseSkillImportSourceInput, readCommunityPresetFallbackImport, readInlineSkillImports, readLocalSkillImportFromDirectory, readLocalSkillImports, readUrlSkillImports, resolveBundledSkillsRoot, resolveCommunityPresetSkillsRoot, resolveGitHubCommitSha, resolveRawGitHubUrl, } from "./organization-skills.sources.js";
14
+ import { createOrganizationSkillScanHandlers } from "./organization-skills.scans.js";
1726
15
  export function organizationSkillService(db) {
1727
16
  const agents = agentService(db);
1728
17
  const enabledSkills = agentEnabledSkillsService(db);
1729
18
  const projects = projectService(db);
19
+ const { scanProjectWorkspaces, scanLocalSkillRoots } = createOrganizationSkillScanHandlers({
20
+ ensureSkillInventoryCurrent,
21
+ listFull,
22
+ projects,
23
+ upsertImportedSkills,
24
+ });
1730
25
  async function getAgentWorkspaceRow(orgId, agentId) {
1731
26
  const row = await db
1732
27
  .select({
@@ -2564,294 +859,6 @@ export function organizationSkillService(db) {
2564
859
  const imported = await upsertImportedSkills(orgId, [matching]);
2565
860
  return imported[0] ?? null;
2566
861
  }
2567
- async function scanProjectWorkspaces(orgId, input = {}) {
2568
- await ensureSkillInventoryCurrent(orgId);
2569
- const projectRows = input.projectIds?.length
2570
- ? await projects.listByIds(orgId, input.projectIds)
2571
- : await projects.list(orgId);
2572
- const workspaceFilter = new Set(input.workspaceIds ?? []);
2573
- const skipped = [];
2574
- const conflicts = [];
2575
- const warnings = [];
2576
- const imported = [];
2577
- const updated = [];
2578
- const availableSkills = await listFull(orgId);
2579
- const acceptedSkills = [...availableSkills];
2580
- const acceptedByKey = new Map(acceptedSkills.map((skill) => [skill.key, skill]));
2581
- const scanTargets = [];
2582
- const scannedProjectIds = new Set();
2583
- let discovered = 0;
2584
- const trackWarning = (message) => {
2585
- warnings.push(message);
2586
- return message;
2587
- };
2588
- const upsertAcceptedSkill = (skill) => {
2589
- const nextIndex = acceptedSkills.findIndex((entry) => entry.id === skill.id || entry.key === skill.key);
2590
- if (nextIndex >= 0)
2591
- acceptedSkills[nextIndex] = skill;
2592
- else
2593
- acceptedSkills.push(skill);
2594
- acceptedByKey.set(skill.key, skill);
2595
- };
2596
- for (const project of projectRows) {
2597
- for (const workspace of project.workspaces) {
2598
- if (workspaceFilter.size > 0 && !workspaceFilter.has(workspace.id))
2599
- continue;
2600
- const workspaceCwd = asString(workspace.cwd);
2601
- if (!workspaceCwd) {
2602
- skipped.push({
2603
- projectId: project.id,
2604
- projectName: project.name,
2605
- workspaceId: workspace.id,
2606
- workspaceName: workspace.name,
2607
- path: null,
2608
- reason: trackWarning(`Skipped ${project.name} / ${workspace.name}: no local workspace path is configured.`),
2609
- });
2610
- continue;
2611
- }
2612
- const workspaceStat = await statPath(workspaceCwd);
2613
- if (!workspaceStat?.isDirectory()) {
2614
- skipped.push({
2615
- projectId: project.id,
2616
- projectName: project.name,
2617
- workspaceId: workspace.id,
2618
- workspaceName: workspace.name,
2619
- path: workspaceCwd,
2620
- reason: trackWarning(`Skipped ${project.name} / ${workspace.name}: local workspace path is not available at ${workspaceCwd}.`),
2621
- });
2622
- continue;
2623
- }
2624
- scanTargets.push({
2625
- projectId: project.id,
2626
- projectName: project.name,
2627
- workspaceId: workspace.id,
2628
- workspaceName: workspace.name,
2629
- workspaceCwd,
2630
- });
2631
- }
2632
- }
2633
- for (const target of scanTargets) {
2634
- scannedProjectIds.add(target.projectId);
2635
- const directories = await discoverProjectWorkspaceSkillDirectories(target);
2636
- for (const directory of directories) {
2637
- discovered += 1;
2638
- let nextSkill;
2639
- try {
2640
- nextSkill = await readLocalSkillImportFromDirectory(orgId, directory.skillDir, {
2641
- inventoryMode: directory.inventoryMode,
2642
- metadata: {
2643
- sourceKind: "project_scan",
2644
- projectId: target.projectId,
2645
- projectName: target.projectName,
2646
- workspaceId: target.workspaceId,
2647
- workspaceName: target.workspaceName,
2648
- workspaceCwd: target.workspaceCwd,
2649
- },
2650
- });
2651
- }
2652
- catch (error) {
2653
- const message = error instanceof Error ? error.message : String(error);
2654
- skipped.push({
2655
- projectId: target.projectId,
2656
- projectName: target.projectName,
2657
- workspaceId: target.workspaceId,
2658
- workspaceName: target.workspaceName,
2659
- path: directory.skillDir,
2660
- reason: trackWarning(`Skipped ${directory.skillDir}: ${message}`),
2661
- });
2662
- continue;
2663
- }
2664
- const normalizedSourceDir = normalizeSourceLocatorDirectory(nextSkill.sourceLocator);
2665
- const existingByKey = acceptedByKey.get(nextSkill.key) ?? null;
2666
- if (existingByKey) {
2667
- const existingSourceDir = normalizeSkillDirectory(existingByKey);
2668
- if (existingByKey.sourceType !== "local_path"
2669
- || !existingSourceDir
2670
- || !normalizedSourceDir
2671
- || existingSourceDir !== normalizedSourceDir) {
2672
- conflicts.push({
2673
- slug: nextSkill.slug,
2674
- key: nextSkill.key,
2675
- projectId: target.projectId,
2676
- projectName: target.projectName,
2677
- workspaceId: target.workspaceId,
2678
- workspaceName: target.workspaceName,
2679
- path: directory.skillDir,
2680
- existingSkillId: existingByKey.id,
2681
- existingSkillKey: existingByKey.key,
2682
- existingSourceLocator: existingByKey.sourceLocator,
2683
- reason: `Skill key ${nextSkill.key} already points at ${existingByKey.sourceLocator ?? "another source"}.`,
2684
- });
2685
- continue;
2686
- }
2687
- const persisted = (await upsertImportedSkills(orgId, [nextSkill]))[0];
2688
- if (!persisted)
2689
- continue;
2690
- updated.push(persisted);
2691
- upsertAcceptedSkill(persisted);
2692
- continue;
2693
- }
2694
- const slugConflict = acceptedSkills.find((skill) => {
2695
- if (skill.slug !== nextSkill.slug)
2696
- return false;
2697
- return normalizeSkillDirectory(skill) !== normalizedSourceDir;
2698
- });
2699
- if (slugConflict) {
2700
- conflicts.push({
2701
- slug: nextSkill.slug,
2702
- key: nextSkill.key,
2703
- projectId: target.projectId,
2704
- projectName: target.projectName,
2705
- workspaceId: target.workspaceId,
2706
- workspaceName: target.workspaceName,
2707
- path: directory.skillDir,
2708
- existingSkillId: slugConflict.id,
2709
- existingSkillKey: slugConflict.key,
2710
- existingSourceLocator: slugConflict.sourceLocator,
2711
- reason: `Slug ${nextSkill.slug} is already in use by ${slugConflict.sourceLocator ?? slugConflict.key}.`,
2712
- });
2713
- continue;
2714
- }
2715
- const persisted = (await upsertImportedSkills(orgId, [nextSkill]))[0];
2716
- if (!persisted)
2717
- continue;
2718
- imported.push(persisted);
2719
- upsertAcceptedSkill(persisted);
2720
- }
2721
- }
2722
- return {
2723
- scannedProjects: scannedProjectIds.size,
2724
- scannedWorkspaces: scanTargets.length,
2725
- discovered,
2726
- imported,
2727
- updated,
2728
- skipped,
2729
- conflicts,
2730
- warnings,
2731
- };
2732
- }
2733
- async function scanLocalSkillRoots(orgId, input = {}) {
2734
- await ensureSkillInventoryCurrent(orgId);
2735
- const requestedRoots = input.roots?.length
2736
- ? input.roots
2737
- : [path.join(os.homedir(), ".agents")];
2738
- const roots = Array.from(new Set(requestedRoots
2739
- .map((root) => root.trim())
2740
- .filter(Boolean)
2741
- .map((root) => path.resolve(root))));
2742
- const skipped = [];
2743
- const conflicts = [];
2744
- const warnings = [];
2745
- const imported = [];
2746
- const updated = [];
2747
- const availableSkills = await listFull(orgId);
2748
- const acceptedSkills = [...availableSkills];
2749
- const acceptedByKey = new Map(acceptedSkills.map((skill) => [skill.key, skill]));
2750
- let discovered = 0;
2751
- const trackWarning = (message) => {
2752
- warnings.push(message);
2753
- return message;
2754
- };
2755
- const upsertAcceptedSkill = (skill) => {
2756
- const nextIndex = acceptedSkills.findIndex((entry) => entry.id === skill.id || entry.key === skill.key);
2757
- if (nextIndex >= 0)
2758
- acceptedSkills[nextIndex] = skill;
2759
- else
2760
- acceptedSkills.push(skill);
2761
- acceptedByKey.set(skill.key, skill);
2762
- };
2763
- for (const root of roots) {
2764
- const rootStat = await statPath(root);
2765
- if (!rootStat?.isDirectory()) {
2766
- skipped.push({
2767
- root,
2768
- path: null,
2769
- reason: trackWarning(`Skipped ${root}: local skill root is not available.`),
2770
- });
2771
- continue;
2772
- }
2773
- let discoveredSkills;
2774
- try {
2775
- discoveredSkills = await readLocalSkillImports(orgId, root);
2776
- }
2777
- catch (error) {
2778
- const message = error instanceof Error ? error.message : String(error);
2779
- skipped.push({
2780
- root,
2781
- path: root,
2782
- reason: trackWarning(`Skipped ${root}: ${message}`),
2783
- });
2784
- continue;
2785
- }
2786
- discovered += discoveredSkills.length;
2787
- for (const nextSkill of discoveredSkills) {
2788
- nextSkill.metadata = {
2789
- ...(nextSkill.metadata ?? {}),
2790
- sourceKind: "local_scan",
2791
- sourceRoot: root,
2792
- };
2793
- const normalizedSourceDir = normalizeSourceLocatorDirectory(nextSkill.sourceLocator);
2794
- const existingByKey = acceptedByKey.get(nextSkill.key) ?? null;
2795
- if (existingByKey) {
2796
- const existingSourceDir = normalizeSkillDirectory(existingByKey);
2797
- if (existingByKey.sourceType !== "local_path"
2798
- || !existingSourceDir
2799
- || !normalizedSourceDir
2800
- || existingSourceDir !== normalizedSourceDir) {
2801
- conflicts.push({
2802
- root,
2803
- slug: nextSkill.slug,
2804
- key: nextSkill.key,
2805
- path: nextSkill.sourceLocator ?? root,
2806
- existingSkillId: existingByKey.id,
2807
- existingSkillKey: existingByKey.key,
2808
- existingSourceLocator: existingByKey.sourceLocator,
2809
- reason: `Skill key ${nextSkill.key} already points at ${existingByKey.sourceLocator ?? "another source"}.`,
2810
- });
2811
- continue;
2812
- }
2813
- const persisted = (await upsertImportedSkills(orgId, [nextSkill]))[0];
2814
- if (!persisted)
2815
- continue;
2816
- updated.push(persisted);
2817
- upsertAcceptedSkill(persisted);
2818
- continue;
2819
- }
2820
- const slugConflict = acceptedSkills.find((skill) => {
2821
- if (skill.slug !== nextSkill.slug)
2822
- return false;
2823
- return normalizeSkillDirectory(skill) !== normalizedSourceDir;
2824
- });
2825
- if (slugConflict) {
2826
- conflicts.push({
2827
- root,
2828
- slug: nextSkill.slug,
2829
- key: nextSkill.key,
2830
- path: nextSkill.sourceLocator ?? root,
2831
- existingSkillId: slugConflict.id,
2832
- existingSkillKey: slugConflict.key,
2833
- existingSourceLocator: slugConflict.sourceLocator,
2834
- reason: `Slug ${nextSkill.slug} is already in use by ${slugConflict.sourceLocator ?? slugConflict.key}.`,
2835
- });
2836
- continue;
2837
- }
2838
- const persisted = (await upsertImportedSkills(orgId, [nextSkill]))[0];
2839
- if (!persisted)
2840
- continue;
2841
- imported.push(persisted);
2842
- upsertAcceptedSkill(persisted);
2843
- }
2844
- }
2845
- return {
2846
- scannedRoots: roots.length,
2847
- discovered,
2848
- imported,
2849
- updated,
2850
- skipped,
2851
- conflicts,
2852
- warnings,
2853
- };
2854
- }
2855
862
  async function materializeCatalogSkillFiles(orgId, skill, normalizedFiles) {
2856
863
  const packageDir = skill.packageDir ? normalizePortablePath(skill.packageDir) : null;
2857
864
  if (!packageDir)
@@ -3092,7 +1099,6 @@ export function organizationSkillService(db) {
3092
1099
  ? `Skill ${parsed.requestedSkillSlug} was not found in the provided source.`
3093
1100
  : "No skills were found in the provided source.");
3094
1101
  }
3095
- // Override sourceType/sourceLocator for skills imported via skills.sh
3096
1102
  if (parsed.originalSkillsShUrl) {
3097
1103
  for (const skill of filteredSkills) {
3098
1104
  skill.sourceType = "skills_sh";
@@ -3115,13 +1121,10 @@ export function organizationSkillService(db) {
3115
1121
  if (!row)
3116
1122
  return null;
3117
1123
  const skill = toCompanySkill(row);
3118
- // Remove from any agent enabled skills that reference this skill
3119
1124
  await enabledSkills.removeSkillKeys(orgId, [skill.key]);
3120
- // Delete DB row
3121
1125
  await db
3122
1126
  .delete(organizationSkills)
3123
1127
  .where(eq(organizationSkills.id, skillId));
3124
- // Clean up materialized runtime files
3125
1128
  await fs.rm(resolveRuntimeSkillMaterializedPath(orgId, skill), { recursive: true, force: true });
3126
1129
  return skill;
3127
1130
  }