@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,805 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { parseSkillMd, SKILL_ENTRY_FILE, ToolError } from "@capybara-hq/plugin-sdk";
3
+ import { sql } from "kysely";
4
+ import { visibleTo } from "../agents/agents.service.js";
5
+ import { skillFilesPrefix } from "../conversations/attachments.service.js";
6
+ import { ApiError } from "../errors.js";
7
+ import { audit } from "../identity/audit.js";
8
+ import { sameSnapshot, } from "../runtime/context/skills.js";
9
+ import { fitPinned, invocationOf, lockLatestCatalog } from "./catalog.js";
10
+ /**
11
+ * 每个 agent 自己的技能(`scope = agent`)上限,含待批准的新技能。远低于目录快照的上限(`SKILLS_CATALOG_MAX`),
12
+ * 正常使用不会让目录被截断。
13
+ */
14
+ export const AGENT_SKILLS_MAX = 50;
15
+ /** 写技能文件时的并发数。 */
16
+ const PUT_CONCURRENCY = 4;
17
+ /** 详情里读取文件内容的上限(草稿 ≤ 1MB,留余量)。 */
18
+ const DETAIL_MAX_BYTES = 2 * 1024 * 1024;
19
+ /** 收件箱一次最多返回的技能变更数。 */
20
+ export const SKILL_CHANGES_LIST_MAX = 100;
21
+ // ---- 模型可见文案(英文) ----
22
+ const STORAGE_UNAVAILABLE_TEXT = "File storage is temporarily unavailable, so the skill could not be saved; retry later.";
23
+ const pendingElsewhereText = (name) => `Skill "${name}" already has a change awaiting the owner's approval (requested in another conversation), so it cannot be changed now; ask the user to have the owner decide that change first, or use a different skill name.`;
24
+ const capText = () => `This agent already has ${AGENT_SKILLS_MAX} skills (including changes awaiting approval), the maximum; update an existing skill instead, or ask the agent's owner to delete one of this agent's skills.`;
25
+ const AGENT_GONE_TEXT = "This agent no longer exists, so the skill cannot be saved; ask the user to start a conversation with another agent.";
26
+ const iso = (v) => new Date(v).toISOString();
27
+ const byName = (a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0;
28
+ const notFound = () => new ApiError("skill_change.not_found", "Skill change not found");
29
+ /** The body of the SKILL.md a skill_write just stored (as run start would read it); null if unparsable. */
30
+ function writtenBody(pkg) {
31
+ const md = pkg.files.find((f) => f.path === SKILL_ENTRY_FILE);
32
+ if (!md)
33
+ return null;
34
+ try {
35
+ const parsed = parseSkillMd(new TextDecoder("utf-8", { fatal: true }).decode(md.data));
36
+ return "errors" in parsed ? null : parsed.body;
37
+ }
38
+ catch {
39
+ return null;
40
+ }
41
+ }
42
+ /**
43
+ * agent 自写技能与共享 agent 的技能变更审批(M5 T15,R4):
44
+ * - `write`(工具 `skill_write` 调用):私有 agent 直接生成新版本;共享 agent 生成一条待负责人批准的申请,
45
+ * 期间只有发起对话试用(`resolveEffectiveSkills` 按对话合并);两种情况都在同一事务里往发起对话追加一份
46
+ * 技能目录快照(Ruling M17:日志是唯一事实源),同一运行的下一步即可 `skill_load`;
47
+ * - `decide`(HTTP,只有该 agent 当前的负责人):批准 → 版本对所有对话生效(各对话下一次运行开始时写新快照);
48
+ * 拒绝 → 删除草稿对象,发起对话下一次运行开始时目录回到当前版本;
49
+ * - 同一 agent 的同名技能最多一条待处理申请:同一对话再写取代旧的(旧的 cancelled、草稿删除、技能 id 不变),
50
+ * 别的对话再写被拒绝(英文说明)。
51
+ * 状态都在 PG(agent 行锁串行化同一 agent 的写与决定),文件在对象存储 `kernel/<orgId>/skills/<id>/`;无进程内状态。
52
+ */
53
+ export class SkillChangesService {
54
+ d;
55
+ constructor(d) {
56
+ this.d = d;
57
+ }
58
+ /** 写技能(见类注释)。模型可见的失败抛 `ToolError`。 */
59
+ async write(ctx, pkg) {
60
+ const { db, eventLog } = this.d;
61
+ let store;
62
+ try {
63
+ this.d.storage.assertAvailable();
64
+ store = this.d.storage.kernel(ctx.orgId);
65
+ }
66
+ catch (e) {
67
+ throw storageError(e);
68
+ }
69
+ const id = randomUUID();
70
+ const prefix = skillFilesPrefix(id);
71
+ try {
72
+ await putAll(store, prefix, pkg.files);
73
+ }
74
+ catch (e) {
75
+ await this.deletePrefix(ctx.orgId, prefix);
76
+ throw storageError(e);
77
+ }
78
+ let committed;
79
+ try {
80
+ committed = await db.transaction().execute(async (t) => {
81
+ await keyShareOrg(t, ctx.orgId);
82
+ // NO KEY UPDATE, not UPDATE (here, in decide and in deleteAgentSkill): it still serializes
83
+ // the writes and decisions of one agent, but not the foreign key check (FOR KEY SHARE) of a
84
+ // transaction that already holds the conversation row this one locks last, e.g. an event
85
+ // log append updating that row a second time (the title job): FOR UPDATE made that 40P01
86
+ const agent = await t
87
+ .selectFrom("agents")
88
+ .select(["visibility", "deleted_at"])
89
+ .where("id", "=", ctx.agentId)
90
+ .where("org_id", "=", ctx.orgId)
91
+ .forNoKeyUpdate()
92
+ .executeTakeFirst();
93
+ if (!agent || agent.deleted_at !== null)
94
+ throw new ToolError(AGENT_GONE_TEXT);
95
+ // Then the conversation row (appendCatalog's lock, still after the agent row like decide),
96
+ // before the change request insert: its foreign key check takes FOR KEY SHARE on that row,
97
+ // and upgrading to FOR UPDATE afterwards deadlocked with another writer doing the same
98
+ await t
99
+ .selectFrom("conversations")
100
+ .select("id")
101
+ .where("id", "=", ctx.conversationId)
102
+ .forUpdate()
103
+ .execute();
104
+ const existing = await t
105
+ .selectFrom("skills")
106
+ .select(["id", "current_version"])
107
+ .where("org_id", "=", ctx.orgId)
108
+ .where("scope", "=", "agent")
109
+ .where("agent_id", "=", ctx.agentId)
110
+ .where("name", "=", pkg.name)
111
+ .where("deleted_at", "is", null)
112
+ .forUpdate()
113
+ .executeTakeFirst();
114
+ const pend = await t
115
+ .selectFrom("skill_change_requests")
116
+ .selectAll()
117
+ .where("agent_id", "=", ctx.agentId)
118
+ .where("status", "=", "pending")
119
+ .where(sql `proposed_version -> 'manifest' ->> 'name'`, "=", pkg.name)
120
+ .forUpdate()
121
+ .executeTakeFirst();
122
+ const drop = [];
123
+ if (pend) {
124
+ if (pend.requested_in_conversation !== ctx.conversationId) {
125
+ throw new ToolError(pendingElsewhereText(pkg.name));
126
+ }
127
+ // 同一对话再写:取代旧申请
128
+ await t
129
+ .updateTable("skill_change_requests")
130
+ .set({ status: "cancelled", decided_at: sql `now()` })
131
+ .where("id", "=", pend.id)
132
+ .execute();
133
+ drop.push(pend.object_prefix);
134
+ await audit(t, {
135
+ actorAccountId: ctx.accountId,
136
+ orgId: ctx.orgId,
137
+ action: "skill.change_decided",
138
+ target: pend.id,
139
+ detail: {
140
+ decision: "cancelled",
141
+ reason: "superseded",
142
+ supersededBy: id,
143
+ agentId: ctx.agentId,
144
+ name: pkg.name,
145
+ },
146
+ });
147
+ }
148
+ if (!existing)
149
+ await this.assertBelowCap(t, ctx.agentId, pend?.id);
150
+ const version = (existing?.current_version ?? 0) + 1;
151
+ const skillId = existing?.id ?? pend?.proposed_version.skillId ?? randomUUID();
152
+ let outcome;
153
+ if (agent.visibility === "private") {
154
+ await this.createVersion(t, {
155
+ orgId: ctx.orgId,
156
+ agentId: ctx.agentId,
157
+ skillId,
158
+ exists: existing !== undefined,
159
+ version,
160
+ manifest: pkg.manifest,
161
+ prefix,
162
+ createdBy: ctx.accountId,
163
+ });
164
+ await audit(t, {
165
+ actorAccountId: ctx.accountId,
166
+ orgId: ctx.orgId,
167
+ action: existing ? "skill.version_created" : "skill.created",
168
+ target: skillId,
169
+ detail: {
170
+ name: pkg.name,
171
+ version,
172
+ files: pkg.manifest.files.length,
173
+ agentId: ctx.agentId,
174
+ conversationId: ctx.conversationId,
175
+ via: "skill_write",
176
+ },
177
+ });
178
+ outcome = { kind: "version", skillId, version, created: !existing };
179
+ }
180
+ else {
181
+ const proposed = { skillId, version, manifest: pkg.manifest };
182
+ await t
183
+ .insertInto("skill_change_requests")
184
+ .values({
185
+ id,
186
+ org_id: ctx.orgId,
187
+ agent_id: ctx.agentId,
188
+ skill_id: existing?.id ?? null,
189
+ proposed_version: JSON.stringify(proposed),
190
+ object_prefix: prefix,
191
+ requested_by_account: ctx.accountId,
192
+ requested_in_conversation: ctx.conversationId,
193
+ decided_by: null,
194
+ })
195
+ .execute();
196
+ await audit(t, {
197
+ actorAccountId: ctx.accountId,
198
+ orgId: ctx.orgId,
199
+ action: "skill.change_requested",
200
+ target: id,
201
+ detail: {
202
+ agentId: ctx.agentId,
203
+ skillId: existing?.id ?? null,
204
+ name: pkg.name,
205
+ version,
206
+ files: pkg.manifest.files.length,
207
+ conversationId: ctx.conversationId,
208
+ },
209
+ });
210
+ outcome = { kind: "requested", requestId: id, skillId, version };
211
+ }
212
+ // 本对话立即看到新版本:在上一份快照上替换 / 加入这个技能(确定、来自日志;来源 = 本次的对象前缀)
213
+ // A pinned entry of this skill gets the version, source and body just written (phase B)
214
+ // A manual-only version (phase D) is never in the model's catalog: it removes the skill from
215
+ // the snapshot instead, and appendCatalog drops its pinned entry with it (no longer live)
216
+ const forModel = invocationOf(pkg.manifest).model;
217
+ const pinnedBody = writtenBody(pkg);
218
+ const toSeq = await this.appendCatalog(t, ctx.conversationId, (base) => ({
219
+ ...base,
220
+ skills: [
221
+ ...base.skills.filter((s) => s.name !== pkg.name),
222
+ ...(forModel
223
+ ? [
224
+ {
225
+ id: skillId,
226
+ name: pkg.name,
227
+ description: pkg.description,
228
+ version,
229
+ source: prefix,
230
+ },
231
+ ]
232
+ : []),
233
+ ],
234
+ ...(base.pinned && {
235
+ pinned: base.pinned.map((p) => p.id === skillId && pinnedBody !== null
236
+ ? { id: skillId, version, name: pkg.name, source: prefix, body: pinnedBody }
237
+ : p),
238
+ }),
239
+ }), `skills_catalog:write:${id}`, ctx.runId);
240
+ return { outcome, drop, toSeq };
241
+ });
242
+ }
243
+ catch (e) {
244
+ await this.deletePrefix(ctx.orgId, prefix);
245
+ throw e;
246
+ }
247
+ if (committed.toSeq !== null)
248
+ await eventLog.notify(ctx.conversationId, committed.toSeq);
249
+ for (const p of committed.drop)
250
+ await this.deletePrefix(ctx.orgId, p);
251
+ return committed.outcome;
252
+ }
253
+ /**
254
+ * 负责人决定一条申请:只有该 agent 当前的负责人(实时读)能决定,其他人 → 403 `skill_change.not_owner`;
255
+ * 已处理 → 409 `skill_change.already_decided`;agent 已删除或申请不在本组织 → 404。
256
+ * 批准:在同一事务里新增版本(技能不存在则用预先分配的 id 新建)、`current_version` 指向它,草稿对象原样成为版本文件;
257
+ * 拒绝:提交后删除草稿对象。审计 `skill.change_decided`。
258
+ */
259
+ async decide(orgId, id, accountId, body, actorTokenId) {
260
+ const { db } = this.d;
261
+ const head = await db
262
+ .selectFrom("skill_change_requests")
263
+ .select("agent_id")
264
+ .where("id", "=", id)
265
+ .where("org_id", "=", orgId)
266
+ .executeTakeFirst();
267
+ if (!head)
268
+ throw notFound();
269
+ const done = await db.transaction().execute(async (t) => {
270
+ // 加锁顺序与 write 一致:组织行(KEY SHARE)→ agent 行 → 申请行 → 会话行
271
+ await keyShareOrg(t, orgId);
272
+ const agent = await t
273
+ .selectFrom("agents")
274
+ .select(["owner_account_id", "deleted_at"])
275
+ .where("id", "=", head.agent_id)
276
+ .forNoKeyUpdate()
277
+ .executeTakeFirst();
278
+ if (!agent || agent.deleted_at !== null)
279
+ throw notFound();
280
+ const req = await t
281
+ .selectFrom("skill_change_requests")
282
+ .selectAll()
283
+ .where("id", "=", id)
284
+ .forUpdate()
285
+ .executeTakeFirst();
286
+ // 首次读与加锁重读之间行被删了(agent / 组织被硬删除)→ 404,不是 500
287
+ if (!req)
288
+ throw notFound();
289
+ if (agent.owner_account_id !== accountId) {
290
+ throw new ApiError("skill_change.not_owner", "Only the agent's owner can decide on its skill changes");
291
+ }
292
+ if (req.status !== "pending") {
293
+ throw new ApiError("skill_change.already_decided", "This skill change has already been decided");
294
+ }
295
+ const p = req.proposed_version;
296
+ const approved = body.decision === "approve";
297
+ let skillId = req.skill_id;
298
+ let version = p.version;
299
+ if (approved) {
300
+ const existing = await t
301
+ .selectFrom("skills")
302
+ .select(["id", "current_version"])
303
+ .where("org_id", "=", orgId)
304
+ .where("scope", "=", "agent")
305
+ .where("agent_id", "=", req.agent_id)
306
+ .where("name", "=", p.manifest.name)
307
+ .where("deleted_at", "is", null)
308
+ .forUpdate()
309
+ .executeTakeFirst();
310
+ skillId = existing?.id ?? p.skillId;
311
+ version = (existing?.current_version ?? 0) + 1;
312
+ await this.createVersion(t, {
313
+ orgId,
314
+ agentId: req.agent_id,
315
+ skillId,
316
+ exists: existing !== undefined,
317
+ version,
318
+ manifest: p.manifest,
319
+ prefix: req.object_prefix,
320
+ createdBy: req.requested_by_account,
321
+ });
322
+ }
323
+ const updated = await t
324
+ .updateTable("skill_change_requests")
325
+ .set({
326
+ status: approved ? "approved" : "rejected",
327
+ decided_by: accountId,
328
+ decided_at: sql `now()`,
329
+ ...(approved && { skill_id: skillId }),
330
+ })
331
+ .where("id", "=", id)
332
+ .returningAll()
333
+ .executeTakeFirstOrThrow();
334
+ await audit(t, {
335
+ actorAccountId: accountId,
336
+ ...(actorTokenId !== undefined && { actorTokenId }),
337
+ orgId,
338
+ action: "skill.change_decided",
339
+ target: id,
340
+ detail: {
341
+ decision: approved ? "approved" : "rejected",
342
+ agentId: req.agent_id,
343
+ skillId,
344
+ name: p.manifest.name,
345
+ version: approved ? version : p.version,
346
+ requestedBy: req.requested_by_account,
347
+ conversationId: req.requested_in_conversation,
348
+ ...(body.note !== undefined && { note: body.note }),
349
+ },
350
+ });
351
+ // 拒绝:发起对话立即回退到正式版本(或移除),模型在当前位置看到提醒
352
+ const revertSeq = approved ? null : await this.revertTrial(t, req);
353
+ return { updated, revertSeq };
354
+ });
355
+ const row = done.updated;
356
+ if (done.revertSeq !== null) {
357
+ await this.d.eventLog.notify(row.requested_in_conversation, done.revertSeq);
358
+ }
359
+ if (row.status === "rejected")
360
+ await this.deletePrefix(orgId, row.object_prefix);
361
+ const [view] = await this.views([row]);
362
+ if (!view)
363
+ throw notFound();
364
+ return view;
365
+ }
366
+ /**
367
+ * 软删除 agent 自己的一个技能(只有该 agent 当前的负责人;其他人 403 `forbidden`):技能不存在 / 已删除 / 不属于该
368
+ * agent → `skill.not_found`。同名的待处理改动一并取消(发起对话追加回退快照,提交后删草稿)。审计 `skill.deleted`。
369
+ * 各对话下一次运行开始时目录里去掉它;之后同名可再写为新技能。
370
+ */
371
+ async deleteAgentSkill(orgId, agentId, skillId, accountId, actorTokenId) {
372
+ const cancelled = await this.d.db.transaction().execute(async (t) => {
373
+ await keyShareOrg(t, orgId);
374
+ const agent = await t
375
+ .selectFrom("agents")
376
+ .select(["owner_account_id", "deleted_at"])
377
+ .where("id", "=", agentId)
378
+ .where("org_id", "=", orgId)
379
+ .forNoKeyUpdate()
380
+ .executeTakeFirst();
381
+ const agentNotFound = () => new ApiError("agent.not_found", "Agent not found");
382
+ if (!agent || agent.deleted_at !== null)
383
+ throw agentNotFound();
384
+ if (agent.owner_account_id !== accountId) {
385
+ // 与 AgentsService 一致:看不到的 agent → 404,看得到但不是负责人 → 403
386
+ const visible = await t
387
+ .selectFrom("agents")
388
+ .select("id")
389
+ .where("id", "=", agentId)
390
+ .where(visibleTo(accountId))
391
+ .executeTakeFirst();
392
+ if (!visible)
393
+ throw agentNotFound();
394
+ throw new ApiError("forbidden", "Only the agent's owner can delete its skills");
395
+ }
396
+ const r = await t
397
+ .updateTable("skills")
398
+ .set({ deleted_at: sql `now()`, updated_at: sql `now()` })
399
+ .where("id", "=", skillId)
400
+ .where("org_id", "=", orgId)
401
+ .where("scope", "=", "agent")
402
+ .where("agent_id", "=", agentId)
403
+ .where("deleted_at", "is", null)
404
+ .returning(["name"])
405
+ .executeTakeFirst();
406
+ if (!r)
407
+ throw new ApiError("skill.not_found", "Skill not found");
408
+ const out = { prefixes: [], seqs: [] };
409
+ const pend = await t
410
+ .selectFrom("skill_change_requests")
411
+ .selectAll()
412
+ .where("agent_id", "=", agentId)
413
+ .where("status", "=", "pending")
414
+ .where(sql `proposed_version -> 'manifest' ->> 'name'`, "=", r.name)
415
+ .forUpdate()
416
+ .executeTakeFirst();
417
+ if (pend) {
418
+ await t
419
+ .updateTable("skill_change_requests")
420
+ .set({ status: "cancelled", decided_at: sql `now()` })
421
+ .where("id", "=", pend.id)
422
+ .execute();
423
+ await audit(t, {
424
+ actorAccountId: accountId,
425
+ ...(actorTokenId !== undefined && { actorTokenId }),
426
+ orgId,
427
+ action: "skill.change_decided",
428
+ target: pend.id,
429
+ detail: { decision: "cancelled", reason: "skill_deleted", agentId, name: r.name },
430
+ });
431
+ const seq = await this.revertTrial(t, pend);
432
+ if (seq !== null)
433
+ out.seqs.push([pend.requested_in_conversation, seq]);
434
+ out.prefixes.push(pend.object_prefix);
435
+ }
436
+ await audit(t, {
437
+ actorAccountId: accountId,
438
+ ...(actorTokenId !== undefined && { actorTokenId }),
439
+ orgId,
440
+ action: "skill.deleted",
441
+ target: skillId,
442
+ detail: { name: r.name, agentId },
443
+ });
444
+ return out;
445
+ });
446
+ await this.finishCancel(orgId, cancelled);
447
+ }
448
+ /** 当前用户(作为 agent 负责人)能决定的待处理申请,新的在前,最多 {@link SKILL_CHANGES_LIST_MAX} 条。 */
449
+ async listPending(orgId, accountId) {
450
+ const rows = await this.d.db
451
+ .selectFrom("skill_change_requests")
452
+ .innerJoin("agents", "agents.id", "skill_change_requests.agent_id")
453
+ .selectAll("skill_change_requests")
454
+ .where("skill_change_requests.org_id", "=", orgId)
455
+ .where("skill_change_requests.status", "=", "pending")
456
+ .where("agents.owner_account_id", "=", accountId)
457
+ .where("agents.deleted_at", "is", null)
458
+ .orderBy("skill_change_requests.created_at", "desc")
459
+ .limit(SKILL_CHANGES_LIST_MAX)
460
+ .execute();
461
+ return this.views(rows);
462
+ }
463
+ /**
464
+ * 详情(含文件文本):只有该 agent 的负责人与发起人能看,其他人一律 404(不泄露存在)。
465
+ * 草稿对象已删除(拒绝 / 取消)时文件内容为 null。
466
+ */
467
+ async get(orgId, id, accountId) {
468
+ const row = await this.d.db
469
+ .selectFrom("skill_change_requests")
470
+ .innerJoin("agents", "agents.id", "skill_change_requests.agent_id")
471
+ .selectAll("skill_change_requests")
472
+ .select("agents.owner_account_id")
473
+ .where("skill_change_requests.id", "=", id)
474
+ .where("skill_change_requests.org_id", "=", orgId)
475
+ .where("agents.deleted_at", "is", null)
476
+ .executeTakeFirst();
477
+ if (!row)
478
+ throw notFound();
479
+ if (row.owner_account_id !== accountId && row.requested_by_account !== accountId) {
480
+ throw notFound();
481
+ }
482
+ const [view] = await this.views([row]);
483
+ if (!view)
484
+ throw notFound();
485
+ const live = row.status === "pending" || row.status === "approved";
486
+ const store = this.d.storage.kernel(orgId);
487
+ const budget = { left: DETAIL_MAX_BYTES };
488
+ const files = await readTexts(live ? store : undefined, row.object_prefix, row.proposed_version.manifest.files, budget);
489
+ // 改动已有技能:附上当前生效版本的文件(批准后它就是上一版,差异仍按申请时的当前版本显示)
490
+ let current = null;
491
+ if (row.skill_id !== null) {
492
+ const cur = await this.d.db
493
+ .selectFrom("skills")
494
+ .innerJoin("skill_versions", (j) => j
495
+ .onRef("skill_versions.skill_id", "=", "skills.id")
496
+ .onRef("skill_versions.version", "=", "skills.current_version"))
497
+ .select([
498
+ "skill_versions.version",
499
+ "skill_versions.manifest",
500
+ "skill_versions.object_prefix",
501
+ ])
502
+ .where("skills.id", "=", row.skill_id)
503
+ .where("skills.deleted_at", "is", null)
504
+ .executeTakeFirst();
505
+ // 已批准的申请自己就是当前版本:没有可比的「之前」,不给
506
+ if (cur && cur.object_prefix !== row.object_prefix) {
507
+ current = {
508
+ version: cur.version,
509
+ files: await readTexts(store, cur.object_prefix, cur.manifest.files, budget),
510
+ };
511
+ }
512
+ }
513
+ return { ...view, files, current };
514
+ }
515
+ /**
516
+ * 在事务 `t` 里由对话最新一份快照推出下一份并追加(不同才写):先锁会话行(与 `EventLog.append` 同一把锁),
517
+ * 锁内读最新快照,保证「读最新 → 追加」之间没有别的快照插进来。返回写入的 seq,没写返回 null。
518
+ * Phase B: `derive` gets the whole latest payload, so `pinned` and `toolMap` are carried forward;
519
+ * a pinned entry is kept only while `skills` has the same id, version and source (pinned ⊆
520
+ * skills), and the pinned bodies still fit the size limit. The tool map is only recomputed at run
521
+ * start.
522
+ */
523
+ async appendCatalog(t, conversationId, derive, idemKey, runId) {
524
+ const base = (await lockLatestCatalog(t, conversationId)) ?? { skills: [] };
525
+ const derived = derive(base);
526
+ if (derived === null)
527
+ return null;
528
+ const skills = [...derived.skills].sort(byName);
529
+ const live = (p) => skills.some((s) => s.id === p.id && s.version === p.version && s.source === p.source);
530
+ const pinned = fitPinned((derived.pinned ?? []).filter(live), this.d.log, {
531
+ conversationId,
532
+ });
533
+ const next = {
534
+ skills,
535
+ ...(pinned.length > 0 && { pinned }),
536
+ ...(derived.toolMap !== undefined && { toolMap: derived.toolMap }),
537
+ };
538
+ if (sameSnapshot(base, next))
539
+ return null;
540
+ const written = await this.d.eventLog.append(conversationId, [
541
+ {
542
+ type: "skills_catalog",
543
+ ...(runId !== undefined && { runId }),
544
+ idemKey,
545
+ payload: next,
546
+ },
547
+ ], t);
548
+ return Math.max(...written.map((e) => e.seq));
549
+ }
550
+ /**
551
+ * 草稿不再生效(拒绝 / 取消)时,在事务 `t` 里给发起对话追加一份回退快照:由该对话最新一份快照推出——
552
+ * 来源是这份草稿的条目换成这个 agent 技能当前的正式版本(`t` 里已是决定之后的状态),没有正式版本就移除。
553
+ * 快照里已没有这份草稿 → 不写。对话正在运行时,提醒落在当前位置(构建时排在工具结果之后),下一步即生效。
554
+ * 移除时不推测同名的组织技能(快照里已被替换掉),下一次运行开始的解析会把它补回来。
555
+ */
556
+ async revertTrial(t, req) {
557
+ const name = req.proposed_version.manifest.name;
558
+ const real = await t
559
+ .selectFrom("skills")
560
+ .innerJoin("skill_versions", (j) => j
561
+ .onRef("skill_versions.skill_id", "=", "skills.id")
562
+ .onRef("skill_versions.version", "=", "skills.current_version"))
563
+ .select([
564
+ "skills.id",
565
+ "skills.current_version",
566
+ "skill_versions.manifest",
567
+ "skill_versions.object_prefix",
568
+ ])
569
+ .where("skills.org_id", "=", req.org_id)
570
+ .where("skills.scope", "=", "agent")
571
+ .where("skills.agent_id", "=", req.agent_id)
572
+ .where("skills.name", "=", name)
573
+ .where("skills.deleted_at", "is", null)
574
+ .executeTakeFirst();
575
+ return this.appendCatalog(t, req.requested_in_conversation, (base) => {
576
+ if (!base.skills.some((s) => s.source === req.object_prefix))
577
+ return null;
578
+ const rest = base.skills.filter((s) => s.source !== req.object_prefix);
579
+ // The draft's pinned entry goes (Decision 8): the next run start pins the real version
580
+ return {
581
+ ...base,
582
+ // A manual-only current version (phase D) stays out of the model's catalog
583
+ skills: real && invocationOf(real.manifest).model
584
+ ? [
585
+ ...rest,
586
+ {
587
+ id: real.id,
588
+ name,
589
+ description: real.manifest.description,
590
+ version: real.current_version,
591
+ source: real.object_prefix,
592
+ },
593
+ ]
594
+ : rest,
595
+ ...(base.pinned && {
596
+ pinned: base.pinned.filter((p) => p.source !== req.object_prefix),
597
+ }),
598
+ };
599
+ }, `skills_catalog:revert:${req.id}`);
600
+ }
601
+ /**
602
+ * 在事务 `t` 里取消该 agent 全部待处理的技能改动(agent 被删除时由 `AgentsService.softDelete` 调用):
603
+ * 置 cancelled、审计、给各发起对话追加回退快照。提交后调用 {@link finishCancel} 删除草稿并发布事件。
604
+ */
605
+ async cancelPendingForAgent(t, orgId, agentId, actorAccountId, reason, actorTokenId) {
606
+ const rows = await t
607
+ .selectFrom("skill_change_requests")
608
+ .selectAll()
609
+ .where("org_id", "=", orgId)
610
+ .where("agent_id", "=", agentId)
611
+ .where("status", "=", "pending")
612
+ .orderBy("created_at")
613
+ .forUpdate()
614
+ .execute();
615
+ const out = { prefixes: [], seqs: [] };
616
+ for (const r of rows) {
617
+ await t
618
+ .updateTable("skill_change_requests")
619
+ .set({ status: "cancelled", decided_at: sql `now()` })
620
+ .where("id", "=", r.id)
621
+ .execute();
622
+ await audit(t, {
623
+ actorAccountId,
624
+ ...(actorTokenId !== undefined && { actorTokenId }),
625
+ orgId,
626
+ action: "skill.change_decided",
627
+ target: r.id,
628
+ detail: { decision: "cancelled", reason, agentId, name: r.proposed_version.manifest.name },
629
+ });
630
+ const seq = await this.revertTrial(t, r);
631
+ if (seq !== null)
632
+ out.seqs.push([r.requested_in_conversation, seq]);
633
+ out.prefixes.push(r.object_prefix);
634
+ }
635
+ return out;
636
+ }
637
+ /** {@link cancelPendingForAgent} 提交之后:发布事件、尽力删除草稿对象。 */
638
+ async finishCancel(orgId, c) {
639
+ for (const [conv, seq] of c.seqs)
640
+ await this.d.eventLog.notify(conv, seq);
641
+ for (const p of c.prefixes)
642
+ await this.deletePrefix(orgId, p);
643
+ }
644
+ /** 新技能的数量上限(含待批准的新技能;`excluding` 是将被取代的申请)。 */
645
+ async assertBelowCap(t, agentId, excluding) {
646
+ const skills = await t
647
+ .selectFrom("skills")
648
+ .select((eb) => eb.fn.countAll().as("n"))
649
+ .where("scope", "=", "agent")
650
+ .where("agent_id", "=", agentId)
651
+ .where("deleted_at", "is", null)
652
+ .executeTakeFirstOrThrow();
653
+ let q = t
654
+ .selectFrom("skill_change_requests")
655
+ .select((eb) => eb.fn.countAll().as("n"))
656
+ .where("agent_id", "=", agentId)
657
+ .where("status", "=", "pending")
658
+ .where("skill_id", "is", null);
659
+ if (excluding !== undefined)
660
+ q = q.where("id", "!=", excluding);
661
+ const drafts = await q.executeTakeFirstOrThrow();
662
+ if (Number(skills.n) + Number(drafts.n) >= AGENT_SKILLS_MAX)
663
+ throw new ToolError(capText());
664
+ }
665
+ /** 写一个版本并让 `current_version` 指向它(技能不存在则新建)。 */
666
+ async createVersion(t, v) {
667
+ if (v.exists) {
668
+ await t
669
+ .updateTable("skills")
670
+ .set({
671
+ current_version: v.version,
672
+ description: v.manifest.description,
673
+ updated_at: sql `now()`,
674
+ })
675
+ .where("id", "=", v.skillId)
676
+ .execute();
677
+ }
678
+ else {
679
+ await t
680
+ .insertInto("skills")
681
+ .values({
682
+ id: v.skillId,
683
+ org_id: v.orgId,
684
+ scope: "agent",
685
+ agent_id: v.agentId,
686
+ name: v.manifest.name,
687
+ description: v.manifest.description,
688
+ current_version: v.version,
689
+ created_by: v.createdBy,
690
+ })
691
+ .execute();
692
+ }
693
+ await t
694
+ .insertInto("skill_versions")
695
+ .values({
696
+ skill_id: v.skillId,
697
+ version: v.version,
698
+ manifest: JSON.stringify(v.manifest),
699
+ object_prefix: v.prefix,
700
+ created_by: v.createdBy,
701
+ })
702
+ .execute();
703
+ }
704
+ /** 尽力删除草稿对象(失败只记日志:孤儿对象随组织数据清理删除)。 */
705
+ async deletePrefix(orgId, prefix) {
706
+ try {
707
+ await this.d.storage.kernel(orgId).deletePrefix(prefix);
708
+ }
709
+ catch (err) {
710
+ this.d.log.warn("skill draft cleanup failed", { orgId, prefix, err });
711
+ }
712
+ }
713
+ /** 补齐 agent 名。 */
714
+ async views(rows) {
715
+ if (rows.length === 0)
716
+ return [];
717
+ const agentIds = [...new Set(rows.map((r) => r.agent_id))];
718
+ const agents = await this.d.db
719
+ .selectFrom("agents")
720
+ .innerJoin("agent_versions", (j) => j
721
+ .onRef("agent_versions.agent_id", "=", "agents.id")
722
+ .onRef("agent_versions.version", "=", "agents.current_version"))
723
+ .select(["agents.id", "agent_versions.definition"])
724
+ .where("agents.id", "in", agentIds)
725
+ .execute();
726
+ const requesters = await this.d.db
727
+ .selectFrom("accounts")
728
+ .select(["id", "display_name"])
729
+ .where("id", "in", [...new Set(rows.map((r) => r.requested_by_account))])
730
+ .execute();
731
+ const requesterNames = new Map(requesters.map((a) => [a.id, a.display_name]));
732
+ const names = new Map(agents.map((a) => {
733
+ const n = a.definition?.name;
734
+ return [a.id, typeof n === "string" ? n : ""];
735
+ }));
736
+ return rows.map((r) => ({
737
+ id: r.id,
738
+ orgId: r.org_id,
739
+ agent: { id: r.agent_id, name: names.get(r.agent_id) ?? "" },
740
+ skillId: r.skill_id,
741
+ name: r.proposed_version.manifest.name,
742
+ description: r.proposed_version.manifest.description,
743
+ version: r.proposed_version.version,
744
+ files: r.proposed_version.manifest.files.map((f) => ({ path: f.path, size: f.size })),
745
+ status: r.status,
746
+ requestedBy: r.requested_by_account,
747
+ requestedByName: requesterNames.get(r.requested_by_account) ?? "",
748
+ requestedInConversation: r.requested_in_conversation,
749
+ conversationPath: `/chat/${r.requested_in_conversation}`,
750
+ decidedBy: r.decided_by,
751
+ decidedAt: r.decided_at === null ? null : iso(r.decided_at),
752
+ createdAt: iso(r.created_at),
753
+ }));
754
+ }
755
+ }
756
+ /**
757
+ * 先给组织行加 KEY SHARE 锁,再锁 agent 行:与 `AgentsService`(组织行 FOR UPDATE → agent 行)同一顺序。
758
+ * 不先锁的话,本事务持有 agent 行后插入引用组织的行(外键取 KEY SHARE)会与之互相等待(40P01)。
759
+ */
760
+ async function keyShareOrg(t, orgId) {
761
+ await t.selectFrom("orgs").select("id").where("id", "=", orgId).forKeyShare().executeTakeFirst();
762
+ }
763
+ /**
764
+ * 按清单顺序读文件文本,共用读取额度 `budget`(超出、对象缺失、存储出错时该文件内容为 null)。
765
+ * `store` 为 undefined 表示不读(如草稿已删除)。
766
+ */
767
+ async function readTexts(store, prefix, manifest, budget) {
768
+ const out = [];
769
+ for (const f of manifest) {
770
+ let content = null;
771
+ if (store && f.size <= budget.left) {
772
+ try {
773
+ const got = await store.get(`${prefix}${f.path}`);
774
+ if (got) {
775
+ content = await new Response(got.body).text();
776
+ budget.left -= f.size;
777
+ }
778
+ }
779
+ catch {
780
+ content = null;
781
+ }
782
+ }
783
+ out.push({ path: f.path, size: f.size, content });
784
+ }
785
+ return out;
786
+ }
787
+ /** 并发写入全部文件。 */
788
+ async function putAll(store, prefix, files) {
789
+ const queue = [...files];
790
+ await Promise.all(Array.from({ length: Math.min(PUT_CONCURRENCY, queue.length) }, async () => {
791
+ for (let f = queue.shift(); f; f = queue.shift()) {
792
+ await store.put(`${prefix}${f.path}`, f.data, {
793
+ contentType: "application/octet-stream",
794
+ size: f.size,
795
+ });
796
+ }
797
+ }));
798
+ }
799
+ /** 存储错误 → 给模型的说明(存储不可用可重试);其余原样抛出。 */
800
+ function storageError(e) {
801
+ if (e instanceof ApiError && e.code === "storage.unavailable") {
802
+ return new ToolError(STORAGE_UNAVAILABLE_TEXT);
803
+ }
804
+ return e;
805
+ }