@capybara-hq/kernel 0.1.0-rc.3 → 0.1.0-rc.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (604) hide show
  1. package/bootstrap.json +61 -5
  2. package/dist/admin/admin.controller.d.ts +47 -16
  3. package/dist/admin/admin.controller.js +44 -19
  4. package/dist/admin/extensions.controller.d.ts +24 -3
  5. package/dist/admin/extensions.controller.js +48 -8
  6. package/dist/admin/setup-lock.d.ts +1 -1
  7. package/dist/admin/setup-lock.js +1 -1
  8. package/dist/admin/setup.controller.d.ts +1 -1
  9. package/dist/admin/setup.controller.js +1 -1
  10. package/dist/admin/setup.service.d.ts +4 -4
  11. package/dist/admin/setup.service.js +8 -8
  12. package/dist/agents/agent-lookup.d.ts +19 -0
  13. package/dist/agents/agent-lookup.js +21 -0
  14. package/dist/agents/agent-profile.service.d.ts +29 -0
  15. package/dist/agents/agent-profile.service.js +117 -0
  16. package/dist/agents/agents.controller.d.ts +168 -3
  17. package/dist/agents/agents.controller.js +201 -12
  18. package/dist/agents/agents.module.d.ts +4 -1
  19. package/dist/agents/agents.module.js +36 -6
  20. package/dist/agents/agents.service.d.ts +64 -27
  21. package/dist/agents/agents.service.js +199 -74
  22. package/dist/agents/definition.d.ts +53 -0
  23. package/dist/agents/definition.js +55 -0
  24. package/dist/agents/from-template.d.ts +106 -0
  25. package/dist/agents/from-template.js +649 -0
  26. package/dist/agents/from-template.service.d.ts +60 -0
  27. package/dist/agents/from-template.service.js +161 -0
  28. package/dist/agents/instruction-files.d.ts +60 -0
  29. package/dist/agents/instruction-files.js +111 -0
  30. package/dist/agents/models.controller.d.ts +9 -3
  31. package/dist/agents/models.controller.js +19 -4
  32. package/dist/agents/org-templates.d.ts +176 -0
  33. package/dist/agents/org-templates.js +827 -0
  34. package/dist/agents/pending-connector-requests.d.ts +77 -0
  35. package/dist/agents/pending-connector-requests.js +215 -0
  36. package/dist/agents/pending-connectors.controller.d.ts +39 -0
  37. package/dist/agents/pending-connectors.controller.js +91 -0
  38. package/dist/agents/pending-connectors.service.d.ts +62 -0
  39. package/dist/agents/pending-connectors.service.js +282 -0
  40. package/dist/agents/profile.d.ts +96 -0
  41. package/dist/agents/profile.js +51 -0
  42. package/dist/agents/readiness.controller.d.ts +26 -0
  43. package/dist/agents/readiness.controller.js +56 -0
  44. package/dist/agents/templates.controller.d.ts +86 -5
  45. package/dist/agents/templates.controller.js +171 -7
  46. package/dist/agents/templates.d.ts +127 -23
  47. package/dist/agents/templates.js +476 -53
  48. package/dist/background/background.controller.d.ts +38 -0
  49. package/dist/background/background.controller.js +87 -0
  50. package/dist/background/background.module.d.ts +10 -0
  51. package/dist/background/background.module.js +39 -0
  52. package/dist/background/finish.d.ts +44 -0
  53. package/dist/background/finish.js +94 -0
  54. package/dist/background/launch-lock.d.ts +15 -0
  55. package/dist/background/launch-lock.js +40 -0
  56. package/dist/background/launch.d.ts +36 -0
  57. package/dist/background/launch.js +70 -0
  58. package/dist/background/poll.job.d.ts +56 -0
  59. package/dist/background/poll.job.js +190 -0
  60. package/dist/background/render.d.ts +23 -0
  61. package/dist/background/render.js +48 -0
  62. package/dist/background/session.d.ts +48 -0
  63. package/dist/background/session.js +79 -0
  64. package/dist/background/status.d.ts +35 -0
  65. package/dist/background/status.js +57 -0
  66. package/dist/background/stop.d.ts +68 -0
  67. package/dist/background/stop.js +243 -0
  68. package/dist/background/store.d.ts +162 -0
  69. package/dist/background/store.js +357 -0
  70. package/dist/background/store.module.d.ts +6 -0
  71. package/dist/background/store.module.js +22 -0
  72. package/dist/background/tasks.service.d.ts +77 -0
  73. package/dist/background/tasks.service.js +211 -0
  74. package/dist/background/wake-rules.d.ts +66 -0
  75. package/dist/background/wake-rules.js +113 -0
  76. package/dist/background/wake.d.ts +30 -0
  77. package/dist/background/wake.js +63 -0
  78. package/dist/catalog/admin-catalog.controller.d.ts +129 -30
  79. package/dist/catalog/admin-catalog.controller.js +213 -42
  80. package/dist/catalog/catalog-content.d.ts +58 -32
  81. package/dist/catalog/catalog-content.js +34 -8
  82. package/dist/catalog/catalog-import.module.d.ts +7 -0
  83. package/dist/catalog/catalog-import.module.js +60 -0
  84. package/dist/catalog/catalog-items.d.ts +111 -7
  85. package/dist/catalog/catalog-items.js +279 -13
  86. package/dist/catalog/catalog-scope.service.d.ts +260 -0
  87. package/dist/catalog/catalog-scope.service.js +1116 -0
  88. package/dist/catalog/catalog.module.d.ts +7 -9
  89. package/dist/catalog/catalog.module.js +41 -31
  90. package/dist/catalog/catalog.service.d.ts +101 -29
  91. package/dist/catalog/catalog.service.js +104 -106
  92. package/dist/catalog/claude/agents.js +2 -0
  93. package/dist/catalog/cli.d.ts +11 -1
  94. package/dist/catalog/cli.js +26 -1
  95. package/dist/catalog/component-promotion.d.ts +96 -0
  96. package/dist/catalog/component-promotion.js +395 -0
  97. package/dist/catalog/component-scope.controller.d.ts +152 -0
  98. package/dist/catalog/component-scope.controller.js +287 -0
  99. package/dist/catalog/component-scope.service.d.ts +303 -0
  100. package/dist/catalog/component-scope.service.js +936 -0
  101. package/dist/catalog/component-state.d.ts +174 -0
  102. package/dist/catalog/component-state.js +437 -0
  103. package/dist/catalog/job-ids.d.ts +30 -0
  104. package/dist/catalog/job-ids.js +25 -0
  105. package/dist/catalog/marketplace-fetch.d.ts +1 -1
  106. package/dist/catalog/marketplaces.controller.d.ts +22 -5
  107. package/dist/catalog/marketplaces.controller.js +56 -7
  108. package/dist/catalog/marketplaces.service.d.ts +54 -14
  109. package/dist/catalog/marketplaces.service.js +71 -22
  110. package/dist/catalog/org-catalog.controller.d.ts +125 -34
  111. package/dist/catalog/org-catalog.controller.js +181 -65
  112. package/dist/catalog/org-catalog.service.d.ts +65 -33
  113. package/dist/catalog/org-catalog.service.js +324 -157
  114. package/dist/catalog/org-extension-switch.d.ts +41 -0
  115. package/dist/catalog/org-extension-switch.js +115 -0
  116. package/dist/catalog/org-extension.controller.d.ts +119 -0
  117. package/dist/catalog/org-extension.controller.js +266 -0
  118. package/dist/catalog/org-plugin-uploads.controller.d.ts +98 -0
  119. package/dist/catalog/org-plugin-uploads.controller.js +213 -0
  120. package/dist/catalog/org-plugin-uploads.d.ts +63 -0
  121. package/dist/catalog/org-plugin-uploads.js +116 -0
  122. package/dist/catalog/owned-items.d.ts +184 -0
  123. package/dist/catalog/owned-items.js +789 -0
  124. package/dist/catalog/owned-plugin-cleanup.d.ts +56 -0
  125. package/dist/catalog/owned-plugin-cleanup.js +194 -0
  126. package/dist/catalog/ownership.d.ts +172 -0
  127. package/dist/catalog/ownership.js +326 -0
  128. package/dist/catalog/platform-components.d.ts +221 -0
  129. package/dist/catalog/platform-components.js +761 -0
  130. package/dist/catalog/platform-migration.d.ts +115 -0
  131. package/dist/catalog/platform-migration.js +582 -0
  132. package/dist/catalog/plugin-import.d.ts +178 -34
  133. package/dist/catalog/plugin-import.js +623 -83
  134. package/dist/catalog/plugin-install.d.ts +185 -41
  135. package/dist/catalog/plugin-install.js +758 -126
  136. package/dist/catalog/plugin-upgrade.d.ts +260 -225
  137. package/dist/catalog/plugin-upgrade.js +1148 -1137
  138. package/dist/catalog/request-rules.d.ts +65 -0
  139. package/dist/catalog/request-rules.js +217 -0
  140. package/dist/catalog/requests.service.d.ts +193 -118
  141. package/dist/catalog/requests.service.js +526 -343
  142. package/dist/catalog/reserved-names.d.ts +8 -0
  143. package/dist/catalog/reserved-names.js +42 -0
  144. package/dist/catalog/scope-orgs.d.ts +21 -0
  145. package/dist/catalog/scope-orgs.js +67 -0
  146. package/dist/catalog/scope-state.d.ts +35 -0
  147. package/dist/catalog/scope-state.js +87 -0
  148. package/dist/catalog/scope-sync-workers.d.ts +7 -0
  149. package/dist/catalog/scope-sync-workers.js +29 -0
  150. package/dist/catalog/scope-sync.d.ts +176 -0
  151. package/dist/catalog/scope-sync.js +576 -0
  152. package/dist/catalog/scope.d.ts +42 -0
  153. package/dist/catalog/scope.js +42 -0
  154. package/dist/catalog/unshare.d.ts +22 -0
  155. package/dist/catalog/unshare.js +118 -0
  156. package/dist/channels/actions.js +1 -0
  157. package/dist/channels/cards.js +21 -3
  158. package/dist/channels/channels.module.js +2 -0
  159. package/dist/channels/connections.service.d.ts +16 -1
  160. package/dist/channels/connections.service.js +38 -4
  161. package/dist/channels/inbound.d.ts +9 -1
  162. package/dist/channels/inbound.js +67 -5
  163. package/dist/channels/phrases.d.ts +35 -0
  164. package/dist/channels/phrases.js +29 -0
  165. package/dist/channels/threads.d.ts +5 -0
  166. package/dist/channels/threads.js +8 -0
  167. package/dist/config/docs.js +3 -1
  168. package/dist/config/schema.d.ts +24 -2
  169. package/dist/config/schema.js +145 -19
  170. package/dist/conversations/access.d.ts +6 -4
  171. package/dist/conversations/access.js +29 -5
  172. package/dist/conversations/agent-tree.d.ts +46 -0
  173. package/dist/conversations/agent-tree.js +92 -0
  174. package/dist/conversations/attachments.service.d.ts +30 -0
  175. package/dist/conversations/attachments.service.js +130 -5
  176. package/dist/conversations/conversations.controller.d.ts +79 -23
  177. package/dist/conversations/conversations.controller.js +141 -50
  178. package/dist/conversations/conversations.module.d.ts +1 -1
  179. package/dist/conversations/conversations.module.js +10 -7
  180. package/dist/conversations/conversations.service.d.ts +108 -9
  181. package/dist/conversations/conversations.service.js +237 -30
  182. package/dist/conversations/environment-status.d.ts +24 -0
  183. package/dist/conversations/environment-status.js +71 -0
  184. package/dist/conversations/event-log.d.ts +21 -6
  185. package/dist/conversations/event-log.js +70 -1
  186. package/dist/conversations/events.d.ts +140 -0
  187. package/dist/conversations/events.js +142 -13
  188. package/dist/conversations/queue.d.ts +3 -1
  189. package/dist/conversations/queue.js +13 -2
  190. package/dist/conversations/queue.service.d.ts +1 -1
  191. package/dist/conversations/queue.service.js +8 -1
  192. package/dist/conversations/titles.d.ts +12 -3
  193. package/dist/conversations/titles.js +36 -8
  194. package/dist/conversations/tree.d.ts +17 -0
  195. package/dist/conversations/tree.js +42 -0
  196. package/dist/ctx/create-ctx.d.ts +5 -0
  197. package/dist/ctx/create-ctx.js +15 -5
  198. package/dist/db/kernel-schema.d.ts +420 -20
  199. package/dist/db/pool.d.ts +5 -0
  200. package/dist/db/pool.js +3 -0
  201. package/dist/environments/access.d.ts +41 -0
  202. package/dist/environments/access.js +77 -0
  203. package/dist/environments/conversation-environments.d.ts +61 -0
  204. package/dist/environments/conversation-environments.js +170 -0
  205. package/dist/environments/dto.d.ts +25 -0
  206. package/dist/environments/dto.js +12 -0
  207. package/dist/environments/environments.controller.d.ts +33 -0
  208. package/dist/environments/environments.controller.js +110 -0
  209. package/dist/environments/environments.module.d.ts +8 -0
  210. package/dist/environments/environments.module.js +27 -0
  211. package/dist/environments/environments.service.d.ts +153 -0
  212. package/dist/environments/environments.service.js +541 -0
  213. package/dist/environments/legacy-cleanup.job.d.ts +34 -0
  214. package/dist/environments/legacy-cleanup.job.js +141 -0
  215. package/dist/errors.d.ts +90 -2
  216. package/dist/errors.js +90 -2
  217. package/dist/evals/reconstruct.d.ts +18 -9
  218. package/dist/evals/reconstruct.js +26 -7
  219. package/dist/evals/run-replay.d.ts +7 -2
  220. package/dist/evals/run-replay.js +42 -7
  221. package/dist/evals/step-replay.d.ts +2 -5
  222. package/dist/evals/step-replay.js +13 -7
  223. package/dist/evals/trajectory.js +1 -1
  224. package/dist/evals/trajectory.service.d.ts +8 -3
  225. package/dist/evals/trajectory.service.js +26 -14
  226. package/dist/evals/worker.d.ts +5 -5
  227. package/dist/evals/worker.js +9 -3
  228. package/dist/extensions/admin-ops.d.ts +36 -10
  229. package/dist/extensions/admin-ops.js +67 -42
  230. package/dist/extensions/admin-view.d.ts +39 -10
  231. package/dist/extensions/admin-view.js +111 -20
  232. package/dist/extensions/blobs.js +1 -0
  233. package/dist/extensions/bootstrap.d.ts +17 -4
  234. package/dist/extensions/bootstrap.js +70 -9
  235. package/dist/extensions/cli.d.ts +12 -0
  236. package/dist/extensions/cli.js +11 -2
  237. package/dist/extensions/config-issues.d.ts +13 -1
  238. package/dist/extensions/config-issues.js +22 -5
  239. package/dist/extensions/config-json-schema.d.ts +43 -7
  240. package/dist/extensions/config-json-schema.js +124 -58
  241. package/dist/extensions/deployment-config-store.d.ts +6 -0
  242. package/dist/extensions/deployment-config.d.ts +78 -8
  243. package/dist/extensions/deployment-config.js +172 -34
  244. package/dist/extensions/display-name.d.ts +22 -0
  245. package/dist/extensions/display-name.js +77 -0
  246. package/dist/extensions/effective-config.d.ts +127 -0
  247. package/dist/extensions/effective-config.js +368 -0
  248. package/dist/extensions/extensions.module.js +14 -2
  249. package/dist/extensions/hooks.d.ts +37 -4
  250. package/dist/extensions/hooks.js +82 -16
  251. package/dist/extensions/host.d.ts +45 -2
  252. package/dist/extensions/host.js +112 -16
  253. package/dist/extensions/installs.d.ts +20 -8
  254. package/dist/extensions/installs.js +37 -15
  255. package/dist/extensions/org-config.d.ts +81 -6
  256. package/dist/extensions/org-config.js +195 -44
  257. package/dist/extensions/org-levels.d.ts +37 -0
  258. package/dist/extensions/org-levels.js +71 -0
  259. package/dist/extensions/org-overrides.d.ts +151 -0
  260. package/dist/extensions/org-overrides.js +524 -0
  261. package/dist/extensions/package.d.ts +14 -1
  262. package/dist/extensions/package.js +51 -2
  263. package/dist/extensions/permission-view.d.ts +19 -4
  264. package/dist/extensions/permission-view.js +4 -4
  265. package/dist/extensions/plugin-items.d.ts +21 -0
  266. package/dist/extensions/plugin-items.js +42 -0
  267. package/dist/extensions/point-defaults.controller.d.ts +34 -0
  268. package/dist/extensions/point-defaults.controller.js +71 -0
  269. package/dist/extensions/point-defaults.d.ts +71 -0
  270. package/dist/extensions/point-defaults.js +234 -0
  271. package/dist/extensions/registry.d.ts +1 -1
  272. package/dist/extensions/registry.js +2 -0
  273. package/dist/extensions/resolve.d.ts +5 -1
  274. package/dist/extensions/resolve.js +15 -2
  275. package/dist/files/previewers.d.ts +8 -1
  276. package/dist/files/previewers.js +35 -6
  277. package/dist/http/api.module.js +31 -3
  278. package/dist/http/app.d.ts +11 -2
  279. package/dist/http/app.js +31 -5
  280. package/dist/http/nest-logger.d.ts +6 -5
  281. package/dist/http/nest-logger.js +24 -10
  282. package/dist/identity/accounts.d.ts +29 -29
  283. package/dist/identity/accounts.js +47 -47
  284. package/dist/identity/audit.d.ts +2 -1
  285. package/dist/identity/auth.controller.js +9 -5
  286. package/dist/identity/auth.guard.d.ts +13 -5
  287. package/dist/identity/auth.guard.js +26 -9
  288. package/dist/identity/cookies.d.ts +20 -5
  289. package/dist/identity/cookies.js +44 -6
  290. package/dist/identity/identity.module.d.ts +1 -1
  291. package/dist/identity/identity.module.js +4 -4
  292. package/dist/identity/me.controller.d.ts +5 -1
  293. package/dist/identity/me.controller.js +12 -3
  294. package/dist/identity/principal.d.ts +3 -3
  295. package/dist/identity/principal.js +3 -3
  296. package/dist/identity/sessions.d.ts +12 -0
  297. package/dist/identity/sessions.js +45 -0
  298. package/dist/identity/settings.d.ts +22 -11
  299. package/dist/identity/settings.js +53 -18
  300. package/dist/identity/{enterprise-admin.d.ts → super-admin.d.ts} +5 -5
  301. package/dist/identity/{enterprise-admin.js → super-admin.js} +24 -24
  302. package/dist/inbox/inbox.module.d.ts +4 -1
  303. package/dist/inbox/inbox.module.js +7 -3
  304. package/dist/inbox/inbox.service.d.ts +62 -3
  305. package/dist/inbox/inbox.service.js +74 -4
  306. package/dist/inbox/org-notices.d.ts +63 -0
  307. package/dist/inbox/org-notices.js +91 -0
  308. package/dist/inbox/platform-inbox.controller.d.ts +23 -0
  309. package/dist/inbox/platform-inbox.controller.js +58 -0
  310. package/dist/inbox/platform-inbox.service.d.ts +151 -0
  311. package/dist/inbox/platform-inbox.service.js +263 -0
  312. package/dist/inbox/platform-notices.d.ts +19 -0
  313. package/dist/inbox/platform-notices.js +9 -0
  314. package/dist/index.d.ts +2 -2
  315. package/dist/index.js +1 -1
  316. package/dist/infra/cli/kernel-cli.module.js +9 -1
  317. package/dist/infra/config/kernel-config.service.js +27 -1
  318. package/dist/infra/database/database.module.js +1 -0
  319. package/dist/infra/database/xact-lock.d.ts +1 -1
  320. package/dist/infra/database/xact-lock.js +1 -1
  321. package/dist/infra/events/kernel-events.d.ts +19 -2
  322. package/dist/infra/lifecycle/process-guards.js +4 -0
  323. package/dist/infra/logging/logging.module.d.ts +4 -2
  324. package/dist/infra/logging/logging.module.js +24 -6
  325. package/dist/infra/queue/add-job-once.d.ts +14 -0
  326. package/dist/infra/queue/add-job-once.js +16 -0
  327. package/dist/infra/queue/redis-connection.d.ts +6 -0
  328. package/dist/infra/queue/redis-connection.js +7 -0
  329. package/dist/infra/redis/redis.module.js +6 -2
  330. package/dist/infra/tokens.d.ts +6 -1
  331. package/dist/infra/tokens.js +6 -1
  332. package/dist/kernel.module.js +6 -0
  333. package/dist/lifecycle/kernel-lifecycle.d.ts +1 -1
  334. package/dist/lifecycle/kernel-lifecycle.js +4 -4
  335. package/dist/log.d.ts +13 -1
  336. package/dist/log.js +93 -17
  337. package/dist/models/prices.d.ts +5 -5
  338. package/dist/models/prices.js +4 -4
  339. package/dist/models/purposes.controller.d.ts +6 -4
  340. package/dist/models/purposes.controller.js +13 -7
  341. package/dist/models/purposes.d.ts +43 -9
  342. package/dist/models/purposes.js +48 -18
  343. package/dist/orgs/directory-sync.d.ts +14 -5
  344. package/dist/orgs/directory-sync.js +41 -17
  345. package/dist/orgs/offboarding.d.ts +12 -8
  346. package/dist/orgs/offboarding.js +54 -33
  347. package/dist/orgs/org-lock.d.ts +5 -0
  348. package/dist/orgs/org-lock.js +13 -0
  349. package/dist/orgs/org.guard.d.ts +10 -0
  350. package/dist/orgs/org.guard.js +43 -32
  351. package/dist/orgs/orgs.module.js +3 -0
  352. package/dist/orgs/orgs.service.d.ts +20 -7
  353. package/dist/orgs/orgs.service.js +32 -12
  354. package/dist/orgs/roles.d.ts +1 -1
  355. package/dist/orgs/roles.js +5 -1
  356. package/dist/orgs/settings.controller.d.ts +1 -1
  357. package/dist/orgs/settings.service.d.ts +20 -3
  358. package/dist/orgs/settings.service.js +19 -4
  359. package/dist/overrides.d.ts +3 -0
  360. package/dist/overrides.js +2 -0
  361. package/dist/platform/actor.d.ts +48 -0
  362. package/dist/platform/actor.js +100 -0
  363. package/dist/platform/agent-docs.d.ts +18 -0
  364. package/dist/platform/agent-docs.js +59 -0
  365. package/dist/platform/availability.d.ts +14 -0
  366. package/dist/platform/availability.js +43 -0
  367. package/dist/platform/errors.d.ts +11 -0
  368. package/dist/platform/errors.js +26 -0
  369. package/dist/platform/exclusions.d.ts +12 -0
  370. package/dist/platform/exclusions.js +1387 -0
  371. package/dist/platform/method.d.ts +6 -0
  372. package/dist/platform/method.js +15 -0
  373. package/dist/platform/operation.d.ts +92 -0
  374. package/dist/platform/operation.js +35 -0
  375. package/dist/platform/ops/agent-templates.ops.d.ts +14 -0
  376. package/dist/platform/ops/agent-templates.ops.js +92 -0
  377. package/dist/platform/ops/agents.ops.d.ts +19 -0
  378. package/dist/platform/ops/agents.ops.js +294 -0
  379. package/dist/platform/ops/connectors.ops.d.ts +15 -0
  380. package/dist/platform/ops/connectors.ops.js +126 -0
  381. package/dist/platform/ops/errors.d.ts +11 -0
  382. package/dist/platform/ops/errors.js +22 -0
  383. package/dist/platform/ops/extensions.ops.d.ts +19 -0
  384. package/dist/platform/ops/extensions.ops.js +116 -0
  385. package/dist/platform/ops/marketplaces.ops.d.ts +16 -0
  386. package/dist/platform/ops/marketplaces.ops.js +157 -0
  387. package/dist/platform/ops/paging.d.ts +14 -0
  388. package/dist/platform/ops/paging.js +20 -0
  389. package/dist/platform/ops/platform.ops.d.ts +23 -0
  390. package/dist/platform/ops/platform.ops.js +158 -0
  391. package/dist/platform/ops/plugins.ops.d.ts +33 -0
  392. package/dist/platform/ops/plugins.ops.js +377 -0
  393. package/dist/platform/ops/requests.ops.d.ts +14 -0
  394. package/dist/platform/ops/requests.ops.js +153 -0
  395. package/dist/platform/ops/role.d.ts +4 -0
  396. package/dist/platform/ops/role.js +10 -0
  397. package/dist/platform/ops/skills.ops.d.ts +13 -0
  398. package/dist/platform/ops/skills.ops.js +98 -0
  399. package/dist/platform/ops/summary.d.ts +10 -0
  400. package/dist/platform/ops/summary.js +18 -0
  401. package/dist/platform/platform-ops.module.d.ts +7 -0
  402. package/dist/platform/platform-ops.module.js +55 -0
  403. package/dist/platform/platform.module.d.ts +8 -0
  404. package/dist/platform/platform.module.js +25 -0
  405. package/dist/platform/redact-orgs.d.ts +7 -0
  406. package/dist/platform/redact-orgs.js +52 -0
  407. package/dist/platform/registry.d.ts +30 -0
  408. package/dist/platform/registry.js +111 -0
  409. package/dist/roles/worker-role.d.ts +6 -4
  410. package/dist/roles/worker-role.js +14 -7
  411. package/dist/roles/worker.module.d.ts +1 -1
  412. package/dist/roles/worker.module.js +15 -1
  413. package/dist/runtime/context/build.d.ts +11 -7
  414. package/dist/runtime/context/build.js +46 -19
  415. package/dist/runtime/context/claude-tools.d.ts +3 -1
  416. package/dist/runtime/context/claude-tools.js +8 -6
  417. package/dist/runtime/context/compaction.js +13 -0
  418. package/dist/runtime/context/reminders.d.ts +2 -0
  419. package/dist/runtime/context/reminders.js +2 -0
  420. package/dist/runtime/context/skills.js +9 -2
  421. package/dist/runtime/context/tool-changes.d.ts +27 -0
  422. package/dist/runtime/context/tool-changes.js +60 -0
  423. package/dist/runtime/hook-calls.js +2 -0
  424. package/dist/runtime/langgraph-loop.d.ts +3 -1
  425. package/dist/runtime/langgraph-loop.js +36 -17
  426. package/dist/runtime/loop.d.ts +34 -5
  427. package/dist/runtime/maintenance.d.ts +9 -4
  428. package/dist/runtime/maintenance.js +35 -8
  429. package/dist/runtime/model-call.d.ts +46 -8
  430. package/dist/runtime/model-call.js +72 -21
  431. package/dist/runtime/providers.d.ts +6 -0
  432. package/dist/runtime/providers.js +8 -0
  433. package/dist/runtime/run-control.d.ts +11 -1
  434. package/dist/runtime/run-control.js +12 -0
  435. package/dist/runtime/run-drafts.d.ts +85 -0
  436. package/dist/runtime/run-drafts.js +230 -0
  437. package/dist/runtime/run-jobs.d.ts +3 -5
  438. package/dist/runtime/run-jobs.js +3 -7
  439. package/dist/runtime/run-queue.d.ts +59 -2
  440. package/dist/runtime/run-queue.js +311 -38
  441. package/dist/runtime/run-worker.d.ts +11 -5
  442. package/dist/runtime/run-worker.js +69 -33
  443. package/dist/runtime/runtime.module.js +11 -3
  444. package/dist/runtime/step-log.d.ts +15 -4
  445. package/dist/runtime/step-log.js +24 -7
  446. package/dist/runtime/stream.controller.d.ts +23 -1
  447. package/dist/runtime/stream.controller.js +60 -3
  448. package/dist/runtime/stream.d.ts +4 -1
  449. package/dist/runtime/stream.js +27 -3
  450. package/dist/runtime/subagents/child.d.ts +55 -7
  451. package/dist/runtime/subagents/child.js +105 -7
  452. package/dist/runtime/subagents/definition.d.ts +12 -3
  453. package/dist/runtime/subagents/definition.js +44 -28
  454. package/dist/runtime/subagents/deliveries.d.ts +71 -0
  455. package/dist/runtime/subagents/deliveries.js +228 -0
  456. package/dist/runtime/subagents/dispatch.d.ts +115 -26
  457. package/dist/runtime/subagents/dispatch.js +212 -141
  458. package/dist/runtime/subagents/limits.d.ts +24 -5
  459. package/dist/runtime/subagents/limits.js +40 -6
  460. package/dist/runtime/subagents/messages.d.ts +95 -0
  461. package/dist/runtime/subagents/messages.js +328 -0
  462. package/dist/runtime/subagents/preamble.d.ts +4 -4
  463. package/dist/runtime/subagents/preamble.js +9 -7
  464. package/dist/runtime/subagents/progress.d.ts +8 -6
  465. package/dist/runtime/subagents/progress.js +11 -6
  466. package/dist/runtime/subagents/render.d.ts +30 -0
  467. package/dist/runtime/subagents/render.js +53 -0
  468. package/dist/runtime/subagents/roster.d.ts +24 -7
  469. package/dist/runtime/subagents/roster.js +47 -11
  470. package/dist/runtime/subagents/skill-fork.d.ts +3 -2
  471. package/dist/runtime/subagents/skill-fork.js +8 -4
  472. package/dist/runtime/subagents/status.d.ts +14 -0
  473. package/dist/runtime/subagents/status.js +23 -0
  474. package/dist/runtime/subagents/subagents.service.d.ts +7 -4
  475. package/dist/runtime/subagents/subagents.service.js +11 -6
  476. package/dist/runtime/usage-report.d.ts +2 -1
  477. package/dist/runtime/usage-report.js +19 -13
  478. package/dist/runtime/waits.d.ts +145 -36
  479. package/dist/runtime/waits.js +423 -109
  480. package/dist/sandbox/jobs.d.ts +40 -13
  481. package/dist/sandbox/jobs.js +57 -20
  482. package/dist/sandbox/leases.d.ts +37 -54
  483. package/dist/sandbox/leases.js +71 -115
  484. package/dist/sandbox/providers.d.ts +2 -2
  485. package/dist/sandbox/providers.js +1 -1
  486. package/dist/sandbox/sandbox.module.d.ts +3 -2
  487. package/dist/sandbox/sandbox.module.js +10 -4
  488. package/dist/sandbox/sandbox.service.d.ts +282 -129
  489. package/dist/sandbox/sandbox.service.js +736 -381
  490. package/dist/skills/catalog.d.ts +3 -2
  491. package/dist/skills/catalog.js +21 -43
  492. package/dist/skills/changes.controller.d.ts +7 -0
  493. package/dist/skills/changes.controller.js +19 -1
  494. package/dist/skills/invoke.js +8 -3
  495. package/dist/skills/package.d.ts +20 -1
  496. package/dist/skills/package.js +28 -1
  497. package/dist/skills/skills.controller.d.ts +39 -4
  498. package/dist/skills/skills.controller.js +88 -10
  499. package/dist/skills/skills.module.js +10 -1
  500. package/dist/skills/skills.service.d.ts +106 -26
  501. package/dist/skills/skills.service.js +421 -75
  502. package/dist/skills/usable.d.ts +81 -0
  503. package/dist/skills/usable.js +379 -0
  504. package/dist/tools/approvals.service.d.ts +20 -2
  505. package/dist/tools/approvals.service.js +25 -4
  506. package/dist/tools/builtin-names.d.ts +41 -7
  507. package/dist/tools/builtin-names.js +59 -7
  508. package/dist/tools/builtins/agent.d.ts +23 -21
  509. package/dist/tools/builtins/agent.js +62 -55
  510. package/dist/tools/builtins/builtin-tools.d.ts +19 -1
  511. package/dist/tools/builtins/builtin-tools.js +59 -2
  512. package/dist/tools/builtins/handback.d.ts +28 -0
  513. package/dist/tools/builtins/handback.js +53 -0
  514. package/dist/tools/builtins/platform.d.ts +34 -0
  515. package/dist/tools/builtins/platform.js +362 -0
  516. package/dist/tools/builtins/sandbox/bash.d.ts +1 -1
  517. package/dist/tools/builtins/sandbox/bash.js +241 -4
  518. package/dist/tools/builtins/sandbox/common.d.ts +69 -27
  519. package/dist/tools/builtins/sandbox/common.js +87 -48
  520. package/dist/tools/builtins/sandbox/deliver.js +1 -1
  521. package/dist/tools/builtins/sandbox/edit.js +2 -2
  522. package/dist/tools/builtins/sandbox/glob.js +2 -2
  523. package/dist/tools/builtins/sandbox/grep.js +2 -4
  524. package/dist/tools/builtins/sandbox/index.d.ts +3 -1
  525. package/dist/tools/builtins/sandbox/index.js +7 -1
  526. package/dist/tools/builtins/sandbox/read.js +1 -1
  527. package/dist/tools/builtins/sandbox/task-output.d.ts +74 -0
  528. package/dist/tools/builtins/sandbox/task-output.js +329 -0
  529. package/dist/tools/builtins/sandbox/task-stop.d.ts +10 -0
  530. package/dist/tools/builtins/sandbox/task-stop.js +113 -0
  531. package/dist/tools/builtins/sandbox/write.js +2 -2
  532. package/dist/tools/builtins/send-message.d.ts +56 -0
  533. package/dist/tools/builtins/send-message.js +100 -0
  534. package/dist/tools/builtins/skill-load.d.ts +22 -14
  535. package/dist/tools/builtins/skill-load.js +86 -57
  536. package/dist/tools/builtins/skill-write.js +1 -1
  537. package/dist/tools/builtins/web/errors.d.ts +8 -0
  538. package/dist/tools/builtins/web/errors.js +53 -0
  539. package/dist/tools/builtins/web/extract.d.ts +62 -0
  540. package/dist/tools/builtins/web/extract.js +271 -0
  541. package/dist/tools/builtins/web/fetch.d.ts +55 -0
  542. package/dist/tools/builtins/web/fetch.js +175 -0
  543. package/dist/tools/builtins/web/index.d.ts +13 -0
  544. package/dist/tools/builtins/web/index.js +12 -0
  545. package/dist/tools/builtins/web/page-cache.d.ts +25 -0
  546. package/dist/tools/builtins/web/page-cache.js +77 -0
  547. package/dist/tools/builtins/web/search.d.ts +25 -0
  548. package/dist/tools/builtins/web/search.js +210 -0
  549. package/dist/tools/builtins/web/url.d.ts +17 -0
  550. package/dist/tools/builtins/web/url.js +43 -0
  551. package/dist/tools/connectors.controller.d.ts +10 -0
  552. package/dist/tools/connectors.controller.js +12 -0
  553. package/dist/tools/connectors.service.d.ts +46 -5
  554. package/dist/tools/connectors.service.js +94 -15
  555. package/dist/tools/extension-tools.controller.d.ts +14 -0
  556. package/dist/tools/extension-tools.controller.js +37 -0
  557. package/dist/tools/info.d.ts +42 -1
  558. package/dist/tools/info.js +64 -1
  559. package/dist/tools/oauth/flow-paths.d.ts +1 -1
  560. package/dist/tools/oauth/flow-paths.js +1 -1
  561. package/dist/tools/org-tool-switches.d.ts +74 -0
  562. package/dist/tools/org-tool-switches.js +184 -0
  563. package/dist/tools/pipeline.d.ts +46 -40
  564. package/dist/tools/pipeline.js +202 -364
  565. package/dist/tools/policy.d.ts +1 -1
  566. package/dist/tools/policy.js +36 -16
  567. package/dist/tools/registry.d.ts +120 -8
  568. package/dist/tools/registry.js +112 -19
  569. package/dist/tools/tools.module.js +24 -2
  570. package/dist/tools/validate.js +1 -1
  571. package/dist/ui/views.d.ts +2 -1
  572. package/dist/ui/views.js +17 -3
  573. package/package.json +3 -3
  574. package/src/migrations/0064_account_last_org.sql +7 -0
  575. package/src/migrations/0065_conversation_archive.sql +8 -0
  576. package/src/migrations/0066_extension_display_name.sql +4 -0
  577. package/src/migrations/0067_agent_profiles.sql +20 -0
  578. package/src/migrations/0068_agent_avatar_uploads.sql +7 -0
  579. package/src/migrations/0069_attachments_agent_idx.sql +3 -0
  580. package/src/migrations/0070_background_tasks.sql +37 -0
  581. package/src/migrations/0071_background_tasks_reserve.sql +6 -0
  582. package/src/migrations/0072_background_tasks_stopping.sql +5 -0
  583. package/src/migrations/0073_org_extension_point_defaults.sql +11 -0
  584. package/src/migrations/0074_subagent_tree.sql +50 -0
  585. package/src/migrations/0075_plugin_scope.sql +61 -0
  586. package/src/migrations/0076_skills_created_by_nullable.sql +6 -0
  587. package/src/migrations/0077_scope_requests.sql +52 -0
  588. package/src/migrations/0078_scope_grant_switches.sql +18 -0
  589. package/src/migrations/0079_scope_live_install_switches.sql +19 -0
  590. package/src/migrations/0080_rename_enterprise_admin.sql +18 -0
  591. package/src/migrations/0081_platform_components.sql +129 -0
  592. package/src/migrations/0082_platform_migration.sql +33 -0
  593. package/src/migrations/0083_plugin_scope_sync_failures.sql +15 -0
  594. package/src/migrations/0084_org_owned_items.sql +85 -0
  595. package/src/migrations/0085_agent_templates_phase4.sql +45 -0
  596. package/src/migrations/0086_org_layering.sql +30 -0
  597. package/src/migrations/0087_approval_summary.sql +6 -0
  598. package/src/migrations/0088_environments.sql +80 -0
  599. package/dist/catalog/upgrade-targets.d.ts +0 -56
  600. package/dist/catalog/upgrade-targets.js +0 -90
  601. package/dist/conversations/sandbox-status.d.ts +0 -24
  602. package/dist/conversations/sandbox-status.js +0 -52
  603. package/dist/extensions/org-config.controller.d.ts +0 -24
  604. package/dist/extensions/org-config.controller.js +0 -62
@@ -8,14 +8,16 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
8
8
  return function (target, key) { decorator(target, key, paramIndex); }
9
9
  };
10
10
  import { createHash, randomUUID } from "node:crypto";
11
- import { PLUGIN_MANIFEST_FILE, parseSkillMd, SDK_VERSION, SKILL_ENTRY_FILE, } from "@capybara-hq/plugin-sdk";
11
+ import { PLUGIN_MANIFEST_FILE, parseSkillMd, pluginDescription, SDK_VERSION, SKILL_ENTRY_FILE, } from "@capybara-hq/plugin-sdk";
12
+ import { getQueueToken } from "@nestjs/bullmq";
12
13
  import { Inject, Injectable } from "@nestjs/common";
13
14
  import { sql } from "kysely";
14
15
  import semver from "semver";
15
16
  import { ApiError } from "../errors.js";
16
17
  import { ExtensionAdminOps } from "../extensions/admin-ops.js";
18
+ import { ExtensionAdmin } from "../extensions/admin-view.js";
17
19
  import { writeSnapshot } from "../extensions/approvals.js";
18
- import { ExtensionBlobs } from "../extensions/blobs.js";
20
+ import { blobKey, ExtensionBlobs } from "../extensions/blobs.js";
19
21
  import { ExtensionInstalls } from "../extensions/installs.js";
20
22
  import { PluginApproveLock, PluginInstallLock } from "../extensions/locks.js";
21
23
  import { unrunMigrations } from "../extensions/migrate-lock.js";
@@ -24,28 +26,40 @@ import { diffPermissions, permissionKeys, WARNINGS_KEY_PREFIX, } from "../extens
24
26
  import { reviewHash as extensionReviewHash, migrationWarnings, permissionGroups, permissionKeyItems, } from "../extensions/permission-view.js";
25
27
  import { ExtensionRegistry } from "../extensions/registry.js";
26
28
  import { audit } from "../identity/audit.js";
27
- import { EnterpriseAdminLock } from "../identity/enterprise-admin.js";
29
+ import { assertCustomAllowed } from "../identity/settings.js";
30
+ import { SuperAdminLock } from "../identity/super-admin.js";
28
31
  import { KernelConfigService } from "../infra/config/kernel-config.service.js";
32
+ import { afterCommit } from "../infra/database/after-commit.js";
29
33
  import { KernelDb } from "../infra/database/kernel-db.js";
30
34
  import { TransactionHost } from "../infra/database/transaction-host.js";
31
35
  import { Transactional } from "../infra/database/transactional.decorator.js";
32
36
  import { KERNEL_LOGGER } from "../infra/tokens.js";
37
+ import { OrgLock } from "../orgs/org-lock.js";
33
38
  import { packPackageTgz } from "../packages/tgz.js";
39
+ import { MAINTENANCE_QUEUE_NAME } from "../runtime/maintenance-queue.js";
34
40
  import { checkSkillFiles, SkillArchiveError } from "../skills/package.js";
35
41
  import { StorageService } from "../storage/storage.service.js";
42
+ import { canonicalJson } from "../tools/canonical-json.js";
36
43
  import { endpointCredentialIssues } from "../tools/endpoint.js";
37
- import { canonicalJson } from "../tools/registry.js";
38
44
  import { findConnectorIn } from "./catalog-content.js";
39
- import { assertPluginNameOwner, catalogObjectPrefix, itemView, permissionsMismatch, precheckCatalogImport, putCatalogFiles, templateProblems, writeCatalogVersion, } from "./catalog-items.js";
45
+ import { assertOrgsExist, assertPluginNameOwner, catalogObjectPrefix, itemConfirmations, itemScopeFacts, itemView, markVersionApplied, permissionsMismatch, precheckCatalogImport, putCatalogFiles, templateProblems, unappliedOwnVersion, writeCatalogVersion, } from "./catalog-items.js";
40
46
  import { CLAUDE_PLUGIN_FILE, claudeContentDigest, } from "./claude/manifest.js";
41
47
  import { CLAUDE_MCP_CONNECTOR } from "./claude/mcp.js";
42
48
  import { item as reportItem, sortItems, } from "./claude/report.js";
43
49
  import { isClaudePluginTree, translateClaudePlugin } from "./claude/translate.js";
44
50
  import { CatalogItemLock } from "./locks.js";
51
+ import { assertNameFree, assertPackageFree, assertShareable, packageOwner, releaseExtensionClaim, shareGate, usableBy, } from "./ownership.js";
52
+ import { PlatformComponents } from "./platform-components.js";
53
+ import { PLATFORM_MIGRATION_JOB } from "./platform-migration.js";
45
54
  import { PluginPackageError, packagePath, readPluginFiles, readPluginPackage, } from "./plugin-package.js";
55
+ import { hasImportRequests, importRequestOf, resolveImportRequests } from "./request-rules.js";
56
+ import { assertNameNotReserved } from "./reserved-names.js";
57
+ import { addScopeOrg } from "./scope-orgs.js";
46
58
  import { maxSatisfying, satisfiesRange } from "./versions.js";
59
+ /** How long after a failed post-import platform sync the migration job runs for the item. */
60
+ export const PLATFORM_SYNC_RETRY_MS = 60_000;
47
61
  /**
48
- * Enterprise import of a plugin (package ecosystem spec §4.3): one review for every plugin, whatever
62
+ * Platform import of a plugin (package ecosystem spec §4.3): one review for every plugin, whatever
49
63
  * it contains (an extension, skills, connector templates, dependencies), confirmed once.
50
64
  *
51
65
  * prepare: the tgz is always hostile input, and **nothing is written until every check passes**
@@ -55,7 +69,7 @@ import { maxSatisfying, satisfiesRange } from "./versions.js";
55
69
  * refused; name ownership; a downgrade to a version with unrun migrations is refused), each skill by
56
70
  * the skill package rules, each connector template against the connector loaded on this replica (or
57
71
  * statically when the connector is provided by the plugin's own extension or by a dependency), the
58
- * catalog name / version conflicts and the actor still an enterprise admin. Dependencies are only
72
+ * catalog name / version conflicts and the actor still a super admin. Dependencies are only
59
73
  * resolved against the imported catalog versions for the review (an unresolved one does not block
60
74
  * the import, spec §4.1); they are never fetched. Only then is the extension handed to
61
75
  * `ExtensionInstalls.ingest` (source `catalog`), the skill / template / icon files written to object
@@ -64,13 +78,13 @@ import { maxSatisfying, satisfiesRange } from "./versions.js";
64
78
  * confirm: `reviewHash` must match the staging; in one transaction it deletes the staging row
65
79
  * (confirm works once), locks the extension name and recomputes its deployment state (installed /
66
80
  * upgraded / swapped after the review -> `plugin.review_stale`), writes the extension's permission
67
- * snapshot when it is installed by this import (or upgraded with `deployExtension`; source web, audit
68
- * `extension.permissions_approved` carrying the plugin), and creates the item or adds the version
69
- * (`manifest` = the normalized plugin.json, `extension_sha256`, the files under the staging prefix).
70
- * After the commit, with `deployExtension`, the plugin's own extension is installed on the
71
- * deployment and enabled (`ExtensionAdminOps.install` + `enable`; each replica reconciles, no
72
- * restart); a failure is returned, not thrown, and an upgrade that was not installed gets its old
73
- * snapshot back.
81
+ * snapshot when it is installed or upgraded by this import (source web, audit
82
+ * `extension.permissions_approved` carrying the plugin), and creates the item (with the scope the
83
+ * admin chose, default `optional`) or adds the version (`manifest` = the normalized plugin.json,
84
+ * `extension_sha256`, the files under the staging prefix). After the commit the plugin's own
85
+ * extension is installed on the deployment and enabled (`ExtensionAdminOps.install` + `enable`;
86
+ * each replica reconciles, no restart); a failure is returned, not thrown, and an upgrade that was
87
+ * not installed gets its old snapshot back.
74
88
  *
75
89
  * Expired staging is cleaned by the maintenance job `app-staging-cleanup`
76
90
  * ({@link PluginImport.cleanupExpired}): it deletes the staging row and its object prefix; a stored
@@ -123,16 +137,20 @@ const fileOf = (path, data) => ({
123
137
  let PluginImport = class PluginImport {
124
138
  kdb;
125
139
  adminLock;
140
+ orgLock;
126
141
  installLock;
127
142
  approveLock;
128
143
  itemLock;
129
144
  config;
130
145
  installs;
131
146
  ops;
147
+ admin;
132
148
  blobs;
133
149
  registry;
134
150
  log;
135
151
  txHost;
152
+ platform;
153
+ maintenance;
136
154
  /** Where plugin files go (the kernel's object storage; the CLI's own, see {@link useCliStorage}). */
137
155
  files;
138
156
  /**
@@ -142,24 +160,34 @@ let PluginImport = class PluginImport {
142
160
  */
143
161
  connectorsLoaded = true;
144
162
  constructor(kdb,
145
- /** The enterprise admin lock (identity/enterprise-admin.ts): joins the caller's transaction. */
146
- adminLock, installLock, approveLock, itemLock, config, storage, installs, ops,
163
+ /** The super admin lock (identity/super-admin.ts): joins the caller's transaction. */
164
+ adminLock,
165
+ /** The owner org's lock: an org upload re-checks its admin under it (ruling P3-7). */
166
+ orgLock, installLock, approveLock, itemLock, config, storage, installs, ops, admin,
147
167
  /** Reads a package from the package store (confirm recomputes the permission set). */
148
168
  blobs,
149
169
  /** Config-declared names, loaded connectors and extension versions (the extension registry). */
150
- registry, log, txHost) {
170
+ registry, log, txHost,
171
+ /** The platform rows of a new item's components, written after the confirm's commit. */
172
+ platform,
173
+ /** A failed platform sync enqueues a run of the migration job here (it heals the item). */
174
+ maintenance) {
151
175
  this.kdb = kdb;
152
176
  this.adminLock = adminLock;
177
+ this.orgLock = orgLock;
153
178
  this.installLock = installLock;
154
179
  this.approveLock = approveLock;
155
180
  this.itemLock = itemLock;
156
181
  this.config = config;
157
182
  this.installs = installs;
158
183
  this.ops = ops;
184
+ this.admin = admin;
159
185
  this.blobs = blobs;
160
186
  this.registry = registry;
161
187
  this.log = log;
162
188
  this.txHost = txHost;
189
+ this.platform = platform;
190
+ this.maintenance = maintenance;
163
191
  this.files = storage;
164
192
  }
165
193
  /** The kernel-schema handle of the current context (the transaction, else the pool). */
@@ -174,21 +202,29 @@ let PluginImport = class PluginImport {
174
202
  useCliStorage(storage) {
175
203
  this.files = storage;
176
204
  this.connectorsLoaded = false;
205
+ this.platform.useCliStorage(storage);
177
206
  }
178
207
  /**
179
- * The enterprise-admin re-check under the lock, in the caller's transaction. `actor` null is the
208
+ * The super-admin re-check under the lock, in the caller's transaction. `actor` null is the
180
209
  * CLI (the operator of the deployment: no account to re-check, audits carry no actor), like
181
- * `ExtensionInstalls.ingest`.
210
+ * `ExtensionInstalls.ingest`. An org upload (`owner`) re-checks the actor as an admin of the
211
+ * owner org under the org row lock instead (`catalog.upload`; an org deleted meanwhile -> 404
212
+ * `org.not_found`).
182
213
  */
183
- async authorizeActor(actor) {
184
- if (actor === null)
214
+ async authorizeActor(actor, owner) {
215
+ if (owner !== undefined) {
216
+ if (actor === null)
217
+ throw new Error("an org upload has an actor");
218
+ await this.orgLock.lockAndAuthorize(owner.orgId, actor, "catalog.upload");
219
+ }
220
+ else if (actor === null)
185
221
  await this.adminLock.lock();
186
222
  else
187
223
  await this.adminLock.lockAndAuthorize(actor);
188
224
  }
189
225
  /** The re-check alone, in a transaction of its own (before anything is written). */
190
- async authorize(actor) {
191
- await this.authorizeActor(actor);
226
+ async authorize(actor, owner) {
227
+ await this.authorizeActor(actor, owner);
192
228
  }
193
229
  /**
194
230
  * Reads, checks and stages a plugin (see the file header). Returns the staging id and review.
@@ -279,6 +315,10 @@ let PluginImport = class PluginImport {
279
315
  */
280
316
  async prepareContents(actor, pkg, tgz, source, opts) {
281
317
  const maxBytes = this.config.get().packages.maxBytes;
318
+ const owner = opts.owner;
319
+ if (owner !== undefined && source.kind !== "file") {
320
+ throw new Error("an org upload is a file (ruling P3-7)");
321
+ }
282
322
  // 1. Every check (nothing written)
283
323
  const m = pkg.manifest;
284
324
  const packageName = packageNameOf(pkg);
@@ -292,14 +332,34 @@ let PluginImport = class PluginImport {
292
332
  ? await readingPackage(() => readExtensionPackage(bytes, { maxBytes, hostSdkVersion: SDK_VERSION }))
293
333
  : undefined;
294
334
  const content = this.checkContent(pkg, format);
295
- const { existing, version } = await precheckCatalogImport(this.db, m.name, {
296
- packageName,
297
- version: m.version,
298
- contentDigest: pkg.contentDigest,
299
- ...(source.integrity !== undefined && { integrity: source.integrity }),
300
- ...(source.detail !== undefined && { detail: source.detail }),
301
- ...(source.marketplaceId !== undefined && { marketplaceId: source.marketplaceId }),
302
- });
335
+ // A name live for another owner (an org's for the super admin; the platform's or another
336
+ // org's for an org) -> 409 plugin.name_taken naming it (P3-14); the same owner adds a version
337
+ await assertNameFree(this.db, m.name, owner?.orgId ?? null);
338
+ if (owner !== undefined) {
339
+ // a bootstrap or marketplace plugin's name stays free for the platform (ruling P3-28)
340
+ await assertNameNotReserved(this.db, m.name);
341
+ // its npm package is an identity of this org only (ruling P3-51)
342
+ await assertPackageFree(this.db, packageName, owner.orgId);
343
+ await assertCustomContent(this.db, content);
344
+ }
345
+ // An org's own version imported but not applied: its update is retried (pre-flight F4)
346
+ const retry = owner !== undefined && !m.extension
347
+ ? await unappliedOwnVersion(this.db, m.name, owner.orgId, {
348
+ packageName,
349
+ version: m.version,
350
+ contentDigest: pkg.contentDigest,
351
+ })
352
+ : undefined;
353
+ const { existing, version } = retry !== undefined
354
+ ? { existing: { id: retry.itemId }, version: retry.version }
355
+ : await precheckCatalogImport(this.db, m.name, {
356
+ packageName,
357
+ version: m.version,
358
+ contentDigest: pkg.contentDigest,
359
+ ...(source.integrity !== undefined && { integrity: source.integrity }),
360
+ ...(source.detail !== undefined && { detail: source.detail }),
361
+ ...(source.marketplaceId !== undefined && { marketplaceId: source.marketplaceId }),
362
+ });
303
363
  // The catalog name space is the extension name space: a declarative plugin cannot take a
304
364
  // config-declared or another package's extension name either
305
365
  this.assertNotDeclared(m.name);
@@ -318,7 +378,7 @@ let PluginImport = class PluginImport {
318
378
  ...(source.marketplaceId !== undefined && { marketplaceId: source.marketplaceId }),
319
379
  ...(source.detail !== undefined && { detail: source.detail }),
320
380
  };
321
- const dependencies = await this.resolveDependencies(m);
381
+ const dependencies = await this.resolveDependencies(m, owner);
322
382
  let translation;
323
383
  if (opts.claude !== undefined) {
324
384
  const added = [
@@ -348,7 +408,8 @@ let PluginImport = class PluginImport {
348
408
  contentDigest: pkg.contentDigest,
349
409
  packageName,
350
410
  publisher: m.publisher,
351
- description: m.description,
411
+ description: pluginDescription(m.description).en,
412
+ descriptionZh: pluginDescription(m.description).zh ?? null,
352
413
  ...(m.displayName !== undefined && { displayName: m.displayName }),
353
414
  ...(m.license !== undefined && { license: m.license }),
354
415
  ...(m.homepage !== undefined && { homepage: m.homepage }),
@@ -364,8 +425,9 @@ let PluginImport = class PluginImport {
364
425
  reviewHash: "",
365
426
  };
366
427
  review.reviewHash = pluginReviewHash(review, content.files);
367
- // Re-check under the lock that the actor is still an enterprise admin before writing
368
- await this.authorize(actor);
428
+ // Re-check under the lock that the actor is still a super admin (an org upload: an admin of
429
+ // the owner org) before writing
430
+ await this.authorize(actor, owner);
369
431
  // 2. Write: the extension into the package store, files into object storage, the staging row
370
432
  const stagingId = randomUUID();
371
433
  const itemId = existing?.id ?? randomUUID();
@@ -379,10 +441,12 @@ let PluginImport = class PluginImport {
379
441
  }, {
380
442
  ...(opts.actorTokenId !== undefined && { actorTokenId: opts.actorTokenId }),
381
443
  ...(bootstrap && { store: "pg" }),
444
+ // an org upload only stores the package (nothing runs until the super admin confirms)
445
+ ...(owner !== undefined && { owner }),
382
446
  });
383
447
  }
384
448
  let objectPrefix = null;
385
- if (content.files.length > 0) {
449
+ if (content.files.length > 0 && retry === undefined) {
386
450
  objectPrefix = catalogObjectPrefix(itemId, version, stagingId);
387
451
  await putCatalogFiles(this.files, objectPrefix, content.files);
388
452
  }
@@ -405,15 +469,16 @@ let PluginImport = class PluginImport {
405
469
  ...(translation !== undefined && { translation }),
406
470
  ...(license.text !== undefined && { licenseText: license.text }),
407
471
  ...(license.truncated && { licenseTruncated: true }),
472
+ ...(retry !== undefined && { retry: true }),
408
473
  };
409
- await this.writeStaging(actor, stagingId, review, staged, objectPrefix, src, opts);
474
+ await this.writeStaging(actor, stagingId, review, staged, objectPrefix, src, opts, owner);
410
475
  return { stagingId, review, permissionKeys: keys, permissionsMismatch: mismatch };
411
476
  }
412
477
  /** The staging row and the `catalog.plugin_staged` audit, the actor re-checked under the lock. */
413
- async writeStaging(actor, stagingId, review, staged, objectPrefix, src, opts) {
478
+ async writeStaging(actor, stagingId, review, staged, objectPrefix, src, opts, owner) {
414
479
  const { extension } = review;
415
480
  const t = this.db;
416
- await this.authorizeActor(actor);
481
+ await this.authorizeActor(actor, owner);
417
482
  await t
418
483
  .insertInto("plugin_import_staging")
419
484
  .values({
@@ -424,6 +489,8 @@ let PluginImport = class PluginImport {
424
489
  source: JSON.stringify(src),
425
490
  created_by: actor,
426
491
  expires_at: new Date(Date.now() + PLUGIN_STAGING_TTL_MS),
492
+ // the org's own staging (P3-8); null = the super admin's
493
+ org_id: owner?.orgId ?? null,
427
494
  })
428
495
  .execute();
429
496
  await audit(t, {
@@ -443,6 +510,7 @@ let PluginImport = class PluginImport {
443
510
  ...(extension && {
444
511
  extension: { sha256: extension.sha256, action: extension.action },
445
512
  }),
513
+ ...(owner !== undefined && { orgId: owner.orgId }),
446
514
  },
447
515
  });
448
516
  }
@@ -465,9 +533,10 @@ let PluginImport = class PluginImport {
465
533
  /**
466
534
  * A staged import's review, as prepare returned it, with a marketplace import's permission
467
535
  * mismatch when there is one (the import page loads `?staging=<id>` with it). Unknown, expired or
468
- * already confirmed -> 404 `plugin.staging_not_found`.
536
+ * already confirmed -> 404 `plugin.staging_not_found`. Each sees only its own staging (P3-8):
537
+ * the super admin's routes the platform's (no `owner`), an org's routes that org's.
469
538
  */
470
- async staged(stagingId) {
539
+ async staged(stagingId, owner) {
471
540
  if (!UUID_RE.test(stagingId))
472
541
  throw notFound();
473
542
  const row = await this.db
@@ -475,6 +544,7 @@ let PluginImport = class PluginImport {
475
544
  .select(["id", "review", "manifest"])
476
545
  .where("id", "=", stagingId)
477
546
  .where("expires_at", ">", sql `now()`)
547
+ .where(ownStaging(owner))
478
548
  .executeTakeFirst();
479
549
  if (!row)
480
550
  throw notFound();
@@ -486,17 +556,117 @@ let PluginImport = class PluginImport {
486
556
  };
487
557
  }
488
558
  /**
489
- * Confirms a staged import (see the file header). Returns the committed catalog item and, with
490
- * `deployExtension`, the extension's deploy result (a failed deploy is returned, not thrown).
559
+ * What an org's staged upload targets (P3-12, pre-flight F3): its item, version and review hash,
560
+ * whether the item exists (a new version of the org's own plugin) or the version is imported
561
+ * already (F4), and the target as the platform updater reads it: the staged manifest and files,
562
+ * or the imported version's for a retry. Another org's staging -> 404 `plugin.staging_not_found`.
563
+ */
564
+ async stagedTarget(stagingId, owner) {
565
+ if (!UUID_RE.test(stagingId))
566
+ throw notFound();
567
+ const row = await this.db
568
+ .selectFrom("plugin_import_staging")
569
+ .select(["review", "manifest", "object_prefix"])
570
+ .where("id", "=", stagingId)
571
+ .where("expires_at", ">", sql `now()`)
572
+ .where(ownStaging(owner))
573
+ .executeTakeFirst();
574
+ if (!row)
575
+ throw notFound();
576
+ const review = row.review;
577
+ const staged = row.manifest;
578
+ const item = await this.db
579
+ .selectFrom("catalog_items")
580
+ .select(["id", "awaiting_confirmation"])
581
+ .where("id", "=", staged.itemId)
582
+ .where("deleted_at", "is", null)
583
+ .where("owner_org_id", "=", owner.orgId)
584
+ .executeTakeFirst();
585
+ const imported = staged.retry === true
586
+ ? await this.db
587
+ .selectFrom("catalog_item_versions")
588
+ .select(["version", "manifest", "object_prefix", "files", "extension_sha256"])
589
+ .where("item_id", "=", staged.itemId)
590
+ .where("version", "=", staged.version)
591
+ .executeTakeFirst()
592
+ : undefined;
593
+ return {
594
+ itemId: staged.itemId,
595
+ version: staged.version,
596
+ reviewHash: review.reviewHash,
597
+ extension: review.extension !== undefined,
598
+ existing: item !== undefined,
599
+ awaiting: item?.awaiting_confirmation === true,
600
+ retry: staged.retry === true,
601
+ target: imported !== undefined
602
+ ? {
603
+ version: imported.version,
604
+ manifest: imported.manifest,
605
+ object_prefix: imported.object_prefix,
606
+ files: imported.files,
607
+ extension_sha256: imported.extension_sha256,
608
+ }
609
+ : {
610
+ version: staged.version,
611
+ manifest: staged.manifest,
612
+ object_prefix: row.object_prefix,
613
+ files: staged.files,
614
+ extension_sha256: review.extension?.sha256 ?? null,
615
+ },
616
+ };
617
+ }
618
+ /** The catalog item's view (as a confirm returns it). */
619
+ async view(itemId) {
620
+ return this.itemView(itemId);
621
+ }
622
+ /**
623
+ * Confirms a staged import (see the file header). Returns the committed catalog item and the
624
+ * extension's deploy result (a failed deploy is returned, not thrown). `scope` (default
625
+ * `optional`) and `orgs` (only with `named`; each an existing org, else `validation_failed`) are
626
+ * written when this confirm creates the item; a new version of an existing item keeps its scope.
627
+ * The caller enqueues the scope sync of the item after this returns.
628
+ *
629
+ * An org upload (`opts.owner`, spec §14): only that org's staging; the actor re-checked as its
630
+ * admin; `scope` / `orgs` are not taken: a new item is owned by the org, scope `named: [owner]`,
631
+ * not shown to other orgs, `shareable` as given (default false). Custom deny, the name owner and
632
+ * the dependencies are checked again under the item name's lock. A package with an extension
633
+ * is stored and its extension name claimed, nothing approved or installed: the version waits
634
+ * for the super admin (`pending`, ruling P3-10; see {@link commit}).
491
635
  */
492
636
  async confirm(actor, stagingId, input, opts = {}) {
493
637
  if (!UUID_RE.test(stagingId))
494
638
  throw notFound();
639
+ const owner = opts.owner;
640
+ if (owner !== undefined && (input.scope !== undefined || input.orgs !== undefined)) {
641
+ throw new Error("an org upload's scope is its owner's");
642
+ }
643
+ // A staging prepared by approving an org's `import` request defaults to that org (spec §5.1
644
+ // rule 3); the admin may still choose any scope
645
+ const linked = input.scope === undefined && owner === undefined
646
+ ? await importRequestOf(this.db, stagingId)
647
+ : undefined;
648
+ const scope = owner !== undefined
649
+ ? "named"
650
+ : (input.scope ?? (linked !== undefined ? "named" : "optional"));
651
+ const orgs = owner !== undefined
652
+ ? [owner.orgId]
653
+ : (input.orgs ?? (linked !== undefined ? [linked.orgId] : undefined));
654
+ if (input.orgs !== undefined && scope !== "named") {
655
+ throw new ApiError("validation_failed", "orgs: only allowed with scope named", [
656
+ { path: "orgs", message: "only allowed with scope named" },
657
+ ]);
658
+ }
659
+ if (scope === "named" && (orgs ?? []).length === 0) {
660
+ throw new ApiError("validation_failed", "orgs: scope named needs at least one organization", [
661
+ { path: "orgs", message: "scope named needs at least one organization" },
662
+ ]);
663
+ }
495
664
  const row = await this.db
496
665
  .selectFrom("plugin_import_staging")
497
666
  .selectAll()
498
667
  .where("id", "=", stagingId)
499
668
  .where("expires_at", ">", sql `now()`)
669
+ .where(ownStaging(owner))
500
670
  .executeTakeFirst();
501
671
  if (!row)
502
672
  throw notFound();
@@ -507,34 +677,92 @@ let PluginImport = class PluginImport {
507
677
  throw reviewStale(review);
508
678
  const manifest = withPinned(staged.manifest, review, input.pinnedSuggestions);
509
679
  const reviewed = review.extension;
510
- // Read the stored package outside the transaction (unless it was already installed as is)
511
- const stored = reviewed && reviewed.action !== "keep" ? await this.readStored(reviewed.sha256) : undefined;
512
- const committed = await this.commit(actor, { stagingId, review, staged, src, manifest, objectPrefix: row.object_prefix }, input, stored, opts);
680
+ // Read the stored package outside the transaction (unless it was already installed as is, or
681
+ // an org upload, which approves nothing)
682
+ const stored = reviewed && reviewed.action !== "keep" && owner === undefined
683
+ ? await this.readStored(reviewed.sha256)
684
+ : undefined;
685
+ const committed = await this.commit(actor, { stagingId, review, staged, src, manifest, objectPrefix: row.object_prefix }, {
686
+ scope,
687
+ orgs: [...new Set(orgs ?? [])].sort(),
688
+ ...(owner !== undefined && { owner, shareable: input.shareable ?? false }),
689
+ }, stored, opts);
513
690
  const { now } = committed;
514
- const deploy = input.deployExtension && now && now.action !== "keep"
691
+ if (committed.pending) {
692
+ // Waits for the super admin (P3-10): no platform components, nothing deployed
693
+ return {
694
+ item: await this.itemView(committed.itemId),
695
+ created: committed.created,
696
+ deploy: null,
697
+ pending: true,
698
+ firstVersion: false,
699
+ };
700
+ }
701
+ // A new item's skills, agent templates and connector templates become platform components
702
+ // (plugin scope phase 2); a new version of an existing item leaves them to the platform
703
+ // update. After the commit: it copies files in object storage
704
+ if (committed.firstVersion)
705
+ await this.syncPlatform(committed.itemId, staged.version);
706
+ const deploy = now && now.action !== "keep"
515
707
  ? await this.deploy(actor, review, committed.itemId, now, committed.previous, opts, input.enable ?? true)
516
708
  : null;
517
- return { item: await this.itemView(committed.itemId), deploy };
709
+ return {
710
+ item: await this.itemView(committed.itemId),
711
+ created: committed.created,
712
+ deploy,
713
+ pending: false,
714
+ firstVersion: committed.firstVersion,
715
+ };
716
+ }
717
+ /**
718
+ * Writes the platform components of an item's first usable version after a commit made
719
+ * elsewhere (the super admin's confirmation of an org upload, `CatalogScopeService`); a failure
720
+ * is logged and retried by the migration job (see {@link syncPlatform}).
721
+ */
722
+ async writePlatformComponents(itemId, version) {
723
+ await this.syncPlatform(itemId, version);
518
724
  }
519
725
  /**
520
726
  * The confirm's transaction: the staging row consumed, the extension's action recomputed under
521
727
  * its install lock (stale -> `plugin.review_stale`), its snapshot approved, and the catalog
522
728
  * version written under the item name's lock.
729
+ *
730
+ * An org upload with an extension (ruling P3-10) approves nothing: under the install lock it
731
+ * claims the extension name for its package (another package's -> 409
732
+ * `extension.name_conflict` naming its owner, before anything is written), and the version
733
+ * written becomes the item's pending one (`pending_version` / `_by` / `_at`; a first version
734
+ * also `awaiting_confirmation`). A later upload replaces the pending version (P3-11). An org
735
+ * upload without an extension for an item whose first version still waits (plan Task 6) replaces
736
+ * that upload and applies at once: the item stops waiting and the claim is released (nothing
737
+ * was installed under it).
523
738
  */
524
- async commit(actor, c, input, stored, opts) {
739
+ async commit(actor, c, scope, stored, opts) {
525
740
  const { stagingId, review, staged, src, manifest } = c;
526
741
  const reviewed = review.extension;
527
742
  const stale = () => reviewStale(review);
528
- await this.authorizeActor(actor);
743
+ const { owner } = scope;
744
+ await this.authorizeActor(actor, owner);
529
745
  const t = this.db;
530
746
  const used = await t
531
747
  .deleteFrom("plugin_import_staging")
532
748
  .where("id", "=", stagingId)
533
749
  .where("expires_at", ">", sql `now()`)
750
+ .where(ownStaging(owner))
534
751
  .returning("id")
535
752
  .executeTakeFirst();
536
753
  if (!used)
537
754
  throw notFound();
755
+ if (owner !== undefined) {
756
+ await assertCustomContent(t, {
757
+ skills: review.skills,
758
+ agentTemplates: review.agentTemplates ?? [],
759
+ templates: review.connectorTemplates,
760
+ });
761
+ }
762
+ await assertOrgsExist(t, scope.orgs);
763
+ // Checked again before this upload claims anything (ruling P3-51)
764
+ if (owner !== undefined)
765
+ await assertPackageFree(t, staged.packageName, owner.orgId);
538
766
  let now;
539
767
  let previous;
540
768
  if (reviewed) {
@@ -544,23 +772,84 @@ let PluginImport = class PluginImport {
544
772
  await this.installLock.lock(reviewed.name);
545
773
  now = {
546
774
  ...reviewed,
547
- ...actionOf(await this.extensionState(reviewed.name, staged.packageName), reviewed.sha256),
775
+ ...actionOf(await this.extensionState(reviewed.name, staged.packageName), reviewed.sha256, reviewed.version),
548
776
  };
549
777
  if (pluginReviewHash({ ...review, extension: now }, staged.files) !== review.reviewHash) {
550
778
  throw stale();
551
779
  }
780
+ if (owner !== undefined) {
781
+ // An org upload only claims the name (P3-10): the super admin approves and installs it
782
+ await t
783
+ .insertInto("extension_name_owners")
784
+ .values({ name: reviewed.name, package_name: staged.packageName })
785
+ .onConflict((oc) => oc.column("name").doNothing())
786
+ .execute();
787
+ await assertPluginNameOwner(t, reviewed.name, staged.packageName);
788
+ }
552
789
  // A foreseeable deploy failure (a downgrade to a version with unrun migrations) is refused
553
790
  // before anything is written
554
- if (input.deployExtension && now.action === "upgrade" && stored) {
791
+ if (now.action === "upgrade" && stored) {
555
792
  await assertDowngradable(t, now, stored.migrationSql);
556
793
  }
557
- if (now.action === "install" || (now.action === "upgrade" && input.deployExtension)) {
794
+ if (owner === undefined && (now.action === "install" || now.action === "upgrade")) {
558
795
  previous = await this.approve(actor, review, staged, now, stored, opts);
559
796
  }
560
797
  }
561
798
  const m = manifest;
562
799
  await this.itemLock.lock(m.name);
563
- const itemId = await writeCatalogVersion(t, {
800
+ // Under the name's lock: the first confirm of a name wins, a later one of another owner is
801
+ // refused naming it, before anything of it is written (P3-14)
802
+ await assertNameFree(t, m.name, owner?.orgId ?? null);
803
+ if (owner !== undefined) {
804
+ await assertNameNotReserved(t, m.name);
805
+ await this.resolveDependencies(m, owner);
806
+ }
807
+ // The scope the audit records: the review's for a new item, the item's own for a new version
808
+ // of a live item (which keeps its scope)
809
+ const existing = await t
810
+ .selectFrom("catalog_items")
811
+ .select(["id", "scope", "awaiting_confirmation", "package_name"])
812
+ .where("name", "=", m.name)
813
+ .where("deleted_at", "is", null)
814
+ .forUpdate()
815
+ .executeTakeFirst();
816
+ const actual = existing === undefined
817
+ ? scope
818
+ : {
819
+ scope: existing.scope,
820
+ orgs: (await t
821
+ .selectFrom("catalog_item_scope_orgs")
822
+ .select("org_id")
823
+ .where("item_id", "=", existing.id)
824
+ .orderBy("org_id")
825
+ .execute()).map((r) => r.org_id),
826
+ };
827
+ if (staged.retry === true) {
828
+ // An org's own version imported already (pre-flight F4): nothing to write, the caller
829
+ // retries its update; it must still be there as reviewed
830
+ const v = existing === undefined
831
+ ? undefined
832
+ : await t
833
+ .selectFrom("catalog_item_versions")
834
+ .select("version")
835
+ .where("item_id", "=", existing.id)
836
+ .where("version", "=", staged.version)
837
+ .where("content_digest", "=", staged.contentDigest)
838
+ .executeTakeFirst();
839
+ if (existing === undefined || existing.id !== staged.itemId || v === undefined)
840
+ throw stale();
841
+ return {
842
+ itemId: existing.id,
843
+ created: false,
844
+ firstVersion: false,
845
+ pending: false,
846
+ now,
847
+ previous,
848
+ };
849
+ }
850
+ const { id: itemId, created } = await writeCatalogVersion(t, {
851
+ // an org's version becomes its latest only when applied or confirmed (P3-34)
852
+ ...(owner !== undefined && { keepLatest: true }),
564
853
  actor,
565
854
  ...(opts.actorTokenId !== undefined && { actorTokenId: opts.actorTokenId }),
566
855
  name: m.name,
@@ -570,7 +859,7 @@ let PluginImport = class PluginImport {
570
859
  manifest: m,
571
860
  listing: {
572
861
  publisher: m.publisher,
573
- description: m.description,
862
+ description: pluginDescription(m.description).en,
574
863
  displayName: m.displayName ?? null,
575
864
  },
576
865
  newItemId: staged.itemId,
@@ -591,12 +880,144 @@ let PluginImport = class PluginImport {
591
880
  licenseTruncated: staged.licenseTruncated === true,
592
881
  auditDetail: {
593
882
  stagingId,
594
- deployExtension: input.deployExtension,
883
+ scope: actual.scope,
884
+ ...(actual.scope === "named" && { orgs: actual.orgs }),
595
885
  suggestedPinned: pinnedNames(manifest, review),
596
886
  ...(now && { extension: { name: now.name, version: now.version, action: now.action } }),
597
887
  },
598
888
  });
599
- return { itemId, now, previous };
889
+ // A new item gets the scope chosen in the review; a new version keeps the item's scope, its
890
+ // org list and its scope version (prepare reuses the live item's id, so the id cannot tell)
891
+ if (created) {
892
+ await t
893
+ .updateTable("catalog_items")
894
+ .set({
895
+ scope: scope.scope,
896
+ // an org upload: the org owns it, nobody else sees it until shared and shown (P3-16)
897
+ ...(owner !== undefined && {
898
+ owner_org_id: owner.orgId,
899
+ shareable: scope.shareable === true,
900
+ shown_to_others: false,
901
+ }),
902
+ })
903
+ .where("id", "=", itemId)
904
+ .execute();
905
+ if (scope.scope === "named" && scope.orgs.length > 0) {
906
+ await t
907
+ .insertInto("catalog_item_scope_orgs")
908
+ .values(scope.orgs.map((org_id) => ({ item_id: itemId, org_id })))
909
+ .onConflict((oc) => oc.doNothing())
910
+ .execute();
911
+ }
912
+ }
913
+ // The org requests this staging answers resolve with the confirm; on an item that existed
914
+ // already (imported meanwhile) a `named` scope gains their orgs. An org-owned item held back by
915
+ // the share gate fails closed before any request is marked (ruling P3-26; P3-14 refuses a
916
+ // super admin import of an org-owned name, so this should not be reached)
917
+ const item = created
918
+ ? undefined
919
+ : await t
920
+ .selectFrom("catalog_items")
921
+ .select(["id", "name", "scope", "builtin", "owner_org_id", "shareable"])
922
+ .where("id", "=", itemId)
923
+ .forUpdate()
924
+ .executeTakeFirstOrThrow();
925
+ if (item !== undefined && !shareGate(item) && (await hasImportRequests(t, stagingId))) {
926
+ assertShareable(item);
927
+ }
928
+ const requestOrgs = await resolveImportRequests(t, stagingId, itemId, actor, opts);
929
+ if (item !== undefined) {
930
+ for (const org of requestOrgs)
931
+ await addScopeOrg(t, actor, item, org, opts);
932
+ }
933
+ const pending = owner !== undefined && reviewed !== undefined;
934
+ // An org's first version without an extension is installed at once: applied (P3-52)
935
+ if (owner !== undefined && created && !pending)
936
+ await markVersionApplied(t, itemId, staged.version);
937
+ if (pending) {
938
+ // Waits for the super admin; a later upload replaces the pending version (P3-10, P3-11)
939
+ await t
940
+ .updateTable("catalog_items")
941
+ .set({
942
+ ...(created && { awaiting_confirmation: true }),
943
+ pending_version: staged.version,
944
+ pending_by: actor,
945
+ pending_at: sql `now()`,
946
+ })
947
+ .where("id", "=", itemId)
948
+ .execute();
949
+ }
950
+ // A first version still waiting replaced by one without an extension: applied at once
951
+ const replacedAwaiting = owner !== undefined && !pending && existing?.awaiting_confirmation === true;
952
+ if (replacedAwaiting) {
953
+ await t
954
+ .updateTable("catalog_items")
955
+ .set({
956
+ awaiting_confirmation: false,
957
+ pending_version: null,
958
+ pending_by: null,
959
+ pending_at: null,
960
+ latest_version: staged.version,
961
+ })
962
+ .where("id", "=", itemId)
963
+ .execute();
964
+ await markVersionApplied(t, itemId, staged.version);
965
+ await releaseExtensionClaim(t, m.name, existing.package_name);
966
+ }
967
+ return {
968
+ itemId,
969
+ created,
970
+ firstVersion: (created && !pending) || replacedAwaiting,
971
+ pending,
972
+ now,
973
+ previous,
974
+ };
975
+ }
976
+ /**
977
+ * The platform components of a new item. The item is committed already, so a failure is logged
978
+ * and not thrown (like a failed deploy, the import itself succeeded); a run of the platform
979
+ * components migration job (which writes what is missing) is enqueued on `cap-kernel-maintenance`
980
+ * after {@link PLATFORM_SYNC_RETRY_MS}, one per item (deterministic job id). If that run fails
981
+ * too, its `itemsFailed` shows in the super admin's inbox; the daily run and every worker start
982
+ * try again.
983
+ */
984
+ async syncPlatform(itemId, version) {
985
+ try {
986
+ await this.platform.syncFromVersion(itemId, version, { initial: true });
987
+ }
988
+ catch (err) {
989
+ // Removed meanwhile (an org deletion racing a confirmation, P3-20): nothing to write
990
+ const live = await this.db
991
+ .selectFrom("catalog_items")
992
+ .select("id")
993
+ .where("id", "=", itemId)
994
+ .where("deleted_at", "is", null)
995
+ .executeTakeFirst();
996
+ if (live === undefined) {
997
+ this.log.info("catalog item removed before its platform components were written", {
998
+ itemId,
999
+ version,
1000
+ });
1001
+ return;
1002
+ }
1003
+ this.log.error("writing the platform components of a new catalog item failed", {
1004
+ itemId,
1005
+ version,
1006
+ err,
1007
+ });
1008
+ try {
1009
+ await this.maintenance.add(PLATFORM_MIGRATION_JOB, {}, {
1010
+ jobId: `${PLATFORM_MIGRATION_JOB}-retry-${itemId}`,
1011
+ delay: PLATFORM_SYNC_RETRY_MS,
1012
+ attempts: 1,
1013
+ removeOnComplete: true,
1014
+ removeOnFail: { age: 86_400 },
1015
+ });
1016
+ }
1017
+ catch (e) {
1018
+ this.log.warn("cannot enqueue the platform components migration", { itemId, err: e });
1019
+ }
1020
+ }
600
1021
  }
601
1022
  /**
602
1023
  * Writes the extension's permission snapshot for the version being imported (source web; cli
@@ -786,7 +1207,7 @@ let PluginImport = class PluginImport {
786
1207
  const t = this.db;
787
1208
  const locked = await t
788
1209
  .selectFrom("plugin_import_staging")
789
- .select("id")
1210
+ .select(["id", "org_id", "review", "manifest"])
790
1211
  .where("id", "=", r.id)
791
1212
  .where("expires_at", "<=", sql `now()`)
792
1213
  .forUpdate()
@@ -797,8 +1218,67 @@ let PluginImport = class PluginImport {
797
1218
  if (r.object_prefix)
798
1219
  await this.files.deployment().deletePrefix(r.object_prefix);
799
1220
  await t.deleteFrom("plugin_import_staging").where("id", "=", r.id).execute();
1221
+ await this.dropOrgPackage(locked);
800
1222
  return true;
801
1223
  }
1224
+ /**
1225
+ * An expired org staging's extension package (an org upload stores it at prepare, P3-10): removed
1226
+ * with the staging unless something else uses it — an install (running or migrated), a catalog
1227
+ * version, another staging — or it was stored by anyone else (the package row's source must be
1228
+ * this staging's own `catalog` ref). A platform staging keeps its package, as before. Its object
1229
+ * is deleted after the commit.
1230
+ */
1231
+ async dropOrgPackage(row) {
1232
+ const sha = row.review.extension?.sha256;
1233
+ if (row.org_id === null || sha === undefined)
1234
+ return;
1235
+ const staged = row.manifest;
1236
+ const t = this.db;
1237
+ const pkg = await t
1238
+ .selectFrom("extension_packages")
1239
+ .select("blob_store")
1240
+ .where("sha256", "=", sha)
1241
+ .where("source", "=", "catalog")
1242
+ .where("source_ref", "=", `${staged.itemId}@${staged.version}`)
1243
+ .forUpdate()
1244
+ .executeTakeFirst();
1245
+ if (!pkg)
1246
+ return;
1247
+ const used = (await t
1248
+ .selectFrom("extension_installs")
1249
+ .select("name")
1250
+ .where((eb) => eb.or([eb("sha256", "=", sha), eb("migrated_sha", "=", sha)]))
1251
+ .executeTakeFirst()) ??
1252
+ (await t
1253
+ .selectFrom("catalog_item_versions")
1254
+ .select("version")
1255
+ .where("extension_sha256", "=", sha)
1256
+ .executeTakeFirst()) ??
1257
+ (await t
1258
+ .selectFrom("plugin_import_staging")
1259
+ .select("id")
1260
+ .where(sql `review->'extension'->>'sha256' = ${sha}`)
1261
+ .executeTakeFirst());
1262
+ if (used !== undefined)
1263
+ return;
1264
+ // extension_blobs (a PG-stored package) goes with the row (ON DELETE CASCADE)
1265
+ await t.deleteFrom("extension_packages").where("sha256", "=", sha).execute();
1266
+ // The object only once the row is gone for good: a failure leaves an unreferenced object
1267
+ // (harmless; a later upload of the same bytes rewrites it), never a row without its bytes
1268
+ if (pkg.blob_store === "object") {
1269
+ afterCommit(async () => {
1270
+ try {
1271
+ await this.files.deployment().delete(blobKey(sha));
1272
+ }
1273
+ catch (err) {
1274
+ this.log.warn("cannot delete an expired org upload's extension package object", {
1275
+ sha256: sha,
1276
+ err,
1277
+ });
1278
+ }
1279
+ });
1280
+ }
1281
+ }
802
1282
  // ---------------------------------------------------------------------------------------------
803
1283
  /** npm / marketplace imports: the package must be the one that was asked for. */
804
1284
  checkExpected(pkg, expect, format = "capybara") {
@@ -943,26 +1423,52 @@ let PluginImport = class PluginImport {
943
1423
  }
944
1424
  /**
945
1425
  * The highest imported, non-deleted catalog version satisfying each dependency's range (null when
946
- * none does).
1426
+ * none does). An org upload (`owner`, P3-13) resolves only against items the org can use
1427
+ * ({@link usableBy}: confirmed, not disabled, offered to it), and any dependency left unresolved
1428
+ * -> 409 `plugin.dependency_unavailable` (details `[{ dependencies }]`, their names): an org
1429
+ * upload never brings in anything the org could not install itself.
947
1430
  */
948
- async resolveDependencies(m) {
1431
+ async resolveDependencies(m, owner) {
949
1432
  const deps = m.dependencies ?? [];
950
1433
  if (deps.length === 0)
951
1434
  return [];
952
- const rows = await this.db
1435
+ const names = deps.map((d) => d.name);
1436
+ const versions = this.db
953
1437
  .selectFrom("catalog_items as i")
954
1438
  .innerJoin("catalog_item_versions as v", "v.item_id", "i.id")
955
- .select(["i.name", "v.version", "v.imported_at"])
956
1439
  .where("i.deleted_at", "is", null)
957
- .where("i.name", "in", deps.map((d) => d.name))
958
- .execute();
959
- return deps.map((d) => ({
1440
+ .where("i.name", "in", names);
1441
+ const rows = owner === undefined
1442
+ ? await versions.select(["i.name", "v.version", "v.imported_at"]).execute()
1443
+ : (await versions
1444
+ // the org's own row of a `named` list (usableBy reads whether it is listed)
1445
+ .leftJoin("catalog_item_scope_orgs as so", (j) => j.onRef("so.item_id", "=", "i.id").on("so.org_id", "=", owner.orgId))
1446
+ .select([
1447
+ "i.name",
1448
+ "v.version",
1449
+ "v.imported_at",
1450
+ "i.scope",
1451
+ "i.builtin",
1452
+ "i.disabled",
1453
+ "i.deleted_at",
1454
+ "i.awaiting_confirmation",
1455
+ "i.owner_org_id",
1456
+ "i.shareable",
1457
+ "so.org_id as listed",
1458
+ ])
1459
+ .execute()).filter((r) => usableBy(r, owner.orgId, r.listed !== null));
1460
+ const resolved = deps.map((d) => ({
960
1461
  name: d.name,
961
1462
  range: d.version,
962
1463
  resolved: maxSatisfying(rows
963
1464
  .filter((r) => r.name === d.name)
964
1465
  .map((r) => ({ version: r.version, importedAt: r.imported_at })), d.version)?.version ?? null,
965
1466
  }));
1467
+ const missing = resolved.filter((d) => d.resolved === null).map((d) => d.name);
1468
+ if (owner !== undefined && missing.length > 0) {
1469
+ throw new ApiError("plugin.dependency_unavailable", `Dependencies not available to this organization: ${missing.join(", ")}`, [{ dependencies: missing }]);
1470
+ }
1471
+ return resolved;
966
1472
  }
967
1473
  /**
968
1474
  * The extension's state on the deployment; installed from another npm package ->
@@ -980,7 +1486,7 @@ let PluginImport = class PluginImport {
980
1486
  .where("extension_installs.name", "=", name)
981
1487
  .executeTakeFirst();
982
1488
  if (r && r.package_name !== packageName) {
983
- throw new ApiError("extension.name_conflict", `Extension ${name} is already installed from package ${r.package_name}; package ${packageName} cannot use it`);
1489
+ throw new ApiError("extension.name_conflict", `Extension ${name} is already installed from package ${r.package_name}; package ${packageName} cannot use it`, [{ owner: await packageOwner(this.db, r.package_name, name) }]);
984
1490
  }
985
1491
  return r
986
1492
  ? { kind: "installed", version: r.version, sha256: r.sha256, packageName: r.package_name }
@@ -1002,7 +1508,7 @@ let PluginImport = class PluginImport {
1002
1508
  name,
1003
1509
  version: pkg.section.version,
1004
1510
  sha256: pkg.sha256,
1005
- ...actionOf(state, pkg.sha256),
1511
+ ...actionOf(state, pkg.sha256, pkg.section.version),
1006
1512
  permissions,
1007
1513
  added,
1008
1514
  addedItems: permissionKeyItems(added),
@@ -1027,10 +1533,11 @@ let PluginImport = class PluginImport {
1027
1533
  .executeTakeFirstOrThrow();
1028
1534
  const versions = await this.db
1029
1535
  .selectFrom("catalog_item_versions")
1030
- .select(["version", "source", "imported_at"])
1536
+ .select(["version", "source", "imported_at", "extension_sha256", "manifest", "source_format"])
1031
1537
  .where("item_id", "=", itemId)
1032
1538
  .execute();
1033
- return itemView(item, versions);
1539
+ const facts = await itemScopeFacts(this.db, [item], await itemConfirmations(this.admin, [item], new Map([[item.id, versions]])));
1540
+ return itemView(item, versions, 0, undefined, facts.get(item.id));
1034
1541
  }
1035
1542
  };
1036
1543
  __decorate([
@@ -1054,21 +1561,28 @@ __decorate([
1054
1561
  __decorate([
1055
1562
  Transactional()
1056
1563
  ], PluginImport.prototype, "cleanupOne", null);
1564
+ __decorate([
1565
+ Transactional({ propagation: "mandatory" })
1566
+ ], PluginImport.prototype, "dropOrgPackage", null);
1057
1567
  PluginImport = __decorate([
1058
1568
  Injectable(),
1059
1569
  __param(0, Inject(KernelDb)),
1060
- __param(1, Inject(EnterpriseAdminLock)),
1061
- __param(2, Inject(PluginInstallLock)),
1062
- __param(3, Inject(PluginApproveLock)),
1063
- __param(4, Inject(CatalogItemLock)),
1064
- __param(5, Inject(KernelConfigService)),
1065
- __param(6, Inject(StorageService)),
1066
- __param(7, Inject(ExtensionInstalls)),
1067
- __param(8, Inject(ExtensionAdminOps)),
1068
- __param(9, Inject(ExtensionBlobs)),
1069
- __param(10, Inject(ExtensionRegistry)),
1070
- __param(11, Inject(KERNEL_LOGGER)),
1071
- __param(12, Inject(TransactionHost))
1570
+ __param(1, Inject(SuperAdminLock)),
1571
+ __param(2, Inject(OrgLock)),
1572
+ __param(3, Inject(PluginInstallLock)),
1573
+ __param(4, Inject(PluginApproveLock)),
1574
+ __param(5, Inject(CatalogItemLock)),
1575
+ __param(6, Inject(KernelConfigService)),
1576
+ __param(7, Inject(StorageService)),
1577
+ __param(8, Inject(ExtensionInstalls)),
1578
+ __param(9, Inject(ExtensionAdminOps)),
1579
+ __param(10, Inject(ExtensionAdmin)),
1580
+ __param(11, Inject(ExtensionBlobs)),
1581
+ __param(12, Inject(ExtensionRegistry)),
1582
+ __param(13, Inject(KERNEL_LOGGER)),
1583
+ __param(14, Inject(TransactionHost)),
1584
+ __param(15, Inject(PlatformComponents)),
1585
+ __param(16, Inject(getQueueToken(MAINTENANCE_QUEUE_NAME)))
1072
1586
  ], PluginImport);
1073
1587
  export { PluginImport };
1074
1588
  /**
@@ -1097,13 +1611,20 @@ function packageNameOf(pkg) {
1097
1611
  return typeof name === "string" ? name : null;
1098
1612
  }
1099
1613
  /** The extension's deployment state -> action and current version. */
1100
- function actionOf(s, sha256) {
1614
+ function actionOf(s, sha256, version) {
1101
1615
  if (s.kind === "installed") {
1616
+ // A version below the deployed one is recorded in the catalog only: an import never
1617
+ // downgrades the deployment (ruling H)
1618
+ const older = s.sha256 !== sha256 &&
1619
+ semver.valid(version) !== null &&
1620
+ semver.valid(s.version) !== null &&
1621
+ semver.lt(version, s.version);
1102
1622
  return {
1103
- action: s.sha256 === sha256 ? "keep" : "upgrade",
1623
+ action: s.sha256 === sha256 || older ? "keep" : "upgrade",
1104
1624
  deployed: true,
1105
1625
  currentVersion: s.version,
1106
1626
  currentSha256: s.sha256,
1627
+ ...(older && { olderThanDeployed: true }),
1107
1628
  };
1108
1629
  }
1109
1630
  return { action: "install", deployed: false, currentVersion: null, currentSha256: null };
@@ -1206,3 +1727,22 @@ function pinnedNames(m, review) {
1206
1727
  const byPath = new Map(review.skills.map((s) => [s.path, s.name]));
1207
1728
  return (m.skills ?? []).filter((s) => s.pinned === true).map((s) => byPath.get(s.path) ?? s.path);
1208
1729
  }
1730
+ /**
1731
+ * The staging rows a route may see (P3-8): the platform's (`org_id` null) without an owner, else
1732
+ * the owner org's.
1733
+ */
1734
+ function ownStaging(owner) {
1735
+ return (eb) => owner === undefined ? eb("org_id", "is", null) : eb("org_id", "=", owner.orgId);
1736
+ }
1737
+ /**
1738
+ * An org upload's custom deny, by content (ruling P3-15'): skills or agent templates ->
1739
+ * `customSkills`, connector templates -> `customConnectors`; each `deny` -> 403
1740
+ * `catalog.custom_disabled`. A package carrying neither passes.
1741
+ */
1742
+ async function assertCustomContent(db, content) {
1743
+ if (content.skills.length > 0 || content.agentTemplates.length > 0) {
1744
+ await assertCustomAllowed(db, "customSkills");
1745
+ }
1746
+ if (content.templates.length > 0)
1747
+ await assertCustomAllowed(db, "customConnectors");
1748
+ }