@bevel-software/platform-core-backend 0.19.0 → 0.21.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 (799) hide show
  1. package/dist/core/catalog-cache-invalidation.d.ts +7 -2
  2. package/dist/core/catalog-cache-invalidation.d.ts.map +1 -1
  3. package/dist/core/catalog-cache-invalidation.js +8 -9
  4. package/dist/core/catalog-cache-invalidation.js.map +1 -1
  5. package/dist/core/core-ports.d.ts +19 -0
  6. package/dist/core/core-ports.d.ts.map +1 -1
  7. package/dist/core/core-ports.js.map +1 -1
  8. package/dist/core/create-core-server.d.ts +2 -0
  9. package/dist/core/create-core-server.d.ts.map +1 -1
  10. package/dist/core/create-core-server.js +45 -105
  11. package/dist/core/create-core-server.js.map +1 -1
  12. package/dist/core/create-core-services.d.ts +33 -5
  13. package/dist/core/create-core-services.d.ts.map +1 -1
  14. package/dist/core/create-core-services.js +146 -82
  15. package/dist/core/create-core-services.js.map +1 -1
  16. package/dist/core/lifecycle.d.ts +74 -28
  17. package/dist/core/lifecycle.d.ts.map +1 -1
  18. package/dist/core/lifecycle.js +157 -20
  19. package/dist/core/lifecycle.js.map +1 -1
  20. package/dist/core/public-config.d.ts +5 -1
  21. package/dist/core/public-config.d.ts.map +1 -1
  22. package/dist/core/public-config.js +7 -5
  23. package/dist/core/public-config.js.map +1 -1
  24. package/dist/core-config.d.ts +95 -1
  25. package/dist/core-config.d.ts.map +1 -1
  26. package/dist/core-config.js +24 -8
  27. package/dist/core-config.js.map +1 -1
  28. package/dist/index.d.ts +5 -3
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +6 -3
  31. package/dist/index.js.map +1 -1
  32. package/dist/modules/access/access-control.service.d.ts +18 -1
  33. package/dist/modules/access/access-control.service.d.ts.map +1 -1
  34. package/dist/modules/access/access-control.service.js +19 -8
  35. package/dist/modules/access/access-control.service.js.map +1 -1
  36. package/dist/modules/access/access.routes.d.ts +2 -1
  37. package/dist/modules/access/access.routes.d.ts.map +1 -1
  38. package/dist/modules/access/access.routes.js +10 -10
  39. package/dist/modules/access/access.routes.js.map +1 -1
  40. package/dist/modules/access/change-read-gate.d.ts +6 -3
  41. package/dist/modules/access/change-read-gate.d.ts.map +1 -1
  42. package/dist/modules/access/change-read-gate.js +9 -6
  43. package/dist/modules/access/change-read-gate.js.map +1 -1
  44. package/dist/modules/access/creator-access.d.ts +4 -2
  45. package/dist/modules/access/creator-access.d.ts.map +1 -1
  46. package/dist/modules/access/creator-access.js +7 -4
  47. package/dist/modules/access/creator-access.js.map +1 -1
  48. package/dist/modules/agent-instructions/read-preamble.d.ts +2 -1
  49. package/dist/modules/agent-instructions/read-preamble.d.ts.map +1 -1
  50. package/dist/modules/agent-instructions/read-preamble.js +6 -9
  51. package/dist/modules/agent-instructions/read-preamble.js.map +1 -1
  52. package/dist/modules/audit/agent-audit.service.d.ts +54 -0
  53. package/dist/modules/audit/agent-audit.service.d.ts.map +1 -0
  54. package/dist/modules/audit/agent-audit.service.js +290 -0
  55. package/dist/modules/audit/agent-audit.service.js.map +1 -0
  56. package/dist/modules/audit/agent-rest-audit.middleware.d.ts +40 -0
  57. package/dist/modules/audit/agent-rest-audit.middleware.d.ts.map +1 -0
  58. package/dist/modules/audit/agent-rest-audit.middleware.js +75 -0
  59. package/dist/modules/audit/agent-rest-audit.middleware.js.map +1 -0
  60. package/dist/modules/audit/audit.contract.d.ts +145 -0
  61. package/dist/modules/audit/audit.contract.d.ts.map +1 -0
  62. package/dist/modules/audit/audit.contract.js +35 -0
  63. package/dist/modules/audit/audit.contract.js.map +1 -0
  64. package/dist/modules/audit/audit.routes.d.ts +21 -0
  65. package/dist/modules/audit/audit.routes.d.ts.map +1 -0
  66. package/dist/modules/audit/audit.routes.js +157 -0
  67. package/dist/modules/audit/audit.routes.js.map +1 -0
  68. package/dist/modules/audit/event-classifier.d.ts +52 -0
  69. package/dist/modules/audit/event-classifier.d.ts.map +1 -0
  70. package/dist/modules/audit/event-classifier.js +123 -0
  71. package/dist/modules/audit/event-classifier.js.map +1 -0
  72. package/dist/modules/audit/index.d.ts +7 -0
  73. package/dist/modules/audit/index.d.ts.map +1 -0
  74. package/dist/modules/audit/index.js +7 -0
  75. package/dist/modules/audit/index.js.map +1 -0
  76. package/dist/modules/audit/request-audit.d.ts +57 -0
  77. package/dist/modules/audit/request-audit.d.ts.map +1 -0
  78. package/dist/modules/audit/request-audit.js +117 -0
  79. package/dist/modules/audit/request-audit.js.map +1 -0
  80. package/dist/modules/auth/account-admission.d.ts +40 -0
  81. package/dist/modules/auth/account-admission.d.ts.map +1 -0
  82. package/dist/modules/auth/account-admission.js +17 -0
  83. package/dist/modules/auth/account-admission.js.map +1 -0
  84. package/dist/modules/auth/account.routes.d.ts.map +1 -1
  85. package/dist/modules/auth/account.routes.js +4 -1
  86. package/dist/modules/auth/account.routes.js.map +1 -1
  87. package/dist/modules/auth/auth.service.d.ts +19 -1
  88. package/dist/modules/auth/auth.service.d.ts.map +1 -1
  89. package/dist/modules/auth/auth.service.js +33 -1
  90. package/dist/modules/auth/auth.service.js.map +1 -1
  91. package/dist/modules/auth/oidc-auth-provider.d.ts.map +1 -1
  92. package/dist/modules/auth/oidc-auth-provider.js +9 -0
  93. package/dist/modules/auth/oidc-auth-provider.js.map +1 -1
  94. package/dist/modules/connection-probe/connection-probe.service.d.ts +13 -1
  95. package/dist/modules/connection-probe/connection-probe.service.d.ts.map +1 -1
  96. package/dist/modules/connection-probe/connection-probe.service.js +10 -2
  97. package/dist/modules/connection-probe/connection-probe.service.js.map +1 -1
  98. package/dist/modules/database/advisory-lock.d.ts +17 -0
  99. package/dist/modules/database/advisory-lock.d.ts.map +1 -1
  100. package/dist/modules/database/advisory-lock.js +24 -3
  101. package/dist/modules/database/advisory-lock.js.map +1 -1
  102. package/dist/modules/database/connection.d.ts +67 -2
  103. package/dist/modules/database/connection.d.ts.map +1 -1
  104. package/dist/modules/database/connection.js +118 -12
  105. package/dist/modules/database/connection.js.map +1 -1
  106. package/dist/modules/database/core-schema.d.ts +414 -0
  107. package/dist/modules/database/core-schema.d.ts.map +1 -1
  108. package/dist/modules/database/core-schema.js +99 -0
  109. package/dist/modules/database/core-schema.js.map +1 -1
  110. package/dist/modules/database/migrate.d.ts +1 -1
  111. package/dist/modules/database/migrate.d.ts.map +1 -1
  112. package/dist/modules/database/migrate.js +27 -3
  113. package/dist/modules/database/migrate.js.map +1 -1
  114. package/dist/modules/diff/diff.service.d.ts.map +1 -1
  115. package/dist/modules/diff/diff.service.js +6 -1
  116. package/dist/modules/diff/diff.service.js.map +1 -1
  117. package/dist/modules/kb-fs/branch-name.d.ts +0 -1
  118. package/dist/modules/kb-fs/branch-name.d.ts.map +1 -1
  119. package/dist/modules/kb-fs/branch-name.js +3 -3
  120. package/dist/modules/kb-fs/branch-name.js.map +1 -1
  121. package/dist/modules/kb-fs/clone-config.d.ts +9 -8
  122. package/dist/modules/kb-fs/clone-config.d.ts.map +1 -1
  123. package/dist/modules/kb-fs/clone-config.js +14 -12
  124. package/dist/modules/kb-fs/clone-config.js.map +1 -1
  125. package/dist/modules/kb-fs/git-guarded-filesystem.d.ts +9 -1
  126. package/dist/modules/kb-fs/git-guarded-filesystem.d.ts.map +1 -1
  127. package/dist/modules/kb-fs/git-guarded-filesystem.js +16 -3
  128. package/dist/modules/kb-fs/git-guarded-filesystem.js.map +1 -1
  129. package/dist/modules/mcp/mcp-auth.middleware.d.ts +1 -0
  130. package/dist/modules/mcp/mcp-auth.middleware.d.ts.map +1 -1
  131. package/dist/modules/mcp/mcp-auth.middleware.js +32 -0
  132. package/dist/modules/mcp/mcp-auth.middleware.js.map +1 -1
  133. package/dist/modules/mcp/mcp.routes.d.ts.map +1 -1
  134. package/dist/modules/mcp/mcp.routes.js +8 -1
  135. package/dist/modules/mcp/mcp.routes.js.map +1 -1
  136. package/dist/modules/mcp/mcp.service.d.ts +16 -1
  137. package/dist/modules/mcp/mcp.service.d.ts.map +1 -1
  138. package/dist/modules/mcp/mcp.service.js +52 -9
  139. package/dist/modules/mcp/mcp.service.js.map +1 -1
  140. package/dist/modules/mcp/oauth/bevel-oauth-provider.d.ts +59 -0
  141. package/dist/modules/mcp/oauth/bevel-oauth-provider.d.ts.map +1 -1
  142. package/dist/modules/mcp/oauth/bevel-oauth-provider.js +180 -8
  143. package/dist/modules/mcp/oauth/bevel-oauth-provider.js.map +1 -1
  144. package/dist/modules/plugins/compile/marketplace-compiler.service.d.ts +4 -4
  145. package/dist/modules/plugins/compile/marketplace-compiler.service.d.ts.map +1 -1
  146. package/dist/modules/plugins/compile/marketplace-compiler.service.js +7 -10
  147. package/dist/modules/plugins/compile/marketplace-compiler.service.js.map +1 -1
  148. package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.d.ts +4 -1
  149. package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.d.ts.map +1 -1
  150. package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.js +5 -3
  151. package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.js.map +1 -1
  152. package/dist/modules/plugins/discovery/kb-plugin-source.d.ts +6 -1
  153. package/dist/modules/plugins/discovery/kb-plugin-source.d.ts.map +1 -1
  154. package/dist/modules/plugins/discovery/kb-plugin-source.js +14 -9
  155. package/dist/modules/plugins/discovery/kb-plugin-source.js.map +1 -1
  156. package/dist/modules/plugins/discovery/native.source.d.ts +4 -1
  157. package/dist/modules/plugins/discovery/native.source.d.ts.map +1 -1
  158. package/dist/modules/plugins/discovery/native.source.js +4 -2
  159. package/dist/modules/plugins/discovery/native.source.js.map +1 -1
  160. package/dist/modules/plugins/index.d.ts +1 -1
  161. package/dist/modules/plugins/index.d.ts.map +1 -1
  162. package/dist/modules/plugins/index.js +1 -1
  163. package/dist/modules/plugins/index.js.map +1 -1
  164. package/dist/modules/plugins/join-request-jobs.service.d.ts +3 -1
  165. package/dist/modules/plugins/join-request-jobs.service.d.ts.map +1 -1
  166. package/dist/modules/plugins/join-request-jobs.service.js +6 -6
  167. package/dist/modules/plugins/join-request-jobs.service.js.map +1 -1
  168. package/dist/modules/plugins/join-requests.service.d.ts +3 -1
  169. package/dist/modules/plugins/join-requests.service.d.ts.map +1 -1
  170. package/dist/modules/plugins/join-requests.service.js +9 -8
  171. package/dist/modules/plugins/join-requests.service.js.map +1 -1
  172. package/dist/modules/plugins/plugin-links.d.ts +65 -10
  173. package/dist/modules/plugins/plugin-links.d.ts.map +1 -1
  174. package/dist/modules/plugins/plugin-links.js +136 -31
  175. package/dist/modules/plugins/plugin-links.js.map +1 -1
  176. package/dist/modules/plugins/plugin-links.service.d.ts +107 -5
  177. package/dist/modules/plugins/plugin-links.service.d.ts.map +1 -1
  178. package/dist/modules/plugins/plugin-links.service.js +151 -21
  179. package/dist/modules/plugins/plugin-links.service.js.map +1 -1
  180. package/dist/modules/plugins/plugin-provision.service.d.ts +10 -3
  181. package/dist/modules/plugins/plugin-provision.service.d.ts.map +1 -1
  182. package/dist/modules/plugins/plugin-provision.service.js +33 -26
  183. package/dist/modules/plugins/plugin-provision.service.js.map +1 -1
  184. package/dist/modules/plugins/plugin-rename.service.d.ts +4 -2
  185. package/dist/modules/plugins/plugin-rename.service.d.ts.map +1 -1
  186. package/dist/modules/plugins/plugin-rename.service.js +10 -12
  187. package/dist/modules/plugins/plugin-rename.service.js.map +1 -1
  188. package/dist/modules/plugins/plugins.routes.d.ts +3 -0
  189. package/dist/modules/plugins/plugins.routes.d.ts.map +1 -1
  190. package/dist/modules/plugins/plugins.routes.js +45 -15
  191. package/dist/modules/plugins/plugins.routes.js.map +1 -1
  192. package/dist/modules/plugins/plugins.service.d.ts +4 -4
  193. package/dist/modules/plugins/plugins.service.d.ts.map +1 -1
  194. package/dist/modules/plugins/plugins.service.js +7 -10
  195. package/dist/modules/plugins/plugins.service.js.map +1 -1
  196. package/dist/modules/plugins/teams.routes.d.ts +4 -1
  197. package/dist/modules/plugins/teams.routes.d.ts.map +1 -1
  198. package/dist/modules/plugins/teams.routes.js +11 -9
  199. package/dist/modules/plugins/teams.routes.js.map +1 -1
  200. package/dist/modules/secrets-vault/index.d.ts +1 -1
  201. package/dist/modules/secrets-vault/index.d.ts.map +1 -1
  202. package/dist/modules/secrets-vault/index.js +1 -1
  203. package/dist/modules/secrets-vault/index.js.map +1 -1
  204. package/dist/modules/secrets-vault/secrets-variable-loader.d.ts +29 -11
  205. package/dist/modules/secrets-vault/secrets-variable-loader.d.ts.map +1 -1
  206. package/dist/modules/secrets-vault/secrets-variable-loader.js +46 -21
  207. package/dist/modules/secrets-vault/secrets-variable-loader.js.map +1 -1
  208. package/dist/modules/secrets-vault/secrets-vault.routes.d.ts +3 -0
  209. package/dist/modules/secrets-vault/secrets-vault.routes.d.ts.map +1 -1
  210. package/dist/modules/secrets-vault/secrets-vault.routes.js +4 -6
  211. package/dist/modules/secrets-vault/secrets-vault.routes.js.map +1 -1
  212. package/dist/modules/settings/deployment-settings.service.d.ts +22 -10
  213. package/dist/modules/settings/deployment-settings.service.d.ts.map +1 -1
  214. package/dist/modules/settings/deployment-settings.service.js +52 -28
  215. package/dist/modules/settings/deployment-settings.service.js.map +1 -1
  216. package/dist/modules/settings/setup.routes.d.ts +9 -2
  217. package/dist/modules/settings/setup.routes.d.ts.map +1 -1
  218. package/dist/modules/settings/setup.routes.js +20 -14
  219. package/dist/modules/settings/setup.routes.js.map +1 -1
  220. package/dist/modules/skills/allowed-tools-check.d.ts +4 -3
  221. package/dist/modules/skills/allowed-tools-check.d.ts.map +1 -1
  222. package/dist/modules/skills/allowed-tools-check.js +8 -8
  223. package/dist/modules/skills/allowed-tools-check.js.map +1 -1
  224. package/dist/modules/skills/pending-skills.service.d.ts +3 -1
  225. package/dist/modules/skills/pending-skills.service.d.ts.map +1 -1
  226. package/dist/modules/skills/pending-skills.service.js +9 -6
  227. package/dist/modules/skills/pending-skills.service.js.map +1 -1
  228. package/dist/modules/skills/skill-access-requests.routes.d.ts +2 -1
  229. package/dist/modules/skills/skill-access-requests.routes.d.ts.map +1 -1
  230. package/dist/modules/skills/skill-access-requests.routes.js +6 -6
  231. package/dist/modules/skills/skill-access-requests.routes.js.map +1 -1
  232. package/dist/modules/skills/skills.routes.d.ts +4 -1
  233. package/dist/modules/skills/skills.routes.d.ts.map +1 -1
  234. package/dist/modules/skills/skills.routes.js +4 -4
  235. package/dist/modules/skills/skills.routes.js.map +1 -1
  236. package/dist/modules/skills/skills.service.d.ts +4 -2
  237. package/dist/modules/skills/skills.service.d.ts.map +1 -1
  238. package/dist/modules/skills/skills.service.js +13 -11
  239. package/dist/modules/skills/skills.service.js.map +1 -1
  240. package/dist/modules/tool-auth/external-api-key.interface.d.ts +21 -5
  241. package/dist/modules/tool-auth/external-api-key.interface.d.ts.map +1 -1
  242. package/dist/modules/tool-auth/external-api-key.interface.js.map +1 -1
  243. package/dist/modules/tool-auth/external-api-key.service.d.ts +1 -0
  244. package/dist/modules/tool-auth/external-api-key.service.d.ts.map +1 -1
  245. package/dist/modules/tool-auth/external-api-key.service.js +22 -9
  246. package/dist/modules/tool-auth/external-api-key.service.js.map +1 -1
  247. package/dist/modules/tool-auth/internal-token.service.d.ts +10 -0
  248. package/dist/modules/tool-auth/internal-token.service.d.ts.map +1 -1
  249. package/dist/modules/tool-auth/internal-token.service.js +1 -0
  250. package/dist/modules/tool-auth/internal-token.service.js.map +1 -1
  251. package/dist/modules/tool-auth/tool-auth.middleware.d.ts +8 -0
  252. package/dist/modules/tool-auth/tool-auth.middleware.d.ts.map +1 -1
  253. package/dist/modules/tool-auth/tool-auth.middleware.js +9 -1
  254. package/dist/modules/tool-auth/tool-auth.middleware.js.map +1 -1
  255. package/dist/modules/tool-manuals/mcp-json-discovery.d.ts +2 -1
  256. package/dist/modules/tool-manuals/mcp-json-discovery.d.ts.map +1 -1
  257. package/dist/modules/tool-manuals/mcp-json-discovery.js +6 -5
  258. package/dist/modules/tool-manuals/mcp-json-discovery.js.map +1 -1
  259. package/dist/modules/tool-manuals/mcp-server-edit.service.d.ts +4 -2
  260. package/dist/modules/tool-manuals/mcp-server-edit.service.d.ts.map +1 -1
  261. package/dist/modules/tool-manuals/mcp-server-edit.service.js +12 -10
  262. package/dist/modules/tool-manuals/mcp-server-edit.service.js.map +1 -1
  263. package/dist/modules/tool-manuals/pending-tools.service.d.ts +3 -1
  264. package/dist/modules/tool-manuals/pending-tools.service.d.ts.map +1 -1
  265. package/dist/modules/tool-manuals/pending-tools.service.js +19 -16
  266. package/dist/modules/tool-manuals/pending-tools.service.js.map +1 -1
  267. package/dist/modules/tool-manuals/tool-delete.service.d.ts +4 -2
  268. package/dist/modules/tool-manuals/tool-delete.service.d.ts.map +1 -1
  269. package/dist/modules/tool-manuals/tool-delete.service.js +14 -12
  270. package/dist/modules/tool-manuals/tool-delete.service.js.map +1 -1
  271. package/dist/modules/tool-manuals/tool-manuals.routes.d.ts +3 -1
  272. package/dist/modules/tool-manuals/tool-manuals.routes.d.ts.map +1 -1
  273. package/dist/modules/tool-manuals/tool-manuals.routes.js +7 -7
  274. package/dist/modules/tool-manuals/tool-manuals.routes.js.map +1 -1
  275. package/dist/modules/tool-manuals/tool-manuals.service.d.ts +4 -2
  276. package/dist/modules/tool-manuals/tool-manuals.service.d.ts.map +1 -1
  277. package/dist/modules/tool-manuals/tool-manuals.service.js +15 -12
  278. package/dist/modules/tool-manuals/tool-manuals.service.js.map +1 -1
  279. package/dist/modules/tool-manuals/tool-manuals.tools.d.ts +3 -0
  280. package/dist/modules/tool-manuals/tool-manuals.tools.d.ts.map +1 -1
  281. package/dist/modules/tool-manuals/tool-manuals.tools.js +4 -6
  282. package/dist/modules/tool-manuals/tool-manuals.tools.js.map +1 -1
  283. package/dist/modules/workflow/agent-tools/workflow.tools.d.ts +3 -2
  284. package/dist/modules/workflow/agent-tools/workflow.tools.d.ts.map +1 -1
  285. package/dist/modules/workflow/agent-tools/workflow.tools.js +9 -9
  286. package/dist/modules/workflow/agent-tools/workflow.tools.js.map +1 -1
  287. package/dist/modules/workflow/git/git.service.d.ts +11 -5
  288. package/dist/modules/workflow/git/git.service.d.ts.map +1 -1
  289. package/dist/modules/workflow/git/git.service.js +23 -14
  290. package/dist/modules/workflow/git/git.service.js.map +1 -1
  291. package/dist/modules/workflow/git/node-git-runner.d.ts +26 -2
  292. package/dist/modules/workflow/git/node-git-runner.d.ts.map +1 -1
  293. package/dist/modules/workflow/git/node-git-runner.js +35 -5
  294. package/dist/modules/workflow/git/node-git-runner.js.map +1 -1
  295. package/dist/modules/workflow/review-workflow/review-workflow.service.d.ts.map +1 -1
  296. package/dist/modules/workflow/review-workflow/review-workflow.service.js +9 -4
  297. package/dist/modules/workflow/review-workflow/review-workflow.service.js.map +1 -1
  298. package/dist/modules/workflow/session-ontology.service.d.ts +6 -1
  299. package/dist/modules/workflow/session-ontology.service.d.ts.map +1 -1
  300. package/dist/modules/workflow/session-ontology.service.js +6 -2
  301. package/dist/modules/workflow/session-ontology.service.js.map +1 -1
  302. package/dist/modules/workflow/workflow.service.d.ts +8 -3
  303. package/dist/modules/workflow/workflow.service.d.ts.map +1 -1
  304. package/dist/modules/workflow/workflow.service.js +33 -23
  305. package/dist/modules/workflow/workflow.service.js.map +1 -1
  306. package/dist/modules/workspace/session-ontology.gate.d.ts +3 -1
  307. package/dist/modules/workspace/session-ontology.gate.d.ts.map +1 -1
  308. package/dist/modules/workspace/session-ontology.gate.js +3 -3
  309. package/dist/modules/workspace/session-ontology.gate.js.map +1 -1
  310. package/dist/modules/workspace/startup/kb-git.d.ts +4 -3
  311. package/dist/modules/workspace/startup/kb-git.d.ts.map +1 -1
  312. package/dist/modules/workspace/startup/kb-git.js +15 -13
  313. package/dist/modules/workspace/startup/kb-git.js.map +1 -1
  314. package/dist/modules/workspace/startup/kb-startup-runner.d.ts +5 -8
  315. package/dist/modules/workspace/startup/kb-startup-runner.d.ts.map +1 -1
  316. package/dist/modules/workspace/startup/kb-startup-runner.js +35 -38
  317. package/dist/modules/workspace/startup/kb-startup-runner.js.map +1 -1
  318. package/dist/modules/workspace/startup/steps/groups-to-plugins.step.d.ts +7 -1
  319. package/dist/modules/workspace/startup/steps/groups-to-plugins.step.d.ts.map +1 -1
  320. package/dist/modules/workspace/startup/steps/groups-to-plugins.step.js +23 -16
  321. package/dist/modules/workspace/startup/steps/groups-to-plugins.step.js.map +1 -1
  322. package/dist/modules/workspace/startup/steps/personal-spaces.step.d.ts +7 -1
  323. package/dist/modules/workspace/startup/steps/personal-spaces.step.d.ts.map +1 -1
  324. package/dist/modules/workspace/startup/steps/personal-spaces.step.js +12 -5
  325. package/dist/modules/workspace/startup/steps/personal-spaces.step.js.map +1 -1
  326. package/dist/modules/workspace/startup/steps/plugin-display-names.step.d.ts +7 -1
  327. package/dist/modules/workspace/startup/steps/plugin-display-names.step.d.ts.map +1 -1
  328. package/dist/modules/workspace/startup/steps/plugin-display-names.step.js +12 -5
  329. package/dist/modules/workspace/startup/steps/plugin-display-names.step.js.map +1 -1
  330. package/dist/modules/workspace/startup/steps/plugin-manifests.step.d.ts +7 -1
  331. package/dist/modules/workspace/startup/steps/plugin-manifests.step.d.ts.map +1 -1
  332. package/dist/modules/workspace/startup/steps/plugin-manifests.step.js +12 -5
  333. package/dist/modules/workspace/startup/steps/plugin-manifests.step.js.map +1 -1
  334. package/dist/modules/workspace/startup/steps/seed-tree.d.ts +4 -1
  335. package/dist/modules/workspace/startup/steps/seed-tree.d.ts.map +1 -1
  336. package/dist/modules/workspace/startup/steps/seed-tree.js +14 -11
  337. package/dist/modules/workspace/startup/steps/seed-tree.js.map +1 -1
  338. package/dist/modules/workspace/startup/steps/template-files.step.d.ts +17 -3
  339. package/dist/modules/workspace/startup/steps/template-files.step.d.ts.map +1 -1
  340. package/dist/modules/workspace/startup/steps/template-files.step.js +36 -30
  341. package/dist/modules/workspace/startup/steps/template-files.step.js.map +1 -1
  342. package/dist/modules/workspace/startup/steps/template-source.d.ts +6 -1
  343. package/dist/modules/workspace/startup/steps/template-source.d.ts.map +1 -1
  344. package/dist/modules/workspace/startup/steps/template-source.js +10 -6
  345. package/dist/modules/workspace/startup/steps/template-source.js.map +1 -1
  346. package/dist/modules/workspace/workspace.routes.d.ts +2 -1
  347. package/dist/modules/workspace/workspace.routes.d.ts.map +1 -1
  348. package/dist/modules/workspace/workspace.routes.js +8 -7
  349. package/dist/modules/workspace/workspace.routes.js.map +1 -1
  350. package/dist/modules/workspace/workspace.service.d.ts +26 -12
  351. package/dist/modules/workspace/workspace.service.d.ts.map +1 -1
  352. package/dist/modules/workspace/workspace.service.js +41 -28
  353. package/dist/modules/workspace/workspace.service.js.map +1 -1
  354. package/dist/modules/workspace/workspace.tools.d.ts +2 -1
  355. package/dist/modules/workspace/workspace.tools.d.ts.map +1 -1
  356. package/dist/modules/workspace/workspace.tools.js +69 -31
  357. package/dist/modules/workspace/workspace.tools.js.map +1 -1
  358. package/dist/modules/workspace/write-denial.d.ts +3 -2
  359. package/dist/modules/workspace/write-denial.d.ts.map +1 -1
  360. package/dist/modules/workspace/write-denial.js +6 -5
  361. package/dist/modules/workspace/write-denial.js.map +1 -1
  362. package/dist/shared/git-internals.d.ts +7 -1
  363. package/dist/shared/git-internals.d.ts.map +1 -1
  364. package/dist/shared/git-internals.js +67 -9
  365. package/dist/shared/git-internals.js.map +1 -1
  366. package/dist/shared/git.contract.d.ts +52 -7
  367. package/dist/shared/git.contract.d.ts.map +1 -1
  368. package/dist/shared/git.contract.js +30 -8
  369. package/dist/shared/git.contract.js.map +1 -1
  370. package/dist/shared/kb-context.d.ts +76 -0
  371. package/dist/shared/kb-context.d.ts.map +1 -0
  372. package/dist/shared/kb-context.js +108 -0
  373. package/dist/shared/kb-context.js.map +1 -0
  374. package/dist/shared/kb-layout.d.ts +3 -2
  375. package/dist/shared/kb-layout.d.ts.map +1 -1
  376. package/dist/shared/kb-layout.js +4 -3
  377. package/dist/shared/kb-layout.js.map +1 -1
  378. package/dist/shared/kb-layout.test.js +35 -27
  379. package/dist/shared/kb-layout.test.js.map +1 -1
  380. package/dist/shared/pending-proposals.d.ts +4 -1
  381. package/dist/shared/pending-proposals.d.ts.map +1 -1
  382. package/dist/shared/pending-proposals.js +3 -4
  383. package/dist/shared/pending-proposals.js.map +1 -1
  384. package/dist/shared/redact-secret.d.ts +5 -5
  385. package/dist/shared/redact-secret.js +5 -5
  386. package/dist/tenancy/index.d.ts +13 -0
  387. package/dist/tenancy/index.d.ts.map +1 -0
  388. package/dist/tenancy/index.js +13 -0
  389. package/dist/tenancy/index.js.map +1 -0
  390. package/dist/tenancy/static-tenant-source.d.ts +98 -0
  391. package/dist/tenancy/static-tenant-source.d.ts.map +1 -0
  392. package/dist/tenancy/static-tenant-source.js +220 -0
  393. package/dist/tenancy/static-tenant-source.js.map +1 -0
  394. package/dist/tenancy/tenant-host.d.ts +80 -0
  395. package/dist/tenancy/tenant-host.d.ts.map +1 -0
  396. package/dist/tenancy/tenant-host.js +217 -0
  397. package/dist/tenancy/tenant-host.js.map +1 -0
  398. package/dist/tenancy/tenant-runtime.d.ts +91 -0
  399. package/dist/tenancy/tenant-runtime.d.ts.map +1 -0
  400. package/dist/tenancy/tenant-runtime.js +174 -0
  401. package/dist/tenancy/tenant-runtime.js.map +1 -0
  402. package/dist/tenancy/tenant-secrets.d.ts +24 -0
  403. package/dist/tenancy/tenant-secrets.d.ts.map +1 -0
  404. package/dist/tenancy/tenant-secrets.js +30 -0
  405. package/dist/tenancy/tenant-secrets.js.map +1 -0
  406. package/dist/tenancy/tenant-source.contract.d.ts +45 -0
  407. package/dist/tenancy/tenant-source.contract.d.ts.map +1 -0
  408. package/dist/tenancy/tenant-source.contract.js +21 -0
  409. package/dist/tenancy/tenant-source.contract.js.map +1 -0
  410. package/migrations/0000_core_init.sql +14 -14
  411. package/migrations/0003_deployment_settings.sql +1 -1
  412. package/migrations/0005_github_facade.sql +1 -1
  413. package/migrations/0012_agent_audit.sql +41 -0
  414. package/migrations/0013_agent_identity_and_key_soft_delete.sql +29 -0
  415. package/migrations/meta/0012_snapshot.json +2247 -0
  416. package/migrations/meta/0013_snapshot.json +2259 -0
  417. package/migrations/meta/_journal.json +14 -0
  418. package/package.json +4 -4
  419. package/src/__tests__/branch-model.test.ts +7 -6
  420. package/src/__tests__/kb-context.ts +30 -0
  421. package/src/__tests__/kb-layout-config.test.ts +35 -30
  422. package/src/core/__tests__/catalog-cache-invalidation.test.ts +2 -1
  423. package/src/core/__tests__/lifecycle.test.ts +78 -1
  424. package/src/core/__tests__/public-config.test.ts +5 -1
  425. package/src/core/catalog-cache-invalidation.ts +16 -11
  426. package/src/core/core-ports.ts +19 -0
  427. package/src/core/create-core-server.ts +55 -106
  428. package/src/core/create-core-services.ts +193 -95
  429. package/src/core/lifecycle.ts +214 -29
  430. package/src/core/public-config.ts +8 -5
  431. package/src/core-config.ts +107 -8
  432. package/src/index.ts +25 -2
  433. package/src/modules/access/__tests__/access-control.admin-root-floor.test.ts +2 -1
  434. package/src/modules/access/__tests__/access.routes.batch.test.ts +2 -1
  435. package/src/modules/access/__tests__/access.routes.folder-governs.test.ts +2 -1
  436. package/src/modules/access/__tests__/access.routes.group-grant.test.ts +2 -1
  437. package/src/modules/access/__tests__/access.routes.overrides.test.ts +2 -1
  438. package/src/modules/access/__tests__/access.routes.proposal-branch.test.ts +2 -1
  439. package/src/modules/access/__tests__/access.routes.prospective.test.ts +2 -1
  440. package/src/modules/access/__tests__/access.routes.revoke.test.ts +2 -1
  441. package/src/modules/access/__tests__/access.routes.unknown-email.test.ts +2 -1
  442. package/src/modules/access/__tests__/change-read-gate.test.ts +13 -11
  443. package/src/modules/access/__tests__/creator-access.test.ts +3 -2
  444. package/src/modules/access/__tests__/roles.routes.test.ts +2 -1
  445. package/src/modules/access/access-control.service.ts +20 -6
  446. package/src/modules/access/access.routes.ts +10 -13
  447. package/src/modules/access/change-read-gate.ts +10 -4
  448. package/src/modules/access/creator-access.ts +7 -2
  449. package/src/modules/agent-instructions/__tests__/read-preamble.test.ts +13 -12
  450. package/src/modules/agent-instructions/read-preamble.ts +10 -12
  451. package/src/modules/audit/__tests__/agent-audit.service.test.ts +370 -0
  452. package/src/modules/audit/__tests__/agent-rest-audit.middleware.test.ts +113 -0
  453. package/src/modules/audit/__tests__/audit.routes.test.ts +201 -0
  454. package/src/modules/audit/__tests__/event-classifier.test.ts +121 -0
  455. package/src/modules/audit/agent-audit.service.ts +316 -0
  456. package/src/modules/audit/agent-rest-audit.middleware.ts +83 -0
  457. package/src/modules/audit/audit.contract.ts +164 -0
  458. package/src/modules/audit/audit.routes.ts +168 -0
  459. package/src/modules/audit/event-classifier.ts +155 -0
  460. package/src/modules/audit/index.ts +14 -0
  461. package/src/modules/audit/request-audit.ts +141 -0
  462. package/src/modules/auth/__tests__/account.routes.test.ts +15 -0
  463. package/src/modules/auth/__tests__/auth.service.test.ts +60 -0
  464. package/src/modules/auth/account-admission.ts +44 -0
  465. package/src/modules/auth/account.routes.ts +4 -1
  466. package/src/modules/auth/auth.service.ts +33 -1
  467. package/src/modules/auth/oidc-auth-provider.ts +9 -0
  468. package/src/modules/connection-probe/connection-probe.service.ts +7 -1
  469. package/src/modules/database/__tests__/advisory-lock.test.ts +23 -1
  470. package/src/modules/database/__tests__/connection.test.ts +98 -0
  471. package/src/modules/database/__tests__/migrations-unqualified.test.ts +32 -0
  472. package/src/modules/database/advisory-lock.ts +28 -4
  473. package/src/modules/database/connection.ts +143 -13
  474. package/src/modules/database/core-schema.ts +104 -0
  475. package/src/modules/database/migrate.ts +48 -14
  476. package/src/modules/diff/__tests__/diff.service.seed-atomicity.test.ts +2 -1
  477. package/src/modules/diff/__tests__/diff.service.test.ts +2 -1
  478. package/src/modules/diff/diff.service.ts +6 -1
  479. package/src/modules/kb-fs/__tests__/branch-name.test.ts +6 -6
  480. package/src/modules/kb-fs/__tests__/clone-config.test.ts +24 -20
  481. package/src/modules/kb-fs/branch-name.ts +3 -3
  482. package/src/modules/kb-fs/clone-config.ts +15 -12
  483. package/src/modules/kb-fs/git-guarded-filesystem.ts +16 -3
  484. package/src/modules/marketplace/__tests__/marketplace-repo.head.test.ts +2 -1
  485. package/src/modules/mcp/__tests__/bevel-oauth-provider.test.ts +183 -13
  486. package/src/modules/mcp/__tests__/mcp-auth.middleware.test.ts +60 -2
  487. package/src/modules/mcp/__tests__/mcp.routes.local-token.test.ts +24 -4
  488. package/src/modules/mcp/__tests__/mcp.routes.stateless.test.ts +1 -1
  489. package/src/modules/mcp/__tests__/mcp.service.test.ts +120 -3
  490. package/src/modules/mcp/mcp-auth.middleware.ts +31 -0
  491. package/src/modules/mcp/mcp.routes.ts +11 -1
  492. package/src/modules/mcp/mcp.service.ts +73 -8
  493. package/src/modules/mcp/oauth/bevel-oauth-provider.ts +184 -6
  494. package/src/modules/plugins/__tests__/bundle-dialect.e2e.test.ts +12 -11
  495. package/src/modules/plugins/__tests__/bundle-dialect.test.ts +2 -1
  496. package/src/modules/plugins/__tests__/compile-marketplace.test.ts +6 -4
  497. package/src/modules/plugins/__tests__/join-request-jobs.service.test.ts +2 -1
  498. package/src/modules/plugins/__tests__/join-requests.service.test.ts +2 -1
  499. package/src/modules/plugins/__tests__/plugin-creation-display-name.test.ts +4 -3
  500. package/src/modules/plugins/__tests__/plugin-index.service.test.ts +6 -4
  501. package/src/modules/plugins/__tests__/plugin-links.service.test.ts +220 -5
  502. package/src/modules/plugins/__tests__/plugin-provision.service.test.ts +3 -1
  503. package/src/modules/plugins/__tests__/plugin-rename.service.test.ts +7 -6
  504. package/src/modules/plugins/__tests__/plugins.routes.test.ts +11 -2
  505. package/src/modules/plugins/__tests__/teams.routes.test.ts +2 -1
  506. package/src/modules/plugins/compile/marketplace-compiler.service.ts +7 -9
  507. package/src/modules/plugins/discovery/__tests__/kb-plugin-source.test.ts +20 -16
  508. package/src/modules/plugins/discovery/bundle-dialect/bundle.source.ts +9 -2
  509. package/src/modules/plugins/discovery/kb-plugin-source.ts +15 -8
  510. package/src/modules/plugins/discovery/native.source.ts +4 -1
  511. package/src/modules/plugins/index.ts +1 -1
  512. package/src/modules/plugins/join-request-jobs.service.ts +8 -7
  513. package/src/modules/plugins/join-requests.service.ts +7 -7
  514. package/src/modules/plugins/plugin-links.service.ts +192 -19
  515. package/src/modules/plugins/plugin-links.ts +147 -27
  516. package/src/modules/plugins/plugin-provision.service.ts +54 -27
  517. package/src/modules/plugins/plugin-rename.service.ts +10 -10
  518. package/src/modules/plugins/plugins.routes.ts +45 -15
  519. package/src/modules/plugins/plugins.service.ts +7 -11
  520. package/src/modules/plugins/teams.routes.ts +16 -8
  521. package/src/modules/secrets-vault/__tests__/connect-pending.route.test.ts +7 -0
  522. package/src/modules/secrets-vault/__tests__/secrets-variable-loader.test.ts +40 -0
  523. package/src/modules/secrets-vault/__tests__/tool-owner-gate.route.test.ts +2 -0
  524. package/src/modules/secrets-vault/index.ts +2 -0
  525. package/src/modules/secrets-vault/secrets-variable-loader.ts +51 -21
  526. package/src/modules/secrets-vault/secrets-vault.routes.ts +7 -6
  527. package/src/modules/settings/__tests__/deployment-settings.service.test.ts +59 -11
  528. package/src/modules/settings/__tests__/git-root-folders.test.ts +2 -1
  529. package/src/modules/settings/__tests__/setup.routes.boot-failure.test.ts +2 -1
  530. package/src/modules/settings/__tests__/setup.routes.layout-phase.test.ts +7 -4
  531. package/src/modules/settings/__tests__/setup.routes.oidc.test.ts +2 -0
  532. package/src/modules/settings/__tests__/setup.routes.sync-status.test.ts +2 -0
  533. package/src/modules/settings/__tests__/setup.routes.test.ts +33 -52
  534. package/src/modules/settings/deployment-settings.service.ts +68 -28
  535. package/src/modules/settings/setup.routes.ts +26 -16
  536. package/src/modules/skills/__tests__/allowed-tools-check.test.ts +11 -10
  537. package/src/modules/skills/__tests__/allowed-tools-warn.tools.test.ts +4 -3
  538. package/src/modules/skills/__tests__/pending-skills.service.test.ts +3 -1
  539. package/src/modules/skills/__tests__/skill-access-requests.routes.test.ts +2 -1
  540. package/src/modules/skills/__tests__/skills.routes.warnings.test.ts +2 -1
  541. package/src/modules/skills/__tests__/skills.service.test.ts +3 -2
  542. package/src/modules/skills/allowed-tools-check.ts +7 -6
  543. package/src/modules/skills/pending-skills.service.ts +9 -8
  544. package/src/modules/skills/skill-access-requests.routes.ts +7 -7
  545. package/src/modules/skills/skills.routes.ts +4 -3
  546. package/src/modules/skills/skills.service.ts +13 -9
  547. package/src/modules/tool-auth/__tests__/external-api-key.service.test.ts +29 -8
  548. package/src/modules/tool-auth/__tests__/internal-token.service.test.ts +6 -0
  549. package/src/modules/tool-auth/external-api-key.interface.ts +22 -5
  550. package/src/modules/tool-auth/external-api-key.service.ts +25 -8
  551. package/src/modules/tool-auth/internal-token.service.ts +11 -0
  552. package/src/modules/tool-auth/tool-auth.middleware.ts +17 -1
  553. package/src/modules/tool-helpers/__tests__/agent-roles-write.test.ts +3 -2
  554. package/src/modules/tool-helpers/__tests__/phase4-tools.test.ts +3 -2
  555. package/src/modules/tool-manuals/__tests__/mcp-json-discovery.test.ts +17 -12
  556. package/src/modules/tool-manuals/__tests__/mcp-server-edit.service.test.ts +2 -1
  557. package/src/modules/tool-manuals/__tests__/pending-tools.service.test.ts +4 -1
  558. package/src/modules/tool-manuals/__tests__/tool-delete.service.test.ts +2 -1
  559. package/src/modules/tool-manuals/__tests__/tool-manuals.archive.route.test.ts +2 -1
  560. package/src/modules/tool-manuals/__tests__/tool-manuals.cli.test.ts +5 -4
  561. package/src/modules/tool-manuals/__tests__/tool-manuals.detail.route.test.ts +2 -1
  562. package/src/modules/tool-manuals/__tests__/tool-manuals.invalid.routes.test.ts +4 -2
  563. package/src/modules/tool-manuals/__tests__/tool-manuals.invalid.test.ts +13 -5
  564. package/src/modules/tool-manuals/__tests__/tool-manuals.mcp-oauth.test.ts +2 -1
  565. package/src/modules/tool-manuals/__tests__/tool-manuals.restart.test.ts +9 -1
  566. package/src/modules/tool-manuals/__tests__/tool-manuals.service.test.ts +3 -2
  567. package/src/modules/tool-manuals/__tests__/tool-manuals.tools.test.ts +2 -0
  568. package/src/modules/tool-manuals/mcp-json-discovery.ts +6 -4
  569. package/src/modules/tool-manuals/mcp-server-edit.service.ts +13 -11
  570. package/src/modules/tool-manuals/pending-tools.service.ts +19 -16
  571. package/src/modules/tool-manuals/tool-delete.service.ts +13 -10
  572. package/src/modules/tool-manuals/tool-manuals.routes.ts +10 -8
  573. package/src/modules/tool-manuals/tool-manuals.service.ts +15 -13
  574. package/src/modules/tool-manuals/tool-manuals.tools.ts +7 -6
  575. package/src/modules/workflow/__tests__/apply-failure.test.ts +2 -1
  576. package/src/modules/workflow/__tests__/merge-announces-tree.test.ts +14 -26
  577. package/src/modules/workflow/__tests__/preserve-roles-yaml.test.ts +2 -1
  578. package/src/modules/workflow/__tests__/session-ontology.service.test.ts +3 -2
  579. package/src/modules/workflow/__tests__/workflow.routes.lock-path.test.ts +2 -1
  580. package/src/modules/workflow/__tests__/workflow.service.branch-in-use.test.ts +3 -10
  581. package/src/modules/workflow/__tests__/workflow.service.commitFileWhileLocked.test.ts +2 -1
  582. package/src/modules/workflow/__tests__/workflow.service.deleted-branch-sweep.test.ts +3 -10
  583. package/src/modules/workflow/__tests__/workflow.service.facade.test.ts +28 -27
  584. package/src/modules/workflow/__tests__/workflow.service.folder-proposals.test.ts +2 -1
  585. package/src/modules/workflow/__tests__/workflow.service.platform-restore.test.ts +2 -1
  586. package/src/modules/workflow/__tests__/workflow.service.read-gate.test.ts +3 -2
  587. package/src/modules/workflow/__tests__/workflow.service.releaseLock.test.ts +2 -1
  588. package/src/modules/workflow/__tests__/workflow.service.sync.test.ts +5 -4
  589. package/src/modules/workflow/__tests__/workflow.service.update-from-target.test.ts +2 -1
  590. package/src/modules/workflow/agent-tools/__tests__/workflow.tools.test.ts +2 -1
  591. package/src/modules/workflow/agent-tools/workflow.tools.ts +11 -9
  592. package/src/modules/workflow/git/__tests__/git.service.accessGating.test.ts +5 -4
  593. package/src/modules/workflow/git/__tests__/git.service.changedFilesForPr.test.ts +12 -11
  594. package/src/modules/workflow/git/__tests__/git.service.commitChanges.test.ts +9 -8
  595. package/src/modules/workflow/git/__tests__/git.service.commitFile.strayPath.test.ts +8 -7
  596. package/src/modules/workflow/git/__tests__/git.service.commitFile.test.ts +6 -5
  597. package/src/modules/workflow/git/__tests__/git.service.createBranch.test.ts +3 -2
  598. package/src/modules/workflow/git/__tests__/git.service.deleteBranch.test.ts +3 -2
  599. package/src/modules/workflow/git/__tests__/git.service.diffFileAtCommit.test.ts +7 -6
  600. package/src/modules/workflow/git/__tests__/git.service.diffFileBetweenBranches.test.ts +16 -15
  601. package/src/modules/workflow/git/__tests__/git.service.fileContentsAtCommit.test.ts +3 -2
  602. package/src/modules/workflow/git/__tests__/git.service.forkPoint.test.ts +2 -1
  603. package/src/modules/workflow/git/__tests__/git.service.history-guards.test.ts +2 -1
  604. package/src/modules/workflow/git/__tests__/git.service.list-branches.test.ts +10 -9
  605. package/src/modules/workflow/git/__tests__/git.service.listTrackedFiles.test.ts +2 -1
  606. package/src/modules/workflow/git/__tests__/git.service.logForFile.test.ts +6 -5
  607. package/src/modules/workflow/git/__tests__/git.service.mergeChangeRequest.test.ts +9 -8
  608. package/src/modules/workflow/git/__tests__/git.service.pendingChanges.test.ts +2 -1
  609. package/src/modules/workflow/git/__tests__/git.service.postMergePull.test.ts +4 -3
  610. package/src/modules/workflow/git/__tests__/git.service.pull.test.ts +9 -8
  611. package/src/modules/workflow/git/__tests__/git.service.readFileAtRef.test.ts +2 -1
  612. package/src/modules/workflow/git/__tests__/git.service.revertPathsAndPush.test.ts +2 -1
  613. package/src/modules/workflow/git/__tests__/git.service.status.test.ts +4 -3
  614. package/src/modules/workflow/git/__tests__/git.service.syncFromRemote.test.ts +8 -7
  615. package/src/modules/workflow/git/__tests__/node-git-runner.test.ts +41 -3
  616. package/src/modules/workflow/git/git.service.ts +24 -13
  617. package/src/modules/workflow/git/node-git-runner.ts +37 -4
  618. package/src/modules/workflow/review-workflow/review-workflow.service.ts +9 -6
  619. package/src/modules/workflow/session-ontology.service.ts +7 -2
  620. package/src/modules/workflow/workflow.service.ts +31 -24
  621. package/src/modules/workspace/__tests__/file-stat-access.test.ts +3 -2
  622. package/src/modules/workspace/__tests__/git-internals.security.test.ts +144 -52
  623. package/src/modules/workspace/__tests__/session-ontology.gate.test.ts +4 -2
  624. package/src/modules/workspace/__tests__/workspace-paths-inside-the-repo.test.ts +3 -2
  625. package/src/modules/workspace/__tests__/workspace.routes.branch-errors.test.ts +2 -1
  626. package/src/modules/workspace/__tests__/workspace.routes.create-grant.test.ts +2 -1
  627. package/src/modules/workspace/__tests__/workspace.routes.delete.test.ts +2 -1
  628. package/src/modules/workspace/__tests__/workspace.routes.download-implies-read.test.ts +2 -1
  629. package/src/modules/workspace/__tests__/workspace.routes.download.test.ts +2 -1
  630. package/src/modules/workspace/__tests__/workspace.routes.file-writes.test.ts +2 -1
  631. package/src/modules/workspace/__tests__/workspace.routes.folders.test.ts +5 -4
  632. package/src/modules/workspace/__tests__/workspace.routes.move-platform-files.test.ts +2 -1
  633. package/src/modules/workspace/__tests__/workspace.routes.read-gate.test.ts +2 -1
  634. package/src/modules/workspace/__tests__/workspace.service.ensure-remotes-fetched.test.ts +2 -2
  635. package/src/modules/workspace/__tests__/workspace.service.list-cloned.test.ts +6 -5
  636. package/src/modules/workspace/__tests__/workspace.service.move-never-overwrites.test.ts +2 -1
  637. package/src/modules/workspace/__tests__/workspace.service.read-filter.test.ts +2 -1
  638. package/src/modules/workspace/__tests__/workspace.service.test.ts +84 -50
  639. package/src/modules/workspace/__tests__/workspace.service.unknown-branch.test.ts +2 -1
  640. package/src/modules/workspace/__tests__/workspace.tools.agents-file.test.ts +10 -7
  641. package/src/modules/workspace/__tests__/workspace.tools.branch-errors.test.ts +4 -3
  642. package/src/modules/workspace/__tests__/workspace.tools.test.ts +9 -8
  643. package/src/modules/workspace/__tests__/write-denial.test.ts +5 -4
  644. package/src/modules/workspace/session-ontology.gate.ts +6 -4
  645. package/src/modules/workspace/startup/__tests__/kb-startup-runner.degraded.test.ts +6 -2
  646. package/src/modules/workspace/startup/__tests__/kb-startup-runner.test.ts +29 -21
  647. package/src/modules/workspace/startup/kb-git.ts +15 -22
  648. package/src/modules/workspace/startup/kb-startup-runner.ts +40 -46
  649. package/src/modules/workspace/startup/steps/__tests__/steps.test.ts +104 -98
  650. package/src/modules/workspace/startup/steps/groups-to-plugins.step.ts +24 -16
  651. package/src/modules/workspace/startup/steps/personal-spaces.step.ts +14 -5
  652. package/src/modules/workspace/startup/steps/plugin-display-names.step.ts +13 -5
  653. package/src/modules/workspace/startup/steps/plugin-manifests.step.ts +14 -5
  654. package/src/modules/workspace/startup/steps/seed-tree.ts +11 -9
  655. package/src/modules/workspace/startup/steps/template-files.step.ts +43 -34
  656. package/src/modules/workspace/startup/steps/template-source.ts +8 -5
  657. package/src/modules/workspace/workspace.routes.ts +8 -7
  658. package/src/modules/workspace/workspace.service.ts +39 -27
  659. package/src/modules/workspace/workspace.tools.ts +68 -31
  660. package/src/modules/workspace/write-denial.ts +7 -5
  661. package/src/shared/__tests__/git-internals.test.ts +41 -0
  662. package/src/shared/__tests__/kb-layout.plugin.test.ts +19 -16
  663. package/src/shared/git-internals.ts +61 -6
  664. package/src/shared/git.contract.ts +70 -8
  665. package/src/shared/kb-context.ts +130 -0
  666. package/src/shared/kb-layout.test.ts +37 -27
  667. package/src/shared/kb-layout.ts +4 -3
  668. package/src/shared/pending-proposals.ts +7 -4
  669. package/src/shared/redact-secret.ts +5 -5
  670. package/src/tenancy/__tests__/static-tenant-source.test.ts +177 -0
  671. package/src/tenancy/__tests__/tenant-host.test.ts +372 -0
  672. package/src/tenancy/__tests__/tenant-runtime.test.ts +221 -0
  673. package/src/tenancy/__tests__/tenant-secrets.test.ts +35 -0
  674. package/src/tenancy/index.ts +35 -0
  675. package/src/tenancy/static-tenant-source.ts +296 -0
  676. package/src/tenancy/tenant-host.ts +261 -0
  677. package/src/tenancy/tenant-runtime.ts +208 -0
  678. package/src/tenancy/tenant-secrets.ts +41 -0
  679. package/src/tenancy/tenant-source.contract.ts +59 -0
  680. package/dist/modules/access/access-errors.d.ts +0 -34
  681. package/dist/modules/access/access-errors.d.ts.map +0 -1
  682. package/dist/modules/access/access-errors.js +0 -40
  683. package/dist/modules/access/access-errors.js.map +0 -1
  684. package/dist/modules/access/access-splice.d.ts +0 -140
  685. package/dist/modules/access/access-splice.d.ts.map +0 -1
  686. package/dist/modules/access/access-splice.js +0 -389
  687. package/dist/modules/access/access-splice.js.map +0 -1
  688. package/dist/modules/access/group-files.d.ts +0 -83
  689. package/dist/modules/access/group-files.d.ts.map +0 -1
  690. package/dist/modules/access/group-files.js +0 -167
  691. package/dist/modules/access/group-files.js.map +0 -1
  692. package/dist/modules/access/kb-read-filter.d.ts +0 -41
  693. package/dist/modules/access/kb-read-filter.d.ts.map +0 -1
  694. package/dist/modules/access/kb-read-filter.js +0 -60
  695. package/dist/modules/access/kb-read-filter.js.map +0 -1
  696. package/dist/modules/access/render-roles-yaml.d.ts +0 -22
  697. package/dist/modules/access/render-roles-yaml.d.ts.map +0 -1
  698. package/dist/modules/access/render-roles-yaml.js +0 -56
  699. package/dist/modules/access/render-roles-yaml.js.map +0 -1
  700. package/dist/modules/access/roles-yaml-guard.d.ts +0 -56
  701. package/dist/modules/access/roles-yaml-guard.d.ts.map +0 -1
  702. package/dist/modules/access/roles-yaml-guard.js +0 -79
  703. package/dist/modules/access/roles-yaml-guard.js.map +0 -1
  704. package/dist/modules/diff/diff-paths.d.ts +0 -2
  705. package/dist/modules/diff/diff-paths.d.ts.map +0 -1
  706. package/dist/modules/diff/diff-paths.js +0 -9
  707. package/dist/modules/diff/diff-paths.js.map +0 -1
  708. package/dist/modules/groups/group-provision.service.d.ts +0 -130
  709. package/dist/modules/groups/group-provision.service.d.ts.map +0 -1
  710. package/dist/modules/groups/group-provision.service.js +0 -288
  711. package/dist/modules/groups/group-provision.service.js.map +0 -1
  712. package/dist/modules/groups/groups.contract.d.ts +0 -106
  713. package/dist/modules/groups/groups.contract.d.ts.map +0 -1
  714. package/dist/modules/groups/groups.contract.js +0 -36
  715. package/dist/modules/groups/groups.contract.js.map +0 -1
  716. package/dist/modules/groups/groups.routes.d.ts +0 -42
  717. package/dist/modules/groups/groups.routes.d.ts.map +0 -1
  718. package/dist/modules/groups/groups.routes.js +0 -379
  719. package/dist/modules/groups/groups.routes.js.map +0 -1
  720. package/dist/modules/groups/groups.service.d.ts +0 -60
  721. package/dist/modules/groups/groups.service.d.ts.map +0 -1
  722. package/dist/modules/groups/groups.service.js +0 -172
  723. package/dist/modules/groups/groups.service.js.map +0 -1
  724. package/dist/modules/groups/index.d.ts +0 -7
  725. package/dist/modules/groups/index.d.ts.map +0 -1
  726. package/dist/modules/groups/index.js +0 -6
  727. package/dist/modules/groups/index.js.map +0 -1
  728. package/dist/modules/groups/join-proposals.d.ts +0 -53
  729. package/dist/modules/groups/join-proposals.d.ts.map +0 -1
  730. package/dist/modules/groups/join-proposals.js +0 -67
  731. package/dist/modules/groups/join-proposals.js.map +0 -1
  732. package/dist/modules/groups/join-requests.service.d.ts +0 -81
  733. package/dist/modules/groups/join-requests.service.d.ts.map +0 -1
  734. package/dist/modules/groups/join-requests.service.js +0 -135
  735. package/dist/modules/groups/join-requests.service.js.map +0 -1
  736. package/dist/modules/mcp/mcp-session-store.d.ts +0 -74
  737. package/dist/modules/mcp/mcp-session-store.d.ts.map +0 -1
  738. package/dist/modules/mcp/mcp-session-store.js +0 -131
  739. package/dist/modules/mcp/mcp-session-store.js.map +0 -1
  740. package/dist/modules/workflow/file-change-notifier.d.ts +0 -38
  741. package/dist/modules/workflow/file-change-notifier.d.ts.map +0 -1
  742. package/dist/modules/workflow/file-change-notifier.js +0 -22
  743. package/dist/modules/workflow/file-change-notifier.js.map +0 -1
  744. package/dist/modules/workflow/git/branch-name.d.ts +0 -10
  745. package/dist/modules/workflow/git/branch-name.d.ts.map +0 -1
  746. package/dist/modules/workflow/git/branch-name.js +0 -76
  747. package/dist/modules/workflow/git/branch-name.js.map +0 -1
  748. package/dist/modules/workflow/git/clone-config.d.ts +0 -61
  749. package/dist/modules/workflow/git/clone-config.d.ts.map +0 -1
  750. package/dist/modules/workflow/git/clone-config.js +0 -69
  751. package/dist/modules/workflow/git/clone-config.js.map +0 -1
  752. package/dist/modules/workflow/git/mutex.d.ts +0 -11
  753. package/dist/modules/workflow/git/mutex.d.ts.map +0 -1
  754. package/dist/modules/workflow/git/mutex.js +0 -23
  755. package/dist/modules/workflow/git/mutex.js.map +0 -1
  756. package/dist/modules/workflow/locking-filesystem.d.ts +0 -137
  757. package/dist/modules/workflow/locking-filesystem.d.ts.map +0 -1
  758. package/dist/modules/workflow/locking-filesystem.js +0 -553
  759. package/dist/modules/workflow/locking-filesystem.js.map +0 -1
  760. package/dist/modules/workflow/read-only-filesystem.d.ts +0 -24
  761. package/dist/modules/workflow/read-only-filesystem.d.ts.map +0 -1
  762. package/dist/modules/workflow/read-only-filesystem.js +0 -39
  763. package/dist/modules/workflow/read-only-filesystem.js.map +0 -1
  764. package/dist/modules/workflow/workflow.errors.d.ts +0 -197
  765. package/dist/modules/workflow/workflow.errors.d.ts.map +0 -1
  766. package/dist/modules/workflow/workflow.errors.js +0 -298
  767. package/dist/modules/workflow/workflow.errors.js.map +0 -1
  768. package/dist/modules/workspace/bevel-ignore.d.ts +0 -30
  769. package/dist/modules/workspace/bevel-ignore.d.ts.map +0 -1
  770. package/dist/modules/workspace/bevel-ignore.js +0 -61
  771. package/dist/modules/workspace/bevel-ignore.js.map +0 -1
  772. package/dist/modules/workspace/kb-seed.interface.d.ts +0 -36
  773. package/dist/modules/workspace/kb-seed.interface.d.ts.map +0 -1
  774. package/dist/modules/workspace/kb-seed.interface.js +0 -2
  775. package/dist/modules/workspace/kb-seed.interface.js.map +0 -1
  776. package/dist/modules/workspace/kb-seed.service.d.ts +0 -125
  777. package/dist/modules/workspace/kb-seed.service.d.ts.map +0 -1
  778. package/dist/modules/workspace/kb-seed.service.js +0 -535
  779. package/dist/modules/workspace/kb-seed.service.js.map +0 -1
  780. package/dist/modules/workspace/plugins-migration.d.ts +0 -50
  781. package/dist/modules/workspace/plugins-migration.d.ts.map +0 -1
  782. package/dist/modules/workspace/plugins-migration.js +0 -379
  783. package/dist/modules/workspace/plugins-migration.js.map +0 -1
  784. package/dist/shared/fs-errors.d.ts +0 -8
  785. package/dist/shared/fs-errors.d.ts.map +0 -1
  786. package/dist/shared/fs-errors.js +0 -11
  787. package/dist/shared/fs-errors.js.map +0 -1
  788. package/dist/shared/fs-walk.d.ts +0 -23
  789. package/dist/shared/fs-walk.d.ts.map +0 -1
  790. package/dist/shared/fs-walk.js +0 -42
  791. package/dist/shared/fs-walk.js.map +0 -1
  792. package/dist/shared/hash-email.d.ts +0 -11
  793. package/dist/shared/hash-email.d.ts.map +0 -1
  794. package/dist/shared/hash-email.js +0 -14
  795. package/dist/shared/hash-email.js.map +0 -1
  796. package/dist/shared/kb-walk.d.ts +0 -52
  797. package/dist/shared/kb-walk.d.ts.map +0 -1
  798. package/dist/shared/kb-walk.js +0 -76
  799. package/dist/shared/kb-walk.js.map +0 -1
@@ -1,10 +1,15 @@
1
1
  import jwt from 'jsonwebtoken';
2
2
  import { eq } from 'drizzle-orm';
3
3
  import type { Database } from '../database/connection.js';
4
- import type { CoreConfig } from '../../core-config.js';
5
4
  import { users } from '../database/schema.js';
6
5
  import type { AuthUser } from '@bevel-software/platform-shared';
7
6
  import { canonicalEmail, hashEmail } from '../../shared/email-identity.js';
7
+ import {
8
+ AccountAdmissionRefusedError,
9
+ admitEveryone,
10
+ type AccountProvisionReason,
11
+ type IAccountAdmission,
12
+ } from './account-admission.js';
8
13
  import {
9
14
  hashPassword,
10
15
  verifyPassword,
@@ -84,8 +89,31 @@ export class AuthService {
84
89
  constructor(
85
90
  private readonly db: Database,
86
91
  private readonly config: AuthConfig,
92
+ /**
93
+ * Whether a new account may be provisioned — see `account-admission.ts`.
94
+ * Core admits everyone; a host that sells seats answers from its plan.
95
+ */
96
+ private readonly admission: IAccountAdmission = admitEveryone,
87
97
  ) {}
88
98
 
99
+ /**
100
+ * Ask the admission port before an account is CREATED: an address that
101
+ * already has a row is never asked about, so a refusal cannot lock an
102
+ * existing user out. The default port is not asked at all, which also
103
+ * spares the lookup.
104
+ */
105
+ private async assertAdmitted(normalizedEmail: string, reason: AccountProvisionReason): Promise<void> {
106
+ if (this.admission === admitEveryone) return;
107
+ const [existing] = await this.db
108
+ .select({ id: users.id })
109
+ .from(users)
110
+ .where(eq(users.email, normalizedEmail))
111
+ .limit(1);
112
+ if (existing) return;
113
+ const verdict = await this.admission.canProvision(normalizedEmail, reason);
114
+ if (!verdict.ok) throw new AccountAdmissionRefusedError(verdict.message);
115
+ }
116
+
89
117
  /**
90
118
  * Password login. Two credential sources, in order:
91
119
  *
@@ -155,6 +183,7 @@ export class AuthService {
155
183
  throw new Error('Invalid credentials');
156
184
  }
157
185
  const defaultName = normalizedEmail.split('@')[0] || normalizedEmail;
186
+ await this.assertAdmitted(normalizedEmail, 'bootstrap');
158
187
  const admin = await this.upsertUserByEmail(normalizedEmail, defaultName);
159
188
  return { token: this.signToken(admin.id, admin.email), user: this.toClientUser(admin) };
160
189
  }
@@ -187,6 +216,7 @@ export class AuthService {
187
216
  throw new Error('Sign-in returned an invalid email');
188
217
  }
189
218
  this.assertAllowedDomain(normalizedEmail);
219
+ await this.assertAdmitted(normalizedEmail, 'sso');
190
220
  const displayName = (name ?? '').trim() || normalizedEmail.split('@')[0] || normalizedEmail;
191
221
  const user = await this.upsertUserByEmail(normalizedEmail, displayName);
192
222
  return { token: this.signToken(user.id, user.email), user: this.toClientUser(user) };
@@ -221,6 +251,7 @@ export class AuthService {
221
251
  throw new Error(ENV_ADMIN_PASSWORD_REFUSAL);
222
252
  }
223
253
  this.assertPasswordPolicy(password);
254
+ await this.assertAdmitted(normalizedEmail, 'admin-create');
224
255
  const suppliedName = (name ?? '').trim();
225
256
  const displayName = suppliedName || normalizedEmail.split('@')[0] || normalizedEmail;
226
257
  const passwordHash = await hashPassword(password);
@@ -382,6 +413,7 @@ export class AuthService {
382
413
  ): Promise<{ id: string; email: string; name: string } | null> {
383
414
  const normalizedEmail = canonicalEmail(email ?? '');
384
415
  if (!EMAIL_REGEX.test(normalizedEmail)) return null;
416
+ await this.assertAdmitted(normalizedEmail, 'embed');
385
417
  const displayName = (name ?? '').trim() || normalizedEmail.split('@')[0] || normalizedEmail;
386
418
  const user = await this.upsertUserByEmail(normalizedEmail, displayName);
387
419
  return { id: user.id, email: user.email, name: user.name };
@@ -7,6 +7,7 @@ import type { AuthProviderPlugin } from './auth.routes.js';
7
7
  import { AUTH_COOKIE_MAX_AGE_S } from './auth.routes.js';
8
8
  import { AUTH_COOKIE_NAME } from './auth.middleware.js';
9
9
  import type { AuthService } from './auth.service.js';
10
+ import { AccountAdmissionRefusedError } from './account-admission.js';
10
11
  import { normalizeIssuerUrl } from '../settings/oidc-check.js';
11
12
 
12
13
  // Short-lived CSRF state + PKCE verifier for the OAuth round-trip: set before
@@ -319,6 +320,14 @@ export class OidcAuthProvider implements AuthProviderPlugin {
319
320
  });
320
321
  res.redirect(`${publicFrontendUrl}/auth/oidc/callback#token=${encodeURIComponent(token)}`);
321
322
  } catch (error) {
323
+ // A refused provisioning is not a failed sign-in: the identity was
324
+ // verified, the deployment has no seat for it. Named so the login
325
+ // screen can say so instead of "try again".
326
+ if (error instanceof AccountAdmissionRefusedError) {
327
+ log.warn('OIDC sign-in refused by the account admission port:', { detail: error.message });
328
+ fail('admission');
329
+ return;
330
+ }
322
331
  log.error('OIDC callback error:', { err: error });
323
332
  fail('auth');
324
333
  }
@@ -399,6 +399,12 @@ export class ConnectionProbeService implements IConnectionProbeService {
399
399
  constructor(
400
400
  private readonly toolManualService: IToolManualService,
401
401
  private readonly secretsVault: ISecretsVaultService,
402
+ /**
403
+ * The scope this knowledge base's vault was registered under with the
404
+ * UTCP variable loader, so a probe's client resolves the caller's secrets
405
+ * from it — see `secrets-variable-loader.ts`. Default: the single one.
406
+ */
407
+ private readonly secretsScope?: string,
402
408
  ) {}
403
409
 
404
410
  async probe(userId: string, userEmail: string, slug: string): Promise<ProbeVerdict | null> {
@@ -556,7 +562,7 @@ export class ConnectionProbeService implements IConnectionProbeService {
556
562
  // loader, which is exactly the credential under test.
557
563
  const config = new UtcpClientConfigSerializer().validateDict({
558
564
  variables: {},
559
- load_variables_from: [bevelSecretsLoaderConfig(userId)],
565
+ load_variables_from: [bevelSecretsLoaderConfig(userId, this.secretsScope)],
560
566
  });
561
567
  // No late-settle owner: a client that arrives after the deadline has no
562
568
  // manual registered and therefore no session, and neither
@@ -1,5 +1,5 @@
1
1
  import { describe, it, expect } from 'vitest';
2
- import { AdvisoryLock, withAdvisoryLock } from '../advisory-lock.js';
2
+ import { AdvisoryLock, advisoryLockKey, withAdvisoryLock } from '../advisory-lock.js';
3
3
  import type { Database } from '../connection.js';
4
4
 
5
5
  /**
@@ -145,3 +145,25 @@ describe('withAdvisoryLock', () => {
145
145
  expect(clients[0].releasedWith).toBeInstanceOf(Error);
146
146
  });
147
147
  });
148
+
149
+ describe('advisoryLockKey', () => {
150
+ it('keeps the ids a single-tenant deployment always used when no tenant is named', () => {
151
+ expect(advisoryLockKey(AdvisoryLock.Migrations)).toBe(AdvisoryLock.Migrations);
152
+ expect(advisoryLockKey(AdvisoryLock.CommitWorker, '')).toBe(AdvisoryLock.CommitWorker);
153
+ });
154
+
155
+ it('gives each tenant its own key for each lock, stable across calls and inside int4', () => {
156
+ const a = advisoryLockKey(AdvisoryLock.CommitWorker, 't_acme');
157
+ const b = advisoryLockKey(AdvisoryLock.CommitWorker, 't_globex');
158
+ expect(a).toBe(advisoryLockKey(AdvisoryLock.CommitWorker, 't_acme'));
159
+ expect(a).not.toBe(b);
160
+ expect(a).not.toBe(AdvisoryLock.CommitWorker);
161
+ // The two locks of one tenant stay two locks.
162
+ expect(advisoryLockKey(AdvisoryLock.Migrations, 't_acme')).not.toBe(a);
163
+ for (const key of [a, b]) {
164
+ expect(Number.isInteger(key)).toBe(true);
165
+ expect(key).toBeGreaterThanOrEqual(-(2 ** 31));
166
+ expect(key).toBeLessThanOrEqual(2 ** 31 - 1);
167
+ }
168
+ });
169
+ });
@@ -0,0 +1,98 @@
1
+ import { describe, it, expect, afterEach } from 'vitest';
2
+ import {
3
+ DEFAULT_DB_SCHEMA,
4
+ assertSchemaName,
5
+ assertSearchPath,
6
+ closeDb,
7
+ createDb,
8
+ dbSchemaOf,
9
+ getDb,
10
+ type Database,
11
+ } from '../connection.js';
12
+
13
+ /**
14
+ * Pools here are never connected: `pg.Pool` opens nothing until a query is
15
+ * asked of it, so what a handle was built with — the schema its connections
16
+ * will search, whether two asks share one pool — is observable without a
17
+ * database, and that is what these cases pin.
18
+ */
19
+ const URL = 'postgresql://u:p@127.0.0.1:1/never';
20
+
21
+ const searchPath = (db: Database): string | undefined =>
22
+ (db.$client.options as { options?: string }).options;
23
+
24
+ const opened: Database[] = [];
25
+ afterEach(async () => {
26
+ await Promise.all(opened.splice(0).map((db) => closeDb(db)));
27
+ });
28
+
29
+ describe('schema per knowledge base', () => {
30
+ it('searches the schema it was built for, and leaves the default schema to the server', () => {
31
+ const acme = createDb(URL, { schema: 'acme' });
32
+ const plain = createDb(URL);
33
+ opened.push(acme, plain);
34
+ expect(searchPath(acme)).toBe('-c search_path=acme');
35
+ expect(dbSchemaOf(acme)).toBe('acme');
36
+ // Nothing set: an operator's own `search_path` stays in force.
37
+ expect(searchPath(plain)).toBeUndefined();
38
+ expect(dbSchemaOf(plain)).toBe(DEFAULT_DB_SCHEMA);
39
+ });
40
+
41
+ it('refuses a schema name that is not a plain lowercase identifier', () => {
42
+ for (const bad of ['Acme', 'a-b', 'a b', '1abc', 'public; drop schema x', '', 'a'.repeat(64)]) {
43
+ expect(() => assertSchemaName(bad), bad).toThrow(/schema name/);
44
+ expect(() => createDb(URL, { schema: bad }), bad).toThrow(/schema name/);
45
+ }
46
+ expect(assertSchemaName('t_acme_2')).toBe('t_acme_2');
47
+ });
48
+
49
+ it('refuses the names Postgres and drizzle already own', () => {
50
+ for (const reserved of ['pg_catalog', 'pg_toast', 'pg_x', 'information_schema', 'drizzle']) {
51
+ expect(() => assertSchemaName(reserved), reserved).toThrow(/reserved/);
52
+ }
53
+ // The default schema is a valid name here: a single-tenant deployment
54
+ // lives on it. A tenant source refuses it for a tenant, not this guard.
55
+ expect(assertSchemaName(DEFAULT_DB_SCHEMA)).toBe(DEFAULT_DB_SCHEMA);
56
+ });
57
+ });
58
+
59
+ describe('assertSearchPath', () => {
60
+ const answering = (schema: string | null) => ({
61
+ execute: async () => ({ rows: [{ schema }] }) as never,
62
+ });
63
+
64
+ it('passes when the server searches the configured schema first', async () => {
65
+ await expect(assertSearchPath(answering('t_acme'), 't_acme')).resolves.toBeUndefined();
66
+ });
67
+
68
+ it('refuses a connection whose schema a pooler dropped, naming both schemas and the cause', async () => {
69
+ // What a transaction-mode pooler leaves behind: the startup parameter
70
+ // never reached the server, so `public` is searched first.
71
+ await expect(assertSearchPath(answering('public'), 't_acme')).rejects.toThrow(
72
+ /search "public" first, not the configured schema "t_acme".*transaction-mode pooler/,
73
+ );
74
+ await expect(assertSearchPath(answering(null), 't_acme')).rejects.toThrow(/\(none\)/);
75
+ });
76
+ });
77
+
78
+ describe('getDb', () => {
79
+ it('shares one pool per (url, schema) and keeps different schemas apart', () => {
80
+ const a1 = getDb(URL, { schema: 'acme' });
81
+ const a2 = getDb(URL, { schema: 'acme' });
82
+ const b = getDb(URL, { schema: 'globex' });
83
+ const plain = getDb(URL);
84
+ opened.push(a1, b, plain);
85
+ expect(a2).toBe(a1);
86
+ expect(b).not.toBe(a1);
87
+ expect(plain).not.toBe(a1);
88
+ expect(getDb(URL, { schema: DEFAULT_DB_SCHEMA })).toBe(plain);
89
+ });
90
+
91
+ it('opens a fresh pool after the cached one was closed', async () => {
92
+ const first = getDb(URL, { schema: 'closing' });
93
+ await closeDb(first);
94
+ const second = getDb(URL, { schema: 'closing' });
95
+ opened.push(second);
96
+ expect(second).not.toBe(first);
97
+ });
98
+ });
@@ -0,0 +1,32 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import fs from 'node:fs/promises';
3
+ import path from 'node:path';
4
+ import { coreMigrationsDir } from '../../../assets.js';
5
+
6
+ /**
7
+ * A knowledge base hosted beside others lives in a schema of its own, found
8
+ * through `search_path`. A migration that spells `public.` runs against the
9
+ * wrong schema there — creating the table in `public`, or guarding on a
10
+ * constraint that lives elsewhere — and the tenant that runs it is the first
11
+ * to find out. So no migration may name a schema: this reads every file the
12
+ * runner would, so the rule cannot be forgotten by the next one.
13
+ */
14
+ describe('core migrations', () => {
15
+ it('never qualify a table with a schema', async () => {
16
+ const dir = coreMigrationsDir();
17
+ const files = (await fs.readdir(dir)).filter((name) => name.endsWith('.sql')).sort();
18
+ expect(files.length).toBeGreaterThan(0);
19
+ const offenders: string[] = [];
20
+ for (const name of files) {
21
+ const text = await fs.readFile(path.join(dir, name), 'utf8');
22
+ text.split('\n').forEach((line, i) => {
23
+ // Bare (`public.users`) and quoted (`"public"."users"`) alike: the
24
+ // quoted spelling is what drizzle generates, and it is what a live
25
+ // two-tenant run found still pointing every tenant's foreign keys at
26
+ // a `public.users` that does not exist there.
27
+ if (/\bpublic"?\./.test(line)) offenders.push(`${name}:${i + 1}: ${line.trim()}`);
28
+ });
29
+ }
30
+ expect(offenders).toEqual([]);
31
+ });
32
+ });
@@ -1,3 +1,4 @@
1
+ import { crc32 } from 'node:zlib';
1
2
  import pg from 'pg';
2
3
  import type { Database } from './connection.js';
3
4
 
@@ -84,6 +85,23 @@ export const AdvisoryLock = {
84
85
 
85
86
  export type AdvisoryLockId = (typeof AdvisoryLock)[keyof typeof AdvisoryLock];
86
87
 
88
+ /**
89
+ * The second integer of a lock: the lock id, folded with the knowledge base
90
+ * it belongs to. A process serving several knowledge bases from one database
91
+ * runs several commit workers and several migration runs, and each must
92
+ * exclude only its own kind: the migrations lock of tenant A has nothing to
93
+ * say to tenant B's. An empty `tenantKey` is the single-tenant deployment
94
+ * and keeps the ids that were always used, so a redeploy's outgoing process
95
+ * on the older build still contends for the same lock.
96
+ *
97
+ * `crc32` for a stable 32-bit spread of the key; XOR keeps every value
98
+ * inside `int4`. Two tenants whose keys collide serialise against each other
99
+ * and nothing worse: an over-locking, never an under-locking.
100
+ */
101
+ export function advisoryLockKey(lock: AdvisoryLockId, tenantKey = ''): number {
102
+ return tenantKey ? lock ^ crc32(tenantKey) : lock;
103
+ }
104
+
87
105
  /** How long to wait for the lock before giving up and failing the boot. */
88
106
  const DEFAULT_WAIT_MS = 60_000;
89
107
 
@@ -138,9 +156,10 @@ export async function withAdvisoryLock<T>(
138
156
  db: Database,
139
157
  lock: AdvisoryLockId,
140
158
  fn: () => Promise<T>,
141
- opts: { waitMs?: number } = {},
159
+ opts: { waitMs?: number; tenantKey?: string } = {},
142
160
  ): Promise<T> {
143
161
  const waitMs = opts.waitMs ?? DEFAULT_WAIT_MS;
162
+ const key = advisoryLockKey(lock, opts.tenantKey);
144
163
  const client = await db.$client.connect();
145
164
  // A statement that did not answer in time is STILL RUNNING on this
146
165
  // connection — `bounded` gives up waiting, it cannot take the statement
@@ -170,7 +189,7 @@ export async function withAdvisoryLock<T>(
170
189
  // parameter. `true` makes the setting transaction-local, so the
171
190
  // `rollback` below reverts it.
172
191
  await onWire(client.query("select set_config('lock_timeout', $1, true)", [String(waitMs)]), 'setting lock_timeout');
173
- await client.query('select pg_advisory_xact_lock($1, $2)', [LOCK_NAMESPACE, lock]);
192
+ await client.query('select pg_advisory_xact_lock($1, $2)', [LOCK_NAMESPACE, key]);
174
193
  } catch (err) {
175
194
  if (isLockTimeout(err)) {
176
195
  throw new Error(
@@ -215,6 +234,8 @@ export interface LeaseClient {
215
234
  }
216
235
 
217
236
  export interface AdvisoryLeaseOptions {
237
+ /** The knowledge base this lease belongs to — see {@link advisoryLockKey}. Empty: the single-tenant ids. */
238
+ tenantKey?: string;
218
239
  /** How the lease opens its connection. Default: a `pg.Client` on the pool's connection string. */
219
240
  connect?: () => Promise<LeaseClient>;
220
241
  /** Bound on the connect and on each query, so an unreachable or half-dead database fails rather than waits. Default 10s. */
@@ -290,7 +311,7 @@ export class AdvisoryLease {
290
311
  try {
291
312
  const { rows } = await client.query('select pg_try_advisory_lock($1, $2) as held', [
292
313
  LOCK_NAMESPACE,
293
- this.lock,
314
+ advisoryLockKey(this.lock, this.opts.tenantKey),
294
315
  ]);
295
316
  if (rows[0]?.held !== true) {
296
317
  await client.end().catch(() => undefined);
@@ -315,7 +336,10 @@ export class AdvisoryLease {
315
336
  this.heldFlag = false;
316
337
  if (!client) return;
317
338
  try {
318
- await client.query('select pg_advisory_unlock($1, $2)', [LOCK_NAMESPACE, this.lock]);
339
+ await client.query('select pg_advisory_unlock($1, $2)', [
340
+ LOCK_NAMESPACE,
341
+ advisoryLockKey(this.lock, this.opts.tenantKey),
342
+ ]);
319
343
  } catch {
320
344
  // Ending the session below releases the lock regardless.
321
345
  } finally {
@@ -1,23 +1,153 @@
1
+ import { sql } from 'drizzle-orm';
1
2
  import { drizzle } from 'drizzle-orm/node-postgres';
2
3
  import pg from 'pg';
3
4
  import * as schema from './schema.js';
4
5
 
5
- let db: ReturnType<typeof drizzle<typeof schema>> | null = null;
6
+ /**
7
+ * One database, one schema per knowledge base.
8
+ *
9
+ * A single-tenant deployment keeps `public`, exactly as before this option
10
+ * existed: no `search_path` is set for it, so an operator's own default
11
+ * (`"$user", public`) is honoured, and the migration ledger stays where
12
+ * drizzle put it. A knowledge base hosted beside others gets a schema of its
13
+ * own: every connection of its pool starts with `search_path` pointing at it,
14
+ * so the unqualified table names the schema module and the migrations use
15
+ * resolve there and nowhere else. Isolation is then a Postgres object, and a
16
+ * tenant leaves as `pg_dump -n <schema>`.
17
+ */
18
+ export const DEFAULT_DB_SCHEMA = 'public';
6
19
 
7
- export function getDb(databaseUrl: string) {
20
+ /**
21
+ * A schema name this module will put into `search_path`: a plain lowercase
22
+ * identifier, at most Postgres's 63 characters. Validated rather than quoted,
23
+ * because the name also travels into `CREATE SCHEMA` and a `pg_dump`
24
+ * invocation, and a name that needs quoting in one of them is a name that
25
+ * will be spelled wrong in another.
26
+ */
27
+ export function assertSchemaName(name: string): string {
28
+ if (!/^[a-z][a-z0-9_]{0,62}$/.test(name)) {
29
+ throw new Error(
30
+ `Database schema name must be a lowercase identifier ([a-z][a-z0-9_]*, at most 63 characters); got "${name}"`,
31
+ );
32
+ }
33
+ // Names Postgres or drizzle already own. `pg_*` would fail at CREATE
34
+ // SCHEMA anyway; `information_schema` would not, and `drizzle` is where a
35
+ // deployment on the default schema keeps its migration ledger, so a
36
+ // knowledge base placed there would share that ledger's home.
37
+ if (name.startsWith('pg_') || name === 'information_schema' || name === 'drizzle') {
38
+ throw new Error(`Database schema name "${name}" is reserved`);
39
+ }
40
+ return name;
41
+ }
42
+
43
+ /**
44
+ * Prove that this handle's connections really search `schema` first, by
45
+ * asking the server. The schema is set as a startup parameter, and a
46
+ * transaction- or statement-mode pooler in front of the database (PgBouncer
47
+ * in those modes, RDS Proxy) either refuses that parameter or resets it
48
+ * between transactions; every unqualified table name would then resolve to
49
+ * `public`, and tenants would read each other's rows without a single
50
+ * error. So a graph refuses to come up on a handle that lost its schema,
51
+ * which is the failure an operator can see. Only session pooling is
52
+ * supported in front of a process that serves several knowledge bases.
53
+ */
54
+ export async function assertSearchPath(db: Pick<Database, 'execute'>, schema: string): Promise<void> {
55
+ const result = await db.execute(sql`select current_schema() as schema`);
56
+ const current = (result.rows[0] as { schema?: string } | undefined)?.schema ?? null;
57
+ if (current !== schema) {
58
+ throw new Error(
59
+ `Database connections search "${current ?? '(none)'}" first, not the configured schema "${schema}". ` +
60
+ 'A transaction-mode pooler in front of Postgres drops the search_path startup parameter; ' +
61
+ 'use session pooling, or connect directly.',
62
+ );
63
+ }
64
+ }
65
+
66
+ export interface DbOptions {
67
+ /** The schema the pool's connections search first. Default {@link DEFAULT_DB_SCHEMA}. */
68
+ schema?: string;
69
+ /**
70
+ * Connections the pool may hold. `pg`'s default (10) suits a process that
71
+ * serves one knowledge base; a process serving many keeps each pool small,
72
+ * since the database's `max_connections` is shared by all of them.
73
+ */
74
+ max?: number;
75
+ /** How long an idle connection is kept before the pool closes it. Default: `pg`'s. */
76
+ idleTimeoutMillis?: number;
77
+ }
78
+
79
+ /**
80
+ * A bounded handshake: `pg` waits forever by default for a NEW connection to
81
+ * come up, so a database that accepts the socket and never finishes the
82
+ * handshake would hold a boot (the migration lock is the first thing that
83
+ * asks) with nothing to say and nothing for the restart policy to see. Half
84
+ * a minute is generous for a handshake and short enough for a failed boot to
85
+ * be visible. It bounds only that: a checkout queued behind a saturated pool,
86
+ * or a query on a connection that stopped answering, is the caller's to
87
+ * bound — the advisory lock does.
88
+ */
89
+ const CONNECT_TIMEOUT_MS = 30_000;
90
+
91
+ /**
92
+ * A NEW pool on `databaseUrl`, searching `opts.schema` first. Not cached:
93
+ * the caller owns it and ends it with {@link closeDb}. The composition root
94
+ * of a process that serves one knowledge base goes through {@link getDb}
95
+ * instead, which caches.
96
+ */
97
+ export function createDb(databaseUrl: string, opts: DbOptions = {}) {
98
+ const dbSchema = assertSchemaName(opts.schema ?? DEFAULT_DB_SCHEMA);
99
+ const pool = new pg.Pool({
100
+ connectionString: databaseUrl,
101
+ connectionTimeoutMillis: CONNECT_TIMEOUT_MS,
102
+ max: opts.max,
103
+ idleTimeoutMillis: opts.idleTimeoutMillis,
104
+ // A startup parameter, applied by the server to every connection this
105
+ // pool opens — not a `SET` run after connecting, which a pooled
106
+ // connection could outlive. The default schema sets nothing, so an
107
+ // operator's own `search_path` stays in force there.
108
+ ...(dbSchema === DEFAULT_DB_SCHEMA ? {} : { options: `-c search_path=${dbSchema}` }),
109
+ });
110
+ const db = drizzle(pool, { schema });
111
+ schemas.set(db, dbSchema);
112
+ return db;
113
+ }
114
+
115
+ export type Database = ReturnType<typeof createDb>;
116
+
117
+ /** The schema a database handle searches first — for the callers that name it in DDL. */
118
+ export function dbSchemaOf(db: Pick<Database, '$client'>): string {
119
+ return schemas.get(db as Database) ?? DEFAULT_DB_SCHEMA;
120
+ }
121
+
122
+ const schemas = new WeakMap<Database, string>();
123
+ const cache = new Map<string, Database>();
124
+
125
+ const cacheKey = (databaseUrl: string, dbSchema: string) => `${dbSchema}\u0000${databaseUrl}`;
126
+
127
+ /**
128
+ * The process's pool on `databaseUrl` for `opts.schema`, created on first
129
+ * use and shared afterwards. One per (url, schema): two handles on the same
130
+ * schema would be two pools competing for the same connection budget.
131
+ */
132
+ export function getDb(databaseUrl: string, opts: DbOptions = {}): Database {
133
+ const dbSchema = assertSchemaName(opts.schema ?? DEFAULT_DB_SCHEMA);
134
+ const key = cacheKey(databaseUrl, dbSchema);
135
+ let db = cache.get(key);
8
136
  if (!db) {
9
- // A bounded handshake: `pg` waits forever by default for a NEW connection
10
- // to come up, so a database that accepts the socket and never finishes
11
- // the handshake would hold a boot (the migration lock is the first thing
12
- // that asks) with nothing to say and nothing for the restart policy to
13
- // see. Half a minute is generous for a handshake and short enough for a
14
- // failed boot to be visible. It bounds only that: a checkout queued
15
- // behind a saturated pool, or a query on a connection that stopped
16
- // answering, is the caller's to bound — the advisory lock does.
17
- const pool = new pg.Pool({ connectionString: databaseUrl, connectionTimeoutMillis: 30_000 });
18
- db = drizzle(pool, { schema });
137
+ db = createDb(databaseUrl, opts);
138
+ cache.set(key, db);
19
139
  }
20
140
  return db;
21
141
  }
22
142
 
23
- export type Database = ReturnType<typeof getDb>;
143
+ /**
144
+ * End a handle's pool and forget it, so a later {@link getDb} for the same
145
+ * schema opens a fresh one rather than handing out a pool that was ended.
146
+ * The last step of stopping a knowledge base's graph.
147
+ */
148
+ export async function closeDb(db: Pick<Database, '$client'>): Promise<void> {
149
+ for (const [key, cached] of cache) {
150
+ if (cached === db) cache.delete(key);
151
+ }
152
+ await db.$client.end();
153
+ }
@@ -211,6 +211,16 @@ export const externalApiKeys = pgTable('api_tokens', {
211
211
  * reconnect a key that was taken from them.
212
212
  */
213
213
  revokedBy: text('revoked_by'),
214
+ /**
215
+ * When the owner deleted the key "for good" from their own pages. A
216
+ * DELETE in name only: the row stays, because the Audit log's events hang
217
+ * off it and a log its subject can erase is not one. Hidden from the
218
+ * owner's listings, shown to admins as deleted; gone for real only when
219
+ * the account is erased (the cascade) or its events have long been
220
+ * pruned. Always set on an already-revoked row — a live key is never
221
+ * deleted in one step.
222
+ */
223
+ deletedAt: timestamp('deleted_at'),
214
224
  }, (t) => ({
215
225
  byUser: index('api_tokens_by_user').on(t.userId),
216
226
  }));
@@ -446,12 +456,58 @@ export const oauthAuthCodes = pgTable('oauth_auth_codes', {
446
456
  byExpiry: index('oauth_auth_codes_by_expiry').on(t.expiresAt),
447
457
  }));
448
458
 
459
+ /**
460
+ * "This person connected this agent" — the durable record behind the Audit
461
+ * log's agent rows. An OAuth grant cannot be that record: its token row is
462
+ * replaced on every refresh (hourly) and pruned once its refresh window
463
+ * closes, so nothing about it outlives a month. This row is made the first
464
+ * time a token is minted for a (user, client) pair, kept across every refresh
465
+ * (each new token row points at it), and REVOKED rather than deleted when the
466
+ * person or an admin cuts the agent off — its events stay readable under it.
467
+ *
468
+ * A connection is the AGENT, per person — not the OAuth client registration.
469
+ * Claude registers a fresh client on every re-authorisation (dynamic client
470
+ * registration mints a new id each time), so keying by registration gave one
471
+ * person five "Claude" rows for one agent. `agent_key` is what a connection is
472
+ * keyed by instead: the registered client name, folded (a name-less client
473
+ * falls back to its id), so every registration of "Claude" by one person
474
+ * lands on the same live row; `client_id` records the registration that
475
+ * first made it. `client_name` is that registration's name as shown.
476
+ *
477
+ * One LIVE connection per (user, agent): the partial unique index below. A
478
+ * reconnect after a revoke is a new row, so the old one's history and its
479
+ * "revoked by an admin" mark are never overwritten.
480
+ */
481
+ export const agentConnections = pgTable('agent_connections', {
482
+ id: uuid('id').defaultRandom().primaryKey(),
483
+ userId: uuid('user_id').notNull().references(() => users.id, { onDelete: 'cascade' }),
484
+ clientId: text('client_id').notNull().references(() => oauthClients.clientId),
485
+ clientName: text('client_name'),
486
+ /** The folded client name, or the client id when the registration carried none. */
487
+ agentKey: text('agent_key').notNull(),
488
+ connectedAt: timestamp('connected_at').defaultNow().notNull(),
489
+ lastUsedAt: timestamp('last_used_at'),
490
+ revokedAt: timestamp('revoked_at'),
491
+ /** `owner` | `admin` — who ended it; null while live. Same vocabulary as `api_tokens.revoked_by`. */
492
+ revokedBy: text('revoked_by'),
493
+ }, (t) => ({
494
+ byUser: index('agent_connections_by_user').on(t.userId),
495
+ liveUnq: uniqueIndex('agent_connections_live_unq')
496
+ .on(t.userId, t.agentKey)
497
+ .where(sql`${t.revokedAt} is null`),
498
+ }));
499
+
449
500
  /**
450
501
  * OAuth access/refresh token pairs minted by the token endpoint. Like
451
502
  * `api_tokens`: plaintext shown only in the token response, SHA-256 hashes
452
503
  * stored, revoked-not-deleted so `last_used_at` keeps its audit value and a
453
504
  * revoked token can't be re-issued. One row per pair; refresh rotation
454
505
  * revokes the old row and inserts a new one.
506
+ *
507
+ * `connection_id` names the {@link agentConnections} row the pair belongs to,
508
+ * so every call made with the token is attributed to that agent and revoking
509
+ * the agent can revoke exactly its tokens. Null only on rows minted before
510
+ * the column existed.
455
511
  */
456
512
  export const oauthTokens = pgTable('oauth_tokens', {
457
513
  id: uuid('id').defaultRandom().primaryKey(),
@@ -459,6 +515,7 @@ export const oauthTokens = pgTable('oauth_tokens', {
459
515
  refreshTokenHash: text('refresh_token_hash').unique(),
460
516
  clientId: text('client_id').notNull().references(() => oauthClients.clientId),
461
517
  userId: uuid('user_id').notNull().references(() => users.id),
518
+ connectionId: uuid('connection_id').references(() => agentConnections.id, { onDelete: 'cascade' }),
462
519
  scope: text('scope'),
463
520
  resource: text('resource'),
464
521
  expiresAt: timestamp('expires_at').notNull(),
@@ -469,6 +526,53 @@ export const oauthTokens = pgTable('oauth_tokens', {
469
526
  }, (t) => ({
470
527
  byUser: index('oauth_tokens_by_user').on(t.userId),
471
528
  byExpiry: index('oauth_tokens_by_expiry').on(t.expiresAt),
529
+ byConnection: index('oauth_tokens_by_connection').on(t.connectionId),
530
+ }));
531
+
532
+ /**
533
+ * The Audit log's events: one row per thing an external agent called through
534
+ * the platform — a hexis capability (the platform's own tools, `read_file`,
535
+ * `call_tool_chain`, …), a tool from a `.tool` manual or a connected MCP
536
+ * server, or a skill it read. Append-only; pruned past the deployment's
537
+ * retention window (the `auditRetentionDays` setting).
538
+ *
539
+ * Deliberately WITHOUT arguments or results: a call's inputs can carry
540
+ * secrets and personal data, and the log's question is "what was used, by
541
+ * which agent, when" — not "what was said".
542
+ *
543
+ * Exactly one principal per row (the CHECK): the connection key or the agent
544
+ * connection the call arrived through. Both cascade, so deleting a key for
545
+ * good, revoking-then-erasing a person, or dropping a connection takes its
546
+ * events along — the same contract the LLM-usage rows already keep.
547
+ */
548
+ export const agentEvents = pgTable('agent_events', {
549
+ id: uuid('id').defaultRandom().primaryKey(),
550
+ userId: uuid('user_id').notNull().references(() => users.id, { onDelete: 'cascade' }),
551
+ keyId: uuid('key_id').references(() => externalApiKeys.id, { onDelete: 'cascade' }),
552
+ connectionId: uuid('connection_id').references(() => agentConnections.id, { onDelete: 'cascade' }),
553
+ /** `capability` | `tool` | `skill`. */
554
+ kind: text('kind').notNull(),
555
+ /** The MCP server / `.tool` manual (catalog name) for a tool, the skill folder for a skill; null for a capability. */
556
+ manual: text('manual'),
557
+ /** The tool's bare name, or the skill's name. */
558
+ name: text('name').notNull(),
559
+ /** `ok` | `error` | `denied` (denied: the caller's sign-in for the tool was missing, so nothing ran). */
560
+ outcome: text('outcome').notNull(),
561
+ durationMs: integer('duration_ms'),
562
+ at: timestamp('at').defaultNow().notNull(),
563
+ }, (t) => ({
564
+ // The two read paths: one principal's events, newest first.
565
+ byKey: index('agent_events_by_key').on(t.keyId, t.at),
566
+ byConnection: index('agent_events_by_connection').on(t.connectionId, t.at),
567
+ // The retention prune, and per-user counts.
568
+ byAt: index('agent_events_by_at').on(t.at),
569
+ byUser: index('agent_events_by_user').on(t.userId),
570
+ kindCheck: check('agent_events_kind', sql`${t.kind} IN ('capability', 'tool', 'skill')`),
571
+ outcomeCheck: check('agent_events_outcome', sql`${t.outcome} IN ('ok', 'error', 'denied')`),
572
+ principalCheck: check(
573
+ 'agent_events_principal',
574
+ sql`(${t.keyId} IS NULL) <> (${t.connectionId} IS NULL)`,
575
+ ),
472
576
  }));
473
577
 
474
578
  export const sessionOntologyTouches = pgTable('session_ontology_touches', {