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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (631) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +2 -0
  3. package/README.md +20 -2
  4. package/bootstrap.json +22 -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 +1125 -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 +223 -0
  112. package/dist/config/schema.js +1151 -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 +422 -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 +150 -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 +210 -0
  166. package/dist/errors.js +212 -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 +789 -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 +149 -0
  210. package/dist/extensions/bootstrap.js +441 -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 +170 -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 +67 -0
  318. package/dist/index.js +65 -0
  319. package/dist/kernel.d.ts +256 -0
  320. package/dist/kernel.js +1326 -0
  321. package/dist/log.d.ts +48 -0
  322. package/dist/log.js +229 -0
  323. package/dist/models/prices.d.ts +53 -0
  324. package/dist/models/prices.js +121 -0
  325. package/dist/models/purposes.controller.d.ts +19 -0
  326. package/dist/models/purposes.controller.js +56 -0
  327. package/dist/models/purposes.d.ts +140 -0
  328. package/dist/models/purposes.js +267 -0
  329. package/dist/net/proxy.d.ts +44 -0
  330. package/dist/net/proxy.js +162 -0
  331. package/dist/net/public-address.d.ts +60 -0
  332. package/dist/net/public-address.js +271 -0
  333. package/dist/net/safe-fetch.d.ts +38 -0
  334. package/dist/net/safe-fetch.js +140 -0
  335. package/dist/orgs/directory-sync.controller.d.ts +14 -0
  336. package/dist/orgs/directory-sync.controller.js +40 -0
  337. package/dist/orgs/directory-sync.d.ts +166 -0
  338. package/dist/orgs/directory-sync.js +558 -0
  339. package/dist/orgs/invitations.controller.d.ts +58 -0
  340. package/dist/orgs/invitations.controller.js +137 -0
  341. package/dist/orgs/invitations.service.d.ts +80 -0
  342. package/dist/orgs/invitations.service.js +217 -0
  343. package/dist/orgs/members.service.d.ts +63 -0
  344. package/dist/orgs/members.service.js +234 -0
  345. package/dist/orgs/offboarding.d.ts +141 -0
  346. package/dist/orgs/offboarding.js +398 -0
  347. package/dist/orgs/org-lock.d.ts +32 -0
  348. package/dist/orgs/org-lock.js +46 -0
  349. package/dist/orgs/org.guard.d.ts +35 -0
  350. package/dist/orgs/org.guard.js +95 -0
  351. package/dist/orgs/orgs.controller.d.ts +78 -0
  352. package/dist/orgs/orgs.controller.js +192 -0
  353. package/dist/orgs/orgs.service.d.ts +61 -0
  354. package/dist/orgs/orgs.service.js +209 -0
  355. package/dist/orgs/roles.d.ts +13 -0
  356. package/dist/orgs/roles.js +58 -0
  357. package/dist/orgs/settings.controller.d.ts +20 -0
  358. package/dist/orgs/settings.controller.js +53 -0
  359. package/dist/orgs/settings.service.d.ts +120 -0
  360. package/dist/orgs/settings.service.js +178 -0
  361. package/dist/packages/npm.d.ts +50 -0
  362. package/dist/packages/npm.js +218 -0
  363. package/dist/packages/provenance.d.ts +47 -0
  364. package/dist/packages/provenance.js +147 -0
  365. package/dist/packages/tgz.d.ts +76 -0
  366. package/dist/packages/tgz.js +225 -0
  367. package/dist/runtime/abort.d.ts +32 -0
  368. package/dist/runtime/abort.js +71 -0
  369. package/dist/runtime/checkpointer.d.ts +32 -0
  370. package/dist/runtime/checkpointer.js +243 -0
  371. package/dist/runtime/context/build.d.ts +254 -0
  372. package/dist/runtime/context/build.js +693 -0
  373. package/dist/runtime/context/claude-tools.d.ts +11 -0
  374. package/dist/runtime/context/claude-tools.js +24 -0
  375. package/dist/runtime/context/compaction.d.ts +26 -0
  376. package/dist/runtime/context/compaction.js +195 -0
  377. package/dist/runtime/context/pairing.d.ts +11 -0
  378. package/dist/runtime/context/pairing.js +82 -0
  379. package/dist/runtime/context/reminders.d.ts +5 -0
  380. package/dist/runtime/context/reminders.js +11 -0
  381. package/dist/runtime/context/skills.d.ts +105 -0
  382. package/dist/runtime/context/skills.js +283 -0
  383. package/dist/runtime/context/tokens.d.ts +19 -0
  384. package/dist/runtime/context/tokens.js +104 -0
  385. package/dist/runtime/conversation-lock.d.ts +40 -0
  386. package/dist/runtime/conversation-lock.js +97 -0
  387. package/dist/runtime/hook-calls.d.ts +84 -0
  388. package/dist/runtime/hook-calls.js +136 -0
  389. package/dist/runtime/langgraph-loop.d.ts +52 -0
  390. package/dist/runtime/langgraph-loop.js +247 -0
  391. package/dist/runtime/loop.d.ts +93 -0
  392. package/dist/runtime/loop.js +7 -0
  393. package/dist/runtime/maintenance.d.ts +80 -0
  394. package/dist/runtime/maintenance.js +147 -0
  395. package/dist/runtime/media-cache.d.ts +21 -0
  396. package/dist/runtime/media-cache.js +51 -0
  397. package/dist/runtime/model-call.d.ts +176 -0
  398. package/dist/runtime/model-call.js +1049 -0
  399. package/dist/runtime/providers.d.ts +86 -0
  400. package/dist/runtime/providers.js +224 -0
  401. package/dist/runtime/quota.d.ts +29 -0
  402. package/dist/runtime/quota.js +70 -0
  403. package/dist/runtime/run-finish.d.ts +45 -0
  404. package/dist/runtime/run-finish.js +69 -0
  405. package/dist/runtime/run-queue.d.ts +121 -0
  406. package/dist/runtime/run-queue.js +493 -0
  407. package/dist/runtime/run-worker.d.ts +138 -0
  408. package/dist/runtime/run-worker.js +805 -0
  409. package/dist/runtime/stream.controller.d.ts +34 -0
  410. package/dist/runtime/stream.controller.js +122 -0
  411. package/dist/runtime/stream.d.ts +63 -0
  412. package/dist/runtime/stream.js +262 -0
  413. package/dist/runtime/subagents/child.d.ts +80 -0
  414. package/dist/runtime/subagents/child.js +225 -0
  415. package/dist/runtime/subagents/definition.d.ts +103 -0
  416. package/dist/runtime/subagents/definition.js +392 -0
  417. package/dist/runtime/subagents/dispatch.d.ts +69 -0
  418. package/dist/runtime/subagents/dispatch.js +502 -0
  419. package/dist/runtime/subagents/limits.d.ts +23 -0
  420. package/dist/runtime/subagents/limits.js +34 -0
  421. package/dist/runtime/subagents/org-agents.d.ts +50 -0
  422. package/dist/runtime/subagents/org-agents.js +70 -0
  423. package/dist/runtime/subagents/preamble.d.ts +7 -0
  424. package/dist/runtime/subagents/preamble.js +11 -0
  425. package/dist/runtime/subagents/progress.d.ts +26 -0
  426. package/dist/runtime/subagents/progress.js +36 -0
  427. package/dist/runtime/subagents/roster.d.ts +55 -0
  428. package/dist/runtime/subagents/roster.js +111 -0
  429. package/dist/runtime/subagents/skill-fork.d.ts +123 -0
  430. package/dist/runtime/subagents/skill-fork.js +259 -0
  431. package/dist/runtime/usage-report.d.ts +163 -0
  432. package/dist/runtime/usage-report.js +550 -0
  433. package/dist/runtime/waits.d.ts +233 -0
  434. package/dist/runtime/waits.js +883 -0
  435. package/dist/sandbox/leases.d.ts +169 -0
  436. package/dist/sandbox/leases.js +515 -0
  437. package/dist/sandbox/lifecycle.d.ts +21 -0
  438. package/dist/sandbox/lifecycle.js +68 -0
  439. package/dist/sandbox/sandbox.service.d.ts +249 -0
  440. package/dist/sandbox/sandbox.service.js +908 -0
  441. package/dist/skills/catalog.d.ts +149 -0
  442. package/dist/skills/catalog.js +405 -0
  443. package/dist/skills/changes.controller.d.ts +56 -0
  444. package/dist/skills/changes.controller.js +136 -0
  445. package/dist/skills/changes.service.d.ts +175 -0
  446. package/dist/skills/changes.service.js +805 -0
  447. package/dist/skills/invocable.controller.d.ts +23 -0
  448. package/dist/skills/invocable.controller.js +50 -0
  449. package/dist/skills/invocation-keys.d.ts +23 -0
  450. package/dist/skills/invocation-keys.js +44 -0
  451. package/dist/skills/invoke.d.ts +135 -0
  452. package/dist/skills/invoke.js +286 -0
  453. package/dist/skills/package.d.ts +87 -0
  454. package/dist/skills/package.js +227 -0
  455. package/dist/skills/skills.controller.d.ts +40 -0
  456. package/dist/skills/skills.controller.js +110 -0
  457. package/dist/skills/skills.service.d.ts +192 -0
  458. package/dist/skills/skills.service.js +567 -0
  459. package/dist/storage/prefix.d.ts +36 -0
  460. package/dist/storage/prefix.js +104 -0
  461. package/dist/storage/purge.d.ts +27 -0
  462. package/dist/storage/purge.js +75 -0
  463. package/dist/storage/storage.service.d.ts +44 -0
  464. package/dist/storage/storage.service.js +145 -0
  465. package/dist/text.d.ts +13 -0
  466. package/dist/text.js +13 -0
  467. package/dist/tools/approvals.controller.d.ts +53 -0
  468. package/dist/tools/approvals.controller.js +128 -0
  469. package/dist/tools/approvals.service.d.ts +172 -0
  470. package/dist/tools/approvals.service.js +568 -0
  471. package/dist/tools/breaker.d.ts +28 -0
  472. package/dist/tools/breaker.js +72 -0
  473. package/dist/tools/builtins/agent.d.ts +81 -0
  474. package/dist/tools/builtins/agent.js +223 -0
  475. package/dist/tools/builtins/ask-user.d.ts +28 -0
  476. package/dist/tools/builtins/ask-user.js +139 -0
  477. package/dist/tools/builtins/read-tool-output.d.ts +18 -0
  478. package/dist/tools/builtins/read-tool-output.js +108 -0
  479. package/dist/tools/builtins/sandbox/bash.d.ts +16 -0
  480. package/dist/tools/builtins/sandbox/bash.js +137 -0
  481. package/dist/tools/builtins/sandbox/common.d.ts +114 -0
  482. package/dist/tools/builtins/sandbox/common.js +304 -0
  483. package/dist/tools/builtins/sandbox/deliver.d.ts +5 -0
  484. package/dist/tools/builtins/sandbox/deliver.js +180 -0
  485. package/dist/tools/builtins/sandbox/edit.d.ts +4 -0
  486. package/dist/tools/builtins/sandbox/edit.js +98 -0
  487. package/dist/tools/builtins/sandbox/glob-match.d.ts +25 -0
  488. package/dist/tools/builtins/sandbox/glob-match.js +240 -0
  489. package/dist/tools/builtins/sandbox/glob.d.ts +4 -0
  490. package/dist/tools/builtins/sandbox/glob.js +104 -0
  491. package/dist/tools/builtins/sandbox/grep.d.ts +9 -0
  492. package/dist/tools/builtins/sandbox/grep.js +133 -0
  493. package/dist/tools/builtins/sandbox/index.d.ts +12 -0
  494. package/dist/tools/builtins/sandbox/index.js +27 -0
  495. package/dist/tools/builtins/sandbox/names.d.ts +7 -0
  496. package/dist/tools/builtins/sandbox/names.js +20 -0
  497. package/dist/tools/builtins/sandbox/read.d.ts +8 -0
  498. package/dist/tools/builtins/sandbox/read.js +121 -0
  499. package/dist/tools/builtins/sandbox/write.d.ts +4 -0
  500. package/dist/tools/builtins/sandbox/write.js +88 -0
  501. package/dist/tools/builtins/skill-load.d.ts +53 -0
  502. package/dist/tools/builtins/skill-load.js +446 -0
  503. package/dist/tools/builtins/skill-write.d.ts +59 -0
  504. package/dist/tools/builtins/skill-write.js +244 -0
  505. package/dist/tools/builtins/tool-search.d.ts +31 -0
  506. package/dist/tools/builtins/tool-search.js +171 -0
  507. package/dist/tools/connector-content.controller.d.ts +34 -0
  508. package/dist/tools/connector-content.controller.js +78 -0
  509. package/dist/tools/connector-content.d.ts +104 -0
  510. package/dist/tools/connector-content.js +267 -0
  511. package/dist/tools/connectors.controller.d.ts +210 -0
  512. package/dist/tools/connectors.controller.js +234 -0
  513. package/dist/tools/connectors.service.d.ts +303 -0
  514. package/dist/tools/connectors.service.js +1102 -0
  515. package/dist/tools/credentials.d.ts +139 -0
  516. package/dist/tools/credentials.js +351 -0
  517. package/dist/tools/drift.d.ts +141 -0
  518. package/dist/tools/drift.js +539 -0
  519. package/dist/tools/elicitation.d.ts +81 -0
  520. package/dist/tools/elicitation.js +266 -0
  521. package/dist/tools/endpoint.d.ts +18 -0
  522. package/dist/tools/endpoint.js +115 -0
  523. package/dist/tools/info.d.ts +67 -0
  524. package/dist/tools/info.js +113 -0
  525. package/dist/tools/naming.d.ts +27 -0
  526. package/dist/tools/naming.js +47 -0
  527. package/dist/tools/oauth/discovery.d.ts +65 -0
  528. package/dist/tools/oauth/discovery.js +307 -0
  529. package/dist/tools/oauth/flow.d.ts +63 -0
  530. package/dist/tools/oauth/flow.js +237 -0
  531. package/dist/tools/oauth/oauth.controller.d.ts +31 -0
  532. package/dist/tools/oauth/oauth.controller.js +95 -0
  533. package/dist/tools/oauth/tokens.d.ts +111 -0
  534. package/dist/tools/oauth/tokens.js +258 -0
  535. package/dist/tools/outputs.d.ts +61 -0
  536. package/dist/tools/outputs.js +156 -0
  537. package/dist/tools/pipeline.d.ts +322 -0
  538. package/dist/tools/pipeline.js +1236 -0
  539. package/dist/tools/policy.d.ts +60 -0
  540. package/dist/tools/policy.js +236 -0
  541. package/dist/tools/questions.controller.d.ts +24 -0
  542. package/dist/tools/questions.controller.js +58 -0
  543. package/dist/tools/questions.service.d.ts +103 -0
  544. package/dist/tools/questions.service.js +295 -0
  545. package/dist/tools/redact.d.ts +20 -0
  546. package/dist/tools/redact.js +60 -0
  547. package/dist/tools/registry.d.ts +246 -0
  548. package/dist/tools/registry.js +481 -0
  549. package/dist/tools/resources.d.ts +16 -0
  550. package/dist/tools/resources.js +76 -0
  551. package/dist/tools/specs.d.ts +14 -0
  552. package/dist/tools/specs.js +31 -0
  553. package/dist/tools/validate.d.ts +20 -0
  554. package/dist/tools/validate.js +183 -0
  555. package/dist/tools/view.d.ts +43 -0
  556. package/dist/tools/view.js +225 -0
  557. package/dist/ui/embed-token.d.ts +31 -0
  558. package/dist/ui/embed-token.js +132 -0
  559. package/dist/ui/registry.d.ts +58 -0
  560. package/dist/ui/registry.js +90 -0
  561. package/dist/ui/ui-stream.d.ts +37 -0
  562. package/dist/ui/ui-stream.js +162 -0
  563. package/dist/ui/views.controller.d.ts +81 -0
  564. package/dist/ui/views.controller.js +261 -0
  565. package/dist/ui/views.d.ts +155 -0
  566. package/dist/ui/views.js +306 -0
  567. package/dist/version.d.ts +5 -0
  568. package/dist/version.js +6 -0
  569. package/package.json +67 -3
  570. package/src/migrations/0001_init.sql +8 -0
  571. package/src/migrations/0002_secrets.sql +8 -0
  572. package/src/migrations/0003_identity.sql +117 -0
  573. package/src/migrations/0004_plugin_org_config_nullable.sql +3 -0
  574. package/src/migrations/0005_agents.sql +27 -0
  575. package/src/migrations/0006_conversations.sql +37 -0
  576. package/src/migrations/0007_checkpoints.sql +26 -0
  577. package/src/migrations/0008_runs_trigger_seq.sql +3 -0
  578. package/src/migrations/0009_runs_active_unique.sql +4 -0
  579. package/src/migrations/0010_tools.sql +125 -0
  580. package/src/migrations/0011_approvals_spec.sql +10 -0
  581. package/src/migrations/0012_run_waits.sql +24 -0
  582. package/src/migrations/0013_app_tools_source.sql +4 -0
  583. package/src/migrations/0014_tool_specs.sql +8 -0
  584. package/src/migrations/0015_tool_drift.sql +20 -0
  585. package/src/migrations/0016_plugin_permissions.sql +11 -0
  586. package/src/migrations/0017_identity_sources.sql +6 -0
  587. package/src/migrations/0018_channels.sql +74 -0
  588. package/src/migrations/0019_identity_trust.sql +17 -0
  589. package/src/migrations/0020_channel_card_lookup.sql +10 -0
  590. package/src/migrations/0021_org_storage_purge.sql +9 -0
  591. package/src/migrations/0022_attachments.sql +29 -0
  592. package/src/migrations/0023_sandboxes.sql +37 -0
  593. package/src/migrations/0024_skills.sql +46 -0
  594. package/src/migrations/0025_skills_catalog_idx.sql +6 -0
  595. package/src/migrations/0026_skill_changes.sql +34 -0
  596. package/src/migrations/0027_model_prices.sql +18 -0
  597. package/src/migrations/0028_evals.sql +105 -0
  598. package/src/migrations/0029_model_purposes.sql +18 -0
  599. package/src/migrations/0030_plugin_installs.sql +73 -0
  600. package/src/migrations/0031_plugin_snapshot_source.sql +6 -0
  601. package/src/migrations/0032_plugin_deployment_configs.sql +10 -0
  602. package/src/migrations/0033_rename_apps_to_connectors.sql +25 -0
  603. package/src/migrations/0034_directory.sql +49 -0
  604. package/src/migrations/0035_catalogs.sql +40 -0
  605. package/src/migrations/0036_app_import_staging.sql +17 -0
  606. package/src/migrations/0037_directory_installs.sql +92 -0
  607. package/src/migrations/0038_channel_inbound_mode.sql +6 -0
  608. package/src/migrations/0039_channel_card_pending.sql +8 -0
  609. package/src/migrations/0040_usage_report_sweep.sql +10 -0
  610. package/src/migrations/0041_rename_plugins_to_extensions.sql +38 -0
  611. package/src/migrations/0042_rename_directory_to_catalog.sql +80 -0
  612. package/src/migrations/0043_rename_app_installs_to_plugin_installs.sql +20 -0
  613. package/src/migrations/0044_catalog_one_kind.sql +90 -0
  614. package/src/migrations/0045_plugin_dependencies.sql +9 -0
  615. package/src/migrations/0046_git_sources.sql +25 -0
  616. package/src/migrations/0047_marketplace_entry_heads.sql +7 -0
  617. package/src/migrations/0048_marketplace_entry_trees.sql +8 -0
  618. package/src/migrations/0049_plugin_upgrades.sql +37 -0
  619. package/src/migrations/0050_bootstrap.sql +53 -0
  620. package/src/migrations/0051_claude_compat.sql +26 -0
  621. package/src/migrations/0052_conversations_account_agent_idx.sql +5 -0
  622. package/src/migrations/0053_subagents.sql +73 -0
  623. package/src/migrations/0054_subagent_wait_expiry.sql +7 -0
  624. package/src/migrations/0055_subagent_parent_indexes.sql +10 -0
  625. package/src/migrations/0056_approval_reason.sql +3 -0
  626. package/src/migrations/0057_conversation_titles.sql +11 -0
  627. package/src/migrations/0058_conversation_selection.sql +4 -0
  628. package/src/migrations/0059_conversation_queue.sql +22 -0
  629. package/src/migrations/0060_file_previewers.sql +10 -0
  630. package/src/migrations/0061_queue_selection.sql +5 -0
  631. package/src/migrations/0062_queued_skill.sql +8 -0
@@ -0,0 +1,625 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { secretValues } from "../config/fields.js";
3
+ import { enabledExtensionsByOrg } from "../extensions/enabled.js";
4
+ import { createRedactor } from "../log.js";
5
+ import { CHANNEL_CHANGED_TOPIC, channelBackoffKey, channelFailsKey, } from "./connections.service.js";
6
+ /** 长连接租约键(内核锁):值为持有方的随机 token。 */
7
+ export const channelLeaseKey = (connectionId) => `capk:channel-lease:${connectionId}`;
8
+ /**
9
+ * Gateway heartbeats, one ZSET per channel plugin (Ruling R3): members are process replica ids of the
10
+ * gateways that have that plugin loaded, scores the Redis server time (ms) of the member's last
11
+ * lease-renewal round. Live = score > server now - `leaseTtlMs`. Per plugin, so a gateway that cannot
12
+ * load a plugin does not count toward that plugin's share.
13
+ */
14
+ export const gatewayReplicasKey = (plugin) => `capk:gateway-replicas:${plugin}`;
15
+ /** Bus topic published after an over-share replica handed a connection back (claim-only nudge). */
16
+ export const CHANNEL_HANDOFF_TOPIC = "channel.handoff";
17
+ /**
18
+ * Handoff marker written when an over-share replica gives a connection back: value = that replica's
19
+ * id, PX = 2 x `scanIntervalMs`. The releasing replica does not claim the connection while it exists.
20
+ */
21
+ export const channelHandoffKey = (connectionId) => `capk:channel-handoff:${connectionId}`;
22
+ /** Rate-limit key of the "no live gateway" warning (one line per check interval, cluster-wide). */
23
+ export const gatewayMissingWarnedKey = "capk:gateway-missing-warned";
24
+ /**
25
+ * Upper bound of the connections one gateway replica holds: `ceil(runnable / live) + slack`, with
26
+ * `live < 1` treated as 1. With `rank` (this replica's index among the live replicas sorted by id)
27
+ * the remainder goes to the lowest ranks only, so the per-replica targets add up to exactly
28
+ * `runnable + live * slack`: with slack 0, 4 connections on 3 replicas split 2 / 1 / 1 instead of
29
+ * leaving a newcomer with nothing next to two replicas that each sit at the ceiling. Rank 0 (the
30
+ * default) gets the full ceiling.
31
+ */
32
+ export function shareTarget(runnable, live, slack, rank = 0) {
33
+ const n = Math.max(1, live);
34
+ return Math.floor(runnable / n) + (rank < runnable % n ? 1 : 0) + slack;
35
+ }
36
+ /** 连续失败的退避上限。 */
37
+ const MAX_BACKOFF_MS = 300_000;
38
+ /** 连续失败计数的保留时长(秒)。 */
39
+ const FAILS_TTL_SECONDS = 3600;
40
+ /**
41
+ * 中止后等插件 `connect` 返回的上限:等待期间照常续租;超时则停止续租、不主动释放,让租约在一个 TTL 后自然过期。
42
+ */
43
+ const SETTLE_MS = 5_000;
44
+ /** `last_error` 的最大长度。 */
45
+ const MAX_ERROR_CHARS = 1000;
46
+ const RENEW = `
47
+ if redis.call('GET', KEYS[1]) == ARGV[1] then
48
+ return redis.call('PEXPIRE', KEYS[1], ARGV[2])
49
+ end
50
+ return 0
51
+ `;
52
+ /**
53
+ * Heartbeat with the Redis server clock (replica wall clocks may drift): for each key, ZADD the
54
+ * member, trim members older than one TTL and refresh the key's expiry. KEYS = heartbeat keys to
55
+ * write; ARGV = [member, ttlMs, ...stale keys to leave].
56
+ */
57
+ const HEARTBEAT = `
58
+ local t = redis.call('TIME')
59
+ local now = tonumber(t[1]) * 1000 + math.floor(tonumber(t[2]) / 1000)
60
+ local ttl = tonumber(ARGV[2])
61
+ for _, k in ipairs(KEYS) do
62
+ redis.call('ZADD', k, now, ARGV[1])
63
+ redis.call('ZREMRANGEBYSCORE', k, '-inf', now - ttl)
64
+ redis.call('PEXPIRE', k, ttl * 2)
65
+ end
66
+ for i = 3, #ARGV do
67
+ redis.call('ZREM', ARGV[i], ARGV[1])
68
+ end
69
+ return now
70
+ `;
71
+ /**
72
+ * Live members per heartbeat key, by the Redis server clock: returns one array per key (in KEYS
73
+ * order) of members with score > now - ARGV[1].
74
+ */
75
+ const LIVE = `
76
+ local t = redis.call('TIME')
77
+ local now = tonumber(t[1]) * 1000 + math.floor(tonumber(t[2]) / 1000)
78
+ local out = {}
79
+ for i, k in ipairs(KEYS) do
80
+ out[i] = redis.call('ZRANGEBYSCORE', k, '(' .. (now - tonumber(ARGV[1])), '+inf')
81
+ end
82
+ return out
83
+ `;
84
+ /** Live heartbeat members of each plugin (Redis server clock). */
85
+ export async function liveGateways(redis, plugins, ttlMs) {
86
+ const out = new Map();
87
+ if (plugins.length === 0)
88
+ return out;
89
+ const res = (await redis.eval(LIVE, plugins.length, ...plugins.map(gatewayReplicasKey), ttlMs));
90
+ plugins.forEach((p, i) => {
91
+ out.set(p, res[i] ?? []);
92
+ });
93
+ return out;
94
+ }
95
+ const RELEASE = `
96
+ if redis.call('GET', KEYS[1]) == ARGV[1] then
97
+ return redis.call('DEL', KEYS[1])
98
+ end
99
+ return 0
100
+ `;
101
+ const errMsg = (e) => (e instanceof Error ? e.message : String(e));
102
+ /**
103
+ * 渠道长连接选主(runs only on the gateway role)。每个副本两个各自独立的循环,周期都是 `channels.scanIntervalMs`(默认 10s):
104
+ * - 续租循环:为本进程持有的连接续租(`capk:channel-lease:<id>`,TTL `channels.leaseTtlMs` 默认 30s)。
105
+ * 它不做任何可能慢的事(不等交还、不查库),一个插件迟迟不退出不会拖慢其他连接的续租。
106
+ * - 扫描循环:复核持有的连接仍为 active、未删除且插件在该组织启用(不满足就交还,交还不阻塞本轮),
107
+ * 再扫描无人持有的这类连接,`SET NX PX` 取到租约的副本调用插件 `connect`(传 `signal`)。
108
+ * 续租失败(租约已丢)→ 立即中止,不释放(已不是自己的);Redis 出错时,自上次续租成功起满 `TTL - 扫描周期`
109
+ * 仍续不上就按丢失处理(赶在租约可能被别的副本拿走之前断开)。连接被停用 / 删除 / 改配置(内核 bus `channel.changed`,
110
+ * 或扫描时复核发现)→ 中止、等 `connect` 返回后释放租约,下一轮任一副本按新配置重连;取得租约到 `connect` 开始之间
111
+ * 收到的重连广播会被记下,开始后立即交还。
112
+ * `connect` 抛错或提前返回 → 记 `last_error`,在 Redis 写退避标记(指数退避,上限 5 分钟),释放租约后由任一副本重试。
113
+ * Fair share (E11-B): the renewal loop also writes this replica's heartbeat into `capk:gateway-replicas`;
114
+ * each scan computes this replica's target from the runnable count and the live replicas
115
+ * (`shareTarget`), stops claiming at the target and, when above it, gives back one connection per
116
+ * round (the most recently connected) with a handoff marker. Exactly one holder per connection is
117
+ * still guaranteed by the lease alone; the share only decides who claims.
118
+ * 停机时中止全部长连接并释放租约,并等进行中的 `onEvent`(入队)结束。持有的长连接、租约 token 与定时器都是「本进程持有的资源」,
119
+ * 跨副本的状态(租约、退避、失败计数)都在 Redis。
120
+ */
121
+ export class ChannelSupervisor {
122
+ deps;
123
+ held = new Map();
124
+ /** 已取得租约、正在读配置准备 `connect` 的连接;值为期间是否收到了重连广播。 */
125
+ connecting = new Map();
126
+ /** 正在交还(已中止、等 `connect` 返回)的连接 → 租约 token:等待期间照常续租,交还完成才释放。 */
127
+ settling = new Map();
128
+ /** 进行中的交还(`stop()` 要等它们全部结束)。 */
129
+ releasing = new Set();
130
+ /** 进行中的 `onEvent`(去重 + 入队,很快):`stop()` 等它们结束,插件才不会在内核关闭队列之后才拿到结果。 */
131
+ inflight = new Set();
132
+ loops = [];
133
+ stopped = false;
134
+ unsubscribe;
135
+ unsubscribeHandoff;
136
+ /** Scans run one at a time (periodic and nudged), so share counts are never raced. */
137
+ scanChain = Promise.resolve();
138
+ /** Plugins this replica heartbeats for (to ZREM when a plugin goes away and on stop). */
139
+ heartbeated = new Set();
140
+ /** A claim-only scan is queued and has not started yet: further nudges until then are dropped. */
141
+ claimQueued = false;
142
+ constructor(deps) {
143
+ this.deps = deps;
144
+ }
145
+ async start() {
146
+ this.unsubscribe = await this.deps.bus.subscribe(CHANNEL_CHANGED_TOPIC, (payload) => {
147
+ const m = payload;
148
+ const id = m?.connectionId;
149
+ if (m?.reconnect !== true || typeof id !== "string")
150
+ return;
151
+ if (this.held.has(id))
152
+ this.releaseInBackground(id);
153
+ else {
154
+ const c = this.connecting.get(id);
155
+ if (c)
156
+ c.reconnect = true;
157
+ }
158
+ });
159
+ // Another replica handed a connection back: claim right away instead of waiting for the next
160
+ // round. Claim only (no hand-back), so hand-backs stay at one per plugin per scan round.
161
+ // Nudges coalesce: at most one claim-only scan waits behind the one running; nudges for a
162
+ // plugin not loaded here are ignored.
163
+ this.unsubscribeHandoff = await this.deps.bus.subscribe(CHANNEL_HANDOFF_TOPIC, (payload) => {
164
+ const m = payload;
165
+ if (this.stopped || m?.replicaId === this.deps.replicaId || this.claimQueued)
166
+ return;
167
+ if (typeof m?.plugin !== "string" || !this.deps.localPlugins().includes(m.plugin))
168
+ return;
169
+ this.claimQueued = true;
170
+ const run = this.exclusive(() => {
171
+ this.claimQueued = false;
172
+ return this.scan(true);
173
+ });
174
+ this.track(run).catch((err) => this.deps.log.error("channel supervisor scan failed", { err }));
175
+ });
176
+ this.loop("renew", () => this.renewAll());
177
+ this.loop("scan", () => this.exclusive(async () => {
178
+ await this.recheckHeld();
179
+ if (!this.stopped)
180
+ await this.scan(false);
181
+ }));
182
+ }
183
+ /** Runs `fn` after any scan in progress. */
184
+ exclusive(fn) {
185
+ const p = this.scanChain.then(fn);
186
+ this.scanChain = p.catch(() => { });
187
+ return p;
188
+ }
189
+ /** 周期循环:上一轮结束后隔 `scanIntervalMs` 再跑下一轮;首轮立即执行。 */
190
+ loop(name, fn) {
191
+ const st = {};
192
+ this.loops.push(st);
193
+ const run = (ms) => {
194
+ if (this.stopped)
195
+ return;
196
+ st.timer = setTimeout(() => {
197
+ st.running = fn()
198
+ .catch((err) => this.deps.log.error(`channel supervisor ${name} failed`, { err }))
199
+ .finally(() => {
200
+ st.running = undefined;
201
+ run(this.deps.config().channels.scanIntervalMs);
202
+ });
203
+ }, ms);
204
+ st.timer.unref?.();
205
+ };
206
+ run(0);
207
+ }
208
+ async renewAll() {
209
+ const { leaseTtlMs: ttl, scanIntervalMs } = this.deps.config().channels;
210
+ // Heartbeat before renewing: a crashed replica's heartbeat then goes stale no later than its
211
+ // leases expire, so the survivors' share already excludes it when those connections free up
212
+ await this.heartbeat(ttl);
213
+ await Promise.all([...this.held].map(async ([id, h]) => {
214
+ let ok;
215
+ try {
216
+ ok =
217
+ Number(await this.deps.redis.eval(RENEW, 1, channelLeaseKey(id), h.token, ttl)) === 1;
218
+ }
219
+ catch (err) {
220
+ // Redis 暂时不可用:再等一轮就可能超过 TTL(租约在别的副本眼里已过期),提前按丢失处理
221
+ this.deps.log.warn("channel lease renew failed", { connectionId: id, err });
222
+ ok = Date.now() - h.renewedAt < ttl - scanIntervalMs;
223
+ if (ok)
224
+ return;
225
+ }
226
+ await this.afterRenew(id, h, ok, ttl);
227
+ }));
228
+ // 交还中的连接:插件还没退出,租约不能在别的副本眼里过期(否则两边同时在线);续不上就算了(已不是自己的)
229
+ await Promise.all([...this.settling].map(([id, token]) => this.deps.redis.eval(RENEW, 1, channelLeaseKey(id), token, ttl).catch((err) => {
230
+ this.deps.log.warn("channel lease renew failed", { connectionId: id, err });
231
+ })));
232
+ }
233
+ /**
234
+ * Writes this replica's heartbeat into the ZSET of every channel plugin loaded here (trimming
235
+ * members older than one TTL; the keys expire too) and leaves the ZSETs of plugins no longer
236
+ * loaded. Uses the Redis server clock.
237
+ */
238
+ async heartbeat(ttl) {
239
+ if (this.stopped)
240
+ return;
241
+ const plugins = [...new Set(this.deps.localPlugins())];
242
+ const gone = [...this.heartbeated].filter((p) => !plugins.includes(p));
243
+ if (plugins.length === 0 && gone.length === 0)
244
+ return;
245
+ try {
246
+ await this.deps.redis.eval(HEARTBEAT, plugins.length, ...plugins.map(gatewayReplicasKey), this.deps.replicaId, ttl, ...gone.map(gatewayReplicasKey));
247
+ this.heartbeated = new Set(plugins);
248
+ }
249
+ catch (err) {
250
+ this.deps.log.warn("gateway heartbeat failed", { err });
251
+ }
252
+ }
253
+ /**
254
+ * This replica's share target per plugin for the round. Live replicas of a plugin are its
255
+ * heartbeat members newer than one TTL plus this replica itself (its own heartbeat may not be
256
+ * written yet on the first round).
257
+ */
258
+ async targets(runnable) {
259
+ const { leaseTtlMs: ttl, shareSlack } = this.deps.config().channels;
260
+ const plugins = [...runnable.keys()];
261
+ const live = await liveGateways(this.deps.redis, plugins, ttl);
262
+ const out = new Map();
263
+ for (const p of plugins) {
264
+ const members = [...new Set([...(live.get(p) ?? []), this.deps.replicaId])].sort();
265
+ const rank = members.indexOf(this.deps.replicaId);
266
+ out.set(p, shareTarget(runnable.get(p) ?? 0, members.length, shareSlack, rank));
267
+ }
268
+ return out;
269
+ }
270
+ heldOf(plugin) {
271
+ let n = 0;
272
+ for (const h of this.held.values())
273
+ if (h.plugin === plugin)
274
+ n++;
275
+ return n;
276
+ }
277
+ /**
278
+ * Gives back the most recently connected connection of `plugin`, leaving a handoff marker first;
279
+ * once its lease is released, nudges the other replicas to claim it.
280
+ */
281
+ async handOff(plugin) {
282
+ let latest;
283
+ for (const e of this.held) {
284
+ if (e[1].plugin !== plugin)
285
+ continue;
286
+ if (!latest || e[1].startedAt > latest[1].startedAt)
287
+ latest = e;
288
+ }
289
+ if (!latest)
290
+ return;
291
+ const [id] = latest;
292
+ const px = this.deps.config().channels.scanIntervalMs * 2;
293
+ await this.deps.redis.set(channelHandoffKey(id), this.deps.replicaId, "PX", px);
294
+ this.releaseInBackground(id, this.nudge(plugin));
295
+ }
296
+ /** After-release callback: tells the other replicas a connection of `plugin` is free to claim. */
297
+ nudge(plugin) {
298
+ return () => this.deps.bus
299
+ .publish(CHANNEL_HANDOFF_TOPIC, { plugin, replicaId: this.deps.replicaId })
300
+ .catch((err) => this.deps.log.warn("cannot publish channel handoff", { err }));
301
+ }
302
+ async afterRenew(id, h, ok, ttl) {
303
+ if (!ok) {
304
+ this.deps.log.warn("channel lease lost; disconnecting", { connectionId: id });
305
+ this.drop(id, h);
306
+ return;
307
+ }
308
+ h.renewedAt = Date.now();
309
+ if (!h.stable && Date.now() - h.startedAt >= ttl) {
310
+ h.stable = true;
311
+ await this.deps.redis.del(channelFailsKey(id)).catch(() => { });
312
+ }
313
+ }
314
+ /**
315
+ * 可以持有的连接:active、未删除、所属组织未删除、插件在该组织启用(组织停用插件 / 删除组织时持有方据此断开),
316
+ * 且插件在本进程已加载——滚动升级期间还没有该插件的副本根本不考虑它(不取租约、不记失败),留给有插件的副本。
317
+ */
318
+ runnable(plugins) {
319
+ return (this.deps.db
320
+ .selectFrom("channel_connections")
321
+ .innerJoin("orgs", "orgs.id", "channel_connections.org_id")
322
+ .innerJoin(enabledExtensionsByOrg(this.deps.db).as("en"), (j) => j
323
+ .onRef("en.plugin", "=", "channel_connections.plugin")
324
+ .onRef("en.org_id", "=", "channel_connections.org_id"))
325
+ .select(["channel_connections.id", "channel_connections.plugin"])
326
+ .where("channel_connections.status", "=", "active")
327
+ // Webhook-mode connections get callbacks on the gateway route instead (F9)
328
+ .where("channel_connections.inbound_mode", "=", "long_connection")
329
+ .where("channel_connections.deleted_at", "is", null)
330
+ .where("orgs.deleted_at", "is", null)
331
+ .where("channel_connections.plugin", "in", plugins));
332
+ }
333
+ /**
334
+ * 持有的连接仍须可持有(bus 广播是尽力而为,这里兜底)。交还不等待:交还要等插件 `connect` 返回(至多 SETTLE_MS),
335
+ * 不能让一个迟迟不退出的插件拖住扫描。
336
+ */
337
+ async recheckHeld() {
338
+ const ids = [...this.held.keys()];
339
+ if (ids.length === 0)
340
+ return;
341
+ const plugins = this.deps.localPlugins();
342
+ const live = new Set(plugins.length === 0
343
+ ? []
344
+ : (await this.runnable(plugins).where("channel_connections.id", "in", ids).execute()).map((r) => r.id));
345
+ for (const id of ids) {
346
+ const h = this.held.get(id);
347
+ if (h && !live.has(id))
348
+ this.releaseInBackground(id, this.nudge(h.plugin));
349
+ }
350
+ }
351
+ /**
352
+ * One scan round, per channel plugin (Ruling R3): above that plugin's share, give back one of its
353
+ * connections (never more, so this replica does not drop below its target) and claim none of it;
354
+ * otherwise claim unheld ones up to the target. `claimOnly` (a handoff nudge) never gives back.
355
+ */
356
+ async scan(claimOnly) {
357
+ if (this.stopped)
358
+ return;
359
+ this.deps.onScan?.(claimOnly);
360
+ const plugins = this.deps.localPlugins();
361
+ if (plugins.length === 0)
362
+ return;
363
+ const rows = await this.runnable(plugins).execute();
364
+ const runnable = new Map();
365
+ for (const r of rows)
366
+ runnable.set(r.plugin, (runnable.get(r.plugin) ?? 0) + 1);
367
+ const targets = await this.targets(runnable);
368
+ const full = new Set();
369
+ for (const [p, target] of targets) {
370
+ const held = this.heldOf(p);
371
+ if (held > target && !claimOnly)
372
+ await this.handOff(p);
373
+ if (held >= target)
374
+ full.add(p);
375
+ }
376
+ for (const { id, plugin } of rows) {
377
+ if (this.stopped)
378
+ return;
379
+ if (full.has(plugin))
380
+ continue;
381
+ if (this.heldOf(plugin) >= (targets.get(plugin) ?? 0)) {
382
+ full.add(plugin);
383
+ continue;
384
+ }
385
+ if (this.held.has(id))
386
+ continue;
387
+ if ((await this.deps.redis.exists(channelBackoffKey(id))) === 1)
388
+ continue;
389
+ if ((await this.deps.redis.get(channelHandoffKey(id))) === this.deps.replicaId)
390
+ continue;
391
+ const token = randomUUID();
392
+ const ttl = this.deps.config().channels.leaseTtlMs;
393
+ const ok = await this.deps.redis.set(channelLeaseKey(id), token, "PX", ttl, "NX");
394
+ if (ok !== "OK")
395
+ continue;
396
+ if (this.stopped) {
397
+ await this.releaseLease(id, token);
398
+ return;
399
+ }
400
+ await this.connect(id, token);
401
+ }
402
+ }
403
+ /** 已取得租约:读配置并在后台跑插件的 `connect`。 */
404
+ async connect(id, token) {
405
+ const pending = { reconnect: false };
406
+ this.connecting.set(id, pending);
407
+ let rt;
408
+ try {
409
+ rt = await this.deps.connections.runtime(id);
410
+ }
411
+ catch (err) {
412
+ this.connecting.delete(id);
413
+ await this.failed(id, err);
414
+ await this.releaseLease(id, token);
415
+ return;
416
+ }
417
+ // 插件异常信息可能带上凭据:写进 last_error / 日志前按该连接的密钥打码
418
+ const redact = createRedactor(secretValues(rt.channel.connectionSchema, rt.config), 4);
419
+ const abort = new AbortController();
420
+ const now = Date.now();
421
+ const h = {
422
+ plugin: rt.row.plugin,
423
+ token,
424
+ abort,
425
+ done: Promise.resolve(),
426
+ startedAt: now,
427
+ renewedAt: now,
428
+ stable: false,
429
+ };
430
+ this.held.set(id, h);
431
+ this.connecting.delete(id);
432
+ h.done = (async () => {
433
+ try {
434
+ await rt.channel.connect({
435
+ connectionId: id,
436
+ config: rt.config,
437
+ onEvent: (e) => this.track(this.deps.onEvent(id, e)),
438
+ signal: abort.signal,
439
+ });
440
+ if (!abort.signal.aborted)
441
+ throw new Error("connect returned before it was aborted");
442
+ }
443
+ catch (err) {
444
+ if (abort.signal.aborted)
445
+ return;
446
+ await this.failed(id, err, redact);
447
+ }
448
+ finally {
449
+ // 自己结束(出错 / 提前返回):交还租约,退避后由任一副本重试
450
+ if (!abort.signal.aborted && this.held.get(id) === h) {
451
+ this.held.delete(id);
452
+ await this.releaseLease(id, token);
453
+ }
454
+ }
455
+ })();
456
+ // 读配置期间收到了重连广播(配置可能已在读取之后改过):立即交还,下一轮按新配置重连
457
+ if (pending.reconnect)
458
+ this.releaseInBackground(id);
459
+ }
460
+ /** 记下进行中的 `onEvent`,原样返回(结果与异常都交给插件)。 */
461
+ track(p) {
462
+ const t = p.then(() => { }, () => { });
463
+ this.inflight.add(t);
464
+ void t.then(() => this.inflight.delete(t));
465
+ return p;
466
+ }
467
+ /** 记录失败:`last_error`、连续失败计数与退避标记(都跨副本可见)。 */
468
+ async failed(id, err, redact) {
469
+ const raw = errMsg(err);
470
+ const message = (redact ? redact(raw) : raw).slice(0, MAX_ERROR_CHARS);
471
+ this.deps.log.warn("channel connection failed", { connectionId: id, error: message });
472
+ try {
473
+ const fails = await this.deps.redis.incr(channelFailsKey(id));
474
+ await this.deps.redis.expire(channelFailsKey(id), FAILS_TTL_SECONDS);
475
+ const delay = Math.min(MAX_BACKOFF_MS, this.deps.config().channels.retryBaseMs * 2 ** Math.min(fails - 1, 20));
476
+ await this.deps.redis.set(channelBackoffKey(id), "1", "PX", delay);
477
+ await this.deps.db
478
+ .updateTable("channel_connections")
479
+ .set({ last_error: message })
480
+ .where("id", "=", id)
481
+ .execute();
482
+ }
483
+ catch (e) {
484
+ this.deps.log.warn("cannot record channel failure", { connectionId: id, err: e });
485
+ }
486
+ }
487
+ /** 租约已丢:中止,不释放(已不是自己的)。 */
488
+ drop(id, h) {
489
+ if (this.held.get(id) === h)
490
+ this.held.delete(id);
491
+ h.abort.abort();
492
+ }
493
+ /** 后台交还,记入 `releasing` 供 `stop()` 等待;`after` runs once the lease is released. */
494
+ releaseInBackground(id, after) {
495
+ const p = this.release(id)
496
+ .then(async (released) => {
497
+ if (released && after)
498
+ await after();
499
+ })
500
+ .finally(() => this.releasing.delete(p));
501
+ this.releasing.add(p);
502
+ }
503
+ /** 主动交还:中止,等 `connect` 返回(至多 SETTLE_MS)后释放租约;超时则让租约自然过期,避免两边同时在线。 */
504
+ async release(id) {
505
+ const h = this.held.get(id);
506
+ if (!h)
507
+ return false;
508
+ this.held.delete(id);
509
+ this.settling.set(id, h.token);
510
+ h.abort.abort();
511
+ let timer;
512
+ const settled = await Promise.race([
513
+ h.done.then(() => true),
514
+ new Promise((r) => {
515
+ timer = setTimeout(() => r(false), SETTLE_MS);
516
+ timer.unref?.();
517
+ }),
518
+ ]);
519
+ clearTimeout(timer);
520
+ if (this.settling.get(id) === h.token)
521
+ this.settling.delete(id);
522
+ if (settled)
523
+ await this.releaseLease(id, h.token);
524
+ else
525
+ this.deps.log.warn("channel connect did not stop in time; lease left to expire", {
526
+ connectionId: id,
527
+ });
528
+ return settled;
529
+ }
530
+ async releaseLease(id, token) {
531
+ try {
532
+ await this.deps.redis.eval(RELEASE, 1, channelLeaseKey(id), token);
533
+ }
534
+ catch (err) {
535
+ this.deps.log.warn("cannot release channel lease", { connectionId: id, err });
536
+ }
537
+ }
538
+ /**
539
+ * 本进程的插件实例变了(撤销、替换为新实例;内核接 `host.onChange`,C17):交还该插件持有的全部长连接
540
+ * (中止旧实例的 `connect`、等它返回后释放租约)。插件仍在本进程(新实例)时,下一轮扫描由任一副本按新实例重新选主;
541
+ * 已撤销则本副本不再考虑它(`localPlugins` 里没有了)。
542
+ */
543
+ pluginChanged(plugin) {
544
+ if (this.stopped)
545
+ return;
546
+ for (const [id, h] of this.held) {
547
+ if (h.plugin === plugin)
548
+ this.releaseInBackground(id, this.nudge(plugin));
549
+ }
550
+ }
551
+ /** 停机:停止扫描,中止全部长连接并释放租约。幂等。 */
552
+ async stop() {
553
+ this.stopped = true;
554
+ for (const st of this.loops)
555
+ clearTimeout(st.timer);
556
+ await Promise.all(this.loops.map((st) => st.running?.catch(() => { })));
557
+ await this.unsubscribe?.().catch(() => { });
558
+ this.unsubscribe = undefined;
559
+ await this.unsubscribeHandoff?.().catch(() => { });
560
+ this.unsubscribeHandoff = undefined;
561
+ // A nudged scan may still be claiming: let it finish so its leases are released below
562
+ await this.scanChain;
563
+ // Leave the share first so the other gateways count one replica fewer right away
564
+ await Promise.all([...this.heartbeated].map((p) => this.deps.redis.zrem(gatewayReplicasKey(p), this.deps.replicaId).catch((err) => {
565
+ this.deps.log.warn("cannot remove gateway heartbeat", { plugin: p, err });
566
+ })));
567
+ this.heartbeated.clear();
568
+ await Promise.all([...this.held.keys()].map((id) => this.release(id)));
569
+ // 别处发起、仍在进行的交还(bus 广播、复核)也要等完,租约才都释放了
570
+ await Promise.all([...this.releasing]);
571
+ // 插件交来的事件已在入队途中:等它们结束(之后内核才关闭队列)
572
+ await Promise.all([...this.inflight]);
573
+ }
574
+ }
575
+ /** Maintenance job that warns when channel connections need a gateway and none is live (Ruling R1). */
576
+ export const GATEWAY_CHECK_JOB = "channel-gateway-check";
577
+ export const GATEWAY_CHECK_SCHEDULER_ID = "channel-gateway-check-every";
578
+ export const GATEWAY_CHECK_EVERY_MS = 60_000;
579
+ /**
580
+ * Runs on the worker role (maintenance queue), per channel plugin (Ruling R3): when a plugin has
581
+ * active connections (not deleted, org not deleted, plugin enabled for the org; long connection or
582
+ * webhook mode, Ruling R4) but no gateway replica with that plugin loaded has a heartbeat newer than
583
+ * one lease TTL (Redis server clock), nobody holds those long connections or answers their webhooks.
584
+ * - Logs one `warn` (naming the plugins) per interval at most across the cluster: a Redis
585
+ * `SET NX PX` rate limit a little shorter than the job period, so a duplicated job or several
586
+ * worker replicas do not repeat it while each period still gets its line.
587
+ * - Silent before `graceUntil` (this process's start + one lease TTL), so a fresh cluster does not
588
+ * warn before the gateways' first heartbeat.
589
+ * Returns whether it warned.
590
+ */
591
+ export async function checkGatewayPresence(deps) {
592
+ if (deps.graceUntil !== undefined && Date.now() < deps.graceUntil)
593
+ return false;
594
+ // Webhook-mode connections count too (Ruling R4): the webhook route is served only by gateway
595
+ // replicas, so without one their callbacks get no answer either
596
+ const rows = await deps.db
597
+ .selectFrom("channel_connections")
598
+ .innerJoin("orgs", "orgs.id", "channel_connections.org_id")
599
+ .innerJoin(enabledExtensionsByOrg(deps.db).as("en"), (j) => j
600
+ .onRef("en.plugin", "=", "channel_connections.plugin")
601
+ .onRef("en.org_id", "=", "channel_connections.org_id"))
602
+ .select(["channel_connections.plugin", (eb) => eb.fn.countAll().as("n")])
603
+ .where("channel_connections.status", "=", "active")
604
+ .where("channel_connections.deleted_at", "is", null)
605
+ .where("orgs.deleted_at", "is", null)
606
+ .groupBy("channel_connections.plugin")
607
+ .execute();
608
+ const counts = new Map(rows.map((r) => [r.plugin, Number(r.n)]));
609
+ const plugins = [...counts.keys()].filter((p) => (counts.get(p) ?? 0) > 0).sort();
610
+ if (plugins.length === 0)
611
+ return false;
612
+ const live = await liveGateways(deps.redis, plugins, deps.config().channels.leaseTtlMs);
613
+ const missing = plugins.filter((p) => (live.get(p) ?? []).length === 0);
614
+ if (missing.length === 0)
615
+ return false;
616
+ const everyMs = deps.everyMs ?? GATEWAY_CHECK_EVERY_MS;
617
+ const first = await deps.redis.set(gatewayMissingWarnedKey, "1", "PX", Math.max(Math.ceil(everyMs / 2), everyMs - 5_000), "NX");
618
+ if (first !== "OK")
619
+ return false;
620
+ deps.log.warn("active channel connections have no live gateway replica with their plugin loaded; add the gateway role to a process (CAPYBARA_ROLES) that can load the plugin, or they receive no messages", {
621
+ plugins: missing,
622
+ connections: missing.reduce((n, p) => n + (counts.get(p) ?? 0), 0),
623
+ });
624
+ return true;
625
+ }
@@ -0,0 +1,29 @@
1
+ import type { ChannelTarget } from "@capybara-hq/plugin-sdk";
2
+ import type { KernelDb } from "../db/kernel-schema.js";
3
+ /**
4
+ * 该组织唯一的匿名访客账号 id;首次使用时创建(`accounts.status = active`、没有任何登录方式、组织角色 guest)。
5
+ * 每次都确保成员关系存在(被移出后再次使用会补回 guest):运行的兜底扫描会中止「发起人已不是该组织成员」的运行。
6
+ * 跨副本并发首次创建用事务级咨询锁串行化,只建一个账号。
7
+ */
8
+ export declare function ensureAnonymousGuest(db: KernelDb, orgId: string): Promise<string>;
9
+ /** 一条 IM 话题的定位:连接 + chat + 话题键 + 账号(匿名为 null)。 */
10
+ export interface ThreadKey {
11
+ connectionId: string;
12
+ chatId: string;
13
+ threadKey: string;
14
+ accountId: string | null;
15
+ }
16
+ /**
17
+ * 话题键:私聊 `dm:<externalId>`;群聊用平台话题 id,消息不在话题里(开启新话题)时用该消息 id——
18
+ * 机器人回复在以它为根的话题里,后续消息的 threadId 就是它,于是落到同一个对话。
19
+ */
20
+ export declare function threadKeyOf(target: ChannelTarget, senderExternalId: string, messageId: string): string;
21
+ /** 未归档的话题行对应的会话;没有返回 undefined。 */
22
+ export declare function findThread(db: KernelDb, k: ThreadKey): Promise<string | undefined>;
23
+ /**
24
+ * 记下话题 → 会话;同一话题已有未归档的行(并发的另一条消息抢先建了)时不写,返回已有的会话 id。
25
+ * 返回实际生效的会话 id。
26
+ */
27
+ export declare function insertThread(db: KernelDb, k: ThreadKey, conversationId: string): Promise<string>;
28
+ /** 私聊 `/new`:归档当前话题行(下一条消息新建对话)。返回是否归档了一行。 */
29
+ export declare function archiveThread(db: KernelDb, k: ThreadKey): Promise<boolean>;