@capybara-hq/kernel 0.0.0-stage → 0.1.0-rc.1

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 (637) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +2 -0
  3. package/README.md +20 -2
  4. package/bootstrap.json +26 -0
  5. package/dist/admin/admin.controller.d.ts +139 -0
  6. package/dist/admin/admin.controller.js +238 -0
  7. package/dist/admin/extensions.controller.d.ts +100 -0
  8. package/dist/admin/extensions.controller.js +226 -0
  9. package/dist/admin/setup.controller.d.ts +36 -0
  10. package/dist/admin/setup.controller.js +106 -0
  11. package/dist/admin/setup.service.d.ts +47 -0
  12. package/dist/admin/setup.service.js +90 -0
  13. package/dist/agents/agents.controller.d.ts +205 -0
  14. package/dist/agents/agents.controller.js +144 -0
  15. package/dist/agents/agents.service.d.ts +177 -0
  16. package/dist/agents/agents.service.js +677 -0
  17. package/dist/agents/definition.d.ts +198 -0
  18. package/dist/agents/definition.js +152 -0
  19. package/dist/agents/models.controller.d.ts +13 -0
  20. package/dist/agents/models.controller.js +31 -0
  21. package/dist/agents/templates.controller.d.ts +15 -0
  22. package/dist/agents/templates.controller.js +37 -0
  23. package/dist/agents/templates.d.ts +83 -0
  24. package/dist/agents/templates.js +173 -0
  25. package/dist/catalog/admin-catalog.controller.d.ts +143 -0
  26. package/dist/catalog/admin-catalog.controller.js +245 -0
  27. package/dist/catalog/catalog.service.d.ts +430 -0
  28. package/dist/catalog/catalog.service.js +882 -0
  29. package/dist/catalog/claude/agents.d.ts +27 -0
  30. package/dist/catalog/claude/agents.js +270 -0
  31. package/dist/catalog/claude/commands.d.ts +50 -0
  32. package/dist/catalog/claude/commands.js +179 -0
  33. package/dist/catalog/claude/manifest.d.ts +69 -0
  34. package/dist/catalog/claude/manifest.js +134 -0
  35. package/dist/catalog/claude/marketplace.d.ts +35 -0
  36. package/dist/catalog/claude/marketplace.js +194 -0
  37. package/dist/catalog/claude/mcp.d.ts +33 -0
  38. package/dist/catalog/claude/mcp.js +226 -0
  39. package/dist/catalog/claude/report.d.ts +86 -0
  40. package/dist/catalog/claude/report.js +121 -0
  41. package/dist/catalog/claude/translate.d.ts +56 -0
  42. package/dist/catalog/claude/translate.js +857 -0
  43. package/dist/catalog/cli.d.ts +46 -0
  44. package/dist/catalog/cli.js +211 -0
  45. package/dist/catalog/git-source.d.ts +127 -0
  46. package/dist/catalog/git-source.js +520 -0
  47. package/dist/catalog/marketplace-fetch.d.ts +99 -0
  48. package/dist/catalog/marketplace-fetch.js +203 -0
  49. package/dist/catalog/marketplaces.controller.d.ts +97 -0
  50. package/dist/catalog/marketplaces.controller.js +197 -0
  51. package/dist/catalog/marketplaces.service.d.ts +340 -0
  52. package/dist/catalog/marketplaces.service.js +1217 -0
  53. package/dist/catalog/org-catalog.controller.d.ts +128 -0
  54. package/dist/catalog/org-catalog.controller.js +277 -0
  55. package/dist/catalog/org-catalog.service.d.ts +246 -0
  56. package/dist/catalog/org-catalog.service.js +625 -0
  57. package/dist/catalog/plugin-import.d.ts +436 -0
  58. package/dist/catalog/plugin-import.js +1069 -0
  59. package/dist/catalog/plugin-install.d.ts +447 -0
  60. package/dist/catalog/plugin-install.js +1333 -0
  61. package/dist/catalog/plugin-package.d.ts +143 -0
  62. package/dist/catalog/plugin-package.js +382 -0
  63. package/dist/catalog/plugin-upgrade.d.ts +222 -0
  64. package/dist/catalog/plugin-upgrade.js +1219 -0
  65. package/dist/catalog/requests.service.d.ts +162 -0
  66. package/dist/catalog/requests.service.js +504 -0
  67. package/dist/catalog/schema-path.d.ts +7 -0
  68. package/dist/catalog/schema-path.js +63 -0
  69. package/dist/catalog/upgrade-targets.d.ts +59 -0
  70. package/dist/catalog/upgrade-targets.js +90 -0
  71. package/dist/catalog/versions.d.ts +31 -0
  72. package/dist/catalog/versions.js +44 -0
  73. package/dist/channels/actions.d.ts +37 -0
  74. package/dist/channels/actions.js +121 -0
  75. package/dist/channels/cards.d.ts +44 -0
  76. package/dist/channels/cards.js +156 -0
  77. package/dist/channels/connections.controller.d.ts +59 -0
  78. package/dist/channels/connections.controller.js +115 -0
  79. package/dist/channels/connections.service.d.ts +187 -0
  80. package/dist/channels/connections.service.js +534 -0
  81. package/dist/channels/features.d.ts +12 -0
  82. package/dist/channels/features.js +22 -0
  83. package/dist/channels/inbound.d.ts +120 -0
  84. package/dist/channels/inbound.js +332 -0
  85. package/dist/channels/outbound.d.ts +140 -0
  86. package/dist/channels/outbound.js +1126 -0
  87. package/dist/channels/phrases.d.ts +100 -0
  88. package/dist/channels/phrases.js +81 -0
  89. package/dist/channels/supervisor.d.ts +182 -0
  90. package/dist/channels/supervisor.js +625 -0
  91. package/dist/channels/threads.d.ts +29 -0
  92. package/dist/channels/threads.js +104 -0
  93. package/dist/channels/webhook-url.d.ts +16 -0
  94. package/dist/channels/webhook-url.js +34 -0
  95. package/dist/channels/webhook.controller.d.ts +19 -0
  96. package/dist/channels/webhook.controller.js +72 -0
  97. package/dist/channels/webhook.d.ts +73 -0
  98. package/dist/channels/webhook.js +274 -0
  99. package/dist/config/docs.d.ts +9 -0
  100. package/dist/config/docs.js +85 -0
  101. package/dist/config/env.d.ts +6 -0
  102. package/dist/config/env.js +73 -0
  103. package/dist/config/fields.d.ts +42 -0
  104. package/dist/config/fields.js +214 -0
  105. package/dist/config/file-source.d.ts +3 -0
  106. package/dist/config/file-source.js +31 -0
  107. package/dist/config/load.d.ts +20 -0
  108. package/dist/config/load.js +98 -0
  109. package/dist/config/nacos-source.d.ts +31 -0
  110. package/dist/config/nacos-source.js +229 -0
  111. package/dist/config/schema.d.ts +237 -0
  112. package/dist/config/schema.js +1192 -0
  113. package/dist/config/sources.d.ts +18 -0
  114. package/dist/config/sources.js +59 -0
  115. package/dist/config/types.d.ts +9 -0
  116. package/dist/config/types.js +7 -0
  117. package/dist/conversations/artifacts.d.ts +52 -0
  118. package/dist/conversations/artifacts.js +137 -0
  119. package/dist/conversations/attachments.controller.d.ts +28 -0
  120. package/dist/conversations/attachments.controller.js +96 -0
  121. package/dist/conversations/attachments.service.d.ts +180 -0
  122. package/dist/conversations/attachments.service.js +578 -0
  123. package/dist/conversations/conversations.controller.d.ts +288 -0
  124. package/dist/conversations/conversations.controller.js +607 -0
  125. package/dist/conversations/conversations.service.d.ts +321 -0
  126. package/dist/conversations/conversations.service.js +754 -0
  127. package/dist/conversations/event-log.d.ts +122 -0
  128. package/dist/conversations/event-log.js +259 -0
  129. package/dist/conversations/events.d.ts +856 -0
  130. package/dist/conversations/events.js +639 -0
  131. package/dist/conversations/files.d.ts +92 -0
  132. package/dist/conversations/files.js +213 -0
  133. package/dist/conversations/outputs-read.d.ts +34 -0
  134. package/dist/conversations/outputs-read.js +37 -0
  135. package/dist/conversations/queue.d.ts +169 -0
  136. package/dist/conversations/queue.js +527 -0
  137. package/dist/conversations/sandbox-status.d.ts +21 -0
  138. package/dist/conversations/sandbox-status.js +24 -0
  139. package/dist/conversations/selection.d.ts +46 -0
  140. package/dist/conversations/selection.js +75 -0
  141. package/dist/conversations/titles.d.ts +93 -0
  142. package/dist/conversations/titles.js +423 -0
  143. package/dist/ctx/bus.d.ts +16 -0
  144. package/dist/ctx/bus.js +101 -0
  145. package/dist/ctx/create-ctx.d.ts +109 -0
  146. package/dist/ctx/create-ctx.js +592 -0
  147. package/dist/ctx/kv.d.ts +4 -0
  148. package/dist/ctx/kv.js +31 -0
  149. package/dist/ctx/lock.d.ts +4 -0
  150. package/dist/ctx/lock.js +39 -0
  151. package/dist/ctx/namespace.d.ts +6 -0
  152. package/dist/ctx/namespace.js +12 -0
  153. package/dist/ctx/queue.d.ts +25 -0
  154. package/dist/ctx/queue.js +151 -0
  155. package/dist/ctx/secrets.d.ts +45 -0
  156. package/dist/ctx/secrets.js +175 -0
  157. package/dist/db/kernel-schema.d.ts +1122 -0
  158. package/dist/db/kernel-schema.js +5 -0
  159. package/dist/db/migrator.d.ts +28 -0
  160. package/dist/db/migrator.js +140 -0
  161. package/dist/db/pool.d.ts +21 -0
  162. package/dist/db/pool.js +28 -0
  163. package/dist/db/sql-statements.d.ts +34 -0
  164. package/dist/db/sql-statements.js +168 -0
  165. package/dist/errors.d.ts +211 -0
  166. package/dist/errors.js +213 -0
  167. package/dist/evals/budget.d.ts +61 -0
  168. package/dist/evals/budget.js +181 -0
  169. package/dist/evals/diff.d.ts +55 -0
  170. package/dist/evals/diff.js +133 -0
  171. package/dist/evals/judge.d.ts +53 -0
  172. package/dist/evals/judge.js +149 -0
  173. package/dist/evals/plan.d.ts +47 -0
  174. package/dist/evals/plan.js +77 -0
  175. package/dist/evals/reconstruct.d.ts +137 -0
  176. package/dist/evals/reconstruct.js +322 -0
  177. package/dist/evals/recorded-tools.d.ts +54 -0
  178. package/dist/evals/recorded-tools.js +167 -0
  179. package/dist/evals/run-replay.d.ts +86 -0
  180. package/dist/evals/run-replay.js +502 -0
  181. package/dist/evals/runs.controller.d.ts +100 -0
  182. package/dist/evals/runs.controller.js +199 -0
  183. package/dist/evals/runs.service.d.ts +275 -0
  184. package/dist/evals/runs.service.js +836 -0
  185. package/dist/evals/sets.controller.d.ts +61 -0
  186. package/dist/evals/sets.controller.js +183 -0
  187. package/dist/evals/sets.service.d.ts +128 -0
  188. package/dist/evals/sets.service.js +558 -0
  189. package/dist/evals/snapshot.d.ts +76 -0
  190. package/dist/evals/snapshot.js +207 -0
  191. package/dist/evals/step-replay.d.ts +113 -0
  192. package/dist/evals/step-replay.js +181 -0
  193. package/dist/evals/trajectory.controller.d.ts +41 -0
  194. package/dist/evals/trajectory.controller.js +88 -0
  195. package/dist/evals/trajectory.d.ts +144 -0
  196. package/dist/evals/trajectory.js +338 -0
  197. package/dist/evals/trajectory.service.d.ts +108 -0
  198. package/dist/evals/trajectory.service.js +323 -0
  199. package/dist/evals/worker.d.ts +101 -0
  200. package/dist/evals/worker.js +790 -0
  201. package/dist/extensions/admin-ops.d.ts +105 -0
  202. package/dist/extensions/admin-ops.js +353 -0
  203. package/dist/extensions/admin-view.d.ts +79 -0
  204. package/dist/extensions/admin-view.js +327 -0
  205. package/dist/extensions/approvals.d.ts +119 -0
  206. package/dist/extensions/approvals.js +205 -0
  207. package/dist/extensions/blobs.d.ts +45 -0
  208. package/dist/extensions/blobs.js +160 -0
  209. package/dist/extensions/bootstrap.d.ts +176 -0
  210. package/dist/extensions/bootstrap.js +535 -0
  211. package/dist/extensions/cli.d.ts +61 -0
  212. package/dist/extensions/cli.js +165 -0
  213. package/dist/extensions/config-json-schema.d.ts +9 -0
  214. package/dist/extensions/config-json-schema.js +73 -0
  215. package/dist/extensions/deployment-config.d.ts +138 -0
  216. package/dist/extensions/deployment-config.js +394 -0
  217. package/dist/extensions/enabled.d.ts +31 -0
  218. package/dist/extensions/enabled.js +55 -0
  219. package/dist/extensions/hooks.d.ts +161 -0
  220. package/dist/extensions/hooks.js +425 -0
  221. package/dist/extensions/host.d.ts +577 -0
  222. package/dist/extensions/host.js +2071 -0
  223. package/dist/extensions/inflight.d.ts +69 -0
  224. package/dist/extensions/inflight.js +277 -0
  225. package/dist/extensions/installs.d.ts +166 -0
  226. package/dist/extensions/installs.js +253 -0
  227. package/dist/extensions/instance.d.ts +167 -0
  228. package/dist/extensions/instance.js +329 -0
  229. package/dist/extensions/ledger.d.ts +30 -0
  230. package/dist/extensions/ledger.js +50 -0
  231. package/dist/extensions/lifecycle.d.ts +80 -0
  232. package/dist/extensions/lifecycle.js +152 -0
  233. package/dist/extensions/migrate-lock.d.ts +51 -0
  234. package/dist/extensions/migrate-lock.js +100 -0
  235. package/dist/extensions/org-config.controller.d.ts +24 -0
  236. package/dist/extensions/org-config.controller.js +59 -0
  237. package/dist/extensions/org-config.d.ts +169 -0
  238. package/dist/extensions/org-config.js +520 -0
  239. package/dist/extensions/package.d.ts +115 -0
  240. package/dist/extensions/package.js +246 -0
  241. package/dist/extensions/permission-set.d.ts +117 -0
  242. package/dist/extensions/permission-set.js +184 -0
  243. package/dist/extensions/permission-view.d.ts +194 -0
  244. package/dist/extensions/permission-view.js +284 -0
  245. package/dist/extensions/registry.d.ts +24 -0
  246. package/dist/extensions/registry.js +56 -0
  247. package/dist/extensions/resolve.d.ts +12 -0
  248. package/dist/extensions/resolve.js +71 -0
  249. package/dist/extensions/sources.d.ts +69 -0
  250. package/dist/extensions/sources.js +120 -0
  251. package/dist/extensions/sync.d.ts +40 -0
  252. package/dist/extensions/sync.js +242 -0
  253. package/dist/files/previewers.controller.d.ts +46 -0
  254. package/dist/files/previewers.controller.js +105 -0
  255. package/dist/files/previewers.d.ts +100 -0
  256. package/dist/files/previewers.js +250 -0
  257. package/dist/http/api.module.d.ts +114 -0
  258. package/dist/http/api.module.js +448 -0
  259. package/dist/http/app.d.ts +77 -0
  260. package/dist/http/app.js +220 -0
  261. package/dist/http/error.filter.d.ts +21 -0
  262. package/dist/http/error.filter.js +85 -0
  263. package/dist/http/gateway.module.d.ts +15 -0
  264. package/dist/http/gateway.module.js +13 -0
  265. package/dist/http/health.controller.d.ts +26 -0
  266. package/dist/http/health.controller.js +79 -0
  267. package/dist/http/nest-logger.d.ts +20 -0
  268. package/dist/http/nest-logger.js +28 -0
  269. package/dist/http/plugin-dispatch.d.ts +68 -0
  270. package/dist/http/plugin-dispatch.js +200 -0
  271. package/dist/http/tokens.d.ts +131 -0
  272. package/dist/http/tokens.js +131 -0
  273. package/dist/http/zod.pipe.d.ts +8 -0
  274. package/dist/http/zod.pipe.js +14 -0
  275. package/dist/identity/accounts.d.ts +93 -0
  276. package/dist/identity/accounts.js +367 -0
  277. package/dist/identity/api-tokens.d.ts +73 -0
  278. package/dist/identity/api-tokens.js +197 -0
  279. package/dist/identity/audit.d.ts +23 -0
  280. package/dist/identity/audit.js +41 -0
  281. package/dist/identity/auth.controller.d.ts +40 -0
  282. package/dist/identity/auth.controller.js +130 -0
  283. package/dist/identity/auth.guard.d.ts +41 -0
  284. package/dist/identity/auth.guard.js +162 -0
  285. package/dist/identity/binding.d.ts +47 -0
  286. package/dist/identity/binding.js +84 -0
  287. package/dist/identity/cookies.d.ts +16 -0
  288. package/dist/identity/cookies.js +32 -0
  289. package/dist/identity/credential-check.d.ts +17 -0
  290. package/dist/identity/credential-check.js +24 -0
  291. package/dist/identity/enterprise-admin.d.ts +14 -0
  292. package/dist/identity/enterprise-admin.js +27 -0
  293. package/dist/identity/external.d.ts +106 -0
  294. package/dist/identity/external.js +337 -0
  295. package/dist/identity/hash.d.ts +2 -0
  296. package/dist/identity/hash.js +3 -0
  297. package/dist/identity/login.d.ts +6 -0
  298. package/dist/identity/login.js +20 -0
  299. package/dist/identity/me.controller.d.ts +61 -0
  300. package/dist/identity/me.controller.js +159 -0
  301. package/dist/identity/passwords.d.ts +6 -0
  302. package/dist/identity/passwords.js +37 -0
  303. package/dist/identity/principal.d.ts +56 -0
  304. package/dist/identity/principal.js +38 -0
  305. package/dist/identity/rate-limit.d.ts +55 -0
  306. package/dist/identity/rate-limit.js +121 -0
  307. package/dist/identity/sessions.d.ts +84 -0
  308. package/dist/identity/sessions.js +306 -0
  309. package/dist/identity/settings.d.ts +121 -0
  310. package/dist/identity/settings.js +248 -0
  311. package/dist/identity/sso.controller.d.ts +59 -0
  312. package/dist/identity/sso.controller.js +192 -0
  313. package/dist/identity/sso.d.ts +83 -0
  314. package/dist/identity/sso.js +202 -0
  315. package/dist/inbox/inbox.service.d.ts +43 -0
  316. package/dist/inbox/inbox.service.js +57 -0
  317. package/dist/index.d.ts +69 -0
  318. package/dist/index.js +67 -0
  319. package/dist/kernel.d.ts +259 -0
  320. package/dist/kernel.js +1326 -0
  321. package/dist/log-config.d.ts +9 -0
  322. package/dist/log-config.js +27 -0
  323. package/dist/log-context.d.ts +32 -0
  324. package/dist/log-context.js +40 -0
  325. package/dist/log-loki.d.ts +34 -0
  326. package/dist/log-loki.js +145 -0
  327. package/dist/log.d.ts +79 -0
  328. package/dist/log.js +303 -0
  329. package/dist/models/prices.d.ts +53 -0
  330. package/dist/models/prices.js +121 -0
  331. package/dist/models/purposes.controller.d.ts +19 -0
  332. package/dist/models/purposes.controller.js +56 -0
  333. package/dist/models/purposes.d.ts +140 -0
  334. package/dist/models/purposes.js +267 -0
  335. package/dist/net/proxy.d.ts +44 -0
  336. package/dist/net/proxy.js +162 -0
  337. package/dist/net/public-address.d.ts +60 -0
  338. package/dist/net/public-address.js +272 -0
  339. package/dist/net/safe-fetch.d.ts +38 -0
  340. package/dist/net/safe-fetch.js +140 -0
  341. package/dist/orgs/directory-sync.controller.d.ts +14 -0
  342. package/dist/orgs/directory-sync.controller.js +40 -0
  343. package/dist/orgs/directory-sync.d.ts +166 -0
  344. package/dist/orgs/directory-sync.js +558 -0
  345. package/dist/orgs/invitations.controller.d.ts +58 -0
  346. package/dist/orgs/invitations.controller.js +137 -0
  347. package/dist/orgs/invitations.service.d.ts +80 -0
  348. package/dist/orgs/invitations.service.js +217 -0
  349. package/dist/orgs/members.service.d.ts +63 -0
  350. package/dist/orgs/members.service.js +234 -0
  351. package/dist/orgs/offboarding.d.ts +141 -0
  352. package/dist/orgs/offboarding.js +398 -0
  353. package/dist/orgs/org-lock.d.ts +32 -0
  354. package/dist/orgs/org-lock.js +46 -0
  355. package/dist/orgs/org.guard.d.ts +35 -0
  356. package/dist/orgs/org.guard.js +95 -0
  357. package/dist/orgs/orgs.controller.d.ts +78 -0
  358. package/dist/orgs/orgs.controller.js +192 -0
  359. package/dist/orgs/orgs.service.d.ts +61 -0
  360. package/dist/orgs/orgs.service.js +209 -0
  361. package/dist/orgs/roles.d.ts +13 -0
  362. package/dist/orgs/roles.js +58 -0
  363. package/dist/orgs/settings.controller.d.ts +20 -0
  364. package/dist/orgs/settings.controller.js +53 -0
  365. package/dist/orgs/settings.service.d.ts +120 -0
  366. package/dist/orgs/settings.service.js +178 -0
  367. package/dist/packages/npm.d.ts +50 -0
  368. package/dist/packages/npm.js +218 -0
  369. package/dist/packages/provenance.d.ts +47 -0
  370. package/dist/packages/provenance.js +147 -0
  371. package/dist/packages/tgz.d.ts +76 -0
  372. package/dist/packages/tgz.js +225 -0
  373. package/dist/runtime/abort.d.ts +32 -0
  374. package/dist/runtime/abort.js +71 -0
  375. package/dist/runtime/checkpointer.d.ts +32 -0
  376. package/dist/runtime/checkpointer.js +243 -0
  377. package/dist/runtime/context/build.d.ts +254 -0
  378. package/dist/runtime/context/build.js +693 -0
  379. package/dist/runtime/context/claude-tools.d.ts +11 -0
  380. package/dist/runtime/context/claude-tools.js +24 -0
  381. package/dist/runtime/context/compaction.d.ts +26 -0
  382. package/dist/runtime/context/compaction.js +195 -0
  383. package/dist/runtime/context/pairing.d.ts +11 -0
  384. package/dist/runtime/context/pairing.js +82 -0
  385. package/dist/runtime/context/reminders.d.ts +5 -0
  386. package/dist/runtime/context/reminders.js +11 -0
  387. package/dist/runtime/context/skills.d.ts +105 -0
  388. package/dist/runtime/context/skills.js +283 -0
  389. package/dist/runtime/context/tokens.d.ts +19 -0
  390. package/dist/runtime/context/tokens.js +104 -0
  391. package/dist/runtime/conversation-lock.d.ts +40 -0
  392. package/dist/runtime/conversation-lock.js +97 -0
  393. package/dist/runtime/hook-calls.d.ts +84 -0
  394. package/dist/runtime/hook-calls.js +136 -0
  395. package/dist/runtime/langgraph-loop.d.ts +52 -0
  396. package/dist/runtime/langgraph-loop.js +247 -0
  397. package/dist/runtime/loop.d.ts +93 -0
  398. package/dist/runtime/loop.js +7 -0
  399. package/dist/runtime/maintenance.d.ts +80 -0
  400. package/dist/runtime/maintenance.js +148 -0
  401. package/dist/runtime/media-cache.d.ts +21 -0
  402. package/dist/runtime/media-cache.js +51 -0
  403. package/dist/runtime/model-call.d.ts +176 -0
  404. package/dist/runtime/model-call.js +1049 -0
  405. package/dist/runtime/providers.d.ts +86 -0
  406. package/dist/runtime/providers.js +224 -0
  407. package/dist/runtime/quota.d.ts +29 -0
  408. package/dist/runtime/quota.js +70 -0
  409. package/dist/runtime/run-finish.d.ts +45 -0
  410. package/dist/runtime/run-finish.js +69 -0
  411. package/dist/runtime/run-queue.d.ts +121 -0
  412. package/dist/runtime/run-queue.js +493 -0
  413. package/dist/runtime/run-worker.d.ts +138 -0
  414. package/dist/runtime/run-worker.js +806 -0
  415. package/dist/runtime/stream.controller.d.ts +34 -0
  416. package/dist/runtime/stream.controller.js +122 -0
  417. package/dist/runtime/stream.d.ts +63 -0
  418. package/dist/runtime/stream.js +262 -0
  419. package/dist/runtime/subagents/child.d.ts +80 -0
  420. package/dist/runtime/subagents/child.js +225 -0
  421. package/dist/runtime/subagents/definition.d.ts +103 -0
  422. package/dist/runtime/subagents/definition.js +392 -0
  423. package/dist/runtime/subagents/dispatch.d.ts +69 -0
  424. package/dist/runtime/subagents/dispatch.js +502 -0
  425. package/dist/runtime/subagents/limits.d.ts +23 -0
  426. package/dist/runtime/subagents/limits.js +34 -0
  427. package/dist/runtime/subagents/org-agents.d.ts +50 -0
  428. package/dist/runtime/subagents/org-agents.js +70 -0
  429. package/dist/runtime/subagents/preamble.d.ts +7 -0
  430. package/dist/runtime/subagents/preamble.js +11 -0
  431. package/dist/runtime/subagents/progress.d.ts +26 -0
  432. package/dist/runtime/subagents/progress.js +36 -0
  433. package/dist/runtime/subagents/roster.d.ts +55 -0
  434. package/dist/runtime/subagents/roster.js +111 -0
  435. package/dist/runtime/subagents/skill-fork.d.ts +123 -0
  436. package/dist/runtime/subagents/skill-fork.js +259 -0
  437. package/dist/runtime/usage-report.d.ts +163 -0
  438. package/dist/runtime/usage-report.js +551 -0
  439. package/dist/runtime/waits.d.ts +233 -0
  440. package/dist/runtime/waits.js +883 -0
  441. package/dist/sandbox/leases.d.ts +169 -0
  442. package/dist/sandbox/leases.js +515 -0
  443. package/dist/sandbox/lifecycle.d.ts +21 -0
  444. package/dist/sandbox/lifecycle.js +68 -0
  445. package/dist/sandbox/sandbox.service.d.ts +249 -0
  446. package/dist/sandbox/sandbox.service.js +908 -0
  447. package/dist/skills/catalog.d.ts +149 -0
  448. package/dist/skills/catalog.js +405 -0
  449. package/dist/skills/changes.controller.d.ts +56 -0
  450. package/dist/skills/changes.controller.js +136 -0
  451. package/dist/skills/changes.service.d.ts +175 -0
  452. package/dist/skills/changes.service.js +805 -0
  453. package/dist/skills/invocable.controller.d.ts +23 -0
  454. package/dist/skills/invocable.controller.js +50 -0
  455. package/dist/skills/invocation-keys.d.ts +23 -0
  456. package/dist/skills/invocation-keys.js +44 -0
  457. package/dist/skills/invoke.d.ts +135 -0
  458. package/dist/skills/invoke.js +286 -0
  459. package/dist/skills/package.d.ts +87 -0
  460. package/dist/skills/package.js +227 -0
  461. package/dist/skills/skills.controller.d.ts +40 -0
  462. package/dist/skills/skills.controller.js +110 -0
  463. package/dist/skills/skills.service.d.ts +192 -0
  464. package/dist/skills/skills.service.js +567 -0
  465. package/dist/storage/prefix.d.ts +36 -0
  466. package/dist/storage/prefix.js +104 -0
  467. package/dist/storage/purge.d.ts +27 -0
  468. package/dist/storage/purge.js +75 -0
  469. package/dist/storage/storage.service.d.ts +44 -0
  470. package/dist/storage/storage.service.js +145 -0
  471. package/dist/text.d.ts +13 -0
  472. package/dist/text.js +13 -0
  473. package/dist/tools/approvals.controller.d.ts +53 -0
  474. package/dist/tools/approvals.controller.js +128 -0
  475. package/dist/tools/approvals.service.d.ts +172 -0
  476. package/dist/tools/approvals.service.js +568 -0
  477. package/dist/tools/breaker.d.ts +28 -0
  478. package/dist/tools/breaker.js +72 -0
  479. package/dist/tools/builtins/agent.d.ts +81 -0
  480. package/dist/tools/builtins/agent.js +223 -0
  481. package/dist/tools/builtins/ask-user.d.ts +28 -0
  482. package/dist/tools/builtins/ask-user.js +139 -0
  483. package/dist/tools/builtins/read-tool-output.d.ts +18 -0
  484. package/dist/tools/builtins/read-tool-output.js +108 -0
  485. package/dist/tools/builtins/sandbox/bash.d.ts +16 -0
  486. package/dist/tools/builtins/sandbox/bash.js +137 -0
  487. package/dist/tools/builtins/sandbox/common.d.ts +116 -0
  488. package/dist/tools/builtins/sandbox/common.js +306 -0
  489. package/dist/tools/builtins/sandbox/deliver.d.ts +5 -0
  490. package/dist/tools/builtins/sandbox/deliver.js +180 -0
  491. package/dist/tools/builtins/sandbox/edit.d.ts +4 -0
  492. package/dist/tools/builtins/sandbox/edit.js +98 -0
  493. package/dist/tools/builtins/sandbox/glob-match.d.ts +25 -0
  494. package/dist/tools/builtins/sandbox/glob-match.js +240 -0
  495. package/dist/tools/builtins/sandbox/glob.d.ts +4 -0
  496. package/dist/tools/builtins/sandbox/glob.js +104 -0
  497. package/dist/tools/builtins/sandbox/grep.d.ts +9 -0
  498. package/dist/tools/builtins/sandbox/grep.js +133 -0
  499. package/dist/tools/builtins/sandbox/index.d.ts +12 -0
  500. package/dist/tools/builtins/sandbox/index.js +27 -0
  501. package/dist/tools/builtins/sandbox/names.d.ts +7 -0
  502. package/dist/tools/builtins/sandbox/names.js +20 -0
  503. package/dist/tools/builtins/sandbox/read.d.ts +8 -0
  504. package/dist/tools/builtins/sandbox/read.js +121 -0
  505. package/dist/tools/builtins/sandbox/write.d.ts +4 -0
  506. package/dist/tools/builtins/sandbox/write.js +88 -0
  507. package/dist/tools/builtins/skill-load.d.ts +53 -0
  508. package/dist/tools/builtins/skill-load.js +446 -0
  509. package/dist/tools/builtins/skill-write.d.ts +59 -0
  510. package/dist/tools/builtins/skill-write.js +244 -0
  511. package/dist/tools/builtins/tool-search.d.ts +31 -0
  512. package/dist/tools/builtins/tool-search.js +171 -0
  513. package/dist/tools/connector-content.controller.d.ts +34 -0
  514. package/dist/tools/connector-content.controller.js +78 -0
  515. package/dist/tools/connector-content.d.ts +104 -0
  516. package/dist/tools/connector-content.js +267 -0
  517. package/dist/tools/connectors.controller.d.ts +210 -0
  518. package/dist/tools/connectors.controller.js +234 -0
  519. package/dist/tools/connectors.service.d.ts +303 -0
  520. package/dist/tools/connectors.service.js +1102 -0
  521. package/dist/tools/credentials.d.ts +139 -0
  522. package/dist/tools/credentials.js +351 -0
  523. package/dist/tools/drift.d.ts +141 -0
  524. package/dist/tools/drift.js +539 -0
  525. package/dist/tools/elicitation.d.ts +81 -0
  526. package/dist/tools/elicitation.js +266 -0
  527. package/dist/tools/endpoint.d.ts +18 -0
  528. package/dist/tools/endpoint.js +115 -0
  529. package/dist/tools/info.d.ts +67 -0
  530. package/dist/tools/info.js +113 -0
  531. package/dist/tools/naming.d.ts +27 -0
  532. package/dist/tools/naming.js +47 -0
  533. package/dist/tools/oauth/discovery.d.ts +65 -0
  534. package/dist/tools/oauth/discovery.js +307 -0
  535. package/dist/tools/oauth/flow.d.ts +63 -0
  536. package/dist/tools/oauth/flow.js +237 -0
  537. package/dist/tools/oauth/oauth.controller.d.ts +31 -0
  538. package/dist/tools/oauth/oauth.controller.js +95 -0
  539. package/dist/tools/oauth/tokens.d.ts +111 -0
  540. package/dist/tools/oauth/tokens.js +258 -0
  541. package/dist/tools/outputs.d.ts +61 -0
  542. package/dist/tools/outputs.js +156 -0
  543. package/dist/tools/pipeline.d.ts +322 -0
  544. package/dist/tools/pipeline.js +1236 -0
  545. package/dist/tools/policy.d.ts +60 -0
  546. package/dist/tools/policy.js +236 -0
  547. package/dist/tools/questions.controller.d.ts +24 -0
  548. package/dist/tools/questions.controller.js +58 -0
  549. package/dist/tools/questions.service.d.ts +103 -0
  550. package/dist/tools/questions.service.js +295 -0
  551. package/dist/tools/redact.d.ts +20 -0
  552. package/dist/tools/redact.js +60 -0
  553. package/dist/tools/registry.d.ts +246 -0
  554. package/dist/tools/registry.js +481 -0
  555. package/dist/tools/resources.d.ts +16 -0
  556. package/dist/tools/resources.js +76 -0
  557. package/dist/tools/specs.d.ts +14 -0
  558. package/dist/tools/specs.js +31 -0
  559. package/dist/tools/validate.d.ts +20 -0
  560. package/dist/tools/validate.js +183 -0
  561. package/dist/tools/view.d.ts +43 -0
  562. package/dist/tools/view.js +225 -0
  563. package/dist/ui/embed-token.d.ts +31 -0
  564. package/dist/ui/embed-token.js +132 -0
  565. package/dist/ui/registry.d.ts +58 -0
  566. package/dist/ui/registry.js +90 -0
  567. package/dist/ui/ui-stream.d.ts +37 -0
  568. package/dist/ui/ui-stream.js +162 -0
  569. package/dist/ui/views.controller.d.ts +81 -0
  570. package/dist/ui/views.controller.js +261 -0
  571. package/dist/ui/views.d.ts +155 -0
  572. package/dist/ui/views.js +306 -0
  573. package/dist/version.d.ts +5 -0
  574. package/dist/version.js +6 -0
  575. package/package.json +69 -3
  576. package/src/migrations/0001_init.sql +8 -0
  577. package/src/migrations/0002_secrets.sql +8 -0
  578. package/src/migrations/0003_identity.sql +117 -0
  579. package/src/migrations/0004_plugin_org_config_nullable.sql +3 -0
  580. package/src/migrations/0005_agents.sql +27 -0
  581. package/src/migrations/0006_conversations.sql +37 -0
  582. package/src/migrations/0007_checkpoints.sql +26 -0
  583. package/src/migrations/0008_runs_trigger_seq.sql +3 -0
  584. package/src/migrations/0009_runs_active_unique.sql +4 -0
  585. package/src/migrations/0010_tools.sql +125 -0
  586. package/src/migrations/0011_approvals_spec.sql +10 -0
  587. package/src/migrations/0012_run_waits.sql +24 -0
  588. package/src/migrations/0013_app_tools_source.sql +4 -0
  589. package/src/migrations/0014_tool_specs.sql +8 -0
  590. package/src/migrations/0015_tool_drift.sql +20 -0
  591. package/src/migrations/0016_plugin_permissions.sql +11 -0
  592. package/src/migrations/0017_identity_sources.sql +6 -0
  593. package/src/migrations/0018_channels.sql +74 -0
  594. package/src/migrations/0019_identity_trust.sql +17 -0
  595. package/src/migrations/0020_channel_card_lookup.sql +10 -0
  596. package/src/migrations/0021_org_storage_purge.sql +9 -0
  597. package/src/migrations/0022_attachments.sql +29 -0
  598. package/src/migrations/0023_sandboxes.sql +37 -0
  599. package/src/migrations/0024_skills.sql +46 -0
  600. package/src/migrations/0025_skills_catalog_idx.sql +6 -0
  601. package/src/migrations/0026_skill_changes.sql +34 -0
  602. package/src/migrations/0027_model_prices.sql +18 -0
  603. package/src/migrations/0028_evals.sql +105 -0
  604. package/src/migrations/0029_model_purposes.sql +18 -0
  605. package/src/migrations/0030_plugin_installs.sql +73 -0
  606. package/src/migrations/0031_plugin_snapshot_source.sql +6 -0
  607. package/src/migrations/0032_plugin_deployment_configs.sql +10 -0
  608. package/src/migrations/0033_rename_apps_to_connectors.sql +25 -0
  609. package/src/migrations/0034_directory.sql +49 -0
  610. package/src/migrations/0035_catalogs.sql +40 -0
  611. package/src/migrations/0036_app_import_staging.sql +17 -0
  612. package/src/migrations/0037_directory_installs.sql +92 -0
  613. package/src/migrations/0038_channel_inbound_mode.sql +6 -0
  614. package/src/migrations/0039_channel_card_pending.sql +8 -0
  615. package/src/migrations/0040_usage_report_sweep.sql +10 -0
  616. package/src/migrations/0041_rename_plugins_to_extensions.sql +38 -0
  617. package/src/migrations/0042_rename_directory_to_catalog.sql +80 -0
  618. package/src/migrations/0043_rename_app_installs_to_plugin_installs.sql +20 -0
  619. package/src/migrations/0044_catalog_one_kind.sql +90 -0
  620. package/src/migrations/0045_plugin_dependencies.sql +9 -0
  621. package/src/migrations/0046_git_sources.sql +25 -0
  622. package/src/migrations/0047_marketplace_entry_heads.sql +7 -0
  623. package/src/migrations/0048_marketplace_entry_trees.sql +8 -0
  624. package/src/migrations/0049_plugin_upgrades.sql +37 -0
  625. package/src/migrations/0050_bootstrap.sql +53 -0
  626. package/src/migrations/0051_claude_compat.sql +26 -0
  627. package/src/migrations/0052_conversations_account_agent_idx.sql +5 -0
  628. package/src/migrations/0053_subagents.sql +73 -0
  629. package/src/migrations/0054_subagent_wait_expiry.sql +7 -0
  630. package/src/migrations/0055_subagent_parent_indexes.sql +10 -0
  631. package/src/migrations/0056_approval_reason.sql +3 -0
  632. package/src/migrations/0057_conversation_titles.sql +11 -0
  633. package/src/migrations/0058_conversation_selection.sql +4 -0
  634. package/src/migrations/0059_conversation_queue.sql +22 -0
  635. package/src/migrations/0060_file_previewers.sql +10 -0
  636. package/src/migrations/0061_queue_selection.sql +5 -0
  637. package/src/migrations/0062_queued_skill.sql +8 -0
@@ -0,0 +1,558 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { DIRECTORY_EXTENSION_POINT, } from "@capybara-hq/plugin-sdk";
3
+ import { ApiError } from "../errors.js";
4
+ import { enabledExtensionsByOrg } from "../extensions/enabled.js";
5
+ import { audit } from "../identity/audit.js";
6
+ import { ConversationLock } from "../runtime/conversation-lock.js";
7
+ import { lockOrgAndAuthorize, tryLockOrg } from "./org-lock.js";
8
+ /** 每小时扫描:维护队列任务名、job scheduler id(不含 `:`)与周期。 */
9
+ export const DIRECTORY_SCAN_JOB = "directory-scan";
10
+ export const DIRECTORY_SCAN_SCHEDULER_ID = "directory-scan-hourly";
11
+ export const DIRECTORY_SCAN_EVERY_MS = 3_600_000;
12
+ /** 一次 (组织, 插件) 同步的维护任务名。 */
13
+ export const DIRECTORY_SYNC_JOB = "directory-sync";
14
+ /** 同步锁的 Redis 键前缀(键为 `<前缀><orgId>:<plugin>`,带 TTL、持有期间续租)。 */
15
+ export const DIRECTORY_SYNC_LOCK_PREFIX = "capk:directory-sync:";
16
+ /** 脏标记的保留时长(秒):锁被占时记下,持有者跑完后取走并补一轮。 */
17
+ export const DIRECTORY_SYNC_DIRTY_TTL_SECONDS = 3_600;
18
+ /** 脏标记(Redis 键):同步进行中又有同步请求被锁挡掉。 */
19
+ export const directorySyncDirtyKey = (orgId, plugin) => `capk:directory-sync-dirty:${orgId}:${plugin}`;
20
+ /**
21
+ * Ruling A17 大批移除保护(非手动触发):计划移除数超过 `max(下限, 比例 × 现有通讯录成员数)`,
22
+ * 或列表里一个在职成员都没有而已有通讯录成员时,本轮当作不完整、不移除任何人。
23
+ */
24
+ export const DIRECTORY_REMOVAL_GUARD_MIN = 5;
25
+ export const DIRECTORY_REMOVAL_GUARD_RATIO = 0.2;
26
+ /** 单页 `listMembers` 的时限。 */
27
+ export const DIRECTORY_PAGE_TIMEOUT_MS = 60_000;
28
+ /** 一轮同步最多翻的页数:防止插件反复返回游标让任务无限长(超出按中途失败处理)。 */
29
+ export const DIRECTORY_MAX_PAGES = 10_000;
30
+ /** 完成的 job id 保留时长(秒):保留期内同一 id 的重复投递被 BullMQ 去重。 */
31
+ const KEEP_COMPLETED_SECONDS = {
32
+ schedule: 7_200,
33
+ changed: 120,
34
+ manual: 3_600,
35
+ };
36
+ const KEEP_FAILED = { age: 86_400 };
37
+ const pad = (n) => String(n).padStart(2, "0");
38
+ /** UTC 小时桶,如 `2026102014`(不含 `:`)。 */
39
+ export function hourBucket(d = new Date()) {
40
+ return `${d.getUTCFullYear()}${pad(d.getUTCMonth() + 1)}${pad(d.getUTCDate())}${pad(d.getUTCHours())}`;
41
+ }
42
+ /** UTC 分钟桶,如 `202610201405`。 */
43
+ export function minuteBucket(d = new Date()) {
44
+ return `${hourBucket(d)}${pad(d.getUTCMinutes())}`;
45
+ }
46
+ /**
47
+ * 同步任务的 job id(不含 `:`):扫描按小时桶(`directory-sync-<org>-<plugin>-<小时桶>`)、
48
+ * `directory_changed` 按分钟桶去重;手动触发每次唯一,不会被同一小时的扫描任务吞掉。
49
+ */
50
+ export function directorySyncJobId(orgId, plugin, trigger, now = new Date()) {
51
+ const base = `directory-sync-${orgId}-${plugin}`;
52
+ switch (trigger) {
53
+ case "schedule":
54
+ return `${base}-${hourBucket(now)}`;
55
+ case "changed":
56
+ return `${base}-changed-${minuteBucket(now)}`;
57
+ case "manual":
58
+ return `${base}-manual-${randomUUID()}`;
59
+ }
60
+ }
61
+ /** 组织已删除(同步途中):停止本轮。 */
62
+ class OrgGone extends Error {
63
+ }
64
+ /**
65
+ * 通讯录同步(`directory@1`):把企业通讯录同步为组织成员。框架无关。
66
+ *
67
+ * - 维护队列每小时 `directory-scan`:给每个「插件提供 `directory@1`、在该组织启用、组织级配置满足 schema」的
68
+ * (组织, 插件) 投递一次同步(job id 按小时桶去重,多副本重复扫描只跑一次);手动与 `directory_changed` 也投递同步。
69
+ * - 同一 (组织, 插件) 同时只跑一个同步(Redis 锁 `capk:directory-sync:<org>:<plugin>`,持有期间续租);
70
+ * 锁被占时本任务记下脏标记 `capk:directory-sync-dirty:<org>:<plugin>`(1 小时)后结束;持有者释放锁后 GETDEL
71
+ * 取走标记,有就投递一次 changed 同步(在跑的那一轮可能已经读过变化之前的页)。Ruling A32:移除阶段前 GET
72
+ * (不取走)脏标记,有就本轮按不完整处理、不移除任何人(审计 `partialReason = changed_during_sync`),移除留给补跑。
73
+ * After writing the flag, a blocked sync tries the lock once more: when the holder finished in
74
+ * between (and its GETDEL found no flag), this sync clears the flag and runs itself.
75
+ * - Ruling A17:非手动触发的一轮,计划移除数超过 `max(5, 20% × 现有通讯录成员数)`,或列表里没有在职成员而已有
76
+ * 通讯录成员时,当作不完整、不移除任何人,审计 `org.directory.removal_blocked`;手动触发不受此限。
77
+ * - 分页 `listMembers`:在职成员按 `<插件>:<租户>` + externalId 解析外部身份(不合并既有账号、不登录、不建会话),
78
+ * 不是成员就加入(角色 member,`memberships.source = "directory:<插件>"`),每人一个短事务;新身份行记
79
+ * `linked_via = directory`。被管理员手动移出(或本人离开)而记下通讯录排除的人不加回(Ruling A20),
80
+ * 直到有人手动重新加入。
81
+ * - **整轮分页成功走完、且没有成员处理失败**、并且移除前再次复核插件仍可同步(仍启用、配置仍有效;中途被停用或
82
+ * 配置变得无效则本轮按不完整处理)之后,才对「离职(active = false)或不再出现、且 source 为该通讯录」的
83
+ * 成员逐个走离职处理(每人一个事务:组织行锁 → 成员关系行锁 → `Offboarding.offboard`);中途失败只加人不删人。
84
+ * 手动 / 邀请加入的成员(source 为空)永远不被同步移除;账号本身不停用。最后一个 owner 跳过并计数。
85
+ * - Ruling A28:插件实现了 `Directory.configured` 且对该组织配置返回 false(通讯录未配置,组织只用插件的别的
86
+ * 能力)时,扫描、`directory_changed` 与执行时的复核都静默跳过(不投递、不审计、不记警告),手动触发 409
87
+ * `directory.not_configured`。
88
+ * - 审计 `org.directory.synced`(计数、是否不完整)。任务执行时再核对插件与配置:已停用的插件的陈旧任务什么都不做。
89
+ */
90
+ export class DirectorySync {
91
+ d;
92
+ lock;
93
+ constructor(d) {
94
+ this.d = d;
95
+ this.lock = new ConversationLock(d.redis, d.log, DIRECTORY_SYNC_LOCK_PREFIX);
96
+ const m = d.maintenance;
97
+ if (m) {
98
+ m.schedule({
99
+ id: DIRECTORY_SCAN_SCHEDULER_ID,
100
+ name: DIRECTORY_SCAN_JOB,
101
+ everyMs: () => DIRECTORY_SCAN_EVERY_MS,
102
+ });
103
+ m.handle(DIRECTORY_SCAN_JOB, async () => {
104
+ const targets = await this.scan();
105
+ if (targets.length > 0)
106
+ d.log.info("directory syncs enqueued", { count: targets.length });
107
+ });
108
+ m.handle(DIRECTORY_SYNC_JOB, async (job) => {
109
+ const data = job.data;
110
+ const r = await this.sync(data.orgId, data.plugin, data);
111
+ // 通讯录未配置(Ruling A28)静默跳过
112
+ if (r.status === "skipped" && r.reason !== "not_configured") {
113
+ d.log.info("directory sync skipped", {
114
+ orgId: data.orgId,
115
+ plugin: data.plugin,
116
+ reason: r.reason,
117
+ });
118
+ }
119
+ });
120
+ }
121
+ }
122
+ /** 插件提供的 `directory@1`;未加载或不提供时 undefined。 */
123
+ provider(plugin) {
124
+ return this.d.host
125
+ .list("directory")
126
+ .find((e) => e.plugin === plugin && e.capability === DIRECTORY_EXTENSION_POINT)?.impl;
127
+ }
128
+ /** The org exists, the extension provides a directory, is enabled in the org and its org config satisfies the schema (reuses the `OrgExtensionConfigs.get` validation). */
129
+ async eligible(orgId, plugin) {
130
+ const directory = this.provider(plugin);
131
+ if (!directory)
132
+ return { ok: false, reason: "plugin_unavailable" };
133
+ const org = await this.d.db
134
+ .selectFrom("orgs")
135
+ .select("id")
136
+ .where("id", "=", orgId)
137
+ .where("deleted_at", "is", null)
138
+ .executeTakeFirst();
139
+ if (!org)
140
+ return { ok: false, reason: "org_not_found" };
141
+ let cfg;
142
+ try {
143
+ cfg = await this.d.orgExtensionConfigs.get(orgId, plugin);
144
+ }
145
+ catch (err) {
146
+ this.d.log.warn("directory sync: stored organization config is invalid", {
147
+ orgId,
148
+ plugin,
149
+ err,
150
+ });
151
+ return { ok: false, reason: "config_invalid" };
152
+ }
153
+ if (!cfg?.enabled)
154
+ return { ok: false, reason: "not_enabled" };
155
+ // Ruling A28:插件说通讯录没配好(组织只用它的别的能力)→ 不同步;插件实现出错按未配置处理
156
+ if (directory.configured !== undefined) {
157
+ let configured = false;
158
+ try {
159
+ configured = directory.configured(cfg.config) === true;
160
+ }
161
+ catch {
162
+ configured = false;
163
+ }
164
+ if (!configured)
165
+ return { ok: false, reason: "not_configured" };
166
+ }
167
+ return { ok: true, directory, orgConfig: cfg.config };
168
+ }
169
+ /**
170
+ * 投递一次 `directory_changed` 同步(按分钟桶去重);返回 job id。入站 `directory_changed` 经
171
+ * {@link DirectorySyncScheduler} 调用这里。通讯录未配置(`Directory.configured` 返回 false,Ruling A28)时
172
+ * 静默不投递,返回 undefined;其他不可同步的情况照常投递,由任务执行时跳过。
173
+ */
174
+ async enqueue(orgId, plugin, now = new Date()) {
175
+ const e = await this.eligible(orgId, plugin);
176
+ if (!e.ok && e.reason === "not_configured")
177
+ return undefined;
178
+ return this.addJob(orgId, plugin, "changed", directorySyncJobId(orgId, plugin, "changed", now));
179
+ }
180
+ async addJob(orgId, plugin, trigger, jobId, requestedBy) {
181
+ const m = this.d.maintenance;
182
+ if (!m)
183
+ throw new Error("directory sync: maintenance queue is not available");
184
+ if (jobId.includes(":"))
185
+ throw new Error("directory sync: job id must not contain ':'");
186
+ const data = {
187
+ orgId,
188
+ plugin,
189
+ trigger,
190
+ ...(requestedBy !== undefined && { requestedBy: requestedBy.accountId }),
191
+ ...(requestedBy?.tokenId !== undefined && { requestedByToken: requestedBy.tokenId }),
192
+ };
193
+ await m.add(DIRECTORY_SYNC_JOB, data, {
194
+ jobId,
195
+ removeOnComplete: { age: KEEP_COMPLETED_SECONDS[trigger] },
196
+ removeOnFail: KEEP_FAILED,
197
+ });
198
+ return jobId;
199
+ }
200
+ /**
201
+ * Manual trigger by an admin: re-checks `org.members.manage` live under the org row lock, then that
202
+ * the extension can sync (does not provide a directory -> `extension.not_found`, not enabled ->
203
+ * `extension.not_enabled`, config no longer valid -> `extension.config_invalid`, the extension says
204
+ * the directory is not configured -> `directory.not_configured`, Ruling A28), and enqueues a sync
205
+ * job with a unique id.
206
+ */
207
+ async request(orgId, plugin, actorAccountId, actorTokenId) {
208
+ await this.d.db
209
+ .transaction()
210
+ .execute((t) => lockOrgAndAuthorize(t, orgId, actorAccountId, "org.members.manage"));
211
+ const e = await this.eligible(orgId, plugin);
212
+ if (!e.ok) {
213
+ switch (e.reason) {
214
+ case "plugin_unavailable":
215
+ throw new ApiError("extension.not_found", `Extension ${plugin} does not provide a directory`);
216
+ case "org_not_found":
217
+ throw new ApiError("org.not_found", "Organization not found");
218
+ case "not_enabled":
219
+ throw new ApiError("extension.not_enabled", `Extension ${plugin} is not enabled for this organization`);
220
+ case "config_invalid":
221
+ throw new ApiError("extension.config_invalid", `Invalid organization config for extension ${plugin}`);
222
+ case "not_configured":
223
+ throw new ApiError("directory.not_configured", `The directory of extension ${plugin} is not configured for this organization`);
224
+ }
225
+ }
226
+ const jobId = await this.addJob(orgId, plugin, "manual", directorySyncJobId(orgId, plugin, "manual"), { accountId: actorAccountId, tokenId: actorTokenId });
227
+ return { jobId };
228
+ }
229
+ /**
230
+ * 每小时扫描:给每个可同步的 (组织, 插件) 投递一次同步(job id 按小时桶),返回投递的目标。
231
+ * 已存配置不再满足 schema 的跳过(记 warn);单个投递失败记 warn、继续其他目标。
232
+ */
233
+ async scan(now = new Date()) {
234
+ const plugins = this.d.host
235
+ .list("directory")
236
+ .filter((e) => e.capability === DIRECTORY_EXTENSION_POINT)
237
+ .map((e) => e.plugin);
238
+ if (plugins.length === 0)
239
+ return [];
240
+ const rows = await this.d.db
241
+ .selectFrom(enabledExtensionsByOrg(this.d.db).as("en"))
242
+ .innerJoin("orgs", "orgs.id", "en.org_id")
243
+ .select(["en.org_id", "en.plugin"])
244
+ .where("orgs.deleted_at", "is", null)
245
+ .where("en.plugin", "in", plugins)
246
+ .orderBy("en.org_id")
247
+ .orderBy("en.plugin")
248
+ .execute();
249
+ const out = [];
250
+ for (const r of rows) {
251
+ const e = await this.eligible(r.org_id, r.plugin);
252
+ if (!e.ok)
253
+ continue;
254
+ try {
255
+ const jobId = await this.addJob(r.org_id, r.plugin, "schedule", directorySyncJobId(r.org_id, r.plugin, "schedule", now));
256
+ out.push({ orgId: r.org_id, plugin: r.plugin, jobId });
257
+ }
258
+ catch (err) {
259
+ this.d.log.warn("cannot enqueue directory sync", {
260
+ orgId: r.org_id,
261
+ plugin: r.plugin,
262
+ err,
263
+ });
264
+ }
265
+ }
266
+ return out;
267
+ }
268
+ /** 执行一轮同步(维护任务的处理函数;测试可直接调用)。 */
269
+ async sync(orgId, plugin, opts = {}) {
270
+ const e = await this.eligible(orgId, plugin);
271
+ if (!e.ok)
272
+ return { status: "skipped", reason: e.reason };
273
+ const dirtyKey = directorySyncDirtyKey(orgId, plugin);
274
+ const lockKey = `${orgId}:${plugin}`;
275
+ let lease = await this.lock.acquire(lockKey, randomUUID());
276
+ if (!lease) {
277
+ // 在跑的那一轮可能已经读过变化之前的页:记下脏标记,由持有者跑完后补一轮
278
+ await this.d.redis.set(dirtyKey, "1", "EX", DIRECTORY_SYNC_DIRTY_TTL_SECONDS);
279
+ // The holder may have released the lock and taken the flag (GETDEL) between the failed
280
+ // attempt and the write above: the flag would then wait an hour with nobody to rerun, and
281
+ // the next sync would skip its removals. Try the lock once more after the write: if it is
282
+ // still held, its holder takes the flag after releasing; if not, run this sync now.
283
+ lease = await this.lock.acquire(lockKey, randomUUID());
284
+ if (!lease)
285
+ return { status: "skipped", reason: "locked" };
286
+ // No page has been read yet, so this run covers every change flagged so far.
287
+ await this.d.redis.del(dirtyKey);
288
+ }
289
+ const abort = new AbortController();
290
+ // 锁丢了(续租失败、过期后被他人取得):停止本轮,不再移除任何人
291
+ lease.onLost(() => abort.abort(new Error("directory sync lock lost")));
292
+ try {
293
+ return await this.run(orgId, plugin, e.directory, e.orgConfig, abort.signal, opts);
294
+ }
295
+ finally {
296
+ await lease.release().catch(() => { });
297
+ await this.rerunIfDirty(orgId, plugin, dirtyKey);
298
+ }
299
+ }
300
+ /**
301
+ * 释放锁之后取走脏标记(GETDEL,只有一个副本取得到);有标记就投递一次 changed 同步。
302
+ * job id 每次唯一(`…-rerun-<uuid>`):不能被刚刚被挡掉的同一分钟的 changed 任务 id 吞掉。失败只记 warn。
303
+ */
304
+ async rerunIfDirty(orgId, plugin, dirtyKey) {
305
+ try {
306
+ if ((await this.d.redis.getdel(dirtyKey)) === null)
307
+ return;
308
+ const jobId = `directory-sync-${orgId}-${plugin}-rerun-${randomUUID()}`;
309
+ await this.addJob(orgId, plugin, "changed", jobId);
310
+ }
311
+ catch (err) {
312
+ this.d.log.warn("directory sync: cannot enqueue follow-up sync", { orgId, plugin, err });
313
+ }
314
+ }
315
+ async run(orgId, plugin, directory, orgConfig, signal, opts) {
316
+ const source = `directory:${plugin}`;
317
+ const counts = { added: 0, removed: 0, skippedLastOwner: 0, failed: 0, total: 0 };
318
+ /** 本轮仍在职的账号(只在本次任务内使用)。 */
319
+ const seen = new Set();
320
+ /** 列表里在职(active = true)的成员数(含处理失败的)。 */
321
+ let active = 0;
322
+ let listed = false;
323
+ try {
324
+ let cursor;
325
+ for (let page = 0;; page++) {
326
+ if (page >= DIRECTORY_MAX_PAGES) {
327
+ throw new Error(`directory returned more than ${DIRECTORY_MAX_PAGES} pages`);
328
+ }
329
+ signal.throwIfAborted();
330
+ const r = await directory.listMembers({
331
+ orgConfig,
332
+ ...(cursor !== undefined && { cursor }),
333
+ signal: AbortSignal.any([signal, AbortSignal.timeout(DIRECTORY_PAGE_TIMEOUT_MS)]),
334
+ });
335
+ signal.throwIfAborted();
336
+ if (!Array.isArray(r?.members))
337
+ throw new Error("directory returned no members array");
338
+ for (const m of r.members) {
339
+ counts.total++;
340
+ // 离职的人在整轮完成后统一处理(只处理由本通讯录加入的)
341
+ if (m?.active !== true)
342
+ continue;
343
+ active++;
344
+ try {
345
+ const { accountId, added } = await this.addMember(orgId, plugin, source, m);
346
+ seen.add(accountId);
347
+ if (added)
348
+ counts.added++;
349
+ }
350
+ catch (err) {
351
+ if (err instanceof OrgGone)
352
+ throw err;
353
+ counts.failed++;
354
+ this.d.log.warn("directory sync: cannot add member", { orgId, plugin, err });
355
+ }
356
+ }
357
+ const next = r.next;
358
+ if (typeof next !== "string" || next === "")
359
+ break;
360
+ if (next === cursor)
361
+ throw new Error("directory returned the same cursor twice");
362
+ cursor = next;
363
+ }
364
+ listed = true;
365
+ }
366
+ catch (err) {
367
+ this.d.log.warn("directory sync stopped before listing all members", { orgId, plugin, err });
368
+ }
369
+ const trigger = opts.trigger ?? "manual";
370
+ let partial = !listed || counts.failed > 0;
371
+ let removalBlocked = false;
372
+ if (!partial) {
373
+ // 移除前复核:同步途中插件可能已被停用、组织级配置可能已变得无效,此时列表不再可信,不移除任何人
374
+ const still = await this.eligible(orgId, plugin);
375
+ if (!still.ok) {
376
+ partial = true;
377
+ // 途中通讯录配置被清空(Ruling A28):照样不移除,但不记警告
378
+ if (still.reason !== "not_configured") {
379
+ this.d.log.warn("directory sync: plugin no longer eligible before removals", {
380
+ orgId,
381
+ plugin,
382
+ reason: still.reason,
383
+ });
384
+ }
385
+ }
386
+ }
387
+ // Ruling A32:本轮持锁期间来过变更(另一任务因锁被占记下了脏标记)——已读过的页可能早于变更,列表不再可信,
388
+ // 本轮不移除任何人;结束时 rerunIfDirty 取走标记补跑一轮,由那一轮移除。这里只 GET,不能取走标记。
389
+ let partialReason;
390
+ if (!partial) {
391
+ let dirty;
392
+ try {
393
+ dirty = await this.d.redis.get(directorySyncDirtyKey(orgId, plugin));
394
+ }
395
+ catch (err) {
396
+ this.d.log.warn("directory sync: cannot read the dirty flag; skipping removals", {
397
+ orgId,
398
+ plugin,
399
+ err,
400
+ });
401
+ dirty = "1";
402
+ }
403
+ if (dirty !== null) {
404
+ partial = true;
405
+ partialReason = "changed_during_sync";
406
+ }
407
+ }
408
+ if (!partial) {
409
+ const existing = await this.d.db
410
+ .selectFrom("memberships")
411
+ .select("account_id")
412
+ .where("org_id", "=", orgId)
413
+ .where("source", "=", source)
414
+ .orderBy("account_id")
415
+ .execute();
416
+ const planned = existing.filter((c) => !seen.has(c.account_id));
417
+ // Ruling A17:非手动触发的一轮要移除太多人(或通讯录忽然一个在职的人都没有)时,多半是插件或平台出错,先不删
418
+ const threshold = Math.max(DIRECTORY_REMOVAL_GUARD_MIN, Math.floor(DIRECTORY_REMOVAL_GUARD_RATIO * existing.length));
419
+ if (trigger !== "manual" &&
420
+ (planned.length > threshold || (active === 0 && existing.length > 0))) {
421
+ partial = true;
422
+ removalBlocked = true;
423
+ this.d.log.warn("directory sync: mass removal blocked", {
424
+ orgId,
425
+ plugin,
426
+ planned: planned.length,
427
+ existing: existing.length,
428
+ });
429
+ await audit(this.d.db, {
430
+ orgId,
431
+ action: "org.directory.removal_blocked",
432
+ target: plugin,
433
+ detail: {
434
+ plugin,
435
+ trigger,
436
+ planned: planned.length,
437
+ existing: existing.length,
438
+ active,
439
+ threshold,
440
+ },
441
+ });
442
+ }
443
+ for (const c of removalBlocked ? [] : planned) {
444
+ if (signal.aborted) {
445
+ partial = true;
446
+ break;
447
+ }
448
+ const outcome = await this.offboardOne(orgId, plugin, source, c.account_id);
449
+ if (outcome === "removed")
450
+ counts.removed++;
451
+ else if (outcome === "last_owner")
452
+ counts.skippedLastOwner++;
453
+ else if (outcome === "failed")
454
+ counts.failed++;
455
+ }
456
+ }
457
+ await audit(this.d.db, {
458
+ ...(opts.requestedBy !== undefined && { actorAccountId: opts.requestedBy }),
459
+ ...(opts.requestedByToken !== undefined && { actorTokenId: opts.requestedByToken }),
460
+ orgId,
461
+ action: "org.directory.synced",
462
+ target: plugin,
463
+ detail: {
464
+ plugin,
465
+ trigger,
466
+ ...counts,
467
+ partial,
468
+ removalBlocked,
469
+ ...(partialReason !== undefined && { partialReason }),
470
+ },
471
+ });
472
+ return {
473
+ status: "synced",
474
+ ...counts,
475
+ partial,
476
+ removalBlocked,
477
+ ...(partialReason !== undefined && { partialReason }),
478
+ };
479
+ }
480
+ /**
481
+ * 一个在职成员:解析外部身份(不合并、不登录,新身份行 `linked_via = directory`),不是成员就以 member 加入
482
+ * (source = 本通讯录);此人在该组织有本通讯录的排除(被手动移出 / 本人离开过)时不加入。
483
+ * 组织行锁内完成(与移出成员同一把锁、与移出时写排除串行),组织已删除 → {@link OrgGone}。
484
+ */
485
+ async addMember(orgId, plugin, source, m) {
486
+ const tenantId = typeof m.tenantId === "string" ? m.tenantId : "";
487
+ const identity = {
488
+ source: `${plugin}:${tenantId}`,
489
+ externalId: m.externalId,
490
+ tenantId,
491
+ ...(typeof m.email === "string" && { email: m.email }),
492
+ emailVerified: m.emailVerified === true,
493
+ displayName: m.displayName,
494
+ };
495
+ return this.d.db.transaction().execute(async (t) => {
496
+ if (!(await tryLockOrg(t, orgId)))
497
+ throw new OrgGone("organization deleted during sync");
498
+ const { accountId } = await this.d.external.resolve(identity, t, { linkedVia: "directory" });
499
+ const excluded = await t
500
+ .selectFrom("directory_exclusions")
501
+ .select("account_id")
502
+ .where("org_id", "=", orgId)
503
+ .where("account_id", "=", accountId)
504
+ .where("plugin", "=", plugin)
505
+ .executeTakeFirst();
506
+ if (excluded)
507
+ return { accountId, added: false };
508
+ const inserted = await t
509
+ .insertInto("memberships")
510
+ .values({ org_id: orgId, account_id: accountId, role: "member", source })
511
+ .onConflict((oc) => oc.columns(["org_id", "account_id"]).doNothing())
512
+ .returning("account_id")
513
+ .executeTakeFirst();
514
+ if (inserted) {
515
+ await audit(t, {
516
+ orgId,
517
+ action: "org.member.added",
518
+ target: accountId,
519
+ detail: { role: "member", source },
520
+ });
521
+ }
522
+ return { accountId, added: inserted !== undefined };
523
+ });
524
+ }
525
+ /**
526
+ * 一个离职者:独立事务内先锁组织行、再锁其成员关系行(与 `switchCurrentOrg` / 移出成员同一顺序),
527
+ * 确认仍是本通讯录加入的,再走 `Offboarding.offboard`(吊销会话与令牌、删个人凭据、转交 agent 都在这个事务里)。
528
+ * 最后一个 owner → 回滚并返回 `last_owner`;期间已被移除或不再是本通讯录加入的 → `gone`。
529
+ */
530
+ async offboardOne(orgId, plugin, source, accountId) {
531
+ try {
532
+ const result = await this.d.db.transaction().execute(async (t) => {
533
+ if (!(await tryLockOrg(t, orgId)))
534
+ return undefined;
535
+ const row = await t
536
+ .selectFrom("memberships")
537
+ .select("source")
538
+ .where("org_id", "=", orgId)
539
+ .where("account_id", "=", accountId)
540
+ .forUpdate()
541
+ .executeTakeFirst();
542
+ if (row?.source !== source)
543
+ return undefined;
544
+ return this.d.offboarding.offboard(t, orgId, accountId, "directory");
545
+ });
546
+ if (!result)
547
+ return "gone";
548
+ await this.d.offboarding.afterCommit(result);
549
+ return "removed";
550
+ }
551
+ catch (err) {
552
+ if (err instanceof ApiError && err.code === "org.last_owner")
553
+ return "last_owner";
554
+ this.d.log.warn("directory sync: cannot offboard member", { orgId, plugin, accountId, err });
555
+ return "failed";
556
+ }
557
+ }
558
+ }
@@ -0,0 +1,58 @@
1
+ import type { FastifyReply, FastifyRequest } from "fastify";
2
+ import { z } from "zod";
3
+ import type { KernelConfig } from "../config/schema.js";
4
+ import type { Account } from "../identity/accounts.js";
5
+ import { type Principal } from "../identity/principal.js";
6
+ import type { LoginRateLimiter } from "../identity/rate-limit.js";
7
+ import type { SessionService } from "../identity/sessions.js";
8
+ import { type InvitableRole, type Invitation, type InvitationStatus, type InvitationsService } from "./invitations.service.js";
9
+ import { type OrgContext } from "./org.guard.js";
10
+ import type { OrgRole } from "./roles.js";
11
+ declare const CreateBody: z.ZodObject<{
12
+ role: z.ZodEnum<{
13
+ admin: "admin";
14
+ guest: "guest";
15
+ member: "member";
16
+ }>;
17
+ expiresInHours: z.ZodOptional<z.ZodNumber>;
18
+ }, z.core.$strip>;
19
+ /** 组织邀请:组织内管理(`/api/v1/orgs/:orgId/invitations`)与凭令牌预览 / 接受(`/api/v1/invitations/:token`,公开)。 */
20
+ export declare class InvitationsController {
21
+ private readonly invitations;
22
+ private readonly sessions;
23
+ private readonly config;
24
+ private readonly limiter;
25
+ constructor(invitations: InvitationsService, sessions: SessionService, config: () => KernelConfig, limiter: LoginRateLimiter);
26
+ /** 令牌只在此返回一次。 */
27
+ create(principal: Principal, org: OrgContext, body: z.infer<typeof CreateBody>): Promise<{
28
+ invitation: Invitation;
29
+ token: string;
30
+ }>;
31
+ list(org: OrgContext): Promise<{
32
+ invitations: (Invitation & {
33
+ status: InvitationStatus;
34
+ })[];
35
+ }>;
36
+ revoke(principal: Principal, org: OrgContext, id: string): Promise<void>;
37
+ /** 公开预览:只给组织 id / 名称、角色与过期时间。 */
38
+ preview(token: string): Promise<{
39
+ org: {
40
+ id: string;
41
+ name: string;
42
+ };
43
+ role: InvitableRole;
44
+ expiresAt: Date;
45
+ }>;
46
+ /**
47
+ * 接受邀请:已登录的 user principal 直接加入(body 可为空);未登录则 body 必须是
48
+ * `{ login, password, displayName }`,注册成功后创建会话并设 Cookie;service principal → `forbidden`。
49
+ * 每次尝试先占用限流额度(scope `inv`:按令牌与客户端 IP),防止猜令牌、探测登录名与用 scrypt 拖垮服务;
50
+ * 超限 → 429 `auth.rate_limited`,成功后退还。
51
+ */
52
+ accept(token: string, principal: Principal | undefined, body: unknown, req: FastifyRequest, reply: FastifyReply): Promise<{
53
+ account: Account;
54
+ orgId: string;
55
+ role: OrgRole;
56
+ }>;
57
+ }
58
+ export {};