@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
@@ -12,385 +12,428 @@ import { Inject, Injectable } from "@nestjs/common";
12
12
  import { sql } from "kysely";
13
13
  import { ApiError } from "../errors.js";
14
14
  import { audit } from "../identity/audit.js";
15
- import { EnterpriseAdminLock } from "../identity/enterprise-admin.js";
15
+ import { readOrgMarketplaceBrowse } from "../identity/settings.js";
16
+ import { SuperAdminLock } from "../identity/super-admin.js";
17
+ import { KernelConfigService } from "../infra/config/kernel-config.service.js";
16
18
  import { KernelDb } from "../infra/database/kernel-db.js";
17
19
  import { TransactionHost } from "../infra/database/transaction-host.js";
18
20
  import { Transactional } from "../infra/database/transactional.decorator.js";
21
+ import { LockService } from "../infra/lock/lock.service.js";
22
+ import { WithLock } from "../infra/lock/with-lock.decorator.js";
19
23
  import { OrgLock } from "../orgs/org-lock.js";
20
24
  import { roleAtLeast } from "../orgs/roles.js";
25
+ import { CatalogService } from "./catalog.service.js";
26
+ import { CatalogScopeService } from "./catalog-scope.service.js";
27
+ import { assertEntryNotDeprecated, loadMarketplaceEntry } from "./marketplaces.service.js";
28
+ import { OrgCatalogService } from "./org-catalog.service.js";
29
+ import { PluginImport } from "./plugin-import.js";
30
+ import { itemsSeenBy } from "./scope-state.js";
21
31
  /** 申请列表一次最多返回的条数。 */
22
32
  export const CATALOG_REQUESTS_LIST_MAX = 200;
23
33
  const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
24
34
  const requestNotFound = () => new ApiError("catalog.request_not_found", "Catalog request not found");
25
35
  const itemNotFound = () => new ApiError("catalog.item_not_found", "Catalog item not found");
26
- const itemDisabled = () => new ApiError("catalog.item_disabled", "This catalog item is disabled by the enterprise admin and cannot be newly installed");
27
- /** 在调用方事务里读条目的策略(FOR SHARE:与企业管理员改策略 / 删除互斥)。不存在或已删除 → undefined。 */
28
- async function lockItem(t, itemId) {
29
- if (!UUID_RE.test(itemId))
30
- return undefined;
31
- return t
32
- .selectFrom("catalog_items")
33
- .select(["id", "name", "policy", "deleted_at"])
34
- .where("id", "=", itemId)
35
- .forShare()
36
- .executeTakeFirst();
37
- }
38
- async function hasGrant(db, orgId, itemId) {
39
- const g = await db
40
- .selectFrom("catalog_org_grants")
41
- .select("item_id")
42
- .where("item_id", "=", itemId)
43
- .where("org_id", "=", orgId)
44
- .executeTakeFirst();
45
- return g !== undefined;
46
- }
47
- /**
48
- * Before an org creates a component from the catalog (enabling an extension, creating a connector
49
- * from a template, importing a skill), re-checks the item policy in the caller's transaction (C22):
50
- * deleted or disabled -> `catalog.item_disabled`; needs_approval without an enterprise admin grant
51
- * for this org -> `catalog.approval_required`; allow or granted -> passes. A dependency's
52
- * components pass `approvedBy`, the item the org is installing (spec §10: approval follows the
53
- * installed plugin only): the dependency's own item must still be live and not disabled, and the
54
- * approval is judged by `approvedBy`.
55
- */
56
- export async function assertItemInstallable(t, orgId, itemId, approvedBy = itemId) {
57
- if (approvedBy !== itemId) {
58
- const own = await lockItem(t, itemId);
59
- if (!own || own.deleted_at !== null || own.policy === "disabled")
60
- throw itemDisabled();
61
- }
62
- const item = await lockItem(t, approvedBy);
63
- if (!item || item.deleted_at !== null || item.policy === "disabled")
64
- throw itemDisabled();
65
- if (item.policy === "needs_approval" && !(await hasGrant(t, orgId, approvedBy))) {
66
- throw new ApiError("catalog.approval_required", "This catalog item needs enterprise admin approval before this organization can install it");
67
- }
68
- }
69
- /**
70
- * The extensions among `plugins` whose own catalog item (the non-deleted item with the same name) is
71
- * disabled (FOR SHARE: exclusive with policy changes). A disabled item is a master switch: no path
72
- * (direct enabling, its item, another plugin) can newly enable its extension (Ruling M-5).
73
- */
74
- export async function disabledPluginItems(db, plugins) {
75
- if (plugins.length === 0)
76
- return [];
77
- const rows = await db
78
- .selectFrom("catalog_items")
79
- .select("name")
80
- .where("name", "in", [...plugins])
81
- .where("policy", "=", "disabled")
82
- .where("deleted_at", "is", null)
83
- .orderBy("name")
84
- .forShare()
85
- .execute();
86
- return [...new Set(rows.map((r) => r.name))];
87
- }
88
- /**
89
- * Throws `catalog.item_disabled` when a plugin's own catalog item is disabled (the message names
90
- * the plugin).
91
- */
92
- export function pluginItemDisabled(names) {
93
- return new ApiError("catalog.item_disabled", `The enterprise admin disabled the catalog item of extension ${names.join(", ")}; it cannot be newly enabled, not even through a plugin that bundles it`);
94
- }
95
- /**
96
- * When an org enables an extension directly (not by installing from an item, e.g.
97
- * `PUT /orgs/:orgId/extensions/:extension`), it is judged by every catalog item that brought it into the
98
- * deployment (`extension_catalog_sources`), and **the strictest wins**: any source disabled ->
99
- * `catalog.item_disabled`; otherwise any source needs_approval without a grant of that item to the
100
- * org -> `catalog.approval_required`; all allow / granted -> passes. Deleted items no longer count
101
- * as sources (an enterprise admin deleting an item withdraws its constraint). No source (not
102
- * installed through the catalog) -> not bound by catalog policy.
103
- */
104
- export async function assertPluginSourcesInstallable(t, orgId, plugin) {
105
- const rows = await t
106
- .selectFrom("extension_catalog_sources as s")
107
- .innerJoin("catalog_items as i", "i.id", "s.item_id")
108
- .select(["i.id", "i.policy"])
109
- .where("s.plugin", "=", plugin)
110
- .where("i.deleted_at", "is", null)
111
- .orderBy("i.id")
112
- .forShare("i")
113
- .execute();
114
- if (rows.some((r) => r.policy === "disabled"))
115
- throw itemDisabled();
116
- for (const r of rows) {
117
- if (r.policy === "needs_approval" && !(await hasGrant(t, orgId, r.id))) {
118
- throw new ApiError("catalog.approval_required", "A catalog item that brought this extension in needs enterprise admin approval before this organization can enable it");
119
- }
120
- }
121
- }
122
- /**
123
- * Cancels catalog requests still pending in the caller's transaction (`db` is its handle; when the
124
- * item or the org is deleted), status `cancelled` (the decider is the actor). Each one audits
125
- * `catalog.request_cancelled` (with the reason). Returns how many were cancelled.
126
- */
127
- export async function cancelPendingRequests(db, where, actor, reason, opts = {}) {
128
- let q = db
129
- .updateTable("catalog_requests")
130
- .set({ status: "cancelled", decided_by: actor, decided_at: sql `now()` })
131
- .where("status", "=", "pending");
132
- q =
133
- "itemId" in where ? q.where("item_id", "=", where.itemId) : q.where("org_id", "=", where.orgId);
134
- const rows = await q.returning(["id", "org_id", "item_id", "stage"]).execute();
135
- for (const r of rows) {
136
- await audit(db, {
137
- actorAccountId: actor,
138
- ...(opts.actorTokenId !== undefined && { actorTokenId: opts.actorTokenId }),
139
- orgId: r.org_id,
140
- action: "catalog.request_cancelled",
141
- target: r.id,
142
- detail: { itemId: r.item_id, stage: r.stage, reason },
143
- });
144
- }
145
- return rows.length;
146
- }
36
+ const itemDisabled = () => new ApiError("catalog.item_disabled", "This catalog item is disabled by the super admin and cannot be requested");
37
+ const alreadyDecided = () => new ApiError("catalog.request_decided", "This request has already been decided");
38
+ const pendingExists = () => new ApiError("catalog.request_pending", "This organization already has a pending request of this kind for it");
39
+ /** A unique violation (the partial index of pending requests). */
40
+ const isUniqueViolation = (e) => typeof e === "object" && e !== null && e.code === "23505";
41
+ /** The deployment-level kinds (decided by the super admin). */
42
+ const DEPLOYMENT_KINDS = ["access", "import"];
43
+ /** The org-level kinds (decided by the org admins). */
44
+ const ORG_KINDS = ["enable", "connector_setup"];
147
45
  /**
148
- * Catalog requests and approvals (C22 / F-AF). Two levels:
149
- * - a member request (stage `org`) goes to the org admins' inbox, an org admin (`catalog.decide`)
150
- * approves or rejects it; when the item is needs_approval without a grant for this org, approving
151
- * moves the request to stage `deployment` (still pending) for the enterprise admins to decide;
152
- * - an org admin installing a needs_approval item without a grant -> creates a stage `deployment`
153
- * request (or moves the existing pending one there);
154
- * - an enterprise admin approving a stage `deployment` request -> writes a grant
155
- * (`catalog_org_grants`, valid across versions), after which org admins can install.
156
- * One pending request per org and item (partial unique index; org-side writes all run inside the
157
- * org row lock, in order). No in-process state.
46
+ * Catalog requests under plugin scope (spec §5.1). Three kinds, one pending request per (org,
47
+ * kind, item or entry) (partial unique indexes; org-side writes run inside the org row lock):
48
+ * - `enable`: a member asks the org admins to switch on an item that is off in the org (an
49
+ * `optional` item); an org admin approving it switches the item on, as that admin;
50
+ * - `access`: an org admin asks the super admin for a `named` item shown to orgs outside its
51
+ * list; approving adds the org to the list (`CatalogScopeService.addOrg`), the scope sync then
52
+ * installs it;
53
+ * - `import`: an org admin asks for a marketplace entry not in the catalog (deployment setting
54
+ * `orgMarketplaceBrowse`); approving prepares the import and returns its staging, the request
55
+ * resolves when the super admin confirms it (scope default `named` = the requesting org);
56
+ * - `connector_setup` (ruling P4-7): one per agent (`agent_id`, `pending_keys`), asking the org
57
+ * admins to set up an agent's pending connectors; written by the agents module
58
+ * (`PendingConnectorRequests`), closed by binding (`approved`) or the agent's deletion
59
+ * (`cancelled`); here it is listed and rejected.
60
+ * A rejection stores an optional reason. Decided requests show in the requester's inbox until
61
+ * dismissed. No in-process state.
158
62
  */
159
63
  let CatalogRequestsService = class CatalogRequestsService {
160
64
  kdb;
161
65
  orgLock;
162
66
  adminLock;
67
+ orgCatalog;
68
+ scope;
69
+ catalog;
70
+ config;
71
+ pluginImport;
163
72
  txHost;
73
+ lockService;
164
74
  constructor(kdb,
165
- /** The org row and enterprise admin locks: both join the caller's transaction. */
166
- orgLock, adminLock, txHost) {
75
+ /** The org row and super admin locks: both join the caller's transaction. */
76
+ orgLock, adminLock, orgCatalog, scope, catalog, config, pluginImport, txHost,
77
+ /** Serializes the approvals of one `import` request (`@WithLock`). */
78
+ lockService) {
167
79
  this.kdb = kdb;
168
80
  this.orgLock = orgLock;
169
81
  this.adminLock = adminLock;
82
+ this.orgCatalog = orgCatalog;
83
+ this.scope = scope;
84
+ this.catalog = catalog;
85
+ this.config = config;
86
+ this.pluginImport = pluginImport;
170
87
  this.txHost = txHost;
88
+ this.lockService = lockService;
171
89
  }
172
90
  /** The kernel-schema handle of the current context (the transaction, else the pool). */
173
91
  get db() {
174
92
  return this.kdb.db;
175
93
  }
176
94
  /**
177
- * A member request (`catalog.request`, re-checked inside the org row lock). Item missing /
178
- * deleted -> `catalog.item_not_found`; disabled -> org admins get `catalog.item_disabled`,
179
- * members get `catalog.item_not_found` (members do not see disabled items). An existing pending
180
- * request is returned as is (`created: false`), no new one. Audits `catalog.requested`.
95
+ * A request for a catalog item (`POST /orgs/:orgId/catalog/:itemId/requests`): `enable`
96
+ * (`catalog.request`, members and up) or `access` (`catalog.decide`, org admins), checked first.
97
+ * The item as the org sees it: absent (missing, deleted, hidden, disabled for a member) ->
98
+ * `catalog.item_not_found`; disabled -> `catalog.item_disabled` for an org admin; `access` needs
99
+ * `not_offered`, `enable` needs `off` (else `catalog.request_invalid`); a pending request of the
100
+ * kind -> `catalog.request_pending`. Audits `catalog.requested`.
181
101
  */
182
- async request(orgId, actor, itemId, input, opts = {}) {
183
- const r = await this.writeRequest(orgId, actor, itemId, input, opts);
184
- return { request: await this.view(r.id), created: r.created };
185
- }
186
- async writeRequest(orgId, actor, itemId, input, opts) {
187
- const t = this.db;
188
- const { role } = await this.orgLock.lockAndAuthorize(orgId, actor, "catalog.request");
189
- const item = await lockItem(t, itemId);
190
- if (!item || item.deleted_at !== null)
102
+ async requestItem(orgId, actor, itemId, input, opts = {}) {
103
+ const action = input.kind === "access" ? "catalog.decide" : "catalog.request";
104
+ await this.authorize(orgId, actor, action);
105
+ if (!UUID_RE.test(itemId))
106
+ throw itemNotFound();
107
+ const [item] = await this.orgCatalog.list(orgId, actor, itemId);
108
+ if (!item)
191
109
  throw itemNotFound();
192
- // 成员看不到 disabled 的条目(列表、详情、图标一致):同样答 not found,不暴露条目存在
193
- if (item.policy === "disabled") {
194
- throw roleAtLeast(role, "admin") ? itemDisabled() : itemNotFound();
110
+ if (item.state === "unavailable")
111
+ throw itemDisabled();
112
+ const want = input.kind === "access" ? "not_offered" : "off";
113
+ if (item.state !== want) {
114
+ throw new ApiError("catalog.request_invalid", input.kind === "access"
115
+ ? "This plugin is already offered to this organization"
116
+ : "This plugin is not off in this organization (or not one an org admin switches on)");
195
117
  }
196
- const existing = await this.pendingRow(orgId, itemId);
118
+ const id = await this.writeItemRequest(orgId, actor, item.name, itemId, input, opts);
119
+ return this.view(id);
120
+ }
121
+ /** The role check alone, before any item error (a member cannot probe items by error codes). */
122
+ async authorize(orgId, actor, action) {
123
+ await this.orgLock.lockAndAuthorize(orgId, actor, action);
124
+ }
125
+ async writeItemRequest(orgId, actor, name, itemId, input, opts) {
126
+ const t = this.db;
127
+ await this.orgLock.lockAndAuthorize(orgId, actor, input.kind === "access" ? "catalog.decide" : "catalog.request");
128
+ const existing = await t
129
+ .selectFrom("catalog_requests")
130
+ .select("id")
131
+ .where("org_id", "=", orgId)
132
+ .where("item_id", "=", itemId)
133
+ .where("kind", "=", input.kind)
134
+ .where("status", "=", "pending")
135
+ .executeTakeFirst();
197
136
  if (existing)
198
- return { id: existing.id, created: false };
137
+ throw pendingExists();
199
138
  const id = randomUUID();
200
- await t
201
- .insertInto("catalog_requests")
202
- .values({
203
- id,
204
- org_id: orgId,
205
- item_id: itemId,
206
- version: input.version ?? null,
207
- stage: "org",
208
- requested_by: actor,
209
- note: input.note ?? "",
210
- })
211
- .execute();
139
+ try {
140
+ await t
141
+ .insertInto("catalog_requests")
142
+ .values({
143
+ id,
144
+ org_id: orgId,
145
+ item_id: itemId,
146
+ kind: input.kind,
147
+ // still written for the old NOT NULL / CHECK, never read
148
+ stage: input.kind === "enable" ? "org" : "deployment",
149
+ requested_by: actor,
150
+ note: input.note ?? "",
151
+ })
152
+ .execute();
153
+ }
154
+ catch (e) {
155
+ if (isUniqueViolation(e))
156
+ throw pendingExists();
157
+ throw e;
158
+ }
212
159
  await audit(t, {
213
160
  actorAccountId: actor,
214
161
  ...(opts.actorTokenId !== undefined && { actorTokenId: opts.actorTokenId }),
215
162
  orgId,
216
163
  action: "catalog.requested",
217
164
  target: id,
218
- detail: { itemId, name: item.name, stage: "org" },
165
+ detail: { itemId, name, kind: input.kind, ...opts.auditDetail },
219
166
  });
220
- return { id, created: true };
221
- }
222
- pendingRow(orgId, itemId) {
223
- return this.db
224
- .selectFrom("catalog_requests")
225
- .select(["id", "stage"])
226
- .where("org_id", "=", orgId)
227
- .where("item_id", "=", itemId)
228
- .where("status", "=", "pending")
229
- .executeTakeFirst();
167
+ return id;
230
168
  }
231
169
  /**
232
- * An org admin installing a needs_approval item without a grant: in the caller's transaction (the
233
- * caller has locked the org row and re-checked the role) creates a stage `deployment` request; an
234
- * existing pending request is moved to deployment (a member request goes to the enterprise admins
235
- * with it). Returns the request id. Audits `catalog.requested`.
170
+ * An org admin asks for a marketplace entry to be imported (`POST /orgs/:orgId/
171
+ * marketplace-requests`, `catalog.decide`). The deployment setting `orgMarketplaceBrowse` off ->
172
+ * `catalog.marketplace_browse_disabled`; the marketplace or the entry / version missing ->
173
+ * `marketplace.not_found` / `marketplace.entry_not_found`; a deprecated version ->
174
+ * `marketplace.entry_deprecated`; a live item of that name ->
175
+ * `catalog.request_invalid` (ask for access instead) when the org can see or request that item
176
+ * (a hidden one is not revealed: the request is accepted); a pending request for the entry ->
177
+ * `catalog.request_pending`. Audits `catalog.requested`.
236
178
  */
237
- async requestDeployment(orgId, actor, item, version, opts = {}) {
179
+ async requestImport(orgId, actor, input, opts = {}) {
180
+ const id = await this.writeImportRequest(orgId, actor, input, opts);
181
+ return this.view(id);
182
+ }
183
+ async writeImportRequest(orgId, actor, input, opts) {
238
184
  const t = this.db;
239
- const existing = await this.pendingRow(orgId, item.id);
240
- if (existing) {
241
- if (existing.stage === "org") {
242
- await t
243
- .updateTable("catalog_requests")
244
- .set({ stage: "deployment", org_decided_by: actor, org_decided_at: sql `now()` })
245
- .where("id", "=", existing.id)
246
- .execute();
247
- await audit(t, {
248
- actorAccountId: actor,
249
- ...(opts.actorTokenId !== undefined && { actorTokenId: opts.actorTokenId }),
250
- orgId,
251
- action: "catalog.request_decided",
252
- target: existing.id,
253
- detail: { itemId: item.id, decision: "approve", stage: "org", escalated: true },
254
- });
255
- }
256
- return existing.id;
185
+ await this.orgLock.lockAndAuthorize(orgId, actor, "catalog.decide");
186
+ if (!(await readOrgMarketplaceBrowse(t))) {
187
+ throw new ApiError("catalog.marketplace_browse_disabled", "Organizations cannot browse the marketplaces or request imports in this deployment");
257
188
  }
189
+ const { entry } = await loadMarketplaceEntry(t, this.config.get(), input.marketplaceId, input.name, input.version);
190
+ assertEntryNotDeprecated(entry);
191
+ const live = await t
192
+ .selectFrom("catalog_items")
193
+ .select("id")
194
+ .where("name", "=", input.name)
195
+ .where("deleted_at", "is", null)
196
+ .executeTakeFirst();
197
+ // Only an item the org can see or request is named back to it; a hidden `named` item stays
198
+ // unknown and the request is accepted (approving it adds the org to that item's list)
199
+ if (live && (await itemsSeenBy(t, orgId, [live.id])).has(live.id)) {
200
+ throw new ApiError("catalog.request_invalid", `Plugin ${input.name} is already in the catalog; request access to it instead`);
201
+ }
202
+ const existing = await t
203
+ .selectFrom("catalog_requests")
204
+ .select("id")
205
+ .where("org_id", "=", orgId)
206
+ .where("kind", "=", "import")
207
+ .where("marketplace_id", "=", input.marketplaceId)
208
+ .where("entry_name", "=", input.name)
209
+ .where("status", "=", "pending")
210
+ .executeTakeFirst();
211
+ if (existing)
212
+ throw pendingExists();
258
213
  const id = randomUUID();
259
- await t
260
- .insertInto("catalog_requests")
261
- .values({
262
- id,
263
- org_id: orgId,
264
- item_id: item.id,
265
- version,
266
- stage: "deployment",
267
- requested_by: actor,
268
- })
269
- .execute();
214
+ try {
215
+ await t
216
+ .insertInto("catalog_requests")
217
+ .values({
218
+ id,
219
+ org_id: orgId,
220
+ item_id: null,
221
+ kind: "import",
222
+ stage: "deployment",
223
+ marketplace_id: input.marketplaceId,
224
+ entry_name: input.name,
225
+ entry_version: input.version,
226
+ requested_by: actor,
227
+ note: input.note ?? "",
228
+ })
229
+ .execute();
230
+ }
231
+ catch (e) {
232
+ if (isUniqueViolation(e))
233
+ throw pendingExists();
234
+ throw e;
235
+ }
270
236
  await audit(t, {
271
237
  actorAccountId: actor,
272
238
  ...(opts.actorTokenId !== undefined && { actorTokenId: opts.actorTokenId }),
273
239
  orgId,
274
240
  action: "catalog.requested",
275
241
  target: id,
276
- detail: { itemId: item.id, name: item.name, stage: "deployment" },
242
+ detail: {
243
+ kind: "import",
244
+ marketplaceId: input.marketplaceId,
245
+ name: input.name,
246
+ version: input.version,
247
+ ...opts.auditDetail,
248
+ },
277
249
  });
278
250
  return id;
279
251
  }
280
252
  /**
281
- * 安装成功后:本组织该条目仍 pending 的申请(成员申请 stage org,以及之前因 needs_approval 建的 stage deployment
282
- * 申请——条目之后改成 allow 再装的就不会一直挂着)标为 approved(安装者即决定人),收件箱与企业管理员列表随之清空。
283
- * 在调用方事务里执行。
284
- */
285
- async resolveByInstall(orgId, itemId, actor, opts = {}) {
286
- const t = this.db;
287
- const rows = await t
288
- .updateTable("catalog_requests")
289
- .set({ status: "approved", decided_by: actor, decided_at: sql `now()` })
290
- .where("org_id", "=", orgId)
291
- .where("item_id", "=", itemId)
292
- .where("status", "=", "pending")
293
- .returning(["id", "stage"])
294
- .execute();
295
- for (const r of rows) {
296
- await audit(t, {
297
- actorAccountId: actor,
298
- ...(opts.actorTokenId !== undefined && { actorTokenId: opts.actorTokenId }),
299
- orgId,
300
- action: "catalog.request_decided",
301
- target: r.id,
302
- detail: { itemId, decision: "approve", stage: r.stage, installed: true },
303
- });
304
- }
305
- }
306
- /**
307
- * An org admin decides a member request (`catalog.decide`, re-checked inside the org row lock;
308
- * the request row FOR UPDATE). Not this org's request -> `catalog.request_not_found`; already
309
- * decided or handed to the enterprise admins -> `catalog.request_decided`. On approval: item
310
- * deleted or disabled -> `catalog.item_disabled`; needs_approval without a grant -> moved to stage
311
- * deployment (still pending); otherwise approved. Audits `catalog.request_decided`.
253
+ * An org admin decides a member's `enable` or `connector_setup` request (`catalog.decide`). Not
254
+ * this org's request of those kinds -> `catalog.request_not_found`; decided ->
255
+ * `catalog.request_decided`. Approving an `enable` request switches the item on in the org as the
256
+ * deciding admin ({@link OrgCatalogService.setSwitch}: its errors, e.g. inputs the install
257
+ * needs, leave the request pending); the install itself resolves the request. A
258
+ * `connector_setup` request is approved only by binding its connectors (ruling P4-T6-6):
259
+ * approving it -> `catalog.request_invalid`. Rejecting stores the reason. Audits
260
+ * `catalog.request_decided`.
312
261
  */
313
262
  async decideOrg(orgId, actor, requestId, decision, opts = {}) {
314
263
  if (!UUID_RE.test(requestId))
315
264
  throw requestNotFound();
316
- await this.writeDecideOrg(orgId, actor, requestId, decision, opts);
265
+ if (decision.approve) {
266
+ const itemId = await this.pendingOrgRequest(orgId, actor, requestId);
267
+ await this.orgCatalog.setSwitch(orgId, actor, itemId, { enabled: true }, opts.actorTokenId);
268
+ }
269
+ await this.writeDecision(requestId, actor, decision, opts, { orgId });
317
270
  return this.view(requestId);
318
271
  }
319
- async writeDecideOrg(orgId, actor, requestId, decision, opts) {
320
- const t = this.db;
272
+ /** The item of a pending `enable` request of the org (the decider re-checked). */
273
+ async pendingOrgRequest(orgId, actor, requestId) {
321
274
  await this.orgLock.lockAndAuthorize(orgId, actor, "catalog.decide");
322
- const row = await t
275
+ const row = await this.db
323
276
  .selectFrom("catalog_requests")
324
- .select(["id", "item_id", "stage", "status"])
277
+ .select(["item_id", "status", "kind"])
325
278
  .where("id", "=", requestId)
326
279
  .where("org_id", "=", orgId)
327
- .forUpdate()
280
+ .where("kind", "in", [...ORG_KINDS])
328
281
  .executeTakeFirst();
329
282
  if (!row)
330
283
  throw requestNotFound();
331
- if (row.status !== "pending" || row.stage !== "org") {
332
- throw new ApiError("catalog.request_decided", row.status === "pending"
333
- ? "This request is waiting for the enterprise admin"
334
- : "This request has already been decided");
284
+ if (row.status !== "pending")
285
+ throw alreadyDecided();
286
+ if (row.kind === "connector_setup") {
287
+ throw new ApiError("catalog.request_invalid", "A connector setup request is resolved by binding the agent's connectors; reject it to refuse");
335
288
  }
336
- let escalated = false;
337
- if (decision === "approve") {
338
- const item = await lockItem(t, row.item_id);
339
- if (!item || item.deleted_at !== null || item.policy === "disabled")
340
- throw itemDisabled();
341
- escalated = item.policy === "needs_approval" && !(await hasGrant(t, orgId, row.item_id));
289
+ if (row.item_id === null)
290
+ throw requestNotFound();
291
+ return row.item_id;
292
+ }
293
+ /**
294
+ * A super admin decides an `access` or `import` request (re-checked inside the super
295
+ * admin lock; the request row FOR UPDATE). Missing or an `enable` request ->
296
+ * `catalog.request_not_found`; decided -> `catalog.request_decided`. Approving `access`: the item
297
+ * deleted or disabled -> `catalog.item_disabled`, the org deleted -> not found; otherwise the org
298
+ * joins the item's `named` list. Approving `import` prepares the import of the entry and returns
299
+ * it; the request stays pending, linked to the staging, until that confirm commits (approving
300
+ * again prepares a new one). Audits `catalog.request_decided` (`catalog.request_import_prepared`
301
+ * for an import's approval).
302
+ */
303
+ async decideDeployment(actor, requestId, decision, opts = {}) {
304
+ if (!UUID_RE.test(requestId))
305
+ throw requestNotFound();
306
+ const row = await this.pendingDeploymentRequest(actor, requestId);
307
+ if (decision.approve && row.kind === "import")
308
+ return this.approveImport(actor, requestId, opts);
309
+ await this.writeDecision(requestId, actor, decision, opts, { deployment: true });
310
+ return { request: await this.view(requestId) };
311
+ }
312
+ /**
313
+ * Approves an `import` request, one approval of a request at a time (across replicas): an item
314
+ * of the entry's name that holds the requested version already (one hidden from the org, which
315
+ * is why the request was accepted) -> the org joins its `named` list at once, nothing imported;
316
+ * a staging linked by an earlier approval and not expired -> that staging again; otherwise the
317
+ * import is prepared and linked. The confirm of a staging adds the org to an item that exists by
318
+ * then (`PluginImport.commit`).
319
+ */
320
+ async approveImport(actor, requestId, opts) {
321
+ const row = await this.pendingDeploymentRequest(actor, requestId);
322
+ if (row.marketplace_id === null || row.entry_name === null) {
323
+ throw new ApiError("catalog.request_invalid", "The marketplace of this request was deleted; reject it");
342
324
  }
343
- await t
325
+ const existing = await this.db
326
+ .selectFrom("catalog_items as i")
327
+ .innerJoin("catalog_item_versions as v", "v.item_id", "i.id")
328
+ .select("i.id")
329
+ .where("i.name", "=", row.entry_name)
330
+ .where("i.deleted_at", "is", null)
331
+ .where("v.version", "=", row.entry_version ?? "")
332
+ .executeTakeFirst();
333
+ if (existing) {
334
+ await this.writeDecision(requestId, actor, { approve: true }, opts, {
335
+ deployment: true,
336
+ grantItem: existing.id,
337
+ });
338
+ return { request: await this.view(requestId) };
339
+ }
340
+ if (row.staging_id !== null) {
341
+ const staged = await this.pluginImport.staged(row.staging_id).catch(() => undefined);
342
+ if (staged) {
343
+ return {
344
+ request: await this.view(requestId),
345
+ import: {
346
+ stagingId: staged.stagingId,
347
+ review: staged.review,
348
+ permissionsMismatch: staged.permissionsMismatch ?? null,
349
+ },
350
+ };
351
+ }
352
+ }
353
+ const prepared = await this.catalog.importFromMarketplace(actor, {
354
+ marketplaceId: row.marketplace_id,
355
+ name: row.entry_name,
356
+ ...(row.entry_version !== null && { version: row.entry_version }),
357
+ }, opts);
358
+ await this.linkStaging(actor, requestId, prepared.stagingId, opts);
359
+ return { request: await this.view(requestId), import: prepared };
360
+ }
361
+ /** A pending `access` / `import` request (the row locked; the super admin re-checked). */
362
+ async pendingDeploymentRequest(actor, requestId) {
363
+ await this.adminLock.lockAndAuthorize(actor);
364
+ const row = await this.db
365
+ .selectFrom("catalog_requests")
366
+ .select(["kind", "status", "marketplace_id", "entry_name", "entry_version", "staging_id"])
367
+ .where("id", "=", requestId)
368
+ .where("kind", "in", [...DEPLOYMENT_KINDS])
369
+ .forUpdate()
370
+ .executeTakeFirst();
371
+ if (!row)
372
+ throw requestNotFound();
373
+ if (row.status !== "pending")
374
+ throw alreadyDecided();
375
+ return row;
376
+ }
377
+ /** Links a still pending `import` request to its prepared staging. */
378
+ async linkStaging(actor, requestId, stagingId, opts) {
379
+ await this.adminLock.lockAndAuthorize(actor);
380
+ const row = await this.db
381
+ .selectFrom("catalog_requests")
382
+ .select(["org_id", "status", "entry_name"])
383
+ .where("id", "=", requestId)
384
+ .forUpdate()
385
+ .executeTakeFirstOrThrow();
386
+ if (row.status !== "pending")
387
+ throw alreadyDecided();
388
+ await this.db
344
389
  .updateTable("catalog_requests")
345
- .set(escalated
346
- ? { stage: "deployment", org_decided_by: actor, org_decided_at: sql `now()` }
347
- : {
348
- status: decision === "approve" ? "approved" : "rejected",
349
- decided_by: actor,
350
- decided_at: sql `now()`,
351
- })
390
+ .set({ staging_id: stagingId })
352
391
  .where("id", "=", requestId)
353
392
  .execute();
354
- await audit(t, {
393
+ await audit(this.db, {
355
394
  actorAccountId: actor,
356
395
  ...(opts.actorTokenId !== undefined && { actorTokenId: opts.actorTokenId }),
357
- orgId,
358
- action: "catalog.request_decided",
396
+ orgId: row.org_id,
397
+ action: "catalog.request_import_prepared",
359
398
  target: requestId,
360
- detail: { itemId: row.item_id, decision, stage: "org", escalated },
399
+ detail: { name: row.entry_name, stagingId },
361
400
  });
362
401
  }
363
402
  /**
364
- * An enterprise admin decides a stage deployment request (re-checked inside the enterprise admin
365
- * lock; the request row FOR UPDATE). Missing or still at the org stage ->
366
- * `catalog.request_not_found`; already decided -> `catalog.request_decided`; on approval, item
367
- * deleted or disabled -> `catalog.item_disabled`, the request's org deleted ->
368
- * `catalog.request_not_found`. Approval writes a grant to `catalog_org_grants`. Audits
369
- * `catalog.request_decided` (with orgId).
403
+ * Writes a decision (the request row FOR UPDATE): org side (`orgId`: the org admin re-checked,
404
+ * `enable` only) or deployment side (the super admin re-checked, `access` / `import`). An
405
+ * approval of an `enable` request may find it approved already by the install it triggered.
370
406
  */
371
- async decideDeployment(actor, requestId, decision, opts = {}) {
372
- if (!UUID_RE.test(requestId))
373
- throw requestNotFound();
374
- await this.writeDecideDeployment(actor, requestId, decision, opts);
375
- return this.view(requestId);
376
- }
377
- async writeDecideDeployment(actor, requestId, decision, opts) {
407
+ async writeDecision(requestId, actor, decision, opts, side) {
378
408
  const t = this.db;
379
- await this.adminLock.lockAndAuthorize(actor);
380
- const row = await t
409
+ if ("orgId" in side)
410
+ await this.orgLock.lockAndAuthorize(side.orgId, actor, "catalog.decide");
411
+ else
412
+ await this.adminLock.lockAndAuthorize(actor);
413
+ let q = t
381
414
  .selectFrom("catalog_requests")
382
- .select(["id", "org_id", "item_id", "stage", "status"])
383
- .where("id", "=", requestId)
384
- .forUpdate()
385
- .executeTakeFirst();
386
- if (row?.stage !== "deployment")
415
+ .select(["id", "org_id", "item_id", "kind", "status", "decided_by"])
416
+ .where("id", "=", requestId);
417
+ q =
418
+ "orgId" in side
419
+ ? q.where("org_id", "=", side.orgId).where("kind", "in", [...ORG_KINDS])
420
+ : q.where("kind", "in", [...DEPLOYMENT_KINDS]);
421
+ const row = await q.forUpdate().executeTakeFirst();
422
+ if (!row)
387
423
  throw requestNotFound();
388
424
  if (row.status !== "pending") {
389
- throw new ApiError("catalog.request_decided", "This request has already been decided");
425
+ // The switch-on of this approval already resolved it (the install approves pending requests)
426
+ if (decision.approve && row.kind === "enable" && row.status === "approved")
427
+ return;
428
+ throw alreadyDecided();
390
429
  }
391
- if (decision === "approve") {
392
- const item = await lockItem(t, row.item_id);
393
- if (!item || item.deleted_at !== null || item.policy === "disabled")
430
+ if (decision.approve && row.kind === "access" && row.item_id !== null) {
431
+ const item = await t
432
+ .selectFrom("catalog_items")
433
+ .select(["deleted_at", "disabled"])
434
+ .where("id", "=", row.item_id)
435
+ .executeTakeFirst();
436
+ if (!item || item.deleted_at !== null || item.disabled)
394
437
  throw itemDisabled();
395
438
  const org = await t
396
439
  .selectFrom("orgs")
@@ -399,16 +442,19 @@ let CatalogRequestsService = class CatalogRequestsService {
399
442
  .executeTakeFirst();
400
443
  if (!org || org.deleted_at !== null)
401
444
  throw requestNotFound();
402
- await t
403
- .insertInto("catalog_org_grants")
404
- .values({ item_id: row.item_id, org_id: row.org_id, granted_by: actor })
405
- .onConflict((oc) => oc.columns(["item_id", "org_id"]).doNothing())
406
- .execute();
445
+ await this.scope.addOrg(actor, row.item_id, row.org_id, { ...opts, requestId });
446
+ }
447
+ // An `import` request whose entry is in the catalog already: the org joins that item's list
448
+ const grantItem = "grantItem" in side ? side.grantItem : undefined;
449
+ if (decision.approve && row.kind === "import" && grantItem !== undefined) {
450
+ await this.scope.addOrg(actor, grantItem, row.org_id, { ...opts, requestId });
407
451
  }
408
452
  await t
409
453
  .updateTable("catalog_requests")
410
454
  .set({
411
- status: decision === "approve" ? "approved" : "rejected",
455
+ status: decision.approve ? "approved" : "rejected",
456
+ reason: decision.approve ? null : (decision.reason ?? null),
457
+ ...(grantItem !== undefined && { item_id: grantItem }),
412
458
  decided_by: actor,
413
459
  decided_at: sql `now()`,
414
460
  })
@@ -420,36 +466,62 @@ let CatalogRequestsService = class CatalogRequestsService {
420
466
  orgId: row.org_id,
421
467
  action: "catalog.request_decided",
422
468
  target: requestId,
423
- detail: { itemId: row.item_id, decision, stage: "deployment" },
469
+ detail: {
470
+ itemId: row.item_id,
471
+ kind: row.kind,
472
+ decision: decision.approve ? "approve" : "reject",
473
+ ...(!decision.approve && decision.reason !== undefined && { reason: decision.reason }),
474
+ },
424
475
  });
425
476
  }
426
- /** 企业管理员的申请列表(stage deployment;`status` 缺省 pending),新的在前。 */
477
+ /**
478
+ * The requester dismisses a decided request from the inbox (`POST /orgs/:orgId/
479
+ * catalog-requests/:id/dismiss`). Not the requester's decided request in this org ->
480
+ * `catalog.request_not_found`.
481
+ */
482
+ async dismiss(orgId, accountId, requestId) {
483
+ if (!UUID_RE.test(requestId))
484
+ throw requestNotFound();
485
+ const r = await this.db
486
+ .updateTable("catalog_requests")
487
+ .set({ dismissed_at: sql `now()` })
488
+ .where("id", "=", requestId)
489
+ .where("org_id", "=", orgId)
490
+ .where("requested_by", "=", accountId)
491
+ .where("status", "in", ["approved", "rejected"])
492
+ .where("dismissed_at", "is", null)
493
+ .executeTakeFirst();
494
+ if (r.numUpdatedRows === 0n)
495
+ throw requestNotFound();
496
+ }
497
+ /** 超级管理员的申请列表(`access` / `import`;`status` 缺省 pending),新的在前。 */
427
498
  async listDeployment(q = {}) {
428
499
  const rows = await this.baseQuery()
429
- .where("r.stage", "=", "deployment")
500
+ .where("r.kind", "in", [...DEPLOYMENT_KINDS])
430
501
  .where("r.status", "=", q.status ?? "pending")
431
502
  .where("o.deleted_at", "is", null)
432
503
  .orderBy("r.created_at", "desc")
433
504
  .orderBy("r.id")
434
505
  .limit(CATALOG_REQUESTS_LIST_MAX)
435
506
  .execute();
436
- return rows.map(toView);
507
+ return this.toViews(rows);
437
508
  }
438
- /** 待企业管理员处理的申请数(后台概览)。 */
509
+ /** 待超级管理员处理的申请数(后台概览)。 */
439
510
  async countPendingDeployment() {
440
511
  const r = await this.db
441
512
  .selectFrom("catalog_requests as r")
442
513
  .innerJoin("orgs as o", "o.id", "r.org_id")
443
514
  .select(sql `count(*)`.as("n"))
444
- .where("r.stage", "=", "deployment")
515
+ .where("r.kind", "in", [...DEPLOYMENT_KINDS])
445
516
  .where("r.status", "=", "pending")
446
517
  .where("o.deleted_at", "is", null)
447
518
  .executeTakeFirstOrThrow();
448
519
  return Number(r.n);
449
520
  }
450
521
  /**
451
- * 收件箱:当前用户是本组织管理员(实时读角色)时,返回待他处理的成员申请(stage org、pending),新的在前;
452
- * 否则为空。
522
+ * The inbox: when the account is an org admin of the org (the role read live), the members'
523
+ * pending `enable` requests and the pending `connector_setup` requests, newest first; otherwise
524
+ * none.
453
525
  */
454
526
  async listForOrgAdmin(orgId, accountId) {
455
527
  const m = await this.db
@@ -462,99 +534,210 @@ let CatalogRequestsService = class CatalogRequestsService {
462
534
  return [];
463
535
  const rows = await this.baseQuery()
464
536
  .where("r.org_id", "=", orgId)
465
- .where("r.stage", "=", "org")
537
+ .where("r.kind", "in", [...ORG_KINDS])
466
538
  .where("r.status", "=", "pending")
467
539
  .orderBy("r.created_at", "desc")
468
540
  .orderBy("r.id")
469
541
  .limit(CATALOG_REQUESTS_LIST_MAX)
470
542
  .execute();
471
- return rows.map(toView);
543
+ // A request on an item the org can no longer see (its scope hid it since) is left out, so
544
+ // nothing reveals the item's name to the org; a setup request of a deleted agent too
545
+ const ids = [...new Set(rows.flatMap((r) => (r.item_id !== null ? [r.item_id] : [])))];
546
+ const seen = await itemsSeenBy(this.db, orgId, ids);
547
+ return this.toViews(rows.filter((r) => r.kind === "connector_setup"
548
+ ? r.agent_id !== null && r.agent_deleted_at === null
549
+ : r.item_id !== null && seen.has(r.item_id)));
472
550
  }
473
- /** 本组织各条目最新的一条申请(组织目录列表用)。 */
474
- async latestByItem(orgId) {
475
- const rows = await this.db
476
- .selectFrom("catalog_requests")
477
- .select(["id", "item_id", "stage", "status", "created_at"])
478
- .where("org_id", "=", orgId)
479
- .orderBy("created_at", "asc")
551
+ /** The inbox: the account's decided requests in the org it has not dismissed, newest first. */
552
+ async listDecidedForRequester(orgId, accountId) {
553
+ const rows = await this.baseQuery()
554
+ .where("r.org_id", "=", orgId)
555
+ .where("r.requested_by", "=", accountId)
556
+ .where("r.status", "in", ["approved", "rejected"])
557
+ .where("r.dismissed_at", "is", null)
558
+ .orderBy("r.decided_at", "desc")
559
+ .orderBy("r.id")
560
+ .limit(CATALOG_REQUESTS_LIST_MAX)
480
561
  .execute();
481
- const out = new Map();
482
- for (const r of rows)
483
- out.set(r.item_id, { id: r.id, stage: r.stage, status: r.status });
484
- return out;
562
+ return this.toViews(rows);
563
+ }
564
+ /**
565
+ * The account's own requests in the org, pending and decided (dismissed ones too), newest first;
566
+ * cancelled ones are left out (the Platform tool's `requests.list-mine`).
567
+ */
568
+ async listForRequester(orgId, accountId) {
569
+ const rows = await this.baseQuery()
570
+ .where("r.org_id", "=", orgId)
571
+ .where("r.requested_by", "=", accountId)
572
+ .where("r.status", "in", ["pending", "approved", "rejected"])
573
+ .orderBy("r.created_at", "desc")
574
+ .orderBy("r.id")
575
+ .limit(CATALOG_REQUESTS_LIST_MAX)
576
+ .execute();
577
+ return this.toViews(rows);
485
578
  }
486
579
  async view(id) {
487
580
  const row = await this.baseQuery().where("r.id", "=", id).executeTakeFirst();
488
581
  if (!row)
489
582
  throw requestNotFound();
490
- return toView(row);
583
+ return (await this.toViews([row]))[0];
584
+ }
585
+ /** The views of `rows`, with the display names of the connector templates setup requests name. */
586
+ async toViews(rows) {
587
+ const ids = new Set();
588
+ for (const r of rows) {
589
+ if (r.kind !== "connector_setup")
590
+ continue;
591
+ const def = r.agent_definition;
592
+ for (const c of def?.pendingConnectors ?? []) {
593
+ if ("template" in c.source && UUID_RE.test(c.source.template))
594
+ ids.add(c.source.template);
595
+ }
596
+ }
597
+ const names = new Map();
598
+ if (ids.size > 0) {
599
+ const found = await this.db
600
+ .selectFrom("platform_connector_templates")
601
+ .select(["id", "file"])
602
+ .where("id", "in", [...ids])
603
+ .execute();
604
+ for (const t of found) {
605
+ const dn = t.file?.displayName;
606
+ names.set(t.id, dn ?? null);
607
+ }
608
+ }
609
+ return rows.map((r) => toView(r, names));
491
610
  }
492
611
  baseQuery() {
493
- return this.db
612
+ return (this.db
494
613
  .selectFrom("catalog_requests as r")
495
- .innerJoin("catalog_items as i", "i.id", "r.item_id")
614
+ .leftJoin("catalog_items as i", "i.id", "r.item_id")
496
615
  .innerJoin("orgs as o", "o.id", "r.org_id")
497
616
  .leftJoin("accounts as a", "a.id", "r.requested_by")
617
+ // a connector_setup request's agent and its current version (name, pending connectors)
618
+ .leftJoin("agents as ag", "ag.id", "r.agent_id")
619
+ .leftJoin("agent_versions as av", (j) => j.onRef("av.agent_id", "=", "ag.id").onRef("av.version", "=", "ag.current_version"))
498
620
  .select([
621
+ "r.agent_id",
622
+ "r.pending_keys",
623
+ "ag.deleted_at as agent_deleted_at",
624
+ "av.definition as agent_definition",
499
625
  "r.id",
500
626
  "r.org_id",
501
627
  "o.name as org_name",
628
+ "r.kind",
502
629
  "r.item_id",
503
630
  "i.name",
504
631
  "i.display_name",
505
- "r.version",
506
- "r.stage",
632
+ "r.marketplace_id",
633
+ "r.entry_name",
634
+ "r.entry_version",
507
635
  "r.status",
508
636
  "r.note",
637
+ "r.reason",
509
638
  "r.requested_by",
510
639
  "a.display_name as requested_by_name",
511
640
  "r.decided_by",
512
641
  "r.decided_at",
513
- "r.org_decided_by",
514
- "r.org_decided_at",
642
+ "r.staging_id",
515
643
  "r.created_at",
516
- ]);
644
+ ]));
517
645
  }
518
646
  };
519
647
  __decorate([
520
648
  Transactional()
521
- ], CatalogRequestsService.prototype, "writeRequest", null);
649
+ ], CatalogRequestsService.prototype, "authorize", null);
650
+ __decorate([
651
+ Transactional()
652
+ ], CatalogRequestsService.prototype, "writeItemRequest", null);
653
+ __decorate([
654
+ Transactional()
655
+ ], CatalogRequestsService.prototype, "writeImportRequest", null);
522
656
  __decorate([
523
- Transactional({ propagation: "mandatory" })
524
- ], CatalogRequestsService.prototype, "requestDeployment", null);
657
+ Transactional()
658
+ ], CatalogRequestsService.prototype, "pendingOrgRequest", null);
659
+ __decorate([
660
+ WithLock({ key: "catalog-request-#{1}", ttl: 60_000, waitTimeout: 180_000 })
661
+ ], CatalogRequestsService.prototype, "approveImport", null);
525
662
  __decorate([
526
- Transactional({ propagation: "mandatory" })
527
- ], CatalogRequestsService.prototype, "resolveByInstall", null);
663
+ Transactional()
664
+ ], CatalogRequestsService.prototype, "pendingDeploymentRequest", null);
528
665
  __decorate([
529
666
  Transactional()
530
- ], CatalogRequestsService.prototype, "writeDecideOrg", null);
667
+ ], CatalogRequestsService.prototype, "linkStaging", null);
531
668
  __decorate([
532
669
  Transactional()
533
- ], CatalogRequestsService.prototype, "writeDecideDeployment", null);
670
+ ], CatalogRequestsService.prototype, "writeDecision", null);
534
671
  CatalogRequestsService = __decorate([
535
672
  Injectable(),
536
673
  __param(0, Inject(KernelDb)),
537
674
  __param(1, Inject(OrgLock)),
538
- __param(2, Inject(EnterpriseAdminLock)),
539
- __param(3, Inject(TransactionHost))
675
+ __param(2, Inject(SuperAdminLock)),
676
+ __param(3, Inject(OrgCatalogService)),
677
+ __param(4, Inject(CatalogScopeService)),
678
+ __param(5, Inject(CatalogService)),
679
+ __param(6, Inject(KernelConfigService)),
680
+ __param(7, Inject(PluginImport)),
681
+ __param(8, Inject(TransactionHost)),
682
+ __param(9, Inject(LockService))
540
683
  ], CatalogRequestsService);
541
684
  export { CatalogRequestsService };
542
- function toView(r) {
685
+ /** The view fields of a `connector_setup` request (ruling P4-T6-5); null for other kinds. */
686
+ function setupFields(r, templateNames) {
687
+ if (r.kind !== "connector_setup" || r.agent_id === null)
688
+ return { agent: null, connectors: null };
689
+ const def = (r.agent_definition ?? null);
690
+ const pending = new Map((def?.pendingConnectors ?? []).map((c) => [c.key, c]));
691
+ const connectors = [];
692
+ for (const key of r.pending_keys ?? []) {
693
+ const c = pending.get(key);
694
+ if (c === undefined)
695
+ continue;
696
+ const src = c.source;
697
+ connectors.push({
698
+ key,
699
+ label: c.label,
700
+ kind: "template" in src ? "template" : "needs",
701
+ source: "template" in src
702
+ ? { template: { id: src.template, displayName: templateNames.get(src.template) ?? null } }
703
+ : {
704
+ needs: {
705
+ protocol: src.needs.protocol,
706
+ endpoint: src.needs.endpoint,
707
+ tools: [...src.needs.tools],
708
+ },
709
+ },
710
+ tools: c.tools !== undefined && c.tools.length > 0 ? [...c.tools] : null,
711
+ // jsonb keeps no key order: sorted
712
+ policies: Object.keys(c.policies ?? {}).sort(),
713
+ });
714
+ }
715
+ return {
716
+ agent: { id: r.agent_id, name: def?.name ?? "", deleted: r.agent_deleted_at !== null },
717
+ connectors,
718
+ };
719
+ }
720
+ function toView(r, templateNames) {
543
721
  return {
544
722
  id: r.id,
545
723
  orgId: r.org_id,
546
724
  orgName: r.org_name,
547
- item: { id: r.item_id, name: r.name, displayName: r.display_name },
548
- version: r.version,
549
- stage: r.stage,
725
+ kind: r.kind,
726
+ item: r.item_id !== null && r.name !== null
727
+ ? { id: r.item_id, name: r.name, displayName: r.display_name }
728
+ : null,
729
+ entry: r.entry_name !== null
730
+ ? { marketplaceId: r.marketplace_id, name: r.entry_name, version: r.entry_version }
731
+ : null,
732
+ ...setupFields(r, templateNames),
550
733
  status: r.status,
551
734
  note: r.note,
735
+ reason: r.reason,
552
736
  requestedBy: r.requested_by,
553
737
  requestedByName: r.requested_by_name,
554
738
  decidedBy: r.decided_by,
555
739
  decidedAt: r.decided_at?.toISOString() ?? null,
556
- orgDecidedBy: r.org_decided_by,
557
- orgDecidedAt: r.org_decided_at?.toISOString() ?? null,
740
+ stagingId: r.status === "pending" ? r.staging_id : null,
558
741
  createdAt: r.created_at.toISOString(),
559
742
  };
560
743
  }