@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,578 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { IMAGE_MEDIA_TYPES, MEDIA_LIMITS, } from "@capybara-hq/plugin-sdk";
3
+ import { sql } from "kysely";
4
+ import { ApiError } from "../errors.js";
5
+ /** 预签名上传的有效期(秒)。尽量短:表单在有效期内可被再次使用(内容替换由 etag 核对兜底)。 */
6
+ export const ATTACHMENT_UPLOAD_TTL_SECONDS = 300;
7
+ /** 下载跳转的预签名有效期(秒);不短于 {@link ATTACHMENT_DOWNLOAD_CACHE_SECONDS}(浏览器缓存的跳转仍可用)。 */
8
+ export const ATTACHMENT_DOWNLOAD_TTL_SECONDS = 300;
9
+ /** 下载 302 的 `Cache-Control: private, max-age=…`(秒):同一页面里缩略图可复用跳转地址。 */
10
+ export const ATTACHMENT_DOWNLOAD_CACHE_SECONDS = 60;
11
+ /** 同一账号在一个组织里最多的未 finalize 附件数(超过 → 429 `attachment.too_many_pending`)。 */
12
+ export const MAX_PENDING_ATTACHMENTS = 50;
13
+ /** 技能包 zip 的内容类型(上传时一律按它签名,finalize 时核对 zip 文件头)。 */
14
+ export const SKILL_PACKAGE_CONTENT_TYPE = "application/zip";
15
+ /** 技能包 zip 的大小上限(字节)。 */
16
+ export const SKILL_PACKAGE_UPLOAD_MAX_BYTES = 50 * 1024 * 1024;
17
+ /** 同一账号在一个组织里最多的未 finalize 技能包上传数(与对话附件分开计数)。 */
18
+ export const MAX_PENDING_SKILL_PACKAGES = 5;
19
+ /**
20
+ * 技能包上传的过期时间(小时):没被 `POST /skills` 用掉的由清理任务删除(不跟对话附件的 `unboundTtlHours`);
21
+ * `POST /skills` 开始处理时再顺延这么久,处理期间不会被清理。
22
+ */
23
+ export const SKILL_PACKAGE_TTL_HOURS = 1;
24
+ /**
25
+ * 技能包解出的文件在 `kernel/<orgId>/` 下的前缀:按上传 id,同一上传重试写到同一批键(幂等),
26
+ * 并发处理同一上传也不会互相覆盖出不同内容。版本行记下这个前缀(`skill_versions.object_prefix`)。
27
+ */
28
+ export const skillFilesPrefix = (uploadId) => `skills/${uploadId}/`;
29
+ /** 维护任务:清理过期未绑定的附件(任务名与 scheduler id 不含 `:`)。 */
30
+ export const ATTACHMENT_CLEANUP_JOB = "attachment-cleanup";
31
+ export const ATTACHMENT_CLEANUP_SCHEDULER_ID = "attachment-cleanup-hourly";
32
+ export const ATTACHMENT_CLEANUP_EVERY_MS = 3_600_000;
33
+ /** 每批认领的行数。 */
34
+ const CLEANUP_BATCH = 100;
35
+ /** finalize 时读取开头多少字节核对文件签名。 */
36
+ const SNIFF_BYTES = 1024;
37
+ const notFound = () => new ApiError("attachment.not_found", "Attachment not found");
38
+ /** 去掉参数、转小写:`Text/Plain; charset=utf-8` → `text/plain`。 */
39
+ export const normalizeContentType = (ct) => (ct.split(";")[0] ?? "").trim().toLowerCase();
40
+ const isImage = (ct) => IMAGE_MEDIA_TYPES.includes(ct);
41
+ /** 对象键:只用附件 id,用户的文件名不进键。技能包另放 `skill-packages/<id>`。 */
42
+ const objectKey = (id, purpose = "chat") => purpose === "chat" ? `attachments/${id}` : `skill-packages/${id}`;
43
+ const startsWith = (b, sig, at = 0) => sig.every((x, i) => b[at + i] === x);
44
+ const ascii = (s) => [...s].map((c) => c.charCodeAt(0));
45
+ /** 文件开头是否与声明的类型相符(图片与 PDF 看签名,文本不能含 NUL)。 */
46
+ export function sniffMatches(contentType, head) {
47
+ switch (contentType) {
48
+ case "image/png":
49
+ return startsWith(head, [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);
50
+ case "image/jpeg":
51
+ return startsWith(head, [0xff, 0xd8, 0xff]);
52
+ case "image/gif":
53
+ return startsWith(head, ascii("GIF87a")) || startsWith(head, ascii("GIF89a"));
54
+ case "image/webp":
55
+ return startsWith(head, ascii("RIFF")) && startsWith(head, ascii("WEBP"), 8);
56
+ case "application/pdf":
57
+ return Buffer.from(head.buffer, head.byteOffset, head.byteLength).includes("%PDF-");
58
+ case "application/zip":
59
+ // 本地文件头,或空 zip 的中央目录结尾
60
+ return (startsWith(head, [0x50, 0x4b, 0x03, 0x04]) || startsWith(head, [0x50, 0x4b, 0x05, 0x06]));
61
+ default:
62
+ return !head.includes(0);
63
+ }
64
+ }
65
+ /**
66
+ * PDF 的页数:数未压缩的页对象(`/Type /Page`,不含 `/Pages`)。页对象放在压缩的对象流里时数不到,返回 0。
67
+ */
68
+ export function countPdfPages(bytes) {
69
+ const text = Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength).toString("latin1");
70
+ return text.match(/\/Type\s*\/Page(?![A-Za-z])/g)?.length ?? 0;
71
+ }
72
+ async function readAll(body) {
73
+ return new Uint8Array(await new Response(body).arrayBuffer());
74
+ }
75
+ /**
76
+ * 对话附件(M5 T3):登记 → 浏览器按预签名直传对象存储 → finalize 核对 → 发消息时绑定到会话。
77
+ * 字节只在对象存储(`kernel/<orgId>/attachments/<id>`),日志里只有引用;构建模型请求时经 {@link fetchMedia} 取字节。
78
+ * 无进程内状态,可多副本共用。
79
+ */
80
+ export class AttachmentsService {
81
+ d;
82
+ constructor(d) {
83
+ this.d = d;
84
+ }
85
+ /** 单个附件的大小上限:配置的 `maxBytes`,图片再受 `MEDIA_LIMITS.imageBytes` 限制。 */
86
+ limitFor(contentType) {
87
+ const { maxBytes } = this.d.config().attachments;
88
+ return Math.min(maxBytes, isImage(contentType) ? MEDIA_LIMITS.imageBytes : MEDIA_LIMITS.documentBytes);
89
+ }
90
+ /** 当前配置下的上限(不需要对象存储)。 */
91
+ limits() {
92
+ const cfg = this.d.config().attachments;
93
+ return {
94
+ types: [...cfg.allowedTypes],
95
+ maxBytes: Math.min(cfg.maxBytes, MEDIA_LIMITS.documentBytes),
96
+ imageMaxBytes: Math.min(cfg.maxBytes, MEDIA_LIMITS.imageBytes),
97
+ maxPerMessage: cfg.maxPerMessage,
98
+ requestMediaBytes: cfg.requestMediaBytes,
99
+ available: this.d.storage.available,
100
+ };
101
+ }
102
+ /**
103
+ * 登记一个附件(`pending`)并返回预签名上传:存储端按声明的大小与类型限制上传。
104
+ * 类型不在 `attachments.allowedTypes` → `attachment.type_not_allowed`;超过上限 → `attachment.too_large`;
105
+ * 该账号在组织里已有 {@link MAX_PENDING_ATTACHMENTS} 个未 finalize 的附件 → `attachment.too_many_pending`
106
+ * (软上限:并发登记可能略超);没有对象存储 → `storage.unavailable`。
107
+ */
108
+ async create(orgId, accountId, input, purpose = "chat") {
109
+ this.d.storage.assertAvailable();
110
+ const cfg = this.d.config().attachments;
111
+ const contentType = normalizeContentType(input.contentType);
112
+ const skill = purpose === "skill-package";
113
+ if (skill
114
+ ? contentType !== SKILL_PACKAGE_CONTENT_TYPE
115
+ : !cfg.allowedTypes.includes(contentType)) {
116
+ throw new ApiError("attachment.type_not_allowed", `Attachment type ${JSON.stringify(contentType)} is not allowed`);
117
+ }
118
+ const limit = skill ? SKILL_PACKAGE_UPLOAD_MAX_BYTES : this.limitFor(contentType);
119
+ if (input.size > limit) {
120
+ throw new ApiError("attachment.too_large", `Attachment is ${input.size} bytes, over the limit of ${limit} bytes`);
121
+ }
122
+ const pending = await this.d.db
123
+ .selectFrom("attachments")
124
+ .select((eb) => eb.fn.countAll().as("n"))
125
+ .where("org_id", "=", orgId)
126
+ .where("account_id", "=", accountId)
127
+ .where("status", "=", "pending")
128
+ .where("purpose", "=", purpose)
129
+ .executeTakeFirst();
130
+ const maxPending = skill ? MAX_PENDING_SKILL_PACKAGES : MAX_PENDING_ATTACHMENTS;
131
+ if (Number(pending?.n ?? 0) >= maxPending) {
132
+ throw new ApiError("attachment.too_many_pending", `Too many unfinished uploads (at most ${maxPending}); finish or wait for them first`);
133
+ }
134
+ const id = randomUUID();
135
+ const key = objectKey(id, purpose);
136
+ const ttlHours = skill ? SKILL_PACKAGE_TTL_HOURS : cfg.unboundTtlHours;
137
+ const upload = await this.d.storage.kernel(orgId).presignPut(key, {
138
+ contentType,
139
+ maxSize: input.size,
140
+ ttlSeconds: ATTACHMENT_UPLOAD_TTL_SECONDS,
141
+ });
142
+ await this.d.db
143
+ .insertInto("attachments")
144
+ .values({
145
+ id,
146
+ org_id: orgId,
147
+ account_id: accountId,
148
+ name: input.name,
149
+ content_type: contentType,
150
+ size: input.size,
151
+ object_key: key,
152
+ status: "pending",
153
+ purpose,
154
+ expires_at: sql `now() + make_interval(hours => ${ttlHours})`,
155
+ })
156
+ .execute();
157
+ return {
158
+ id,
159
+ upload,
160
+ expiresAt: new Date(Date.now() + ATTACHMENT_UPLOAD_TTL_SECONDS * 1000).toISOString(),
161
+ };
162
+ }
163
+ /**
164
+ * 上传完成后核对并标记为 `ready`(只有上传者能做;已 ready 时直接返回):
165
+ * - 对象还不存在 → `attachment.not_ready`;
166
+ * - 大小与声明不符 → 删除已传的对象,大了 `attachment.too_large`、小了 `attachment.not_ready`(可重传);
167
+ * - 存储记录的类型或文件开头的签名与声明不符 → 删除对象,`attachment.type_not_allowed`。
168
+ */
169
+ async finalize(orgId, accountId, id) {
170
+ this.d.storage.assertAvailable();
171
+ const row = await this.d.db
172
+ .selectFrom("attachments")
173
+ .select(["id", "name", "content_type", "size", "object_key", "status"])
174
+ .where("id", "=", id)
175
+ .where("org_id", "=", orgId)
176
+ .where("account_id", "=", accountId)
177
+ .where("status", "in", ["pending", "ready"])
178
+ .executeTakeFirst();
179
+ if (!row)
180
+ throw notFound();
181
+ const view = {
182
+ id: row.id,
183
+ name: row.name,
184
+ contentType: row.content_type,
185
+ size: Number(row.size),
186
+ };
187
+ if (row.status === "ready")
188
+ return view;
189
+ const store = this.d.storage.kernel(orgId);
190
+ const head = await store.head(row.object_key);
191
+ if (!head) {
192
+ throw new ApiError("attachment.not_ready", "The file has not been uploaded yet");
193
+ }
194
+ const reject = async (err) => {
195
+ await store.delete(row.object_key);
196
+ throw err;
197
+ };
198
+ if (head.size !== view.size) {
199
+ await reject(head.size > view.size
200
+ ? new ApiError("attachment.too_large", "Uploaded file is larger than declared")
201
+ : new ApiError("attachment.not_ready", `Uploaded file is ${head.size} bytes, but ${view.size} bytes were declared; upload it again`));
202
+ }
203
+ if (normalizeContentType(head.contentType) !== view.contentType) {
204
+ await reject(new ApiError("attachment.type_not_allowed", "Uploaded file type does not match"));
205
+ }
206
+ // PDF 读全文(数页数,供 token 估算);其他类型只读开头核对签名
207
+ const pdf = view.contentType === "application/pdf";
208
+ const got = await store.get(row.object_key, pdf ? {} : { range: { start: 0, end: Math.max(0, Math.min(view.size, SNIFF_BYTES) - 1) } });
209
+ const data = got ? await readAll(got.body) : new Uint8Array();
210
+ const pages = pdf ? countPdfPages(data) || null : null;
211
+ if (!sniffMatches(view.contentType, data.subarray(0, SNIFF_BYTES))) {
212
+ await reject(new ApiError("attachment.type_not_allowed", `Uploaded file content is not ${view.contentType}`));
213
+ }
214
+ await this.d.db
215
+ .updateTable("attachments")
216
+ .set({ status: "ready", etag: got?.head.etag ?? head.etag ?? null, pages })
217
+ .where("id", "=", id)
218
+ .where("status", "=", "pending")
219
+ .execute();
220
+ return view;
221
+ }
222
+ /**
223
+ * 下载地址(预签名,{@link ATTACHMENT_DOWNLOAD_TTL_SECONDS} 秒):已绑定的附件要求能访问其会话,
224
+ * 未绑定的只有上传者;否则 `attachment.not_found`。只有图片与 PDF 以 `inline` 打开,其余一律 `attachment`
225
+ * (即使存储里的类型被改成 text/html 也不会在页面里渲染);响应类型按 finalize 核对过的类型返回。
226
+ */
227
+ async downloadUrl(orgId, accountId, id) {
228
+ this.d.storage.assertAvailable();
229
+ const row = await this.d.db
230
+ .selectFrom("attachments")
231
+ .select(["account_id", "conversation_id", "name", "content_type", "object_key", "etag"])
232
+ .where("id", "=", id)
233
+ .where("org_id", "=", orgId)
234
+ .where("status", "=", "ready")
235
+ .where("purpose", "=", "chat")
236
+ .executeTakeFirst();
237
+ if (!row)
238
+ throw notFound();
239
+ const allowed = row.conversation_id === null
240
+ ? row.account_id === accountId
241
+ : await this.d.canAccessConversation(orgId, row.conversation_id, accountId);
242
+ if (!allowed)
243
+ throw notFound();
244
+ const store = this.d.storage.kernel(orgId);
245
+ const head = await store.head(row.object_key);
246
+ if (!head || !this.sameContent(row.etag, head.etag, { orgId, attachmentId: id })) {
247
+ throw notFound();
248
+ }
249
+ const inline = isImage(row.content_type) || row.content_type === "application/pdf";
250
+ return store.presignGet(row.object_key, {
251
+ ttlSeconds: ATTACHMENT_DOWNLOAD_TTL_SECONDS,
252
+ downloadName: row.name,
253
+ disposition: inline ? "inline" : "attachment",
254
+ responseContentType: row.content_type,
255
+ });
256
+ }
257
+ /**
258
+ * 绑定在该会话、已 ready 的附件(id 与原始文件名),按上传时间、id 排序(沙箱同步按这个顺序分配文件名)。
259
+ */
260
+ async listForConversation(orgId, conversationId) {
261
+ return this.d.db
262
+ .selectFrom("attachments")
263
+ .select(["id", "name"])
264
+ .where("org_id", "=", orgId)
265
+ .where("conversation_id", "=", conversationId)
266
+ .where("purpose", "=", "chat")
267
+ .where("status", "=", "ready")
268
+ .orderBy("created_at")
269
+ .orderBy("id")
270
+ .execute();
271
+ }
272
+ /**
273
+ * 读取一个绑定在该会话、已 ready 的附件(沙箱同步等内核内部用途):没有行、未绑定到该会话、对象已不在、
274
+ * 大小或 etag 与 finalize 时不符 → null。其余错误(存储不可用等)照常抛出。调用方负责读完或取消 `body`。
275
+ */
276
+ async openForConversation(orgId, conversationId, attachmentId) {
277
+ const row = await this.d.db
278
+ .selectFrom("attachments")
279
+ .select(["name", "content_type", "object_key", "size", "etag"])
280
+ .where("id", "=", attachmentId)
281
+ .where("org_id", "=", orgId)
282
+ .where("conversation_id", "=", conversationId)
283
+ .where("purpose", "=", "chat")
284
+ .where("status", "=", "ready")
285
+ .executeTakeFirst();
286
+ if (!row)
287
+ return null;
288
+ const got = await this.d.storage.kernel(orgId).get(row.object_key);
289
+ if (!got)
290
+ return null;
291
+ const size = Number(row.size);
292
+ if (got.head.size !== size ||
293
+ !this.sameContent(row.etag, got.head.etag, { orgId, conversationId, attachmentId })) {
294
+ await got.body.cancel().catch(() => { });
295
+ return null;
296
+ }
297
+ return { name: row.name, contentType: row.content_type, size, body: got.body };
298
+ }
299
+ /**
300
+ * 发消息时在调用方事务里绑定附件(行锁),返回写进 user_message 的媒体块(`ref`,按 ids 顺序):
301
+ * - 超过 `attachments.maxPerMessage`、或同一个 id 出现多次 → `validation_failed`;
302
+ * - 不存在、不是发送者上传的、已绑定到别的会话、未绑定且已过期 → `attachment.not_found`;
303
+ * - 还没 finalize → `attachment.not_ready`。
304
+ * 后两种的 details 为 `[{ path: "files", message, attachmentId }]`,网页据此标出对应条目。
305
+ * 已绑定到本会话的(重试)照常返回块。
306
+ */
307
+ async bindForMessage(trx, orgId, conversationId, accountId, ids) {
308
+ const unique = [...new Set(ids)];
309
+ const max = this.d.config().attachments.maxPerMessage;
310
+ if (ids.length > max) {
311
+ throw new ApiError("validation_failed", "Request validation failed", [
312
+ { path: "files", message: `At most ${max} files per message` },
313
+ ]);
314
+ }
315
+ if (unique.length !== ids.length) {
316
+ throw new ApiError("validation_failed", "Request validation failed", [
317
+ { path: "files", message: "Each file may appear only once per message" },
318
+ ]);
319
+ }
320
+ if (unique.length === 0)
321
+ return [];
322
+ const rows = await trx
323
+ .selectFrom("attachments")
324
+ .select([
325
+ "id",
326
+ "account_id",
327
+ "conversation_id",
328
+ "name",
329
+ "content_type",
330
+ "status",
331
+ sql `expires_at IS NOT NULL AND expires_at <= now()`.as("expired"),
332
+ ])
333
+ .where("org_id", "=", orgId)
334
+ .where("id", "in", unique)
335
+ // 技能包上传不能当附件发出(当作不存在)
336
+ .where("purpose", "=", "chat")
337
+ .orderBy("id")
338
+ .forUpdate()
339
+ .execute();
340
+ const byId = new Map(rows.map((r) => [r.id, r]));
341
+ const blocks = [];
342
+ const toBind = [];
343
+ for (const id of unique) {
344
+ const r = byId.get(id);
345
+ if (!r ||
346
+ r.account_id !== accountId ||
347
+ r.status === "deleting" ||
348
+ (r.conversation_id !== null && r.conversation_id !== conversationId) ||
349
+ (r.conversation_id === null && r.expired)) {
350
+ const message = `Attachment ${id} not found, expired, or already used in another conversation`;
351
+ throw new ApiError("attachment.not_found", message, [
352
+ { path: "files", message, attachmentId: id },
353
+ ]);
354
+ }
355
+ if (r.status !== "ready") {
356
+ const message = `Attachment ${id} has not been finalized`;
357
+ throw new ApiError("attachment.not_ready", message, [
358
+ { path: "files", message, attachmentId: id },
359
+ ]);
360
+ }
361
+ if (r.conversation_id === null)
362
+ toBind.push(id);
363
+ const source = { kind: "ref", attachmentId: id };
364
+ blocks.push(isImage(r.content_type)
365
+ ? { type: "image", mediaType: r.content_type, source, name: r.name }
366
+ : {
367
+ type: "document",
368
+ mediaType: r.content_type,
369
+ source,
370
+ name: r.name,
371
+ });
372
+ }
373
+ if (toBind.length > 0) {
374
+ await trx
375
+ .updateTable("attachments")
376
+ .set({ conversation_id: conversationId, expires_at: null })
377
+ .where("id", "in", toBind)
378
+ .execute();
379
+ }
380
+ return blocks;
381
+ }
382
+ /** 下载 / 取字节时核对 etag:finalize 记下的与当前对象的不一致 → 内容被替换(记 warn)。没有记录时不核对。 */
383
+ sameContent(recorded, current, where) {
384
+ if (recorded === null || recorded === (current ?? null))
385
+ return true;
386
+ this.d.log.warn("attachment content changed after finalize; treating it as unavailable", where);
387
+ return false;
388
+ }
389
+ /**
390
+ * 构建模型请求时查附件行的声明信息(只含绑定在该会话、已 ready 的):大小与 PDF 页数。
391
+ * 没有行的不在结果里;查询失败照常抛出。
392
+ */
393
+ async mediaInfo(orgId, conversationId, ids) {
394
+ if (ids.length === 0)
395
+ return new Map();
396
+ const rows = await this.d.db
397
+ .selectFrom("attachments")
398
+ .select(["id", "size", "pages", "etag"])
399
+ .where("org_id", "=", orgId)
400
+ .where("conversation_id", "=", conversationId)
401
+ .where("purpose", "=", "chat")
402
+ .where("status", "=", "ready")
403
+ .where("id", "in", [...ids])
404
+ .execute();
405
+ return new Map(rows.map((r) => [r.id, { size: Number(r.size), pages: r.pages, etag: r.etag }]));
406
+ }
407
+ /**
408
+ * 构建模型请求时取附件字节:只取绑定在该会话、已 ready 的附件。只有「确定不存在」才为 null:没有行、对象已不在、
409
+ * 大小或 etag 与 finalize 时不符(内容被替换,记 warn)。其余错误(存储不可用、网络错误)一律抛出(Ruling M4),
410
+ * 由调用方按可重试处理,不会变成占位。`caps` 里的附件只按范围读开头若干字节(`text/*` 封顶,更后面的不取)。
411
+ */
412
+ async fetchMedia(orgId, conversationId, ids, caps) {
413
+ const out = new Map();
414
+ if (ids.length === 0)
415
+ return out;
416
+ const rows = await this.d.db
417
+ .selectFrom("attachments")
418
+ .select(["id", "content_type", "object_key", "size", "etag"])
419
+ .where("org_id", "=", orgId)
420
+ .where("conversation_id", "=", conversationId)
421
+ .where("purpose", "=", "chat")
422
+ .where("status", "=", "ready")
423
+ .where("id", "in", [...ids])
424
+ .execute();
425
+ const byId = new Map(rows.map((r) => [r.id, r]));
426
+ const store = this.d.storage.kernel(orgId);
427
+ await Promise.all(ids.map(async (id) => {
428
+ const r = byId.get(id);
429
+ if (!r)
430
+ return out.set(id, null);
431
+ const cap = caps?.get(id);
432
+ const want = cap !== undefined && cap < Number(r.size) ? Math.max(1, cap) : Number(r.size);
433
+ const got = await store.get(r.object_key, want < Number(r.size) ? { range: { start: 0, end: want - 1 } } : undefined);
434
+ if (!got)
435
+ return out.set(id, null);
436
+ const where = { orgId, conversationId, attachmentId: id };
437
+ if (got.head.size !== Number(r.size) || !this.sameContent(r.etag, got.head.etag, where)) {
438
+ if (got.head.size !== Number(r.size)) {
439
+ this.d.log.warn("attachment size changed after finalize; treating it as unavailable", where);
440
+ }
441
+ await got.body.cancel().catch(() => { });
442
+ return out.set(id, null);
443
+ }
444
+ // 提供方没按范围读、给了整个对象时只留开头
445
+ const all = await readAll(got.body);
446
+ const data = all.byteLength === Number(r.size) ? all.subarray(0, want) : all;
447
+ out.set(id, data.byteLength === want ? { mediaType: r.content_type, data } : null);
448
+ }));
449
+ return out;
450
+ }
451
+ /**
452
+ * 取一个技能包上传的字节,供 `POST /skills` 解包(只有上传者、只认 `skill-package` 用途):
453
+ * 还没 finalize 的先 finalize(核对大小与 zip 文件头);过期时间顺延 {@link SKILL_PACKAGE_TTL_HOURS} 小时,
454
+ * 处理期间不会被清理任务删掉。不存在、不是技能包、已用掉或已过期 → `attachment.not_found`;
455
+ * 对象已不在或内容与 finalize 时不符 → `attachment.not_found`。
456
+ */
457
+ async readSkillPackage(orgId, accountId, id) {
458
+ this.d.storage.assertAvailable();
459
+ const row = await this.d.db
460
+ .selectFrom("attachments")
461
+ .select(["status", "purpose", sql `expires_at <= now()`.as("expired")])
462
+ .where("id", "=", id)
463
+ .where("org_id", "=", orgId)
464
+ .where("account_id", "=", accountId)
465
+ .executeTakeFirst();
466
+ if (row?.purpose !== "skill-package" || row.status === "deleting" || row.expired) {
467
+ throw notFound();
468
+ }
469
+ if (row.status === "pending")
470
+ await this.finalize(orgId, accountId, id);
471
+ const live = await this.d.db
472
+ .updateTable("attachments")
473
+ .set({ expires_at: sql `now() + make_interval(hours => ${SKILL_PACKAGE_TTL_HOURS})` })
474
+ .where("id", "=", id)
475
+ .where("status", "=", "ready")
476
+ .where("purpose", "=", "skill-package")
477
+ .returning(["object_key", "size", "etag"])
478
+ .executeTakeFirst();
479
+ if (!live)
480
+ throw notFound();
481
+ const got = await this.d.storage.kernel(orgId).get(live.object_key);
482
+ if (!got)
483
+ throw notFound();
484
+ if (got.head.size !== Number(live.size) ||
485
+ !this.sameContent(live.etag, got.head.etag, { orgId, attachmentId: id })) {
486
+ await got.body.cancel().catch(() => { });
487
+ throw notFound();
488
+ }
489
+ return readAll(got.body);
490
+ }
491
+ /**
492
+ * 在调用方事务里把技能包上传标记为已用掉(行锁;之后由清理任务删 zip,解出的文件因被版本引用而保留)。
493
+ * 不是该账号的 ready 技能包(如已被并发的请求用掉)→ `attachment.not_found`。
494
+ */
495
+ async consumeSkillPackage(trx, orgId, accountId, id) {
496
+ const row = await trx
497
+ .selectFrom("attachments")
498
+ .select("status")
499
+ .where("id", "=", id)
500
+ .where("org_id", "=", orgId)
501
+ .where("account_id", "=", accountId)
502
+ .where("purpose", "=", "skill-package")
503
+ .forUpdate()
504
+ .executeTakeFirst();
505
+ if (row?.status !== "ready")
506
+ throw notFound();
507
+ await trx
508
+ .updateTable("attachments")
509
+ .set({ status: "deleting", expires_at: sql `now()` })
510
+ .where("id", "=", id)
511
+ .execute();
512
+ }
513
+ /**
514
+ * 删除过期(`expires_at < now()`)且从未绑定到会话的附件:先把行认领为 `deleting`(`FOR UPDATE SKIP LOCKED`,
515
+ * 多副本并发时互不重复),再删对象、删行。删对象失败的行保持 `deleting`,下次运行重试。
516
+ * 技能包上传(过期未用掉的,或已被 `POST /skills` 用掉、`expires_at` 置为当时的)同样由这里删 zip;
517
+ * 解出的文件 `skills/<id>/` 只在没有任何技能版本引用时一并删除。
518
+ * 没有对象存储时什么也不做。返回删除的附件数。
519
+ */
520
+ async deleteExpired() {
521
+ if (!this.d.storage.available)
522
+ return 0;
523
+ let deleted = 0;
524
+ const failed = [];
525
+ for (;;) {
526
+ const claimed = await this.d.db
527
+ .updateTable("attachments")
528
+ .set({ status: "deleting" })
529
+ .where("id", "in", this.d.db
530
+ .selectFrom("attachments")
531
+ .select("id")
532
+ .where("conversation_id", "is", null)
533
+ .where("expires_at", "<", sql `now()`)
534
+ .$if(failed.length > 0, (q) => q.where("id", "not in", failed))
535
+ .orderBy("expires_at")
536
+ .limit(CLEANUP_BATCH)
537
+ .forUpdate()
538
+ .skipLocked())
539
+ .returning(["id", "org_id", "object_key", "purpose"])
540
+ .execute();
541
+ if (claimed.length === 0)
542
+ return deleted;
543
+ for (const r of claimed) {
544
+ try {
545
+ const store = this.d.storage.kernel(r.org_id);
546
+ await store.delete(r.object_key);
547
+ if (r.purpose === "skill-package") {
548
+ // 解出的文件没被任何版本引用(处理中途失败、或从未用掉)才删
549
+ const prefix = skillFilesPrefix(r.id);
550
+ const used = await this.d.db
551
+ .selectFrom("skill_versions")
552
+ .select("skill_id")
553
+ .where("object_prefix", "=", prefix)
554
+ .executeTakeFirst();
555
+ if (!used)
556
+ await store.deletePrefix(prefix);
557
+ }
558
+ await this.d.db
559
+ .deleteFrom("attachments")
560
+ .where("id", "=", r.id)
561
+ .where("conversation_id", "is", null)
562
+ .execute();
563
+ deleted++;
564
+ }
565
+ catch (err) {
566
+ failed.push(r.id);
567
+ this.d.log.warn("cannot delete expired attachment; will retry", {
568
+ orgId: r.org_id,
569
+ attachmentId: r.id,
570
+ err,
571
+ });
572
+ }
573
+ }
574
+ if (claimed.length < CLEANUP_BATCH)
575
+ return deleted;
576
+ }
577
+ }
578
+ }