@rudderhq/server 0.1.0-canary.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (902) hide show
  1. package/LICENSE +14 -0
  2. package/dist/agent-auth-jwt.d.ts +14 -0
  3. package/dist/agent-auth-jwt.d.ts.map +1 -0
  4. package/dist/agent-auth-jwt.js +119 -0
  5. package/dist/agent-auth-jwt.js.map +1 -0
  6. package/dist/agent-runtimes/codex-models.d.ts +4 -0
  7. package/dist/agent-runtimes/codex-models.d.ts.map +1 -0
  8. package/dist/agent-runtimes/codex-models.js +98 -0
  9. package/dist/agent-runtimes/codex-models.js.map +1 -0
  10. package/dist/agent-runtimes/cursor-models.d.ts +13 -0
  11. package/dist/agent-runtimes/cursor-models.d.ts.map +1 -0
  12. package/dist/agent-runtimes/cursor-models.js +148 -0
  13. package/dist/agent-runtimes/cursor-models.js.map +1 -0
  14. package/dist/agent-runtimes/http/execute.d.ts +3 -0
  15. package/dist/agent-runtimes/http/execute.d.ts.map +1 -0
  16. package/dist/agent-runtimes/http/execute.js +39 -0
  17. package/dist/agent-runtimes/http/execute.js.map +1 -0
  18. package/dist/agent-runtimes/http/index.d.ts +3 -0
  19. package/dist/agent-runtimes/http/index.d.ts.map +1 -0
  20. package/dist/agent-runtimes/http/index.js +20 -0
  21. package/dist/agent-runtimes/http/index.js.map +1 -0
  22. package/dist/agent-runtimes/http/test.d.ts +3 -0
  23. package/dist/agent-runtimes/http/test.d.ts.map +1 -0
  24. package/dist/agent-runtimes/http/test.js +106 -0
  25. package/dist/agent-runtimes/http/test.js.map +1 -0
  26. package/dist/agent-runtimes/index.d.ts +4 -0
  27. package/dist/agent-runtimes/index.d.ts.map +1 -0
  28. package/dist/agent-runtimes/index.js +3 -0
  29. package/dist/agent-runtimes/index.js.map +1 -0
  30. package/dist/agent-runtimes/process/execute.d.ts +3 -0
  31. package/dist/agent-runtimes/process/execute.d.ts.map +1 -0
  32. package/dist/agent-runtimes/process/execute.js +63 -0
  33. package/dist/agent-runtimes/process/execute.js.map +1 -0
  34. package/dist/agent-runtimes/process/index.d.ts +3 -0
  35. package/dist/agent-runtimes/process/index.d.ts.map +1 -0
  36. package/dist/agent-runtimes/process/index.js +23 -0
  37. package/dist/agent-runtimes/process/index.js.map +1 -0
  38. package/dist/agent-runtimes/process/test.d.ts +3 -0
  39. package/dist/agent-runtimes/process/test.d.ts.map +1 -0
  40. package/dist/agent-runtimes/process/test.js +77 -0
  41. package/dist/agent-runtimes/process/test.js.map +1 -0
  42. package/dist/agent-runtimes/registry.d.ts +9 -0
  43. package/dist/agent-runtimes/registry.d.ts.map +1 -0
  44. package/dist/agent-runtimes/registry.js +189 -0
  45. package/dist/agent-runtimes/registry.js.map +1 -0
  46. package/dist/agent-runtimes/types.d.ts +2 -0
  47. package/dist/agent-runtimes/types.d.ts.map +1 -0
  48. package/dist/agent-runtimes/types.js +2 -0
  49. package/dist/agent-runtimes/types.js.map +1 -0
  50. package/dist/agent-runtimes/utils.d.ts +10 -0
  51. package/dist/agent-runtimes/utils.d.ts.map +1 -0
  52. package/dist/agent-runtimes/utils.js +14 -0
  53. package/dist/agent-runtimes/utils.js.map +1 -0
  54. package/dist/agent-workspace-key.d.ts +17 -0
  55. package/dist/agent-workspace-key.d.ts.map +1 -0
  56. package/dist/agent-workspace-key.js +49 -0
  57. package/dist/agent-workspace-key.js.map +1 -0
  58. package/dist/app.d.ts +14 -0
  59. package/dist/app.d.ts.map +1 -0
  60. package/dist/app.js +19 -0
  61. package/dist/app.js.map +1 -0
  62. package/dist/attachment-types.d.ts +33 -0
  63. package/dist/attachment-types.d.ts.map +1 -0
  64. package/dist/attachment-types.js +67 -0
  65. package/dist/attachment-types.js.map +1 -0
  66. package/dist/auth/better-auth.d.ts +24 -0
  67. package/dist/auth/better-auth.d.ts.map +1 -0
  68. package/dist/auth/better-auth.js +108 -0
  69. package/dist/auth/better-auth.js.map +1 -0
  70. package/dist/board-claim.d.ts +23 -0
  71. package/dist/board-claim.d.ts.map +1 -0
  72. package/dist/board-claim.js +115 -0
  73. package/dist/board-claim.js.map +1 -0
  74. package/dist/bootstrap/create-http-app.d.ts +6 -0
  75. package/dist/bootstrap/create-http-app.d.ts.map +1 -0
  76. package/dist/bootstrap/create-http-app.js +122 -0
  77. package/dist/bootstrap/create-http-app.js.map +1 -0
  78. package/dist/bootstrap/plugin-host-runtime.d.ts +116 -0
  79. package/dist/bootstrap/plugin-host-runtime.d.ts.map +1 -0
  80. package/dist/bootstrap/plugin-host-runtime.js +121 -0
  81. package/dist/bootstrap/plugin-host-runtime.js.map +1 -0
  82. package/dist/bootstrap/register-api-routes.d.ts +5 -0
  83. package/dist/bootstrap/register-api-routes.d.ts.map +1 -0
  84. package/dist/bootstrap/register-api-routes.js +65 -0
  85. package/dist/bootstrap/register-api-routes.js.map +1 -0
  86. package/dist/bootstrap/types.d.ts +24 -0
  87. package/dist/bootstrap/types.d.ts.map +1 -0
  88. package/dist/bootstrap/types.js +2 -0
  89. package/dist/bootstrap/types.js.map +1 -0
  90. package/dist/config-file.d.ts +5 -0
  91. package/dist/config-file.d.ts.map +1 -0
  92. package/dist/config-file.js +48 -0
  93. package/dist/config-file.js.map +1 -0
  94. package/dist/config.d.ts +45 -0
  95. package/dist/config.d.ts.map +1 -0
  96. package/dist/config.js +233 -0
  97. package/dist/config.js.map +1 -0
  98. package/dist/dev-server-status.d.ts +29 -0
  99. package/dist/dev-server-status.d.ts.map +1 -0
  100. package/dist/dev-server-status.js +75 -0
  101. package/dist/dev-server-status.js.map +1 -0
  102. package/dist/errors.d.ts +12 -0
  103. package/dist/errors.d.ts.map +1 -0
  104. package/dist/errors.js +28 -0
  105. package/dist/errors.js.map +1 -0
  106. package/dist/home-paths.d.ts +50 -0
  107. package/dist/home-paths.d.ts.map +1 -0
  108. package/dist/home-paths.js +183 -0
  109. package/dist/home-paths.js.map +1 -0
  110. package/dist/index.d.ts +69 -0
  111. package/dist/index.d.ts.map +1 -0
  112. package/dist/index.js +827 -0
  113. package/dist/index.js.map +1 -0
  114. package/dist/langfuse-transcript.d.ts +32 -0
  115. package/dist/langfuse-transcript.d.ts.map +1 -0
  116. package/dist/langfuse-transcript.js +341 -0
  117. package/dist/langfuse-transcript.js.map +1 -0
  118. package/dist/langfuse.d.ts +93 -0
  119. package/dist/langfuse.d.ts.map +1 -0
  120. package/dist/langfuse.js +412 -0
  121. package/dist/langfuse.js.map +1 -0
  122. package/dist/local-runtime.d.ts +67 -0
  123. package/dist/local-runtime.d.ts.map +1 -0
  124. package/dist/local-runtime.js +302 -0
  125. package/dist/local-runtime.js.map +1 -0
  126. package/dist/log-redaction.d.ts +11 -0
  127. package/dist/log-redaction.d.ts.map +1 -0
  128. package/dist/log-redaction.js +118 -0
  129. package/dist/log-redaction.js.map +1 -0
  130. package/dist/middleware/auth.d.ts +12 -0
  131. package/dist/middleware/auth.d.ts.map +1 -0
  132. package/dist/middleware/auth.js +144 -0
  133. package/dist/middleware/auth.js.map +1 -0
  134. package/dist/middleware/board-mutation-guard.d.ts +3 -0
  135. package/dist/middleware/board-mutation-guard.d.ts.map +1 -0
  136. package/dist/middleware/board-mutation-guard.js +59 -0
  137. package/dist/middleware/board-mutation-guard.js.map +1 -0
  138. package/dist/middleware/error-handler.d.ts +17 -0
  139. package/dist/middleware/error-handler.d.ts.map +1 -0
  140. package/dist/middleware/error-handler.js +37 -0
  141. package/dist/middleware/error-handler.js.map +1 -0
  142. package/dist/middleware/index.d.ts +4 -0
  143. package/dist/middleware/index.d.ts.map +1 -0
  144. package/dist/middleware/index.js +4 -0
  145. package/dist/middleware/index.js.map +1 -0
  146. package/dist/middleware/logger.d.ts +4 -0
  147. package/dist/middleware/logger.d.ts.map +1 -0
  148. package/dist/middleware/logger.js +133 -0
  149. package/dist/middleware/logger.js.map +1 -0
  150. package/dist/middleware/private-hostname-guard.d.ts +11 -0
  151. package/dist/middleware/private-hostname-guard.d.ts.map +1 -0
  152. package/dist/middleware/private-hostname-guard.js +78 -0
  153. package/dist/middleware/private-hostname-guard.js.map +1 -0
  154. package/dist/middleware/validate.d.ts +4 -0
  155. package/dist/middleware/validate.d.ts.map +1 -0
  156. package/dist/middleware/validate.js +7 -0
  157. package/dist/middleware/validate.js.map +1 -0
  158. package/dist/onboarding-assets/ceo/AGENTS.md +33 -0
  159. package/dist/onboarding-assets/ceo/HEARTBEAT.md +77 -0
  160. package/dist/onboarding-assets/ceo/SOUL.md +33 -0
  161. package/dist/onboarding-assets/ceo/TOOLS.md +3 -0
  162. package/dist/onboarding-assets/default/AGENTS.md +9 -0
  163. package/dist/onboarding-assets/default/HEARTBEAT.md +36 -0
  164. package/dist/onboarding-assets/default/SOUL.md +23 -0
  165. package/dist/onboarding-assets/default/TOOLS.md +3 -0
  166. package/dist/paths.d.ts +3 -0
  167. package/dist/paths.d.ts.map +1 -0
  168. package/dist/paths.js +31 -0
  169. package/dist/paths.js.map +1 -0
  170. package/dist/realtime/live-events-ws.d.ts +28 -0
  171. package/dist/realtime/live-events-ws.d.ts.map +1 -0
  172. package/dist/realtime/live-events-ws.js +187 -0
  173. package/dist/realtime/live-events-ws.js.map +1 -0
  174. package/dist/redaction.d.ts +4 -0
  175. package/dist/redaction.d.ts.map +1 -0
  176. package/dist/redaction.js +63 -0
  177. package/dist/redaction.js.map +1 -0
  178. package/dist/routes/access.d.ts +57 -0
  179. package/dist/routes/access.d.ts.map +1 -0
  180. package/dist/routes/access.js +2266 -0
  181. package/dist/routes/access.js.map +1 -0
  182. package/dist/routes/activity.d.ts +3 -0
  183. package/dist/routes/activity.d.ts.map +1 -0
  184. package/dist/routes/activity.js +78 -0
  185. package/dist/routes/activity.js.map +1 -0
  186. package/dist/routes/agents.d.ts +3 -0
  187. package/dist/routes/agents.d.ts.map +1 -0
  188. package/dist/routes/agents.js +1913 -0
  189. package/dist/routes/agents.js.map +1 -0
  190. package/dist/routes/approvals.d.ts +3 -0
  191. package/dist/routes/approvals.d.ts.map +1 -0
  192. package/dist/routes/approvals.js +365 -0
  193. package/dist/routes/approvals.js.map +1 -0
  194. package/dist/routes/assets.d.ts +4 -0
  195. package/dist/routes/assets.d.ts.map +1 -0
  196. package/dist/routes/assets.js +309 -0
  197. package/dist/routes/assets.js.map +1 -0
  198. package/dist/routes/authz.d.ts +16 -0
  199. package/dist/routes/authz.d.ts.map +1 -0
  200. package/dist/routes/authz.js +47 -0
  201. package/dist/routes/authz.js.map +1 -0
  202. package/dist/routes/automations.d.ts +3 -0
  203. package/dist/routes/automations.d.ts.map +1 -0
  204. package/dist/routes/automations.js +277 -0
  205. package/dist/routes/automations.js.map +1 -0
  206. package/dist/routes/chats.d.ts +4 -0
  207. package/dist/routes/chats.d.ts.map +1 -0
  208. package/dist/routes/chats.js +1162 -0
  209. package/dist/routes/chats.js.map +1 -0
  210. package/dist/routes/costs.d.ts +3 -0
  211. package/dist/routes/costs.d.ts.map +1 -0
  212. package/dist/routes/costs.js +268 -0
  213. package/dist/routes/costs.js.map +1 -0
  214. package/dist/routes/dashboard.d.ts +3 -0
  215. package/dist/routes/dashboard.d.ts.map +1 -0
  216. package/dist/routes/dashboard.js +15 -0
  217. package/dist/routes/dashboard.js.map +1 -0
  218. package/dist/routes/execution-workspaces.d.ts +3 -0
  219. package/dist/routes/execution-workspaces.d.ts.map +1 -0
  220. package/dist/routes/execution-workspaces.js +165 -0
  221. package/dist/routes/execution-workspaces.js.map +1 -0
  222. package/dist/routes/goals.d.ts +3 -0
  223. package/dist/routes/goals.d.ts.map +1 -0
  224. package/dist/routes/goals.js +95 -0
  225. package/dist/routes/goals.js.map +1 -0
  226. package/dist/routes/health.d.ts +12 -0
  227. package/dist/routes/health.d.ts.map +1 -0
  228. package/dist/routes/health.js +85 -0
  229. package/dist/routes/health.js.map +1 -0
  230. package/dist/routes/index.d.ts +19 -0
  231. package/dist/routes/index.d.ts.map +1 -0
  232. package/dist/routes/index.js +19 -0
  233. package/dist/routes/index.js.map +1 -0
  234. package/dist/routes/instance-settings.d.ts +6 -0
  235. package/dist/routes/instance-settings.d.ts.map +1 -0
  236. package/dist/routes/instance-settings.js +250 -0
  237. package/dist/routes/instance-settings.js.map +1 -0
  238. package/dist/routes/issues-checkout-wakeup.d.ts +9 -0
  239. package/dist/routes/issues-checkout-wakeup.d.ts.map +1 -0
  240. package/dist/routes/issues-checkout-wakeup.js +12 -0
  241. package/dist/routes/issues-checkout-wakeup.js.map +1 -0
  242. package/dist/routes/issues.d.ts +4 -0
  243. package/dist/routes/issues.d.ts.map +1 -0
  244. package/dist/routes/issues.js +1615 -0
  245. package/dist/routes/issues.js.map +1 -0
  246. package/dist/routes/llms.d.ts +3 -0
  247. package/dist/routes/llms.d.ts.map +1 -0
  248. package/dist/routes/llms.js +78 -0
  249. package/dist/routes/llms.js.map +1 -0
  250. package/dist/routes/messenger.d.ts +3 -0
  251. package/dist/routes/messenger.d.ts.map +1 -0
  252. package/dist/routes/messenger.js +108 -0
  253. package/dist/routes/messenger.js.map +1 -0
  254. package/dist/routes/org-chart-logo.d.ts +2 -0
  255. package/dist/routes/org-chart-logo.d.ts.map +1 -0
  256. package/dist/routes/org-chart-logo.js +2 -0
  257. package/dist/routes/org-chart-logo.js.map +1 -0
  258. package/dist/routes/org-chart-svg.d.ts +25 -0
  259. package/dist/routes/org-chart-svg.d.ts.map +1 -0
  260. package/dist/routes/org-chart-svg.js +652 -0
  261. package/dist/routes/org-chart-svg.js.map +1 -0
  262. package/dist/routes/organization-skills.d.ts +3 -0
  263. package/dist/routes/organization-skills.d.ts.map +1 -0
  264. package/dist/routes/organization-skills.js +253 -0
  265. package/dist/routes/organization-skills.js.map +1 -0
  266. package/dist/routes/orgs.d.ts +4 -0
  267. package/dist/routes/orgs.d.ts.map +1 -0
  268. package/dist/routes/orgs.js +575 -0
  269. package/dist/routes/orgs.js.map +1 -0
  270. package/dist/routes/plugin-ui-static.d.ts +69 -0
  271. package/dist/routes/plugin-ui-static.d.ts.map +1 -0
  272. package/dist/routes/plugin-ui-static.js +411 -0
  273. package/dist/routes/plugin-ui-static.js.map +1 -0
  274. package/dist/routes/plugins.d.ts +120 -0
  275. package/dist/routes/plugins.d.ts.map +1 -0
  276. package/dist/routes/plugins.js +1776 -0
  277. package/dist/routes/plugins.js.map +1 -0
  278. package/dist/routes/projects.d.ts +3 -0
  279. package/dist/routes/projects.d.ts.map +1 -0
  280. package/dist/routes/projects.js +235 -0
  281. package/dist/routes/projects.js.map +1 -0
  282. package/dist/routes/run-intelligence.d.ts +3 -0
  283. package/dist/routes/run-intelligence.d.ts.map +1 -0
  284. package/dist/routes/run-intelligence.js +58 -0
  285. package/dist/routes/run-intelligence.js.map +1 -0
  286. package/dist/routes/secrets.d.ts +3 -0
  287. package/dist/routes/secrets.d.ts.map +1 -0
  288. package/dist/routes/secrets.js +128 -0
  289. package/dist/routes/secrets.js.map +1 -0
  290. package/dist/routes/sidebar-badges.d.ts +3 -0
  291. package/dist/routes/sidebar-badges.d.ts.map +1 -0
  292. package/dist/routes/sidebar-badges.js +70 -0
  293. package/dist/routes/sidebar-badges.js.map +1 -0
  294. package/dist/secrets/external-stub-providers.d.ts +5 -0
  295. package/dist/secrets/external-stub-providers.d.ts.map +1 -0
  296. package/dist/secrets/external-stub-providers.js +21 -0
  297. package/dist/secrets/external-stub-providers.js.map +1 -0
  298. package/dist/secrets/local-encrypted-provider.d.ts +3 -0
  299. package/dist/secrets/local-encrypted-provider.d.ts.map +1 -0
  300. package/dist/secrets/local-encrypted-provider.js +116 -0
  301. package/dist/secrets/local-encrypted-provider.js.map +1 -0
  302. package/dist/secrets/provider-registry.d.ts +5 -0
  303. package/dist/secrets/provider-registry.d.ts.map +1 -0
  304. package/dist/secrets/provider-registry.js +20 -0
  305. package/dist/secrets/provider-registry.js.map +1 -0
  306. package/dist/secrets/types.d.ts +21 -0
  307. package/dist/secrets/types.d.ts.map +1 -0
  308. package/dist/secrets/types.js +2 -0
  309. package/dist/secrets/types.js.map +1 -0
  310. package/dist/services/access.d.ts +113 -0
  311. package/dist/services/access.d.ts.map +1 -0
  312. package/dist/services/access.js +247 -0
  313. package/dist/services/access.js.map +1 -0
  314. package/dist/services/activity-log.d.ts +17 -0
  315. package/dist/services/activity-log.d.ts.map +1 -0
  316. package/dist/services/activity-log.js +109 -0
  317. package/dist/services/activity-log.js.map +1 -0
  318. package/dist/services/activity.d.ts +472 -0
  319. package/dist/services/activity.d.ts.map +1 -0
  320. package/dist/services/activity.js +134 -0
  321. package/dist/services/activity.js.map +1 -0
  322. package/dist/services/agent-enabled-skills.d.ts +9 -0
  323. package/dist/services/agent-enabled-skills.d.ts.map +1 -0
  324. package/dist/services/agent-enabled-skills.js +89 -0
  325. package/dist/services/agent-enabled-skills.js.map +1 -0
  326. package/dist/services/agent-instructions.d.ts +98 -0
  327. package/dist/services/agent-instructions.d.ts.map +1 -0
  328. package/dist/services/agent-instructions.js +596 -0
  329. package/dist/services/agent-instructions.js.map +1 -0
  330. package/dist/services/agent-name-pool.d.ts +10 -0
  331. package/dist/services/agent-name-pool.d.ts.map +1 -0
  332. package/dist/services/agent-name-pool.js +230 -0
  333. package/dist/services/agent-name-pool.js.map +1 -0
  334. package/dist/services/agent-permissions.d.ts +6 -0
  335. package/dist/services/agent-permissions.d.ts.map +1 -0
  336. package/dist/services/agent-permissions.js +18 -0
  337. package/dist/services/agent-permissions.js.map +1 -0
  338. package/dist/services/agent-run-context.d.ts +142 -0
  339. package/dist/services/agent-run-context.d.ts.map +1 -0
  340. package/dist/services/agent-run-context.js +451 -0
  341. package/dist/services/agent-run-context.js.map +1 -0
  342. package/dist/services/agents.d.ts +1713 -0
  343. package/dist/services/agents.d.ts.map +1 -0
  344. package/dist/services/agents.js +750 -0
  345. package/dist/services/agents.js.map +1 -0
  346. package/dist/services/approvals.d.ts +546 -0
  347. package/dist/services/approvals.d.ts.map +1 -0
  348. package/dist/services/approvals.js +212 -0
  349. package/dist/services/approvals.js.map +1 -0
  350. package/dist/services/assets.d.ts +33 -0
  351. package/dist/services/assets.d.ts.map +1 -0
  352. package/dist/services/assets.js +17 -0
  353. package/dist/services/assets.js.map +1 -0
  354. package/dist/services/automations.d.ts +135 -0
  355. package/dist/services/automations.d.ts.map +1 -0
  356. package/dist/services/automations.js +1105 -0
  357. package/dist/services/automations.js.map +1 -0
  358. package/dist/services/board-auth.d.ts +234 -0
  359. package/dist/services/board-auth.d.ts.map +1 -0
  360. package/dist/services/board-auth.js +295 -0
  361. package/dist/services/board-auth.js.map +1 -0
  362. package/dist/services/budgets.d.ts +38 -0
  363. package/dist/services/budgets.d.ts.map +1 -0
  364. package/dist/services/budgets.js +784 -0
  365. package/dist/services/budgets.js.map +1 -0
  366. package/dist/services/chat-assistant.d.ts +62 -0
  367. package/dist/services/chat-assistant.d.ts.map +1 -0
  368. package/dist/services/chat-assistant.js +943 -0
  369. package/dist/services/chat-assistant.js.map +1 -0
  370. package/dist/services/chat-generation-locks.d.ts +3 -0
  371. package/dist/services/chat-generation-locks.d.ts.map +1 -0
  372. package/dist/services/chat-generation-locks.js +16 -0
  373. package/dist/services/chat-generation-locks.js.map +1 -0
  374. package/dist/services/chats.d.ts +723 -0
  375. package/dist/services/chats.d.ts.map +1 -0
  376. package/dist/services/chats.js +1188 -0
  377. package/dist/services/chats.js.map +1 -0
  378. package/dist/services/costs.d.ts +114 -0
  379. package/dist/services/costs.d.ts.map +1 -0
  380. package/dist/services/costs.js +326 -0
  381. package/dist/services/costs.js.map +1 -0
  382. package/dist/services/cron.d.ts +80 -0
  383. package/dist/services/cron.d.ts.map +1 -0
  384. package/dist/services/cron.js +300 -0
  385. package/dist/services/cron.js.map +1 -0
  386. package/dist/services/dashboard.d.ts +26 -0
  387. package/dist/services/dashboard.d.ts.map +1 -0
  388. package/dist/services/dashboard.js +98 -0
  389. package/dist/services/dashboard.js.map +1 -0
  390. package/dist/services/default-agent-instructions.d.ts +9 -0
  391. package/dist/services/default-agent-instructions.d.ts.map +1 -0
  392. package/dist/services/default-agent-instructions.js +20 -0
  393. package/dist/services/default-agent-instructions.js.map +1 -0
  394. package/dist/services/documents.d.ts +164 -0
  395. package/dist/services/documents.d.ts.map +1 -0
  396. package/dist/services/documents.js +382 -0
  397. package/dist/services/documents.js.map +1 -0
  398. package/dist/services/execution-workspace-policy.d.ts +20 -0
  399. package/dist/services/execution-workspace-policy.d.ts.map +1 -0
  400. package/dist/services/execution-workspace-policy.js +172 -0
  401. package/dist/services/execution-workspace-policy.js.map +1 -0
  402. package/dist/services/execution-workspaces.d.ts +19 -0
  403. package/dist/services/execution-workspaces.d.ts.map +1 -0
  404. package/dist/services/execution-workspaces.js +87 -0
  405. package/dist/services/execution-workspaces.js.map +1 -0
  406. package/dist/services/finance.d.ts +93 -0
  407. package/dist/services/finance.d.ts.map +1 -0
  408. package/dist/services/finance.js +120 -0
  409. package/dist/services/finance.js.map +1 -0
  410. package/dist/services/goals.d.ts +433 -0
  411. package/dist/services/goals.d.ts.map +1 -0
  412. package/dist/services/goals.js +54 -0
  413. package/dist/services/goals.js.map +1 -0
  414. package/dist/services/heartbeat-run-summary.d.ts +2 -0
  415. package/dist/services/heartbeat-run-summary.d.ts.map +1 -0
  416. package/dist/services/heartbeat-run-summary.js +131 -0
  417. package/dist/services/heartbeat-run-summary.js.map +1 -0
  418. package/dist/services/heartbeat.d.ts +2 -0
  419. package/dist/services/heartbeat.d.ts.map +1 -0
  420. package/dist/services/heartbeat.js +2 -0
  421. package/dist/services/heartbeat.js.map +1 -0
  422. package/dist/services/hire-hook.d.ts +14 -0
  423. package/dist/services/hire-hook.d.ts.map +1 -0
  424. package/dist/services/hire-hook.js +85 -0
  425. package/dist/services/hire-hook.js.map +1 -0
  426. package/dist/services/index.d.ts +38 -0
  427. package/dist/services/index.d.ts.map +1 -0
  428. package/dist/services/index.js +38 -0
  429. package/dist/services/index.js.map +1 -0
  430. package/dist/services/instance-settings.d.ts +14 -0
  431. package/dist/services/instance-settings.d.ts.map +1 -0
  432. package/dist/services/instance-settings.js +158 -0
  433. package/dist/services/instance-settings.js.map +1 -0
  434. package/dist/services/issue-approvals.d.ts +56 -0
  435. package/dist/services/issue-approvals.d.ts.map +1 -0
  436. package/dist/services/issue-approvals.js +153 -0
  437. package/dist/services/issue-approvals.js.map +1 -0
  438. package/dist/services/issue-assignment-wakeup.d.ts +32 -0
  439. package/dist/services/issue-assignment-wakeup.d.ts.map +1 -0
  440. package/dist/services/issue-assignment-wakeup.js +43 -0
  441. package/dist/services/issue-assignment-wakeup.js.map +1 -0
  442. package/dist/services/issue-goal-fallback.d.ts +15 -0
  443. package/dist/services/issue-goal-fallback.d.ts.map +1 -0
  444. package/dist/services/issue-goal-fallback.js +15 -0
  445. package/dist/services/issue-goal-fallback.js.map +1 -0
  446. package/dist/services/issues.d.ts +580 -0
  447. package/dist/services/issues.d.ts.map +1 -0
  448. package/dist/services/issues.js +1464 -0
  449. package/dist/services/issues.js.map +1 -0
  450. package/dist/services/knowledge-portability/organization-portability.d.ts +23 -0
  451. package/dist/services/knowledge-portability/organization-portability.d.ts.map +1 -0
  452. package/dist/services/knowledge-portability/organization-portability.js +3795 -0
  453. package/dist/services/knowledge-portability/organization-portability.js.map +1 -0
  454. package/dist/services/knowledge-portability/organization-skills.d.ts +105 -0
  455. package/dist/services/knowledge-portability/organization-skills.d.ts.map +1 -0
  456. package/dist/services/knowledge-portability/organization-skills.js +3172 -0
  457. package/dist/services/knowledge-portability/organization-skills.js.map +1 -0
  458. package/dist/services/live-events.d.ts +17 -0
  459. package/dist/services/live-events.d.ts.map +1 -0
  460. package/dist/services/live-events.js +33 -0
  461. package/dist/services/live-events.js.map +1 -0
  462. package/dist/services/messenger.d.ts +111 -0
  463. package/dist/services/messenger.d.ts.map +1 -0
  464. package/dist/services/messenger.js +774 -0
  465. package/dist/services/messenger.js.map +1 -0
  466. package/dist/services/native-path-picker.d.ts +18 -0
  467. package/dist/services/native-path-picker.d.ts.map +1 -0
  468. package/dist/services/native-path-picker.js +119 -0
  469. package/dist/services/native-path-picker.js.map +1 -0
  470. package/dist/services/operator-profile.d.ts +7 -0
  471. package/dist/services/operator-profile.d.ts.map +1 -0
  472. package/dist/services/operator-profile.js +66 -0
  473. package/dist/services/operator-profile.js.map +1 -0
  474. package/dist/services/organization-export-readme.d.ts +17 -0
  475. package/dist/services/organization-export-readme.d.ts.map +1 -0
  476. package/dist/services/organization-export-readme.js +148 -0
  477. package/dist/services/organization-export-readme.js.map +1 -0
  478. package/dist/services/organization-portability.d.ts +2 -0
  479. package/dist/services/organization-portability.d.ts.map +1 -0
  480. package/dist/services/organization-portability.js +2 -0
  481. package/dist/services/organization-portability.js.map +1 -0
  482. package/dist/services/organization-skills.d.ts +2 -0
  483. package/dist/services/organization-skills.d.ts.map +1 -0
  484. package/dist/services/organization-skills.js +2 -0
  485. package/dist/services/organization-skills.js.map +1 -0
  486. package/dist/services/organization-workspace-browser.d.ts +8 -0
  487. package/dist/services/organization-workspace-browser.d.ts.map +1 -0
  488. package/dist/services/organization-workspace-browser.js +229 -0
  489. package/dist/services/organization-workspace-browser.js.map +1 -0
  490. package/dist/services/organization-workspace.d.ts +5 -0
  491. package/dist/services/organization-workspace.d.ts.map +1 -0
  492. package/dist/services/organization-workspace.js +71 -0
  493. package/dist/services/organization-workspace.js.map +1 -0
  494. package/dist/services/orgs.d.ts +163 -0
  495. package/dist/services/orgs.d.ts.map +1 -0
  496. package/dist/services/orgs.js +327 -0
  497. package/dist/services/orgs.js.map +1 -0
  498. package/dist/services/plugin-capability-validator.d.ts +108 -0
  499. package/dist/services/plugin-capability-validator.d.ts.map +1 -0
  500. package/dist/services/plugin-capability-validator.js +268 -0
  501. package/dist/services/plugin-capability-validator.js.map +1 -0
  502. package/dist/services/plugin-config-validator.d.ts +26 -0
  503. package/dist/services/plugin-config-validator.d.ts.map +1 -0
  504. package/dist/services/plugin-config-validator.js +41 -0
  505. package/dist/services/plugin-config-validator.js.map +1 -0
  506. package/dist/services/plugin-dev-watcher.d.ts +30 -0
  507. package/dist/services/plugin-dev-watcher.d.ts.map +1 -0
  508. package/dist/services/plugin-dev-watcher.js +241 -0
  509. package/dist/services/plugin-dev-watcher.js.map +1 -0
  510. package/dist/services/plugin-event-bus.d.ts +149 -0
  511. package/dist/services/plugin-event-bus.d.ts.map +1 -0
  512. package/dist/services/plugin-event-bus.js +258 -0
  513. package/dist/services/plugin-event-bus.js.map +1 -0
  514. package/dist/services/plugin-host-service-cleanup.d.ts +14 -0
  515. package/dist/services/plugin-host-service-cleanup.d.ts.map +1 -0
  516. package/dist/services/plugin-host-service-cleanup.js +37 -0
  517. package/dist/services/plugin-host-service-cleanup.js.map +1 -0
  518. package/dist/services/plugin-host-services.d.ts +13 -0
  519. package/dist/services/plugin-host-services.d.ts.map +1 -0
  520. package/dist/services/plugin-host-services.js +973 -0
  521. package/dist/services/plugin-host-services.js.map +1 -0
  522. package/dist/services/plugin-job-coordinator.d.ts +81 -0
  523. package/dist/services/plugin-job-coordinator.d.ts.map +1 -0
  524. package/dist/services/plugin-job-coordinator.js +172 -0
  525. package/dist/services/plugin-job-coordinator.js.map +1 -0
  526. package/dist/services/plugin-job-scheduler.d.ts +163 -0
  527. package/dist/services/plugin-job-scheduler.d.ts.map +1 -0
  528. package/dist/services/plugin-job-scheduler.js +564 -0
  529. package/dist/services/plugin-job-scheduler.js.map +1 -0
  530. package/dist/services/plugin-job-store.d.ts +208 -0
  531. package/dist/services/plugin-job-store.d.ts.map +1 -0
  532. package/dist/services/plugin-job-store.js +350 -0
  533. package/dist/services/plugin-job-store.js.map +1 -0
  534. package/dist/services/plugin-lifecycle.d.ts +203 -0
  535. package/dist/services/plugin-lifecycle.d.ts.map +1 -0
  536. package/dist/services/plugin-lifecycle.js +476 -0
  537. package/dist/services/plugin-lifecycle.js.map +1 -0
  538. package/dist/services/plugin-loader.d.ts +441 -0
  539. package/dist/services/plugin-loader.d.ts.map +1 -0
  540. package/dist/services/plugin-loader.js +1192 -0
  541. package/dist/services/plugin-loader.js.map +1 -0
  542. package/dist/services/plugin-log-retention.d.ts +20 -0
  543. package/dist/services/plugin-log-retention.d.ts.map +1 -0
  544. package/dist/services/plugin-log-retention.js +63 -0
  545. package/dist/services/plugin-log-retention.js.map +1 -0
  546. package/dist/services/plugin-manifest-validator.d.ts +79 -0
  547. package/dist/services/plugin-manifest-validator.d.ts.map +1 -0
  548. package/dist/services/plugin-manifest-validator.js +84 -0
  549. package/dist/services/plugin-manifest-validator.js.map +1 -0
  550. package/dist/services/plugin-registry.d.ts +2542 -0
  551. package/dist/services/plugin-registry.d.ts.map +1 -0
  552. package/dist/services/plugin-registry.js +539 -0
  553. package/dist/services/plugin-registry.js.map +1 -0
  554. package/dist/services/plugin-runtime-sandbox.d.ts +40 -0
  555. package/dist/services/plugin-runtime-sandbox.d.ts.map +1 -0
  556. package/dist/services/plugin-runtime-sandbox.js +154 -0
  557. package/dist/services/plugin-runtime-sandbox.js.map +1 -0
  558. package/dist/services/plugin-secrets-handler.d.ts +81 -0
  559. package/dist/services/plugin-secrets-handler.d.ts.map +1 -0
  560. package/dist/services/plugin-secrets-handler.js +275 -0
  561. package/dist/services/plugin-secrets-handler.js.map +1 -0
  562. package/dist/services/plugin-state-store.d.ts +92 -0
  563. package/dist/services/plugin-state-store.d.ts.map +1 -0
  564. package/dist/services/plugin-state-store.js +190 -0
  565. package/dist/services/plugin-state-store.js.map +1 -0
  566. package/dist/services/plugin-stream-bus.d.ts +29 -0
  567. package/dist/services/plugin-stream-bus.d.ts.map +1 -0
  568. package/dist/services/plugin-stream-bus.js +48 -0
  569. package/dist/services/plugin-stream-bus.js.map +1 -0
  570. package/dist/services/plugin-tool-dispatcher.d.ts +180 -0
  571. package/dist/services/plugin-tool-dispatcher.d.ts.map +1 -0
  572. package/dist/services/plugin-tool-dispatcher.js +224 -0
  573. package/dist/services/plugin-tool-dispatcher.js.map +1 -0
  574. package/dist/services/plugin-tool-registry.d.ts +192 -0
  575. package/dist/services/plugin-tool-registry.d.ts.map +1 -0
  576. package/dist/services/plugin-tool-registry.js +224 -0
  577. package/dist/services/plugin-tool-registry.js.map +1 -0
  578. package/dist/services/plugin-worker-manager.d.ts +260 -0
  579. package/dist/services/plugin-worker-manager.d.ts.map +1 -0
  580. package/dist/services/plugin-worker-manager.js +835 -0
  581. package/dist/services/plugin-worker-manager.js.map +1 -0
  582. package/dist/services/projects.d.ts +92 -0
  583. package/dist/services/projects.d.ts.map +1 -0
  584. package/dist/services/projects.js +705 -0
  585. package/dist/services/projects.js.map +1 -0
  586. package/dist/services/quota-windows.d.ts +9 -0
  587. package/dist/services/quota-windows.d.ts.map +1 -0
  588. package/dist/services/quota-windows.js +56 -0
  589. package/dist/services/quota-windows.js.map +1 -0
  590. package/dist/services/resource-catalog.d.ts +29 -0
  591. package/dist/services/resource-catalog.d.ts.map +1 -0
  592. package/dist/services/resource-catalog.js +298 -0
  593. package/dist/services/resource-catalog.js.map +1 -0
  594. package/dist/services/run-intelligence.d.ts +31 -0
  595. package/dist/services/run-intelligence.d.ts.map +1 -0
  596. package/dist/services/run-intelligence.js +315 -0
  597. package/dist/services/run-intelligence.js.map +1 -0
  598. package/dist/services/run-log-store.d.ts +36 -0
  599. package/dist/services/run-log-store.d.ts.map +1 -0
  600. package/dist/services/run-log-store.js +114 -0
  601. package/dist/services/run-log-store.js.map +1 -0
  602. package/dist/services/runtime-kernel/heartbeat.d.ts +882 -0
  603. package/dist/services/runtime-kernel/heartbeat.d.ts.map +1 -0
  604. package/dist/services/runtime-kernel/heartbeat.js +4345 -0
  605. package/dist/services/runtime-kernel/heartbeat.js.map +1 -0
  606. package/dist/services/runtime-trace-metadata.d.ts +12 -0
  607. package/dist/services/runtime-trace-metadata.d.ts.map +1 -0
  608. package/dist/services/runtime-trace-metadata.js +13 -0
  609. package/dist/services/runtime-trace-metadata.js.map +1 -0
  610. package/dist/services/secrets.d.ts +511 -0
  611. package/dist/services/secrets.d.ts.map +1 -0
  612. package/dist/services/secrets.js +289 -0
  613. package/dist/services/secrets.js.map +1 -0
  614. package/dist/services/sidebar-badges.d.ts +11 -0
  615. package/dist/services/sidebar-badges.d.ts.map +1 -0
  616. package/dist/services/sidebar-badges.js +43 -0
  617. package/dist/services/sidebar-badges.js.map +1 -0
  618. package/dist/services/work-products.d.ts +14 -0
  619. package/dist/services/work-products.d.ts.map +1 -0
  620. package/dist/services/work-products.js +100 -0
  621. package/dist/services/work-products.js.map +1 -0
  622. package/dist/services/workspace-operation-log-store.d.ts +35 -0
  623. package/dist/services/workspace-operation-log-store.d.ts.map +1 -0
  624. package/dist/services/workspace-operation-log-store.js +115 -0
  625. package/dist/services/workspace-operation-log-store.js.map +1 -0
  626. package/dist/services/workspace-operations.d.ts +46 -0
  627. package/dist/services/workspace-operations.d.ts.map +1 -0
  628. package/dist/services/workspace-operations.js +237 -0
  629. package/dist/services/workspace-operations.js.map +1 -0
  630. package/dist/services/workspace-runtime.d.ts +164 -0
  631. package/dist/services/workspace-runtime.d.ts.map +1 -0
  632. package/dist/services/workspace-runtime.js +1235 -0
  633. package/dist/services/workspace-runtime.js.map +1 -0
  634. package/dist/startup-banner.d.ts +31 -0
  635. package/dist/startup-banner.d.ts.map +1 -0
  636. package/dist/startup-banner.js +121 -0
  637. package/dist/startup-banner.js.map +1 -0
  638. package/dist/storage/index.d.ts +6 -0
  639. package/dist/storage/index.d.ts.map +1 -0
  640. package/dist/storage/index.js +29 -0
  641. package/dist/storage/index.js.map +1 -0
  642. package/dist/storage/local-disk-provider.d.ts +3 -0
  643. package/dist/storage/local-disk-provider.d.ts.map +1 -0
  644. package/dist/storage/local-disk-provider.js +79 -0
  645. package/dist/storage/local-disk-provider.js.map +1 -0
  646. package/dist/storage/provider-registry.d.ts +4 -0
  647. package/dist/storage/provider-registry.d.ts.map +1 -0
  648. package/dist/storage/provider-registry.js +15 -0
  649. package/dist/storage/provider-registry.js.map +1 -0
  650. package/dist/storage/s3-provider.d.ts +11 -0
  651. package/dist/storage/s3-provider.d.ts.map +1 -0
  652. package/dist/storage/s3-provider.js +123 -0
  653. package/dist/storage/s3-provider.js.map +1 -0
  654. package/dist/storage/service.d.ts +3 -0
  655. package/dist/storage/service.d.ts.map +1 -0
  656. package/dist/storage/service.js +120 -0
  657. package/dist/storage/service.js.map +1 -0
  658. package/dist/storage/types.d.ts +55 -0
  659. package/dist/storage/types.d.ts.map +1 -0
  660. package/dist/storage/types.js +2 -0
  661. package/dist/storage/types.js.map +1 -0
  662. package/dist/ui-branding.d.ts +14 -0
  663. package/dist/ui-branding.d.ts.map +1 -0
  664. package/dist/ui-branding.js +201 -0
  665. package/dist/ui-branding.js.map +1 -0
  666. package/dist/version.d.ts +2 -0
  667. package/dist/version.d.ts.map +1 -0
  668. package/dist/version.js +5 -0
  669. package/dist/version.js.map +1 -0
  670. package/package.json +101 -0
  671. package/resources/bundled-skills/para-memory-files/SKILL.md +114 -0
  672. package/resources/bundled-skills/para-memory-files/references/schemas.md +35 -0
  673. package/resources/bundled-skills/rudder/SKILL.md +265 -0
  674. package/resources/bundled-skills/rudder/references/api-reference.md +253 -0
  675. package/resources/bundled-skills/rudder/references/cli-reference.md +67 -0
  676. package/resources/bundled-skills/rudder/references/organization-skills.md +155 -0
  677. package/resources/bundled-skills/rudder-create-agent/SKILL.md +166 -0
  678. package/resources/bundled-skills/rudder-create-agent/references/api-reference.md +172 -0
  679. package/resources/bundled-skills/rudder-create-agent/references/cli-reference.md +126 -0
  680. package/resources/bundled-skills/rudder-create-plugin/SKILL.md +103 -0
  681. package/resources/community-skills/deep-research/README.md +124 -0
  682. package/resources/community-skills/deep-research/SKILL.md +107 -0
  683. package/resources/community-skills/deep-research/reference/continuation.md +169 -0
  684. package/resources/community-skills/deep-research/reference/html-generation.md +103 -0
  685. package/resources/community-skills/deep-research/reference/methodology.md +421 -0
  686. package/resources/community-skills/deep-research/reference/quality-gates.md +197 -0
  687. package/resources/community-skills/deep-research/reference/report-assembly.md +119 -0
  688. package/resources/community-skills/deep-research/reference/weasyprint_guidelines.md +324 -0
  689. package/resources/community-skills/deep-research/requirements.txt +14 -0
  690. package/resources/community-skills/deep-research/scripts/citation_manager.py +177 -0
  691. package/resources/community-skills/deep-research/scripts/md_to_html.py +330 -0
  692. package/resources/community-skills/deep-research/scripts/research_engine.py +582 -0
  693. package/resources/community-skills/deep-research/scripts/source_evaluator.py +292 -0
  694. package/resources/community-skills/deep-research/scripts/validate_report.py +403 -0
  695. package/resources/community-skills/deep-research/scripts/verify_citations.py +426 -0
  696. package/resources/community-skills/deep-research/scripts/verify_html.py +220 -0
  697. package/resources/community-skills/deep-research/templates/mckinsey_report_template.html +443 -0
  698. package/resources/community-skills/deep-research/templates/report_template.md +433 -0
  699. package/resources/community-skills/skill-creator/SKILL.md +9 -0
  700. package/resources/community-skills/software-product-advisor/SKILL.md +290 -0
  701. package/skills/para-memory-files/SKILL.md +114 -0
  702. package/skills/para-memory-files/references/schemas.md +35 -0
  703. package/skills/rudder/SKILL.md +265 -0
  704. package/skills/rudder/references/api-reference.md +253 -0
  705. package/skills/rudder/references/cli-reference.md +67 -0
  706. package/skills/rudder/references/organization-skills.md +155 -0
  707. package/skills/rudder-create-agent/SKILL.md +166 -0
  708. package/skills/rudder-create-agent/references/api-reference.md +172 -0
  709. package/skills/rudder-create-agent/references/cli-reference.md +126 -0
  710. package/skills/rudder-create-plugin/SKILL.md +103 -0
  711. package/ui-dist/android-chrome-192x192.png +0 -0
  712. package/ui-dist/android-chrome-512x512.png +0 -0
  713. package/ui-dist/android-chrome-maskable-512x512.png +0 -0
  714. package/ui-dist/apple-touch-icon.png +0 -0
  715. package/ui-dist/assets/_basePickBy-CjUu04_e.js +1 -0
  716. package/ui-dist/assets/_baseUniq-C9YNlrVG.js +1 -0
  717. package/ui-dist/assets/apl-B4CMkyY2.js +1 -0
  718. package/ui-dist/assets/arc-CSSZfktq.js +1 -0
  719. package/ui-dist/assets/architectureDiagram-2XIMDMQ5-Co78JKUi.js +36 -0
  720. package/ui-dist/assets/asciiarmor-Df11BRmG.js +1 -0
  721. package/ui-dist/assets/asn1-EdZsLKOL.js +1 -0
  722. package/ui-dist/assets/asterisk-B-8jnY81.js +1 -0
  723. package/ui-dist/assets/blockDiagram-WCTKOSBZ-2KUUIzzz.js +132 -0
  724. package/ui-dist/assets/brainfuck-C4LP7Hcl.js +1 -0
  725. package/ui-dist/assets/c4Diagram-IC4MRINW-C6pq8tPP.js +10 -0
  726. package/ui-dist/assets/channel-BEODbRMk.js +1 -0
  727. package/ui-dist/assets/chunk-4BX2VUAB-ojCLkixe.js +1 -0
  728. package/ui-dist/assets/chunk-55IACEB6-MGONqzmz.js +1 -0
  729. package/ui-dist/assets/chunk-FMBD7UC4-CmGuLv2P.js +15 -0
  730. package/ui-dist/assets/chunk-JSJVCQXG-BNBefVr6.js +1 -0
  731. package/ui-dist/assets/chunk-KX2RTZJC-DIGBQLn5.js +1 -0
  732. package/ui-dist/assets/chunk-NQ4KR5QH-_KEutsaQ.js +220 -0
  733. package/ui-dist/assets/chunk-QZHKN3VN-B6pzyuwm.js +1 -0
  734. package/ui-dist/assets/chunk-WL4C6EOR-B8NDzcfm.js +189 -0
  735. package/ui-dist/assets/classDiagram-VBA2DB6C-CsSqaaRj.js +1 -0
  736. package/ui-dist/assets/classDiagram-v2-RAHNMMFH-CsSqaaRj.js +1 -0
  737. package/ui-dist/assets/clike-B9uivgTg.js +1 -0
  738. package/ui-dist/assets/clojure-BMjYHr_A.js +1 -0
  739. package/ui-dist/assets/clone-5oWMCI0u.js +1 -0
  740. package/ui-dist/assets/cmake-BQqOBYOt.js +1 -0
  741. package/ui-dist/assets/cobol-CWcv1MsR.js +1 -0
  742. package/ui-dist/assets/coffeescript-S37ZYGWr.js +1 -0
  743. package/ui-dist/assets/commonlisp-DBKNyK5s.js +1 -0
  744. package/ui-dist/assets/cose-bilkent-S5V4N54A-B1t6ulcV.js +1 -0
  745. package/ui-dist/assets/crystal-SjHAIU92.js +1 -0
  746. package/ui-dist/assets/css-BnMrqG3P.js +1 -0
  747. package/ui-dist/assets/cypher-C_CwsFkJ.js +1 -0
  748. package/ui-dist/assets/cytoscape.esm-BQaXIfA_.js +331 -0
  749. package/ui-dist/assets/d-pRatUO7H.js +1 -0
  750. package/ui-dist/assets/dagre-KLK3FWXG-DWVC5_HJ.js +4 -0
  751. package/ui-dist/assets/defaultLocale-DX6XiGOO.js +1 -0
  752. package/ui-dist/assets/diagram-E7M64L7V-C4ztYLox.js +24 -0
  753. package/ui-dist/assets/diagram-IFDJBPK2-DtWBGLnA.js +43 -0
  754. package/ui-dist/assets/diagram-P4PSJMXO-BiqiI4Df.js +24 -0
  755. package/ui-dist/assets/diff-DbItnlRl.js +1 -0
  756. package/ui-dist/assets/dockerfile-BKs6k2Af.js +1 -0
  757. package/ui-dist/assets/dtd-DF_7sFjM.js +1 -0
  758. package/ui-dist/assets/dylan-DwRh75JA.js +1 -0
  759. package/ui-dist/assets/ebnf-CDyGwa7X.js +1 -0
  760. package/ui-dist/assets/ecl-Cabwm37j.js +1 -0
  761. package/ui-dist/assets/eiffel-CnydiIhH.js +1 -0
  762. package/ui-dist/assets/elm-vLlmbW-K.js +1 -0
  763. package/ui-dist/assets/erDiagram-INFDFZHY-CUhr9rIh.js +70 -0
  764. package/ui-dist/assets/erlang-BNw1qcRV.js +1 -0
  765. package/ui-dist/assets/factor-kuTfRLto.js +1 -0
  766. package/ui-dist/assets/fcl-Kvtd6kyn.js +1 -0
  767. package/ui-dist/assets/flowDiagram-PKNHOUZH-BEqBmNL-.js +162 -0
  768. package/ui-dist/assets/forth-Ffai-XNe.js +1 -0
  769. package/ui-dist/assets/fortran-DYz_wnZ1.js +1 -0
  770. package/ui-dist/assets/ganttDiagram-A5KZAMGK-CdeWhdno.js +292 -0
  771. package/ui-dist/assets/gas-Bneqetm1.js +1 -0
  772. package/ui-dist/assets/gherkin-heZmZLOM.js +1 -0
  773. package/ui-dist/assets/gitGraphDiagram-K3NZZRJ6-CgG66QFg.js +65 -0
  774. package/ui-dist/assets/graph-rmownl79.js +1 -0
  775. package/ui-dist/assets/groovy-D9Dt4D0W.js +1 -0
  776. package/ui-dist/assets/haskell-Cw1EW3IL.js +1 -0
  777. package/ui-dist/assets/haxe-H-WmDvRZ.js +1 -0
  778. package/ui-dist/assets/http-DBlCnlav.js +1 -0
  779. package/ui-dist/assets/idl-BEugSyMb.js +1 -0
  780. package/ui-dist/assets/index-B1YyDqaG.js +1 -0
  781. package/ui-dist/assets/index-B7exNxYd.js +1 -0
  782. package/ui-dist/assets/index-BIuriVDl.js +1 -0
  783. package/ui-dist/assets/index-BT9rfwYt.js +1 -0
  784. package/ui-dist/assets/index-BZhmacJG.js +1 -0
  785. package/ui-dist/assets/index-B_ebS3U_.js +3 -0
  786. package/ui-dist/assets/index-BnQqZOsc.js +1 -0
  787. package/ui-dist/assets/index-BwPbAax6.js +1 -0
  788. package/ui-dist/assets/index-C5i670o5.js +1 -0
  789. package/ui-dist/assets/index-C9KwE7Yr.js +1 -0
  790. package/ui-dist/assets/index-CDId_UjP.js +1 -0
  791. package/ui-dist/assets/index-CI9ydSGM.js +1 -0
  792. package/ui-dist/assets/index-CKpm3WGI.css +1 -0
  793. package/ui-dist/assets/index-CMP_bzP3.js +2 -0
  794. package/ui-dist/assets/index-CRcHIoCW.js +1 -0
  795. package/ui-dist/assets/index-DZqNY-Lg.js +1 -0
  796. package/ui-dist/assets/index-DbDKJhW-.js +7 -0
  797. package/ui-dist/assets/index-Dkg6MwQ_.js +1 -0
  798. package/ui-dist/assets/index-Dn0iitKg.js +1 -0
  799. package/ui-dist/assets/index-GvHywIOA.js +1323 -0
  800. package/ui-dist/assets/index-WtX4Y4Fx.js +13 -0
  801. package/ui-dist/assets/index-iyC5PHC3.js +6 -0
  802. package/ui-dist/assets/index-jMlzlqoV.js +1 -0
  803. package/ui-dist/assets/index-pTIOLGTe.js +1 -0
  804. package/ui-dist/assets/infoDiagram-LFFYTUFH-CEhdbTYQ.js +2 -0
  805. package/ui-dist/assets/init-Gi6I4Gst.js +1 -0
  806. package/ui-dist/assets/ishikawaDiagram-PHBUUO56-g9GiiXI2.js +70 -0
  807. package/ui-dist/assets/javascript-iXu5QeM3.js +1 -0
  808. package/ui-dist/assets/journeyDiagram-4ABVD52K-CheeZzlg.js +139 -0
  809. package/ui-dist/assets/julia-DuME0IfC.js +1 -0
  810. package/ui-dist/assets/kanban-definition-K7BYSVSG-BTpuAgUJ.js +89 -0
  811. package/ui-dist/assets/katex-B1X10hvy.js +261 -0
  812. package/ui-dist/assets/layout-CuBgufef.js +1 -0
  813. package/ui-dist/assets/linear-CnXO6wXw.js +1 -0
  814. package/ui-dist/assets/livescript-BwQOo05w.js +1 -0
  815. package/ui-dist/assets/lua-BgMRiT3U.js +1 -0
  816. package/ui-dist/assets/mathematica-DTrFuWx2.js +1 -0
  817. package/ui-dist/assets/mbox-CNhZ1qSd.js +1 -0
  818. package/ui-dist/assets/mermaid.core-DVaYxfh9.js +255 -0
  819. package/ui-dist/assets/mindmap-definition-YRQLILUH-00nAuexq.js +68 -0
  820. package/ui-dist/assets/mirc-CjQqDB4T.js +1 -0
  821. package/ui-dist/assets/mllike-CXdrOF99.js +1 -0
  822. package/ui-dist/assets/modelica-Dc1JOy9r.js +1 -0
  823. package/ui-dist/assets/mscgen-BA5vi2Kp.js +1 -0
  824. package/ui-dist/assets/mumps-BT43cFF4.js +1 -0
  825. package/ui-dist/assets/nginx-DdIZxoE0.js +1 -0
  826. package/ui-dist/assets/nsis-LdVXkNf5.js +1 -0
  827. package/ui-dist/assets/ntriples-BfvgReVJ.js +1 -0
  828. package/ui-dist/assets/octave-Ck1zUtKM.js +1 -0
  829. package/ui-dist/assets/ordinal-Cboi1Yqb.js +1 -0
  830. package/ui-dist/assets/oz-BzwKVEFT.js +1 -0
  831. package/ui-dist/assets/pascal--L3eBynH.js +1 -0
  832. package/ui-dist/assets/perl-CdXCOZ3F.js +1 -0
  833. package/ui-dist/assets/pieDiagram-SKSYHLDU-NaOgRqIj.js +30 -0
  834. package/ui-dist/assets/pig-CevX1Tat.js +1 -0
  835. package/ui-dist/assets/powershell-CFHJl5sT.js +1 -0
  836. package/ui-dist/assets/properties-C78fOPTZ.js +1 -0
  837. package/ui-dist/assets/protobuf-ChK-085T.js +1 -0
  838. package/ui-dist/assets/pug-DeIclll2.js +1 -0
  839. package/ui-dist/assets/puppet-DMA9R1ak.js +1 -0
  840. package/ui-dist/assets/python-BuPzkPfP.js +1 -0
  841. package/ui-dist/assets/q-pXgVlZs6.js +1 -0
  842. package/ui-dist/assets/quadrantDiagram-337W2JSQ-Bnf9OCW0.js +7 -0
  843. package/ui-dist/assets/r-B6wPVr8A.js +1 -0
  844. package/ui-dist/assets/requirementDiagram-Z7DCOOCP-BiacZTTh.js +73 -0
  845. package/ui-dist/assets/rpm-CTu-6PCP.js +1 -0
  846. package/ui-dist/assets/ruby-B2Rjki9n.js +1 -0
  847. package/ui-dist/assets/sankeyDiagram-WA2Y5GQK-DOuD4D2Q.js +10 -0
  848. package/ui-dist/assets/sas-B4kiWyti.js +1 -0
  849. package/ui-dist/assets/scheme-C41bIUwD.js +1 -0
  850. package/ui-dist/assets/sequenceDiagram-2WXFIKYE-oV3M_w-H.js +145 -0
  851. package/ui-dist/assets/shell-CjFT_Tl9.js +1 -0
  852. package/ui-dist/assets/sieve-C3Gn_uJK.js +1 -0
  853. package/ui-dist/assets/simple-mode-GW_nhZxv.js +1 -0
  854. package/ui-dist/assets/smalltalk-CnHTOXQT.js +1 -0
  855. package/ui-dist/assets/solr-DehyRSwq.js +1 -0
  856. package/ui-dist/assets/sparql-DkYu6x3z.js +1 -0
  857. package/ui-dist/assets/spreadsheet-BCZA_wO0.js +1 -0
  858. package/ui-dist/assets/sql-D0XecflT.js +1 -0
  859. package/ui-dist/assets/stateDiagram-RAJIS63D-CdRc2Pqb.js +1 -0
  860. package/ui-dist/assets/stateDiagram-v2-FVOUBMTO-CIMHFJYg.js +1 -0
  861. package/ui-dist/assets/stex-C3f8Ysf7.js +1 -0
  862. package/ui-dist/assets/stylus-B533Al4x.js +1 -0
  863. package/ui-dist/assets/swift-BzpIVaGY.js +1 -0
  864. package/ui-dist/assets/tcl-DVfN8rqt.js +1 -0
  865. package/ui-dist/assets/textile-CnDTJFAw.js +1 -0
  866. package/ui-dist/assets/tiddlywiki-DO-Gjzrf.js +1 -0
  867. package/ui-dist/assets/tiki-DGYXhP31.js +1 -0
  868. package/ui-dist/assets/timeline-definition-YZTLITO2-BCWQDIwt.js +61 -0
  869. package/ui-dist/assets/toml-Bm5Em-hy.js +1 -0
  870. package/ui-dist/assets/treemap-KZPCXAKY-BvsIxXAi.js +162 -0
  871. package/ui-dist/assets/troff-wAsdV37c.js +1 -0
  872. package/ui-dist/assets/ttcn-CfJYG6tj.js +1 -0
  873. package/ui-dist/assets/ttcn-cfg-B9xdYoR4.js +1 -0
  874. package/ui-dist/assets/turtle-B1tBg_DP.js +1 -0
  875. package/ui-dist/assets/vb-CmGdzxic.js +1 -0
  876. package/ui-dist/assets/vbscript-BuJXcnF6.js +1 -0
  877. package/ui-dist/assets/velocity-D8B20fx6.js +1 -0
  878. package/ui-dist/assets/vennDiagram-LZ73GAT5-BzibHs4r.js +34 -0
  879. package/ui-dist/assets/verilog-C6RDOZhf.js +1 -0
  880. package/ui-dist/assets/vhdl-lSbBsy5d.js +1 -0
  881. package/ui-dist/assets/webidl-ZXfAyPTL.js +1 -0
  882. package/ui-dist/assets/xquery-DzFWVndE.js +1 -0
  883. package/ui-dist/assets/xychartDiagram-JWTSCODW-CX_Xt_y-.js +7 -0
  884. package/ui-dist/assets/yacas-BJ4BC0dw.js +1 -0
  885. package/ui-dist/assets/z80-Hz9HOZM7.js +1 -0
  886. package/ui-dist/brands/opencode-logo-dark-square.svg +18 -0
  887. package/ui-dist/brands/opencode-logo-light-square.svg +18 -0
  888. package/ui-dist/favicon-16x16.png +0 -0
  889. package/ui-dist/favicon-32x32.png +0 -0
  890. package/ui-dist/favicon-dev-16x16.png +0 -0
  891. package/ui-dist/favicon-dev-32x32.png +0 -0
  892. package/ui-dist/favicon-dev.ico +0 -0
  893. package/ui-dist/favicon.ico +0 -0
  894. package/ui-dist/favicon.svg +1 -0
  895. package/ui-dist/index.html +61 -0
  896. package/ui-dist/rudder-logo.png +0 -0
  897. package/ui-dist/site.webmanifest +30 -0
  898. package/ui-dist/sw.js +42 -0
  899. package/ui-dist/worktree-favicon-16x16.png +0 -0
  900. package/ui-dist/worktree-favicon-32x32.png +0 -0
  901. package/ui-dist/worktree-favicon.ico +0 -0
  902. package/ui-dist/worktree-favicon.svg +1 -0
@@ -0,0 +1,3172 @@
1
+ import { createHash } from "node:crypto";
2
+ import { promises as fs } from "node:fs";
3
+ import os from "node:os";
4
+ import path from "node:path";
5
+ import { fileURLToPath } from "node:url";
6
+ import { and, asc, eq } from "drizzle-orm";
7
+ import { agents as agentRows, organizationSkills } from "@rudderhq/db";
8
+ 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";
12
+ import { conflict, notFound, unprocessable } from "../../errors.js";
13
+ import { agentEnabledSkillsService } from "../agent-enabled-skills.js";
14
+ import { agentService } from "../agents.js";
15
+ 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: "skill-creator",
25
+ source: "github",
26
+ sourceUrl: "https://github.com/Undertone0809/skill-creator/tree/main/.agents/skills",
27
+ },
28
+ {
29
+ slug: "software-product-advisor",
30
+ source: "repo",
31
+ },
32
+ ];
33
+ const COMMUNITY_PRESET_SKILL_SLUGS = COMMUNITY_PRESET_SKILLS.map((preset) => preset.slug);
34
+ const BUNDLED_SELECTION_PREFIX = "bundled:";
35
+ const ORGANIZATION_SELECTION_PREFIX = "org:";
36
+ const AGENT_SELECTION_PREFIX = "agent:";
37
+ const GLOBAL_SELECTION_PREFIX = "global:";
38
+ const ADAPTER_SELECTION_PREFIX = "adapter:";
39
+ const AGENT_SKILL_SOURCE_CLASS_ORDER = {
40
+ bundled: 0,
41
+ organization: 1,
42
+ agent_home: 2,
43
+ global: 3,
44
+ adapter_home: 4,
45
+ };
46
+ const ADAPTER_SKILL_HOME_DEFINITIONS = {
47
+ claude_local: {
48
+ mode: "ephemeral",
49
+ label: "Adapter skill",
50
+ locationLabel: "~/.claude/skills",
51
+ resolveRoot: (config) => path.join(resolveConfiguredHomeDir(config), ".claude", "skills"),
52
+ },
53
+ opencode_local: {
54
+ mode: "ephemeral",
55
+ label: "Adapter skill",
56
+ locationLabel: "~/.claude/skills",
57
+ resolveRoot: (config) => path.join(resolveConfiguredHomeDir(config), ".claude", "skills"),
58
+ },
59
+ codex_local: {
60
+ mode: "persistent",
61
+ label: "Adapter skill",
62
+ locationLabel: "~/.codex/skills",
63
+ resolveRoot: (config) => path.join(resolveConfiguredCodexHomeDir(config), "skills"),
64
+ },
65
+ cursor: {
66
+ mode: "persistent",
67
+ label: "Adapter skill",
68
+ locationLabel: "~/.cursor/skills",
69
+ resolveRoot: (config) => path.join(resolveConfiguredHomeDir(config), ".cursor", "skills"),
70
+ },
71
+ gemini_local: {
72
+ mode: "persistent",
73
+ label: "Adapter skill",
74
+ locationLabel: "~/.gemini/skills",
75
+ resolveRoot: (config) => path.join(resolveConfiguredHomeDir(config), ".gemini", "skills"),
76
+ },
77
+ pi_local: {
78
+ mode: "persistent",
79
+ label: "Adapter skill",
80
+ locationLabel: "~/.pi/agent/skills",
81
+ resolveRoot: (config) => path.join(resolveConfiguredHomeDir(config), ".pi", "agent", "skills"),
82
+ },
83
+ };
84
+ const PROJECT_SCAN_DIRECTORY_ROOTS = [
85
+ "skills",
86
+ "skills/.curated",
87
+ "skills/.experimental",
88
+ "skills/.system",
89
+ ".agents/skills",
90
+ ".agent/skills",
91
+ ".augment/skills",
92
+ ".claude/skills",
93
+ ".codebuddy/skills",
94
+ ".commandcode/skills",
95
+ ".continue/skills",
96
+ ".cortex/skills",
97
+ ".crush/skills",
98
+ ".factory/skills",
99
+ ".goose/skills",
100
+ ".junie/skills",
101
+ ".iflow/skills",
102
+ ".kilocode/skills",
103
+ ".kiro/skills",
104
+ ".kode/skills",
105
+ ".mcpjam/skills",
106
+ ".vibe/skills",
107
+ ".mux/skills",
108
+ ".openhands/skills",
109
+ ".pi/skills",
110
+ ".qoder/skills",
111
+ ".qwen/skills",
112
+ ".roo/skills",
113
+ ".trae/skills",
114
+ ".windsurf/skills",
115
+ ".zencoder/skills",
116
+ ".neovate/skills",
117
+ ".pochi/skills",
118
+ ".adal/skills",
119
+ ];
120
+ const PROJECT_ROOT_SKILL_SUBDIRECTORIES = [
121
+ "references",
122
+ "scripts",
123
+ "assets",
124
+ ];
125
+ function asString(value) {
126
+ if (typeof value !== "string")
127
+ return null;
128
+ const trimmed = value.trim();
129
+ return trimmed.length > 0 ? trimmed : null;
130
+ }
131
+ function normalizeSkillDescription(value) {
132
+ const description = asString(value);
133
+ if (!description)
134
+ return null;
135
+ return /^[>|][+-]?$/.test(description) ? null : description;
136
+ }
137
+ function isPlainRecord(value) {
138
+ return typeof value === "object" && value !== null && !Array.isArray(value);
139
+ }
140
+ function resolveConfigEnvRecord(config) {
141
+ return isPlainRecord(config.env) ? config.env : {};
142
+ }
143
+ function resolveConfiguredHomeDir(config) {
144
+ const env = resolveConfigEnvRecord(config);
145
+ const configuredHome = asString(env.HOME);
146
+ return configuredHome ? path.resolve(configuredHome) : os.homedir();
147
+ }
148
+ function resolveConfiguredCodexHomeDir(config) {
149
+ const env = resolveConfigEnvRecord(config);
150
+ const configuredCodexHome = asString(env.CODEX_HOME);
151
+ return configuredCodexHome
152
+ ? path.resolve(configuredCodexHome)
153
+ : path.join(resolveConfiguredHomeDir(config), ".codex");
154
+ }
155
+ function normalizePortablePath(input) {
156
+ const parts = [];
157
+ for (const segment of input.replace(/\\/g, "/").replace(/^\.\/+/, "").replace(/^\/+/, "").split("/")) {
158
+ if (!segment || segment === ".")
159
+ continue;
160
+ if (segment === "..") {
161
+ if (parts.length > 0)
162
+ parts.pop();
163
+ continue;
164
+ }
165
+ parts.push(segment);
166
+ }
167
+ return parts.join("/");
168
+ }
169
+ function normalizePackageFileMap(files) {
170
+ const out = {};
171
+ for (const [rawPath, content] of Object.entries(files)) {
172
+ const nextPath = normalizePortablePath(rawPath);
173
+ if (!nextPath)
174
+ continue;
175
+ out[nextPath] = content;
176
+ }
177
+ return out;
178
+ }
179
+ function normalizeSkillSlug(value) {
180
+ return value ? normalizeAgentUrlKey(value) ?? null : null;
181
+ }
182
+ function normalizeSkillKey(value) {
183
+ if (!value)
184
+ return null;
185
+ const segments = value
186
+ .split("/")
187
+ .map((segment) => normalizeSkillSlug(segment))
188
+ .filter((segment) => Boolean(segment));
189
+ return segments.length > 0 ? segments.join("/") : null;
190
+ }
191
+ function isBundledRudderSourceKind(value) {
192
+ return value === "rudder_bundled" || value === "paperclip_bundled";
193
+ }
194
+ function isBundledRudderSkillKey(value) {
195
+ return isCanonicalBundledRudderSkillKey(value);
196
+ }
197
+ function buildBundledSelectionKey(skillKey) {
198
+ return `${BUNDLED_SELECTION_PREFIX}${skillKey}`;
199
+ }
200
+ function buildOrganizationSelectionKey(skillKey) {
201
+ return `${ORGANIZATION_SELECTION_PREFIX}${skillKey}`;
202
+ }
203
+ function buildAgentSelectionKey(slug) {
204
+ return `${AGENT_SELECTION_PREFIX}${slug}`;
205
+ }
206
+ function buildGlobalSelectionKey(slug) {
207
+ return `${GLOBAL_SELECTION_PREFIX}${slug}`;
208
+ }
209
+ function buildAdapterSelectionKey(agentRuntimeType, slug) {
210
+ return `${ADAPTER_SELECTION_PREFIX}${agentRuntimeType}:${slug}`;
211
+ }
212
+ function parseSelectionKey(selectionKey) {
213
+ const trimmed = selectionKey.trim();
214
+ if (!trimmed) {
215
+ return { sourceClass: null, orgKey: null, slug: null, agentRuntimeType: null };
216
+ }
217
+ if (trimmed.startsWith(BUNDLED_SELECTION_PREFIX)) {
218
+ const orgKey = trimmed.slice(BUNDLED_SELECTION_PREFIX.length).trim();
219
+ return {
220
+ sourceClass: "bundled",
221
+ orgKey: orgKey || null,
222
+ slug: normalizeSkillSlug(orgKey.split("/").pop() ?? null),
223
+ agentRuntimeType: null,
224
+ };
225
+ }
226
+ if (trimmed.startsWith(ORGANIZATION_SELECTION_PREFIX)) {
227
+ const orgKey = trimmed.slice(ORGANIZATION_SELECTION_PREFIX.length).trim();
228
+ return {
229
+ sourceClass: "organization",
230
+ orgKey: orgKey || null,
231
+ slug: normalizeSkillSlug(orgKey.split("/").pop() ?? null),
232
+ agentRuntimeType: null,
233
+ };
234
+ }
235
+ if (trimmed.startsWith(AGENT_SELECTION_PREFIX)) {
236
+ const slug = normalizeSkillSlug(trimmed.slice(AGENT_SELECTION_PREFIX.length));
237
+ return {
238
+ sourceClass: "agent_home",
239
+ orgKey: null,
240
+ slug,
241
+ agentRuntimeType: null,
242
+ };
243
+ }
244
+ if (trimmed.startsWith(GLOBAL_SELECTION_PREFIX)) {
245
+ const slug = normalizeSkillSlug(trimmed.slice(GLOBAL_SELECTION_PREFIX.length));
246
+ return {
247
+ sourceClass: "global",
248
+ orgKey: null,
249
+ slug,
250
+ agentRuntimeType: null,
251
+ };
252
+ }
253
+ if (trimmed.startsWith(ADAPTER_SELECTION_PREFIX)) {
254
+ const payload = trimmed.slice(ADAPTER_SELECTION_PREFIX.length);
255
+ const delimiter = payload.indexOf(":");
256
+ if (delimiter <= 0) {
257
+ return { sourceClass: "adapter_home", orgKey: null, slug: null, agentRuntimeType: null };
258
+ }
259
+ return {
260
+ sourceClass: "adapter_home",
261
+ orgKey: null,
262
+ slug: normalizeSkillSlug(payload.slice(delimiter + 1)),
263
+ agentRuntimeType: payload.slice(0, delimiter).trim() || null,
264
+ };
265
+ }
266
+ return { sourceClass: null, orgKey: null, slug: null, agentRuntimeType: null };
267
+ }
268
+ function normalizeSelectionRef(reference, skills, orgId, agentRuntimeType) {
269
+ const trimmed = reference.trim();
270
+ if (!trimmed)
271
+ return null;
272
+ const parsedSelection = parseSelectionKey(trimmed);
273
+ if (parsedSelection.sourceClass === "bundled") {
274
+ return parsedSelection.orgKey ? buildBundledSelectionKey(parsedSelection.orgKey) : null;
275
+ }
276
+ if (parsedSelection.sourceClass === "organization") {
277
+ return parsedSelection.orgKey ? buildOrganizationSelectionKey(parsedSelection.orgKey) : null;
278
+ }
279
+ if (parsedSelection.sourceClass === "agent_home") {
280
+ return parsedSelection.slug ? buildAgentSelectionKey(parsedSelection.slug) : null;
281
+ }
282
+ if (parsedSelection.sourceClass === "global") {
283
+ return parsedSelection.slug ? buildGlobalSelectionKey(parsedSelection.slug) : null;
284
+ }
285
+ if (parsedSelection.sourceClass === "adapter_home") {
286
+ if (!parsedSelection.slug || !parsedSelection.agentRuntimeType)
287
+ return null;
288
+ return buildAdapterSelectionKey(parsedSelection.agentRuntimeType, parsedSelection.slug);
289
+ }
290
+ const orgMatch = resolveSkillReference(skills, trimmed, orgId);
291
+ if (orgMatch.skill) {
292
+ if (isBundledRudderSkillKey(orgMatch.skill.key)) {
293
+ return buildBundledSelectionKey(orgMatch.skill.key);
294
+ }
295
+ return buildOrganizationSelectionKey(orgMatch.skill.key);
296
+ }
297
+ const bundledSlug = getBundledRudderSkillSlug(trimmed);
298
+ if (bundledSlug) {
299
+ const bundledKey = toBundledRudderSkillKey(bundledSlug);
300
+ return bundledKey ? buildBundledSelectionKey(bundledKey) : null;
301
+ }
302
+ const normalizedSlug = normalizeSkillSlug(trimmed);
303
+ if (!normalizedSlug)
304
+ return null;
305
+ return buildAdapterSelectionKey(agentRuntimeType, normalizedSlug);
306
+ }
307
+ async function discoverLocalSkillDirectories(root) {
308
+ const discovered = new Set();
309
+ for (const candidateRoot of [root, path.join(root, "skills")]) {
310
+ const candidateStat = await statPath(candidateRoot);
311
+ if (!candidateStat?.isDirectory())
312
+ continue;
313
+ const entries = await fs.readdir(candidateRoot, { withFileTypes: true }).catch(() => []);
314
+ for (const entry of entries) {
315
+ if (!entry.isDirectory())
316
+ continue;
317
+ const skillDir = path.resolve(candidateRoot, entry.name);
318
+ if (!(await statPath(path.join(skillDir, "SKILL.md")))?.isFile())
319
+ continue;
320
+ discovered.add(skillDir);
321
+ }
322
+ }
323
+ return Array.from(discovered).sort((left, right) => left.localeCompare(right));
324
+ }
325
+ async function readDiscoveredSkillEntries(orgId, root, selectionKeyForSlug, options) {
326
+ const out = [];
327
+ const seenSelectionKeys = new Set();
328
+ for (const skillDir of await discoverLocalSkillDirectories(root)) {
329
+ const slug = normalizeSkillSlug(path.basename(skillDir));
330
+ if (!slug)
331
+ continue;
332
+ const selectionKey = selectionKeyForSlug(slug);
333
+ if (seenSelectionKeys.has(selectionKey))
334
+ continue;
335
+ seenSelectionKeys.add(selectionKey);
336
+ const metadata = await readSkillMetadataFromPath(skillDir).catch(() => ({ name: null, description: null }));
337
+ out.push({
338
+ key: slug,
339
+ selectionKey,
340
+ runtimeName: slug,
341
+ description: metadata.description ?? null,
342
+ desired: false,
343
+ configurable: true,
344
+ alwaysEnabled: false,
345
+ managed: false,
346
+ state: "external",
347
+ sourceClass: options.sourceClass,
348
+ origin: "user_installed",
349
+ originLabel: options.originLabel,
350
+ locationLabel: options.locationLabel,
351
+ readOnly: false,
352
+ sourcePath: skillDir,
353
+ targetPath: null,
354
+ workspaceEditPath: resolveWorkspaceEditPath(orgId, skillDir),
355
+ detail: null,
356
+ organizationSkillKey: null,
357
+ runtimeSourcePath: skillDir,
358
+ });
359
+ }
360
+ return out;
361
+ }
362
+ function buildDraftSkillMarkdown(input) {
363
+ return (input.markdown?.trim().length
364
+ ? input.markdown
365
+ : [
366
+ "---",
367
+ `name: ${input.name}`,
368
+ ...(input.description?.trim() ? [`description: ${input.description.trim()}`] : []),
369
+ "---",
370
+ "",
371
+ `# ${input.name}`,
372
+ "",
373
+ input.description?.trim() ? input.description.trim() : "Describe what this skill does.",
374
+ "",
375
+ ].join("\n"));
376
+ }
377
+ function buildAgentPrivateSkillEntry(orgId, slug, skillDir, description) {
378
+ return {
379
+ key: slug,
380
+ selectionKey: buildAgentSelectionKey(slug),
381
+ runtimeName: slug,
382
+ description,
383
+ desired: false,
384
+ configurable: true,
385
+ alwaysEnabled: false,
386
+ managed: false,
387
+ state: "external",
388
+ sourceClass: "agent_home",
389
+ origin: "user_installed",
390
+ originLabel: "Agent skill",
391
+ locationLabel: "AGENT_HOME/skills",
392
+ readOnly: false,
393
+ sourcePath: skillDir,
394
+ targetPath: null,
395
+ workspaceEditPath: resolveWorkspaceEditPath(orgId, skillDir),
396
+ detail: "Created in AGENT_HOME/skills.",
397
+ organizationSkillKey: null,
398
+ runtimeSourcePath: skillDir,
399
+ };
400
+ }
401
+ export function normalizeGitHubSkillDirectory(value, fallback) {
402
+ const normalized = normalizePortablePath(value ?? "");
403
+ if (!normalized)
404
+ return normalizePortablePath(fallback);
405
+ if (path.posix.basename(normalized).toLowerCase() === "skill.md") {
406
+ return normalizePortablePath(path.posix.dirname(normalized));
407
+ }
408
+ return normalized;
409
+ }
410
+ export function listStaleBundledSkillIds(existingSkills, currentBundledKeys) {
411
+ const currentKeysSet = new Set(currentBundledKeys.map((key) => {
412
+ const bundledKey = toBundledRudderSkillKey(getBundledRudderSkillSlug(key));
413
+ return bundledKey ?? key;
414
+ }));
415
+ return existingSkills
416
+ .filter((skill) => {
417
+ const sourceKind = skill.metadata?.sourceKind;
418
+ if (sourceKind !== "rudder_bundled" && sourceKind !== "paperclip_bundled") {
419
+ return false;
420
+ }
421
+ const canonicalKey = toBundledRudderSkillKey(getBundledRudderSkillSlug(skill.key)) ?? skill.key;
422
+ return !currentKeysSet.has(canonicalKey);
423
+ })
424
+ .map((skill) => skill.id);
425
+ }
426
+ export function listStaleCommunityPresetSkillIds(existingSkills, currentCommunityPresetKeys) {
427
+ const currentKeysSet = new Set(currentCommunityPresetKeys);
428
+ return existingSkills
429
+ .filter((skill) => skill.metadata?.sourceKind === "community_preset")
430
+ .filter((skill) => !currentKeysSet.has(skill.key))
431
+ .map((skill) => skill.id);
432
+ }
433
+ function hashSkillValue(value) {
434
+ return createHash("sha256").update(value).digest("hex").slice(0, 10);
435
+ }
436
+ function uniqueSkillSlug(baseSlug, usedSlugs) {
437
+ if (!usedSlugs.has(baseSlug))
438
+ return baseSlug;
439
+ let attempt = 2;
440
+ let candidate = `${baseSlug}-${attempt}`;
441
+ while (usedSlugs.has(candidate)) {
442
+ attempt += 1;
443
+ candidate = `${baseSlug}-${attempt}`;
444
+ }
445
+ return candidate;
446
+ }
447
+ function uniqueImportedSkillKey(orgId, baseSlug, usedKeys) {
448
+ const initial = `organization/${orgId}/${baseSlug}`;
449
+ if (!usedKeys.has(initial))
450
+ return initial;
451
+ let attempt = 2;
452
+ let candidate = `organization/${orgId}/${baseSlug}-${attempt}`;
453
+ while (usedKeys.has(candidate)) {
454
+ attempt += 1;
455
+ candidate = `organization/${orgId}/${baseSlug}-${attempt}`;
456
+ }
457
+ return candidate;
458
+ }
459
+ function buildSkillRuntimeName(key, slug) {
460
+ if (getBundledRudderSkillSlug(key))
461
+ return slug;
462
+ return `${slug}--${hashSkillValue(key)}`;
463
+ }
464
+ function readCanonicalSkillKey(frontmatter, metadata) {
465
+ const direct = normalizeSkillKey(asString(frontmatter.key)
466
+ ?? asString(frontmatter.skillKey)
467
+ ?? asString(metadata?.skillKey)
468
+ ?? asString(metadata?.canonicalKey)
469
+ ?? asString(metadata?.rudderSkillKey));
470
+ if (direct)
471
+ return direct;
472
+ const rudder = isPlainRecord(metadata?.rudder) ? metadata?.rudder : null;
473
+ return normalizeSkillKey(asString(rudder?.skillKey)
474
+ ?? asString(rudder?.key));
475
+ }
476
+ function deriveCanonicalSkillKey(orgId, input) {
477
+ const slug = normalizeSkillSlug(input.slug) ?? "skill";
478
+ const metadata = isPlainRecord(input.metadata) ? input.metadata : null;
479
+ const sourceKind = asString(metadata?.sourceKind);
480
+ const explicitKey = readCanonicalSkillKey({}, metadata);
481
+ if (explicitKey) {
482
+ if (isBundledRudderSourceKind(sourceKind)) {
483
+ return toBundledRudderSkillKey(getBundledRudderSkillSlug(explicitKey) ?? slug) ?? explicitKey;
484
+ }
485
+ return explicitKey;
486
+ }
487
+ if (isBundledRudderSourceKind(sourceKind)) {
488
+ return toBundledRudderSkillKey(slug) ?? `rudder/${slug}`;
489
+ }
490
+ if (sourceKind === "community_preset") {
491
+ return `organization/${orgId}/${slug}`;
492
+ }
493
+ const owner = normalizeSkillSlug(asString(metadata?.owner));
494
+ const repo = normalizeSkillSlug(asString(metadata?.repo));
495
+ if ((input.sourceType === "github" || input.sourceType === "skills_sh" || sourceKind === "github" || sourceKind === "skills_sh") && owner && repo) {
496
+ return `${owner}/${repo}/${slug}`;
497
+ }
498
+ if (input.sourceType === "url" || sourceKind === "url") {
499
+ const locator = asString(input.sourceLocator);
500
+ if (locator) {
501
+ try {
502
+ const url = new URL(locator);
503
+ const host = normalizeSkillSlug(url.host) ?? "url";
504
+ return `url/${host}/${hashSkillValue(locator)}/${slug}`;
505
+ }
506
+ catch {
507
+ return `url/unknown/${hashSkillValue(locator)}/${slug}`;
508
+ }
509
+ }
510
+ }
511
+ if (input.sourceType === "local_path") {
512
+ if (sourceKind === "managed_local") {
513
+ return `organization/${orgId}/${slug}`;
514
+ }
515
+ const locator = asString(input.sourceLocator);
516
+ if (locator) {
517
+ return `local/${hashSkillValue(path.resolve(locator))}/${slug}`;
518
+ }
519
+ }
520
+ return `organization/${orgId}/${slug}`;
521
+ }
522
+ function classifyInventoryKind(relativePath) {
523
+ const normalized = normalizePortablePath(relativePath).toLowerCase();
524
+ if (normalized.endsWith("/skill.md") || normalized === "skill.md")
525
+ return "skill";
526
+ if (normalized.startsWith("references/"))
527
+ return "reference";
528
+ if (normalized.startsWith("scripts/"))
529
+ return "script";
530
+ if (normalized.startsWith("assets/"))
531
+ return "asset";
532
+ if (normalized.endsWith(".md"))
533
+ return "markdown";
534
+ const fileName = path.posix.basename(normalized);
535
+ if (fileName.endsWith(".sh")
536
+ || fileName.endsWith(".js")
537
+ || fileName.endsWith(".mjs")
538
+ || fileName.endsWith(".cjs")
539
+ || fileName.endsWith(".ts")
540
+ || fileName.endsWith(".py")
541
+ || fileName.endsWith(".rb")
542
+ || fileName.endsWith(".bash")) {
543
+ return "script";
544
+ }
545
+ if (fileName.endsWith(".png")
546
+ || fileName.endsWith(".jpg")
547
+ || fileName.endsWith(".jpeg")
548
+ || fileName.endsWith(".gif")
549
+ || fileName.endsWith(".svg")
550
+ || fileName.endsWith(".webp")
551
+ || fileName.endsWith(".pdf")) {
552
+ return "asset";
553
+ }
554
+ return "other";
555
+ }
556
+ function deriveTrustLevel(fileInventory) {
557
+ if (fileInventory.some((entry) => entry.kind === "script"))
558
+ return "scripts_executables";
559
+ if (fileInventory.some((entry) => entry.kind === "asset" || entry.kind === "other"))
560
+ return "assets";
561
+ return "markdown_only";
562
+ }
563
+ function prepareYamlLines(raw) {
564
+ return raw
565
+ .split("\n")
566
+ .map((line) => ({
567
+ indent: line.match(/^ */)?.[0].length ?? 0,
568
+ content: line.trim(),
569
+ }))
570
+ .filter((line) => line.content.length > 0 && !line.content.startsWith("#"));
571
+ }
572
+ function parseYamlScalar(rawValue) {
573
+ const trimmed = rawValue.trim();
574
+ if (trimmed === "")
575
+ return "";
576
+ if (trimmed === "null" || trimmed === "~")
577
+ return null;
578
+ if (trimmed === "true")
579
+ return true;
580
+ if (trimmed === "false")
581
+ return false;
582
+ if (trimmed === "[]")
583
+ return [];
584
+ if (trimmed === "{}")
585
+ return {};
586
+ if (/^-?\d+(\.\d+)?$/.test(trimmed))
587
+ return Number(trimmed);
588
+ if (trimmed.startsWith("\"") || trimmed.startsWith("[") || trimmed.startsWith("{")) {
589
+ try {
590
+ return JSON.parse(trimmed);
591
+ }
592
+ catch {
593
+ return trimmed;
594
+ }
595
+ }
596
+ return trimmed;
597
+ }
598
+ function parseYamlBlockScalar(lines, startIndex, indentLevel, style) {
599
+ const parts = [];
600
+ let index = startIndex;
601
+ while (index < lines.length) {
602
+ const line = lines[index];
603
+ if (line.indent < indentLevel)
604
+ break;
605
+ parts.push(line.content);
606
+ index += 1;
607
+ }
608
+ if (style === ">") {
609
+ return { value: parts.join(" "), nextIndex: index };
610
+ }
611
+ return { value: parts.join("\n"), nextIndex: index };
612
+ }
613
+ function parseYamlBlock(lines, startIndex, indentLevel) {
614
+ let index = startIndex;
615
+ while (index < lines.length && lines[index].content.length === 0)
616
+ index += 1;
617
+ if (index >= lines.length || lines[index].indent < indentLevel) {
618
+ return { value: {}, nextIndex: index };
619
+ }
620
+ const isArray = lines[index].indent === indentLevel && lines[index].content.startsWith("-");
621
+ if (isArray) {
622
+ const values = [];
623
+ while (index < lines.length) {
624
+ const line = lines[index];
625
+ if (line.indent < indentLevel)
626
+ break;
627
+ if (line.indent !== indentLevel || !line.content.startsWith("-"))
628
+ break;
629
+ const remainder = line.content.slice(1).trim();
630
+ index += 1;
631
+ if (!remainder) {
632
+ const nested = parseYamlBlock(lines, index, indentLevel + 2);
633
+ values.push(nested.value);
634
+ index = nested.nextIndex;
635
+ continue;
636
+ }
637
+ const inlineObjectSeparator = remainder.indexOf(":");
638
+ if (inlineObjectSeparator > 0 &&
639
+ !remainder.startsWith("\"") &&
640
+ !remainder.startsWith("{") &&
641
+ !remainder.startsWith("[")) {
642
+ const key = remainder.slice(0, inlineObjectSeparator).trim();
643
+ const rawValue = remainder.slice(inlineObjectSeparator + 1).trim();
644
+ const nextObject = {
645
+ [key]: parseYamlScalar(rawValue),
646
+ };
647
+ if (index < lines.length && lines[index].indent > indentLevel) {
648
+ const nested = parseYamlBlock(lines, index, indentLevel + 2);
649
+ if (isPlainRecord(nested.value)) {
650
+ Object.assign(nextObject, nested.value);
651
+ }
652
+ index = nested.nextIndex;
653
+ }
654
+ values.push(nextObject);
655
+ continue;
656
+ }
657
+ values.push(parseYamlScalar(remainder));
658
+ }
659
+ return { value: values, nextIndex: index };
660
+ }
661
+ const record = {};
662
+ while (index < lines.length) {
663
+ const line = lines[index];
664
+ if (line.indent < indentLevel)
665
+ break;
666
+ if (line.indent !== indentLevel) {
667
+ index += 1;
668
+ continue;
669
+ }
670
+ const separatorIndex = line.content.indexOf(":");
671
+ if (separatorIndex <= 0) {
672
+ index += 1;
673
+ continue;
674
+ }
675
+ const key = line.content.slice(0, separatorIndex).trim();
676
+ const remainder = line.content.slice(separatorIndex + 1).trim();
677
+ index += 1;
678
+ if (/^[>|][+-]?$/.test(remainder)) {
679
+ const blockScalar = parseYamlBlockScalar(lines, index, indentLevel + 2, remainder.startsWith(">") ? ">" : "|");
680
+ record[key] = blockScalar.value;
681
+ index = blockScalar.nextIndex;
682
+ continue;
683
+ }
684
+ if (!remainder) {
685
+ const nested = parseYamlBlock(lines, index, indentLevel + 2);
686
+ record[key] = nested.value;
687
+ index = nested.nextIndex;
688
+ continue;
689
+ }
690
+ record[key] = parseYamlScalar(remainder);
691
+ }
692
+ return { value: record, nextIndex: index };
693
+ }
694
+ function parseYamlFrontmatter(raw) {
695
+ const prepared = prepareYamlLines(raw);
696
+ if (prepared.length === 0)
697
+ return {};
698
+ const parsed = parseYamlBlock(prepared, 0, prepared[0].indent);
699
+ return isPlainRecord(parsed.value) ? parsed.value : {};
700
+ }
701
+ function parseFrontmatterMarkdown(raw) {
702
+ const normalized = raw.replace(/\r\n/g, "\n");
703
+ if (!normalized.startsWith("---\n")) {
704
+ return { frontmatter: {}, body: normalized.trim() };
705
+ }
706
+ const closing = normalized.indexOf("\n---\n", 4);
707
+ if (closing < 0) {
708
+ return { frontmatter: {}, body: normalized.trim() };
709
+ }
710
+ const frontmatterRaw = normalized.slice(4, closing).trim();
711
+ const body = normalized.slice(closing + 5).trim();
712
+ return {
713
+ frontmatter: parseYamlFrontmatter(frontmatterRaw),
714
+ body,
715
+ };
716
+ }
717
+ async function fetchText(url) {
718
+ const response = await fetch(url);
719
+ if (!response.ok) {
720
+ throw unprocessable(`Failed to fetch ${url}: ${response.status}`);
721
+ }
722
+ return response.text();
723
+ }
724
+ async function fetchJson(url) {
725
+ const response = await fetch(url, {
726
+ headers: {
727
+ accept: "application/vnd.github+json",
728
+ },
729
+ });
730
+ if (!response.ok) {
731
+ throw unprocessable(`Failed to fetch ${url}: ${response.status}`);
732
+ }
733
+ return response.json();
734
+ }
735
+ async function resolveGitHubDefaultBranch(owner, repo) {
736
+ const response = await fetchJson(`https://api.github.com/repos/${owner}/${repo}`);
737
+ return asString(response.default_branch) ?? "main";
738
+ }
739
+ async function resolveGitHubCommitSha(owner, repo, ref) {
740
+ const response = await fetchJson(`https://api.github.com/repos/${owner}/${repo}/commits/${encodeURIComponent(ref)}`);
741
+ const sha = asString(response.sha);
742
+ if (!sha) {
743
+ throw unprocessable(`Failed to resolve GitHub ref ${ref}`);
744
+ }
745
+ return sha;
746
+ }
747
+ function parseGitHubSourceUrl(rawUrl) {
748
+ const url = new URL(rawUrl);
749
+ if (url.hostname !== "github.com") {
750
+ throw unprocessable("GitHub source must use github.com URL");
751
+ }
752
+ const parts = url.pathname.split("/").filter(Boolean);
753
+ if (parts.length < 2) {
754
+ throw unprocessable("Invalid GitHub URL");
755
+ }
756
+ const owner = parts[0];
757
+ const repo = parts[1].replace(/\.git$/i, "");
758
+ let ref = "main";
759
+ let basePath = "";
760
+ let filePath = null;
761
+ let explicitRef = false;
762
+ if (parts[2] === "tree") {
763
+ ref = parts[3] ?? "main";
764
+ basePath = parts.slice(4).join("/");
765
+ explicitRef = true;
766
+ }
767
+ else if (parts[2] === "blob") {
768
+ ref = parts[3] ?? "main";
769
+ filePath = parts.slice(4).join("/");
770
+ basePath = filePath ? path.posix.dirname(filePath) : "";
771
+ explicitRef = true;
772
+ }
773
+ return { owner, repo, ref, basePath, filePath, explicitRef };
774
+ }
775
+ async function resolveGitHubPinnedRef(parsed) {
776
+ if (/^[0-9a-f]{40}$/i.test(parsed.ref.trim())) {
777
+ return {
778
+ pinnedRef: parsed.ref,
779
+ trackingRef: parsed.explicitRef ? parsed.ref : null,
780
+ };
781
+ }
782
+ const trackingRef = parsed.explicitRef
783
+ ? parsed.ref
784
+ : await resolveGitHubDefaultBranch(parsed.owner, parsed.repo);
785
+ const pinnedRef = await resolveGitHubCommitSha(parsed.owner, parsed.repo, trackingRef);
786
+ return { pinnedRef, trackingRef };
787
+ }
788
+ function resolveRawGitHubUrl(owner, repo, ref, filePath) {
789
+ return `https://raw.githubusercontent.com/${owner}/${repo}/${ref}/${filePath.replace(/^\/+/, "")}`;
790
+ }
791
+ function extractCommandTokens(raw) {
792
+ const matches = raw.match(/"[^"]*"|'[^']*'|\S+/g) ?? [];
793
+ return matches.map((token) => token.replace(/^['"]|['"]$/g, ""));
794
+ }
795
+ export function parseSkillImportSourceInput(rawInput) {
796
+ const trimmed = rawInput.trim();
797
+ if (!trimmed) {
798
+ throw unprocessable("Skill source is required.");
799
+ }
800
+ const warnings = [];
801
+ let source = trimmed;
802
+ let requestedSkillSlug = null;
803
+ if (/^npx\s+skills\s+add\s+/i.test(trimmed)) {
804
+ const tokens = extractCommandTokens(trimmed);
805
+ const addIndex = tokens.findIndex((token, index) => token === "add"
806
+ && index > 0
807
+ && tokens[index - 1]?.toLowerCase() === "skills");
808
+ if (addIndex >= 0) {
809
+ source = tokens[addIndex + 1] ?? "";
810
+ for (let index = addIndex + 2; index < tokens.length; index += 1) {
811
+ const token = tokens[index];
812
+ if (token === "--skill") {
813
+ requestedSkillSlug = normalizeSkillSlug(tokens[index + 1] ?? null);
814
+ index += 1;
815
+ continue;
816
+ }
817
+ if (token.startsWith("--skill=")) {
818
+ requestedSkillSlug = normalizeSkillSlug(token.slice("--skill=".length));
819
+ }
820
+ }
821
+ }
822
+ }
823
+ const normalizedSource = source.trim();
824
+ if (!normalizedSource) {
825
+ throw unprocessable("Skill source is required.");
826
+ }
827
+ // Key-style imports (org/repo/skill) originate from the skills.sh registry
828
+ if (!/^https?:\/\//i.test(normalizedSource) && /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/.test(normalizedSource)) {
829
+ const [owner, repo, skillSlugRaw] = normalizedSource.split("/");
830
+ return {
831
+ resolvedSource: `https://github.com/${owner}/${repo}`,
832
+ requestedSkillSlug: normalizeSkillSlug(skillSlugRaw),
833
+ originalSkillsShUrl: `https://skills.sh/${owner}/${repo}/${skillSlugRaw}`,
834
+ warnings,
835
+ };
836
+ }
837
+ if (!/^https?:\/\//i.test(normalizedSource) && /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/.test(normalizedSource)) {
838
+ return {
839
+ resolvedSource: `https://github.com/${normalizedSource}`,
840
+ requestedSkillSlug,
841
+ originalSkillsShUrl: null,
842
+ warnings,
843
+ };
844
+ }
845
+ // Detect skills.sh URLs and resolve to GitHub: https://skills.sh/org/repo/skill → org/repo/skill key
846
+ const skillsShMatch = normalizedSource.match(/^https?:\/\/(?:www\.)?skills\.sh\/([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+)(?:\/([A-Za-z0-9_.-]+))?(?:[?#].*)?$/i);
847
+ if (skillsShMatch) {
848
+ const [, owner, repo, skillSlugRaw] = skillsShMatch;
849
+ return {
850
+ resolvedSource: `https://github.com/${owner}/${repo}`,
851
+ requestedSkillSlug: skillSlugRaw ? normalizeSkillSlug(skillSlugRaw) : requestedSkillSlug,
852
+ originalSkillsShUrl: normalizedSource,
853
+ warnings,
854
+ };
855
+ }
856
+ return {
857
+ resolvedSource: normalizedSource,
858
+ requestedSkillSlug,
859
+ originalSkillsShUrl: null,
860
+ warnings,
861
+ };
862
+ }
863
+ function resolveBundledSkillsRoot() {
864
+ const moduleDir = path.dirname(fileURLToPath(import.meta.url));
865
+ return [
866
+ path.resolve(moduleDir, "../../../resources/bundled-skills"),
867
+ path.resolve(process.cwd(), "server/resources/bundled-skills"),
868
+ ];
869
+ }
870
+ async function readCommunityPresetFallbackImport(orgId, slug, skillKey, sourceUrl) {
871
+ for (const skillsRoot of resolveCommunityPresetSkillsRoot()) {
872
+ const stats = await fs.stat(skillsRoot).catch(() => null);
873
+ if (!stats?.isDirectory())
874
+ continue;
875
+ const skillDir = path.join(skillsRoot, slug);
876
+ const skillStats = await fs.stat(skillDir).catch(() => null);
877
+ if (!skillStats?.isDirectory())
878
+ continue;
879
+ const imported = await readLocalSkillImportFromDirectory(orgId, skillDir, {
880
+ metadata: {
881
+ sourceKind: "community_preset",
882
+ skillKey,
883
+ },
884
+ }).catch(() => null);
885
+ if (!imported)
886
+ continue;
887
+ return {
888
+ ...imported,
889
+ key: skillKey,
890
+ slug,
891
+ sourceType: "github",
892
+ sourceLocator: sourceUrl,
893
+ sourceRef: imported.sourceRef ?? null,
894
+ metadata: {
895
+ ...(imported.metadata ?? {}),
896
+ sourceKind: "community_preset",
897
+ skillKey,
898
+ },
899
+ };
900
+ }
901
+ return null;
902
+ }
903
+ function resolveCommunityPresetSkillsRoot() {
904
+ const moduleDir = path.dirname(fileURLToPath(import.meta.url));
905
+ return [
906
+ path.resolve(moduleDir, "../../../resources/community-skills"),
907
+ path.resolve(process.cwd(), "server/resources/community-skills"),
908
+ ];
909
+ }
910
+ function matchesRequestedSkill(relativeSkillPath, requestedSkillSlug) {
911
+ if (!requestedSkillSlug)
912
+ return true;
913
+ const skillDir = path.posix.dirname(relativeSkillPath);
914
+ return normalizeSkillSlug(path.posix.basename(skillDir)) === requestedSkillSlug;
915
+ }
916
+ function deriveImportedSkillSlug(frontmatter, fallback) {
917
+ return normalizeSkillSlug(asString(frontmatter.slug))
918
+ ?? normalizeSkillSlug(asString(frontmatter.name))
919
+ ?? normalizeAgentUrlKey(fallback)
920
+ ?? "skill";
921
+ }
922
+ function deriveImportedSkillSource(frontmatter, fallbackSlug) {
923
+ const metadata = isPlainRecord(frontmatter.metadata) ? frontmatter.metadata : null;
924
+ const canonicalKey = readCanonicalSkillKey(frontmatter, metadata);
925
+ const rawSources = metadata && Array.isArray(metadata.sources) ? metadata.sources : [];
926
+ const sourceEntry = rawSources.find((entry) => isPlainRecord(entry));
927
+ const kind = asString(sourceEntry?.kind);
928
+ if (kind === "github-dir" || kind === "github-file") {
929
+ const repo = asString(sourceEntry?.repo);
930
+ const repoPath = asString(sourceEntry?.path);
931
+ const commit = asString(sourceEntry?.commit);
932
+ const trackingRef = asString(sourceEntry?.trackingRef);
933
+ const url = asString(sourceEntry?.url)
934
+ ?? (repo
935
+ ? `https://github.com/${repo}${repoPath ? `/tree/${trackingRef ?? commit ?? "main"}/${repoPath}` : ""}`
936
+ : null);
937
+ const [owner, repoName] = (repo ?? "").split("/");
938
+ if (repo && owner && repoName) {
939
+ return {
940
+ sourceType: "github",
941
+ sourceLocator: url,
942
+ sourceRef: commit,
943
+ metadata: {
944
+ ...(canonicalKey ? { skillKey: canonicalKey } : {}),
945
+ sourceKind: "github",
946
+ owner,
947
+ repo: repoName,
948
+ ref: commit,
949
+ trackingRef,
950
+ repoSkillDir: repoPath ?? `skills/${fallbackSlug}`,
951
+ },
952
+ };
953
+ }
954
+ }
955
+ if (kind === "url") {
956
+ const url = asString(sourceEntry?.url) ?? asString(sourceEntry?.rawUrl);
957
+ if (url) {
958
+ return {
959
+ sourceType: "url",
960
+ sourceLocator: url,
961
+ sourceRef: null,
962
+ metadata: {
963
+ ...(canonicalKey ? { skillKey: canonicalKey } : {}),
964
+ sourceKind: "url",
965
+ },
966
+ };
967
+ }
968
+ }
969
+ return {
970
+ sourceType: "catalog",
971
+ sourceLocator: null,
972
+ sourceRef: null,
973
+ metadata: {
974
+ ...(canonicalKey ? { skillKey: canonicalKey } : {}),
975
+ sourceKind: "catalog",
976
+ },
977
+ };
978
+ }
979
+ function readInlineSkillImports(orgId, files) {
980
+ const normalizedFiles = normalizePackageFileMap(files);
981
+ const skillPaths = Object.keys(normalizedFiles).filter((entry) => path.posix.basename(entry).toLowerCase() === "skill.md");
982
+ const imports = [];
983
+ for (const skillPath of skillPaths) {
984
+ const dir = path.posix.dirname(skillPath);
985
+ const skillDir = dir === "." ? "" : dir;
986
+ const slugFallback = path.posix.basename(skillDir || path.posix.dirname(skillPath));
987
+ const markdown = normalizedFiles[skillPath];
988
+ const parsed = parseFrontmatterMarkdown(markdown);
989
+ const slug = deriveImportedSkillSlug(parsed.frontmatter, slugFallback);
990
+ const source = deriveImportedSkillSource(parsed.frontmatter, slug);
991
+ const inventory = Object.keys(normalizedFiles)
992
+ .filter((entry) => entry === skillPath || (skillDir ? entry.startsWith(`${skillDir}/`) : false))
993
+ .map((entry) => {
994
+ const relative = entry === skillPath ? "SKILL.md" : entry.slice(skillDir.length + 1);
995
+ return {
996
+ path: normalizePortablePath(relative),
997
+ kind: classifyInventoryKind(relative),
998
+ };
999
+ })
1000
+ .sort((left, right) => left.path.localeCompare(right.path));
1001
+ imports.push({
1002
+ key: "",
1003
+ slug,
1004
+ name: asString(parsed.frontmatter.name) ?? slug,
1005
+ description: normalizeSkillDescription(parsed.frontmatter.description),
1006
+ markdown,
1007
+ packageDir: skillDir,
1008
+ sourceType: source.sourceType,
1009
+ sourceLocator: source.sourceLocator,
1010
+ sourceRef: source.sourceRef,
1011
+ trustLevel: deriveTrustLevel(inventory),
1012
+ compatibility: "compatible",
1013
+ fileInventory: inventory,
1014
+ metadata: source.metadata,
1015
+ });
1016
+ imports[imports.length - 1].key = deriveCanonicalSkillKey(orgId, imports[imports.length - 1]);
1017
+ }
1018
+ return imports;
1019
+ }
1020
+ async function walkLocalFiles(root, current, out) {
1021
+ const entries = await fs.readdir(current, { withFileTypes: true });
1022
+ for (const entry of entries) {
1023
+ if (entry.name === ".git" || entry.name === "node_modules")
1024
+ continue;
1025
+ const absolutePath = path.join(current, entry.name);
1026
+ if (entry.isDirectory()) {
1027
+ await walkLocalFiles(root, absolutePath, out);
1028
+ continue;
1029
+ }
1030
+ if (!entry.isFile())
1031
+ continue;
1032
+ out.push(normalizePortablePath(path.relative(root, absolutePath)));
1033
+ }
1034
+ }
1035
+ async function statPath(targetPath) {
1036
+ return fs.stat(targetPath).catch(() => null);
1037
+ }
1038
+ async function collectLocalSkillInventory(skillDir, mode = "full") {
1039
+ const skillFilePath = path.join(skillDir, "SKILL.md");
1040
+ const skillFileStat = await statPath(skillFilePath);
1041
+ if (!skillFileStat?.isFile()) {
1042
+ throw unprocessable(`No SKILL.md file was found in ${skillDir}.`);
1043
+ }
1044
+ const allFiles = new Set(["SKILL.md"]);
1045
+ if (mode === "full") {
1046
+ const discoveredFiles = [];
1047
+ await walkLocalFiles(skillDir, skillDir, discoveredFiles);
1048
+ for (const relativePath of discoveredFiles) {
1049
+ allFiles.add(relativePath);
1050
+ }
1051
+ }
1052
+ else {
1053
+ for (const relativeDir of PROJECT_ROOT_SKILL_SUBDIRECTORIES) {
1054
+ const absoluteDir = path.join(skillDir, relativeDir);
1055
+ const dirStat = await statPath(absoluteDir);
1056
+ if (!dirStat?.isDirectory())
1057
+ continue;
1058
+ const discoveredFiles = [];
1059
+ await walkLocalFiles(skillDir, absoluteDir, discoveredFiles);
1060
+ for (const relativePath of discoveredFiles) {
1061
+ allFiles.add(relativePath);
1062
+ }
1063
+ }
1064
+ }
1065
+ return Array.from(allFiles)
1066
+ .map((relativePath) => ({
1067
+ path: normalizePortablePath(relativePath),
1068
+ kind: classifyInventoryKind(relativePath),
1069
+ }))
1070
+ .sort((left, right) => left.path.localeCompare(right.path));
1071
+ }
1072
+ export async function readLocalSkillImportFromDirectory(orgId, skillDir, options) {
1073
+ const resolvedSkillDir = path.resolve(skillDir);
1074
+ const skillFilePath = path.join(resolvedSkillDir, "SKILL.md");
1075
+ const markdown = await fs.readFile(skillFilePath, "utf8");
1076
+ const parsed = parseFrontmatterMarkdown(markdown);
1077
+ const slug = deriveImportedSkillSlug(parsed.frontmatter, path.basename(resolvedSkillDir));
1078
+ const parsedMetadata = isPlainRecord(parsed.frontmatter.metadata) ? parsed.frontmatter.metadata : null;
1079
+ const skillKey = readCanonicalSkillKey(parsed.frontmatter, parsedMetadata);
1080
+ const metadata = {
1081
+ ...(skillKey ? { skillKey } : {}),
1082
+ ...(parsedMetadata ?? {}),
1083
+ sourceKind: "local_path",
1084
+ ...(options?.metadata ?? {}),
1085
+ };
1086
+ const inventory = await collectLocalSkillInventory(resolvedSkillDir, options?.inventoryMode ?? "full");
1087
+ return {
1088
+ key: deriveCanonicalSkillKey(orgId, {
1089
+ slug,
1090
+ sourceType: "local_path",
1091
+ sourceLocator: resolvedSkillDir,
1092
+ metadata,
1093
+ }),
1094
+ slug,
1095
+ name: asString(parsed.frontmatter.name) ?? slug,
1096
+ description: normalizeSkillDescription(parsed.frontmatter.description),
1097
+ markdown,
1098
+ packageDir: resolvedSkillDir,
1099
+ sourceType: "local_path",
1100
+ sourceLocator: resolvedSkillDir,
1101
+ sourceRef: null,
1102
+ trustLevel: deriveTrustLevel(inventory),
1103
+ compatibility: "compatible",
1104
+ fileInventory: inventory,
1105
+ metadata,
1106
+ };
1107
+ }
1108
+ export async function discoverProjectWorkspaceSkillDirectories(target) {
1109
+ const discovered = new Map();
1110
+ const rootSkillPath = path.join(target.workspaceCwd, "SKILL.md");
1111
+ if ((await statPath(rootSkillPath))?.isFile()) {
1112
+ discovered.set(path.resolve(target.workspaceCwd), "project_root");
1113
+ }
1114
+ for (const relativeRoot of PROJECT_SCAN_DIRECTORY_ROOTS) {
1115
+ const absoluteRoot = path.join(target.workspaceCwd, relativeRoot);
1116
+ const rootStat = await statPath(absoluteRoot);
1117
+ if (!rootStat?.isDirectory())
1118
+ continue;
1119
+ const entries = await fs.readdir(absoluteRoot, { withFileTypes: true }).catch(() => []);
1120
+ for (const entry of entries) {
1121
+ if (!entry.isDirectory())
1122
+ continue;
1123
+ const absoluteSkillDir = path.resolve(absoluteRoot, entry.name);
1124
+ if (!(await statPath(path.join(absoluteSkillDir, "SKILL.md")))?.isFile())
1125
+ continue;
1126
+ discovered.set(absoluteSkillDir, "full");
1127
+ }
1128
+ }
1129
+ return Array.from(discovered.entries())
1130
+ .map(([skillDir, inventoryMode]) => ({ skillDir, inventoryMode }))
1131
+ .sort((left, right) => left.skillDir.localeCompare(right.skillDir));
1132
+ }
1133
+ async function readLocalSkillImports(orgId, sourcePath) {
1134
+ const resolvedPath = path.resolve(sourcePath);
1135
+ const stat = await fs.stat(resolvedPath).catch(() => null);
1136
+ if (!stat) {
1137
+ throw unprocessable(`Skill source path does not exist: ${sourcePath}`);
1138
+ }
1139
+ if (stat.isFile()) {
1140
+ if (path.basename(resolvedPath).toLowerCase() !== "skill.md") {
1141
+ throw unprocessable("Local skill imports must point at SKILL.md or a directory that contains skill folders.");
1142
+ }
1143
+ return [await readLocalSkillImportFromDirectory(orgId, path.dirname(resolvedPath))];
1144
+ }
1145
+ const discovered = new Set();
1146
+ if ((await statPath(path.join(resolvedPath, "SKILL.md")))?.isFile()) {
1147
+ discovered.add(resolvedPath);
1148
+ }
1149
+ for (const candidateRoot of [resolvedPath, path.join(resolvedPath, "skills")]) {
1150
+ const candidateStat = await statPath(candidateRoot);
1151
+ if (!candidateStat?.isDirectory())
1152
+ continue;
1153
+ const entries = await fs.readdir(candidateRoot, { withFileTypes: true }).catch(() => []);
1154
+ for (const entry of entries) {
1155
+ if (!entry.isDirectory())
1156
+ continue;
1157
+ const skillDir = path.join(candidateRoot, entry.name);
1158
+ if ((await statPath(path.join(skillDir, "SKILL.md")))?.isFile()) {
1159
+ discovered.add(path.resolve(skillDir));
1160
+ }
1161
+ }
1162
+ }
1163
+ if (discovered.size === 0) {
1164
+ throw unprocessable("No SKILL.md files were found in the provided path.");
1165
+ }
1166
+ return Promise.all(Array.from(discovered)
1167
+ .sort((left, right) => left.localeCompare(right))
1168
+ .map((skillDir) => readLocalSkillImportFromDirectory(orgId, skillDir)));
1169
+ }
1170
+ async function readUrlSkillImports(orgId, sourceUrl, requestedSkillSlug = null) {
1171
+ const url = sourceUrl.trim();
1172
+ const warnings = [];
1173
+ if (url.includes("github.com/")) {
1174
+ const parsed = parseGitHubSourceUrl(url);
1175
+ const { pinnedRef, trackingRef } = await resolveGitHubPinnedRef(parsed);
1176
+ let ref = pinnedRef;
1177
+ const tree = await fetchJson(`https://api.github.com/repos/${parsed.owner}/${parsed.repo}/git/trees/${ref}?recursive=1`).catch(() => {
1178
+ throw unprocessable(`Failed to read GitHub tree for ${url}`);
1179
+ });
1180
+ const allPaths = (tree.tree ?? [])
1181
+ .filter((entry) => entry.type === "blob")
1182
+ .map((entry) => entry.path)
1183
+ .filter((entry) => typeof entry === "string");
1184
+ const basePrefix = parsed.basePath ? `${parsed.basePath.replace(/^\/+|\/+$/g, "")}/` : "";
1185
+ const scopedPaths = basePrefix
1186
+ ? allPaths.filter((entry) => entry.startsWith(basePrefix))
1187
+ : allPaths;
1188
+ const relativePaths = scopedPaths.map((entry) => basePrefix ? entry.slice(basePrefix.length) : entry);
1189
+ const filteredPaths = parsed.filePath
1190
+ ? relativePaths.filter((entry) => entry === path.posix.relative(parsed.basePath || ".", parsed.filePath))
1191
+ : relativePaths;
1192
+ const skillPaths = filteredPaths.filter((entry) => path.posix.basename(entry).toLowerCase() === "skill.md");
1193
+ if (skillPaths.length === 0) {
1194
+ throw unprocessable("No SKILL.md files were found in the provided GitHub source.");
1195
+ }
1196
+ const skills = [];
1197
+ for (const relativeSkillPath of skillPaths) {
1198
+ const repoSkillPath = basePrefix ? `${basePrefix}${relativeSkillPath}` : relativeSkillPath;
1199
+ const markdown = await fetchText(resolveRawGitHubUrl(parsed.owner, parsed.repo, ref, repoSkillPath));
1200
+ const parsedMarkdown = parseFrontmatterMarkdown(markdown);
1201
+ const skillDir = path.posix.dirname(relativeSkillPath);
1202
+ const slug = deriveImportedSkillSlug(parsedMarkdown.frontmatter, path.posix.basename(skillDir));
1203
+ const skillKey = readCanonicalSkillKey(parsedMarkdown.frontmatter, isPlainRecord(parsedMarkdown.frontmatter.metadata) ? parsedMarkdown.frontmatter.metadata : null);
1204
+ if (requestedSkillSlug && !matchesRequestedSkill(relativeSkillPath, requestedSkillSlug) && slug !== requestedSkillSlug) {
1205
+ continue;
1206
+ }
1207
+ const metadata = {
1208
+ ...(skillKey ? { skillKey } : {}),
1209
+ sourceKind: "github",
1210
+ owner: parsed.owner,
1211
+ repo: parsed.repo,
1212
+ ref: ref,
1213
+ trackingRef,
1214
+ repoSkillDir: normalizeGitHubSkillDirectory(basePrefix ? `${basePrefix}${skillDir}` : skillDir, slug),
1215
+ };
1216
+ const inventory = filteredPaths
1217
+ .filter((entry) => entry === relativeSkillPath || entry.startsWith(`${skillDir}/`))
1218
+ .map((entry) => ({
1219
+ path: entry === relativeSkillPath ? "SKILL.md" : entry.slice(skillDir.length + 1),
1220
+ kind: classifyInventoryKind(entry === relativeSkillPath ? "SKILL.md" : entry.slice(skillDir.length + 1)),
1221
+ }))
1222
+ .sort((left, right) => left.path.localeCompare(right.path));
1223
+ skills.push({
1224
+ key: deriveCanonicalSkillKey(orgId, {
1225
+ slug,
1226
+ sourceType: "github",
1227
+ sourceLocator: sourceUrl,
1228
+ metadata,
1229
+ }),
1230
+ slug,
1231
+ name: asString(parsedMarkdown.frontmatter.name) ?? slug,
1232
+ description: normalizeSkillDescription(parsedMarkdown.frontmatter.description),
1233
+ markdown,
1234
+ sourceType: "github",
1235
+ sourceLocator: sourceUrl,
1236
+ sourceRef: ref,
1237
+ trustLevel: deriveTrustLevel(inventory),
1238
+ compatibility: "compatible",
1239
+ fileInventory: inventory,
1240
+ metadata,
1241
+ });
1242
+ }
1243
+ if (skills.length === 0) {
1244
+ throw unprocessable(requestedSkillSlug
1245
+ ? `Skill ${requestedSkillSlug} was not found in the provided GitHub source.`
1246
+ : "No SKILL.md files were found in the provided GitHub source.");
1247
+ }
1248
+ return { skills, warnings };
1249
+ }
1250
+ if (url.startsWith("http://") || url.startsWith("https://")) {
1251
+ const markdown = await fetchText(url);
1252
+ const parsedMarkdown = parseFrontmatterMarkdown(markdown);
1253
+ const urlObj = new URL(url);
1254
+ const fileName = path.posix.basename(urlObj.pathname);
1255
+ const slug = deriveImportedSkillSlug(parsedMarkdown.frontmatter, fileName.replace(/\.md$/i, ""));
1256
+ const skillKey = readCanonicalSkillKey(parsedMarkdown.frontmatter, isPlainRecord(parsedMarkdown.frontmatter.metadata) ? parsedMarkdown.frontmatter.metadata : null);
1257
+ const metadata = {
1258
+ ...(skillKey ? { skillKey } : {}),
1259
+ sourceKind: "url",
1260
+ };
1261
+ const inventory = [{ path: "SKILL.md", kind: "skill" }];
1262
+ return {
1263
+ skills: [{
1264
+ key: deriveCanonicalSkillKey(orgId, {
1265
+ slug,
1266
+ sourceType: "url",
1267
+ sourceLocator: url,
1268
+ metadata,
1269
+ }),
1270
+ slug,
1271
+ name: asString(parsedMarkdown.frontmatter.name) ?? slug,
1272
+ description: normalizeSkillDescription(parsedMarkdown.frontmatter.description),
1273
+ markdown,
1274
+ sourceType: "url",
1275
+ sourceLocator: url,
1276
+ sourceRef: null,
1277
+ trustLevel: deriveTrustLevel(inventory),
1278
+ compatibility: "compatible",
1279
+ fileInventory: inventory,
1280
+ metadata,
1281
+ }],
1282
+ warnings,
1283
+ };
1284
+ }
1285
+ throw unprocessable("Unsupported skill source. Use a local path or URL.");
1286
+ }
1287
+ function toCompanySkill(row) {
1288
+ return {
1289
+ ...row,
1290
+ description: row.description ?? null,
1291
+ sourceType: row.sourceType,
1292
+ sourceLocator: row.sourceLocator ?? null,
1293
+ sourceRef: row.sourceRef ?? null,
1294
+ trustLevel: row.trustLevel,
1295
+ compatibility: row.compatibility,
1296
+ fileInventory: Array.isArray(row.fileInventory)
1297
+ ? row.fileInventory.flatMap((entry) => {
1298
+ if (!isPlainRecord(entry))
1299
+ return [];
1300
+ return [{
1301
+ path: String(entry.path ?? ""),
1302
+ kind: String(entry.kind ?? "other"),
1303
+ }];
1304
+ })
1305
+ : [],
1306
+ metadata: isPlainRecord(row.metadata) ? row.metadata : null,
1307
+ };
1308
+ }
1309
+ function serializeFileInventory(fileInventory) {
1310
+ return fileInventory.map((entry) => ({
1311
+ path: entry.path,
1312
+ kind: entry.kind,
1313
+ }));
1314
+ }
1315
+ function getSkillMeta(skill) {
1316
+ return isPlainRecord(skill.metadata) ? skill.metadata : {};
1317
+ }
1318
+ function resolveSkillReference(skills, reference, orgId) {
1319
+ const trimmed = reference.trim();
1320
+ if (!trimmed) {
1321
+ return { skill: null, ambiguous: false };
1322
+ }
1323
+ const byId = skills.find((skill) => skill.id === trimmed);
1324
+ if (byId) {
1325
+ return { skill: byId, ambiguous: false };
1326
+ }
1327
+ return resolveOrganizationSkillReference(skills, trimmed, { orgId });
1328
+ }
1329
+ function resolveRequestedSkillKeysOrThrow(skills, requestedReferences, orgId) {
1330
+ const missing = new Set();
1331
+ const ambiguous = new Set();
1332
+ const resolved = new Set();
1333
+ for (const reference of requestedReferences) {
1334
+ const trimmed = reference.trim();
1335
+ if (!trimmed)
1336
+ continue;
1337
+ const match = resolveSkillReference(skills, trimmed, orgId);
1338
+ if (match.skill) {
1339
+ resolved.add(match.skill.key);
1340
+ continue;
1341
+ }
1342
+ if (match.ambiguous) {
1343
+ ambiguous.add(trimmed);
1344
+ continue;
1345
+ }
1346
+ missing.add(trimmed);
1347
+ }
1348
+ if (ambiguous.size > 0 || missing.size > 0) {
1349
+ const problems = [];
1350
+ if (ambiguous.size > 0) {
1351
+ problems.push(`ambiguous references: ${Array.from(ambiguous).sort().join(", ")}`);
1352
+ }
1353
+ if (missing.size > 0) {
1354
+ problems.push(`unknown references: ${Array.from(missing).sort().join(", ")}`);
1355
+ }
1356
+ throw unprocessable(`Invalid organization skill selection (${problems.join("; ")}).`);
1357
+ }
1358
+ return Array.from(resolved);
1359
+ }
1360
+ function resolveDesiredSkillKeys(skills, config, orgId) {
1361
+ const preference = readRudderSkillSyncPreference(config);
1362
+ return Array.from(new Set(preference.desiredSkills
1363
+ .map((reference) => {
1364
+ const resolved = resolveSkillReference(skills, reference, orgId).skill?.key;
1365
+ if (resolved)
1366
+ return resolved;
1367
+ const bundledKey = toBundledRudderSkillKey(getBundledRudderSkillSlug(reference));
1368
+ return bundledKey ?? normalizeSkillKey(reference);
1369
+ })
1370
+ .filter((value) => Boolean(value))));
1371
+ }
1372
+ function getRequiredBundledSkillKeys(skills) {
1373
+ const availableKeys = new Set(skills.map((skill) => skill.key));
1374
+ return RUDDER_BUNDLED_SKILL_SLUGS
1375
+ .map((slug) => `rudder/${slug}`)
1376
+ .filter((key) => availableKeys.has(key));
1377
+ }
1378
+ function sortUniqueSkillKeys(skillKeys) {
1379
+ return Array.from(new Set(skillKeys
1380
+ .map((value) => value.trim())
1381
+ .filter(Boolean))).sort((left, right) => left.localeCompare(right));
1382
+ }
1383
+ function sortUniqueSelectionRefs(selectionRefs) {
1384
+ return Array.from(new Set(selectionRefs
1385
+ .map((value) => value.trim())
1386
+ .filter(Boolean))).sort((left, right) => left.localeCompare(right));
1387
+ }
1388
+ function arraysEqual(left, right) {
1389
+ if (left === right)
1390
+ return true;
1391
+ if (left.length !== right.length)
1392
+ return false;
1393
+ return left.every((value, index) => value === right[index]);
1394
+ }
1395
+ function buildMissingSelectionEntry(selectionKey, agentRuntimeType) {
1396
+ const parsed = parseSelectionKey(selectionKey);
1397
+ const key = parsed.slug ?? parsed.orgKey ?? selectionKey;
1398
+ const runtimeTypeMismatch = parsed.sourceClass === "adapter_home"
1399
+ && parsed.agentRuntimeType
1400
+ && parsed.agentRuntimeType !== agentRuntimeType;
1401
+ const locationLabel = (() => {
1402
+ if (parsed.sourceClass === "agent_home")
1403
+ return "AGENT_HOME/skills";
1404
+ if (parsed.sourceClass === "global")
1405
+ return "~/.agents/skills";
1406
+ if (parsed.sourceClass === "adapter_home" && parsed.agentRuntimeType) {
1407
+ return ADAPTER_SKILL_HOME_DEFINITIONS[parsed.agentRuntimeType]?.locationLabel ?? null;
1408
+ }
1409
+ return null;
1410
+ })();
1411
+ const detail = runtimeTypeMismatch
1412
+ ? `This adapter-specific skill was saved for ${parsed.agentRuntimeType} and is unavailable on ${agentRuntimeType}.`
1413
+ : "Rudder cannot find this enabled skill in the current Rudder-owned catalog.";
1414
+ return {
1415
+ key,
1416
+ selectionKey,
1417
+ runtimeName: parsed.slug ?? key,
1418
+ description: null,
1419
+ desired: true,
1420
+ configurable: parsed.sourceClass !== "bundled",
1421
+ alwaysEnabled: parsed.sourceClass === "bundled",
1422
+ managed: parsed.sourceClass === "bundled" || parsed.sourceClass === "organization",
1423
+ state: "missing",
1424
+ sourceClass: parsed.sourceClass ?? "adapter_home",
1425
+ origin: "external_unknown",
1426
+ originLabel: runtimeTypeMismatch ? "Unavailable for this runtime" : "Unavailable",
1427
+ locationLabel,
1428
+ readOnly: parsed.sourceClass === "bundled",
1429
+ sourcePath: null,
1430
+ targetPath: null,
1431
+ detail,
1432
+ organizationSkillKey: parsed.orgKey ?? null,
1433
+ runtimeSourcePath: null,
1434
+ };
1435
+ }
1436
+ function applyDesiredSelectionsToCatalog(entries, desiredSelectionRefs, agentRuntimeType) {
1437
+ const desiredSet = new Set(desiredSelectionRefs);
1438
+ const warnings = [];
1439
+ const out = entries.map((entry) => {
1440
+ const desired = entry.alwaysEnabled || desiredSet.has(entry.selectionKey);
1441
+ const state = entry.alwaysEnabled
1442
+ ? "configured"
1443
+ : desired
1444
+ ? "configured"
1445
+ : entry.sourceClass === "agent_home" || entry.sourceClass === "global" || entry.sourceClass === "adapter_home"
1446
+ ? "external"
1447
+ : "available";
1448
+ return {
1449
+ ...entry,
1450
+ desired,
1451
+ state,
1452
+ detail: desired
1453
+ ? entry.alwaysEnabled
1454
+ ? (entry.detail ?? "Always loaded by Rudder for every agent run.")
1455
+ : (entry.detail ?? "Enabled for this agent and loaded on the next run.")
1456
+ : (entry.detail ?? null),
1457
+ };
1458
+ });
1459
+ const knownSelectionKeys = new Set(out.map((entry) => entry.selectionKey));
1460
+ for (const selectionKey of desiredSelectionRefs) {
1461
+ if (knownSelectionKeys.has(selectionKey))
1462
+ continue;
1463
+ warnings.push(`Enabled skill "${selectionKey}" is no longer available in the current skill catalog.`);
1464
+ out.push(buildMissingSelectionEntry(selectionKey, agentRuntimeType));
1465
+ }
1466
+ out.sort((left, right) => {
1467
+ const orderDelta = AGENT_SKILL_SOURCE_CLASS_ORDER[left.sourceClass] - AGENT_SKILL_SOURCE_CLASS_ORDER[right.sourceClass];
1468
+ if (orderDelta !== 0)
1469
+ return orderDelta;
1470
+ return left.key.localeCompare(right.key) || left.selectionKey.localeCompare(right.selectionKey);
1471
+ });
1472
+ const conflictGroups = new Map();
1473
+ for (const entry of out) {
1474
+ if (!entry.desired || entry.alwaysEnabled)
1475
+ continue;
1476
+ const existing = conflictGroups.get(entry.key) ?? [];
1477
+ existing.push(entry.selectionKey);
1478
+ conflictGroups.set(entry.key, existing);
1479
+ }
1480
+ for (const [skillKey, selectionKeys] of conflictGroups.entries()) {
1481
+ if (selectionKeys.length <= 1)
1482
+ continue;
1483
+ warnings.push(`Enabled skill collision for "${skillKey}": ${selectionKeys.join(", ")}`);
1484
+ }
1485
+ return {
1486
+ desiredSkills: sortUniqueSelectionRefs(desiredSelectionRefs),
1487
+ entries: out,
1488
+ warnings,
1489
+ };
1490
+ }
1491
+ function stripBundledRequiredSkillKeys(skillKeys) {
1492
+ return sortUniqueSkillKeys(skillKeys).filter((skillKey) => !isBundledRudderSkillKey(skillKey));
1493
+ }
1494
+ function mergeRequiredBundledSkillKeys(skills, skillKeys) {
1495
+ return sortUniqueSkillKeys([
1496
+ ...stripBundledRequiredSkillKeys(skillKeys),
1497
+ ...getRequiredBundledSkillKeys(skills),
1498
+ ]);
1499
+ }
1500
+ function normalizeSkillDirectory(skill) {
1501
+ if ((skill.sourceType !== "local_path" && skill.sourceType !== "catalog") || !skill.sourceLocator)
1502
+ return null;
1503
+ const resolved = path.resolve(skill.sourceLocator);
1504
+ if (path.basename(resolved).toLowerCase() === "skill.md") {
1505
+ return path.dirname(resolved);
1506
+ }
1507
+ return resolved;
1508
+ }
1509
+ function normalizeSourceLocatorDirectory(sourceLocator) {
1510
+ if (!sourceLocator)
1511
+ return null;
1512
+ const resolved = path.resolve(sourceLocator);
1513
+ return path.basename(resolved).toLowerCase() === "skill.md" ? path.dirname(resolved) : resolved;
1514
+ }
1515
+ export async function findMissingLocalSkillIds(skills) {
1516
+ const missingIds = [];
1517
+ for (const skill of skills) {
1518
+ if (skill.sourceType !== "local_path")
1519
+ continue;
1520
+ const skillDir = normalizeSourceLocatorDirectory(skill.sourceLocator);
1521
+ if (!skillDir) {
1522
+ missingIds.push(skill.id);
1523
+ continue;
1524
+ }
1525
+ const skillDirStat = await statPath(skillDir);
1526
+ const skillFileStat = await statPath(path.join(skillDir, "SKILL.md"));
1527
+ if (!skillDirStat?.isDirectory() || !skillFileStat?.isFile()) {
1528
+ missingIds.push(skill.id);
1529
+ }
1530
+ }
1531
+ return missingIds;
1532
+ }
1533
+ function resolveManagedSkillsRoot(orgId) {
1534
+ return resolveOrganizationSkillsDir(orgId);
1535
+ }
1536
+ function resolveWorkspaceEditPath(orgId, sourcePath) {
1537
+ if (!sourcePath)
1538
+ return null;
1539
+ const workspaceRoot = path.resolve(resolveOrganizationWorkspaceRoot(orgId));
1540
+ const skillDir = path.resolve(sourcePath);
1541
+ const entryFilePath = path.resolve(skillDir, "SKILL.md");
1542
+ const relativePath = path.relative(workspaceRoot, entryFilePath);
1543
+ if (relativePath.startsWith("..") || path.isAbsolute(relativePath)) {
1544
+ return null;
1545
+ }
1546
+ return normalizePortablePath(relativePath);
1547
+ }
1548
+ function resolveLocalSkillFilePath(skill, relativePath) {
1549
+ const normalized = normalizePortablePath(relativePath);
1550
+ const skillDir = normalizeSkillDirectory(skill);
1551
+ if (skillDir) {
1552
+ return path.resolve(skillDir, normalized);
1553
+ }
1554
+ if (!skill.sourceLocator)
1555
+ return null;
1556
+ const fallbackRoot = path.resolve(skill.sourceLocator);
1557
+ const directPath = path.resolve(fallbackRoot, normalized);
1558
+ return directPath;
1559
+ }
1560
+ function inferLanguageFromPath(filePath) {
1561
+ const fileName = path.posix.basename(filePath).toLowerCase();
1562
+ if (fileName === "skill.md" || fileName.endsWith(".md"))
1563
+ return "markdown";
1564
+ if (fileName.endsWith(".ts"))
1565
+ return "typescript";
1566
+ if (fileName.endsWith(".tsx"))
1567
+ return "tsx";
1568
+ if (fileName.endsWith(".js"))
1569
+ return "javascript";
1570
+ if (fileName.endsWith(".jsx"))
1571
+ return "jsx";
1572
+ if (fileName.endsWith(".json"))
1573
+ return "json";
1574
+ if (fileName.endsWith(".yml") || fileName.endsWith(".yaml"))
1575
+ return "yaml";
1576
+ if (fileName.endsWith(".sh"))
1577
+ return "bash";
1578
+ if (fileName.endsWith(".py"))
1579
+ return "python";
1580
+ if (fileName.endsWith(".html"))
1581
+ return "html";
1582
+ if (fileName.endsWith(".css"))
1583
+ return "css";
1584
+ return null;
1585
+ }
1586
+ function isMarkdownPath(filePath) {
1587
+ const fileName = path.posix.basename(filePath).toLowerCase();
1588
+ return fileName === "skill.md" || fileName.endsWith(".md");
1589
+ }
1590
+ function deriveSkillSourceInfo(skill) {
1591
+ const metadata = getSkillMeta(skill);
1592
+ const localSkillDir = normalizeSkillDirectory(skill);
1593
+ if (isBundledRudderSourceKind(asString(metadata.sourceKind))) {
1594
+ return {
1595
+ editable: false,
1596
+ editableReason: "Bundled Rudder skills are read-only.",
1597
+ sourceLabel: "Bundled by Rudder",
1598
+ sourceBadge: "rudder",
1599
+ sourcePath: null,
1600
+ };
1601
+ }
1602
+ if (asString(metadata.sourceKind) === "community_preset") {
1603
+ return {
1604
+ editable: false,
1605
+ editableReason: "Community preset skills are read-only.",
1606
+ sourceLabel: "Community preset",
1607
+ sourceBadge: "community",
1608
+ sourcePath: null,
1609
+ };
1610
+ }
1611
+ if (skill.sourceType === "skills_sh") {
1612
+ const owner = asString(metadata.owner) ?? null;
1613
+ const repo = asString(metadata.repo) ?? null;
1614
+ return {
1615
+ editable: false,
1616
+ editableReason: "Skills.sh-managed skills are read-only.",
1617
+ sourceLabel: skill.sourceLocator ?? (owner && repo ? `${owner}/${repo}` : null),
1618
+ sourceBadge: "skills_sh",
1619
+ sourcePath: null,
1620
+ };
1621
+ }
1622
+ if (skill.sourceType === "github") {
1623
+ const owner = asString(metadata.owner) ?? null;
1624
+ const repo = asString(metadata.repo) ?? null;
1625
+ return {
1626
+ editable: false,
1627
+ editableReason: "Remote GitHub skills are read-only. Fork or import locally to edit them.",
1628
+ sourceLabel: owner && repo ? `${owner}/${repo}` : skill.sourceLocator,
1629
+ sourceBadge: "github",
1630
+ sourcePath: null,
1631
+ };
1632
+ }
1633
+ if (skill.sourceType === "url") {
1634
+ return {
1635
+ editable: false,
1636
+ editableReason: "URL-based skills are read-only. Save them locally to edit them.",
1637
+ sourceLabel: skill.sourceLocator,
1638
+ sourceBadge: "url",
1639
+ sourcePath: null,
1640
+ };
1641
+ }
1642
+ if (skill.sourceType === "local_path") {
1643
+ const managedRoot = resolveManagedSkillsRoot(skill.orgId);
1644
+ const projectName = asString(metadata.projectName);
1645
+ const workspaceName = asString(metadata.workspaceName);
1646
+ const isProjectScan = metadata.sourceKind === "project_scan";
1647
+ if (localSkillDir && localSkillDir.startsWith(managedRoot)) {
1648
+ return {
1649
+ editable: true,
1650
+ editableReason: null,
1651
+ sourceLabel: "Rudder workspace",
1652
+ sourceBadge: "rudder",
1653
+ sourcePath: managedRoot,
1654
+ };
1655
+ }
1656
+ return {
1657
+ editable: true,
1658
+ editableReason: null,
1659
+ sourceLabel: isProjectScan
1660
+ ? [projectName, workspaceName].filter((value) => Boolean(value)).join(" / ")
1661
+ || skill.sourceLocator
1662
+ : skill.sourceLocator,
1663
+ sourceBadge: "local",
1664
+ sourcePath: null,
1665
+ };
1666
+ }
1667
+ return {
1668
+ editable: false,
1669
+ editableReason: "This skill source is read-only.",
1670
+ sourceLabel: skill.sourceLocator,
1671
+ sourceBadge: "catalog",
1672
+ sourcePath: null,
1673
+ };
1674
+ }
1675
+ function enrichSkill(skill, attachedAgentCount, usedByAgents = []) {
1676
+ const source = deriveSkillSourceInfo(skill);
1677
+ return {
1678
+ ...skill,
1679
+ attachedAgentCount,
1680
+ usedByAgents,
1681
+ ...source,
1682
+ workspaceEditPath: resolveWorkspaceEditPath(skill.orgId, normalizeSkillDirectory(skill)),
1683
+ };
1684
+ }
1685
+ function toCompanySkillListItem(skill, attachedAgentCount) {
1686
+ const source = deriveSkillSourceInfo(skill);
1687
+ return {
1688
+ id: skill.id,
1689
+ orgId: skill.orgId,
1690
+ key: skill.key,
1691
+ slug: skill.slug,
1692
+ name: skill.name,
1693
+ description: skill.description,
1694
+ sourceType: skill.sourceType,
1695
+ sourceLocator: skill.sourceLocator,
1696
+ sourceRef: skill.sourceRef,
1697
+ trustLevel: skill.trustLevel,
1698
+ compatibility: skill.compatibility,
1699
+ fileInventory: skill.fileInventory,
1700
+ createdAt: skill.createdAt,
1701
+ updatedAt: skill.updatedAt,
1702
+ attachedAgentCount,
1703
+ editable: source.editable,
1704
+ editableReason: source.editableReason,
1705
+ sourceLabel: source.sourceLabel,
1706
+ sourceBadge: source.sourceBadge,
1707
+ sourcePath: source.sourcePath,
1708
+ workspaceEditPath: resolveWorkspaceEditPath(skill.orgId, normalizeSkillDirectory(skill)),
1709
+ };
1710
+ }
1711
+ function compareOrganizationSkillListItems(left, right) {
1712
+ const leftBundledSlug = getBundledRudderSkillSlug(left.key);
1713
+ const rightBundledSlug = getBundledRudderSkillSlug(right.key);
1714
+ if (leftBundledSlug && rightBundledSlug) {
1715
+ const leftIndex = RUDDER_BUNDLED_SKILL_SLUGS.findIndex((slug) => slug === leftBundledSlug);
1716
+ const rightIndex = RUDDER_BUNDLED_SKILL_SLUGS.findIndex((slug) => slug === rightBundledSlug);
1717
+ if (leftIndex !== rightIndex)
1718
+ return leftIndex - rightIndex;
1719
+ }
1720
+ else if (leftBundledSlug) {
1721
+ return -1;
1722
+ }
1723
+ else if (rightBundledSlug) {
1724
+ return 1;
1725
+ }
1726
+ const byName = left.name.localeCompare(right.name, undefined, { sensitivity: "base" });
1727
+ if (byName !== 0)
1728
+ return byName;
1729
+ return left.key.localeCompare(right.key, undefined, { sensitivity: "base" });
1730
+ }
1731
+ export function organizationSkillService(db) {
1732
+ const agents = agentService(db);
1733
+ const enabledSkills = agentEnabledSkillsService(db);
1734
+ const projects = projectService(db);
1735
+ async function getAgentWorkspaceRow(orgId, agentId) {
1736
+ const row = await db
1737
+ .select({
1738
+ id: agentRows.id,
1739
+ name: agentRows.name,
1740
+ workspaceKey: agentRows.workspaceKey,
1741
+ })
1742
+ .from(agentRows)
1743
+ .where(and(eq(agentRows.orgId, orgId), eq(agentRows.id, agentId)))
1744
+ .then((rows) => rows[0] ?? null);
1745
+ if (!row)
1746
+ throw notFound("Agent not found");
1747
+ return row;
1748
+ }
1749
+ async function ensureBundledSkills(orgId) {
1750
+ for (const skillsRoot of resolveBundledSkillsRoot()) {
1751
+ const stats = await fs.stat(skillsRoot).catch(() => null);
1752
+ if (!stats?.isDirectory())
1753
+ continue;
1754
+ let bundledSkillCandidates = [];
1755
+ try {
1756
+ bundledSkillCandidates = await Promise.all(RUDDER_BUNDLED_SKILL_SLUGS.map(async (slug) => {
1757
+ const skillDir = path.join(skillsRoot, slug);
1758
+ const skillStats = await fs.stat(skillDir).catch(() => null);
1759
+ if (!skillStats?.isDirectory())
1760
+ return null;
1761
+ const imported = await readLocalSkillImportFromDirectory(orgId, skillDir, {
1762
+ metadata: {
1763
+ sourceKind: "rudder_bundled",
1764
+ skillKey: `rudder/${slug}`,
1765
+ },
1766
+ }).catch(() => null);
1767
+ if (!imported)
1768
+ return null;
1769
+ return {
1770
+ ...imported,
1771
+ key: `rudder/${slug}`,
1772
+ slug,
1773
+ metadata: {
1774
+ ...(imported.metadata ?? {}),
1775
+ sourceKind: "rudder_bundled",
1776
+ skillKey: `rudder/${slug}`,
1777
+ },
1778
+ };
1779
+ }));
1780
+ }
1781
+ catch {
1782
+ bundledSkillCandidates = [];
1783
+ }
1784
+ const bundledSkills = bundledSkillCandidates.filter((skill) => skill !== null);
1785
+ if (bundledSkills.length === 0)
1786
+ continue;
1787
+ const persisted = await upsertImportedSkills(orgId, bundledSkills);
1788
+ const existingRows = await db
1789
+ .select({
1790
+ id: organizationSkills.id,
1791
+ key: organizationSkills.key,
1792
+ metadata: organizationSkills.metadata,
1793
+ })
1794
+ .from(organizationSkills)
1795
+ .where(eq(organizationSkills.orgId, orgId));
1796
+ const staleBundledIds = listStaleBundledSkillIds(existingRows, Array.from(CANONICAL_BUNDLED_SKILL_KEYS));
1797
+ if (staleBundledIds.length > 0) {
1798
+ const staleKeys = existingRows
1799
+ .filter((row) => staleBundledIds.includes(row.id))
1800
+ .map((row) => String(row.key));
1801
+ await enabledSkills.removeSkillKeys(orgId, staleKeys);
1802
+ for (const staleId of staleBundledIds) {
1803
+ await db.delete(organizationSkills).where(eq(organizationSkills.id, staleId));
1804
+ }
1805
+ }
1806
+ return persisted;
1807
+ }
1808
+ return [];
1809
+ }
1810
+ /**
1811
+ * Seed community presets into the org library without upgrading them to
1812
+ * bundled Rudder runtime skills.
1813
+ *
1814
+ * Reasoning:
1815
+ * - Presets should behave like optional organization skills in agent pickers.
1816
+ * - Existing non-preset rows with the same canonical key win, so a local
1817
+ * org-managed replacement is not overwritten by refresh.
1818
+ * - Presets can come from repo-owned packages or GitHub-managed sources
1819
+ * without changing their product meaning in the UI.
1820
+ *
1821
+ * Traceability:
1822
+ * - doc/plans/2026-04-19-community-preset-skills.md
1823
+ */
1824
+ async function ensureCommunityPresetSkills(orgId) {
1825
+ const currentCommunityPresetKeys = COMMUNITY_PRESET_SKILL_SLUGS.map((slug) => `organization/${orgId}/${slug}`);
1826
+ const localPresetRoots = resolveCommunityPresetSkillsRoot();
1827
+ const presetCandidates = await Promise.all(COMMUNITY_PRESET_SKILLS.map(async (preset) => {
1828
+ const skillKey = `organization/${orgId}/${preset.slug}`;
1829
+ if (preset.source === "repo") {
1830
+ for (const skillsRoot of localPresetRoots) {
1831
+ const stats = await fs.stat(skillsRoot).catch(() => null);
1832
+ if (!stats?.isDirectory())
1833
+ continue;
1834
+ const skillDir = path.join(skillsRoot, preset.slug);
1835
+ const skillStats = await fs.stat(skillDir).catch(() => null);
1836
+ if (!skillStats?.isDirectory())
1837
+ continue;
1838
+ const imported = await readLocalSkillImportFromDirectory(orgId, skillDir, {
1839
+ metadata: {
1840
+ sourceKind: "community_preset",
1841
+ skillKey,
1842
+ },
1843
+ }).catch(() => null);
1844
+ if (!imported)
1845
+ continue;
1846
+ return {
1847
+ ...imported,
1848
+ key: skillKey,
1849
+ slug: preset.slug,
1850
+ metadata: {
1851
+ ...(imported.metadata ?? {}),
1852
+ sourceKind: "community_preset",
1853
+ skillKey,
1854
+ },
1855
+ };
1856
+ }
1857
+ return null;
1858
+ }
1859
+ const imported = await readUrlSkillImports(orgId, preset.sourceUrl, preset.slug)
1860
+ .then((result) => result.skills.find((skill) => skill.slug === preset.slug) ?? result.skills[0] ?? null)
1861
+ .catch(() => null);
1862
+ const resolvedImported = imported ?? await readCommunityPresetFallbackImport(orgId, preset.slug, skillKey, preset.sourceUrl);
1863
+ if (!resolvedImported)
1864
+ return null;
1865
+ return {
1866
+ ...resolvedImported,
1867
+ key: skillKey,
1868
+ slug: preset.slug,
1869
+ metadata: {
1870
+ ...(resolvedImported.metadata ?? {}),
1871
+ sourceKind: "community_preset",
1872
+ skillKey,
1873
+ },
1874
+ };
1875
+ }));
1876
+ const presetSkills = presetCandidates.filter((skill) => skill !== null);
1877
+ const existingRows = await db
1878
+ .select({
1879
+ id: organizationSkills.id,
1880
+ key: organizationSkills.key,
1881
+ metadata: organizationSkills.metadata,
1882
+ })
1883
+ .from(organizationSkills)
1884
+ .where(eq(organizationSkills.orgId, orgId));
1885
+ const existingByKey = new Map(existingRows.map((row) => [String(row.key), row]));
1886
+ const toPersist = presetSkills.filter((skill) => {
1887
+ const existing = existingByKey.get(skill.key);
1888
+ if (!existing)
1889
+ return true;
1890
+ return asString(existing.metadata?.sourceKind) === "community_preset";
1891
+ });
1892
+ const persisted = toPersist.length > 0 ? await upsertImportedSkills(orgId, toPersist) : [];
1893
+ const stalePresetIds = listStaleCommunityPresetSkillIds(existingRows, currentCommunityPresetKeys);
1894
+ if (stalePresetIds.length > 0) {
1895
+ const staleKeys = existingRows
1896
+ .filter((row) => stalePresetIds.includes(row.id))
1897
+ .map((row) => String(row.key));
1898
+ await enabledSkills.removeSkillKeys(orgId, staleKeys);
1899
+ for (const staleId of stalePresetIds) {
1900
+ await db.delete(organizationSkills).where(eq(organizationSkills.id, staleId));
1901
+ }
1902
+ }
1903
+ return persisted;
1904
+ }
1905
+ async function pruneMissingLocalPathSkills(orgId) {
1906
+ const rows = await db
1907
+ .select()
1908
+ .from(organizationSkills)
1909
+ .where(eq(organizationSkills.orgId, orgId));
1910
+ const skills = rows.map((row) => toCompanySkill(row));
1911
+ const missingIds = new Set(await findMissingLocalSkillIds(skills));
1912
+ if (missingIds.size === 0)
1913
+ return;
1914
+ for (const skill of skills) {
1915
+ if (!missingIds.has(skill.id))
1916
+ continue;
1917
+ await db
1918
+ .delete(organizationSkills)
1919
+ .where(eq(organizationSkills.id, skill.id));
1920
+ await fs.rm(resolveRuntimeSkillMaterializedPath(orgId, skill), { recursive: true, force: true });
1921
+ }
1922
+ }
1923
+ async function backfillMissingSkillDescriptions(orgId) {
1924
+ const rows = await db
1925
+ .select()
1926
+ .from(organizationSkills)
1927
+ .where(eq(organizationSkills.orgId, orgId));
1928
+ for (const row of rows) {
1929
+ if (normalizeSkillDescription(row.description))
1930
+ continue;
1931
+ const skill = toCompanySkill(row);
1932
+ let description = normalizeSkillDescription(parseFrontmatterMarkdown(skill.markdown).frontmatter.description);
1933
+ if (!description) {
1934
+ const skillDir = normalizeSkillDirectory(skill);
1935
+ if (skillDir) {
1936
+ const markdown = await fs.readFile(path.join(skillDir, "SKILL.md"), "utf8").catch(() => null);
1937
+ if (markdown) {
1938
+ description = normalizeSkillDescription(parseFrontmatterMarkdown(markdown).frontmatter.description);
1939
+ }
1940
+ }
1941
+ }
1942
+ if (!description)
1943
+ continue;
1944
+ await db
1945
+ .update(organizationSkills)
1946
+ .set({ description })
1947
+ .where(eq(organizationSkills.id, skill.id));
1948
+ }
1949
+ }
1950
+ async function ensureSkillInventoryCurrent(orgId) {
1951
+ const existingRefresh = skillInventoryRefreshPromises.get(orgId);
1952
+ if (existingRefresh) {
1953
+ await existingRefresh;
1954
+ return;
1955
+ }
1956
+ const refreshPromise = (async () => {
1957
+ await ensureBundledSkills(orgId);
1958
+ await ensureCommunityPresetSkills(orgId);
1959
+ await pruneMissingLocalPathSkills(orgId);
1960
+ await backfillMissingSkillDescriptions(orgId);
1961
+ })();
1962
+ skillInventoryRefreshPromises.set(orgId, refreshPromise);
1963
+ try {
1964
+ await refreshPromise;
1965
+ }
1966
+ finally {
1967
+ if (skillInventoryRefreshPromises.get(orgId) === refreshPromise) {
1968
+ skillInventoryRefreshPromises.delete(orgId);
1969
+ }
1970
+ }
1971
+ }
1972
+ function resolveSkillMode(agentRuntimeType) {
1973
+ return ADAPTER_SKILL_HOME_DEFINITIONS[agentRuntimeType]?.mode ?? "unsupported";
1974
+ }
1975
+ function selectionRefsToOrganizationSkillKeys(skills, selectionRefs) {
1976
+ const selected = new Set(getRequiredBundledSkillKeys(skills));
1977
+ const skillKeys = new Set(skills.map((skill) => skill.key));
1978
+ for (const selectionRef of selectionRefs) {
1979
+ const parsed = parseSelectionKey(selectionRef);
1980
+ if (parsed.sourceClass === "bundled" && parsed.orgKey && skillKeys.has(parsed.orgKey)) {
1981
+ selected.add(parsed.orgKey);
1982
+ continue;
1983
+ }
1984
+ if (parsed.sourceClass === "organization" && parsed.orgKey && skillKeys.has(parsed.orgKey)) {
1985
+ selected.add(parsed.orgKey);
1986
+ }
1987
+ }
1988
+ return Array.from(selected).sort((left, right) => left.localeCompare(right));
1989
+ }
1990
+ function normalizeStoredSelectionRefs(orgId, agent, skills, refs) {
1991
+ if (!agent)
1992
+ return [];
1993
+ const normalized = refs
1994
+ .map((reference) => normalizeSelectionRef(reference, skills, orgId, agent.agentRuntimeType))
1995
+ .filter((value) => Boolean(value))
1996
+ .filter((value) => parseSelectionKey(value).sourceClass !== "bundled");
1997
+ return sortUniqueSelectionRefs(normalized);
1998
+ }
1999
+ async function migrateLegacyEnabledSkills(orgId, agent, skills) {
2000
+ if (!agent?.id)
2001
+ return [];
2002
+ const currentRefs = await enabledSkills.listKeys(agent.id);
2003
+ if (currentRefs.length > 0) {
2004
+ const normalizedCurrentRefs = normalizeStoredSelectionRefs(orgId, agent, skills, currentRefs);
2005
+ if (!arraysEqual(currentRefs, normalizedCurrentRefs)) {
2006
+ await enabledSkills.replaceKeys(orgId, agent.id, normalizedCurrentRefs);
2007
+ }
2008
+ return normalizedCurrentRefs;
2009
+ }
2010
+ const legacyPreference = readRudderSkillSyncPreference(agent.agentRuntimeConfig ?? {});
2011
+ if (!legacyPreference.explicit && legacyPreference.desiredSkills.length === 0) {
2012
+ return [];
2013
+ }
2014
+ const migratedRefs = normalizeStoredSelectionRefs(orgId, agent, skills, legacyPreference.desiredSkills);
2015
+ if (migratedRefs.length > 0) {
2016
+ await enabledSkills.addMissingKeys(orgId, agent.id, migratedRefs);
2017
+ }
2018
+ await agents.update(agent.id, {
2019
+ agentRuntimeConfig: writeRudderSkillSyncPreference(agent.agentRuntimeConfig ?? {}, []),
2020
+ });
2021
+ return migratedRefs;
2022
+ }
2023
+ async function getEnabledSkillSelectionMap(orgId, skills, agentRows) {
2024
+ const selectionMap = await enabledSkills.listKeyMap(agentRows.map((agent) => agent.id));
2025
+ for (const agent of agentRows) {
2026
+ const existing = selectionMap.get(agent.id);
2027
+ if (existing) {
2028
+ const normalizedExisting = normalizeStoredSelectionRefs(orgId, agent, skills, existing);
2029
+ if (!arraysEqual(existing, normalizedExisting)) {
2030
+ await enabledSkills.replaceKeys(orgId, agent.id, normalizedExisting);
2031
+ }
2032
+ selectionMap.set(agent.id, normalizedExisting);
2033
+ continue;
2034
+ }
2035
+ selectionMap.set(agent.id, await migrateLegacyEnabledSkills(orgId, agent, skills));
2036
+ }
2037
+ return selectionMap;
2038
+ }
2039
+ async function list(orgId) {
2040
+ const rows = await listFull(orgId);
2041
+ const agentRows = await agents.list(orgId);
2042
+ const enabledSkillSelectionMap = await getEnabledSkillSelectionMap(orgId, rows, agentRows);
2043
+ return rows.map((skill) => {
2044
+ const attachedAgentCount = agentRows.filter((agent) => {
2045
+ const desiredSelectionRefs = enabledSkillSelectionMap.get(agent.id) ?? [];
2046
+ return selectionRefsToOrganizationSkillKeys(rows, desiredSelectionRefs).includes(skill.key);
2047
+ }).length;
2048
+ return toCompanySkillListItem(skill, attachedAgentCount);
2049
+ }).sort(compareOrganizationSkillListItems);
2050
+ }
2051
+ async function listFull(orgId) {
2052
+ await ensureSkillInventoryCurrent(orgId);
2053
+ const rows = await db
2054
+ .select()
2055
+ .from(organizationSkills)
2056
+ .where(eq(organizationSkills.orgId, orgId))
2057
+ .orderBy(asc(organizationSkills.name), asc(organizationSkills.key));
2058
+ return rows.map((row) => toCompanySkill(row));
2059
+ }
2060
+ async function buildAgentSkillCatalogEntries(orgId, agentId, agentRuntimeType, runtimeConfig, skills) {
2061
+ const entries = [];
2062
+ for (const skill of skills) {
2063
+ const bundled = isBundledRudderSkillKey(skill.key);
2064
+ entries.push({
2065
+ key: skill.slug,
2066
+ selectionKey: bundled
2067
+ ? buildBundledSelectionKey(skill.key)
2068
+ : buildOrganizationSelectionKey(skill.key),
2069
+ runtimeName: skill.slug,
2070
+ description: skill.description ?? null,
2071
+ desired: bundled,
2072
+ configurable: !bundled,
2073
+ alwaysEnabled: bundled,
2074
+ managed: true,
2075
+ state: bundled ? "configured" : "available",
2076
+ sourceClass: bundled ? "bundled" : "organization",
2077
+ origin: "organization_managed",
2078
+ originLabel: bundled ? "Bundled by Rudder" : "Organization skill",
2079
+ locationLabel: null,
2080
+ readOnly: bundled,
2081
+ sourcePath: normalizeSkillDirectory(skill),
2082
+ targetPath: null,
2083
+ workspaceEditPath: resolveWorkspaceEditPath(orgId, normalizeSkillDirectory(skill)),
2084
+ detail: bundled ? "Always loaded by Rudder for every agent run." : null,
2085
+ organizationSkillKey: skill.key,
2086
+ runtimeSourcePath: null,
2087
+ });
2088
+ }
2089
+ if (agentId) {
2090
+ const agentWorkspace = await getAgentWorkspaceRow(orgId, agentId);
2091
+ entries.push(...await readDiscoveredSkillEntries(orgId, resolveAgentSkillsDir(orgId, agentWorkspace), (slug) => buildAgentSelectionKey(slug), {
2092
+ sourceClass: "agent_home",
2093
+ originLabel: "Agent skill",
2094
+ locationLabel: "AGENT_HOME/skills",
2095
+ }));
2096
+ }
2097
+ const globalRoot = path.join(resolveConfiguredHomeDir(runtimeConfig), ".agents", "skills");
2098
+ entries.push(...await readDiscoveredSkillEntries(orgId, globalRoot, (slug) => buildGlobalSelectionKey(slug), {
2099
+ sourceClass: "global",
2100
+ originLabel: "Global skill",
2101
+ locationLabel: "~/.agents/skills",
2102
+ }));
2103
+ const adapterHome = ADAPTER_SKILL_HOME_DEFINITIONS[agentRuntimeType];
2104
+ if (adapterHome) {
2105
+ entries.push(...await readDiscoveredSkillEntries(orgId, adapterHome.resolveRoot(runtimeConfig), (slug) => buildAdapterSelectionKey(agentRuntimeType, slug), {
2106
+ sourceClass: "adapter_home",
2107
+ originLabel: "Adapter skill",
2108
+ locationLabel: adapterHome.locationLabel,
2109
+ }));
2110
+ }
2111
+ return entries.sort((left, right) => left.key.localeCompare(right.key) || left.selectionKey.localeCompare(right.selectionKey));
2112
+ }
2113
+ function validateDesiredSelectionRefs(entries, requestedDesiredRefs) {
2114
+ const bySelectionKey = new Map(entries.map((entry) => [entry.selectionKey, entry]));
2115
+ const desiredRefs = sortUniqueSelectionRefs(requestedDesiredRefs).filter((selectionRef) => {
2116
+ const entry = bySelectionKey.get(selectionRef);
2117
+ return entry?.configurable ?? true;
2118
+ });
2119
+ const unknownRefs = desiredRefs.filter((selectionRef) => !bySelectionKey.has(selectionRef));
2120
+ if (unknownRefs.length > 0) {
2121
+ throw unprocessable(`Invalid skill selection (unknown references: ${unknownRefs.join(", ")}).`);
2122
+ }
2123
+ const conflicts = new Map();
2124
+ for (const selectionRef of desiredRefs) {
2125
+ const entry = bySelectionKey.get(selectionRef);
2126
+ if (!entry)
2127
+ continue;
2128
+ const existing = conflicts.get(entry.key) ?? [];
2129
+ existing.push(selectionRef);
2130
+ conflicts.set(entry.key, existing);
2131
+ }
2132
+ const conflictMessages = Array.from(conflicts.entries())
2133
+ .filter(([, refs]) => refs.length > 1)
2134
+ .map(([skillKey, refs]) => `${skillKey}: ${refs.join(", ")}`);
2135
+ if (conflictMessages.length > 0) {
2136
+ throw unprocessable(`Invalid skill selection (conflicting skill names: ${conflictMessages.join("; ")}).`);
2137
+ }
2138
+ return {
2139
+ desiredSkills: desiredRefs,
2140
+ warnings: [],
2141
+ };
2142
+ }
2143
+ async function getEnabledSkillSelectionRefsForAgent(orgId, agent, skills) {
2144
+ const availableSkills = skills ?? await listFull(orgId);
2145
+ return migrateLegacyEnabledSkills(orgId, agent, availableSkills);
2146
+ }
2147
+ async function buildAgentSkillSnapshot(agent, runtimeConfig) {
2148
+ if (!agent) {
2149
+ return {
2150
+ agentRuntimeType: "",
2151
+ supported: false,
2152
+ mode: "unsupported",
2153
+ desiredSkills: [],
2154
+ entries: [],
2155
+ warnings: [],
2156
+ };
2157
+ }
2158
+ const skills = await listFull(agent.orgId);
2159
+ const desiredSkills = await getEnabledSkillSelectionRefsForAgent(agent.orgId, agent, skills);
2160
+ const entries = await buildAgentSkillCatalogEntries(agent.orgId, agent.id, agent.agentRuntimeType, runtimeConfig, skills);
2161
+ const applied = applyDesiredSelectionsToCatalog(entries, desiredSkills, agent.agentRuntimeType);
2162
+ return {
2163
+ agentRuntimeType: agent.agentRuntimeType,
2164
+ supported: resolveSkillMode(agent.agentRuntimeType) !== "unsupported",
2165
+ mode: resolveSkillMode(agent.agentRuntimeType),
2166
+ desiredSkills: applied.desiredSkills,
2167
+ entries: applied.entries,
2168
+ warnings: applied.warnings,
2169
+ };
2170
+ }
2171
+ function resolveRequestedSelectionRefAgainstCatalog(reference, skills, catalogEntries, agent) {
2172
+ const trimmed = reference.trim();
2173
+ if (!trimmed)
2174
+ return { selectionKey: null, ambiguous: false };
2175
+ const parsed = parseSelectionKey(trimmed);
2176
+ if (parsed.sourceClass) {
2177
+ return {
2178
+ selectionKey: catalogEntries.some((entry) => entry.selectionKey === trimmed) ? trimmed : null,
2179
+ ambiguous: false,
2180
+ };
2181
+ }
2182
+ const normalized = normalizeSelectionRef(trimmed, skills, agent.orgId, agent.agentRuntimeType);
2183
+ if (normalized) {
2184
+ const normalizedParsed = parseSelectionKey(normalized);
2185
+ if (normalizedParsed.sourceClass === "bundled") {
2186
+ return { selectionKey: null, ambiguous: false };
2187
+ }
2188
+ if (catalogEntries.some((entry) => entry.selectionKey === normalized)) {
2189
+ return { selectionKey: normalized, ambiguous: false };
2190
+ }
2191
+ }
2192
+ const externalMatches = catalogEntries.filter((entry) => entry.configurable
2193
+ && !entry.organizationSkillKey
2194
+ && (entry.key === normalizeSkillSlug(trimmed)
2195
+ || entry.runtimeName?.trim().toLowerCase() === trimmed.toLowerCase()));
2196
+ if (externalMatches.length === 1) {
2197
+ return { selectionKey: externalMatches[0].selectionKey, ambiguous: false };
2198
+ }
2199
+ if (externalMatches.length > 1) {
2200
+ return { selectionKey: null, ambiguous: true };
2201
+ }
2202
+ return { selectionKey: null, ambiguous: false };
2203
+ }
2204
+ async function resolveDesiredSkillSelectionForAgent(agent, runtimeConfig, requestedDesiredSkills) {
2205
+ if (!agent) {
2206
+ return { desiredSkills: [], warnings: [] };
2207
+ }
2208
+ const skills = await listFull(agent.orgId);
2209
+ const catalogEntries = await buildAgentSkillCatalogEntries(agent.orgId, agent.id, agent.agentRuntimeType, runtimeConfig, skills);
2210
+ const ambiguousRefs = new Set();
2211
+ const unresolvedRefs = new Set();
2212
+ const requestedRefs = sortUniqueSelectionRefs((requestedDesiredSkills ?? []).flatMap((reference) => {
2213
+ const resolved = resolveRequestedSelectionRefAgainstCatalog(reference, skills, catalogEntries, agent);
2214
+ if (resolved.ambiguous) {
2215
+ ambiguousRefs.add(reference.trim());
2216
+ return [];
2217
+ }
2218
+ if (!resolved.selectionKey) {
2219
+ const normalized = normalizeSelectionRef(reference, skills, agent.orgId, agent.agentRuntimeType);
2220
+ if (!normalized || parseSelectionKey(normalized).sourceClass !== "bundled") {
2221
+ unresolvedRefs.add(reference.trim());
2222
+ }
2223
+ return [];
2224
+ }
2225
+ return [resolved.selectionKey];
2226
+ }));
2227
+ if (ambiguousRefs.size > 0 || unresolvedRefs.size > 0) {
2228
+ const problems = [];
2229
+ if (ambiguousRefs.size > 0) {
2230
+ problems.push(`ambiguous references: ${sortUniqueSelectionRefs(Array.from(ambiguousRefs)).join(", ")}`);
2231
+ }
2232
+ if (unresolvedRefs.size > 0) {
2233
+ problems.push(`unknown references: ${sortUniqueSelectionRefs(Array.from(unresolvedRefs)).join(", ")}`);
2234
+ }
2235
+ throw unprocessable(`Invalid skill selection (${problems.join("; ")}).`);
2236
+ }
2237
+ return validateDesiredSelectionRefs(catalogEntries, requestedRefs);
2238
+ }
2239
+ async function listRealizedSkillEntriesForAgent(orgId, agentId, agentRuntimeType, runtimeConfig, selectionRefs, options = {}) {
2240
+ const skills = await listFull(orgId);
2241
+ const skillByKey = new Map(skills.map((skill) => [skill.key, skill]));
2242
+ const catalogEntries = await buildAgentSkillCatalogEntries(orgId, agentId, agentRuntimeType, runtimeConfig, skills);
2243
+ const bySelectionKey = new Map(catalogEntries.map((entry) => [entry.selectionKey, entry]));
2244
+ const desiredSet = new Set(selectionRefs);
2245
+ const activeEntries = catalogEntries.filter((entry) => entry.alwaysEnabled || desiredSet.has(entry.selectionKey));
2246
+ const out = [];
2247
+ for (const entry of activeEntries) {
2248
+ if (entry.organizationSkillKey) {
2249
+ const skill = skillByKey.get(entry.organizationSkillKey);
2250
+ if (!skill)
2251
+ continue;
2252
+ let source = normalizeSkillDirectory(skill);
2253
+ if (!source) {
2254
+ source = options.materializeMissing === false
2255
+ ? resolveRuntimeSkillMaterializedPath(orgId, skill)
2256
+ : await materializeRuntimeSkillFiles(orgId, skill).catch(() => null);
2257
+ }
2258
+ if (!source)
2259
+ continue;
2260
+ out.push({
2261
+ key: entry.selectionKey,
2262
+ runtimeName: entry.key,
2263
+ source,
2264
+ name: skill.name,
2265
+ description: skill.description,
2266
+ });
2267
+ continue;
2268
+ }
2269
+ const catalogEntry = bySelectionKey.get(entry.selectionKey);
2270
+ if (!catalogEntry?.runtimeSourcePath)
2271
+ continue;
2272
+ out.push({
2273
+ key: entry.selectionKey,
2274
+ runtimeName: entry.key,
2275
+ source: catalogEntry.runtimeSourcePath,
2276
+ name: catalogEntry.runtimeName ?? entry.key,
2277
+ description: catalogEntry.description ?? null,
2278
+ });
2279
+ }
2280
+ return out.sort((left, right) => left.key.localeCompare(right.key));
2281
+ }
2282
+ async function getById(id) {
2283
+ const row = await db
2284
+ .select()
2285
+ .from(organizationSkills)
2286
+ .where(eq(organizationSkills.id, id))
2287
+ .then((rows) => rows[0] ?? null);
2288
+ return row ? toCompanySkill(row) : null;
2289
+ }
2290
+ async function getByKey(orgId, key) {
2291
+ const exactRow = await db
2292
+ .select()
2293
+ .from(organizationSkills)
2294
+ .where(and(eq(organizationSkills.orgId, orgId), eq(organizationSkills.key, key)))
2295
+ .then((rows) => rows[0] ?? null);
2296
+ if (exactRow)
2297
+ return toCompanySkill(exactRow);
2298
+ const bundledSlug = getBundledRudderSkillSlug(key);
2299
+ if (!bundledSlug)
2300
+ return null;
2301
+ const canonicalKey = toBundledRudderSkillKey(bundledSlug);
2302
+ const legacyKey = canonicalKey ? `rudder/${canonicalKey}` : null;
2303
+ const alternateKey = key === canonicalKey ? legacyKey : canonicalKey;
2304
+ if (!alternateKey)
2305
+ return null;
2306
+ const alternateRow = await db
2307
+ .select()
2308
+ .from(organizationSkills)
2309
+ .where(and(eq(organizationSkills.orgId, orgId), eq(organizationSkills.key, alternateKey)))
2310
+ .then((rows) => rows[0] ?? null);
2311
+ return alternateRow ? toCompanySkill(alternateRow) : null;
2312
+ }
2313
+ async function usage(orgId, key) {
2314
+ const skills = await listFull(orgId);
2315
+ const agentRows = await agents.list(orgId);
2316
+ const enabledSkillSelectionMap = await getEnabledSkillSelectionMap(orgId, skills, agentRows);
2317
+ const desiredAgents = agentRows.filter((agent) => selectionRefsToOrganizationSkillKeys(skills, enabledSkillSelectionMap.get(agent.id) ?? []).includes(key));
2318
+ return Promise.all(desiredAgents.map(async (agent) => {
2319
+ const actualState = resolveSkillMode(agent.agentRuntimeType) === "unsupported"
2320
+ ? "unsupported"
2321
+ : "configured";
2322
+ return {
2323
+ id: agent.id,
2324
+ name: agent.name,
2325
+ urlKey: agent.urlKey,
2326
+ agentRuntimeType: agent.agentRuntimeType,
2327
+ desired: true,
2328
+ actualState,
2329
+ };
2330
+ }));
2331
+ }
2332
+ async function detail(orgId, id) {
2333
+ await ensureSkillInventoryCurrent(orgId);
2334
+ const skill = await getById(id);
2335
+ if (!skill || skill.orgId !== orgId)
2336
+ return null;
2337
+ const usedByAgents = await usage(orgId, skill.key);
2338
+ return enrichSkill(skill, usedByAgents.length, usedByAgents);
2339
+ }
2340
+ async function updateStatus(orgId, skillId) {
2341
+ await ensureSkillInventoryCurrent(orgId);
2342
+ const skill = await getById(skillId);
2343
+ if (!skill || skill.orgId !== orgId)
2344
+ return null;
2345
+ if (skill.sourceType !== "github" && skill.sourceType !== "skills_sh") {
2346
+ return {
2347
+ supported: false,
2348
+ reason: "Only GitHub-managed skills support update checks.",
2349
+ trackingRef: null,
2350
+ currentRef: skill.sourceRef ?? null,
2351
+ latestRef: null,
2352
+ hasUpdate: false,
2353
+ };
2354
+ }
2355
+ const metadata = getSkillMeta(skill);
2356
+ const owner = asString(metadata.owner);
2357
+ const repo = asString(metadata.repo);
2358
+ const trackingRef = asString(metadata.trackingRef) ?? asString(metadata.ref);
2359
+ if (!owner || !repo || !trackingRef) {
2360
+ return {
2361
+ supported: false,
2362
+ reason: "This GitHub skill does not have enough metadata to track updates.",
2363
+ trackingRef: trackingRef ?? null,
2364
+ currentRef: skill.sourceRef ?? null,
2365
+ latestRef: null,
2366
+ hasUpdate: false,
2367
+ };
2368
+ }
2369
+ const latestRef = await resolveGitHubCommitSha(owner, repo, trackingRef);
2370
+ return {
2371
+ supported: true,
2372
+ reason: null,
2373
+ trackingRef,
2374
+ currentRef: skill.sourceRef ?? null,
2375
+ latestRef,
2376
+ hasUpdate: latestRef !== (skill.sourceRef ?? null),
2377
+ };
2378
+ }
2379
+ async function readFile(orgId, skillId, relativePath) {
2380
+ await ensureSkillInventoryCurrent(orgId);
2381
+ const skill = await getById(skillId);
2382
+ if (!skill || skill.orgId !== orgId)
2383
+ return null;
2384
+ const normalizedPath = normalizePortablePath(relativePath || "SKILL.md");
2385
+ const fileEntry = skill.fileInventory.find((entry) => entry.path === normalizedPath);
2386
+ if (!fileEntry) {
2387
+ throw notFound("Skill file not found");
2388
+ }
2389
+ const source = deriveSkillSourceInfo(skill);
2390
+ let content = "";
2391
+ if (skill.sourceType === "local_path" || skill.sourceType === "catalog") {
2392
+ const absolutePath = resolveLocalSkillFilePath(skill, normalizedPath);
2393
+ if (absolutePath) {
2394
+ content = await fs.readFile(absolutePath, "utf8");
2395
+ }
2396
+ else if (normalizedPath === "SKILL.md") {
2397
+ content = skill.markdown;
2398
+ }
2399
+ else {
2400
+ throw notFound("Skill file not found");
2401
+ }
2402
+ }
2403
+ else if (skill.sourceType === "github" || skill.sourceType === "skills_sh") {
2404
+ const metadata = getSkillMeta(skill);
2405
+ const owner = asString(metadata.owner);
2406
+ const repo = asString(metadata.repo);
2407
+ const ref = skill.sourceRef ?? asString(metadata.ref) ?? "main";
2408
+ const repoSkillDir = normalizeGitHubSkillDirectory(asString(metadata.repoSkillDir), skill.slug);
2409
+ if (!owner || !repo) {
2410
+ throw unprocessable("Skill source metadata is incomplete.");
2411
+ }
2412
+ const repoPath = normalizePortablePath(path.posix.join(repoSkillDir, normalizedPath));
2413
+ content = await fetchText(resolveRawGitHubUrl(owner, repo, ref, repoPath));
2414
+ }
2415
+ else if (skill.sourceType === "url") {
2416
+ if (normalizedPath !== "SKILL.md") {
2417
+ throw notFound("This skill source only exposes SKILL.md");
2418
+ }
2419
+ content = skill.markdown;
2420
+ }
2421
+ else {
2422
+ throw unprocessable("Unsupported skill source.");
2423
+ }
2424
+ return {
2425
+ skillId: skill.id,
2426
+ path: normalizedPath,
2427
+ kind: fileEntry.kind,
2428
+ content,
2429
+ language: inferLanguageFromPath(normalizedPath),
2430
+ markdown: isMarkdownPath(normalizedPath),
2431
+ editable: source.editable,
2432
+ };
2433
+ }
2434
+ async function createLocalSkill(orgId, input) {
2435
+ const slug = normalizeSkillSlug(input.slug ?? input.name) ?? "skill";
2436
+ const managedRoot = resolveManagedSkillsRoot(orgId);
2437
+ const skillDir = path.resolve(managedRoot, slug);
2438
+ const skillFilePath = path.resolve(skillDir, "SKILL.md");
2439
+ await fs.mkdir(skillDir, { recursive: true });
2440
+ const markdown = buildDraftSkillMarkdown(input);
2441
+ await fs.writeFile(skillFilePath, markdown, "utf8");
2442
+ const parsed = parseFrontmatterMarkdown(markdown);
2443
+ const imported = await upsertImportedSkills(orgId, [{
2444
+ key: `organization/${orgId}/${slug}`,
2445
+ slug,
2446
+ name: asString(parsed.frontmatter.name) ?? input.name,
2447
+ description: normalizeSkillDescription(parsed.frontmatter.description) ?? input.description?.trim() ?? null,
2448
+ markdown,
2449
+ sourceType: "local_path",
2450
+ sourceLocator: skillDir,
2451
+ sourceRef: null,
2452
+ trustLevel: "markdown_only",
2453
+ compatibility: "compatible",
2454
+ fileInventory: [{ path: "SKILL.md", kind: "skill" }],
2455
+ metadata: { sourceKind: "managed_local" },
2456
+ }]);
2457
+ return imported[0];
2458
+ }
2459
+ async function createAgentPrivateSkill(orgId, agentId, input) {
2460
+ const slug = normalizeSkillSlug(input.slug ?? input.name) ?? "skill";
2461
+ const agentWorkspace = await getAgentWorkspaceRow(orgId, agentId);
2462
+ const skillsRoot = resolveAgentSkillsDir(orgId, agentWorkspace);
2463
+ const skillDir = path.resolve(skillsRoot, slug);
2464
+ const relativePath = path.relative(skillsRoot, skillDir);
2465
+ if (relativePath.startsWith("..")
2466
+ || path.isAbsolute(relativePath)
2467
+ || relativePath === ""
2468
+ || relativePath === ".") {
2469
+ throw unprocessable("Invalid agent skill slug.");
2470
+ }
2471
+ const skillFilePath = path.resolve(skillDir, "SKILL.md");
2472
+ const existing = await statPath(skillFilePath);
2473
+ if (existing?.isFile()) {
2474
+ throw conflict(`Agent skill already exists: ${slug}`);
2475
+ }
2476
+ await fs.mkdir(skillDir, { recursive: true });
2477
+ const markdown = buildDraftSkillMarkdown(input);
2478
+ await fs.writeFile(skillFilePath, markdown, "utf8");
2479
+ const parsed = parseFrontmatterMarkdown(markdown);
2480
+ const description = normalizeSkillDescription(parsed.frontmatter.description) ?? input.description?.trim() ?? null;
2481
+ return buildAgentPrivateSkillEntry(orgId, slug, skillDir, description);
2482
+ }
2483
+ async function updateFile(orgId, skillId, relativePath, content) {
2484
+ await ensureSkillInventoryCurrent(orgId);
2485
+ const skill = await getById(skillId);
2486
+ if (!skill || skill.orgId !== orgId)
2487
+ throw notFound("Skill not found");
2488
+ const source = deriveSkillSourceInfo(skill);
2489
+ if (!source.editable || skill.sourceType !== "local_path") {
2490
+ throw unprocessable(source.editableReason ?? "This skill cannot be edited.");
2491
+ }
2492
+ const normalizedPath = normalizePortablePath(relativePath);
2493
+ const absolutePath = resolveLocalSkillFilePath(skill, normalizedPath);
2494
+ if (!absolutePath)
2495
+ throw notFound("Skill file not found");
2496
+ await fs.mkdir(path.dirname(absolutePath), { recursive: true });
2497
+ await fs.writeFile(absolutePath, content, "utf8");
2498
+ if (normalizedPath === "SKILL.md") {
2499
+ const parsed = parseFrontmatterMarkdown(content);
2500
+ await db
2501
+ .update(organizationSkills)
2502
+ .set({
2503
+ name: asString(parsed.frontmatter.name) ?? skill.name,
2504
+ description: normalizeSkillDescription(parsed.frontmatter.description) ?? skill.description,
2505
+ markdown: content,
2506
+ updatedAt: new Date(),
2507
+ })
2508
+ .where(eq(organizationSkills.id, skill.id));
2509
+ }
2510
+ else {
2511
+ await db
2512
+ .update(organizationSkills)
2513
+ .set({ updatedAt: new Date() })
2514
+ .where(eq(organizationSkills.id, skill.id));
2515
+ }
2516
+ const detail = await readFile(orgId, skillId, normalizedPath);
2517
+ if (!detail)
2518
+ throw notFound("Skill file not found");
2519
+ return detail;
2520
+ }
2521
+ async function syncWorkspaceFileChange(orgId, workspaceFilePath, content) {
2522
+ await ensureSkillInventoryCurrent(orgId);
2523
+ const normalizedWorkspaceFilePath = normalizePortablePath(workspaceFilePath);
2524
+ if (!normalizedWorkspaceFilePath)
2525
+ return;
2526
+ const absoluteTargetPath = path.resolve(resolveOrganizationWorkspaceRoot(orgId), normalizedWorkspaceFilePath);
2527
+ const skills = await listFull(orgId);
2528
+ const matchingSkill = skills.find((skill) => {
2529
+ const skillDir = normalizeSkillDirectory(skill);
2530
+ if (!skillDir)
2531
+ return false;
2532
+ const absoluteSkillDir = path.resolve(skillDir);
2533
+ return absoluteTargetPath === path.resolve(absoluteSkillDir, "SKILL.md")
2534
+ || absoluteTargetPath.startsWith(`${absoluteSkillDir}${path.sep}`);
2535
+ });
2536
+ if (!matchingSkill)
2537
+ return;
2538
+ const updatePatch = {
2539
+ updatedAt: new Date(),
2540
+ };
2541
+ if (absoluteTargetPath === path.resolve(normalizeSkillDirectory(matchingSkill), "SKILL.md")) {
2542
+ const parsed = parseFrontmatterMarkdown(content);
2543
+ updatePatch.markdown = content;
2544
+ updatePatch.name = asString(parsed.frontmatter.name) ?? matchingSkill.name;
2545
+ updatePatch.description = normalizeSkillDescription(parsed.frontmatter.description) ?? matchingSkill.description;
2546
+ }
2547
+ await db
2548
+ .update(organizationSkills)
2549
+ .set(updatePatch)
2550
+ .where(eq(organizationSkills.id, matchingSkill.id));
2551
+ }
2552
+ async function installUpdate(orgId, skillId) {
2553
+ await ensureSkillInventoryCurrent(orgId);
2554
+ const skill = await getById(skillId);
2555
+ if (!skill || skill.orgId !== orgId)
2556
+ return null;
2557
+ const status = await updateStatus(orgId, skillId);
2558
+ if (!status?.supported) {
2559
+ throw unprocessable(status?.reason ?? "This skill does not support updates.");
2560
+ }
2561
+ if (!skill.sourceLocator) {
2562
+ throw unprocessable("Skill source locator is missing.");
2563
+ }
2564
+ const result = await readUrlSkillImports(orgId, skill.sourceLocator, skill.slug);
2565
+ const matching = result.skills.find((entry) => entry.key === skill.key) ?? result.skills[0] ?? null;
2566
+ if (!matching) {
2567
+ throw unprocessable(`Skill ${skill.key} could not be re-imported from its source.`);
2568
+ }
2569
+ const imported = await upsertImportedSkills(orgId, [matching]);
2570
+ return imported[0] ?? null;
2571
+ }
2572
+ async function scanProjectWorkspaces(orgId, input = {}) {
2573
+ await ensureSkillInventoryCurrent(orgId);
2574
+ const projectRows = input.projectIds?.length
2575
+ ? await projects.listByIds(orgId, input.projectIds)
2576
+ : await projects.list(orgId);
2577
+ const workspaceFilter = new Set(input.workspaceIds ?? []);
2578
+ const skipped = [];
2579
+ const conflicts = [];
2580
+ const warnings = [];
2581
+ const imported = [];
2582
+ const updated = [];
2583
+ const availableSkills = await listFull(orgId);
2584
+ const acceptedSkills = [...availableSkills];
2585
+ const acceptedByKey = new Map(acceptedSkills.map((skill) => [skill.key, skill]));
2586
+ const scanTargets = [];
2587
+ const scannedProjectIds = new Set();
2588
+ let discovered = 0;
2589
+ const trackWarning = (message) => {
2590
+ warnings.push(message);
2591
+ return message;
2592
+ };
2593
+ const upsertAcceptedSkill = (skill) => {
2594
+ const nextIndex = acceptedSkills.findIndex((entry) => entry.id === skill.id || entry.key === skill.key);
2595
+ if (nextIndex >= 0)
2596
+ acceptedSkills[nextIndex] = skill;
2597
+ else
2598
+ acceptedSkills.push(skill);
2599
+ acceptedByKey.set(skill.key, skill);
2600
+ };
2601
+ for (const project of projectRows) {
2602
+ for (const workspace of project.workspaces) {
2603
+ if (workspaceFilter.size > 0 && !workspaceFilter.has(workspace.id))
2604
+ continue;
2605
+ const workspaceCwd = asString(workspace.cwd);
2606
+ if (!workspaceCwd) {
2607
+ skipped.push({
2608
+ projectId: project.id,
2609
+ projectName: project.name,
2610
+ workspaceId: workspace.id,
2611
+ workspaceName: workspace.name,
2612
+ path: null,
2613
+ reason: trackWarning(`Skipped ${project.name} / ${workspace.name}: no local workspace path is configured.`),
2614
+ });
2615
+ continue;
2616
+ }
2617
+ const workspaceStat = await statPath(workspaceCwd);
2618
+ if (!workspaceStat?.isDirectory()) {
2619
+ skipped.push({
2620
+ projectId: project.id,
2621
+ projectName: project.name,
2622
+ workspaceId: workspace.id,
2623
+ workspaceName: workspace.name,
2624
+ path: workspaceCwd,
2625
+ reason: trackWarning(`Skipped ${project.name} / ${workspace.name}: local workspace path is not available at ${workspaceCwd}.`),
2626
+ });
2627
+ continue;
2628
+ }
2629
+ scanTargets.push({
2630
+ projectId: project.id,
2631
+ projectName: project.name,
2632
+ workspaceId: workspace.id,
2633
+ workspaceName: workspace.name,
2634
+ workspaceCwd,
2635
+ });
2636
+ }
2637
+ }
2638
+ for (const target of scanTargets) {
2639
+ scannedProjectIds.add(target.projectId);
2640
+ const directories = await discoverProjectWorkspaceSkillDirectories(target);
2641
+ for (const directory of directories) {
2642
+ discovered += 1;
2643
+ let nextSkill;
2644
+ try {
2645
+ nextSkill = await readLocalSkillImportFromDirectory(orgId, directory.skillDir, {
2646
+ inventoryMode: directory.inventoryMode,
2647
+ metadata: {
2648
+ sourceKind: "project_scan",
2649
+ projectId: target.projectId,
2650
+ projectName: target.projectName,
2651
+ workspaceId: target.workspaceId,
2652
+ workspaceName: target.workspaceName,
2653
+ workspaceCwd: target.workspaceCwd,
2654
+ },
2655
+ });
2656
+ }
2657
+ catch (error) {
2658
+ const message = error instanceof Error ? error.message : String(error);
2659
+ skipped.push({
2660
+ projectId: target.projectId,
2661
+ projectName: target.projectName,
2662
+ workspaceId: target.workspaceId,
2663
+ workspaceName: target.workspaceName,
2664
+ path: directory.skillDir,
2665
+ reason: trackWarning(`Skipped ${directory.skillDir}: ${message}`),
2666
+ });
2667
+ continue;
2668
+ }
2669
+ const normalizedSourceDir = normalizeSourceLocatorDirectory(nextSkill.sourceLocator);
2670
+ const existingByKey = acceptedByKey.get(nextSkill.key) ?? null;
2671
+ if (existingByKey) {
2672
+ const existingSourceDir = normalizeSkillDirectory(existingByKey);
2673
+ if (existingByKey.sourceType !== "local_path"
2674
+ || !existingSourceDir
2675
+ || !normalizedSourceDir
2676
+ || existingSourceDir !== normalizedSourceDir) {
2677
+ conflicts.push({
2678
+ slug: nextSkill.slug,
2679
+ key: nextSkill.key,
2680
+ projectId: target.projectId,
2681
+ projectName: target.projectName,
2682
+ workspaceId: target.workspaceId,
2683
+ workspaceName: target.workspaceName,
2684
+ path: directory.skillDir,
2685
+ existingSkillId: existingByKey.id,
2686
+ existingSkillKey: existingByKey.key,
2687
+ existingSourceLocator: existingByKey.sourceLocator,
2688
+ reason: `Skill key ${nextSkill.key} already points at ${existingByKey.sourceLocator ?? "another source"}.`,
2689
+ });
2690
+ continue;
2691
+ }
2692
+ const persisted = (await upsertImportedSkills(orgId, [nextSkill]))[0];
2693
+ if (!persisted)
2694
+ continue;
2695
+ updated.push(persisted);
2696
+ upsertAcceptedSkill(persisted);
2697
+ continue;
2698
+ }
2699
+ const slugConflict = acceptedSkills.find((skill) => {
2700
+ if (skill.slug !== nextSkill.slug)
2701
+ return false;
2702
+ return normalizeSkillDirectory(skill) !== normalizedSourceDir;
2703
+ });
2704
+ if (slugConflict) {
2705
+ conflicts.push({
2706
+ slug: nextSkill.slug,
2707
+ key: nextSkill.key,
2708
+ projectId: target.projectId,
2709
+ projectName: target.projectName,
2710
+ workspaceId: target.workspaceId,
2711
+ workspaceName: target.workspaceName,
2712
+ path: directory.skillDir,
2713
+ existingSkillId: slugConflict.id,
2714
+ existingSkillKey: slugConflict.key,
2715
+ existingSourceLocator: slugConflict.sourceLocator,
2716
+ reason: `Slug ${nextSkill.slug} is already in use by ${slugConflict.sourceLocator ?? slugConflict.key}.`,
2717
+ });
2718
+ continue;
2719
+ }
2720
+ const persisted = (await upsertImportedSkills(orgId, [nextSkill]))[0];
2721
+ if (!persisted)
2722
+ continue;
2723
+ imported.push(persisted);
2724
+ upsertAcceptedSkill(persisted);
2725
+ }
2726
+ }
2727
+ return {
2728
+ scannedProjects: scannedProjectIds.size,
2729
+ scannedWorkspaces: scanTargets.length,
2730
+ discovered,
2731
+ imported,
2732
+ updated,
2733
+ skipped,
2734
+ conflicts,
2735
+ warnings,
2736
+ };
2737
+ }
2738
+ async function scanLocalSkillRoots(orgId, input = {}) {
2739
+ await ensureSkillInventoryCurrent(orgId);
2740
+ const requestedRoots = input.roots?.length
2741
+ ? input.roots
2742
+ : [path.join(os.homedir(), ".agents")];
2743
+ const roots = Array.from(new Set(requestedRoots
2744
+ .map((root) => root.trim())
2745
+ .filter(Boolean)
2746
+ .map((root) => path.resolve(root))));
2747
+ const skipped = [];
2748
+ const conflicts = [];
2749
+ const warnings = [];
2750
+ const imported = [];
2751
+ const updated = [];
2752
+ const availableSkills = await listFull(orgId);
2753
+ const acceptedSkills = [...availableSkills];
2754
+ const acceptedByKey = new Map(acceptedSkills.map((skill) => [skill.key, skill]));
2755
+ let discovered = 0;
2756
+ const trackWarning = (message) => {
2757
+ warnings.push(message);
2758
+ return message;
2759
+ };
2760
+ const upsertAcceptedSkill = (skill) => {
2761
+ const nextIndex = acceptedSkills.findIndex((entry) => entry.id === skill.id || entry.key === skill.key);
2762
+ if (nextIndex >= 0)
2763
+ acceptedSkills[nextIndex] = skill;
2764
+ else
2765
+ acceptedSkills.push(skill);
2766
+ acceptedByKey.set(skill.key, skill);
2767
+ };
2768
+ for (const root of roots) {
2769
+ const rootStat = await statPath(root);
2770
+ if (!rootStat?.isDirectory()) {
2771
+ skipped.push({
2772
+ root,
2773
+ path: null,
2774
+ reason: trackWarning(`Skipped ${root}: local skill root is not available.`),
2775
+ });
2776
+ continue;
2777
+ }
2778
+ let discoveredSkills;
2779
+ try {
2780
+ discoveredSkills = await readLocalSkillImports(orgId, root);
2781
+ }
2782
+ catch (error) {
2783
+ const message = error instanceof Error ? error.message : String(error);
2784
+ skipped.push({
2785
+ root,
2786
+ path: root,
2787
+ reason: trackWarning(`Skipped ${root}: ${message}`),
2788
+ });
2789
+ continue;
2790
+ }
2791
+ discovered += discoveredSkills.length;
2792
+ for (const nextSkill of discoveredSkills) {
2793
+ nextSkill.metadata = {
2794
+ ...(nextSkill.metadata ?? {}),
2795
+ sourceKind: "local_scan",
2796
+ sourceRoot: root,
2797
+ };
2798
+ const normalizedSourceDir = normalizeSourceLocatorDirectory(nextSkill.sourceLocator);
2799
+ const existingByKey = acceptedByKey.get(nextSkill.key) ?? null;
2800
+ if (existingByKey) {
2801
+ const existingSourceDir = normalizeSkillDirectory(existingByKey);
2802
+ if (existingByKey.sourceType !== "local_path"
2803
+ || !existingSourceDir
2804
+ || !normalizedSourceDir
2805
+ || existingSourceDir !== normalizedSourceDir) {
2806
+ conflicts.push({
2807
+ root,
2808
+ slug: nextSkill.slug,
2809
+ key: nextSkill.key,
2810
+ path: nextSkill.sourceLocator ?? root,
2811
+ existingSkillId: existingByKey.id,
2812
+ existingSkillKey: existingByKey.key,
2813
+ existingSourceLocator: existingByKey.sourceLocator,
2814
+ reason: `Skill key ${nextSkill.key} already points at ${existingByKey.sourceLocator ?? "another source"}.`,
2815
+ });
2816
+ continue;
2817
+ }
2818
+ const persisted = (await upsertImportedSkills(orgId, [nextSkill]))[0];
2819
+ if (!persisted)
2820
+ continue;
2821
+ updated.push(persisted);
2822
+ upsertAcceptedSkill(persisted);
2823
+ continue;
2824
+ }
2825
+ const slugConflict = acceptedSkills.find((skill) => {
2826
+ if (skill.slug !== nextSkill.slug)
2827
+ return false;
2828
+ return normalizeSkillDirectory(skill) !== normalizedSourceDir;
2829
+ });
2830
+ if (slugConflict) {
2831
+ conflicts.push({
2832
+ root,
2833
+ slug: nextSkill.slug,
2834
+ key: nextSkill.key,
2835
+ path: nextSkill.sourceLocator ?? root,
2836
+ existingSkillId: slugConflict.id,
2837
+ existingSkillKey: slugConflict.key,
2838
+ existingSourceLocator: slugConflict.sourceLocator,
2839
+ reason: `Slug ${nextSkill.slug} is already in use by ${slugConflict.sourceLocator ?? slugConflict.key}.`,
2840
+ });
2841
+ continue;
2842
+ }
2843
+ const persisted = (await upsertImportedSkills(orgId, [nextSkill]))[0];
2844
+ if (!persisted)
2845
+ continue;
2846
+ imported.push(persisted);
2847
+ upsertAcceptedSkill(persisted);
2848
+ }
2849
+ }
2850
+ return {
2851
+ scannedRoots: roots.length,
2852
+ discovered,
2853
+ imported,
2854
+ updated,
2855
+ skipped,
2856
+ conflicts,
2857
+ warnings,
2858
+ };
2859
+ }
2860
+ async function materializeCatalogSkillFiles(orgId, skill, normalizedFiles) {
2861
+ const packageDir = skill.packageDir ? normalizePortablePath(skill.packageDir) : null;
2862
+ if (!packageDir)
2863
+ return null;
2864
+ const catalogRoot = path.resolve(resolveManagedSkillsRoot(orgId), "__catalog__");
2865
+ const skillDir = path.resolve(catalogRoot, buildSkillRuntimeName(skill.key, skill.slug));
2866
+ await fs.rm(skillDir, { recursive: true, force: true });
2867
+ await fs.mkdir(skillDir, { recursive: true });
2868
+ for (const entry of skill.fileInventory) {
2869
+ const sourcePath = entry.path === "SKILL.md"
2870
+ ? `${packageDir}/SKILL.md`
2871
+ : `${packageDir}/${entry.path}`;
2872
+ const content = normalizedFiles[sourcePath];
2873
+ if (typeof content !== "string")
2874
+ continue;
2875
+ const targetPath = path.resolve(skillDir, entry.path);
2876
+ await fs.mkdir(path.dirname(targetPath), { recursive: true });
2877
+ await fs.writeFile(targetPath, content, "utf8");
2878
+ }
2879
+ return skillDir;
2880
+ }
2881
+ async function materializeRuntimeSkillFiles(orgId, skill) {
2882
+ const runtimeRoot = path.resolve(resolveManagedSkillsRoot(orgId), "__runtime__");
2883
+ const skillDir = path.resolve(runtimeRoot, buildSkillRuntimeName(skill.key, skill.slug));
2884
+ await fs.rm(skillDir, { recursive: true, force: true });
2885
+ await fs.mkdir(skillDir, { recursive: true });
2886
+ for (const entry of skill.fileInventory) {
2887
+ const detail = await readFile(orgId, skill.id, entry.path).catch(() => null);
2888
+ if (!detail)
2889
+ continue;
2890
+ const targetPath = path.resolve(skillDir, entry.path);
2891
+ await fs.mkdir(path.dirname(targetPath), { recursive: true });
2892
+ await fs.writeFile(targetPath, detail.content, "utf8");
2893
+ }
2894
+ return skillDir;
2895
+ }
2896
+ function resolveRuntimeSkillMaterializedPath(orgId, skill) {
2897
+ const runtimeRoot = path.resolve(resolveManagedSkillsRoot(orgId), "__runtime__");
2898
+ return path.resolve(runtimeRoot, buildSkillRuntimeName(skill.key, skill.slug));
2899
+ }
2900
+ async function listRuntimeSkillEntries(orgId, options = {}) {
2901
+ const skills = await listFull(orgId);
2902
+ const out = [];
2903
+ for (const skill of skills) {
2904
+ let source = normalizeSkillDirectory(skill);
2905
+ if (!source) {
2906
+ source = options.materializeMissing === false
2907
+ ? resolveRuntimeSkillMaterializedPath(orgId, skill)
2908
+ : await materializeRuntimeSkillFiles(orgId, skill).catch(() => null);
2909
+ }
2910
+ if (!source)
2911
+ continue;
2912
+ out.push({
2913
+ key: skill.key,
2914
+ runtimeName: buildSkillRuntimeName(skill.key, skill.slug),
2915
+ source,
2916
+ name: skill.name,
2917
+ description: skill.description,
2918
+ });
2919
+ }
2920
+ out.sort((left, right) => left.key.localeCompare(right.key));
2921
+ return out;
2922
+ }
2923
+ async function importPackageFiles(orgId, files, options) {
2924
+ await ensureSkillInventoryCurrent(orgId);
2925
+ const normalizedFiles = normalizePackageFileMap(files);
2926
+ const importedSkills = readInlineSkillImports(orgId, normalizedFiles);
2927
+ if (importedSkills.length === 0)
2928
+ return [];
2929
+ for (const skill of importedSkills) {
2930
+ if (skill.sourceType !== "catalog")
2931
+ continue;
2932
+ const materializedDir = await materializeCatalogSkillFiles(orgId, skill, normalizedFiles);
2933
+ if (materializedDir) {
2934
+ skill.sourceLocator = materializedDir;
2935
+ }
2936
+ }
2937
+ const conflictStrategy = options?.onConflict ?? "replace";
2938
+ const existingSkills = await listFull(orgId);
2939
+ const existingByKey = new Map(existingSkills.map((skill) => [skill.key, skill]));
2940
+ const existingBySlug = new Map(existingSkills.map((skill) => [normalizeSkillSlug(skill.slug) ?? skill.slug, skill]));
2941
+ const usedSlugs = new Set(existingBySlug.keys());
2942
+ const usedKeys = new Set(existingByKey.keys());
2943
+ const toPersist = [];
2944
+ const prepared = [];
2945
+ const out = [];
2946
+ for (const importedSkill of importedSkills) {
2947
+ const originalKey = importedSkill.key;
2948
+ const originalSlug = importedSkill.slug;
2949
+ const normalizedSlug = normalizeSkillSlug(importedSkill.slug) ?? importedSkill.slug;
2950
+ const existingByIncomingKey = existingByKey.get(importedSkill.key) ?? null;
2951
+ const existingByIncomingSlug = existingBySlug.get(normalizedSlug) ?? null;
2952
+ const conflict = existingByIncomingKey ?? existingByIncomingSlug;
2953
+ if (!conflict || conflictStrategy === "replace") {
2954
+ toPersist.push(importedSkill);
2955
+ prepared.push({
2956
+ skill: importedSkill,
2957
+ originalKey,
2958
+ originalSlug,
2959
+ existingBefore: existingByIncomingKey,
2960
+ actionHint: existingByIncomingKey ? "updated" : "created",
2961
+ reason: existingByIncomingKey ? "Existing skill key matched; replace strategy." : null,
2962
+ });
2963
+ usedSlugs.add(normalizedSlug);
2964
+ usedKeys.add(importedSkill.key);
2965
+ continue;
2966
+ }
2967
+ if (conflictStrategy === "skip") {
2968
+ out.push({
2969
+ skill: conflict,
2970
+ action: "skipped",
2971
+ originalKey,
2972
+ originalSlug,
2973
+ requestedRefs: Array.from(new Set([originalKey, originalSlug])),
2974
+ reason: "Existing skill matched; skip strategy.",
2975
+ });
2976
+ continue;
2977
+ }
2978
+ const renamedSlug = uniqueSkillSlug(normalizedSlug || "skill", usedSlugs);
2979
+ const renamedKey = uniqueImportedSkillKey(orgId, renamedSlug, usedKeys);
2980
+ const renamedSkill = {
2981
+ ...importedSkill,
2982
+ slug: renamedSlug,
2983
+ key: renamedKey,
2984
+ metadata: {
2985
+ ...(importedSkill.metadata ?? {}),
2986
+ skillKey: renamedKey,
2987
+ importedFromSkillKey: originalKey,
2988
+ importedFromSkillSlug: originalSlug,
2989
+ },
2990
+ };
2991
+ toPersist.push(renamedSkill);
2992
+ prepared.push({
2993
+ skill: renamedSkill,
2994
+ originalKey,
2995
+ originalSlug,
2996
+ existingBefore: null,
2997
+ actionHint: "created",
2998
+ reason: `Existing skill matched; renamed to ${renamedSlug}.`,
2999
+ });
3000
+ usedSlugs.add(renamedSlug);
3001
+ usedKeys.add(renamedKey);
3002
+ }
3003
+ if (toPersist.length === 0)
3004
+ return out;
3005
+ const persisted = await upsertImportedSkills(orgId, toPersist);
3006
+ for (let index = 0; index < prepared.length; index += 1) {
3007
+ const persistedSkill = persisted[index];
3008
+ const preparedSkill = prepared[index];
3009
+ if (!persistedSkill || !preparedSkill)
3010
+ continue;
3011
+ out.push({
3012
+ skill: persistedSkill,
3013
+ action: preparedSkill.actionHint,
3014
+ originalKey: preparedSkill.originalKey,
3015
+ originalSlug: preparedSkill.originalSlug,
3016
+ requestedRefs: Array.from(new Set([preparedSkill.originalKey, preparedSkill.originalSlug])),
3017
+ reason: preparedSkill.reason,
3018
+ });
3019
+ }
3020
+ return out;
3021
+ }
3022
+ async function upsertImportedSkills(orgId, imported) {
3023
+ const out = [];
3024
+ for (const skill of imported) {
3025
+ const existing = await getByKey(orgId, skill.key);
3026
+ const existingMeta = existing ? getSkillMeta(existing) : {};
3027
+ const incomingMeta = skill.metadata && isPlainRecord(skill.metadata) ? skill.metadata : {};
3028
+ const incomingOwner = asString(incomingMeta.owner);
3029
+ const incomingRepo = asString(incomingMeta.repo);
3030
+ const incomingKind = asString(incomingMeta.sourceKind);
3031
+ if (existing
3032
+ && isBundledRudderSourceKind(asString(existingMeta.sourceKind))
3033
+ && incomingKind === "github"
3034
+ && incomingOwner === "rudder"
3035
+ && incomingRepo === "rudder") {
3036
+ out.push(existing);
3037
+ continue;
3038
+ }
3039
+ const metadata = {
3040
+ ...(skill.metadata ?? {}),
3041
+ skillKey: skill.key,
3042
+ };
3043
+ const values = {
3044
+ orgId,
3045
+ key: skill.key,
3046
+ slug: skill.slug,
3047
+ name: skill.name,
3048
+ description: skill.description,
3049
+ markdown: skill.markdown,
3050
+ sourceType: skill.sourceType,
3051
+ sourceLocator: skill.sourceLocator,
3052
+ sourceRef: skill.sourceRef,
3053
+ trustLevel: skill.trustLevel,
3054
+ compatibility: skill.compatibility,
3055
+ fileInventory: serializeFileInventory(skill.fileInventory),
3056
+ metadata,
3057
+ updatedAt: new Date(),
3058
+ };
3059
+ const row = existing
3060
+ ? await db
3061
+ .update(organizationSkills)
3062
+ .set(values)
3063
+ .where(eq(organizationSkills.id, existing.id))
3064
+ .returning()
3065
+ .then((rows) => rows[0] ?? null)
3066
+ : await db
3067
+ .insert(organizationSkills)
3068
+ .values(values)
3069
+ .returning()
3070
+ .then((rows) => rows[0] ?? null);
3071
+ if (!row)
3072
+ throw notFound("Failed to persist organization skill");
3073
+ out.push(toCompanySkill(row));
3074
+ }
3075
+ return out;
3076
+ }
3077
+ async function importFromSource(orgId, source) {
3078
+ await ensureSkillInventoryCurrent(orgId);
3079
+ const parsed = parseSkillImportSourceInput(source);
3080
+ const local = !/^https?:\/\//i.test(parsed.resolvedSource);
3081
+ const { skills, warnings } = local
3082
+ ? {
3083
+ skills: (await readLocalSkillImports(orgId, parsed.resolvedSource))
3084
+ .filter((skill) => !parsed.requestedSkillSlug || skill.slug === parsed.requestedSkillSlug),
3085
+ warnings: parsed.warnings,
3086
+ }
3087
+ : await readUrlSkillImports(orgId, parsed.resolvedSource, parsed.requestedSkillSlug)
3088
+ .then((result) => ({
3089
+ skills: result.skills,
3090
+ warnings: [...parsed.warnings, ...result.warnings],
3091
+ }));
3092
+ const filteredSkills = parsed.requestedSkillSlug
3093
+ ? skills.filter((skill) => skill.slug === parsed.requestedSkillSlug)
3094
+ : skills;
3095
+ if (filteredSkills.length === 0) {
3096
+ throw unprocessable(parsed.requestedSkillSlug
3097
+ ? `Skill ${parsed.requestedSkillSlug} was not found in the provided source.`
3098
+ : "No skills were found in the provided source.");
3099
+ }
3100
+ // Override sourceType/sourceLocator for skills imported via skills.sh
3101
+ if (parsed.originalSkillsShUrl) {
3102
+ for (const skill of filteredSkills) {
3103
+ skill.sourceType = "skills_sh";
3104
+ skill.sourceLocator = parsed.originalSkillsShUrl;
3105
+ if (skill.metadata) {
3106
+ skill.metadata.sourceKind = "skills_sh";
3107
+ }
3108
+ skill.key = deriveCanonicalSkillKey(orgId, skill);
3109
+ }
3110
+ }
3111
+ const imported = await upsertImportedSkills(orgId, filteredSkills);
3112
+ return { imported, warnings };
3113
+ }
3114
+ async function deleteSkill(orgId, skillId) {
3115
+ const row = await db
3116
+ .select()
3117
+ .from(organizationSkills)
3118
+ .where(and(eq(organizationSkills.id, skillId), eq(organizationSkills.orgId, orgId)))
3119
+ .then((rows) => rows[0] ?? null);
3120
+ if (!row)
3121
+ return null;
3122
+ const skill = toCompanySkill(row);
3123
+ // Remove from any agent enabled skills that reference this skill
3124
+ await enabledSkills.removeSkillKeys(orgId, [skill.key]);
3125
+ // Delete DB row
3126
+ await db
3127
+ .delete(organizationSkills)
3128
+ .where(eq(organizationSkills.id, skillId));
3129
+ // Clean up materialized runtime files
3130
+ await fs.rm(resolveRuntimeSkillMaterializedPath(orgId, skill), { recursive: true, force: true });
3131
+ return skill;
3132
+ }
3133
+ return {
3134
+ list,
3135
+ listFull,
3136
+ getById,
3137
+ getByKey,
3138
+ resolveRequestedSkillKeys: async (orgId, requestedReferences) => {
3139
+ const skills = await listFull(orgId);
3140
+ return resolveRequestedSkillKeysOrThrow(skills, requestedReferences, orgId);
3141
+ },
3142
+ detail,
3143
+ updateStatus,
3144
+ readFile,
3145
+ updateFile,
3146
+ syncWorkspaceFileChange,
3147
+ createLocalSkill,
3148
+ createAgentPrivateSkill,
3149
+ deleteSkill,
3150
+ importFromSource,
3151
+ scanProjectWorkspaces,
3152
+ scanLocalSkillRoots,
3153
+ importPackageFiles,
3154
+ installUpdate,
3155
+ listRuntimeSkillEntries,
3156
+ mergeWithRequiredSkillKeys: async (orgId, skillKeys) => {
3157
+ const skills = await listFull(orgId);
3158
+ return sortUniqueSelectionRefs(skillKeys.flatMap((skillKey) => {
3159
+ const normalized = normalizeSelectionRef(skillKey, skills, orgId, "claude_local");
3160
+ if (!normalized)
3161
+ return [];
3162
+ return parseSelectionKey(normalized).sourceClass === "bundled" ? [] : [normalized];
3163
+ }));
3164
+ },
3165
+ getEnabledSkillKeysForAgent: async (orgId, agent) => getEnabledSkillSelectionRefsForAgent(orgId, agent),
3166
+ buildAgentSkillSnapshot,
3167
+ resolveDesiredSkillSelectionForAgent,
3168
+ listRealizedSkillEntriesForAgent,
3169
+ replaceEnabledSkillKeysForAgent: async (orgId, agentId, skillKeys) => enabledSkills.replaceKeys(orgId, agentId, sortUniqueSelectionRefs(skillKeys)),
3170
+ };
3171
+ }
3172
+ //# sourceMappingURL=organization-skills.js.map