@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
@@ -9,6 +9,7 @@ import type { InternalTokenService } from '../tool-auth/internal-token.service.j
9
9
  import { rejectConnectionKey } from '../tool-auth/connection-key-rejection.js';
10
10
  import type { BevelOAuthProvider } from './oauth/bevel-oauth-provider.js';
11
11
  import '../tool-auth/external-api-key.interface.js'; // Express Request augmentation (req.externalApiKeyId)
12
+ import '../audit/audit.contract.js'; // Express Request augmentation (req.agentConnectionId)
12
13
 
13
14
  /**
14
15
  * Auth middleware for the MCP endpoint. Accepts any of:
@@ -111,6 +112,12 @@ export function createMcpAuthMiddleware(
111
112
  const info = await oauthProvider.verifyAccessToken(token);
112
113
  req.userId = String(info.extra?.userId ?? '');
113
114
  req.userEmail = String(info.extra?.userEmail ?? '');
115
+ // The agent behind the grant, for the Audit log. A token minted
116
+ // before connections existed carries none; the call then runs
117
+ // unattributed rather than refused.
118
+ if (typeof info.extra?.connectionId === 'string') {
119
+ req.agentConnectionId = info.extra.connectionId;
120
+ }
114
121
  if (!req.userId) {
115
122
  unauthorized(res, 'Invalid access token');
116
123
  return;
@@ -176,6 +183,30 @@ export function createMcpAuthMiddleware(
176
183
  }
177
184
  req.userId = user.id;
178
185
  req.userEmail = user.email;
186
+ // The local server's exchanged grant names its agent connection (see
187
+ // InternalTokenClaim.connectionId). The token itself is stateless and
188
+ // lives up to five hours, so the connection is asked on every request
189
+ // whether it still admits the agent — revoking the agent must reach
190
+ // this path as surely as it reaches the grant's own tokens. The use is
191
+ // stamped too (throttled, off the request's path), so the Audit log's
192
+ // "last used" follows the local server's calls, not only its sign-ins.
193
+ // Carried on the request so those calls are logged under the agent.
194
+ if (claim.connectionId) {
195
+ let live: boolean;
196
+ try {
197
+ live = await oauthProvider.isConnectionLive(claim.connectionId);
198
+ } catch (err) {
199
+ log.error('agent-connection check failed:', { err });
200
+ res.status(500).json({ error: 'Authentication backend unavailable' });
201
+ return;
202
+ }
203
+ if (!live) {
204
+ unauthorized(res, 'Access for this agent was revoked');
205
+ return;
206
+ }
207
+ oauthProvider.noteConnectionUse(claim.connectionId);
208
+ req.agentConnectionId = claim.connectionId;
209
+ }
179
210
  next();
180
211
  return;
181
212
  }
@@ -115,6 +115,10 @@ export function createMcpRoutes(
115
115
  // undefined for OAuth/JWT) — resolved per request, so per-key metering
116
116
  // never depends on anything remembered from an earlier request.
117
117
  tokenId: req.externalApiKeyId ?? null,
118
+ // Agent-connection id (set for OAuth bearers and the local server's
119
+ // exchanged grant; undefined for keys/JWTs) — the Audit log's other
120
+ // principal, resolved per request like the key id.
121
+ connectionId: req.agentConnectionId ?? null,
118
122
  // The proxy authenticates its loopback calls with the SAME bearer the
119
123
  // client used here, so it acts on the request exactly as the caller would.
120
124
  bearer: extractBearer(req),
@@ -355,7 +359,13 @@ export function createMcpRoutes(
355
359
  grantRemainingMs === undefined
356
360
  ? MCP_LOOPBACK_TOKEN_TTL_MS
357
361
  : Math.min(MCP_LOOPBACK_TOKEN_TTL_MS, grantRemainingMs);
358
- const minted = internalTokens.mint({ userId, externalProxy: true }, ttlMs);
362
+ // The grant's agent connection rides along, so the local server's
363
+ // calls with this token stay attributed to the agent in the Audit log.
364
+ const connectionId = typeof info.extra?.connectionId === 'string' ? info.extra.connectionId : undefined;
365
+ const minted = internalTokens.mint(
366
+ { userId, externalProxy: true, ...(connectionId ? { connectionId } : {}) },
367
+ ttlMs,
368
+ );
359
369
  // The ACTUAL lifetime, not the constant — the caller schedules its
360
370
  // proactive renewal off this number.
361
371
  res.json({ token: minted, expiresInMs: ttlMs });
@@ -54,6 +54,8 @@ import type { IToolManualService } from '../tool-manuals/tool-manuals.contract.j
54
54
  import type { SpillStore } from '../workspace/spill-store.js';
55
55
  import { seedBevelHostedManualVars } from '../../shared/utcp-namespace.js';
56
56
  import type { InternalTokenService } from '../tool-auth/internal-token.service.js';
57
+ import type { IAgentEventRecorder } from '../audit/audit.contract.js';
58
+ import { RequestAudit } from '../audit/request-audit.js';
57
59
  import { ManualFailureMemo } from './manual-failure-memo.js';
58
60
  import { DownstreamPool, POOL_KEY_SEPARATOR, type DownstreamPoolOptions, type Lease } from './downstream-pool.js';
59
61
  import { SurfaceLogThrottle } from './surface-log-throttle.js';
@@ -91,6 +93,13 @@ export interface McpProxyOptions {
91
93
  readAgentPreamble?: AgentPreambleReader;
92
94
  /** Bounds of the downstream (`mcp.json`) connection pool; defaults are 4h idle / 5000 entries. */
93
95
  downstreamPool?: Pick<DownstreamPoolOptions<unknown>, 'idleTtlMs' | 'maxEntries' | 'now'>;
96
+ /**
97
+ * The scope this knowledge base's secrets vault was registered under (see
98
+ * `secrets-variable-loader.ts`), so the UTCP clients built here resolve a
99
+ * caller's `${VAR}`s from that vault and no other's. Default: the single
100
+ * knowledge base's.
101
+ */
102
+ secretsScope?: string;
94
103
  }
95
104
 
96
105
  /** Who a request is from — everything the proxy needs, resolved from that request's own bearer. */
@@ -98,6 +107,12 @@ export interface McpCaller {
98
107
  userId: string;
99
108
  /** The connection-key id (per-key metering rides on it), or null for an OAuth/JWT bearer. */
100
109
  tokenId: string | null;
110
+ /**
111
+ * The agent connection behind an OAuth bearer (or the local server's
112
+ * exchanged grant), or null. With `tokenId`, the two ways a call is
113
+ * attributed in the Audit log; a request with neither records nothing.
114
+ */
115
+ connectionId?: string | null;
101
116
  /** The raw bearer the request carried. */
102
117
  bearer: string;
103
118
  }
@@ -268,6 +283,10 @@ export class McpService {
268
283
  // authorization when one of its TOOL sign-ins breaks. Optional: without
269
284
  // it, broken sign-ins surface only as the /connect link in the result.
270
285
  private readonly revokeOAuthAccess?: (bearer: string) => Promise<void>,
286
+ // The Audit log's recorder: every tool call, skill read and meta-tool run
287
+ // of a request that arrived with a key or an agent connection goes
288
+ // through it. Optional like the others; without it nothing is recorded.
289
+ private readonly auditRecorder?: IAgentEventRecorder,
271
290
  ) {
272
291
  this.downstream = new DownstreamPool<PooledDownstream>({
273
292
  ...opts.downstreamPool,
@@ -332,6 +351,7 @@ export class McpService {
332
351
  */
333
352
  async createRequestServer(caller: McpCaller, messages: unknown): Promise<Server> {
334
353
  const { userId, tokenId, bearer } = caller;
354
+ const connectionId = caller.connectionId ?? null;
335
355
  // The loopback surface (`/api/agent/*`) accepts connection keys and
336
356
  // internal tokens only. A connection-key request passes the caller's own
337
357
  // key through (per-key metering rides on it); an OAuth/JWT request's
@@ -347,8 +367,30 @@ export class McpService {
347
367
 
348
368
  let instructions: Promise<ComposedAgentInstructions> | undefined;
349
369
  const agentInstructions = () => (instructions ??= this.composeAgentInstructions());
370
+ // The Audit log's view of this request — only when the request can be
371
+ // attributed to a key or an agent connection. The catalog names it
372
+ // classifies pooled tools by are the surface's, which is built lazily
373
+ // below, so it reads them through a holder the surface fills in.
374
+ const catalogNamesHolder: { current: ReadonlyMap<string, string> } = { current: new Map() };
375
+ const principal = tokenId != null ? { kind: 'key' as const, id: tokenId } : connectionId ? { kind: 'agent' as const, id: connectionId } : null;
376
+ const audit =
377
+ this.auditRecorder && principal
378
+ ? new RequestAudit(this.auditRecorder, userId, principal, {
379
+ kbManualName: EXTERNAL_KB_MANUAL_NAME,
380
+ catalogNames: () => catalogNamesHolder.current,
381
+ loadSkills: () =>
382
+ this.fetchSkillList(loopbackBearer).then((skills) =>
383
+ skills.flatMap((s) => (s.path ? [{ name: s.name, path: s.path }] : [])),
384
+ ),
385
+ })
386
+ : null;
350
387
  let surface: Promise<RequestSurface> | undefined;
351
- const requestSurface = () => (surface ??= this.buildSurface(userId, tokenId, loopbackBearer));
388
+ const requestSurface = () =>
389
+ (surface ??= this.buildSurface(userId, tokenId, loopbackBearer).then((built) => {
390
+ catalogNamesHolder.current = built.catalogNames;
391
+ audit?.instrumentChainCalls(built.client);
392
+ return built;
393
+ }));
352
394
 
353
395
  const initializing = (Array.isArray(messages) ? messages : [messages]).some((m) => isInitializeRequest(m));
354
396
  const server = new Server(
@@ -432,8 +474,12 @@ export class McpService {
432
474
  server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
433
475
  const { client, tools, unavailable, catalogNames } = await requestSurface();
434
476
  const toolName = request.params.name;
477
+ const args = request.params.arguments ?? {};
435
478
  if (META_TOOL_NAMES.has(toolName)) {
436
- return this.dispatchMetaTool(client, toolName, request.params.arguments ?? {});
479
+ // A meta-tool is the platform's own; its inner tool calls (a chain's)
480
+ // are recorded one by one through the instrumented client.
481
+ const run = () => this.dispatchMetaTool(client, toolName, args);
482
+ return audit ? audit.call(toolName, args, run, isErrorResult) : run();
437
483
  }
438
484
  /**
439
485
  * The needs-authorization answer, when the caller's sign-in for the
@@ -476,11 +522,18 @@ export class McpService {
476
522
  .filter((m) => toolName.startsWith(`${m.utcpName}_`))
477
523
  .sort((a, b) => b.utcpName.length - a.utcpName.length)[0];
478
524
  const answer = owner ? await needsAuthorization(owner.utcpName) : null;
525
+ if (answer && owner && audit) {
526
+ await audit.denied(`${owner.utcpName}.${toolName.slice(owner.utcpName.length + 1)}`, args);
527
+ }
479
528
  return answer ?? toolError(retiredToolMessage(toolName) ?? `Unknown tool "${toolName}".`);
480
529
  }
481
530
  const needsAuth = await needsAuthorization(proxied.manualName);
482
- if (needsAuth) return needsAuth;
483
- return this.dispatch(client, proxied, request, extra);
531
+ if (needsAuth) {
532
+ if (audit) await audit.denied(proxied.utcpName, args);
533
+ return needsAuth;
534
+ }
535
+ const run = () => this.dispatch(client, proxied, request, extra);
536
+ return audit ? audit.call(proxied.utcpName, args, run, isErrorResult) : run();
484
537
  });
485
538
 
486
539
  // Prompts = skills. Each skill becomes a user-callable prompt (slash command
@@ -499,7 +552,14 @@ export class McpService {
499
552
  });
500
553
 
501
554
  server.setRequestHandler(GetPromptRequestSchema, async (request): Promise<GetPromptResult> => {
555
+ const started = performance.now();
502
556
  const skill = await this.fetchSkill(loopbackBearer, request.params.name);
557
+ // A prompt IS a skill read — the same event `get_skill` produces.
558
+ audit?.emit(
559
+ { kind: 'skill', manual: skill?.path ?? null, name: request.params.name },
560
+ skill ? 'ok' : 'error',
561
+ Math.round(performance.now() - started),
562
+ );
503
563
  if (!skill) {
504
564
  throw new McpError(ErrorCode.InvalidParams, `Unknown skill "${request.params.name}".`);
505
565
  }
@@ -674,7 +734,7 @@ export class McpService {
674
734
  */
675
735
  private async buildClient(bearer: string, userId: string, manuals: CallTemplate[]): Promise<CodeModeUtcpClient> {
676
736
  const variables = seedBevelHostedManualVars(manuals, this.opts.loopbackBaseUrl, bearer);
677
- return CodeModeUtcpClient.create(process.cwd(), utcpClientConfig(userId, variables));
737
+ return CodeModeUtcpClient.create(process.cwd(), utcpClientConfig(userId, variables, this.opts.secretsScope));
678
738
  }
679
739
 
680
740
  /**
@@ -906,7 +966,7 @@ export class McpService {
906
966
  private async connectDownstream(userId: string, template: CallTemplate): Promise<PooledDownstream> {
907
967
  // Third-party manuals are never seeded loopback credentials (see
908
968
  // `buildClient`), so a pooled client carries no request-scoped bearer.
909
- const client = await CodeModeUtcpClient.create(process.cwd(), utcpClientConfig(userId, {}));
969
+ const client = await CodeModeUtcpClient.create(process.cwd(), utcpClientConfig(userId, {}, this.opts.secretsScope));
910
970
  // Our own copy: registration renames the template in place, and recovery
911
971
  // re-registers from exactly what discovery used.
912
972
  const own = structuredClone(template);
@@ -1176,16 +1236,21 @@ export class McpService {
1176
1236
  }
1177
1237
  }
1178
1238
 
1239
+ /** Whether a tool result is the tool saying it failed — what the Audit log records as `error`. */
1240
+ function isErrorResult(result: CallToolResult): boolean {
1241
+ return result.isError === true;
1242
+ }
1243
+
1179
1244
  /**
1180
1245
  * The UTCP client config for `userId`: the given variables, plus the per-user
1181
1246
  * `bevel-secrets` loader that resolves every `${SECRET}` ref lazily. Shared by
1182
1247
  * request clients and pooled downstream clients, so both resolve a manual's
1183
1248
  * variables through exactly the same tiers.
1184
1249
  */
1185
- function utcpClientConfig(userId: string, variables: Record<string, string>) {
1250
+ function utcpClientConfig(userId: string, variables: Record<string, string>, secretsScope?: string) {
1186
1251
  return new UtcpClientConfigSerializer().validateDict({
1187
1252
  variables,
1188
- load_variables_from: [bevelSecretsLoaderConfig(userId)],
1253
+ load_variables_from: [bevelSecretsLoaderConfig(userId, secretsScope)],
1189
1254
  });
1190
1255
  }
1191
1256
 
@@ -2,7 +2,7 @@ import { createHash, randomBytes } from 'node:crypto';
2
2
  import { logger } from '../../../shared/logging.js';
3
3
 
4
4
  const log = logger('mcp-oauth');
5
- import { and, eq, gt, isNull, lt, or } from 'drizzle-orm';
5
+ import { and, count, eq, gt, isNull, lt, or, sql } from 'drizzle-orm';
6
6
  import type { Response } from 'express';
7
7
  import type {
8
8
  AuthorizationParams,
@@ -21,7 +21,7 @@ import type {
21
21
  OAuthTokens,
22
22
  } from '@modelcontextprotocol/sdk/shared/auth.js';
23
23
  import type { Database } from '../../database/connection.js';
24
- import { oauthAuthCodes, oauthClients, oauthTokens, users } from '../../database/schema.js';
24
+ import { agentConnections, oauthAuthCodes, oauthClients, oauthTokens, users } from '../../database/schema.js';
25
25
  import type { TokenCrypto } from '../../../shared/token-crypto.js';
26
26
  import { signAuthRequest, type McpAuthRequestState } from './oauth-state.js';
27
27
 
@@ -34,6 +34,13 @@ const TOKEN_BYTES = 32;
34
34
  const ACCESS_TTL_MS = 60 * 60_000; // 1 hour
35
35
  const REFRESH_TTL_MS = 30 * 24 * 60 * 60_000; // 30 days, rotated on use
36
36
  const CODE_TTL_MS = 60_000; // exchanged within seconds of Finish
37
+ /**
38
+ * How often, at most, one process stamps an agent connection's `last_used_at`.
39
+ * The Audit log shows the instant relatively ("4 minutes ago"), so a minute's
40
+ * staleness is invisible, while a write per request on a chain-heavy session
41
+ * would serialise hundreds of requests a minute on one row.
42
+ */
43
+ const CONNECTION_TOUCH_INTERVAL_MS = 60_000;
37
44
 
38
45
  export interface BevelOAuthProviderDeps {
39
46
  db: Database;
@@ -66,6 +73,8 @@ export interface BevelOAuthProviderDeps {
66
73
  */
67
74
  export class BevelOAuthProvider implements OAuthServerProvider {
68
75
  private readonly store: OAuthRegisteredClientsStore;
76
+ /** When this process last stamped each connection's use — see {@link noteConnectionUse}. */
77
+ private readonly connectionTouchedAt = new Map<string, number>();
69
78
 
70
79
  constructor(private readonly deps: BevelOAuthProviderDeps) {
71
80
  this.store = {
@@ -276,15 +285,36 @@ export class BevelOAuthProvider implements OAuthServerProvider {
276
285
  }
277
286
  scope = scopes.join(' ');
278
287
  }
279
- return this.mintTokens(row.userId, row.clientId, scope, row.resource);
288
+ // A refresh STAYS on its token's agent connection and is refused once
289
+ // that connection is revoked. The connection is the authority on whether
290
+ // the agent may hold tokens at all: were a refresh to look the connection
291
+ // up afresh, one racing a revoke would find none live, make a new one and
292
+ // mint an unrevoked pair — the revoke undone by a millisecond. A token
293
+ // from before connections existed has none to stay on and is placed
294
+ // under one as a first mint would be.
295
+ if (row.connectionId) {
296
+ if (!(await this.isConnectionLive(row.connectionId))) {
297
+ throw new InvalidGrantError('Access for this agent was revoked');
298
+ }
299
+ this.noteConnectionUse(row.connectionId);
300
+ }
301
+ return this.mintTokens(row.userId, row.clientId, scope, row.resource, row.connectionId ?? undefined);
280
302
  }
281
303
 
282
304
  async verifyAccessToken(token: string): Promise<AuthInfo> {
283
305
  const now = new Date();
306
+ // The agent connection is joined so a token of a REVOKED connection fails
307
+ // here whatever its own row says: revoking an agent marks its tokens too,
308
+ // but the connection is the authority, and a token minted a moment after
309
+ // the revoke (a refresh that raced it) is dead on arrival rather than
310
+ // live until its own expiry. A token from before connections existed
311
+ // (null `connection_id`) has no connection to be revoked and verifies on
312
+ // its own row alone.
284
313
  const [row] = await this.deps.db
285
314
  .select({
286
315
  id: oauthTokens.id,
287
316
  clientId: oauthTokens.clientId,
317
+ connectionId: oauthTokens.connectionId,
288
318
  scope: oauthTokens.scope,
289
319
  resource: oauthTokens.resource,
290
320
  expiresAt: oauthTokens.expiresAt,
@@ -293,11 +323,13 @@ export class BevelOAuthProvider implements OAuthServerProvider {
293
323
  })
294
324
  .from(oauthTokens)
295
325
  .innerJoin(users, eq(oauthTokens.userId, users.id))
326
+ .leftJoin(agentConnections, eq(oauthTokens.connectionId, agentConnections.id))
296
327
  .where(
297
328
  and(
298
329
  eq(oauthTokens.accessTokenHash, hashToken(token)),
299
330
  isNull(oauthTokens.revokedAt),
300
331
  gt(oauthTokens.expiresAt, now),
332
+ or(isNull(oauthTokens.connectionId), isNull(agentConnections.revokedAt)),
301
333
  ),
302
334
  )
303
335
  .limit(1);
@@ -311,13 +343,22 @@ export class BevelOAuthProvider implements OAuthServerProvider {
311
343
  .set({ lastUsedAt: now })
312
344
  .where(eq(oauthTokens.id, row.id))
313
345
  .then(undefined, (err) => log.warn('touch lastUsedAt failed:', { err }));
346
+ // The agent connection's own "last used" — what the Audit log shows for
347
+ // the agent, across every token it has held. Throttled, never awaited.
348
+ if (row.connectionId) this.noteConnectionUse(row.connectionId);
314
349
  return {
315
350
  token,
316
351
  clientId: row.clientId,
317
352
  scopes: (row.scope ?? '').split(' ').filter(Boolean),
318
353
  expiresAt: Math.floor(row.expiresAt.getTime() / 1000),
319
354
  resource: row.resource ? new URL(row.resource) : undefined,
320
- extra: { userId: row.userId, userEmail: row.userEmail },
355
+ extra: {
356
+ userId: row.userId,
357
+ userEmail: row.userEmail,
358
+ // Null on a token minted before connections existed; the auth
359
+ // middleware then binds no agent and the call goes unrecorded.
360
+ connectionId: row.connectionId,
361
+ },
321
362
  };
322
363
  }
323
364
 
@@ -343,7 +384,7 @@ export class BevelOAuthProvider implements OAuthServerProvider {
343
384
  // RFC 7009: revoking an unknown/foreign/already-revoked token is a no-op.
344
385
  // The token may be either half of a pair — one UPDATE matching either hash.
345
386
  const hash = hashToken(request.token);
346
- await this.deps.db
387
+ const revoked = await this.deps.db
347
388
  .update(oauthTokens)
348
389
  .set({ revokedAt: new Date() })
349
390
  .where(
@@ -352,14 +393,39 @@ export class BevelOAuthProvider implements OAuthServerProvider {
352
393
  isNull(oauthTokens.revokedAt),
353
394
  or(eq(oauthTokens.accessTokenHash, hash), eq(oauthTokens.refreshTokenHash, hash)),
354
395
  ),
355
- );
396
+ )
397
+ .returning({ connectionId: oauthTokens.connectionId });
398
+ // A client revoking its own token is signing out. When that leaves the
399
+ // agent connection with no live token at all, the connection is over
400
+ // too — disconnected by its owner, as the Audit log then says — rather
401
+ // than listed as live forever with nothing behind it. (The proxy's own
402
+ // reset of a broken sign-in goes through `revokeByAccessToken`, not
403
+ // here, and must NOT close the connection: that agent is being sent
404
+ // back to re-authorise into the same one.)
405
+ const connectionId = revoked.find((r) => r.connectionId)?.connectionId;
406
+ if (!connectionId) return;
407
+ const [{ live }] = await this.deps.db
408
+ .select({ live: count() })
409
+ .from(oauthTokens)
410
+ .where(and(eq(oauthTokens.connectionId, connectionId), isNull(oauthTokens.revokedAt)));
411
+ if (Number(live) > 0) return;
412
+ await this.deps.db
413
+ .update(agentConnections)
414
+ .set({ revokedAt: new Date(), revokedBy: 'owner' })
415
+ .where(and(eq(agentConnections.id, connectionId), isNull(agentConnections.revokedAt)));
356
416
  }
357
417
 
418
+ /**
419
+ * @param connectionId The agent connection the pair belongs to, when the
420
+ * caller already holds one (a refresh: the consumed token's). Absent on a
421
+ * first mint, which finds or makes the live connection for (user, client).
422
+ */
358
423
  private async mintTokens(
359
424
  userId: string,
360
425
  clientId: string,
361
426
  scope: string | null,
362
427
  resource: string | null,
428
+ connectionId?: string,
363
429
  ): Promise<OAuthTokens> {
364
430
  const accessToken = this.deps.tokenPrefix + randomBytes(TOKEN_BYTES).toString('base64url');
365
431
  const refreshToken = this.refreshPrefix + randomBytes(TOKEN_BYTES).toString('base64url');
@@ -382,11 +448,13 @@ export class BevelOAuthProvider implements OAuthServerProvider {
382
448
  } catch (err) {
383
449
  log.warn('token-table prune failed (non-fatal):', { err });
384
450
  }
451
+ const boundTo = connectionId ?? (await this.ensureConnection(userId, clientId));
385
452
  await this.deps.db.insert(oauthTokens).values({
386
453
  accessTokenHash: hashToken(accessToken),
387
454
  refreshTokenHash: hashToken(refreshToken),
388
455
  clientId,
389
456
  userId,
457
+ connectionId: boundTo,
390
458
  scope,
391
459
  resource,
392
460
  expiresAt: new Date(now + ACCESS_TTL_MS),
@@ -400,6 +468,116 @@ export class BevelOAuthProvider implements OAuthServerProvider {
400
468
  ...(scope ? { scope } : {}),
401
469
  };
402
470
  }
471
+
472
+ /**
473
+ * The live `agent_connections` row for (user, client) — found, or made on
474
+ * the first mint for the pair. A refresh finds the row the sign-in made, so
475
+ * one connection spans every token the agent ever holds; a mint after a
476
+ * revoke finds nothing live and makes a fresh row, which is what keeps the
477
+ * revoked one's history intact.
478
+ *
479
+ * Two concurrent first mints (a client racing its own token exchange) both
480
+ * miss the select; the partial unique index lets exactly one insert land,
481
+ * the other's `ON CONFLICT DO NOTHING` returns no row, and it re-reads the
482
+ * winner's. The client's display name is snapshotted from its registration
483
+ * at that moment.
484
+ */
485
+ /**
486
+ * Whether an agent connection still admits requests: it exists and nobody
487
+ * has revoked it. Asked on every refresh, and by the MCP auth middleware on
488
+ * every request through the local server's exchanged grant — the one path
489
+ * where a token verifies statelessly and would otherwise outlive the
490
+ * revoke. A read, not a write: the use is stamped separately, throttled.
491
+ */
492
+ async isConnectionLive(connectionId: string): Promise<boolean> {
493
+ const [row] = await this.deps.db
494
+ .select({ id: agentConnections.id })
495
+ .from(agentConnections)
496
+ .where(and(eq(agentConnections.id, connectionId), isNull(agentConnections.revokedAt)))
497
+ .limit(1);
498
+ return row !== undefined;
499
+ }
500
+
501
+ /**
502
+ * Record that an agent connection is in use — its `last_used_at` on the
503
+ * Audit log — at most once a minute per connection per process, and never
504
+ * on the caller's critical path. The stamp is what the page shows; the
505
+ * liveness decision above never depends on it.
506
+ */
507
+ noteConnectionUse(connectionId: string): void {
508
+ const now = Date.now();
509
+ const last = this.connectionTouchedAt.get(connectionId);
510
+ if (last !== undefined && now - last < CONNECTION_TOUCH_INTERVAL_MS) return;
511
+ this.connectionTouchedAt.set(connectionId, now);
512
+ this.deps.db
513
+ .update(agentConnections)
514
+ .set({ lastUsedAt: new Date(now) })
515
+ .where(eq(agentConnections.id, connectionId))
516
+ .then(undefined, (err) => log.warn('touch connection lastUsedAt failed:', { err }));
517
+ }
518
+
519
+ /**
520
+ * The live `agent_connections` row for (user, agent) — found, or made on
521
+ * the first mint for the pair. The AGENT is the registered client's name,
522
+ * folded (see the schema): a client that registers itself afresh on every
523
+ * re-authorisation, as Claude does, lands every registration on the one
524
+ * row rather than a row per client id. A refresh finds the row the sign-in
525
+ * made, so one connection spans every token the agent ever holds; a mint
526
+ * after a revoke finds nothing live and makes a fresh row, which is what
527
+ * keeps the revoked one's history intact.
528
+ *
529
+ * Two concurrent first mints (a client racing its own token exchange) both
530
+ * miss the select; the partial unique index lets exactly one insert land,
531
+ * the other's `ON CONFLICT DO NOTHING` returns no row, and it re-reads the
532
+ * winner's. The client's display name is snapshotted from its registration
533
+ * at that moment.
534
+ */
535
+ private async ensureConnection(userId: string, clientId: string): Promise<string> {
536
+ const [client] = await this.deps.db
537
+ .select({ clientName: oauthClients.clientName })
538
+ .from(oauthClients)
539
+ .where(eq(oauthClients.clientId, clientId))
540
+ .limit(1);
541
+ const clientName = client?.clientName ?? null;
542
+ const agentKey = agentKeyFor(clientName, clientId);
543
+ const live = () =>
544
+ this.deps.db
545
+ .select({ id: agentConnections.id })
546
+ .from(agentConnections)
547
+ .where(
548
+ and(
549
+ eq(agentConnections.userId, userId),
550
+ eq(agentConnections.agentKey, agentKey),
551
+ isNull(agentConnections.revokedAt),
552
+ ),
553
+ )
554
+ .limit(1);
555
+ const [existing] = await live();
556
+ if (existing) return existing.id;
557
+ const [inserted] = await this.deps.db
558
+ .insert(agentConnections)
559
+ .values({ userId, clientId, clientName, agentKey })
560
+ .onConflictDoNothing({
561
+ target: [agentConnections.userId, agentConnections.agentKey],
562
+ where: sql`${agentConnections.revokedAt} is null`,
563
+ })
564
+ .returning({ id: agentConnections.id });
565
+ if (inserted) return inserted.id;
566
+ const [winner] = await live();
567
+ if (!winner) throw new Error('agent connection vanished between insert and re-read');
568
+ return winner.id;
569
+ }
570
+ }
571
+
572
+ /**
573
+ * What an agent connection is keyed by: the registered client name, folded
574
+ * (case and surrounding whitespace are not identity), or the client id for
575
+ * a registration that carried no name. The SAME fold the migration applied
576
+ * to the rows that existed before the key did.
577
+ */
578
+ export function agentKeyFor(clientName: string | null, clientId: string): string {
579
+ const folded = (clientName ?? '').trim().toLowerCase();
580
+ return folded || clientId;
403
581
  }
404
582
 
405
583
  function hashToken(plaintext: string): string {
@@ -3,7 +3,8 @@ import { NodeFs } from '../../kb-fs/node-fs.js';
3
3
  import fs from 'node:fs/promises';
4
4
  import os from 'node:os';
5
5
  import path from 'node:path';
6
- import { DEFAULT_BRANCH, DEFAULT_KB_LAYOUT, configureKbLayout } from '@bevel-software/platform-shared';
6
+ import { DEFAULT_BRANCH } from '@bevel-software/platform-shared';
7
+ import { testKbContext } from '../../../__tests__/kb-context.js';
7
8
 
8
9
  import type { WorkspaceService } from '../../workspace/workspace.service.js';
9
10
  import { AccessControlService } from '../../access/access-control.service.js';
@@ -46,7 +47,8 @@ describe('bundle dialect, end to end', () => {
46
47
  };
47
48
 
48
49
  beforeEach(async () => {
49
- configureKbLayout({ knowledgeBaseDir: 'docs', skillsDir: 'skills', pluginsDir: 'plugins' });
50
+ // The customer's root names, read by every consumer through one context.
51
+ const kb = testKbContext({ kbDirName: KB_DIR, layout: { knowledgeBaseDir: 'docs', skillsDir: 'skills', pluginsDir: 'plugins' } });
50
52
  root = await fs.mkdtemp(path.join(os.tmpdir(), 'bevel-dialect-'));
51
53
  repo = path.join(root, wsId, KB_DIR);
52
54
  const workspaceService = {
@@ -94,17 +96,16 @@ describe('bundle dialect, end to end', () => {
94
96
  );
95
97
 
96
98
  const disk = new NodeFs();
97
- const source = new KbPluginSource(disk);
98
- access = new AccessControlService(workspaceService, KB_DIR, disk);
99
- skills = new SkillService(workspaceService, access, KB_DIR, disk);
100
- tools = new ToolManualService(workspaceService, access, KB_DIR, disk, source);
101
- links = new PluginLinkIndex(workspaceService, skills, access, KB_DIR, source);
102
- index = new PluginIndexService(workspaceService, access, skills, tools, KB_DIR, source, Date.now, links);
103
- compiler = new MarketplaceCompilerService(workspaceService, access, skills, links, KB_DIR, { name: 'acme', owner: 'Acme' }, source, disk, new NodeGitRunner());
104
- linkService = new PluginLinksService(workspaceService, { runPendingCommit: async () => undefined }, access, skills, links, KB_DIR);
99
+ const source = new KbPluginSource(disk, kb);
100
+ access = new AccessControlService(workspaceService, KB_DIR, disk, [], new NodeGitRunner(), kb);
101
+ skills = new SkillService(workspaceService, access, kb, disk);
102
+ tools = new ToolManualService(workspaceService, access, kb, disk, source);
103
+ links = new PluginLinkIndex(workspaceService, skills, access, kb, source);
104
+ index = new PluginIndexService(workspaceService, access, skills, tools, kb, source, Date.now, links);
105
+ compiler = new MarketplaceCompilerService(workspaceService, access, skills, links, kb, { name: 'acme', owner: 'Acme' }, source, disk, new NodeGitRunner());
106
+ linkService = new PluginLinksService(workspaceService, { runPendingCommit: async () => undefined }, access, skills, links, kb);
105
107
  });
106
108
  afterEach(async () => {
107
- configureKbLayout({ ...DEFAULT_KB_LAYOUT });
108
109
  await fs.rm(root, { recursive: true, force: true });
109
110
  });
110
111
 
@@ -1,4 +1,5 @@
1
1
  import { describe, it, expect } from 'vitest';
2
+ import { DEFAULT_KB_LAYOUT } from '@bevel-software/platform-shared';
2
3
  import fs from 'node:fs/promises';
3
4
  import os from 'node:os';
4
5
  import path from 'node:path';
@@ -147,7 +148,7 @@ describe('bundle: what it says about itself survives', () => {
147
148
  }),
148
149
  );
149
150
  const warnings: string[] = [];
150
- const plugin = await readBundlePlugin(dir, 'plugins/ado', 'ado', null, warnings, []);
151
+ const plugin = await readBundlePlugin(dir, 'plugins/ado', 'ado', null, warnings, [], DEFAULT_KB_LAYOUT);
151
152
  expect(plugin?.manifest).toEqual({
152
153
  name: 'ado',
153
154
  version: '1.3.5',
@@ -16,6 +16,7 @@ import { NodeGitRunner } from '../../workflow/git/node-git-runner.js';
16
16
  import express from 'express';
17
17
  import { ToolRegistry } from '../../tool-registry/tool-registry.js';
18
18
  import { registerSkillsTools } from '../../skills/skills.tools.js';
19
+ import { testKbContext } from '../../../__tests__/kb-context.js';
19
20
 
20
21
  /**
21
22
  * Source in, distribution out — for one caller. The real resolver decides
@@ -90,17 +91,18 @@ describe('compileMarketplace', () => {
90
91
  await write('Skills/Sales/pitch/SKILL.md', '---\ndescription: Pitch.\n---\n');
91
92
 
92
93
  const disk = new NodeFs();
93
- const source = new KbPluginSource(disk);
94
+ const kb = testKbContext({ kbDirName: KB_DIR });
95
+ const source = new KbPluginSource(disk, kb);
94
96
  const access = new AccessControlService(workspaceService, KB_DIR, disk);
95
- const skills = new SkillService(workspaceService, access, KB_DIR, disk);
97
+ const skills = new SkillService(workspaceService, access, kb, disk);
96
98
  catalog = skills;
97
- const links = new PluginLinkIndex(workspaceService, skills, access, KB_DIR, source);
99
+ const links = new PluginLinkIndex(workspaceService, skills, access, kb, source);
98
100
  compiler = new MarketplaceCompilerService(
99
101
  workspaceService,
100
102
  access,
101
103
  skills,
102
104
  links,
103
- KB_DIR,
105
+ kb,
104
106
  {
105
107
  name: 'acme-hexis',
106
108
  owner: 'Acme',
@@ -8,6 +8,7 @@ import {
8
8
  } from '../join-request-jobs.service.js';
9
9
  import { workspaceIdForBranch } from '../../../shared/workspace-id.js';
10
10
  import { FakeJoinRequestStore } from './fake-join-request-store.js';
11
+ import { testKbContext } from '../../../__tests__/kb-context.js';
11
12
 
12
13
  /**
13
14
  * The git half of a join request, on its own: what it does to the row it was
@@ -40,7 +41,7 @@ function harness(over: Partial<JoinRequestJobsDeps> = {}, sharedStore?: FakeJoin
40
41
  const jobs = new PluginJoinRequestJobs(store, {
41
42
  workflow: workflow as never,
42
43
  workspaceService: workspaceService as never,
43
- kbDirName: KB,
44
+ kb: testKbContext({ kbDirName: KB }),
44
45
  target: async () => ({ folder: 'Plugins/Finance', displayName: 'Finance' }),
45
46
  requester: async (mail) => ({ ...ALI_USER, email: mail }),
46
47
  ...over,