@capybara-hq/kernel 0.1.0-rc.4 → 0.1.0-rc.6

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 (534) hide show
  1. package/bootstrap.json +61 -5
  2. package/dist/admin/admin.controller.d.ts +51 -14
  3. package/dist/admin/admin.controller.js +60 -19
  4. package/dist/admin/extensions.controller.d.ts +16 -2
  5. package/dist/admin/extensions.controller.js +26 -6
  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 +16 -0
  13. package/dist/agents/agent-lookup.js +11 -0
  14. package/dist/agents/agents.controller.d.ts +76 -1
  15. package/dist/agents/agents.controller.js +90 -11
  16. package/dist/agents/agents.module.d.ts +4 -1
  17. package/dist/agents/agents.module.js +32 -6
  18. package/dist/agents/agents.service.d.ts +54 -23
  19. package/dist/agents/agents.service.js +180 -76
  20. package/dist/agents/definition.d.ts +49 -0
  21. package/dist/agents/definition.js +45 -0
  22. package/dist/agents/from-template.d.ts +106 -0
  23. package/dist/agents/from-template.js +649 -0
  24. package/dist/agents/from-template.service.d.ts +60 -0
  25. package/dist/agents/from-template.service.js +161 -0
  26. package/dist/agents/models.controller.d.ts +34 -5
  27. package/dist/agents/models.controller.js +50 -6
  28. package/dist/agents/org-templates.d.ts +176 -0
  29. package/dist/agents/org-templates.js +827 -0
  30. package/dist/agents/pending-connector-requests.d.ts +77 -0
  31. package/dist/agents/pending-connector-requests.js +215 -0
  32. package/dist/agents/pending-connectors.controller.d.ts +39 -0
  33. package/dist/agents/pending-connectors.controller.js +91 -0
  34. package/dist/agents/pending-connectors.service.d.ts +62 -0
  35. package/dist/agents/pending-connectors.service.js +282 -0
  36. package/dist/agents/readiness.controller.d.ts +5 -5
  37. package/dist/agents/readiness.controller.js +6 -6
  38. package/dist/agents/templates.controller.d.ts +86 -5
  39. package/dist/agents/templates.controller.js +171 -7
  40. package/dist/agents/templates.d.ts +127 -23
  41. package/dist/agents/templates.js +475 -52
  42. package/dist/background/background.module.js +8 -1
  43. package/dist/background/finish.d.ts +3 -2
  44. package/dist/background/launch-lock.d.ts +4 -3
  45. package/dist/background/launch-lock.js +4 -3
  46. package/dist/background/poll.job.d.ts +9 -6
  47. package/dist/background/poll.job.js +30 -22
  48. package/dist/background/session.d.ts +13 -2
  49. package/dist/background/session.js +13 -0
  50. package/dist/background/stop.d.ts +12 -6
  51. package/dist/background/stop.js +57 -39
  52. package/dist/background/store.d.ts +18 -6
  53. package/dist/background/store.js +12 -6
  54. package/dist/background/tasks.service.d.ts +15 -5
  55. package/dist/background/tasks.service.js +42 -17
  56. package/dist/background/wake-rules.d.ts +27 -18
  57. package/dist/background/wake-rules.js +52 -22
  58. package/dist/background/wake.d.ts +13 -11
  59. package/dist/background/wake.js +20 -14
  60. package/dist/catalog/admin-catalog.controller.d.ts +129 -30
  61. package/dist/catalog/admin-catalog.controller.js +213 -42
  62. package/dist/catalog/catalog-content.d.ts +58 -32
  63. package/dist/catalog/catalog-content.js +34 -8
  64. package/dist/catalog/catalog-import.module.d.ts +7 -0
  65. package/dist/catalog/catalog-import.module.js +60 -0
  66. package/dist/catalog/catalog-items.d.ts +111 -7
  67. package/dist/catalog/catalog-items.js +279 -13
  68. package/dist/catalog/catalog-scope.service.d.ts +260 -0
  69. package/dist/catalog/catalog-scope.service.js +1116 -0
  70. package/dist/catalog/catalog.module.d.ts +7 -9
  71. package/dist/catalog/catalog.module.js +41 -31
  72. package/dist/catalog/catalog.service.d.ts +101 -29
  73. package/dist/catalog/catalog.service.js +104 -106
  74. package/dist/catalog/cli.d.ts +11 -1
  75. package/dist/catalog/cli.js +26 -1
  76. package/dist/catalog/component-promotion.d.ts +96 -0
  77. package/dist/catalog/component-promotion.js +395 -0
  78. package/dist/catalog/component-scope.controller.d.ts +152 -0
  79. package/dist/catalog/component-scope.controller.js +287 -0
  80. package/dist/catalog/component-scope.service.d.ts +303 -0
  81. package/dist/catalog/component-scope.service.js +936 -0
  82. package/dist/catalog/component-state.d.ts +174 -0
  83. package/dist/catalog/component-state.js +437 -0
  84. package/dist/catalog/job-ids.d.ts +30 -0
  85. package/dist/catalog/job-ids.js +25 -0
  86. package/dist/catalog/marketplace-fetch.d.ts +1 -1
  87. package/dist/catalog/marketplaces.controller.d.ts +22 -5
  88. package/dist/catalog/marketplaces.controller.js +56 -7
  89. package/dist/catalog/marketplaces.service.d.ts +54 -14
  90. package/dist/catalog/marketplaces.service.js +71 -22
  91. package/dist/catalog/org-catalog.controller.d.ts +125 -34
  92. package/dist/catalog/org-catalog.controller.js +181 -65
  93. package/dist/catalog/org-catalog.service.d.ts +65 -33
  94. package/dist/catalog/org-catalog.service.js +324 -157
  95. package/dist/catalog/org-extension-switch.d.ts +41 -0
  96. package/dist/catalog/org-extension-switch.js +115 -0
  97. package/dist/catalog/org-extension.controller.d.ts +119 -0
  98. package/dist/catalog/org-extension.controller.js +266 -0
  99. package/dist/catalog/org-plugin-uploads.controller.d.ts +98 -0
  100. package/dist/catalog/org-plugin-uploads.controller.js +213 -0
  101. package/dist/catalog/org-plugin-uploads.d.ts +63 -0
  102. package/dist/catalog/org-plugin-uploads.js +116 -0
  103. package/dist/catalog/owned-items.d.ts +184 -0
  104. package/dist/catalog/owned-items.js +789 -0
  105. package/dist/catalog/owned-plugin-cleanup.d.ts +56 -0
  106. package/dist/catalog/owned-plugin-cleanup.js +194 -0
  107. package/dist/catalog/ownership.d.ts +172 -0
  108. package/dist/catalog/ownership.js +326 -0
  109. package/dist/catalog/platform-components.d.ts +221 -0
  110. package/dist/catalog/platform-components.js +761 -0
  111. package/dist/catalog/platform-migration.d.ts +115 -0
  112. package/dist/catalog/platform-migration.js +582 -0
  113. package/dist/catalog/plugin-import.d.ts +178 -34
  114. package/dist/catalog/plugin-import.js +622 -82
  115. package/dist/catalog/plugin-install.d.ts +185 -41
  116. package/dist/catalog/plugin-install.js +758 -126
  117. package/dist/catalog/plugin-upgrade.d.ts +260 -225
  118. package/dist/catalog/plugin-upgrade.js +1147 -1136
  119. package/dist/catalog/request-rules.d.ts +65 -0
  120. package/dist/catalog/request-rules.js +217 -0
  121. package/dist/catalog/requests.service.d.ts +193 -118
  122. package/dist/catalog/requests.service.js +526 -343
  123. package/dist/catalog/reserved-names.d.ts +8 -0
  124. package/dist/catalog/reserved-names.js +42 -0
  125. package/dist/catalog/scope-orgs.d.ts +21 -0
  126. package/dist/catalog/scope-orgs.js +67 -0
  127. package/dist/catalog/scope-state.d.ts +35 -0
  128. package/dist/catalog/scope-state.js +87 -0
  129. package/dist/catalog/scope-sync-workers.d.ts +7 -0
  130. package/dist/catalog/scope-sync-workers.js +29 -0
  131. package/dist/catalog/scope-sync.d.ts +176 -0
  132. package/dist/catalog/scope-sync.js +576 -0
  133. package/dist/catalog/scope.d.ts +42 -0
  134. package/dist/catalog/scope.js +42 -0
  135. package/dist/catalog/unshare.d.ts +22 -0
  136. package/dist/catalog/unshare.js +118 -0
  137. package/dist/channels/actions.js +1 -0
  138. package/dist/channels/cards.js +20 -2
  139. package/dist/channels/channels.module.js +2 -0
  140. package/dist/channels/inbound.d.ts +9 -1
  141. package/dist/channels/inbound.js +67 -5
  142. package/dist/channels/phrases.d.ts +35 -0
  143. package/dist/channels/phrases.js +29 -0
  144. package/dist/config/docs.js +3 -1
  145. package/dist/config/schema.d.ts +10 -2
  146. package/dist/config/schema.js +70 -22
  147. package/dist/conversations/access.d.ts +6 -4
  148. package/dist/conversations/access.js +27 -5
  149. package/dist/conversations/agent-tree.d.ts +46 -0
  150. package/dist/conversations/agent-tree.js +92 -0
  151. package/dist/conversations/conversations.controller.d.ts +43 -18
  152. package/dist/conversations/conversations.controller.js +79 -38
  153. package/dist/conversations/conversations.module.d.ts +1 -1
  154. package/dist/conversations/conversations.module.js +7 -7
  155. package/dist/conversations/conversations.service.d.ts +73 -15
  156. package/dist/conversations/conversations.service.js +115 -35
  157. package/dist/conversations/environment-status.d.ts +24 -0
  158. package/dist/conversations/environment-status.js +71 -0
  159. package/dist/conversations/event-log.d.ts +20 -5
  160. package/dist/conversations/event-log.js +60 -0
  161. package/dist/conversations/events.d.ts +84 -2
  162. package/dist/conversations/events.js +91 -17
  163. package/dist/conversations/queue.service.d.ts +1 -1
  164. package/dist/conversations/queue.service.js +5 -0
  165. package/dist/conversations/titles.d.ts +5 -3
  166. package/dist/conversations/titles.js +21 -8
  167. package/dist/conversations/tree.d.ts +17 -0
  168. package/dist/conversations/tree.js +42 -0
  169. package/dist/ctx/create-ctx.d.ts +20 -1
  170. package/dist/ctx/create-ctx.js +38 -7
  171. package/dist/db/kernel-schema.d.ts +386 -18
  172. package/dist/environments/access.d.ts +41 -0
  173. package/dist/environments/access.js +77 -0
  174. package/dist/environments/conversation-environments.d.ts +61 -0
  175. package/dist/environments/conversation-environments.js +170 -0
  176. package/dist/environments/dto.d.ts +25 -0
  177. package/dist/environments/dto.js +12 -0
  178. package/dist/environments/environments.controller.d.ts +33 -0
  179. package/dist/environments/environments.controller.js +110 -0
  180. package/dist/environments/environments.module.d.ts +8 -0
  181. package/dist/environments/environments.module.js +27 -0
  182. package/dist/environments/environments.service.d.ts +153 -0
  183. package/dist/environments/environments.service.js +541 -0
  184. package/dist/environments/legacy-cleanup.job.d.ts +34 -0
  185. package/dist/environments/legacy-cleanup.job.js +141 -0
  186. package/dist/errors.d.ts +85 -2
  187. package/dist/errors.js +85 -2
  188. package/dist/evals/reconstruct.d.ts +18 -9
  189. package/dist/evals/reconstruct.js +26 -7
  190. package/dist/evals/run-replay.d.ts +4 -2
  191. package/dist/evals/run-replay.js +20 -6
  192. package/dist/evals/runs.service.d.ts +2 -1
  193. package/dist/evals/runs.service.js +13 -12
  194. package/dist/evals/step-replay.d.ts +4 -6
  195. package/dist/evals/step-replay.js +4 -3
  196. package/dist/evals/trajectory.service.d.ts +8 -3
  197. package/dist/evals/trajectory.service.js +26 -14
  198. package/dist/evals/worker.d.ts +5 -5
  199. package/dist/evals/worker.js +9 -3
  200. package/dist/extensions/admin-ops.d.ts +36 -10
  201. package/dist/extensions/admin-ops.js +65 -42
  202. package/dist/extensions/admin-view.d.ts +37 -10
  203. package/dist/extensions/admin-view.js +103 -20
  204. package/dist/extensions/bootstrap.d.ts +17 -4
  205. package/dist/extensions/bootstrap.js +70 -9
  206. package/dist/extensions/cli.d.ts +12 -0
  207. package/dist/extensions/cli.js +11 -2
  208. package/dist/extensions/config-hash.d.ts +10 -0
  209. package/dist/extensions/config-hash.js +38 -0
  210. package/dist/extensions/deployment-config.d.ts +28 -5
  211. package/dist/extensions/deployment-config.js +48 -7
  212. package/dist/extensions/effective-config.d.ts +127 -0
  213. package/dist/extensions/effective-config.js +368 -0
  214. package/dist/extensions/extensions.module.js +11 -11
  215. package/dist/extensions/hooks.d.ts +37 -4
  216. package/dist/extensions/hooks.js +82 -16
  217. package/dist/extensions/host.d.ts +24 -10
  218. package/dist/extensions/host.js +49 -54
  219. package/dist/extensions/installs.d.ts +20 -8
  220. package/dist/extensions/installs.js +37 -15
  221. package/dist/extensions/org-config.d.ts +75 -6
  222. package/dist/extensions/org-config.js +184 -32
  223. package/dist/extensions/org-levels.d.ts +37 -0
  224. package/dist/extensions/org-levels.js +71 -0
  225. package/dist/extensions/org-overrides.d.ts +151 -0
  226. package/dist/extensions/org-overrides.js +524 -0
  227. package/dist/extensions/permission-view.d.ts +16 -4
  228. package/dist/extensions/permission-view.js +4 -4
  229. package/dist/extensions/plugin-items.d.ts +21 -0
  230. package/dist/extensions/plugin-items.js +42 -0
  231. package/dist/extensions/point-defaults.d.ts +12 -5
  232. package/dist/extensions/point-defaults.js +37 -9
  233. package/dist/extensions/resolve.d.ts +5 -1
  234. package/dist/extensions/resolve.js +15 -2
  235. package/dist/extensions/state.module.d.ts +9 -0
  236. package/dist/extensions/state.module.js +38 -0
  237. package/dist/files/previewers.d.ts +8 -1
  238. package/dist/files/previewers.js +35 -6
  239. package/dist/http/api.module.js +25 -3
  240. package/dist/http/app.d.ts +11 -2
  241. package/dist/http/app.js +31 -5
  242. package/dist/http/plugin-dispatch.d.ts +4 -1
  243. package/dist/http/plugin-dispatch.js +14 -2
  244. package/dist/identity/accounts.d.ts +29 -29
  245. package/dist/identity/accounts.js +47 -47
  246. package/dist/identity/audit.d.ts +2 -1
  247. package/dist/identity/auth.guard.d.ts +13 -5
  248. package/dist/identity/auth.guard.js +26 -9
  249. package/dist/identity/identity.module.d.ts +1 -1
  250. package/dist/identity/identity.module.js +4 -4
  251. package/dist/identity/me.controller.js +1 -1
  252. package/dist/identity/principal.d.ts +3 -3
  253. package/dist/identity/principal.js +3 -3
  254. package/dist/identity/settings.d.ts +22 -11
  255. package/dist/identity/settings.js +53 -18
  256. package/dist/identity/{enterprise-admin.d.ts → super-admin.d.ts} +5 -5
  257. package/dist/identity/{enterprise-admin.js → super-admin.js} +24 -24
  258. package/dist/inbox/inbox.module.d.ts +4 -1
  259. package/dist/inbox/inbox.module.js +7 -3
  260. package/dist/inbox/inbox.service.d.ts +62 -3
  261. package/dist/inbox/inbox.service.js +74 -4
  262. package/dist/inbox/org-notices.d.ts +63 -0
  263. package/dist/inbox/org-notices.js +91 -0
  264. package/dist/inbox/platform-inbox.controller.d.ts +23 -0
  265. package/dist/inbox/platform-inbox.controller.js +58 -0
  266. package/dist/inbox/platform-inbox.service.d.ts +151 -0
  267. package/dist/inbox/platform-inbox.service.js +263 -0
  268. package/dist/inbox/platform-notices.d.ts +19 -0
  269. package/dist/inbox/platform-notices.js +9 -0
  270. package/dist/index.d.ts +1 -1
  271. package/dist/index.js +1 -1
  272. package/dist/infra/cli/kernel-cli.module.js +9 -1
  273. package/dist/infra/config/kernel-config.service.js +24 -1
  274. package/dist/infra/database/xact-lock.d.ts +1 -1
  275. package/dist/infra/database/xact-lock.js +1 -1
  276. package/dist/infra/events/kernel-events.d.ts +19 -2
  277. package/dist/infra/queue/add-job-once.d.ts +14 -0
  278. package/dist/infra/queue/add-job-once.js +16 -0
  279. package/dist/kernel.module.js +6 -0
  280. package/dist/lifecycle/kernel-lifecycle.d.ts +1 -1
  281. package/dist/lifecycle/kernel-lifecycle.js +4 -4
  282. package/dist/models/embeddings.d.ts +82 -0
  283. package/dist/models/embeddings.js +326 -0
  284. package/dist/models/enablement.controller.d.ts +40 -0
  285. package/dist/models/enablement.controller.js +74 -0
  286. package/dist/models/enablement.d.ts +99 -0
  287. package/dist/models/enablement.js +263 -0
  288. package/dist/models/models.module.d.ts +5 -1
  289. package/dist/models/models.module.js +16 -4
  290. package/dist/models/prices.d.ts +5 -5
  291. package/dist/models/prices.js +4 -4
  292. package/dist/models/purposes.controller.d.ts +6 -4
  293. package/dist/models/purposes.controller.js +13 -7
  294. package/dist/models/purposes.d.ts +37 -12
  295. package/dist/models/purposes.js +63 -17
  296. package/dist/orgs/directory-sync.d.ts +14 -5
  297. package/dist/orgs/directory-sync.js +41 -17
  298. package/dist/orgs/offboarding.d.ts +9 -7
  299. package/dist/orgs/offboarding.js +28 -17
  300. package/dist/orgs/org-lock.d.ts +5 -0
  301. package/dist/orgs/org-lock.js +13 -0
  302. package/dist/orgs/org.guard.d.ts +10 -0
  303. package/dist/orgs/org.guard.js +43 -32
  304. package/dist/orgs/orgs.module.js +3 -0
  305. package/dist/orgs/orgs.service.d.ts +20 -7
  306. package/dist/orgs/orgs.service.js +32 -12
  307. package/dist/orgs/roles.d.ts +1 -1
  308. package/dist/orgs/roles.js +5 -1
  309. package/dist/orgs/settings.controller.d.ts +1 -1
  310. package/dist/orgs/settings.service.d.ts +15 -3
  311. package/dist/orgs/settings.service.js +6 -2
  312. package/dist/overrides.d.ts +3 -0
  313. package/dist/overrides.js +2 -0
  314. package/dist/platform/actor.d.ts +48 -0
  315. package/dist/platform/actor.js +100 -0
  316. package/dist/platform/agent-docs.d.ts +18 -0
  317. package/dist/platform/agent-docs.js +59 -0
  318. package/dist/platform/availability.d.ts +14 -0
  319. package/dist/platform/availability.js +43 -0
  320. package/dist/platform/errors.d.ts +11 -0
  321. package/dist/platform/errors.js +26 -0
  322. package/dist/platform/exclusions.d.ts +12 -0
  323. package/dist/platform/exclusions.js +1405 -0
  324. package/dist/platform/method.d.ts +6 -0
  325. package/dist/platform/method.js +15 -0
  326. package/dist/platform/operation.d.ts +92 -0
  327. package/dist/platform/operation.js +35 -0
  328. package/dist/platform/ops/agent-templates.ops.d.ts +14 -0
  329. package/dist/platform/ops/agent-templates.ops.js +92 -0
  330. package/dist/platform/ops/agents.ops.d.ts +19 -0
  331. package/dist/platform/ops/agents.ops.js +294 -0
  332. package/dist/platform/ops/connectors.ops.d.ts +15 -0
  333. package/dist/platform/ops/connectors.ops.js +126 -0
  334. package/dist/platform/ops/errors.d.ts +11 -0
  335. package/dist/platform/ops/errors.js +22 -0
  336. package/dist/platform/ops/extensions.ops.d.ts +19 -0
  337. package/dist/platform/ops/extensions.ops.js +116 -0
  338. package/dist/platform/ops/marketplaces.ops.d.ts +16 -0
  339. package/dist/platform/ops/marketplaces.ops.js +157 -0
  340. package/dist/platform/ops/paging.d.ts +14 -0
  341. package/dist/platform/ops/paging.js +20 -0
  342. package/dist/platform/ops/platform.ops.d.ts +23 -0
  343. package/dist/platform/ops/platform.ops.js +158 -0
  344. package/dist/platform/ops/plugins.ops.d.ts +33 -0
  345. package/dist/platform/ops/plugins.ops.js +377 -0
  346. package/dist/platform/ops/requests.ops.d.ts +14 -0
  347. package/dist/platform/ops/requests.ops.js +153 -0
  348. package/dist/platform/ops/role.d.ts +4 -0
  349. package/dist/platform/ops/role.js +10 -0
  350. package/dist/platform/ops/skills.ops.d.ts +13 -0
  351. package/dist/platform/ops/skills.ops.js +98 -0
  352. package/dist/platform/ops/summary.d.ts +10 -0
  353. package/dist/platform/ops/summary.js +18 -0
  354. package/dist/platform/platform-ops.module.d.ts +7 -0
  355. package/dist/platform/platform-ops.module.js +55 -0
  356. package/dist/platform/platform.module.d.ts +8 -0
  357. package/dist/platform/platform.module.js +25 -0
  358. package/dist/platform/redact-orgs.d.ts +7 -0
  359. package/dist/platform/redact-orgs.js +52 -0
  360. package/dist/platform/registry.d.ts +30 -0
  361. package/dist/platform/registry.js +111 -0
  362. package/dist/roles/worker-role.d.ts +6 -4
  363. package/dist/roles/worker-role.js +14 -7
  364. package/dist/roles/worker.module.d.ts +1 -1
  365. package/dist/roles/worker.module.js +9 -1
  366. package/dist/runtime/context/build.d.ts +6 -4
  367. package/dist/runtime/context/build.js +26 -7
  368. package/dist/runtime/context/claude-tools.d.ts +2 -1
  369. package/dist/runtime/context/claude-tools.js +5 -4
  370. package/dist/runtime/context/compaction.js +9 -0
  371. package/dist/runtime/context/reminders.d.ts +2 -0
  372. package/dist/runtime/context/reminders.js +2 -0
  373. package/dist/runtime/context/skills.js +9 -2
  374. package/dist/runtime/context/tool-changes.d.ts +27 -0
  375. package/dist/runtime/context/tool-changes.js +60 -0
  376. package/dist/runtime/hook-calls.d.ts +8 -1
  377. package/dist/runtime/hook-calls.js +40 -7
  378. package/dist/runtime/langgraph-loop.d.ts +3 -1
  379. package/dist/runtime/langgraph-loop.js +35 -17
  380. package/dist/runtime/loop.d.ts +32 -4
  381. package/dist/runtime/maintenance.d.ts +7 -4
  382. package/dist/runtime/maintenance.js +23 -8
  383. package/dist/runtime/model-call.d.ts +38 -11
  384. package/dist/runtime/model-call.js +97 -24
  385. package/dist/runtime/providers.d.ts +146 -32
  386. package/dist/runtime/providers.js +321 -67
  387. package/dist/runtime/run-control.d.ts +11 -1
  388. package/dist/runtime/run-control.js +12 -0
  389. package/dist/runtime/run-drafts.d.ts +85 -0
  390. package/dist/runtime/run-drafts.js +230 -0
  391. package/dist/runtime/run-jobs.d.ts +3 -5
  392. package/dist/runtime/run-jobs.js +3 -7
  393. package/dist/runtime/run-queue.d.ts +37 -3
  394. package/dist/runtime/run-queue.js +188 -11
  395. package/dist/runtime/run-worker.d.ts +12 -6
  396. package/dist/runtime/run-worker.js +58 -35
  397. package/dist/runtime/runtime.module.js +3 -0
  398. package/dist/runtime/step-log.d.ts +9 -4
  399. package/dist/runtime/step-log.js +8 -5
  400. package/dist/runtime/stream.controller.d.ts +23 -1
  401. package/dist/runtime/stream.controller.js +60 -3
  402. package/dist/runtime/stream.d.ts +4 -1
  403. package/dist/runtime/stream.js +27 -3
  404. package/dist/runtime/subagents/child.d.ts +55 -7
  405. package/dist/runtime/subagents/child.js +105 -7
  406. package/dist/runtime/subagents/definition.d.ts +12 -3
  407. package/dist/runtime/subagents/definition.js +46 -32
  408. package/dist/runtime/subagents/deliveries.d.ts +71 -0
  409. package/dist/runtime/subagents/deliveries.js +228 -0
  410. package/dist/runtime/subagents/dispatch.d.ts +115 -26
  411. package/dist/runtime/subagents/dispatch.js +212 -141
  412. package/dist/runtime/subagents/limits.d.ts +24 -5
  413. package/dist/runtime/subagents/limits.js +40 -6
  414. package/dist/runtime/subagents/messages.d.ts +95 -0
  415. package/dist/runtime/subagents/messages.js +328 -0
  416. package/dist/runtime/subagents/preamble.d.ts +4 -4
  417. package/dist/runtime/subagents/preamble.js +9 -7
  418. package/dist/runtime/subagents/progress.d.ts +8 -6
  419. package/dist/runtime/subagents/progress.js +11 -6
  420. package/dist/runtime/subagents/render.d.ts +30 -0
  421. package/dist/runtime/subagents/render.js +53 -0
  422. package/dist/runtime/subagents/roster.d.ts +24 -7
  423. package/dist/runtime/subagents/roster.js +47 -11
  424. package/dist/runtime/subagents/skill-fork.d.ts +3 -2
  425. package/dist/runtime/subagents/skill-fork.js +8 -4
  426. package/dist/runtime/subagents/status.d.ts +14 -0
  427. package/dist/runtime/subagents/status.js +23 -0
  428. package/dist/runtime/subagents/subagents.service.d.ts +7 -4
  429. package/dist/runtime/subagents/subagents.service.js +11 -6
  430. package/dist/runtime/usage-report-jobs.d.ts +88 -0
  431. package/dist/runtime/usage-report-jobs.js +158 -0
  432. package/dist/runtime/usage-report.d.ts +33 -38
  433. package/dist/runtime/usage-report.js +169 -96
  434. package/dist/runtime/waits.d.ts +140 -37
  435. package/dist/runtime/waits.js +394 -106
  436. package/dist/sandbox/jobs.d.ts +40 -13
  437. package/dist/sandbox/jobs.js +57 -20
  438. package/dist/sandbox/leases.d.ts +37 -54
  439. package/dist/sandbox/leases.js +71 -115
  440. package/dist/sandbox/providers.d.ts +2 -2
  441. package/dist/sandbox/providers.js +1 -1
  442. package/dist/sandbox/sandbox.module.d.ts +3 -2
  443. package/dist/sandbox/sandbox.module.js +4 -3
  444. package/dist/sandbox/sandbox.service.d.ts +229 -134
  445. package/dist/sandbox/sandbox.service.js +630 -409
  446. package/dist/skills/catalog.d.ts +3 -2
  447. package/dist/skills/catalog.js +21 -43
  448. package/dist/skills/changes.controller.d.ts +7 -0
  449. package/dist/skills/changes.controller.js +19 -1
  450. package/dist/skills/invoke.js +8 -3
  451. package/dist/skills/package.d.ts +20 -1
  452. package/dist/skills/package.js +28 -1
  453. package/dist/skills/skills.controller.d.ts +39 -4
  454. package/dist/skills/skills.controller.js +88 -10
  455. package/dist/skills/skills.module.js +10 -1
  456. package/dist/skills/skills.service.d.ts +106 -26
  457. package/dist/skills/skills.service.js +421 -75
  458. package/dist/skills/usable.d.ts +81 -0
  459. package/dist/skills/usable.js +379 -0
  460. package/dist/tools/approvals.service.d.ts +20 -2
  461. package/dist/tools/approvals.service.js +23 -4
  462. package/dist/tools/builtin-names.d.ts +21 -5
  463. package/dist/tools/builtin-names.js +30 -5
  464. package/dist/tools/builtins/agent.d.ts +23 -21
  465. package/dist/tools/builtins/agent.js +62 -55
  466. package/dist/tools/builtins/builtin-tools.d.ts +6 -2
  467. package/dist/tools/builtins/builtin-tools.js +37 -12
  468. package/dist/tools/builtins/handback.d.ts +28 -0
  469. package/dist/tools/builtins/handback.js +53 -0
  470. package/dist/tools/builtins/platform.d.ts +34 -0
  471. package/dist/tools/builtins/platform.js +362 -0
  472. package/dist/tools/builtins/sandbox/bash.js +13 -3
  473. package/dist/tools/builtins/sandbox/common.d.ts +43 -24
  474. package/dist/tools/builtins/sandbox/common.js +80 -45
  475. package/dist/tools/builtins/sandbox/edit.js +2 -2
  476. package/dist/tools/builtins/sandbox/glob.js +2 -2
  477. package/dist/tools/builtins/sandbox/grep.js +2 -4
  478. package/dist/tools/builtins/sandbox/index.d.ts +1 -1
  479. package/dist/tools/builtins/sandbox/index.js +1 -1
  480. package/dist/tools/builtins/sandbox/read.js +1 -1
  481. package/dist/tools/builtins/sandbox/task-output.d.ts +14 -3
  482. package/dist/tools/builtins/sandbox/task-output.js +30 -5
  483. package/dist/tools/builtins/sandbox/task-stop.js +2 -1
  484. package/dist/tools/builtins/sandbox/write.js +2 -2
  485. package/dist/tools/builtins/send-message.d.ts +56 -0
  486. package/dist/tools/builtins/send-message.js +100 -0
  487. package/dist/tools/builtins/skill-load.d.ts +22 -14
  488. package/dist/tools/builtins/skill-load.js +86 -57
  489. package/dist/tools/builtins/skill-write.js +1 -1
  490. package/dist/tools/builtins/web/extract.js +5 -1
  491. package/dist/tools/builtins/web/fetch.js +1 -0
  492. package/dist/tools/builtins/web/search.js +1 -0
  493. package/dist/tools/connectors.controller.d.ts +10 -0
  494. package/dist/tools/connectors.controller.js +12 -0
  495. package/dist/tools/connectors.service.d.ts +46 -5
  496. package/dist/tools/connectors.service.js +94 -15
  497. package/dist/tools/extension-tools.controller.d.ts +14 -0
  498. package/dist/tools/extension-tools.controller.js +37 -0
  499. package/dist/tools/info.d.ts +42 -1
  500. package/dist/tools/info.js +64 -1
  501. package/dist/tools/org-tool-switches.d.ts +74 -0
  502. package/dist/tools/org-tool-switches.js +184 -0
  503. package/dist/tools/pipeline.d.ts +46 -40
  504. package/dist/tools/pipeline.js +193 -364
  505. package/dist/tools/policy.d.ts +1 -1
  506. package/dist/tools/policy.js +36 -16
  507. package/dist/tools/registry.d.ts +98 -5
  508. package/dist/tools/registry.js +87 -9
  509. package/dist/tools/tools.module.js +12 -2
  510. package/dist/ui/views.d.ts +2 -1
  511. package/dist/ui/views.js +17 -3
  512. package/package.json +3 -3
  513. package/src/migrations/0074_subagent_tree.sql +50 -0
  514. package/src/migrations/0075_plugin_scope.sql +61 -0
  515. package/src/migrations/0076_skills_created_by_nullable.sql +6 -0
  516. package/src/migrations/0077_scope_requests.sql +52 -0
  517. package/src/migrations/0078_scope_grant_switches.sql +18 -0
  518. package/src/migrations/0079_scope_live_install_switches.sql +19 -0
  519. package/src/migrations/0080_rename_enterprise_admin.sql +18 -0
  520. package/src/migrations/0081_platform_components.sql +129 -0
  521. package/src/migrations/0082_platform_migration.sql +33 -0
  522. package/src/migrations/0083_plugin_scope_sync_failures.sql +15 -0
  523. package/src/migrations/0084_org_owned_items.sql +85 -0
  524. package/src/migrations/0085_agent_templates_phase4.sql +45 -0
  525. package/src/migrations/0086_org_layering.sql +30 -0
  526. package/src/migrations/0087_approval_summary.sql +6 -0
  527. package/src/migrations/0088_environments.sql +80 -0
  528. package/src/migrations/0089_model_kinds_usage.sql +38 -0
  529. package/dist/catalog/upgrade-targets.d.ts +0 -56
  530. package/dist/catalog/upgrade-targets.js +0 -90
  531. package/dist/conversations/sandbox-status.d.ts +0 -24
  532. package/dist/conversations/sandbox-status.js +0 -52
  533. package/dist/extensions/org-config.controller.d.ts +0 -32
  534. package/dist/extensions/org-config.controller.js +0 -70
@@ -7,12 +7,12 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
7
  var __param = (this && this.__param) || function (paramIndex, decorator) {
8
8
  return function (target, key) { decorator(target, key, paramIndex); }
9
9
  };
10
- import { randomUUID } from "node:crypto";
11
- import { EXTENSION_POINTS, parseExtensionPoint, parseSkillMd, SKILL_ENTRY_FILE, } from "@capybara-hq/plugin-sdk";
10
+ import { createHash, randomUUID } from "node:crypto";
11
+ import { EXTENSION_POINTS, marketplaceEntryDeprecation, parseExtensionPoint, parseSkillMd, SKILL_ENTRY_FILE, } from "@capybara-hq/plugin-sdk";
12
12
  import { Inject, Injectable } from "@nestjs/common";
13
13
  import { sql } from "kysely";
14
- import { normalizeToolRef } from "../agents/definition.js";
15
- import { putTemplateVersionIn, revertTemplateVersionIn, softDeleteTemplateIn, } from "../agents/templates.js";
14
+ import semver from "semver";
15
+ import { revertTemplateVersionIn, softDeleteTemplateIn } from "../agents/templates.js";
16
16
  import { ApiError } from "../errors.js";
17
17
  import { isExtensionEnabled } from "../extensions/enabled.js";
18
18
  import { OrgExtensionConfigs, } from "../extensions/org-config.js";
@@ -29,10 +29,48 @@ import { packagePath } from "../packages/tgz.js";
29
29
  import { SkillsService, skillConflictError, skillConflicts, } from "../skills/skills.service.js";
30
30
  import { StorageService } from "../storage/storage.service.js";
31
31
  import { ConnectorsService } from "../tools/connectors.service.js";
32
- import { findConnectorIn, lockOrgForActions, readCatalogAgentTemplates, readCatalogFiles, readCatalogTemplates, requiredActions, skillOf, templateConnectorInput, templatePluginProblem, } from "./catalog-content.js";
33
- import { assertItemInstallable, CatalogRequestsService, disabledPluginItems, pluginItemDisabled, } from "./requests.service.js";
34
- import { upgradeInfo } from "./upgrade-targets.js";
32
+ import { findConnectorIn, lockOrgForActions, readCatalogAgentTemplates, readCatalogFiles, readCatalogTemplates, requiredActions, templateConnectorInput, templatePluginProblem, } from "./catalog-content.js";
33
+ import { versionUsable } from "./catalog-items.js";
34
+ import { agentDefinitionRefs, componentOn, connectorTemplateState, connectorTemplatesOn, listedIn, loadComponents, loadScopeState, pluginFactsOf, referenceIds, switchOf, } from "./component-state.js";
35
+ import { assertItemInstallable, disabledPluginItems, pluginItemDisabled, resolveRequestsByInstall, } from "./request-rules.js";
36
+ import { visibleTo } from "./scope.js";
37
+ import { ScopeNoLongerWanted, ScopeStillWanted, wantedByScope } from "./scope-state.js";
35
38
  import { maxSatisfying, satisfiesRange } from "./versions.js";
39
+ /** The confirm hash of an uninstall preview: sha256 over its sorted JSON (the scheme of `diffHash`). */
40
+ export function uninstallPreviewHash(p) {
41
+ const by = (xs) => [...xs].sort((a, b) => `${a.kind}:${a.ref}`.localeCompare(`${b.kind}:${b.ref}`));
42
+ return createHash("sha256")
43
+ .update(JSON.stringify({
44
+ ...p,
45
+ components: by(p.components),
46
+ kept: by(p.kept),
47
+ agents: [...p.agents]
48
+ .sort((a, b) => a.id.localeCompare(b.id))
49
+ .map((a) => ({ ...a, uses: by(a.uses) })),
50
+ }))
51
+ .digest("hex");
52
+ }
53
+ /** Upserts the org's switch row of an item in the caller's transaction (the org lock is held). */
54
+ export async function upsertOrgSwitch(db, orgId, itemId, enabled, actor) {
55
+ await db
56
+ .insertInto("catalog_item_org_switches")
57
+ .values({ item_id: itemId, org_id: orgId, enabled, updated_by: actor })
58
+ .onConflict((oc) => oc.columns(["item_id", "org_id"]).doUpdateSet({
59
+ enabled,
60
+ updated_by: actor,
61
+ updated_at: sql `now()`,
62
+ }))
63
+ .execute();
64
+ }
65
+ /** The kernel (actor null, the scope sync) never installs what needs the org's input. */
66
+ export class NeedsOrgInput extends ApiError {
67
+ plugin;
68
+ constructor(plugin) {
69
+ super("internal", `Plugin ${plugin} needs the organization's input (connector templates); only a person can install it`);
70
+ this.plugin = plugin;
71
+ }
72
+ }
73
+ const systemNeedsInput = (name) => new NeedsOrgInput(name);
36
74
  /** How deep plugin dependencies may nest (the root plugin's dependencies are level 1). */
37
75
  export const DEPENDENCY_DEPTH_LIMIT = 10;
38
76
  /** A failed install step, carried up through the dependency installs to the root install. */
@@ -65,33 +103,66 @@ const installNotFound = () => new ApiError("plugin.install_not_found", "Plugin i
65
103
  const fail = (path, message) => new ApiError("validation_failed", "Request validation failed", [{ path, message }]);
66
104
  const isUniqueViolation = (e) => typeof e === "object" && e !== null && e.code === "23505";
67
105
  const unresolved = (name, range, why) => new ApiError("catalog.dependency_unresolved", `Dependency ${name}@${range} cannot be resolved: ${why}`, [{ dependency: name, range }]);
68
- const dependencyDisabled = (name) => new ApiError("catalog.dependency_disabled", `Dependency ${name} is disabled by the enterprise admin, so this plugin cannot be installed`, [{ dependency: name }]);
106
+ const dependencyDisabled = (name) => new ApiError("catalog.dependency_disabled", `Dependency ${name} is disabled by the super admin, so this plugin cannot be installed`, [{ dependency: name }]);
69
107
  /**
70
- * The dependency `d` resolved against the catalog: the highest imported version (of the live item
71
- * with that name) satisfying its range. No such item or version -> `catalog.dependency_unresolved`;
72
- * the item disabled -> `catalog.dependency_disabled` (the enterprise admin's ban is not bypassed,
73
- * spec §10).
108
+ * The dependency `d` resolved against the catalog (ruling P2-17, one version per deployment): the
109
+ * dependency's platform version (`platform_synced_version`), which must satisfy its range; only
110
+ * while it has none yet (its first sync failed), the highest imported version satisfying the range
111
+ * that its marketplace does not deprecate, a stable one before a prerelease (the marketplace
112
+ * folding rule). No such item or version -> `catalog.dependency_unresolved`; the item disabled ->
113
+ * `catalog.dependency_disabled` (the super admin's ban is not bypassed, spec §10).
74
114
  */
75
115
  async function resolveOne(db, d) {
76
116
  const item = await db
77
117
  .selectFrom("catalog_items")
78
- .select(["id", "policy"])
118
+ .select([
119
+ "id",
120
+ "disabled",
121
+ "platform_synced_version",
122
+ "marketplace_id",
123
+ "awaiting_confirmation",
124
+ "owner_org_id",
125
+ "latest_version",
126
+ ])
79
127
  .where("name", "=", d.name)
80
128
  .where("deleted_at", "is", null)
81
129
  .executeTakeFirst();
82
130
  if (!item) {
83
- throw unresolved(d.name, d.version, "it is not in the enterprise catalog; ask the enterprise admin to import it");
131
+ throw unresolved(d.name, d.version, "it is not in the platform catalog; ask the super admin to import it");
84
132
  }
85
- if (item.policy === "disabled")
133
+ if (item.disabled)
86
134
  throw dependencyDisabled(d.name);
135
+ // An org upload waiting for the super admin is no dependency target (ruling P3-9)
136
+ if (item.awaiting_confirmation) {
137
+ throw unresolved(d.name, d.version, "it waits for a super admin to confirm its extension");
138
+ }
87
139
  const versions = await db
88
140
  .selectFrom("catalog_item_versions")
89
- .select(["version", "manifest", "imported_at"])
141
+ .select(["version", "manifest", "imported_at", "applied_at", "rejected_at"])
90
142
  .where("item_id", "=", item.id)
91
143
  .execute();
92
- const v = maxSatisfying(versions.map((x) => ({ ...x, importedAt: x.imported_at })), d.version);
144
+ let v;
145
+ if (item.platform_synced_version !== null) {
146
+ v = versions.find((x) => x.version === item.platform_synced_version);
147
+ if (!v || !satisfiesRange(v.version, d.version)) {
148
+ throw unresolved(d.name, d.version, `its platform version ${item.platform_synced_version} does not satisfy the range; ask ` +
149
+ "the super admin to update it");
150
+ }
151
+ }
152
+ else {
153
+ const deprecated = await deprecatedVersions(db, d.name, item.marketplace_id);
154
+ // An org's plugin offers only its applied version: never one pending or rejected (P3-34),
155
+ // also once transferred to the platform (P3-52)
156
+ const candidates = versions
157
+ .filter((x) => versionUsable(x))
158
+ .filter((x) => item.owner_org_id === null || x.version === item.latest_version)
159
+ .filter((x) => !deprecated.has(x.version))
160
+ .map((x) => ({ ...x, importedAt: x.imported_at }));
161
+ v =
162
+ maxSatisfying(candidates.filter((x) => semver.prerelease(x.version) === null), d.version) ?? maxSatisfying(candidates, d.version);
163
+ }
93
164
  if (!v) {
94
- throw unresolved(d.name, d.version, "no imported version satisfies the range; ask the enterprise admin to import one");
165
+ throw unresolved(d.name, d.version, "no imported version satisfies the range; ask the super admin to import one");
95
166
  }
96
167
  return {
97
168
  name: d.name,
@@ -101,10 +172,24 @@ async function resolveOne(db, d) {
101
172
  manifest: v.manifest,
102
173
  };
103
174
  }
175
+ /** The versions of plugin `name` its marketplace (`marketplaceId`) marks deprecated. */
176
+ async function deprecatedVersions(db, name, marketplaceId) {
177
+ if (marketplaceId === null)
178
+ return new Set();
179
+ const rows = await db
180
+ .selectFrom("marketplace_entries")
181
+ .select(["version", "entry"])
182
+ .where("source_id", "=", marketplaceId)
183
+ .where("name", "=", name)
184
+ .execute();
185
+ return new Set(rows
186
+ .filter((r) => marketplaceEntryDeprecation(r.entry) !== null)
187
+ .map((r) => r.version));
188
+ }
104
189
  /**
105
- * Resolves a plugin's dependencies against the catalog: for each one the highest imported version
106
- * of the live item with that name satisfying its range. The whole dependency tree is checked: a
107
- * dependency nothing satisfies -> `catalog.dependency_unresolved`; a disabled one ->
190
+ * Resolves a plugin's dependencies against the catalog: for each one the platform version of the
191
+ * live item with that name, which must satisfy its range (see `resolveOne`). The whole dependency
192
+ * tree is checked: a dependency nothing satisfies -> `catalog.dependency_unresolved`; a disabled one ->
108
193
  * `catalog.dependency_disabled`; a cycle (`a` -> `b` -> `a`, by name) or nesting deeper than
109
194
  * {@link DEPENDENCY_DEPTH_LIMIT} -> `catalog.dependency_cycle`. Returns the direct dependencies.
110
195
  */
@@ -189,9 +274,11 @@ export function under(e, at) {
189
274
  * not run it; already enabled is recorded created=false);
190
275
  * 3. connectors from the templates (credentials / clients go to secrets, default policies are
191
276
  * recorded `policy_source 'template'`);
192
- * 4. the skills (an org skill of the same name from the same catalog item gets a new version,
193
- * recorded created=false with skill_version; one of other provenance, the org's own or another
194
- * item's, refuses the install while planning with `plugin.skill_conflict`, spec §9.2).
277
+ * The plugin's skills and agent templates are platform components (plugin scope phase 2): stored
278
+ * once for the deployment and on in the org while the plugin is, so an install writes no org rows
279
+ * for them; a skill name the org already uses (its own skill, another plugin's) refuses the install
280
+ * while planning with `plugin.skill_conflict` (spec §9.2, rule 10). Uninstall leaves the org copies
281
+ * earlier installs wrote (linked to the platform components by the migration).
195
282
  * Approval follows the installed plugin's policy only (spec §10): dependency components are
196
283
  * re-checked against the root item's policy and their own item's disabled state. Each component is
197
284
  * recorded in `plugin_install_components` as soon as it exists; if any step fails, the components
@@ -199,9 +286,10 @@ export function under(e, at) {
199
286
  * install is marked failed (error holds only the step and the error code) and 502
200
287
  * `plugin.install_failed` is thrown. Uninstall removes only components with created=true that
201
288
  * nothing else uses, and reports what it kept and why. No in-process state; the org row lock
202
- * serializes writes within one org. In-place upgrades are run by `PluginUpgrader`
203
- * (plugin-upgrade.ts), which reuses the planning, install and ledger methods here (the ones without
204
- * `private` are internal to the catalog, not an API).
289
+ * serializes writes within one org. There is no per-org upgrade: a platform plugin is updated
290
+ * once for the deployment (`PlatformPluginUpdater`, plugin-upgrade.ts, ruling F2); an install left
291
+ * `upgrading` by an earlier per-org upgrade is undone from its journal by the next uninstall. The
292
+ * methods without `private` are internal to the catalog, not an API.
205
293
  */
206
294
  let PluginInstaller = class PluginInstaller {
207
295
  kdb;
@@ -210,7 +298,6 @@ let PluginInstaller = class PluginInstaller {
210
298
  registry;
211
299
  skills;
212
300
  orgConfigs;
213
- requests;
214
301
  config;
215
302
  connectors;
216
303
  log;
@@ -219,7 +306,7 @@ let PluginInstaller = class PluginInstaller {
219
306
  /** The org row lock (orgs/org-lock.ts): joins the caller's transaction. */
220
307
  orgLock, storage,
221
308
  /** The loaded extensions and connectors of this replica (the extension registry). */
222
- registry, skills, orgConfigs, requests, config,
309
+ registry, skills, orgConfigs, config,
223
310
  /** Org connectors: installs create, upgrade and remove them. */
224
311
  connectors, log, txHost) {
225
312
  this.kdb = kdb;
@@ -228,7 +315,6 @@ let PluginInstaller = class PluginInstaller {
228
315
  this.registry = registry;
229
316
  this.skills = skills;
230
317
  this.orgConfigs = orgConfigs;
231
- this.requests = requests;
232
318
  this.config = config;
233
319
  this.connectors = connectors;
234
320
  this.log = log;
@@ -253,12 +339,15 @@ let PluginInstaller = class PluginInstaller {
253
339
  return { actions: planActions(plan) };
254
340
  }
255
341
  async install(orgId, actor, itemId, version, input, opts = {}) {
342
+ const { switchOn, via, ...actorOpts } = opts;
256
343
  const plan = await this.plan(orgId, actor, itemId, version, input, "", undefined);
257
344
  await this.assertNoSkillConflicts(orgId, plan);
258
345
  let installId;
259
346
  try {
260
- installId = await this.execute(orgId, actor, plan, opts, {
347
+ installId = await this.execute(orgId, actor, plan, actorOpts, {
261
348
  actions: planActions(plan),
349
+ ...(switchOn === true && { switchOn }),
350
+ ...(via !== undefined && { via }),
262
351
  });
263
352
  }
264
353
  catch (e) {
@@ -332,9 +421,17 @@ let PluginInstaller = class PluginInstaller {
332
421
  if (!v)
333
422
  throw new ApiError("catalog.item_not_found", "Plugin version not found");
334
423
  const manifest = v.manifest;
335
- const deps = await resolveDependencies(this.db, manifest);
424
+ const declared = await resolveDependencies(this.db, manifest);
336
425
  const extension = await this.planExtension(orgId, manifest);
337
- const templates = await readCatalogTemplates(this.storage, v);
426
+ const allTemplates = await readCatalogTemplates(this.storage, v);
427
+ // Only the connector templates on in the org make connectors (ruling P2-6): one switched off
428
+ // there, outside its own scope or disabled is skipped (input given for it is ignored)
429
+ const on = await connectorTemplatesOn(this.db, orgId, itemId, allTemplates.map((t) => t.id));
430
+ const templates = allTemplates.filter((t) => on.has(t.id));
431
+ const deps = [
432
+ ...declared,
433
+ ...(await this.impliedProviders(orgId, manifest, templates, declared)),
434
+ ];
338
435
  const skillNames = await catalogSkillNames(this.storage, v, manifest);
339
436
  const agentTemplates = await readCatalogAgentTemplates(this.storage, v);
340
437
  const connectors = new Map();
@@ -346,8 +443,11 @@ let PluginInstaller = class PluginInstaller {
346
443
  }
347
444
  }
348
445
  else {
349
- this.checkInput(manifest, templates, input, at);
446
+ this.checkInput(manifest, allTemplates, input, at);
350
447
  for (const ct of templates) {
448
+ // The kernel installs only what needs no org input (the scope sync's `needs_config` rule)
449
+ if (actor === null)
450
+ throw systemNeedsInput(manifest.name);
351
451
  connectors.set(ct.id, this.planConnector(actor, { itemId, version, name: manifest.name }, ct, input, at, approvedBy));
352
452
  }
353
453
  }
@@ -378,6 +478,64 @@ let PluginInstaller = class PluginInstaller {
378
478
  dependencies,
379
479
  };
380
480
  }
481
+ /**
482
+ * The providers of the templates' connector kinds as implied dependencies: a template whose
483
+ * `plugin` is neither this plugin, a declared dependency nor already enabled in the org makes that
484
+ * plugin a dependency (installed first, recorded like a declared one, so an uninstall hands it
485
+ * back). No such plugin offered by the catalog -> `connector.kind_unavailable` naming it, before
486
+ * anything is written.
487
+ */
488
+ async impliedProviders(orgId, manifest, templates, declared) {
489
+ const out = [];
490
+ const seen = new Set([manifest.name, ...declared.map((d) => d.name)]);
491
+ for (const ct of templates) {
492
+ const provider = ct.file.template.plugin;
493
+ if (seen.has(provider))
494
+ continue;
495
+ seen.add(provider);
496
+ // Not deployed: the not_deployed refusal of the plan's own checks says it
497
+ if (templatePluginProblem(this.templateDeps(), ct.file.template) !== undefined)
498
+ continue;
499
+ if (await isExtensionEnabled(this.db, orgId, provider))
500
+ continue;
501
+ const refuse = (why) => new ApiError("connector.kind_unavailable", `Connector template ${ct.id} needs the plugin ${provider}, which is not enabled in this organization: ${why}`);
502
+ let dep;
503
+ try {
504
+ const { manifest: _m, ...resolved } = await resolveOne(this.db, {
505
+ name: provider,
506
+ version: ct.file.template.pluginVersion ?? "*",
507
+ });
508
+ dep = resolved;
509
+ }
510
+ catch (e) {
511
+ if (!(e instanceof ApiError))
512
+ throw e;
513
+ throw refuse(e.code === "catalog.dependency_unresolved"
514
+ ? `${provider} is deployed but switched off here and the catalog has no entry to switch it on; ask the super admin to enable it`
515
+ : `${provider} is not offered to this organization`);
516
+ }
517
+ // Scope: only a plugin offered to this org may be switched on for it (nothing more is said)
518
+ const item = await this.db
519
+ .selectFrom("catalog_items")
520
+ .select(["scope", "builtin"])
521
+ .where("id", "=", dep.itemId)
522
+ .executeTakeFirstOrThrow();
523
+ const listed = await this.db
524
+ .selectFrom("catalog_item_scope_orgs")
525
+ .select("item_id")
526
+ .where("item_id", "=", dep.itemId)
527
+ .where("org_id", "=", orgId)
528
+ .executeTakeFirst();
529
+ if (!visibleTo({ scope: item.builtin ? "all" : item.scope }, listed !== undefined)) {
530
+ throw refuse(`${provider} is not offered to this organization`);
531
+ }
532
+ if (await this.findLiveDependency(this.db, orgId, dep, false)) {
533
+ throw refuse(`${provider} is installed but switched off in this organization`);
534
+ }
535
+ out.push(dep);
536
+ }
537
+ return out;
538
+ }
381
539
  /**
382
540
  * The connector input of one template from the org's input (C30), checked without a connection:
383
541
  * the template's connector extension deployed, the input valid, the credential / OAuth client it
@@ -481,7 +639,7 @@ let PluginInstaller = class PluginInstaller {
481
639
  * as they are. Returns the install id.
482
640
  */
483
641
  async execute(orgId, actor, plan, opts, ctx) {
484
- const { itemId, version, manifest } = plan;
642
+ const { itemId, manifest } = plan;
485
643
  // The install row (role and item policy re-checked under the lock; one live install per org
486
644
  // and item)
487
645
  const installId = randomUUID();
@@ -523,6 +681,7 @@ let PluginInstaller = class PluginInstaller {
523
681
  actions: requiredActions(depPlan.manifest),
524
682
  approvedBy,
525
683
  parent: installId,
684
+ ...(ctx.via !== undefined && { via: ctx.via }),
526
685
  });
527
686
  }
528
687
  catch (e) {
@@ -551,6 +710,8 @@ let PluginInstaller = class PluginInstaller {
551
710
  const ci = plan.connectors.get(ct.id);
552
711
  if (!ci)
553
712
  throw new ApiError("internal", `Connector template ${ct.id} was not planned`);
713
+ if (actor === null)
714
+ throw systemNeedsInput(manifest.name);
554
715
  const r = await this.connectors.create(orgId, actor, ci, opts.actorTokenId);
555
716
  await record({
556
717
  kind: "connector",
@@ -560,30 +721,8 @@ let PluginInstaller = class PluginInstaller {
560
721
  templateId: ct.id,
561
722
  });
562
723
  }
563
- step = "agent_templates";
564
- for (const a of plan.agentTemplates) {
565
- await this.installAgentTemplate(orgId, plan, a.template, record);
566
- }
567
- step = "skills";
568
- for (const s of manifest.skills ?? []) {
569
- const files = await readCatalogFiles(this.storage, plan.row.object_prefix, plan.row.files, packagePath(s.path));
570
- const r = await this.skills.createVersionFromFiles(orgId, actor, { ...skillOf(files), files }, {
571
- catalog: {
572
- itemId,
573
- version,
574
- ...(nested && { approvedBy }),
575
- format: plan.sourceFormat,
576
- suggestPinned: s.pinned === true,
577
- },
578
- ...opts,
579
- });
580
- await record({
581
- kind: "skill",
582
- ref: r.skill.id,
583
- created: r.created,
584
- skillVersion: r.created ? null : r.version,
585
- });
586
- }
724
+ // Skills and agent templates are platform components (plugin scope phase 2): stored once for
725
+ // the deployment and on in the org while the plugin is, so the install writes no org rows
587
726
  await this.markInstalled(orgId, actor, installId, plan, done, ctx, opts);
588
727
  return installId;
589
728
  }
@@ -620,18 +759,25 @@ let PluginInstaller = class PluginInstaller {
620
759
  const { itemId, version } = plan;
621
760
  const t = this.db;
622
761
  await lockOrgForActions(this.orgLock, orgId, actor, ctx.actions);
762
+ // The scope sync decided outside this lock: a person's switch-off or a scope change committed
763
+ // since then wins (nothing written, converged)
764
+ if (ctx.via === "scope" &&
765
+ ctx.approvedBy === undefined &&
766
+ !(await wantedByScope(t, orgId, itemId))) {
767
+ throw new ScopeNoLongerWanted(orgId, itemId);
768
+ }
623
769
  if (ctx.approvedBy !== undefined) {
624
770
  // A dependency disabled (or removed) since it was planned
625
771
  const own = await t
626
772
  .selectFrom("catalog_items")
627
- .select(["policy", "deleted_at"])
773
+ .select(["disabled", "deleted_at"])
628
774
  .where("id", "=", itemId)
629
775
  .forShare()
630
776
  .executeTakeFirst();
631
777
  if (!own || own.deleted_at !== null) {
632
- throw unresolved(plan.name, plan.version, "it was removed from the enterprise catalog");
778
+ throw unresolved(plan.name, plan.version, "it was removed from the platform catalog");
633
779
  }
634
- if (own.policy === "disabled")
780
+ if (own.disabled)
635
781
  throw dependencyDisabled(plan.name);
636
782
  }
637
783
  await assertItemInstallable(t, orgId, itemId, ctx.approvedBy ?? itemId);
@@ -663,34 +809,22 @@ let PluginInstaller = class PluginInstaller {
663
809
  throw e;
664
810
  }
665
811
  }
666
- /**
667
- * An agent template step: created (or a new version of the org's live template of this plugin and
668
- * name) and recorded in one transaction of its own, under the org row lock.
669
- */
670
- async installAgentTemplate(orgId, plan, template, record) {
671
- await this.orgLock.lock(orgId);
672
- const r = await putTemplateVersionIn(this.db, {
673
- orgId,
674
- plugin: plan.name,
675
- catalogItemId: plan.itemId,
676
- catalogVersion: plan.version,
677
- sourceFormat: plan.sourceFormat,
678
- }, template);
679
- await record({
680
- kind: "agent_template",
681
- ref: r.id,
682
- created: r.created,
683
- skillVersion: !r.created && r.changed ? r.version : null,
684
- });
685
- }
686
812
  /** The install `installed` and its `plugin.org_installed` audit, under the org row lock (its own transaction). */
687
813
  async markInstalled(orgId, actor, installId, plan, done, ctx, opts) {
688
814
  const { itemId, version } = plan;
689
815
  const t = this.db;
690
816
  await this.orgLock.lock(orgId);
817
+ // The platform version current at commit (one per deployment): a platform update that
818
+ // committed while this install ran moved the row already, or did not see it yet
691
819
  const updated = await t
692
820
  .updateTable("plugin_installs")
693
- .set({ status: "installed" })
821
+ .set((eb) => ({
822
+ status: "installed",
823
+ version: eb.fn.coalesce(eb
824
+ .selectFrom("catalog_items as i")
825
+ .select("i.platform_synced_version")
826
+ .where("i.id", "=", itemId), eb.ref("plugin_installs.version")),
827
+ }))
694
828
  .where("id", "=", installId)
695
829
  .where("status", "=", "installing")
696
830
  .executeTakeFirst();
@@ -699,7 +833,11 @@ let PluginInstaller = class PluginInstaller {
699
833
  if (updated.numUpdatedRows === 0n) {
700
834
  throw new ApiError("plugin.install_not_found", "The install record was cleaned up as stale while the install was running");
701
835
  }
702
- await this.requests.resolveByInstall(orgId, itemId, actor, opts);
836
+ await resolveRequestsByInstall(t, orgId, itemId, actor, opts);
837
+ // The org switch is written with the install, in one transaction under the org lock
838
+ if (ctx.switchOn === true && ctx.parent === undefined) {
839
+ await upsertOrgSwitch(t, orgId, itemId, true, actor);
840
+ }
703
841
  await audit(t, {
704
842
  actorAccountId: actor,
705
843
  ...(opts.actorTokenId !== undefined && { actorTokenId: opts.actorTokenId }),
@@ -712,6 +850,8 @@ let PluginInstaller = class PluginInstaller {
712
850
  version,
713
851
  components: done,
714
852
  ...(ctx.parent !== undefined && { dependencyOf: ctx.parent }),
853
+ ...(ctx.via !== undefined && { via: ctx.via }),
854
+ ...opts.auditDetail,
715
855
  },
716
856
  });
717
857
  }
@@ -740,6 +880,8 @@ let PluginInstaller = class PluginInstaller {
740
880
  rolledBack: done,
741
881
  rollbackErrors,
742
882
  ...(ctx.parent !== undefined && { dependencyOf: ctx.parent }),
883
+ ...(ctx.via !== undefined && { via: ctx.via }),
884
+ ...opts.auditDetail,
743
885
  },
744
886
  });
745
887
  }
@@ -754,7 +896,7 @@ let PluginInstaller = class PluginInstaller {
754
896
  return null;
755
897
  const name = manifest.name;
756
898
  if (!this.registry.manifests().some((m) => m.name === name)) {
757
- throw new ApiError("catalog.not_deployed", `The extension of plugin ${name} is not deployed; ask the enterprise admin to install and enable it`);
899
+ throw new ApiError("catalog.not_deployed", `The extension of plugin ${name} is not deployed; ask the super admin to install and enable it`);
758
900
  }
759
901
  const enabled = await isExtensionEnabled(this.db, orgId, name);
760
902
  if (!enabled && (await disabledPluginItems(this.db, [name])).length > 0) {
@@ -864,6 +1006,13 @@ let PluginInstaller = class PluginInstaller {
864
1006
  }
865
1007
  if (c.kind === "plugin")
866
1008
  return false;
1009
+ // A row the org promoted is the org's own shared item (ruling P3-47): an install never
1010
+ // removes or reverts it (P3-46 keeps plugin content from being promoted; this guards rows
1011
+ // recorded before that or by a legacy install)
1012
+ if ((c.kind === "agent_template" || c.kind === "skill") &&
1013
+ (await promotedOrgRow(t, orgId, c.kind, c.ref))) {
1014
+ return false;
1015
+ }
867
1016
  if (c.kind === "agent_template") {
868
1017
  if (c.created)
869
1018
  return softDeleteTemplateIn(t, orgId, c.ref);
@@ -901,25 +1050,79 @@ let PluginInstaller = class PluginInstaller {
901
1050
  * (a replica crashed midway) - the last two are cleaned up as a rollback (versions added to
902
1051
  * existing skills are reverted too). Still installing -> `plugin.install_in_progress`.
903
1052
  */
904
- async uninstall(orgId, actor, installId, opts = {}) {
1053
+ async uninstall(orgId, actor, installId, opts = {}, sw) {
905
1054
  if (!UUID_RE.test(installId))
906
1055
  throw installNotFound();
907
- return this.writeUninstall(orgId, actor, installId, opts);
1056
+ return this.writeUninstall(orgId, actor, installId, opts, sw);
908
1057
  }
909
- /** The uninstall's one transaction; the extensions it disabled are notified once it commits. */
910
- async writeUninstall(orgId, actor, installId, opts) {
1058
+ /**
1059
+ * The uninstall's one transaction; the extensions it disabled are notified once it commits. A
1060
+ * scope sync uninstall (`via: "scope"`) re-checks under the org row lock that the item is still
1061
+ * not wanted in the org and that no other live install depends on it ({@link ScopeStillWanted},
1062
+ * nothing written), and keeps the connectors it created as the org's own (`org_owned`).
1063
+ */
1064
+ async writeUninstall(orgId, actor, installId, opts, sw) {
1065
+ const { via, ...actorOpts } = opts;
911
1066
  const report = { removed: [], kept: [] };
1067
+ let itemId;
1068
+ if (via === "scope") {
1069
+ // A person's switch-on (or a scope change) committed after the sync's decision wins
1070
+ await this.orgLock.lock(orgId);
1071
+ const row = await this.db
1072
+ .selectFrom("plugin_installs")
1073
+ .select("item_id")
1074
+ .where("id", "=", installId)
1075
+ .where("org_id", "=", orgId)
1076
+ .executeTakeFirst();
1077
+ if (row !== undefined &&
1078
+ ((await wantedByScope(this.db, orgId, row.item_id)) ||
1079
+ (await this.heir(orgId, new Set([installId]), "plugin", installId)) !== undefined)) {
1080
+ throw new ScopeStillWanted(orgId, row.item_id);
1081
+ }
1082
+ }
1083
+ if (sw !== undefined) {
1084
+ // Switching off: the org lock first, then the preview is re-checked and the switch row is
1085
+ // written in this same transaction
1086
+ await this.orgLock.lock(orgId);
1087
+ const row = await this.db
1088
+ .selectFrom("plugin_installs")
1089
+ .select("item_id")
1090
+ .where("id", "=", installId)
1091
+ .where("org_id", "=", orgId)
1092
+ .executeTakeFirst();
1093
+ itemId = row?.item_id;
1094
+ // The item row FOR SHARE, as a switch without an uninstall takes it: an owner's delete or
1095
+ // transfer (FOR UPDATE) decides on who uses it
1096
+ if (itemId !== undefined) {
1097
+ await this.db
1098
+ .selectFrom("catalog_items")
1099
+ .select("id")
1100
+ .where("id", "=", itemId)
1101
+ .forShare()
1102
+ .executeTakeFirst();
1103
+ }
1104
+ if (sw.expectHash !== undefined && row !== undefined) {
1105
+ const now = uninstallPreviewHash(await this.previewUninstall(orgId, installId));
1106
+ if (now !== sw.expectHash) {
1107
+ throw new ApiError("plugin.switch_stale", "The uninstall preview changed; review it and confirm again");
1108
+ }
1109
+ }
1110
+ }
912
1111
  const outcome = await this.uninstallIn(orgId, actor, installId, {
913
1112
  report,
914
1113
  removing: new Set(),
915
1114
  authorize: true,
916
- opts,
1115
+ opts: actorOpts,
1116
+ ...(via !== undefined && { via }),
917
1117
  });
918
1118
  if (outcome === "missing")
919
1119
  throw installNotFound();
920
1120
  if (outcome === "kept") {
921
1121
  report.kept.push({ kind: "plugin", ref: installId, reason: "used_by_other_install" });
922
1122
  }
1123
+ if (itemId !== undefined && outcome === "removed") {
1124
+ await upsertOrgSwitch(this.db, orgId, itemId, false, actor);
1125
+ }
923
1126
  afterCommit(async () => {
924
1127
  for (const r of report.removed) {
925
1128
  if (r.kind === "extension")
@@ -1007,6 +1210,11 @@ let PluginInstaller = class PluginInstaller {
1007
1210
  .executeTakeFirst();
1008
1211
  if (!row)
1009
1212
  return "missing";
1213
+ // A dependency its own scope still wants on in the org stays as a standalone install (the
1214
+ // dependent's component row goes with the dependent's install row)
1215
+ if (ctx.from !== undefined && (await wantedByScope(t, orgId, row.item_id))) {
1216
+ return "wanted_by_scope";
1217
+ }
1010
1218
  // Another install outside this uninstall depends on it: kept (a dependency uninstall hands
1011
1219
  // ownership over)
1012
1220
  const user = await this.heir(orgId, new Set([...removing, installId]), "plugin", installId);
@@ -1072,6 +1280,10 @@ let PluginInstaller = class PluginInstaller {
1072
1280
  created = now.created;
1073
1281
  }
1074
1282
  const comp = { kind: c.kind, ref: c.ref, created, skillVersion: c.skill_version };
1283
+ // Skills and agent templates of earlier installs (org copies, now linked to the platform
1284
+ // components, phase 2) stay: the plugin's components go off in the org with the install
1285
+ if ((c.kind === "skill" || c.kind === "agent_template") && !rollbackMode)
1286
+ continue;
1075
1287
  if (!created) {
1076
1288
  // Rollback cleanup: a version this install added to an existing skill is reverted; other
1077
1289
  // pre-existing components are kept
@@ -1091,6 +1303,14 @@ let PluginInstaller = class PluginInstaller {
1091
1303
  addRemoved({ kind: "plugin", ref: c.ref });
1092
1304
  else if (outcome === "kept")
1093
1305
  keep("used_by_other_install");
1306
+ else if (outcome === "wanted_by_scope")
1307
+ keep("wanted_by_scope");
1308
+ continue;
1309
+ }
1310
+ // A scope sync uninstall leaves the connectors to the org (spec §5 rule 8): the component row
1311
+ // goes with the install row, so nothing removes them later
1312
+ if (c.kind === "connector" && ctx.via === "scope" && !rollbackMode) {
1313
+ keep("org_owned");
1094
1314
  continue;
1095
1315
  }
1096
1316
  const reason = rollbackMode ? "plugin_install_cleanup" : (ctx.reason ?? "plugin_uninstall");
@@ -1115,6 +1335,8 @@ let PluginInstaller = class PluginInstaller {
1115
1335
  removed: mine.removed,
1116
1336
  kept: mine.kept,
1117
1337
  ...(ctx.from !== undefined && { dependencyOf: ctx.from }),
1338
+ ...(ctx.via !== undefined && { via: ctx.via }),
1339
+ ...ctx.opts.auditDetail,
1118
1340
  },
1119
1341
  });
1120
1342
  return "removed";
@@ -1189,7 +1411,6 @@ let PluginInstaller = class PluginInstaller {
1189
1411
  const rows = await q.orderBy("a.installed_at", "desc").orderBy("a.id").execute();
1190
1412
  if (rows.length === 0)
1191
1413
  return [];
1192
- const info = await upgradeInfo(this.db, this.registry, rows.map((r) => ({ itemId: r.item_id, name: r.name, version: r.version })));
1193
1414
  const comps = await this.db
1194
1415
  .selectFrom("plugin_install_components")
1195
1416
  .select(["install_id", "kind", "ref", "created", "skill_version", "dropped"])
@@ -1213,8 +1434,8 @@ let PluginInstaller = class PluginInstaller {
1213
1434
  skillVersion: c.skill_version,
1214
1435
  dropped: c.dropped,
1215
1436
  })),
1216
- upgradeAvailable: info.get(`${r.item_id}@${r.version}`)?.upgradeAvailable ?? null,
1217
- deploymentPending: info.get(`${r.item_id}@${r.version}`)?.deploymentPending ?? false,
1437
+ upgradeAvailable: null,
1438
+ deploymentPending: false,
1218
1439
  }));
1219
1440
  }
1220
1441
  /**
@@ -1276,6 +1497,288 @@ let PluginInstaller = class PluginInstaller {
1276
1497
  }
1277
1498
  return removed;
1278
1499
  }
1500
+ /**
1501
+ * Installs the dependencies an installed plugin's version declares and the org lacks (rule 9),
1502
+ * as the kernel (actor null): a platform update can add one. Each is recorded on the install
1503
+ * as a `plugin` component (created when this installed it, so an uninstall takes it along). One
1504
+ * that needs the org's input (connector templates) is left out and its name returned. A
1505
+ * dependency already installed in the org is recorded as it is (created false).
1506
+ */
1507
+ async addMissingDependencies(orgId, installId) {
1508
+ const row = await this.db
1509
+ .selectFrom("plugin_installs as a")
1510
+ .innerJoin("catalog_item_versions as v", (j) => j.onRef("v.item_id", "=", "a.item_id").onRef("v.version", "=", "a.version"))
1511
+ .select(["a.item_id", "a.status", "v.manifest"])
1512
+ .where("a.id", "=", installId)
1513
+ .where("a.org_id", "=", orgId)
1514
+ .executeTakeFirst();
1515
+ if (row?.status !== "installed")
1516
+ return [];
1517
+ const record = async (c) => {
1518
+ await this.db
1519
+ .insertInto("plugin_install_components")
1520
+ .values({
1521
+ install_id: installId,
1522
+ kind: c.kind,
1523
+ ref: c.ref,
1524
+ created: c.created,
1525
+ skill_version: null,
1526
+ })
1527
+ .onConflict((oc) => oc.columns(["install_id", "kind", "ref"]).doNothing())
1528
+ .execute();
1529
+ };
1530
+ const needsInput = [];
1531
+ for (const dep of await resolveDependencies(this.db, row.manifest)) {
1532
+ if ((await this.recordDependency(orgId, dep, record)) !== undefined)
1533
+ continue;
1534
+ let plan;
1535
+ try {
1536
+ plan = await this.plan(orgId, null, dep.itemId, dep.version, {}, "", row.item_id);
1537
+ }
1538
+ catch (e) {
1539
+ if (e instanceof NeedsOrgInput) {
1540
+ needsInput.push(dep.name);
1541
+ continue;
1542
+ }
1543
+ throw e;
1544
+ }
1545
+ const child = await this.execute(orgId, null, plan, {}, {
1546
+ actions: requiredActions(plan.manifest),
1547
+ approvedBy: row.item_id,
1548
+ parent: installId,
1549
+ via: "scope",
1550
+ });
1551
+ await this.recordDependency(orgId, dep, record, child);
1552
+ }
1553
+ return needsInput;
1554
+ }
1555
+ /**
1556
+ * The connector templates of an installed plugin that are on in the org (ruling P2-6) and have
1557
+ * no live connector there: made from the platform template (`platform_template_id`) or recorded
1558
+ * on the install (`template_id`). The org's plugin is `needs_config` while any is missing (ruling
1559
+ * P2-10). Empty for a plugin not installed.
1560
+ */
1561
+ async missingConnectors(orgId, itemId) {
1562
+ const a = await this.db
1563
+ .selectFrom("plugin_installs as a")
1564
+ .innerJoin("catalog_item_versions as v", (j) => j.onRef("v.item_id", "=", "a.item_id").onRef("v.version", "=", "a.version"))
1565
+ .select(["a.id", "a.version", "v.manifest", "v.object_prefix", "v.files"])
1566
+ .where("a.org_id", "=", orgId)
1567
+ .where("a.item_id", "=", itemId)
1568
+ .where("a.status", "=", "installed")
1569
+ .executeTakeFirst();
1570
+ if (!a)
1571
+ return undefined;
1572
+ if ((a.manifest.connectorTemplates ?? []).length === 0) {
1573
+ return { installId: a.id, version: a.version, templates: [] };
1574
+ }
1575
+ const all = await readCatalogTemplates(this.storage, a);
1576
+ const on = await connectorTemplatesOn(this.db, orgId, itemId, all.map((t) => t.id));
1577
+ const made = new Set((await this.db
1578
+ .selectFrom("connectors as c")
1579
+ .innerJoin("platform_connector_templates as p", "p.id", "c.platform_template_id")
1580
+ .select("p.template_id")
1581
+ .where("c.org_id", "=", orgId)
1582
+ .where("c.deleted_at", "is", null)
1583
+ .where("p.catalog_item_id", "=", itemId)
1584
+ .execute()).map((r) => r.template_id));
1585
+ const recorded = await this.db
1586
+ .selectFrom("plugin_install_components as l")
1587
+ .innerJoin("connectors as c", (j) => j.on(sql `c.id::text`, "=", sql `l.ref`))
1588
+ .select("l.template_id")
1589
+ .where("l.install_id", "=", a.id)
1590
+ .where("l.kind", "=", "connector")
1591
+ .where("c.deleted_at", "is", null)
1592
+ .execute();
1593
+ for (const r of recorded)
1594
+ if (r.template_id !== null)
1595
+ made.add(r.template_id);
1596
+ return {
1597
+ installId: a.id,
1598
+ version: a.version,
1599
+ templates: all.filter((t) => on.has(t.id) && !made.has(t.id)),
1600
+ };
1601
+ }
1602
+ /**
1603
+ * Creates the connectors an installed plugin is missing (ruling P2-10, `POST …/catalog/:itemId/
1604
+ * connectors`): `input.connectors` names some of {@link missingConnectors}' templates with the
1605
+ * same input as an install (endpoint, credential or OAuth client); each is created as at install
1606
+ * and recorded on the install. Returns the created connectors by template.
1607
+ */
1608
+ async configureConnectors(orgId, actor, itemId, input, opts = {}) {
1609
+ if (!UUID_RE.test(itemId))
1610
+ throw installNotFound();
1611
+ const missing = await this.missingConnectors(orgId, itemId);
1612
+ if (!missing)
1613
+ throw installNotFound();
1614
+ const keys = Object.keys(input.connectors ?? {});
1615
+ if (keys.length === 0) {
1616
+ throw new ApiError("validation_failed", "Request validation failed", [
1617
+ { path: "connectors", message: "Give the input of at least one missing connector" },
1618
+ ]);
1619
+ }
1620
+ for (const k of keys) {
1621
+ if (!missing.templates.some((t) => t.id === k)) {
1622
+ throw new ApiError("validation_failed", "Request validation failed", [
1623
+ {
1624
+ path: `connectors.${k}`,
1625
+ message: "No connector of this template is missing in this organization",
1626
+ },
1627
+ ]);
1628
+ }
1629
+ }
1630
+ const item = await this.db
1631
+ .selectFrom("catalog_items")
1632
+ .select("name")
1633
+ .where("id", "=", itemId)
1634
+ .executeTakeFirstOrThrow();
1635
+ const plans = missing.templates
1636
+ .filter((t) => keys.includes(t.id))
1637
+ .map((t) => ({
1638
+ id: t.id,
1639
+ ci: this.planConnector(actor, { itemId, version: missing.version, name: item.name }, t, input, "", undefined),
1640
+ }));
1641
+ const out = [];
1642
+ for (const p of plans) {
1643
+ const r = await this.connectors.create(orgId, actor, p.ci, opts.actorTokenId);
1644
+ await this.recordConnector(missing.installId, r.connector.id, p.id);
1645
+ out.push({ templateId: p.id, connectorId: r.connector.id });
1646
+ }
1647
+ return out;
1648
+ }
1649
+ /** A configured connector's ledger row (its own transaction). */
1650
+ async recordConnector(installId, ref, templateId) {
1651
+ await this.db
1652
+ .insertInto("plugin_install_components")
1653
+ .values({
1654
+ install_id: installId,
1655
+ kind: "connector",
1656
+ ref,
1657
+ created: true,
1658
+ skill_version: null,
1659
+ template_id: templateId,
1660
+ })
1661
+ .onConflict((oc) => oc.columns(["install_id", "kind", "ref"]).doNothing())
1662
+ .execute();
1663
+ }
1664
+ /**
1665
+ * One more connector from a platform connector template on in the org (rulings P4-7, P4-T6-8;
1666
+ * `POST …/connector-templates/:templateId/connectors`): `templateId` is the platform connector
1667
+ * template's id; `config` is an install's connector input (endpoint, credential or OAuth client,
1668
+ * slug) and `name` its name. Without a slug the name and slug default to the first free ones,
1669
+ * chosen by the create under the org lock after its outbound calls
1670
+ * (`CreateConnectorInput.slugDefault`); only a given slug answers 409 `connector.slug_taken`. Created as at install ({@link planConnector}, then
1671
+ * `ConnectorsService.create`, which checks the slug before any outbound call and re-checks it,
1672
+ * `connectors.manage`, the item and the template being on under the org lock), linked to the
1673
+ * template, and recorded on the plugin's live install in the org when there is one. A template
1674
+ * that is missing, deleted or not offered to the org -> 404 `component.not_found`; offered but
1675
+ * off there (its plugin not installed, or switched off) -> 409 `component.off`; input errors ->
1676
+ * 400 `validation_failed` at `config.<field>`.
1677
+ */
1678
+ async addTemplateConnector(orgId, actor, templateId, input, opts = {}) {
1679
+ const notFound = () => new ApiError("component.not_found", "The connector template does not exist or is not available in this organization");
1680
+ if (!UUID_RE.test(templateId))
1681
+ throw notFound();
1682
+ // read here to fail early, and again under the org lock by the create (`mustBeOn`)
1683
+ const state = await connectorTemplateState(this.db, orgId, templateId);
1684
+ if (state === "absent")
1685
+ throw notFound();
1686
+ if (state === "off") {
1687
+ throw new ApiError("component.off", "This connector template is off in this organization; switch it (or its plugin) on first");
1688
+ }
1689
+ const row = await this.db
1690
+ .selectFrom("platform_connector_templates as t")
1691
+ .innerJoin("catalog_items as i", "i.id", "t.catalog_item_id")
1692
+ .leftJoin("plugin_installs as a", (j) => j
1693
+ .onRef("a.item_id", "=", "t.catalog_item_id")
1694
+ .on("a.org_id", "=", orgId)
1695
+ .on("a.status", "=", "installed"))
1696
+ .select([
1697
+ "t.template_id",
1698
+ "t.catalog_item_id",
1699
+ "t.file",
1700
+ "i.name",
1701
+ "i.latest_version",
1702
+ "a.version",
1703
+ ])
1704
+ .where("t.id", "=", templateId)
1705
+ .executeTakeFirstOrThrow();
1706
+ const ct = { id: row.template_id, file: row.file };
1707
+ const at = `connectors.${ct.id}`;
1708
+ // the paths of an install's input and of the create, under `config` here (`name` stays)
1709
+ const rebase = (e) => {
1710
+ if (!(e instanceof ApiError) || e.code !== "validation_failed" || !e.details)
1711
+ return e;
1712
+ return new ApiError(e.code, e.message, e.details.map((d) => {
1713
+ const path = d.path;
1714
+ if (typeof path !== "string")
1715
+ return d;
1716
+ const rest = path === at || path.startsWith(`${at}.`) ? path.slice(at.length + 1) : path;
1717
+ if (!/^(slug|credential|endpoint|client)(\.|$)/.test(rest)) {
1718
+ return rest === path ? d : { ...d, path: rest };
1719
+ }
1720
+ return { ...d, path: `config.${rest}` };
1721
+ }));
1722
+ };
1723
+ const display = ct.file.displayName?.en ?? ct.id;
1724
+ // a slug given by the caller is theirs (409 when taken); otherwise the create picks the first
1725
+ // free default under the org lock, after its outbound calls (no retry repeats them)
1726
+ const defaulted = input.config.slug === undefined;
1727
+ let ci;
1728
+ try {
1729
+ ci = this.planConnector(actor, { itemId: row.catalog_item_id, version: row.version ?? row.latest_version, name: row.name }, ct, {
1730
+ connectors: {
1731
+ [ct.id]: { ...input.config, ...(input.name !== undefined && { name: input.name }) },
1732
+ },
1733
+ }, "", undefined);
1734
+ }
1735
+ catch (e) {
1736
+ throw rebase(e);
1737
+ }
1738
+ ci = {
1739
+ ...ci,
1740
+ template: ci.template && { ...ci.template, mustBeOn: true },
1741
+ ...(defaulted && {
1742
+ slugDefault: { display, ...(input.name !== undefined && { name: input.name }) },
1743
+ }),
1744
+ };
1745
+ try {
1746
+ const r = await this.connectors.create(orgId, actor, ci, opts.actorTokenId);
1747
+ await this.recordOnLiveInstall(orgId, row.catalog_item_id, r.connector.id, ct.id);
1748
+ return r;
1749
+ }
1750
+ catch (e) {
1751
+ throw rebase(e);
1752
+ }
1753
+ }
1754
+ /**
1755
+ * Records a connector made from a plugin's template on the org's live install of that plugin,
1756
+ * when there is one, under the org lock (so an uninstall in between is seen).
1757
+ */
1758
+ async recordOnLiveInstall(orgId, itemId, connectorId, templateId) {
1759
+ await this.orgLock.lock(orgId);
1760
+ const install = await this.db
1761
+ .selectFrom("plugin_installs")
1762
+ .select("id")
1763
+ .where("org_id", "=", orgId)
1764
+ .where("item_id", "=", itemId)
1765
+ .where("status", "=", "installed")
1766
+ .executeTakeFirst();
1767
+ if (!install)
1768
+ return;
1769
+ await this.db
1770
+ .insertInto("plugin_install_components")
1771
+ .values({
1772
+ install_id: install.id,
1773
+ kind: "connector",
1774
+ ref: connectorId,
1775
+ created: true,
1776
+ skill_version: null,
1777
+ template_id: templateId,
1778
+ })
1779
+ .onConflict((oc) => oc.columns(["install_id", "kind", "ref"]).doNothing())
1780
+ .execute();
1781
+ }
1279
1782
  /** The connector kinds an extension provides (the `connector@1` implementations loaded on this replica). */
1280
1783
  connectorKindsOf(plugin) {
1281
1784
  return this.registry
@@ -1285,36 +1788,130 @@ let PluginInstaller = class PluginInstaller {
1285
1788
  .filter((k) => typeof k === "string");
1286
1789
  }
1287
1790
  /**
1288
- * The connectors, org skills and agent templates (`subagents.templates`) referenced by the
1289
- * current definitions of the org's live agents.
1791
+ * The uninstall preview of an install (see {@link UninstallPreview}); the real uninstall may keep
1792
+ * more (another install using a component, a connector still using an extension). The plugin's
1793
+ * skills and agent templates are platform components (phase 2): the ones on in the org through
1794
+ * the plugin (`follow`) go off with it, so the agents using them (by the platform id or an
1795
+ * unpinned org copy linked to it) are listed, also for the dependency installs it created that
1796
+ * go with it; ledger rows of earlier installs' org copies are not removed and not listed (an
1797
+ * uninstall keeps legacy copies, like the platform update keeps copies of removed components).
1290
1798
  */
1291
- async agentRefs(orgId) {
1292
- const rows = await this.db
1293
- .selectFrom("agents as a")
1294
- .innerJoin("agent_versions as v", (j) => j.onRef("v.agent_id", "=", "a.id").onRef("v.version", "=", "a.current_version"))
1295
- .select("v.definition")
1799
+ async previewUninstall(orgId, installId) {
1800
+ if (!UUID_RE.test(installId))
1801
+ throw installNotFound();
1802
+ const t = this.db;
1803
+ const row = await t
1804
+ .selectFrom("plugin_installs as a")
1805
+ .innerJoin("catalog_items as i", "i.id", "a.item_id")
1806
+ .select(["a.id", "a.item_id", "a.version", "i.name"])
1807
+ .where("a.id", "=", installId)
1296
1808
  .where("a.org_id", "=", orgId)
1297
- .where("a.deleted_at", "is", null)
1809
+ .executeTakeFirst();
1810
+ if (!row)
1811
+ throw installNotFound();
1812
+ const ledger = (id) => t
1813
+ .selectFrom("plugin_install_components")
1814
+ .select(["kind", "ref", "created"])
1815
+ .where("install_id", "=", id)
1816
+ .orderBy("kind")
1817
+ .orderBy("ref")
1298
1818
  .execute();
1299
- const connectors = new Set();
1300
- const skills = new Set();
1301
- const templates = new Set();
1302
- for (const r of rows) {
1303
- const def = r.definition;
1304
- for (const ref of def?.tools ?? []) {
1305
- const n = normalizeToolRef(ref);
1306
- if (n?.kind === "connector" && typeof n.connectorId === "string") {
1307
- connectors.add(n.connectorId);
1819
+ const comps = (await ledger(installId)).filter((c) => c.kind !== "skill" && c.kind !== "agent_template");
1820
+ const agents = await agentDefinitionRefs(t, orgId);
1821
+ const used = new Map();
1822
+ const use = (a, kind, ref) => {
1823
+ const e = used.get(a.id) ?? { id: a.id, name: a.name, uses: [] };
1824
+ if (!e.uses.some((u) => u.kind === kind && u.ref === ref))
1825
+ e.uses.push({ kind, ref });
1826
+ used.set(a.id, e);
1827
+ };
1828
+ const kept = [];
1829
+ /**
1830
+ * The agents using what goes with an install: connectors it created (they stay, kept for the
1831
+ * agents) and the plugin's platform skills and agent templates on in the org through it
1832
+ * (`follow`; by the platform id or an unpinned org copy linked to it). Dependency installs it
1833
+ * created go with it unless their own scope wants them (Task 7: their components count too).
1834
+ */
1835
+ const visit = async (itemId, rows, top, seen) => {
1836
+ for (const c of rows) {
1837
+ if (!c.created) {
1838
+ if (top)
1839
+ kept.push({ kind: c.kind, ref: c.ref, reason: "pre_existing" });
1840
+ continue;
1841
+ }
1842
+ if (c.kind === "plugin") {
1843
+ const dep = await t
1844
+ .selectFrom("plugin_installs")
1845
+ .select("item_id")
1846
+ .where("id", "=", c.ref)
1847
+ .where("org_id", "=", orgId)
1848
+ .executeTakeFirst();
1849
+ if (!dep)
1850
+ continue;
1851
+ if (await wantedByScope(t, orgId, dep.item_id)) {
1852
+ if (top)
1853
+ kept.push({ kind: c.kind, ref: c.ref, reason: "wanted_by_scope" });
1854
+ continue;
1855
+ }
1856
+ if (seen.has(c.ref))
1857
+ continue;
1858
+ seen.add(c.ref);
1859
+ const sub = (await ledger(c.ref)).filter((x) => x.kind !== "skill" && x.kind !== "agent_template");
1860
+ await visit(dep.item_id, sub, false, seen);
1861
+ continue;
1862
+ }
1863
+ if (c.kind !== "connector")
1864
+ continue;
1865
+ const users = agents.filter((a) => a.connectors.has(c.ref));
1866
+ if (users.length === 0)
1867
+ continue;
1868
+ if (top)
1869
+ kept.push({ kind: c.kind, ref: c.ref, reason: "used_by_agents" });
1870
+ for (const a of users)
1871
+ use(a, c.kind, c.ref);
1872
+ }
1873
+ for (const kind of ["skill", "agent_template"]) {
1874
+ const platform = await loadComponents(t, kind, { itemId });
1875
+ const st = await loadScopeState(t, kind, platform);
1876
+ const off = platform.filter((c) => c.scopeMode === "follow" &&
1877
+ componentOn(c, pluginFactsOf(st, c.itemId, orgId), listedIn(st, c.id, orgId), switchOf(st, c.id, orgId)));
1878
+ const refs = await referenceIds(t, orgId, kind, off.map((c) => c.id));
1879
+ for (const a of agents) {
1880
+ for (const ref of kind === "skill" ? a.skills : a.templates) {
1881
+ if (refs.has(ref))
1882
+ use(a, kind, ref);
1883
+ }
1308
1884
  }
1309
1885
  }
1310
- for (const s of def?.skills?.orgSkills ?? [])
1311
- if (typeof s === "string")
1312
- skills.add(s);
1313
- for (const x of def?.subagents?.templates ?? [])
1314
- if (typeof x === "string")
1315
- templates.add(x);
1316
- }
1317
- return { connectors, skills, templates };
1886
+ };
1887
+ await visit(row.item_id, comps, true, new Set([installId]));
1888
+ return {
1889
+ installId,
1890
+ name: row.name,
1891
+ version: row.version,
1892
+ components: comps.map((c) => ({ kind: c.kind, ref: c.ref, created: c.created })),
1893
+ kept,
1894
+ agents: [...used.values()]
1895
+ .map((a) => ({ ...a, uses: a.uses.sort((x, y) => x.ref.localeCompare(y.ref)) }))
1896
+ .sort((x, y) => x.id.localeCompare(y.id)),
1897
+ };
1898
+ }
1899
+ /**
1900
+ * The connectors, skills (selected, pinned, or in an inline sub-agent template) and agent
1901
+ * templates (`subagents.templates`) referenced by the current definitions of the org's live
1902
+ * agents.
1903
+ */
1904
+ async agentRefs(orgId) {
1905
+ const out = { connectors: new Set(), skills: new Set(), templates: new Set() };
1906
+ for (const a of await agentDefinitionRefs(this.db, orgId)) {
1907
+ for (const x of a.connectors)
1908
+ out.connectors.add(x);
1909
+ for (const x of a.skills)
1910
+ out.skills.add(x);
1911
+ for (const x of a.templates)
1912
+ out.templates.add(x);
1913
+ }
1914
+ return out;
1318
1915
  }
1319
1916
  };
1320
1917
  __decorate([
@@ -1326,9 +1923,6 @@ __decorate([
1326
1923
  __decorate([
1327
1924
  Transactional({ propagation: "requires_new" })
1328
1925
  ], PluginInstaller.prototype, "createInstallRow", null);
1329
- __decorate([
1330
- Transactional({ propagation: "requires_new" })
1331
- ], PluginInstaller.prototype, "installAgentTemplate", null);
1332
1926
  __decorate([
1333
1927
  Transactional({ propagation: "requires_new" })
1334
1928
  ], PluginInstaller.prototype, "markInstalled", null);
@@ -1359,6 +1953,12 @@ __decorate([
1359
1953
  __decorate([
1360
1954
  Transactional({ propagation: "mandatory" })
1361
1955
  ], PluginInstaller.prototype, "undoUpgradeIn", null);
1956
+ __decorate([
1957
+ Transactional({ propagation: "requires_new" })
1958
+ ], PluginInstaller.prototype, "recordConnector", null);
1959
+ __decorate([
1960
+ Transactional()
1961
+ ], PluginInstaller.prototype, "recordOnLiveInstall", null);
1362
1962
  PluginInstaller = __decorate([
1363
1963
  Injectable(),
1364
1964
  __param(0, Inject(KernelDb)),
@@ -1367,11 +1967,10 @@ PluginInstaller = __decorate([
1367
1967
  __param(3, Inject(ExtensionRegistry)),
1368
1968
  __param(4, Inject(SkillsService)),
1369
1969
  __param(5, Inject(OrgExtensionConfigs)),
1370
- __param(6, Inject(CatalogRequestsService)),
1371
- __param(7, Inject(KernelConfigService)),
1372
- __param(8, Inject(ConnectorsService)),
1373
- __param(9, Inject(KERNEL_LOGGER)),
1374
- __param(10, Inject(TransactionHost))
1970
+ __param(6, Inject(KernelConfigService)),
1971
+ __param(7, Inject(ConnectorsService)),
1972
+ __param(8, Inject(KERNEL_LOGGER)),
1973
+ __param(9, Inject(TransactionHost))
1375
1974
  ], PluginInstaller);
1376
1975
  export { PluginInstaller };
1377
1976
  /**
@@ -1483,3 +2082,36 @@ function orderByRequires(set) {
1483
2082
  }
1484
2083
  return placed;
1485
2084
  }
2085
+ /**
2086
+ * Whether org row `id` (a skill or an agent template of the org) is linked without a pin to a live
2087
+ * platform row the org promoted when sharing it (ruling P3-3): owned by the org and from no plugin
2088
+ * (`catalog_item_id` null). A component of the org's own uploaded plugin is a plugin's, so its
2089
+ * install copies are removed and reverted as any plugin's.
2090
+ */
2091
+ async function promotedOrgRow(db, orgId, kind, id) {
2092
+ const row = kind === "skill"
2093
+ ? await db
2094
+ .selectFrom("skills as s")
2095
+ .innerJoin("platform_skills as p", "p.id", "s.platform_skill_id")
2096
+ .select("s.id")
2097
+ .where("s.id", "=", id)
2098
+ .where("s.org_id", "=", orgId)
2099
+ .where("s.pinned_version", "is", null)
2100
+ .where("p.owner_org_id", "=", orgId)
2101
+ // promoted, not an org plugin's component (which has its plugin, P3-2)
2102
+ .where("p.catalog_item_id", "is", null)
2103
+ .where("p.deleted_at", "is", null)
2104
+ .executeTakeFirst()
2105
+ : await db
2106
+ .selectFrom("agent_templates as a")
2107
+ .innerJoin("platform_agent_templates as p", "p.id", "a.platform_template_id")
2108
+ .select("a.id")
2109
+ .where("a.id", "=", id)
2110
+ .where("a.org_id", "=", orgId)
2111
+ .where("a.pinned_version", "is", null)
2112
+ .where("p.owner_org_id", "=", orgId)
2113
+ .where("p.catalog_item_id", "is", null)
2114
+ .where("p.deleted_at", "is", null)
2115
+ .executeTakeFirst();
2116
+ return row !== undefined;
2117
+ }