@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
@@ -0,0 +1,121 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { classifyToolCall, skillContaining, skillReadPath, splitUtcpName } from '../event-classifier.js';
3
+
4
+ const KB = 'KNOWLEDGE_BASE';
5
+ const ctx = { kbManualName: KB, catalogNames: new Map([['my_server', 'my-server']]) };
6
+ const skills = [
7
+ { name: 'rfi', path: 'Plugins/Sales/rfi' },
8
+ { name: 'deploy-checklist', path: 'Skills/Engineering/deploy-checklist' },
9
+ // Nested under another skill's folder: the longer match must win.
10
+ { name: 'rfi-followup', path: 'Plugins/Sales/rfi/followup' },
11
+ ];
12
+
13
+ describe('splitUtcpName', () => {
14
+ it('splits on the first dot and leaves a bare name without a manual', () => {
15
+ expect(splitUtcpName('KNOWLEDGE_BASE.read_file')).toEqual({ manual: 'KNOWLEDGE_BASE', tool: 'read_file' });
16
+ expect(splitUtcpName('notion.notion-search')).toEqual({ manual: 'notion', tool: 'notion-search' });
17
+ expect(splitUtcpName('call_tool_chain')).toEqual({ manual: '', tool: 'call_tool_chain' });
18
+ });
19
+ });
20
+
21
+ describe('skillReadPath', () => {
22
+ it('asks for the skill catalog only for a platform read that names a path, or a get_skill with a name', () => {
23
+ expect(skillReadPath(`${KB}.read_file`, { body: { path: 'Plugins/Sales/rfi/SKILL.md' } }, KB)).toBe(
24
+ 'Plugins/Sales/rfi/SKILL.md',
25
+ );
26
+ expect(skillReadPath(`${KB}.grep`, { path: 'Skills' }, KB)).toBe('Skills');
27
+ expect(skillReadPath(`${KB}.get_skill`, { body: { name: 'rfi' } }, KB)).toBe('');
28
+ // Not worth a catalog fetch: a write, a read with no path, another manual's tool, a meta-tool.
29
+ expect(skillReadPath(`${KB}.write_file`, { body: { path: 'Plugins/x' } }, KB)).toBeNull();
30
+ expect(skillReadPath(`${KB}.read_file`, { body: {} }, KB)).toBeNull();
31
+ expect(skillReadPath('notion.search', { body: { path: 'Plugins/x' } }, KB)).toBeNull();
32
+ expect(skillReadPath('call_tool_chain', { code: 'x' }, KB)).toBeNull();
33
+ });
34
+ });
35
+
36
+ describe('skillContaining', () => {
37
+ it('matches a path inside a skill folder on a segment boundary, from either root, longest folder first', () => {
38
+ expect(skillContaining('Plugins/Sales/rfi/SKILL.md', skills)?.name).toBe('rfi');
39
+ expect(skillContaining('knowledge-base/Plugins/Sales/rfi/scripts/build.py', skills)?.name).toBe('rfi');
40
+ expect(skillContaining('./Skills\\Engineering\\deploy-checklist\\SKILL.md', skills)?.name).toBe('deploy-checklist');
41
+ expect(skillContaining('Plugins/Sales/rfi/followup/SKILL.md', skills)?.name).toBe('rfi-followup');
42
+ // The file tools accept a doubled separator as the same path; so does this.
43
+ expect(skillContaining('Plugins//Sales/rfi/SKILL.md', skills)?.name).toBe('rfi');
44
+ // `.` and `..` are resolved before matching: a path that climbs out of a
45
+ // skill folder is not a read of that skill, and one that climbs above its
46
+ // own start is no place at all.
47
+ expect(skillContaining('Plugins/Sales/rfi/./SKILL.md', skills)?.name).toBe('rfi');
48
+ expect(skillContaining('Plugins/Sales/other/../rfi/SKILL.md', skills)?.name).toBe('rfi');
49
+ expect(skillContaining('Plugins/Sales/rfi/../../../KnowledgeBase/Secrets.md', skills)).toBeNull();
50
+ expect(skillContaining('../Plugins/Sales/rfi/SKILL.md', skills)).toBeNull();
51
+ // A folder that merely shares a prefix is not the skill's folder.
52
+ expect(skillContaining('Plugins/Sales/rfi-old/notes.md', skills)).toBeNull();
53
+ expect(skillContaining('KnowledgeBase/Product/roadmap.md', skills)).toBeNull();
54
+ });
55
+ });
56
+
57
+ describe('classifyToolCall', () => {
58
+ it('logs the platform manual and the meta-tools as hexis capabilities, by bare name', () => {
59
+ expect(classifyToolCall(`${KB}.write_file`, { body: { path: 'x' } }, ctx, null)).toEqual({
60
+ kind: 'capability',
61
+ manual: null,
62
+ name: 'write_file',
63
+ });
64
+ expect(classifyToolCall('call_tool_chain', { code: 'x' }, ctx, null)).toEqual({
65
+ kind: 'capability',
66
+ manual: null,
67
+ name: 'call_tool_chain',
68
+ });
69
+ });
70
+
71
+ it("logs another manual's tool as a tool under its catalog name", () => {
72
+ expect(classifyToolCall('my_server.search', { q: 'x' }, ctx, null)).toEqual({
73
+ kind: 'tool',
74
+ manual: 'my-server',
75
+ name: 'search',
76
+ });
77
+ // An http `.tool` manual has no rewrite, so its registered name is the catalog name.
78
+ expect(classifyToolCall('hubspot.search_contacts', {}, ctx, null)).toEqual({
79
+ kind: 'tool',
80
+ manual: 'hubspot',
81
+ name: 'search_contacts',
82
+ });
83
+ });
84
+
85
+ it('logs get_skill as a skill read, with the folder when the catalog knows it', () => {
86
+ expect(classifyToolCall(`${KB}.get_skill`, { body: { name: 'rfi' } }, ctx, skills)).toEqual({
87
+ kind: 'skill',
88
+ manual: 'Plugins/Sales/rfi',
89
+ name: 'rfi',
90
+ });
91
+ expect(classifyToolCall(`${KB}.get_skill`, { name: 'unknown' }, ctx, skills)).toEqual({
92
+ kind: 'skill',
93
+ manual: null,
94
+ name: 'unknown',
95
+ });
96
+ });
97
+
98
+ it('logs a platform read inside a skill folder as that skill, and elsewhere as the read', () => {
99
+ expect(classifyToolCall(`${KB}.read_file`, { body: { path: 'Plugins/Sales/rfi/SKILL.md' } }, ctx, skills)).toEqual({
100
+ kind: 'skill',
101
+ manual: 'Plugins/Sales/rfi',
102
+ name: 'rfi',
103
+ });
104
+ expect(classifyToolCall(`${KB}.list_files`, { body: { path: 'Skills/Engineering/deploy-checklist' } }, ctx, skills)).toEqual({
105
+ kind: 'skill',
106
+ manual: 'Skills/Engineering/deploy-checklist',
107
+ name: 'deploy-checklist',
108
+ });
109
+ expect(classifyToolCall(`${KB}.read_file`, { body: { path: 'KnowledgeBase/Product/roadmap.md' } }, ctx, skills)).toEqual({
110
+ kind: 'capability',
111
+ manual: null,
112
+ name: 'read_file',
113
+ });
114
+ // No catalog (the fetch failed): the honest fallback is the read itself.
115
+ expect(classifyToolCall(`${KB}.read_file`, { body: { path: 'Plugins/Sales/rfi/SKILL.md' } }, ctx, null)).toEqual({
116
+ kind: 'capability',
117
+ manual: null,
118
+ name: 'read_file',
119
+ });
120
+ });
121
+ });
@@ -0,0 +1,316 @@
1
+ import { and, asc, count, desc, eq, isNull, lt, or, type SQL } from 'drizzle-orm';
2
+ import { logger } from '../../shared/logging.js';
3
+ import type { Database } from '../database/connection.js';
4
+ import { agentConnections, agentEvents, oauthTokens, users } from '../database/schema.js';
5
+ import type { IExternalApiKeyService } from '../tool-auth/external-api-key.interface.js';
6
+ import {
7
+ AuditPrincipalNotFoundError,
8
+ InvalidCursorError,
9
+ isUuid,
10
+ parseRetentionWindow,
11
+ type AgentEventInput,
12
+ type AgentEventPage,
13
+ type AgentEventView,
14
+ type AuditPrincipal,
15
+ type AuditPrincipalRef,
16
+ type AuditScope,
17
+ type IAgentAuditService,
18
+ type IAgentEventRecorder,
19
+ } from './audit.contract.js';
20
+
21
+ const log = logger('audit');
22
+
23
+ /** The most events one page may carry; the routes clamp to it. */
24
+ export const MAX_EVENT_PAGE = 200;
25
+
26
+ /** How often, at most, one process sweeps events past the retention window. */
27
+ const PRUNE_INTERVAL_MS = 60 * 60_000;
28
+
29
+ /**
30
+ * The Audit log: the write half the MCP proxy records through, and the read
31
+ * and revoke half its page is built on.
32
+ *
33
+ * Writes are fire-and-forget by contract — a tool result must never wait on,
34
+ * or fail over, its own bookkeeping. Retention is enforced opportunistically
35
+ * on the write path (one sweep per process per hour, piggybacked on an
36
+ * insert), the same way the OAuth tables prune themselves on mint: no
37
+ * scheduler, and a deployment that records nothing has nothing to sweep.
38
+ *
39
+ * Connection keys are read through the key service rather than joined here,
40
+ * so their summary shape (kind, revoked-by, …) has exactly one definition.
41
+ */
42
+ export class AgentAuditService implements IAgentAuditService, IAgentEventRecorder {
43
+ private lastPruneAt = 0;
44
+
45
+ constructor(
46
+ private readonly db: Database,
47
+ private readonly keys: Pick<IExternalApiKeyService, 'listForUser' | 'listForDeployment' | 'ownerOf'>,
48
+ /** Read per sweep, so a changed setting applies without a restart; null = keep forever. */
49
+ private readonly retentionDays: () => number | null,
50
+ private readonly now: () => number = Date.now,
51
+ ) {}
52
+
53
+ record(event: AgentEventInput): void {
54
+ this.db
55
+ .insert(agentEvents)
56
+ .values({
57
+ userId: event.userId,
58
+ keyId: event.principal.kind === 'key' ? event.principal.id : null,
59
+ connectionId: event.principal.kind === 'agent' ? event.principal.id : null,
60
+ kind: event.kind,
61
+ manual: event.manual,
62
+ name: event.name,
63
+ outcome: event.outcome,
64
+ durationMs: event.durationMs,
65
+ at: new Date(this.now()),
66
+ })
67
+ .then(
68
+ () => this.maybePrune(),
69
+ (err) => log.warn('recording an agent event failed:', { err }),
70
+ );
71
+ }
72
+
73
+ /**
74
+ * Sweep events older than the retention window — at most once per hour per
75
+ * process, best-effort, never awaited by a caller. A deployment that keeps
76
+ * events forever sweeps nothing.
77
+ */
78
+ private async maybePrune(): Promise<void> {
79
+ const now = this.now();
80
+ if (now - this.lastPruneAt < PRUNE_INTERVAL_MS) return;
81
+ this.lastPruneAt = now;
82
+ const days = this.retentionDays();
83
+ if (days === null) return;
84
+ const cutoff = new Date(now - days * 24 * 60 * 60_000);
85
+ try {
86
+ await this.db.delete(agentEvents).where(lt(agentEvents.at, cutoff));
87
+ } catch (err) {
88
+ log.warn('agent-event prune failed (non-fatal):', { err });
89
+ }
90
+ }
91
+
92
+ async listPrincipals(scope: AuditScope): Promise<AuditPrincipal[]> {
93
+ const mine = scope === 'all' ? null : scope.userId;
94
+ const [keyRows, connectionRows, countRows] = await Promise.all([
95
+ mine === null ? this.keys.listForDeployment() : this.keysForUser(mine),
96
+ this.db
97
+ .select({
98
+ connection: agentConnections,
99
+ user: { id: users.id, email: users.email, name: users.name },
100
+ })
101
+ .from(agentConnections)
102
+ .innerJoin(users, eq(agentConnections.userId, users.id))
103
+ .where(mine === null ? undefined : eq(agentConnections.userId, mine))
104
+ .orderBy(asc(users.email), desc(agentConnections.connectedAt)),
105
+ this.db
106
+ .select({ keyId: agentEvents.keyId, connectionId: agentEvents.connectionId, n: count() })
107
+ .from(agentEvents)
108
+ .where(mine === null ? undefined : eq(agentEvents.userId, mine))
109
+ .groupBy(agentEvents.keyId, agentEvents.connectionId),
110
+ ]);
111
+
112
+ const counts = new Map<string, number>();
113
+ for (const row of countRows) {
114
+ const id = row.keyId ?? row.connectionId;
115
+ if (id) counts.set(id, Number(row.n));
116
+ }
117
+
118
+ const principals: AuditPrincipal[] = [
119
+ ...keyRows.map((k) => ({
120
+ kind: 'key' as const,
121
+ id: k.id,
122
+ label: k.label,
123
+ keyKind: k.kind,
124
+ createdAt: k.createdAt,
125
+ lastUsedAt: k.lastUsedAt,
126
+ revokedAt: k.revokedAt,
127
+ revokedBy: k.revokedBy,
128
+ deletedAt: k.deletedAt,
129
+ eventCount: counts.get(k.id) ?? 0,
130
+ user: k.user,
131
+ })),
132
+ ...connectionRows.map(({ connection: c, user }) => ({
133
+ kind: 'agent' as const,
134
+ id: c.id,
135
+ label: c.clientName ?? 'Unnamed agent',
136
+ createdAt: c.connectedAt.getTime(),
137
+ lastUsedAt: c.lastUsedAt ? c.lastUsedAt.getTime() : null,
138
+ revokedAt: c.revokedAt ? c.revokedAt.getTime() : null,
139
+ revokedBy: (c.revokedBy as 'owner' | 'admin' | null) ?? null,
140
+ eventCount: counts.get(c.id) ?? 0,
141
+ user,
142
+ })),
143
+ ];
144
+ // Per account (by email), live before revoked, most recently used first,
145
+ // newest first among the never-used — the order the page shows without
146
+ // re-sorting, and the one the Connection keys overview had.
147
+ principals.sort((a, b) => {
148
+ const byEmail = a.user.email.localeCompare(b.user.email);
149
+ if (byEmail !== 0) return byEmail;
150
+ const aRevoked = a.revokedAt !== null;
151
+ const bRevoked = b.revokedAt !== null;
152
+ if (aRevoked !== bRevoked) return aRevoked ? 1 : -1;
153
+ const byUse = (b.lastUsedAt ?? 0) - (a.lastUsedAt ?? 0);
154
+ return byUse !== 0 ? byUse : b.createdAt - a.createdAt;
155
+ });
156
+ return principals;
157
+ }
158
+
159
+ /** One person's keys, with the owner attached the way the deployment listing attaches it. */
160
+ private async keysForUser(userId: string) {
161
+ const [keys, [user]] = await Promise.all([
162
+ this.keys.listForUser(userId),
163
+ this.db
164
+ .select({ id: users.id, email: users.email, name: users.name })
165
+ .from(users)
166
+ .where(eq(users.id, userId))
167
+ .limit(1),
168
+ ]);
169
+ if (!user) return [];
170
+ return keys.map((k) => ({ ...k, user }));
171
+ }
172
+
173
+ async ownerOf(principal: AuditPrincipalRef): Promise<string | null> {
174
+ if (principal.kind === 'agent') {
175
+ const [row] = await this.db
176
+ .select({ userId: agentConnections.userId })
177
+ .from(agentConnections)
178
+ .where(eq(agentConnections.id, principal.id))
179
+ .limit(1);
180
+ return row?.userId ?? null;
181
+ }
182
+ // A key is the key service's to answer for, like every other read of one.
183
+ return this.keys.ownerOf(principal.id);
184
+ }
185
+
186
+ async listEvents(
187
+ principal: AuditPrincipalRef,
188
+ page: { before?: string; limit: number },
189
+ ): Promise<AgentEventPage> {
190
+ const limit = Math.max(1, Math.min(MAX_EVENT_PAGE, Math.floor(page.limit)));
191
+ const byPrincipal =
192
+ principal.kind === 'key'
193
+ ? eq(agentEvents.keyId, principal.id)
194
+ : eq(agentEvents.connectionId, principal.id);
195
+ // Keyset on (at, id): a page boundary between two events at the same
196
+ // instant is still a boundary, and a row inserted while the reader pages
197
+ // never shifts what the next page returns.
198
+ const cursor = page.before ? parseCursor(page.before) : null;
199
+ if (page.before && !cursor) throw new InvalidCursorError();
200
+ const after: SQL | undefined = cursor
201
+ ? or(
202
+ lt(agentEvents.at, cursor.at),
203
+ and(eq(agentEvents.at, cursor.at), lt(agentEvents.id, cursor.id)),
204
+ )
205
+ : undefined;
206
+ // The total is counted on the FIRST page only: a reader paging back
207
+ // through a busy principal's history would otherwise pay a full count of
208
+ // the same number on every step, for a figure the page already holds.
209
+ const [rows, totals] = await Promise.all([
210
+ this.db
211
+ .select({
212
+ id: agentEvents.id,
213
+ kind: agentEvents.kind,
214
+ manual: agentEvents.manual,
215
+ name: agentEvents.name,
216
+ outcome: agentEvents.outcome,
217
+ at: agentEvents.at,
218
+ })
219
+ .from(agentEvents)
220
+ .where(and(byPrincipal, after))
221
+ .orderBy(desc(agentEvents.at), desc(agentEvents.id))
222
+ .limit(limit + 1),
223
+ cursor ? null : this.db.select({ total: count() }).from(agentEvents).where(byPrincipal),
224
+ ]);
225
+ const hasMore = rows.length > limit;
226
+ const pageRows = hasMore ? rows.slice(0, limit) : rows;
227
+ const events: AgentEventView[] = pageRows.map((r) => ({
228
+ id: r.id,
229
+ kind: r.kind as AgentEventView['kind'],
230
+ manual: r.manual,
231
+ name: r.name,
232
+ outcome: r.outcome as AgentEventView['outcome'],
233
+ at: r.at.getTime(),
234
+ }));
235
+ const last = pageRows[pageRows.length - 1];
236
+ return {
237
+ events,
238
+ total: totals ? Number(totals[0]?.total ?? 0) : null,
239
+ nextCursor: hasMore && last ? formatCursor(last.at, last.id) : null,
240
+ };
241
+ }
242
+
243
+ async revokeConnection(id: string, by: 'owner' | 'admin', ownerUserId?: string): Promise<void> {
244
+ const scope = ownerUserId
245
+ ? and(eq(agentConnections.id, id), eq(agentConnections.userId, ownerUserId))!
246
+ : eq(agentConnections.id, id);
247
+ await this.db.transaction(async (tx) => {
248
+ const revoked = await tx
249
+ .update(agentConnections)
250
+ .set({ revokedAt: new Date(this.now()), revokedBy: by })
251
+ .where(and(scope, isNull(agentConnections.revokedAt)))
252
+ .returning({ id: agentConnections.id });
253
+ if (revoked.length === 0) {
254
+ // Already revoked stays idempotent; out of scope or unknown throws —
255
+ // the same split `ExternalApiKeyService.markRevoked` makes.
256
+ const [existing] = await tx
257
+ .select({ id: agentConnections.id })
258
+ .from(agentConnections)
259
+ .where(scope)
260
+ .limit(1);
261
+ if (!existing) throw new AuditPrincipalNotFoundError();
262
+ return;
263
+ }
264
+ // Every live token of the connection, access and refresh alike: the
265
+ // agent's next request 401s, its refresh fails, and re-authorizing —
266
+ // through the browser, as a person — is the only way back in.
267
+ await tx
268
+ .update(oauthTokens)
269
+ .set({ revokedAt: new Date(this.now()) })
270
+ .where(and(eq(oauthTokens.connectionId, id), isNull(oauthTokens.revokedAt)));
271
+ });
272
+ }
273
+ }
274
+
275
+ /** `<epoch ms>.<uuid>` — the page's opaque-enough cursor. */
276
+ function formatCursor(at: Date, id: string): string {
277
+ return `${at.getTime()}.${id}`;
278
+ }
279
+
280
+ /**
281
+ * The cursor back into its parts, or null for anything this service did not
282
+ * issue: the id must be a uuid (the column is one, and Postgres refuses to
283
+ * compare it with anything else) and the instant a whole number of epoch
284
+ * milliseconds a `timestamp` can hold.
285
+ */
286
+ function parseCursor(raw: string): { at: Date; id: string } | null {
287
+ const dot = raw.indexOf('.');
288
+ if (dot < 0) return null;
289
+ const msText = raw.slice(0, dot);
290
+ const id = raw.slice(dot + 1);
291
+ if (!/^\d{1,15}$/.test(msText) || !isUuid(id)) return null;
292
+ return { at: new Date(Number(msText)), id };
293
+ }
294
+
295
+ /** The last invalid setting value warned about, so a standing misconfiguration is said once, not once per prune. */
296
+ let warnedInvalidRetention: string | null = null;
297
+
298
+ /**
299
+ * The retention window the service runs on, in days — or null to keep
300
+ * events forever, which is what a blank, zero or negative setting means. A
301
+ * value that is not a window at all is kept-forever too, said out loud once:
302
+ * the Deployment page shows an environment value as the one in effect and
303
+ * would otherwise be the only place claiming a window nobody is keeping.
304
+ */
305
+ export function retentionDaysFrom(raw: string): number | null {
306
+ const window = parseRetentionWindow(raw);
307
+ if (window === 'forever') return null;
308
+ if (window !== null) return window.days;
309
+ if (raw !== warnedInvalidRetention) {
310
+ warnedInvalidRetention = raw;
311
+ log.warn(
312
+ `auditRetentionDays is "${raw}", which is not a whole number of days — keeping events forever until it is fixed.`,
313
+ );
314
+ }
315
+ return null;
316
+ }
@@ -0,0 +1,83 @@
1
+ import type { RequestHandler } from 'express';
2
+ import { logger } from '../../shared/logging.js';
3
+ import type { IAgentEventRecorder } from './audit.contract.js';
4
+ import { classifyToolCall, skillReadPath, type SkillFolder } from './event-classifier.js';
5
+ import '../tool-auth/tool-auth.middleware.js'; // Express Request augmentation (req.toolAuth)
6
+
7
+ const log = logger('audit');
8
+
9
+ export interface AgentRestAuditDeps {
10
+ recorder: IAgentEventRecorder;
11
+ /** The registered name of the platform's own manual (`KNOWLEDGE_BASE`). */
12
+ kbManualName: string;
13
+ /** The caller's skill catalog, for telling a skill read from a file read; fetched only when a read names a path. */
14
+ skillFolders: (userId: string) => Promise<readonly SkillFolder[]>;
15
+ }
16
+
17
+ /**
18
+ * Records the REST tool calls the LOCAL server makes directly — the ones that
19
+ * never pass through the hosted MCP endpoint, where every other call an agent
20
+ * makes is recorded.
21
+ *
22
+ * hexis-mcp reaches the deployment two ways. Tool calls go through the
23
+ * hosted `/api/mcp` as its remote manual, and the proxy records them there.
24
+ * But the skill catalog and a skill's body are read straight off the REST
25
+ * surface (`list_skills`, `get_skill`, `list_local_tools`, …) with the
26
+ * internal token the server exchanged its grant for — so a person loading a
27
+ * skill as a slash command in Claude Code through the local server left no
28
+ * `skill` event, while the same read through the hosted endpoint did.
29
+ *
30
+ * WHICH calls are recorded here is decided by the credential, not the route:
31
+ * only an `externalProxy` token that names an agent connection — the
32
+ * exchanged grant — is recorded. The hosted proxy's own loopback tokens name
33
+ * none, so a call the proxy has already recorded is never counted twice;
34
+ * and a connection key reaching REST directly is indistinguishable from the
35
+ * proxy passing that same key through, so keys stay recorded at the proxy
36
+ * alone. The rule is the credential's shape, which no caller chooses.
37
+ *
38
+ * Mounted in front of every `/agent/tools/:name` route and judging on
39
+ * `finish`, when the route's own auth has run and the status is known: a 2xx
40
+ * is `ok`, anything else `error`. Never on the tool's critical path — the
41
+ * classification (and the skill catalog it may need) runs after the answer
42
+ * has gone out.
43
+ */
44
+ export function createAgentRestAuditMiddleware(deps: AgentRestAuditDeps): RequestHandler {
45
+ return (req, res, next) => {
46
+ const started = performance.now();
47
+ // Read NOW: `req.params` is rewritten for each layer Express matches, and
48
+ // by `finish` it is the route's own (empty) set, not this mount's.
49
+ const name = String(req.params.name ?? '');
50
+ res.on('finish', () => {
51
+ const auth = req.toolAuth;
52
+ if (!auth || auth.source !== 'external' || !auth.connectionId) return;
53
+ if (!name) return;
54
+ const durationMs = Math.max(0, Math.round(performance.now() - started));
55
+ const outcome = res.statusCode < 400 ? 'ok' : 'error';
56
+ const args = (req.body && typeof req.body === 'object' ? req.body : {}) as Record<string, unknown>;
57
+ const utcpName = `${deps.kbManualName}.${name}`;
58
+ const ctx = { kbManualName: deps.kbManualName, catalogNames: new Map<string, string>() };
59
+ const record = (skills: readonly SkillFolder[] | null) => {
60
+ try {
61
+ deps.recorder.record({
62
+ userId: auth.userId,
63
+ principal: { kind: 'agent', id: auth.connectionId! },
64
+ ...classifyToolCall(utcpName, args, ctx, skills),
65
+ outcome,
66
+ durationMs,
67
+ });
68
+ } catch (err) {
69
+ log.warn('recording a REST agent event failed:', { err });
70
+ }
71
+ };
72
+ if (skillReadPath(utcpName, args, deps.kbManualName) === null) {
73
+ record(null);
74
+ return;
75
+ }
76
+ deps.skillFolders(auth.userId).then(record, (err) => {
77
+ log.warn('skill catalog unavailable for audit classification:', { err });
78
+ record(null);
79
+ });
80
+ });
81
+ next();
82
+ };
83
+ }
@@ -0,0 +1,164 @@
1
+ /**
2
+ * The Audit log's contracts: what an external agent's activity is recorded
3
+ * as, who a recorded call is attributed to, and the two services around
4
+ * them — the recorder the MCP proxy writes through, and the read/revoke
5
+ * service the Audit log page is built on.
6
+ */
7
+
8
+ declare global {
9
+ // eslint-disable-next-line @typescript-eslint/no-namespace
10
+ namespace Express {
11
+ interface Request {
12
+ /**
13
+ * The agent connection (`agent_connections.id`) an OAuth-authenticated
14
+ * MCP request arrived through — bound by the MCP auth middleware from
15
+ * the access token, or from the `connectionId` claim of the internal
16
+ * token the local server exchanged its grant for. Unset for connection
17
+ * keys (those carry `externalApiKeyId`) and for browser sessions.
18
+ */
19
+ agentConnectionId?: string;
20
+ }
21
+ }
22
+ }
23
+
24
+ /** What was called: the platform's own tool, a manual's tool, or a skill read. */
25
+ export type AgentEventKind = 'capability' | 'tool' | 'skill';
26
+
27
+ /** How the call ended. `denied`: the caller's sign-in for the tool was missing, so nothing ran. */
28
+ export type AgentEventOutcome = 'ok' | 'error' | 'denied';
29
+
30
+ /**
31
+ * Who a call is attributed to: the connection key it was authenticated with,
32
+ * or the agent connection behind its OAuth grant. Exactly one.
33
+ */
34
+ export type AuditPrincipalRef = { kind: 'key'; id: string } | { kind: 'agent'; id: string };
35
+
36
+ /** One recorded call, as the recorder takes it. */
37
+ export interface AgentEventInput {
38
+ userId: string;
39
+ principal: AuditPrincipalRef;
40
+ kind: AgentEventKind;
41
+ /** The MCP server / `.tool` manual for a tool, the skill folder for a skill; null for a capability. */
42
+ manual: string | null;
43
+ name: string;
44
+ outcome: AgentEventOutcome;
45
+ durationMs: number | null;
46
+ }
47
+
48
+ /**
49
+ * The write half. `record` never throws and never blocks the call it
50
+ * describes: a recording failure is logged and the tool result still goes
51
+ * back to the agent.
52
+ */
53
+ export interface IAgentEventRecorder {
54
+ record(event: AgentEventInput): void;
55
+ }
56
+
57
+ /** One row of the Audit log: an agent connection or a connection key, with its owner. */
58
+ export interface AuditPrincipal {
59
+ kind: 'key' | 'agent';
60
+ id: string;
61
+ /** The key's label, or the agent's registered client name. */
62
+ label: string;
63
+ /**
64
+ * For a key: what it was minted as (`key` by hand, `github-link` for a
65
+ * Claude link). Absent for an agent.
66
+ */
67
+ keyKind?: string;
68
+ /** When the key was created / the agent connected. Epoch ms. */
69
+ createdAt: number;
70
+ lastUsedAt: number | null;
71
+ revokedAt: number | null;
72
+ /** Who ended it, once revoked: the owner, or an admin. */
73
+ revokedBy: 'owner' | 'admin' | null;
74
+ /** For a key: when its owner deleted it for good. Such rows reach admins only. */
75
+ deletedAt?: number | null;
76
+ /** Events currently on record for it (within the retention window). */
77
+ eventCount: number;
78
+ user: { id: string; email: string; name: string };
79
+ }
80
+
81
+ /** One event as the page reads it. */
82
+ export interface AgentEventView {
83
+ id: string;
84
+ kind: AgentEventKind;
85
+ manual: string | null;
86
+ name: string;
87
+ outcome: AgentEventOutcome;
88
+ at: number;
89
+ }
90
+
91
+ export interface AgentEventPage {
92
+ events: AgentEventView[];
93
+ /**
94
+ * Every event on record for the principal, not just this page — counted
95
+ * on the first page only; null on a page reached through a cursor, since
96
+ * the reader already holds the figure.
97
+ */
98
+ total: number | null;
99
+ /** Pass back as `before` to load the next (older) page; null when this was the last. */
100
+ nextCursor: string | null;
101
+ }
102
+
103
+ /** Whose rows: one person's, or the whole deployment's (admins). */
104
+ export type AuditScope = { userId: string } | 'all';
105
+
106
+ export interface IAgentAuditService {
107
+ listPrincipals(scope: AuditScope): Promise<AuditPrincipal[]>;
108
+ /** The account a principal belongs to, or null when there is no such principal. The routes' ownership check. */
109
+ ownerOf(principal: AuditPrincipalRef): Promise<string | null>;
110
+ listEvents(
111
+ principal: AuditPrincipalRef,
112
+ page: { before?: string; limit: number },
113
+ ): Promise<AgentEventPage>;
114
+ /**
115
+ * Cut an agent off: mark its connection revoked and revoke every live
116
+ * token it holds, so its next request fails and its refresh fails with it.
117
+ * `ownerUserId` scopes the revoke to the person's own connections; an admin
118
+ * passes none. Idempotent on an already-revoked connection; throws
119
+ * {@link AuditPrincipalNotFoundError} when nothing matches.
120
+ */
121
+ revokeConnection(id: string, by: 'owner' | 'admin', ownerUserId?: string): Promise<void>;
122
+ }
123
+
124
+ export class AuditPrincipalNotFoundError extends Error {
125
+ constructor() {
126
+ super('No such agent or key');
127
+ this.name = 'AuditPrincipalNotFoundError';
128
+ }
129
+ }
130
+
131
+ /** A `before` cursor that is not one this service issued — the caller's mistake, answered as such. */
132
+ export class InvalidCursorError extends Error {
133
+ constructor() {
134
+ super('Invalid cursor');
135
+ this.name = 'InvalidCursorError';
136
+ }
137
+ }
138
+
139
+ /** Shape of the id columns (any uuid version; case-insensitive). */
140
+ const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
141
+
142
+ export function isUuid(value: string): boolean {
143
+ return UUID_RE.test(value);
144
+ }
145
+
146
+ /**
147
+ * The retention window's one rule, shared by the setting's validator and the
148
+ * runtime reader. A positive whole number of days is the window; blank,
149
+ * zero or a negative number is "keep forever" — the deployment's choice,
150
+ * made the same way whether typed on the Deployment page or set through
151
+ * `AUDIT_RETENTION_DAYS`. Anything else is not a window at all: the
152
+ * validator refuses the save, and the reader, which cannot refuse, keeps
153
+ * everything and says so.
154
+ */
155
+ export type RetentionWindow = { days: number } | 'forever';
156
+
157
+ /** The window a retention setting names, or null when it names none this rule accepts. */
158
+ export function parseRetentionWindow(raw: string): RetentionWindow | null {
159
+ const trimmed = raw.trim();
160
+ if (trimmed === '') return 'forever';
161
+ if (!/^-?\d+$/.test(trimmed)) return null;
162
+ const n = Number(trimmed);
163
+ return n > 0 ? { days: n } : 'forever';
164
+ }