@bevel-software/platform-core-backend 0.22.0 → 0.24.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 (466) hide show
  1. package/dist/core/core-ports.d.ts +11 -1
  2. package/dist/core/core-ports.d.ts.map +1 -1
  3. package/dist/core/core-ports.js.map +1 -1
  4. package/dist/core/create-core-server.d.ts +3 -3
  5. package/dist/core/create-core-server.d.ts.map +1 -1
  6. package/dist/core/create-core-server.js +46 -13
  7. package/dist/core/create-core-server.js.map +1 -1
  8. package/dist/core/create-core-services.d.ts +12 -2
  9. package/dist/core/create-core-services.d.ts.map +1 -1
  10. package/dist/core/create-core-services.js +137 -24
  11. package/dist/core/create-core-services.js.map +1 -1
  12. package/dist/core/lifecycle.d.ts +46 -1
  13. package/dist/core/lifecycle.d.ts.map +1 -1
  14. package/dist/core/lifecycle.js +99 -13
  15. package/dist/core/lifecycle.js.map +1 -1
  16. package/dist/core-config.d.ts +16 -12
  17. package/dist/core-config.d.ts.map +1 -1
  18. package/dist/core-config.js +28 -13
  19. package/dist/core-config.js.map +1 -1
  20. package/dist/index.d.ts +6 -4
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +12 -3
  23. package/dist/index.js.map +1 -1
  24. package/dist/modules/access/access-control.interface.d.ts +42 -12
  25. package/dist/modules/access/access-control.interface.d.ts.map +1 -1
  26. package/dist/modules/access/access-control.service.d.ts +67 -10
  27. package/dist/modules/access/access-control.service.d.ts.map +1 -1
  28. package/dist/modules/access/access-control.service.js +214 -35
  29. package/dist/modules/access/access-control.service.js.map +1 -1
  30. package/dist/modules/access/access.routes.d.ts.map +1 -1
  31. package/dist/modules/access/access.routes.js +17 -16
  32. package/dist/modules/access/access.routes.js.map +1 -1
  33. package/dist/modules/access/directory-sync-bot.d.ts.map +1 -1
  34. package/dist/modules/access/directory-sync-bot.js +7 -3
  35. package/dist/modules/access/directory-sync-bot.js.map +1 -1
  36. package/dist/modules/agent-instructions/agent-instructions.routes.d.ts +8 -1
  37. package/dist/modules/agent-instructions/agent-instructions.routes.d.ts.map +1 -1
  38. package/dist/modules/agent-instructions/agent-instructions.routes.js +8 -2
  39. package/dist/modules/agent-instructions/agent-instructions.routes.js.map +1 -1
  40. package/dist/modules/agent-instructions/compose.d.ts +38 -6
  41. package/dist/modules/agent-instructions/compose.d.ts.map +1 -1
  42. package/dist/modules/agent-instructions/compose.js +39 -6
  43. package/dist/modules/agent-instructions/compose.js.map +1 -1
  44. package/dist/modules/agent-instructions/index.d.ts +2 -1
  45. package/dist/modules/agent-instructions/index.d.ts.map +1 -1
  46. package/dist/modules/agent-instructions/index.js +2 -1
  47. package/dist/modules/agent-instructions/index.js.map +1 -1
  48. package/dist/modules/agent-instructions/shared-file-rules.d.ts +115 -0
  49. package/dist/modules/agent-instructions/shared-file-rules.d.ts.map +1 -0
  50. package/dist/modules/agent-instructions/shared-file-rules.js +272 -0
  51. package/dist/modules/agent-instructions/shared-file-rules.js.map +1 -0
  52. package/dist/modules/audit/agent-audit.service.d.ts.map +1 -1
  53. package/dist/modules/audit/agent-audit.service.js +4 -2
  54. package/dist/modules/audit/agent-audit.service.js.map +1 -1
  55. package/dist/modules/auth/account-admission.d.ts +58 -7
  56. package/dist/modules/auth/account-admission.d.ts.map +1 -1
  57. package/dist/modules/auth/account-admission.js +44 -1
  58. package/dist/modules/auth/account-admission.js.map +1 -1
  59. package/dist/modules/auth/account-erasure.service.d.ts.map +1 -1
  60. package/dist/modules/auth/account-erasure.service.js +57 -16
  61. package/dist/modules/auth/account-erasure.service.js.map +1 -1
  62. package/dist/modules/auth/account.routes.d.ts +1 -1
  63. package/dist/modules/auth/account.routes.d.ts.map +1 -1
  64. package/dist/modules/auth/account.routes.js +61 -5
  65. package/dist/modules/auth/account.routes.js.map +1 -1
  66. package/dist/modules/auth/auth.middleware.d.ts +1 -1
  67. package/dist/modules/auth/auth.middleware.d.ts.map +1 -1
  68. package/dist/modules/auth/auth.middleware.js +18 -7
  69. package/dist/modules/auth/auth.middleware.js.map +1 -1
  70. package/dist/modules/auth/auth.routes.d.ts.map +1 -1
  71. package/dist/modules/auth/auth.routes.js +8 -0
  72. package/dist/modules/auth/auth.routes.js.map +1 -1
  73. package/dist/modules/auth/auth.service.d.ts +70 -2
  74. package/dist/modules/auth/auth.service.d.ts.map +1 -1
  75. package/dist/modules/auth/auth.service.js +197 -18
  76. package/dist/modules/auth/auth.service.js.map +1 -1
  77. package/dist/modules/auth/oidc-auth-provider.d.ts.map +1 -1
  78. package/dist/modules/auth/oidc-auth-provider.js +7 -2
  79. package/dist/modules/auth/oidc-auth-provider.js.map +1 -1
  80. package/dist/modules/code-mode/code-mode.tool.d.ts +20 -2
  81. package/dist/modules/code-mode/code-mode.tool.d.ts.map +1 -1
  82. package/dist/modules/code-mode/code-mode.tool.js +66 -35
  83. package/dist/modules/code-mode/code-mode.tool.js.map +1 -1
  84. package/dist/modules/database/connection.d.ts +16 -0
  85. package/dist/modules/database/connection.d.ts.map +1 -1
  86. package/dist/modules/database/connection.js +117 -0
  87. package/dist/modules/database/connection.js.map +1 -1
  88. package/dist/modules/database/core-schema.d.ts +337 -120
  89. package/dist/modules/database/core-schema.d.ts.map +1 -1
  90. package/dist/modules/database/core-schema.js +116 -58
  91. package/dist/modules/database/core-schema.js.map +1 -1
  92. package/dist/modules/database/migrate.d.ts +8 -0
  93. package/dist/modules/database/migrate.d.ts.map +1 -1
  94. package/dist/modules/database/migrate.js +271 -1
  95. package/dist/modules/database/migrate.js.map +1 -1
  96. package/dist/modules/kb-fs/branch-name.d.ts.map +1 -1
  97. package/dist/modules/kb-fs/branch-name.js +12 -2
  98. package/dist/modules/kb-fs/branch-name.js.map +1 -1
  99. package/dist/modules/kb-fs/repo-path.d.ts +11 -16
  100. package/dist/modules/kb-fs/repo-path.d.ts.map +1 -1
  101. package/dist/modules/kb-fs/repo-path.js +79 -0
  102. package/dist/modules/kb-fs/repo-path.js.map +1 -1
  103. package/dist/modules/kb-sync/kb-sync.routes.d.ts +2 -2
  104. package/dist/modules/kb-sync/kb-sync.routes.d.ts.map +1 -1
  105. package/dist/modules/kb-sync/kb-sync.routes.js +14 -3
  106. package/dist/modules/kb-sync/kb-sync.routes.js.map +1 -1
  107. package/dist/modules/kb-sync/sync-auth.d.ts +3 -1
  108. package/dist/modules/kb-sync/sync-auth.d.ts.map +1 -1
  109. package/dist/modules/kb-sync/sync-auth.js +1 -1
  110. package/dist/modules/kb-sync/sync-auth.js.map +1 -1
  111. package/dist/modules/mcp/mcp-auth.middleware.d.ts.map +1 -1
  112. package/dist/modules/mcp/mcp-auth.middleware.js +21 -6
  113. package/dist/modules/mcp/mcp-auth.middleware.js.map +1 -1
  114. package/dist/modules/mcp/mcp.service.d.ts +8 -0
  115. package/dist/modules/mcp/mcp.service.d.ts.map +1 -1
  116. package/dist/modules/mcp/mcp.service.js +38 -8
  117. package/dist/modules/mcp/mcp.service.js.map +1 -1
  118. package/dist/modules/mcp/oauth/bevel-oauth-provider.d.ts.map +1 -1
  119. package/dist/modules/mcp/oauth/bevel-oauth-provider.js +3 -2
  120. package/dist/modules/mcp/oauth/bevel-oauth-provider.js.map +1 -1
  121. package/dist/modules/plugins/join-request-records.store.d.ts.map +1 -1
  122. package/dist/modules/plugins/join-request-records.store.js +7 -4
  123. package/dist/modules/plugins/join-request-records.store.js.map +1 -1
  124. package/dist/modules/settings/deployment-settings.service.d.ts.map +1 -1
  125. package/dist/modules/settings/deployment-settings.service.js +8 -3
  126. package/dist/modules/settings/deployment-settings.service.js.map +1 -1
  127. package/dist/modules/settings/setup.routes.d.ts +52 -1
  128. package/dist/modules/settings/setup.routes.d.ts.map +1 -1
  129. package/dist/modules/settings/setup.routes.js +207 -19
  130. package/dist/modules/settings/setup.routes.js.map +1 -1
  131. package/dist/modules/skills/skills.contract.d.ts +90 -18
  132. package/dist/modules/skills/skills.contract.d.ts.map +1 -1
  133. package/dist/modules/skills/skills.contract.js +4 -1
  134. package/dist/modules/skills/skills.contract.js.map +1 -1
  135. package/dist/modules/skills/skills.service.d.ts +98 -9
  136. package/dist/modules/skills/skills.service.d.ts.map +1 -1
  137. package/dist/modules/skills/skills.service.js +239 -37
  138. package/dist/modules/skills/skills.service.js.map +1 -1
  139. package/dist/modules/skills/skills.tools.d.ts +7 -0
  140. package/dist/modules/skills/skills.tools.d.ts.map +1 -1
  141. package/dist/modules/skills/skills.tools.js +71 -7
  142. package/dist/modules/skills/skills.tools.js.map +1 -1
  143. package/dist/modules/tool-auth/external-api-key.service.d.ts.map +1 -1
  144. package/dist/modules/tool-auth/external-api-key.service.js +12 -4
  145. package/dist/modules/tool-auth/external-api-key.service.js.map +1 -1
  146. package/dist/modules/tool-auth/internal-token.service.d.ts +3 -3
  147. package/dist/modules/tool-auth/tool-auth.middleware.d.ts +16 -7
  148. package/dist/modules/tool-auth/tool-auth.middleware.d.ts.map +1 -1
  149. package/dist/modules/tool-auth/tool-auth.middleware.js +34 -12
  150. package/dist/modules/tool-auth/tool-auth.middleware.js.map +1 -1
  151. package/dist/modules/tool-helpers/tool-handler.d.ts +2 -1
  152. package/dist/modules/tool-helpers/tool-handler.d.ts.map +1 -1
  153. package/dist/modules/tool-helpers/tool-handler.js +25 -4
  154. package/dist/modules/tool-helpers/tool-handler.js.map +1 -1
  155. package/dist/modules/tool-helpers/tool.contract.d.ts +3 -2
  156. package/dist/modules/tool-helpers/tool.contract.d.ts.map +1 -1
  157. package/dist/modules/tool-helpers/tool.contract.js.map +1 -1
  158. package/dist/modules/tool-helpers/validate-token.js +1 -1
  159. package/dist/modules/tool-helpers/validate-token.js.map +1 -1
  160. package/dist/modules/tool-manuals/tool-manuals.tools.d.ts.map +1 -1
  161. package/dist/modules/tool-manuals/tool-manuals.tools.js +42 -31
  162. package/dist/modules/tool-manuals/tool-manuals.tools.js.map +1 -1
  163. package/dist/modules/tool-registry/description-length.d.ts +80 -0
  164. package/dist/modules/tool-registry/description-length.d.ts.map +1 -0
  165. package/dist/modules/tool-registry/description-length.js +108 -0
  166. package/dist/modules/tool-registry/description-length.js.map +1 -0
  167. package/dist/modules/workflow/agent-tools/change-request-summary.d.ts +98 -0
  168. package/dist/modules/workflow/agent-tools/change-request-summary.d.ts.map +1 -0
  169. package/dist/modules/workflow/agent-tools/change-request-summary.js +81 -0
  170. package/dist/modules/workflow/agent-tools/change-request-summary.js.map +1 -0
  171. package/dist/modules/workflow/agent-tools/workflow.tools.d.ts.map +1 -1
  172. package/dist/modules/workflow/agent-tools/workflow.tools.js +75 -35
  173. package/dist/modules/workflow/agent-tools/workflow.tools.js.map +1 -1
  174. package/dist/modules/workflow/file-lock.service.d.ts +24 -0
  175. package/dist/modules/workflow/file-lock.service.d.ts.map +1 -1
  176. package/dist/modules/workflow/file-lock.service.js +30 -0
  177. package/dist/modules/workflow/file-lock.service.js.map +1 -1
  178. package/dist/modules/workflow/git/git.service.d.ts +94 -0
  179. package/dist/modules/workflow/git/git.service.d.ts.map +1 -1
  180. package/dist/modules/workflow/git/git.service.js +193 -3
  181. package/dist/modules/workflow/git/git.service.js.map +1 -1
  182. package/dist/modules/workflow/pending-commits.service.d.ts +38 -0
  183. package/dist/modules/workflow/pending-commits.service.d.ts.map +1 -1
  184. package/dist/modules/workflow/pending-commits.service.js +60 -1
  185. package/dist/modules/workflow/pending-commits.service.js.map +1 -1
  186. package/dist/modules/workflow/recovery-bot.d.ts.map +1 -1
  187. package/dist/modules/workflow/recovery-bot.js +7 -3
  188. package/dist/modules/workflow/recovery-bot.js.map +1 -1
  189. package/dist/modules/workflow/review-workflow/review-workflow.service.d.ts.map +1 -1
  190. package/dist/modules/workflow/review-workflow/review-workflow.service.js +12 -3
  191. package/dist/modules/workflow/review-workflow/review-workflow.service.js.map +1 -1
  192. package/dist/modules/workflow/workflow-hooks.d.ts +54 -32
  193. package/dist/modules/workflow/workflow-hooks.d.ts.map +1 -1
  194. package/dist/modules/workflow/workflow-hooks.js +16 -1
  195. package/dist/modules/workflow/workflow-hooks.js.map +1 -1
  196. package/dist/modules/workflow/workflow.service.d.ts +60 -6
  197. package/dist/modules/workflow/workflow.service.d.ts.map +1 -1
  198. package/dist/modules/workflow/workflow.service.js +115 -5
  199. package/dist/modules/workflow/workflow.service.js.map +1 -1
  200. package/dist/modules/workspace/agent-access.gate.d.ts +94 -0
  201. package/dist/modules/workspace/agent-access.gate.d.ts.map +1 -0
  202. package/dist/modules/workspace/agent-access.gate.js +123 -0
  203. package/dist/modules/workspace/agent-access.gate.js.map +1 -0
  204. package/dist/modules/workspace/agent-upload.routes.d.ts +77 -0
  205. package/dist/modules/workspace/agent-upload.routes.d.ts.map +1 -0
  206. package/dist/modules/workspace/agent-upload.routes.js +210 -0
  207. package/dist/modules/workspace/agent-upload.routes.js.map +1 -0
  208. package/dist/modules/workspace/agent-upload.store.d.ts +284 -0
  209. package/dist/modules/workspace/agent-upload.store.d.ts.map +1 -0
  210. package/dist/modules/workspace/agent-upload.store.js +553 -0
  211. package/dist/modules/workspace/agent-upload.store.js.map +1 -0
  212. package/dist/modules/workspace/routine-write-policy.d.ts +5 -6
  213. package/dist/modules/workspace/routine-write-policy.d.ts.map +1 -1
  214. package/dist/modules/workspace/routine-write-policy.js +5 -6
  215. package/dist/modules/workspace/routine-write-policy.js.map +1 -1
  216. package/dist/modules/workspace/session-sink.d.ts +5 -5
  217. package/dist/modules/workspace/set-aside-clone.d.ts +46 -0
  218. package/dist/modules/workspace/set-aside-clone.d.ts.map +1 -0
  219. package/dist/modules/workspace/set-aside-clone.js +92 -0
  220. package/dist/modules/workspace/set-aside-clone.js.map +1 -0
  221. package/dist/modules/workspace/startup/kb-startup-runner.d.ts +59 -9
  222. package/dist/modules/workspace/startup/kb-startup-runner.d.ts.map +1 -1
  223. package/dist/modules/workspace/startup/kb-startup-runner.js +65 -24
  224. package/dist/modules/workspace/startup/kb-startup-runner.js.map +1 -1
  225. package/dist/modules/workspace/startup/steps/seed-tree.d.ts.map +1 -1
  226. package/dist/modules/workspace/startup/steps/seed-tree.js +3 -3
  227. package/dist/modules/workspace/startup/steps/seed-tree.js.map +1 -1
  228. package/dist/modules/workspace/startup/steps/template-source.d.ts +40 -0
  229. package/dist/modules/workspace/startup/steps/template-source.d.ts.map +1 -1
  230. package/dist/modules/workspace/startup/steps/template-source.js +46 -4
  231. package/dist/modules/workspace/startup/steps/template-source.js.map +1 -1
  232. package/dist/modules/workspace/upload-limits.d.ts +13 -0
  233. package/dist/modules/workspace/upload-limits.d.ts.map +1 -0
  234. package/dist/modules/workspace/upload-limits.js +13 -0
  235. package/dist/modules/workspace/upload-limits.js.map +1 -0
  236. package/dist/modules/workspace/workspace.routes.d.ts.map +1 -1
  237. package/dist/modules/workspace/workspace.routes.js +93 -4
  238. package/dist/modules/workspace/workspace.routes.js.map +1 -1
  239. package/dist/modules/workspace/workspace.service.d.ts +128 -5
  240. package/dist/modules/workspace/workspace.service.d.ts.map +1 -1
  241. package/dist/modules/workspace/workspace.service.js +316 -58
  242. package/dist/modules/workspace/workspace.service.js.map +1 -1
  243. package/dist/modules/workspace/workspace.tools.d.ts +13 -11
  244. package/dist/modules/workspace/workspace.tools.d.ts.map +1 -1
  245. package/dist/modules/workspace/workspace.tools.js +791 -198
  246. package/dist/modules/workspace/workspace.tools.js.map +1 -1
  247. package/dist/modules/workspace/write-denial.d.ts +0 -6
  248. package/dist/modules/workspace/write-denial.d.ts.map +1 -1
  249. package/dist/modules/workspace/write-denial.js +0 -6
  250. package/dist/modules/workspace/write-denial.js.map +1 -1
  251. package/dist/modules/workspace/zip-entry-rules.d.ts +114 -0
  252. package/dist/modules/workspace/zip-entry-rules.d.ts.map +1 -0
  253. package/dist/modules/workspace/zip-entry-rules.js +154 -0
  254. package/dist/modules/workspace/zip-entry-rules.js.map +1 -0
  255. package/dist/modules/write-access/write-access.d.ts +60 -0
  256. package/dist/modules/write-access/write-access.d.ts.map +1 -0
  257. package/dist/modules/write-access/write-access.js +129 -0
  258. package/dist/modules/write-access/write-access.js.map +1 -0
  259. package/dist/shared/column-crypto.d.ts +194 -0
  260. package/dist/shared/column-crypto.d.ts.map +1 -0
  261. package/dist/shared/column-crypto.js +144 -0
  262. package/dist/shared/column-crypto.js.map +1 -0
  263. package/dist/shared/domain-errors.d.ts +25 -0
  264. package/dist/shared/domain-errors.d.ts.map +1 -1
  265. package/dist/shared/domain-errors.js +28 -0
  266. package/dist/shared/domain-errors.js.map +1 -1
  267. package/dist/shared/git.contract.d.ts +20 -0
  268. package/dist/shared/git.contract.d.ts.map +1 -1
  269. package/dist/shared/git.contract.js +26 -0
  270. package/dist/shared/git.contract.js.map +1 -1
  271. package/dist/shared/token-crypto.d.ts.map +1 -1
  272. package/dist/shared/token-crypto.js +25 -1
  273. package/dist/shared/token-crypto.js.map +1 -1
  274. package/dist/tenancy/static-tenant-source.d.ts +0 -1
  275. package/dist/tenancy/static-tenant-source.d.ts.map +1 -1
  276. package/dist/tenancy/static-tenant-source.js +1 -2
  277. package/dist/tenancy/static-tenant-source.js.map +1 -1
  278. package/dist/tenancy/tenant-secrets.d.ts +5 -1
  279. package/dist/tenancy/tenant-secrets.d.ts.map +1 -1
  280. package/dist/tenancy/tenant-secrets.js +4 -0
  281. package/dist/tenancy/tenant-secrets.js.map +1 -1
  282. package/kb-template/AGENTS.md +2 -0
  283. package/migrations/0014_change_request_closed_reason.sql +1 -0
  284. package/migrations/0015_account_deactivation.sql +3 -0
  285. package/migrations/0016_pii_encryption.sql +20 -0
  286. package/migrations/meta/0014_snapshot.json +2265 -0
  287. package/migrations/meta/0015_snapshot.json +2271 -0
  288. package/migrations/meta/0016_snapshot.json +2327 -0
  289. package/migrations/meta/_journal.json +21 -0
  290. package/package.json +3 -3
  291. package/src/__tests__/kb-layout-config.test.ts +0 -2
  292. package/src/__tests__/retired-settings.test.ts +96 -0
  293. package/src/core/__tests__/gated-boot.test.ts +132 -0
  294. package/src/core/__tests__/lifecycle.test.ts +241 -5
  295. package/src/core/__tests__/set-aside-root-is-one-place.test.ts +63 -0
  296. package/src/core/core-ports.ts +11 -1
  297. package/src/core/create-core-server.ts +52 -16
  298. package/src/core/create-core-services.ts +156 -24
  299. package/src/core/lifecycle.ts +117 -13
  300. package/src/core-config.ts +31 -14
  301. package/src/index.ts +30 -1
  302. package/src/modules/access/__tests__/access-control.preview-relocation.test.ts +385 -0
  303. package/src/modules/access/__tests__/access-control.prospective.test.ts +94 -18
  304. package/src/modules/access/__tests__/access.routes.prospective.test.ts +6 -7
  305. package/src/modules/access/__tests__/users-db-double.ts +21 -12
  306. package/src/modules/access/access-control.interface.ts +43 -12
  307. package/src/modules/access/access-control.service.ts +234 -36
  308. package/src/modules/access/access.routes.ts +17 -16
  309. package/src/modules/access/directory-sync-bot.ts +7 -3
  310. package/src/modules/agent-instructions/__tests__/agent-instructions.route.test.ts +11 -5
  311. package/src/modules/agent-instructions/__tests__/compose.test.ts +19 -10
  312. package/src/modules/agent-instructions/__tests__/shared-file-rules.test.ts +238 -0
  313. package/src/modules/agent-instructions/agent-instructions.routes.ts +12 -2
  314. package/src/modules/agent-instructions/compose.ts +50 -7
  315. package/src/modules/agent-instructions/index.ts +12 -0
  316. package/src/modules/agent-instructions/shared-file-rules.ts +314 -0
  317. package/src/modules/audit/agent-audit.service.ts +4 -2
  318. package/src/modules/auth/__tests__/account-deactivation.test.ts +253 -0
  319. package/src/modules/auth/__tests__/account-erasure.approval-gate.test.ts +6 -2
  320. package/src/modules/auth/__tests__/account.routes.test.ts +87 -6
  321. package/src/modules/auth/__tests__/auth.middleware.test.ts +45 -22
  322. package/src/modules/auth/__tests__/auth.service.test.ts +4 -2
  323. package/src/modules/auth/account-admission.ts +78 -9
  324. package/src/modules/auth/account-erasure.service.ts +69 -18
  325. package/src/modules/auth/account.routes.ts +63 -7
  326. package/src/modules/auth/auth.middleware.ts +19 -8
  327. package/src/modules/auth/auth.routes.ts +8 -0
  328. package/src/modules/auth/auth.service.ts +206 -23
  329. package/src/modules/auth/oidc-auth-provider.ts +7 -2
  330. package/src/modules/code-mode/__tests__/chain-runtime.e2e.test.ts +335 -0
  331. package/src/modules/code-mode/__tests__/code-mode.tool.test.ts +46 -2
  332. package/src/modules/code-mode/code-mode.tool.ts +80 -34
  333. package/src/modules/database/__tests__/connection.test.ts +12 -0
  334. package/src/modules/database/__tests__/pii-backfill.pg.test.ts +561 -0
  335. package/src/modules/database/connection.ts +117 -0
  336. package/src/modules/database/core-schema.ts +116 -58
  337. package/src/modules/database/migrate.ts +353 -1
  338. package/src/modules/kb-fs/__tests__/branch-name.test.ts +10 -0
  339. package/src/modules/kb-fs/__tests__/repo-path.test.ts +123 -0
  340. package/src/modules/kb-fs/branch-name.ts +14 -1
  341. package/src/modules/kb-fs/repo-path.ts +85 -0
  342. package/src/modules/kb-sync/__tests__/kb-sync.routes.test.ts +26 -1
  343. package/src/modules/kb-sync/kb-sync.routes.ts +14 -4
  344. package/src/modules/kb-sync/sync-auth.ts +2 -2
  345. package/src/modules/mcp/__tests__/mcp-auth.middleware.test.ts +60 -3
  346. package/src/modules/mcp/__tests__/mcp.e2e.test.ts +4 -3
  347. package/src/modules/mcp/__tests__/mcp.service.test.ts +115 -13
  348. package/src/modules/mcp/mcp-auth.middleware.ts +20 -6
  349. package/src/modules/mcp/mcp.service.ts +46 -7
  350. package/src/modules/mcp/oauth/bevel-oauth-provider.ts +3 -1
  351. package/src/modules/plugins/__tests__/plugins.tools.test.ts +2 -1
  352. package/src/modules/plugins/join-request-records.store.ts +7 -4
  353. package/src/modules/settings/__tests__/deployment-settings.service.test.ts +16 -0
  354. package/src/modules/settings/__tests__/setup.routes.git-mode.test.ts +91 -58
  355. package/src/modules/settings/__tests__/setup.routes.github-app.test.ts +25 -8
  356. package/src/modules/settings/__tests__/setup.routes.managed-phase.test.ts +14 -11
  357. package/src/modules/settings/__tests__/setup.routes.repository-change.test.ts +390 -0
  358. package/src/modules/settings/__tests__/setup.routes.test.ts +3 -0
  359. package/src/modules/settings/deployment-settings.service.ts +8 -3
  360. package/src/modules/settings/setup.routes.ts +263 -19
  361. package/src/modules/skills/__tests__/allowed-tools-warn.tools.test.ts +2 -1
  362. package/src/modules/skills/__tests__/branch-skills.tools.test.ts +218 -0
  363. package/src/modules/skills/__tests__/skills.service.test.ts +229 -5
  364. package/src/modules/skills/skills.contract.ts +91 -18
  365. package/src/modules/skills/skills.service.ts +278 -41
  366. package/src/modules/skills/skills.tools.ts +80 -8
  367. package/src/modules/tool-auth/__tests__/manual-auth.middleware.test.ts +14 -1
  368. package/src/modules/tool-auth/external-api-key.service.ts +12 -4
  369. package/src/modules/tool-auth/internal-token.service.ts +3 -3
  370. package/src/modules/tool-auth/tool-auth.middleware.ts +34 -11
  371. package/src/modules/tool-helpers/__tests__/agent-roles-write.test.ts +5 -3
  372. package/src/modules/tool-helpers/__tests__/phase4-tools.test.ts +3 -3
  373. package/src/modules/tool-helpers/__tests__/validate-token.test.ts +11 -1
  374. package/src/modules/tool-helpers/tool-handler.ts +24 -4
  375. package/src/modules/tool-helpers/tool.contract.ts +3 -2
  376. package/src/modules/tool-helpers/validate-token.ts +1 -1
  377. package/src/modules/tool-manuals/tool-manuals.tools.ts +44 -31
  378. package/src/modules/tool-registry/__tests__/tool-description-length.test.ts +378 -0
  379. package/src/modules/tool-registry/description-length.ts +111 -0
  380. package/src/modules/workflow/__tests__/pending-commits.repository-replaced.test.ts +111 -0
  381. package/src/modules/workflow/__tests__/workflow.routes.history-read-gate.test.ts +25 -0
  382. package/src/modules/workflow/__tests__/workflow.service.repository-replaced.test.ts +249 -0
  383. package/src/modules/workflow/agent-tools/__tests__/workflow.tools.test.ts +264 -6
  384. package/src/modules/workflow/agent-tools/change-request-summary.ts +182 -0
  385. package/src/modules/workflow/agent-tools/workflow.tools.ts +86 -35
  386. package/src/modules/workflow/file-lock.service.ts +31 -0
  387. package/src/modules/workflow/git/__tests__/git.service.fileBytesAtCommit.test.ts +260 -0
  388. package/src/modules/workflow/git/__tests__/git.service.prFetchFailure.test.ts +170 -0
  389. package/src/modules/workflow/git/git.service.ts +215 -1
  390. package/src/modules/workflow/pending-commits.service.ts +64 -2
  391. package/src/modules/workflow/recovery-bot.ts +7 -3
  392. package/src/modules/workflow/review-workflow/__tests__/carry-approvals-forward.test.ts +4 -0
  393. package/src/modules/workflow/review-workflow/__tests__/erase-approver.test.ts +25 -3
  394. package/src/modules/workflow/review-workflow/review-workflow.service.ts +12 -3
  395. package/src/modules/workflow/workflow-hooks.ts +64 -26
  396. package/src/modules/workflow/workflow.service.ts +125 -5
  397. package/src/modules/workspace/__tests__/agent-access.gate.test.ts +208 -0
  398. package/src/modules/workspace/__tests__/agent-uploads.test.ts +1604 -0
  399. package/src/modules/workspace/__tests__/escape-sequences.routes.test.ts +394 -0
  400. package/src/modules/workspace/__tests__/file-stat-access.test.ts +2 -1
  401. package/src/modules/workspace/__tests__/git-internals.security.test.ts +2 -1
  402. package/src/modules/workspace/__tests__/set-aside-clone.test.ts +52 -0
  403. package/src/modules/workspace/__tests__/workspace.routes.at-ref.test.ts +305 -0
  404. package/src/modules/workspace/__tests__/workspace.routes.download.test.ts +2 -0
  405. package/src/modules/workspace/__tests__/workspace.service.any-workspace-credentials.test.ts +156 -0
  406. package/src/modules/workspace/__tests__/workspace.service.forget-clone-races.test.ts +147 -0
  407. package/src/modules/workspace/__tests__/workspace.service.replaced-repository.test.ts +402 -0
  408. package/src/modules/workspace/__tests__/workspace.service.test.ts +77 -9
  409. package/src/modules/workspace/__tests__/workspace.tools.agents-file.test.ts +41 -39
  410. package/src/modules/workspace/__tests__/workspace.tools.branch-errors.test.ts +2 -3
  411. package/src/modules/workspace/__tests__/workspace.tools.test.ts +766 -56
  412. package/src/modules/workspace/agent-access.gate.ts +164 -0
  413. package/src/modules/workspace/agent-upload.routes.ts +214 -0
  414. package/src/modules/workspace/agent-upload.store.ts +668 -0
  415. package/src/modules/workspace/routine-write-policy.ts +5 -6
  416. package/src/modules/workspace/session-sink.ts +5 -5
  417. package/src/modules/workspace/set-aside-clone.ts +96 -0
  418. package/src/modules/workspace/startup/__tests__/kb-startup-runner.test.ts +86 -0
  419. package/src/modules/workspace/startup/kb-startup-runner.ts +115 -34
  420. package/src/modules/workspace/startup/steps/__tests__/steps.test.ts +9 -9
  421. package/src/modules/workspace/startup/steps/seed-tree.ts +3 -6
  422. package/src/modules/workspace/startup/steps/template-source.ts +53 -5
  423. package/src/modules/workspace/upload-limits.ts +12 -0
  424. package/src/modules/workspace/workspace.routes.ts +96 -5
  425. package/src/modules/workspace/workspace.service.ts +319 -61
  426. package/src/modules/workspace/workspace.tools.ts +894 -214
  427. package/src/modules/workspace/write-denial.ts +0 -8
  428. package/src/modules/workspace/zip-entry-rules.ts +173 -0
  429. package/src/modules/write-access/__tests__/write-access.test.ts +248 -0
  430. package/src/modules/write-access/write-access.ts +153 -0
  431. package/src/shared/__tests__/column-crypto.test.ts +217 -0
  432. package/src/shared/column-crypto.ts +218 -0
  433. package/src/shared/domain-errors.ts +31 -0
  434. package/src/shared/git.contract.ts +27 -0
  435. package/src/shared/token-crypto.ts +28 -1
  436. package/src/tenancy/__tests__/static-tenant-source.test.ts +4 -1
  437. package/src/tenancy/static-tenant-source.ts +1 -3
  438. package/src/tenancy/tenant-secrets.ts +5 -1
  439. package/dist/modules/workflow/session-ontology.policy.d.ts +0 -52
  440. package/dist/modules/workflow/session-ontology.policy.d.ts.map +0 -1
  441. package/dist/modules/workflow/session-ontology.policy.js +0 -62
  442. package/dist/modules/workflow/session-ontology.policy.js.map +0 -1
  443. package/dist/modules/workflow/session-ontology.service.d.ts +0 -105
  444. package/dist/modules/workflow/session-ontology.service.d.ts.map +0 -1
  445. package/dist/modules/workflow/session-ontology.service.js +0 -147
  446. package/dist/modules/workflow/session-ontology.service.js.map +0 -1
  447. package/dist/modules/workspace/session-ontology.gate.d.ts +0 -114
  448. package/dist/modules/workspace/session-ontology.gate.d.ts.map +0 -1
  449. package/dist/modules/workspace/session-ontology.gate.js +0 -161
  450. package/dist/modules/workspace/session-ontology.gate.js.map +0 -1
  451. package/dist/shared/kb-layout.d.ts +0 -39
  452. package/dist/shared/kb-layout.d.ts.map +0 -1
  453. package/dist/shared/kb-layout.js +0 -103
  454. package/dist/shared/kb-layout.js.map +0 -1
  455. package/dist/shared/kb-layout.test.d.ts +0 -2
  456. package/dist/shared/kb-layout.test.d.ts.map +0 -1
  457. package/dist/shared/kb-layout.test.js +0 -75
  458. package/dist/shared/kb-layout.test.js.map +0 -1
  459. package/src/modules/workflow/__tests__/session-ontology.policy.test.ts +0 -62
  460. package/src/modules/workflow/__tests__/session-ontology.service.test.ts +0 -201
  461. package/src/modules/workflow/session-ontology.policy.ts +0 -70
  462. package/src/modules/workflow/session-ontology.service.ts +0 -183
  463. package/src/modules/workspace/__tests__/session-ontology.gate.test.ts +0 -239
  464. package/src/modules/workspace/session-ontology.gate.ts +0 -191
  465. package/src/shared/kb-layout.test.ts +0 -98
  466. package/src/shared/kb-layout.ts +0 -102
@@ -0,0 +1,553 @@
1
+ import { createHash, randomBytes } from 'node:crypto';
2
+ import { promises as fs } from 'node:fs';
3
+ import path from 'node:path';
4
+ import AdmZip from 'adm-zip';
5
+ import { logger } from '../../shared/logging.js';
6
+ import { MAX_UPLOAD_BYTES } from './upload-limits.js';
7
+ const log = logger('agent-uploads');
8
+ /** How long an issued token, and the bytes sent against it, stay usable. */
9
+ export const UPLOAD_TOKEN_TTL_MS = 15 * 60 * 1000; // 15 minutes
10
+ /** How often the store looks for tokens that have expired. */
11
+ const SWEEP_INTERVAL_MS = 60 * 1000;
12
+ /**
13
+ * How long past its expiry a CLAIMED record is pinned against the sweep.
14
+ *
15
+ * An apply holds its claim while it resolves the branch (which may clone),
16
+ * reads the bytes, judges every path and commits — work that can outlast a
17
+ * token whose TTL was nearly up when the apply started. Deleting the source
18
+ * mid-apply would make the commit land short with no refusal naming the
19
+ * reason, so a claim keeps its bytes alive. The grace is what stops that from
20
+ * being forever: an apply that neither consumed nor released within it has
21
+ * died with its process (the record is in memory, so there is no third
22
+ * possibility), and the bytes are reclaimed.
23
+ */
24
+ const CLAIM_GRACE_MS = 10 * 60 * 1000; // 10 minutes
25
+ /**
26
+ * THE one refusal for every way a token can fail to be usable: it was never
27
+ * issued, it has already been applied, it has expired, or it belongs to
28
+ * somebody else. One sentence for all four, deliberately — an answer that
29
+ * distinguished "no such token" from "not yours" would let anyone holding a
30
+ * guess learn which guesses exist, and the token is the whole credential this
31
+ * route has.
32
+ */
33
+ export const UPLOAD_TOKEN_REFUSAL = 'That upload token cannot be used: it is unknown, already applied, expired, or was issued to someone else. ' +
34
+ 'Call `request_file_upload` for a new one.';
35
+ /**
36
+ * How many tokens one user may hold open at once.
37
+ *
38
+ * A token is permission to put the deployment's whole upload limit on its
39
+ * disk for a TTL, and to hold a connection open while it arrives. Without a
40
+ * bound, one caller asks for a hundred and sends against all of them
41
+ * together. Ten is far more than the route's own use needs — one token carries
42
+ * a zip of any number of files — and a token is given back the moment it is
43
+ * applied or expires.
44
+ */
45
+ export const MAX_OPEN_UPLOADS_PER_USER = 10;
46
+ /** The refusal an over-limit upload gets, naming the limit that applied. */
47
+ export function overLimit(bytes, maxBytes) {
48
+ return (`That upload is ${bytes} bytes, over this deployment's ${maxBytes} byte upload limit. ` +
49
+ 'Send a smaller file, or split it across several uploads.');
50
+ }
51
+ /** What an upload with no body is told. */
52
+ const EMPTY_UPLOAD = 'That upload carried no bytes. Send the file as the request body — e.g. ' +
53
+ '`curl -X POST --data-binary @<file> "<uploadUrl>?filename=<name>"`.';
54
+ /** A refusal with the HTTP status the upload route and the apply tool both answer. */
55
+ export class UploadTokenError extends Error {
56
+ status;
57
+ constructor(message, status) {
58
+ super(message);
59
+ this.status = status;
60
+ this.name = 'UploadTokenError';
61
+ }
62
+ }
63
+ /**
64
+ * The upload tokens an agent lands files with, and the bytes sent against
65
+ * them.
66
+ *
67
+ * An agent that wants to put 27 files on a branch has no way to do it through
68
+ * a tool argument: the content would have to pass through the model, which
69
+ * truncates, mangles escape characters and cannot carry a PNG at all. So the
70
+ * bytes take a route of their own — this store issues a one-time token, the
71
+ * upload route attaches bytes to it, and `apply_file_upload` lands them.
72
+ *
73
+ * Three properties the whole design rests on, because the upload route is the
74
+ * one endpoint on this server that authenticates by a token alone:
75
+ *
76
+ * - **Unguessable.** 32 random bytes, base64url. Nothing about the token is
77
+ * derived from the user, the time or a counter.
78
+ * - **Never stored in the clear.** Records are keyed by the token's SHA-256,
79
+ * so the store's own memory (and anything that dumps it) holds no usable
80
+ * credential.
81
+ * - **Bound and single-use.** A record carries the id of the user it was
82
+ * issued to and is consumed by the apply that lands it; a second apply, an
83
+ * apply by anyone else, and an apply after the expiry all meet
84
+ * {@link UPLOAD_TOKEN_REFUSAL}.
85
+ *
86
+ * And the bytes land in `root` — a directory beside the workspaces root, not
87
+ * inside one. No file tool can reach it: every workspace path is resolved
88
+ * against a branch's checkout, so there is no spelling of a tool argument that
89
+ * names a file in here. An upload nobody applies is deleted when its token
90
+ * expires (see {@link startSweeping}), so an abandoned drop costs disk for at
91
+ * most one TTL.
92
+ */
93
+ export class AgentUploadStore {
94
+ records = new Map();
95
+ root;
96
+ publicBaseUrl;
97
+ tokenPrefix;
98
+ ttlMs;
99
+ listRoot;
100
+ maxBytes;
101
+ maxOpenPerUser;
102
+ sweepTimer = null;
103
+ /** The sweep in flight, so a shutdown can wait for it — see {@link drainSweep}. */
104
+ sweeping = null;
105
+ /** Set by {@link stopSweeping}: no further sweep deletes anything. */
106
+ stopped = false;
107
+ constructor(options) {
108
+ this.root = options.root;
109
+ this.publicBaseUrl = options.publicBaseUrl.replace(/\/+$/, '');
110
+ this.tokenPrefix = options.tokenPrefix ?? '';
111
+ this.ttlMs = options.ttlMs ?? UPLOAD_TOKEN_TTL_MS;
112
+ this.listRoot = options.listRoot ?? ((root) => fs.readdir(root));
113
+ this.maxBytes = options.maxBytes ?? MAX_UPLOAD_BYTES;
114
+ this.maxOpenPerUser = options.maxOpenPerUser ?? MAX_OPEN_UPLOADS_PER_USER;
115
+ }
116
+ /** The URL a token's bytes are sent to. The one spelling of this route's address. */
117
+ uploadUrlFor(token) {
118
+ return `${this.publicBaseUrl}/api/agent/uploads/${encodeURIComponent(token)}`;
119
+ }
120
+ /**
121
+ * Mint a token for `user` and answer the terms it is good for. Nothing is
122
+ * written to disk yet — a token nobody uploads against costs one map entry
123
+ * until the sweep drops it.
124
+ */
125
+ issue(user) {
126
+ // Counted over what the user still HOLDS: a token that can still be used,
127
+ // and one whose expiry has passed but whose work has not ended — an upload
128
+ // still arriving, an apply still reading. Those keep a connection or a file
129
+ // open exactly as a live token does, so letting them fall out of the count
130
+ // at expiry would let a caller keep ten slow uploads going and ask for ten
131
+ // more. An expired record that is doing nothing is waiting for the sweep,
132
+ // and is not one the user holds.
133
+ const now = Date.now();
134
+ let open = 0;
135
+ for (const record of this.records.values()) {
136
+ if (record.userId !== user.id)
137
+ continue;
138
+ if (record.expiresAt > now || this.pinned(record, now))
139
+ open += 1;
140
+ }
141
+ if (open >= this.maxOpenPerUser) {
142
+ throw new UploadTokenError(`You already hold ${open} upload tokens, the most one user may have open at once. Apply one of them with ` +
143
+ '`apply_file_upload`, or wait for one to expire, then ask again. One token carries a zip of any number of files.', 429);
144
+ }
145
+ const token = this.tokenPrefix + randomBytes(32).toString('base64url');
146
+ const expiresAt = Date.now() + this.ttlMs;
147
+ this.records.set(hash(token), {
148
+ id: `upload-${Date.now()}-${randomBytes(8).toString('hex')}`,
149
+ userId: user.id,
150
+ expiresAt,
151
+ attaching: false,
152
+ claimed: false,
153
+ });
154
+ // AFTER the record exists, not before. The first sweep runs the moment the
155
+ // timer starts, and started from an empty map it would be a sweep that
156
+ // believes nothing is live — this token's own id included.
157
+ this.startSweeping();
158
+ return {
159
+ uploadUrl: this.uploadUrlFor(token),
160
+ token,
161
+ expiresAt: new Date(expiresAt).toISOString(),
162
+ expiresInSeconds: Math.round(this.ttlMs / 1000),
163
+ maxBytes: this.maxBytes,
164
+ };
165
+ }
166
+ /**
167
+ * Store the bytes of `body` against `token` and say what was received. One
168
+ * file per token: a second upload against the same token is refused, so a
169
+ * token cannot be used to keep replacing bytes an apply is about to land.
170
+ *
171
+ * WRITTEN AS THEY ARRIVE, never gathered first. The body is up to the
172
+ * deployment's whole upload limit, and this is the one route a caller can
173
+ * send to without a session: held in memory, a handful of uploads at once
174
+ * cost the process several times that limit each (the chunks, the buffer
175
+ * they were joined into, the archive read over it). Streamed, an upload in
176
+ * flight costs one chunk.
177
+ *
178
+ * A name ending in `.zip` is read as an archive HERE, once the bytes are on
179
+ * disk, so the answer can carry the entry count and so a corrupt archive is
180
+ * refused while the caller is still holding the file — rather than at apply
181
+ * time, when its token would already be spent.
182
+ */
183
+ async receive(token, filename, body) {
184
+ const record = this.openRecord(token);
185
+ // RESERVED FIRST, before any `await`: two uploads arriving at once would
186
+ // otherwise both find the token open, both write, and the apply would land
187
+ // whichever set of bytes finished last — against a token whose answer
188
+ // described the other one.
189
+ record.attaching = true;
190
+ const stored = path.join(this.root, record.id);
191
+ let bytes = 0;
192
+ const received = { filename, bytes: 0, kind: 'file' };
193
+ try {
194
+ await fs.mkdir(this.root, { recursive: true });
195
+ const file = await fs.open(stored, 'w');
196
+ try {
197
+ for await (const chunk of body) {
198
+ const buf = typeof chunk === 'string' ? Buffer.from(chunk) : chunk;
199
+ bytes += buf.byteLength;
200
+ // The real total, counted as it arrives: a `content-length` is the
201
+ // sender's claim, and a chunked body makes none.
202
+ if (bytes > this.maxBytes)
203
+ throw new UploadTokenError(overLimit(bytes, this.maxBytes), 413);
204
+ // To the last byte: one `write` may put down only part of what it
205
+ // was handed and say so in `bytesWritten`, and a chunk counted as
206
+ // received while half of it is on disk would land a file shorter
207
+ // than the size the answer names.
208
+ for (let written = 0; written < buf.byteLength;) {
209
+ written += (await file.write(buf, written, buf.byteLength - written)).bytesWritten;
210
+ }
211
+ }
212
+ }
213
+ finally {
214
+ await file.close();
215
+ }
216
+ if (bytes === 0)
217
+ throw new UploadTokenError(EMPTY_UPLOAD, 400);
218
+ received.bytes = bytes;
219
+ if (filename.toLowerCase().endsWith('.zip')) {
220
+ try {
221
+ received.entries = new AdmZip(stored).getEntries().length;
222
+ }
223
+ catch (err) {
224
+ throw new UploadTokenError(`"${filename}" is not a readable .zip archive: ${err instanceof Error ? err.message : String(err)}`, 422);
225
+ }
226
+ received.kind = 'zip';
227
+ }
228
+ }
229
+ catch (err) {
230
+ // Nothing was received, so the token is open again: the sender may retry
231
+ // with the same one rather than ask for another. Whatever part of the
232
+ // body reached the disk goes now, rather than at the next sweep.
233
+ await this.remove(record.id);
234
+ record.attaching = false;
235
+ throw err;
236
+ }
237
+ // THE TTL MAY HAVE PASSED while the bytes were arriving — a 40 MB upload
238
+ // over a slow link takes real time, and the token was issued before it
239
+ // started. The record was pinned against the sweep throughout (see
240
+ // {@link pinned}), so neither it nor the file could be deleted under the
241
+ // write; but an expired token cannot be applied, so answering "received"
242
+ // would hand the sender a success it can do nothing with. The refusal is
243
+ // the honest answer, and the bytes go with it rather than waiting for a
244
+ // sweep to notice.
245
+ if (record.expiresAt <= Date.now()) {
246
+ this.records.delete(hash(token));
247
+ await this.remove(record.id);
248
+ throw new UploadTokenError(UPLOAD_TOKEN_REFUSAL, 404);
249
+ }
250
+ record.received = received;
251
+ return received;
252
+ }
253
+ /**
254
+ * Refuse `token` if it cannot accept bytes — unknown, expired, somebody
255
+ * else's doing, or already holding a file — and answer its record if it can.
256
+ *
257
+ * Exists as its own step so the upload route can ask BEFORE it reads the
258
+ * body. The route is the one endpoint here authenticated by a token alone,
259
+ * and buffering up to the deployment's whole upload limit for an invented
260
+ * token would let a handful of concurrent requests spend the process's
261
+ * memory on bytes that were never going to be stored.
262
+ */
263
+ assertOpen(token) {
264
+ this.openRecord(token);
265
+ }
266
+ /** {@link assertOpen}, with the record it found — the store's own view of it. */
267
+ openRecord(token) {
268
+ const record = this.find(token);
269
+ if (record.received !== undefined || record.attaching) {
270
+ throw new UploadTokenError(UPLOAD_TOKEN_REFUSAL, 404);
271
+ }
272
+ return record;
273
+ }
274
+ /**
275
+ * Hold `token` for an apply by `userId`, and answer where its bytes are.
276
+ *
277
+ * A CLAIM rather than a consume, because an apply can be refused whole —
278
+ * the destination is on a protected branch the caller may not write, the
279
+ * archive turned out unreadable — and a token spent on a refusal would make
280
+ * the agent send the same 40 MB again to try a different destination. The
281
+ * claim is what keeps it single-use meanwhile: a second apply arriving while
282
+ * the first runs finds the token in use and is refused. The caller
283
+ * {@link consume}s it once an answer exists, or {@link release}s it on a
284
+ * refusal that landed nothing.
285
+ */
286
+ claim(token, userId) {
287
+ const record = this.find(token);
288
+ if (record.userId !== userId || record.claimed || record.received === undefined) {
289
+ throw new UploadTokenError(UPLOAD_TOKEN_REFUSAL, 404);
290
+ }
291
+ record.claimed = true;
292
+ record.claimedAt = Date.now();
293
+ return { ...record.received, absolutePath: path.join(this.root, record.id) };
294
+ }
295
+ /** Give a claimed token back, unused — the apply refused without landing anything. */
296
+ release(token) {
297
+ const record = this.records.get(hash(token));
298
+ if (record) {
299
+ record.claimed = false;
300
+ record.claimedAt = undefined;
301
+ }
302
+ }
303
+ /** Spend the token and delete its bytes. Idempotent. */
304
+ async consume(token) {
305
+ const key = hash(token);
306
+ const record = this.records.get(key);
307
+ if (!record)
308
+ return;
309
+ this.records.delete(key);
310
+ await this.remove(record.id);
311
+ }
312
+ /**
313
+ * Delete every record whose token has expired, with the bytes it was
314
+ * holding — then delete any file in the root that no LIVE record claims and
315
+ * that has outlived every token that could name it.
316
+ *
317
+ * The second half is what makes the first one true. A process killed between
318
+ * the write and the apply leaves a file no map will ever mention again, and
319
+ * sweeping by what the records DON'T name is the honest reading of the
320
+ * promise: an upload nobody applied does not stay. By AGE rather than at
321
+ * once, because a file this map does not name may be another process's (see
322
+ * the loop below).
323
+ *
324
+ * ONE record is kept past its expiry: one an apply has CLAIMED. Those bytes
325
+ * are being read right now, and a sweep that deleted them would make the
326
+ * commit land short of what the answer promised. The pin lasts
327
+ * {@link CLAIM_GRACE_MS}, after which a claim nobody consumed or released
328
+ * belongs to a dead process and is reclaimed.
329
+ */
330
+ async sweepNow() {
331
+ if (this.stopped)
332
+ return;
333
+ const now = Date.now();
334
+ for (const [key, record] of [...this.records]) {
335
+ if (record.expiresAt > now)
336
+ continue;
337
+ if (this.pinned(record, now))
338
+ continue;
339
+ this.records.delete(key);
340
+ await this.remove(record.id);
341
+ }
342
+ let names;
343
+ try {
344
+ names = await this.listRoot(this.root);
345
+ }
346
+ catch {
347
+ return; // root not created yet, or unreadable — nothing to reclaim
348
+ }
349
+ // Every id a live record is holding — including one whose bytes have not
350
+ // arrived yet, so an upload in flight is never swept out from under itself,
351
+ // and one an apply has pinned past its expiry.
352
+ //
353
+ // Read AFTER the directory, never before. The gap between the two is a
354
+ // real one — the readdir is a filesystem round-trip, and this process
355
+ // serves other requests across it — so a token issued and uploaded during
356
+ // that gap would appear in `names` while a set taken earlier had never
357
+ // heard of it, and the sweep would delete bytes somebody had just been
358
+ // told were received. Taken afterwards, the set is a superset of what the
359
+ // listing could possibly name.
360
+ const live = new Set([...this.records.values()].map((r) => r.id));
361
+ for (const name of names) {
362
+ // Asked again per name: a stop (an evicted tenant, a shutdown) that
363
+ // landed while this sweep was reading the directory must not go on to
364
+ // delete files a replacement store may already have issued ids for.
365
+ if (this.stopped)
366
+ return;
367
+ if (live.has(name))
368
+ continue;
369
+ // A file this map does not name is not necessarily nobody's. The records
370
+ // are ONE PROCESS's memory, and two processes share this directory
371
+ // whenever a deployment restarts by starting the new one before the old
372
+ // one has stopped: to each, the other's uploads are files no record
373
+ // names. So such a file goes only once it is older than any token could
374
+ // still be good for — its TTL, and the grace an apply holding it is
375
+ // given. A process that died leaves its files for that long and no
376
+ // longer; a process that is alive never loses one in use.
377
+ if (await this.outlivedEveryToken(name, now))
378
+ await this.remove(name);
379
+ }
380
+ }
381
+ /**
382
+ * Whether the stored file `name` is older than any token that could still be
383
+ * naming it, in this process or another. A file that cannot be examined is
384
+ * left for the next sweep rather than judged.
385
+ */
386
+ async outlivedEveryToken(name, now) {
387
+ try {
388
+ const { mtimeMs } = await fs.stat(path.join(this.root, name));
389
+ return now - mtimeMs > this.ttlMs + CLAIM_GRACE_MS;
390
+ }
391
+ catch {
392
+ return false;
393
+ }
394
+ }
395
+ /**
396
+ * Whether an expired record is held open by work that is still running:
397
+ * an UPLOAD still writing its bytes, or an APPLY still reading them.
398
+ *
399
+ * Both windows can outlast a TTL — a large upload over a slow link, an apply
400
+ * that clones a branch before it reads — and in both the record's own file is
401
+ * being written or read right now. A sweep that deleted either would leave a
402
+ * file no map mentions (the upload writes after the delete) or an apply
403
+ * reading a path that has gone. The apply's pin has a grace, because a claim
404
+ * can be abandoned by a process that dies; the upload's needs none, because
405
+ * `receive` always ends — it clears `attaching` on failure and sets
406
+ * `received` on success, and one whose TTL passed meanwhile deletes the
407
+ * record itself rather than leaving it pinned.
408
+ */
409
+ pinned(record, now) {
410
+ if (record.attaching && record.received === undefined)
411
+ return true;
412
+ return record.claimed && now - (record.claimedAt ?? now) < CLAIM_GRACE_MS;
413
+ }
414
+ /**
415
+ * Sweep now, and keep sweeping. Started by the first {@link issue} rather
416
+ * than at boot, so a deployment nobody uploads to runs no timer; idempotent,
417
+ * and the timer is `unref`'d because nothing here is worth keeping a process
418
+ * alive for — the records are in memory and go with it.
419
+ *
420
+ * The first sweep runs IMMEDIATELY, not one interval later, because the
421
+ * records are in memory: a process that restarted holds no record of what
422
+ * the previous one stored, and what that one left behind long enough ago
423
+ * has no reason to wait a further interval.
424
+ */
425
+ startSweeping(intervalMs = SWEEP_INTERVAL_MS) {
426
+ if (this.sweepTimer)
427
+ return;
428
+ this.stopped = false;
429
+ this.sweep();
430
+ this.sweepTimer = setInterval(() => this.sweep(), intervalMs);
431
+ this.sweepTimer.unref?.();
432
+ }
433
+ /**
434
+ * Stop sweeping, for good: the timer is cleared AND a sweep already running
435
+ * abandons the rest of its work.
436
+ *
437
+ * Both halves matter when a graph is stopped — a tenant evicted, the process
438
+ * shutting down. The root is this tenant's, and a reactivation builds a new
439
+ * store over the same directory with an empty record map: a sweep left
440
+ * running from the old store would find the new store's files named by no
441
+ * record of ITS own and delete them, under an apply that is about to read
442
+ * them. {@link drainSweep} is how a caller waits for the abandonment to
443
+ * actually have happened.
444
+ */
445
+ stopSweeping() {
446
+ this.stopped = true;
447
+ if (this.sweepTimer)
448
+ clearInterval(this.sweepTimer);
449
+ this.sweepTimer = null;
450
+ }
451
+ /** Wait for the sweep in flight, if any. Pairs with {@link stopSweeping} on shutdown. */
452
+ async drainSweep() {
453
+ await this.sweeping;
454
+ }
455
+ /** One sweep, with its failure logged and its promise kept for {@link drainSweep}. */
456
+ sweep() {
457
+ const running = this.sweepNow()
458
+ .catch((err) => {
459
+ log.warn('could not sweep expired uploads:', { err });
460
+ })
461
+ .finally(() => {
462
+ if (this.sweeping === running)
463
+ this.sweeping = null;
464
+ });
465
+ this.sweeping = running;
466
+ }
467
+ /** The live record for `token`, or the one refusal. Expiry is judged here. */
468
+ find(token) {
469
+ const key = hash(token);
470
+ const record = this.records.get(key);
471
+ if (!record)
472
+ throw new UploadTokenError(UPLOAD_TOKEN_REFUSAL, 404);
473
+ const now = Date.now();
474
+ if (record.expiresAt <= now) {
475
+ // Expired either way — but a record an apply is still reading keeps its
476
+ // bytes (and its map entry) until that apply ends, for the reason
477
+ // {@link sweepNow} gives. The refusal is the same; only the deletion waits.
478
+ if (!this.pinned(record, now)) {
479
+ this.records.delete(key);
480
+ void this.remove(record.id);
481
+ }
482
+ throw new UploadTokenError(UPLOAD_TOKEN_REFUSAL, 404);
483
+ }
484
+ return record;
485
+ }
486
+ /** Best-effort delete of one stored upload. Never throws. */
487
+ async remove(id) {
488
+ try {
489
+ await fs.rm(path.join(this.root, id), { force: true });
490
+ }
491
+ catch (err) {
492
+ log.warn(`could not delete the stored upload "${id}":`, { err });
493
+ }
494
+ }
495
+ }
496
+ function hash(token) {
497
+ return createHash('sha256').update(token).digest('hex');
498
+ }
499
+ /**
500
+ * Refuse a boot whose upload root is not OUTSIDE every workspace.
501
+ *
502
+ * The whole safety of this route rests on where the bytes land: they are a
503
+ * buffer somebody sent, judged by nothing until `apply_file_upload` judges each
504
+ * path against a branch. A root configured inside `workspacesRoot` would put
505
+ * that unjudged buffer where the file tools read — `read_file`, `grep`, the
506
+ * download route — bypassing the access and platform-file rules the apply
507
+ * exists to apply. The invariant is documented on `AGENT_UPLOADS_ROOT`; this is
508
+ * it checked, at boot, naming the variable, rather than trusted.
509
+ *
510
+ * Both directions and both spellings: equal paths, either containing the
511
+ * other, and the real paths, so a root that is a LINK into the workspaces tree
512
+ * is refused too.
513
+ */
514
+ export async function assertUploadsRootOutsideWorkspaces(uploadsRoot, workspacesRoot) {
515
+ for (const [uploads, workspaces] of [
516
+ [path.resolve(uploadsRoot), path.resolve(workspacesRoot)],
517
+ [await realBase(uploadsRoot), await realBase(workspacesRoot)],
518
+ ]) {
519
+ if (uploads === workspaces || contains(workspaces, uploads) || contains(uploads, workspaces)) {
520
+ throw new Error(`AGENT_UPLOADS_ROOT ("${uploadsRoot}") must be outside WORKSPACES_ROOT ("${workspacesRoot}"): uploaded ` +
521
+ 'bytes are staged there before any access or platform-file rule has judged them, so a root inside a ' +
522
+ 'workspace would let the file tools read them. Point it at a sibling directory.');
523
+ }
524
+ }
525
+ }
526
+ /** Whether `child` is inside `parent`. Paths already resolved. */
527
+ function contains(parent, child) {
528
+ return child.startsWith(parent.endsWith(path.sep) ? parent : parent + path.sep);
529
+ }
530
+ /**
531
+ * `dir` with every link on it resolved — as far as it exists. Neither root is
532
+ * required to exist yet (the store makes its own on the first upload), so the
533
+ * deepest existing ancestor is resolved and the missing rest joined back on:
534
+ * a link anywhere along the part that DOES exist is what could redirect the
535
+ * one into the other.
536
+ */
537
+ async function realBase(dir) {
538
+ let existing = path.resolve(dir);
539
+ const rest = [];
540
+ for (;;) {
541
+ try {
542
+ return path.join(await fs.realpath(existing), ...rest);
543
+ }
544
+ catch {
545
+ const up = path.dirname(existing);
546
+ if (up === existing)
547
+ return path.join(existing, ...rest);
548
+ rest.unshift(path.basename(existing));
549
+ existing = up;
550
+ }
551
+ }
552
+ }
553
+ //# sourceMappingURL=agent-upload.store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-upload.store.js","sourceRoot":"","sources":["../../../src/modules/workspace/agent-upload.store.ts"],"names":[],"mappings":"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"}
@@ -1,9 +1,9 @@
1
1
  /**
2
2
  * Per-run write restriction for background/routine agents.
3
3
  *
4
- * The ontology-session gate ({@link ../workflow/session-ontology.service}) bounds
5
- * WHICH ontology a run may write; this narrower gate bounds WHAT KIND of file a
6
- * run may write, by extension. It exists for the `watchlist_check` routine, which is
4
+ * The agent-access gate ({@link ./agent-access.gate}) lets a deployment decide
5
+ * WHETHER a run may write a path at all; this narrower gate bounds WHAT KIND of
6
+ * file a run may write, by extension. It exists for the `watchlist_check` routine, which is
7
7
  * allowed to refresh dashboard views (`.html`) but must never touch the
8
8
  * knowledge-graph nodes (`.md`) or any other file — a hard, code-level guarantee
9
9
  * rather than a prompt request (a prompt-only rule has already proven insufficient).
@@ -11,9 +11,8 @@
11
11
  * Keyed by the agent run's `sessionId` (the background agent passes its run id as
12
12
  * the session id, which the internal token then carries onto every loopback tool
13
13
  * call as `ctx.sessionId`). A restriction lives only for the duration of one
14
- * in-process run, so the store is a plain in-memory map — no durability needed,
15
- * unlike the ontology touched-set which must survive restarts and span the MCP
16
- * proxy. The executor sets the restriction before streaming and clears it after.
14
+ * in-process run, so the store is a plain in-memory map — no durability needed.
15
+ * The executor sets the restriction before streaming and clears it after.
17
16
  */
18
17
  export interface IRoutineWritePolicy {
19
18
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"routine-write-policy.d.ts","sourceRoot":"","sources":["../../../src/modules/workspace/routine-write-policy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH,MAAM,WAAW,mBAAmB;IAClC;;;;;OAKG;IACH,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAAC;IAC7E,wDAAwD;IACxD,KAAK,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B;;;;OAIG;IACH,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACxE;;;;OAIG;IACH,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAAC;CACzD;AAED,qBAAa,yBAA0B,YAAW,mBAAmB;IACnE,wEAAwE;IACxE,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAkC;IAE/D,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI;IAI5E,KAAK,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAI9B,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAcvE,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI;CAQxD"}
1
+ {"version":3,"file":"routine-write-policy.d.ts","sourceRoot":"","sources":["../../../src/modules/workspace/routine-write-policy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH,MAAM,WAAW,mBAAmB;IAClC;;;;;OAKG;IACH,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAAC;IAC7E,wDAAwD;IACxD,KAAK,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B;;;;OAIG;IACH,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACxE;;;;OAIG;IACH,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAAC;CACzD;AAED,qBAAa,yBAA0B,YAAW,mBAAmB;IACnE,wEAAwE;IACxE,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAkC;IAE/D,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI;IAI5E,KAAK,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAI9B,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAcvE,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI;CAQxD"}
@@ -1,9 +1,9 @@
1
1
  /**
2
2
  * Per-run write restriction for background/routine agents.
3
3
  *
4
- * The ontology-session gate ({@link ../workflow/session-ontology.service}) bounds
5
- * WHICH ontology a run may write; this narrower gate bounds WHAT KIND of file a
6
- * run may write, by extension. It exists for the `watchlist_check` routine, which is
4
+ * The agent-access gate ({@link ./agent-access.gate}) lets a deployment decide
5
+ * WHETHER a run may write a path at all; this narrower gate bounds WHAT KIND of
6
+ * file a run may write, by extension. It exists for the `watchlist_check` routine, which is
7
7
  * allowed to refresh dashboard views (`.html`) but must never touch the
8
8
  * knowledge-graph nodes (`.md`) or any other file — a hard, code-level guarantee
9
9
  * rather than a prompt request (a prompt-only rule has already proven insufficient).
@@ -11,9 +11,8 @@
11
11
  * Keyed by the agent run's `sessionId` (the background agent passes its run id as
12
12
  * the session id, which the internal token then carries onto every loopback tool
13
13
  * call as `ctx.sessionId`). A restriction lives only for the duration of one
14
- * in-process run, so the store is a plain in-memory map — no durability needed,
15
- * unlike the ontology touched-set which must survive restarts and span the MCP
16
- * proxy. The executor sets the restriction before streaming and clears it after.
14
+ * in-process run, so the store is a plain in-memory map — no durability needed.
15
+ * The executor sets the restriction before streaming and clears it after.
17
16
  */
18
17
  import { ToolError } from '../tool-helpers/tool.contract.js';
19
18
  export class RoutineWritePolicyService {
@@ -1 +1 @@
1
- {"version":3,"file":"routine-write-policy.js","sourceRoot":"","sources":["../../../src/modules/workspace/routine-write-policy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,kCAAkC,CAAC;AA0B7D,MAAM,OAAO,yBAAyB;IACpC,wEAAwE;IACvD,YAAY,GAAG,IAAI,GAAG,EAAuB,CAAC;IAE/D,oBAAoB,CAAC,SAAiB,EAAE,UAA6B;QACnE,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC;IACpF,CAAC;IAED,KAAK,CAAC,SAAiB;QACrB,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACtC,CAAC;IAED,kBAAkB,CAAC,SAA6B,EAAE,MAAc;QAC9D,MAAM,OAAO,GAAG,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QACzE,IAAI,CAAC,OAAO;YAAE,OAAO;QACrB,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC;QACnC,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;YAC1B,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC;gBAAE,OAAO;QAClC,CAAC;QACD,MAAM,IAAI,SAAS,CACjB,2BAA2B,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,8BAA8B,MAAM,gBAAgB;YACpG,uEAAuE,EACzE,GAAG,CACJ,CAAC;IACJ,CAAC;IAED,kBAAkB,CAAC,SAA6B;QAC9C,IAAI,SAAS,IAAI,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;YAClD,MAAM,IAAI,SAAS,CACjB,sHAAsH,EACtH,GAAG,CACJ,CAAC;QACJ,CAAC;IACH,CAAC;CACF"}
1
+ {"version":3,"file":"routine-write-policy.js","sourceRoot":"","sources":["../../../src/modules/workspace/routine-write-policy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,kCAAkC,CAAC;AA0B7D,MAAM,OAAO,yBAAyB;IACpC,wEAAwE;IACvD,YAAY,GAAG,IAAI,GAAG,EAAuB,CAAC;IAE/D,oBAAoB,CAAC,SAAiB,EAAE,UAA6B;QACnE,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC;IACpF,CAAC;IAED,KAAK,CAAC,SAAiB;QACrB,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACtC,CAAC;IAED,kBAAkB,CAAC,SAA6B,EAAE,MAAc;QAC9D,MAAM,OAAO,GAAG,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QACzE,IAAI,CAAC,OAAO;YAAE,OAAO;QACrB,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC;QACnC,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;YAC1B,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC;gBAAE,OAAO;QAClC,CAAC;QACD,MAAM,IAAI,SAAS,CACjB,2BAA2B,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,8BAA8B,MAAM,gBAAgB;YACpG,uEAAuE,EACzE,GAAG,CACJ,CAAC;IACJ,CAAC;IAED,kBAAkB,CAAC,SAA6B;QAC9C,IAAI,SAAS,IAAI,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;YAClD,MAAM,IAAI,SAAS,CACjB,sHAAsH,EACtH,GAAG,CACJ,CAAC;QACJ,CAAC;IACH,CAAC;CACF"}