@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,261 @@
1
+ import express, { type Express, type Request } from 'express';
2
+ import path from 'node:path';
3
+ import { isIP } from 'node:net';
4
+ import type { ProcessConfig } from '../core-config.js';
5
+ import { GIT_SHA } from '../version.js';
6
+ import { logger } from '../shared/logging.js';
7
+ import { TenantRuntime, type TenantRuntimeDeps } from './tenant-runtime.js';
8
+ import { TENANT_SLUG_PATTERN, normalizeHost, type TenantDescriptor, type TenantSource } from './tenant-source.contract.js';
9
+
10
+ const log = logger('tenancy');
11
+
12
+ /**
13
+ * The path prefix under which a process reaches ONE of its own tenants over
14
+ * loopback: `http://127.0.0.1:<port>/_tenant/<slug>/api/...`. The MCP proxy
15
+ * and the UTCP manuals it seeds dial the tenant's own REST surface this way,
16
+ * because a loopback request carries no tenant host name and a header cannot
17
+ * ride a UTCP call (the proxy is a passthrough; it reshapes nothing).
18
+ *
19
+ * The host honours the prefix only for a request that came from this
20
+ * machine AND was forwarded by nobody: the socket peer is loopback and there
21
+ * is no `X-Forwarded-For`. A reverse proxy on the same host (nginx, a
22
+ * Coolify proxy) delivers every public request from a loopback socket, and
23
+ * every such proxy adds that header; the process's own dial never does.
24
+ * What the prefix could grant anyone who got past this is only what the
25
+ * tenant's host name grants already — sessions, keys and tokens are per
26
+ * tenant — but the addressing rule is stated so it can be relied on.
27
+ */
28
+ export const LOOPBACK_TENANT_PREFIX = '/_tenant';
29
+
30
+ /** The base URL a tenant's graph dials itself at — see {@link LOOPBACK_TENANT_PREFIX}. */
31
+ export function loopbackTenantBaseUrl(port: number, slug: string): string {
32
+ return `http://127.0.0.1:${port}${LOOPBACK_TENANT_PREFIX}/${slug}`;
33
+ }
34
+
35
+ /** Whether `address` is this machine talking to itself. */
36
+ export function isLoopbackAddress(address: string | undefined): boolean {
37
+ if (!address) return false;
38
+ const bare = address.startsWith('::ffff:') ? address.slice('::ffff:'.length) : address;
39
+ if (bare === '::1') return true;
40
+ return isIP(bare) === 4 && bare.startsWith('127.');
41
+ }
42
+
43
+ /** How a request names its tenant: by the loopback prefix, or by its host. */
44
+ export type TenantSelector = { kind: 'slug'; slug: string; rest: string } | { kind: 'host'; host: string };
45
+
46
+ /**
47
+ * Which tenant a request is for. The loopback prefix wins, but only from a
48
+ * loopback peer that no proxy forwarded (no `X-Forwarded-For`); everything
49
+ * else is decided by the host name (the `X-Forwarded-Host` a trusted proxy
50
+ * set, else `Host`), lowercase and without its port.
51
+ */
52
+ export function selectTenant(req: {
53
+ hostname: string;
54
+ url: string;
55
+ peer: string | undefined;
56
+ forwardedFor?: string | string[] | undefined;
57
+ }): TenantSelector {
58
+ const forwarded = Array.isArray(req.forwardedFor) ? req.forwardedFor.length > 0 : Boolean(req.forwardedFor);
59
+ if (isLoopbackAddress(req.peer) && !forwarded && req.url.startsWith(`${LOOPBACK_TENANT_PREFIX}/`)) {
60
+ const afterPrefix = req.url.slice(LOOPBACK_TENANT_PREFIX.length + 1);
61
+ const end = afterPrefix.search(/[/?#]/);
62
+ const slug = end === -1 ? afterPrefix : afterPrefix.slice(0, end);
63
+ if (TENANT_SLUG_PATTERN.test(slug)) {
64
+ const rest = end === -1 ? '/' : afterPrefix.slice(end).replace(/^(?=[?#])/, '/');
65
+ return { kind: 'slug', slug, rest };
66
+ }
67
+ }
68
+ return { kind: 'host', host: normalizeHost(req.hostname || '') };
69
+ }
70
+
71
+ export interface TenantHostOptions {
72
+ source: TenantSource;
73
+ process: ProcessConfig;
74
+ /** The built SPA, served once for every resolved tenant. */
75
+ staticDir?: string;
76
+ /** Minutes without a request after which a tenant's graph is stopped. Default 30; 0 never evicts. */
77
+ idleMinutes?: number;
78
+ /** How long a request waits for an activation in flight before answering 503. Default 60s. */
79
+ activationWaitMs?: number;
80
+ /** Seams for the runtimes the host builds — a suite's fake graphs. */
81
+ runtime?: TenantRuntimeDeps;
82
+ /** How often idle tenants are looked for. Default: once a minute. */
83
+ sweepIntervalMs?: number;
84
+ }
85
+
86
+ export interface TenantHost {
87
+ /** The app the process listens on. */
88
+ app: Express;
89
+ /** The runtimes built so far, by slug. */
90
+ runtimes(): ReadonlyMap<string, TenantRuntime>;
91
+ /** Stop every active tenant; the host keeps serving and reactivates on demand. */
92
+ evictAll(): Promise<void>;
93
+ /** Stop the idle sweep and every tenant: the process's shutdown. */
94
+ stop(): Promise<void>;
95
+ }
96
+
97
+ const DEFAULT_ACTIVATION_WAIT_MS = 60_000;
98
+ const DEFAULT_IDLE_MINUTES = 30;
99
+ const DEFAULT_SWEEP_INTERVAL_MS = 60_000;
100
+
101
+ /** `promise`, or `null` once `ms` have passed. */
102
+ function within<T>(promise: Promise<T>, ms: number): Promise<T | null> {
103
+ let timer: NodeJS.Timeout | undefined;
104
+ const late = new Promise<null>((resolve) => {
105
+ timer = setTimeout(() => resolve(null), ms);
106
+ });
107
+ return Promise.race([promise, late]).finally(() => clearTimeout(timer));
108
+ }
109
+
110
+ /**
111
+ * One Express app in front of many tenants' apps. It answers process health
112
+ * itself, resolves each request to a tenant (see {@link selectTenant}),
113
+ * activates that tenant's graph on first use, hands the request to the
114
+ * tenant's app, and serves the SPA for whatever the tenant's app leaves
115
+ * unhandled. Nothing below it knows there are other tenants: each graph was
116
+ * built by the same composition root a single-tenant deployment uses.
117
+ */
118
+ export function createTenantHost(opts: TenantHostOptions): TenantHost {
119
+ const runtimes = new Map<string, TenantRuntime>();
120
+ const activationWaitMs = opts.activationWaitMs ?? DEFAULT_ACTIVATION_WAIT_MS;
121
+ const idleMs = (opts.idleMinutes ?? DEFAULT_IDLE_MINUTES) * 60_000;
122
+
123
+ const runtimeFor = (descriptor: TenantDescriptor): TenantRuntime => {
124
+ let runtime = runtimes.get(descriptor.slug);
125
+ if (!runtime) {
126
+ runtime = new TenantRuntime(descriptor, opts.runtime);
127
+ runtimes.set(descriptor.slug, runtime);
128
+ }
129
+ return runtime;
130
+ };
131
+
132
+ const app = express();
133
+ // Forwarded headers are honoured exactly as a single-tenant deployment
134
+ // honours them, and for the same reason: `req.hostname` is what picks the
135
+ // tenant, and behind a proxy it lives in `X-Forwarded-Host`.
136
+ if (opts.process.trustProxy) {
137
+ const raw = opts.process.trustProxy;
138
+ app.set('trust proxy', /^\d+$/.test(raw) ? Number(raw) : raw);
139
+ }
140
+
141
+ // The process's own health, before any tenant is involved: a load balancer
142
+ // asks with whatever host name it likes, and a process with no active
143
+ // tenant is still a healthy process.
144
+ app.get('/api/health', (_req, res) => {
145
+ res.json({ status: 'ok', sha: GIT_SHA, timestamp: Date.now(), tenants: runtimes.size });
146
+ });
147
+
148
+ app.use(async (req: Request, res, next) => {
149
+ const selector = selectTenant({
150
+ hostname: req.hostname,
151
+ url: req.url,
152
+ peer: req.socket.remoteAddress,
153
+ forwardedFor: req.headers['x-forwarded-for'],
154
+ });
155
+ let descriptor: TenantDescriptor | null;
156
+ try {
157
+ descriptor =
158
+ selector.kind === 'slug'
159
+ ? await opts.source.describe(selector.slug)
160
+ : await opts.source.resolveByHost(selector.host);
161
+ } catch (err) {
162
+ log.error('tenant lookup failed:', { err });
163
+ res.status(503).set('Retry-After', '5').json({ error: 'Tenant lookup failed' });
164
+ return;
165
+ }
166
+ if (!descriptor) {
167
+ if (req.path.startsWith('/api/') || req.path.startsWith(LOOPBACK_TENANT_PREFIX)) {
168
+ res.status(404).json({ error: 'No workspace at this address' });
169
+ } else {
170
+ res.status(404).type('text/plain').send('No workspace at this address.');
171
+ }
172
+ return;
173
+ }
174
+ if (selector.kind === 'slug') req.url = selector.rest;
175
+
176
+ const runtime = runtimeFor(descriptor);
177
+ // Counted from here, before the graph is even asked for, until the
178
+ // response closes however it ends — a 503 below included. An open
179
+ // response is what keeps a tenant from being evicted from under it.
180
+ // Left exactly once: a client that dropped during the tenant lookup
181
+ // above has had its `close` already, and that event will not come
182
+ // again, so the socket is asked directly; a socket destroyed but not
183
+ // yet closed would otherwise be left twice, once here and once by the
184
+ // listener, taking another request's count with it.
185
+ runtime.enter();
186
+ let left = false;
187
+ const leave = () => {
188
+ if (left) return;
189
+ left = true;
190
+ runtime.leave();
191
+ };
192
+ res.on('close', leave);
193
+ if (req.socket.destroyed) {
194
+ leave();
195
+ return;
196
+ }
197
+ let graph: Awaited<ReturnType<TenantRuntime['handle']>> | null;
198
+ try {
199
+ graph = await within(runtime.handle(), activationWaitMs);
200
+ } catch {
201
+ // Logged by the runtime; the caller learns only that it may try again.
202
+ res.status(503).set('Retry-After', '5').json({ error: 'This workspace could not be started; try again shortly' });
203
+ return;
204
+ }
205
+ if (!graph) {
206
+ res.status(503).set('Retry-After', '5').json({ error: 'This workspace is starting; try again shortly' });
207
+ return;
208
+ }
209
+ graph.app(req, res, next);
210
+ });
211
+
212
+ // Whatever a tenant's app left unhandled: the SPA, with the same rule a
213
+ // single-tenant deployment applies to the namespaces that must never
214
+ // resolve to `index.html` (see `createCoreServer`).
215
+ if (opts.staticDir) {
216
+ const frontendDist = opts.staticDir;
217
+ app.use(express.static(frontendDist));
218
+ app.get('{*path}', (req, res) => {
219
+ if (
220
+ req.path.startsWith('/.well-known/') ||
221
+ req.path.startsWith('/api/') ||
222
+ req.path.startsWith('/login/oauth/')
223
+ ) {
224
+ res.status(404).json({ error: 'Not found' });
225
+ return;
226
+ }
227
+ res.sendFile(path.join(frontendDist, 'index.html'));
228
+ });
229
+ }
230
+
231
+ // Idle tenants are stopped on a timer, never on the request that would
232
+ // have been their last: a graph whose last response closed `idleMs` ago,
233
+ // with none still open and no queued commit, is not worth its pool and
234
+ // its lease. `busy()` is what keeps an event stream's tenant alive.
235
+ const sweep = async () => {
236
+ for (const runtime of runtimes.values()) {
237
+ if (runtime.state !== 'active' || runtime.idleFor() < idleMs) continue;
238
+ if (await runtime.busy()) continue;
239
+ await runtime.evict().catch((err: unknown) => log.warn(`evicting tenant "${runtime.slug}" failed:`, { err }));
240
+ }
241
+ };
242
+ const sweeper =
243
+ idleMs > 0
244
+ ? setInterval(() => void sweep(), Math.min(opts.sweepIntervalMs ?? DEFAULT_SWEEP_INTERVAL_MS, idleMs))
245
+ : null;
246
+ sweeper?.unref();
247
+
248
+ const evictAll = async () => {
249
+ await Promise.all([...runtimes.values()].map((runtime) => runtime.evict().catch(() => undefined)));
250
+ };
251
+
252
+ return {
253
+ app,
254
+ runtimes: () => runtimes,
255
+ evictAll,
256
+ async stop() {
257
+ if (sweeper) clearInterval(sweeper);
258
+ await evictAll();
259
+ },
260
+ };
261
+ }
@@ -0,0 +1,208 @@
1
+ import type { Express } from 'express';
2
+ import { createCoreServices, type CoreServices } from '../core/create-core-services.js';
3
+ import { createCoreServer } from '../core/create-core-server.js';
4
+ import { stopCore } from '../core/lifecycle.js';
5
+ import { logger } from '../shared/logging.js';
6
+ import type { TenantDescriptor } from './tenant-source.contract.js';
7
+
8
+ const log = logger('tenancy');
9
+
10
+ /** A tenant's running graph: its services and the Express app that serves them. */
11
+ export interface TenantGraph {
12
+ core: CoreServices;
13
+ app: Express;
14
+ }
15
+
16
+ export type TenantState = 'idle' | 'activating' | 'active' | 'evicting';
17
+
18
+ /** The lifecycle seams, so a suite can drive a runtime without a database. */
19
+ export interface TenantRuntimeDeps {
20
+ /** Build and start the graph. Default: `createCoreServices` + `createCoreServer`. */
21
+ activate?: (descriptor: TenantDescriptor) => Promise<TenantGraph>;
22
+ /** Stop a graph. Default: `stopCore`. */
23
+ stop?: (graph: TenantGraph) => Promise<void>;
24
+ /** Whether the graph has work in flight that an eviction would strand. Default: queued commits. */
25
+ busy?: (graph: TenantGraph) => Promise<boolean>;
26
+ now?: () => number;
27
+ /**
28
+ * How long a failed activation is remembered before the next request tries
29
+ * again: `initialMs` after the first failure, doubling per consecutive
30
+ * failure up to `maxMs`. Defaults: 5 s to 60 s.
31
+ */
32
+ retry?: { initialMs?: number; maxMs?: number };
33
+ }
34
+
35
+ const DEFAULT_RETRY_INITIAL_MS = 5_000;
36
+ const DEFAULT_RETRY_MAX_MS = 60_000;
37
+
38
+ /**
39
+ * How a tenant's graph is built with the composition root as a distribution
40
+ * calls it, plus the one thing a host must say: no mirroring onto the shared
41
+ * package's process-wide bindings, since this process has several graphs and
42
+ * no single value to put there.
43
+ */
44
+ async function activateWithCore(descriptor: TenantDescriptor): Promise<TenantGraph> {
45
+ const core = await createCoreServices(descriptor.config, { ...descriptor.ports, mirrorSharedBindings: false });
46
+ try {
47
+ // No static dir: the host serves the SPA once, for every tenant.
48
+ const app = await createCoreServer(core, descriptor.extensions ?? {}, {});
49
+ return { core, app };
50
+ } catch (err) {
51
+ // A graph whose boot failed still holds a pool and a lease.
52
+ await stopCore(core).catch(() => undefined);
53
+ throw err;
54
+ }
55
+ }
56
+
57
+ async function queuedCommits(graph: TenantGraph): Promise<boolean> {
58
+ return (await graph.core.pendingCommitsService.oldestQueuedAt()) !== null;
59
+ }
60
+
61
+ /**
62
+ * One tenant's graph, brought up on first use and stopped when the host
63
+ * says so: `idle → activating → active → evicting → idle`.
64
+ *
65
+ * ACTIVATE ONCE. Requests arriving while the graph is being built all await
66
+ * the one activation in flight. A failed activation is remembered for a
67
+ * short, growing window and answered from memory inside it, so a tenant
68
+ * whose remote is down or whose token is wrong costs one clone attempt per
69
+ * window rather than one per request; past the window the next request
70
+ * tries again, since the remote may be back or the token fixed. An eviction
71
+ * that lands mid-activation waits for the activation and then stops what it
72
+ * produced, so a graph is never left running behind an evicted runtime.
73
+ *
74
+ * IN USE MEANS A RESPONSE IS OPEN. The host tells the runtime when it hands
75
+ * a request over and when that response closes, so idleness counts from the
76
+ * last response that ENDED, and a tenant with any response still open — an
77
+ * event stream a browser holds, a clone in flight — is busy and never
78
+ * evicted from under it.
79
+ */
80
+ export class TenantRuntime {
81
+ private graph: TenantGraph | null = null;
82
+ private activation: Promise<TenantGraph> | null = null;
83
+ private eviction: Promise<void> | null = null;
84
+ private failure: { error: unknown; until: number; backoffMs: number } | null = null;
85
+ private openResponses = 0;
86
+ private lastUsedAt: number;
87
+ private readonly activate: (descriptor: TenantDescriptor) => Promise<TenantGraph>;
88
+ private readonly stopGraph: (graph: TenantGraph) => Promise<void>;
89
+ private readonly isBusy: (graph: TenantGraph) => Promise<boolean>;
90
+ private readonly now: () => number;
91
+ private readonly retryInitialMs: number;
92
+ private readonly retryMaxMs: number;
93
+
94
+ constructor(
95
+ readonly descriptor: TenantDescriptor,
96
+ deps: TenantRuntimeDeps = {},
97
+ ) {
98
+ this.activate = deps.activate ?? activateWithCore;
99
+ this.stopGraph = deps.stop ?? ((graph) => stopCore(graph.core));
100
+ this.isBusy = deps.busy ?? queuedCommits;
101
+ this.now = deps.now ?? Date.now;
102
+ this.retryInitialMs = deps.retry?.initialMs ?? DEFAULT_RETRY_INITIAL_MS;
103
+ this.retryMaxMs = deps.retry?.maxMs ?? DEFAULT_RETRY_MAX_MS;
104
+ this.lastUsedAt = this.now();
105
+ }
106
+
107
+ /** A request was handed to this tenant; paired with {@link leave} when its response closes. */
108
+ enter(): void {
109
+ this.openResponses += 1;
110
+ this.lastUsedAt = this.now();
111
+ }
112
+
113
+ /** A response to this tenant closed, however it ended. */
114
+ leave(): void {
115
+ if (this.openResponses > 0) this.openResponses -= 1;
116
+ this.lastUsedAt = this.now();
117
+ }
118
+
119
+ /** Responses handed over and not yet closed. */
120
+ get open(): number {
121
+ return this.openResponses;
122
+ }
123
+
124
+ get slug(): string {
125
+ return this.descriptor.slug;
126
+ }
127
+
128
+ get state(): TenantState {
129
+ if (this.eviction) return 'evicting';
130
+ if (this.graph) return 'active';
131
+ if (this.activation) return 'activating';
132
+ return 'idle';
133
+ }
134
+
135
+ /** Milliseconds since a request last touched this tenant. */
136
+ idleFor(): number {
137
+ return this.now() - this.lastUsedAt;
138
+ }
139
+
140
+ /**
141
+ * The graph, built if it is not running. Every caller of a concurrent
142
+ * first burst gets the same promise; a caller that arrives during an
143
+ * eviction waits for it, then starts the graph afresh.
144
+ */
145
+ async handle(): Promise<TenantGraph> {
146
+ this.lastUsedAt = this.now();
147
+ if (this.eviction) await this.eviction;
148
+ if (this.graph) return this.graph;
149
+ if (this.failure && this.now() < this.failure.until) throw this.failure.error;
150
+ this.activation ??= this.activate(this.descriptor).then(
151
+ (graph) => {
152
+ this.graph = graph;
153
+ this.activation = null;
154
+ this.failure = null;
155
+ log.info(`tenant "${this.slug}" activated`);
156
+ return graph;
157
+ },
158
+ (err: unknown) => {
159
+ this.activation = null;
160
+ const backoffMs = Math.min(this.failure ? this.failure.backoffMs * 2 : this.retryInitialMs, this.retryMaxMs);
161
+ this.failure = { error: err, until: this.now() + backoffMs, backoffMs };
162
+ log.error(`tenant "${this.slug}" failed to activate; not asked again for ${backoffMs}ms:`, { err });
163
+ throw err;
164
+ },
165
+ );
166
+ return this.activation;
167
+ }
168
+
169
+ /**
170
+ * Whether an eviction would strand something: a response still open, or
171
+ * work the graph reports (queued commits). False when nothing runs.
172
+ */
173
+ async busy(): Promise<boolean> {
174
+ if (this.openResponses > 0) return true;
175
+ return this.graph ? this.isBusy(this.graph) : false;
176
+ }
177
+
178
+ /**
179
+ * Stop the graph, if one runs or is being built. Idempotent: a second call
180
+ * joins the eviction under way. Afterwards the runtime is idle and the
181
+ * next {@link handle} builds a fresh graph.
182
+ */
183
+ evict(): Promise<void> {
184
+ if (this.eviction) return this.eviction;
185
+ const eviction = (async () => {
186
+ if (this.activation) {
187
+ // Whatever the build produces is stopped; a build that fails has
188
+ // stopped its own graph already.
189
+ await this.activation.catch(() => undefined);
190
+ }
191
+ const graph = this.graph;
192
+ this.graph = null;
193
+ if (graph) {
194
+ await this.stopGraph(graph);
195
+ log.info(`tenant "${this.slug}" evicted`);
196
+ }
197
+ })();
198
+ // Assigned, then cleared by identity: an eviction with nothing to stop
199
+ // settles before this line runs, and a `finally` inside it would have
200
+ // cleared a field that was not yet set — leaving the settled promise
201
+ // in place as an eviction forever under way.
202
+ this.eviction = eviction;
203
+ void eviction.finally(() => {
204
+ if (this.eviction === eviction) this.eviction = null;
205
+ });
206
+ return eviction;
207
+ }
208
+ }
@@ -0,0 +1,41 @@
1
+ import { hkdfSync } from 'node:crypto';
2
+
3
+ /** The three secrets every graph needs, derived rather than stored. */
4
+ export interface TenantSecrets {
5
+ /** Signs the tenant's login sessions and OAuth state. */
6
+ jwtSecret: string;
7
+ /** 32 bytes, base64: encrypts the tenant's vault values, MCP OAuth tokens and stored git credential. */
8
+ secretsEncKey: string;
9
+ /** HMAC key for the tenant's internal (loopback) tool tokens. */
10
+ internalTokenSecret: string;
11
+ }
12
+
13
+ /** The least a master key may hold: 32 characters is 256 bits of a random string. */
14
+ const MIN_MASTER_KEY_LENGTH = 32;
15
+
16
+ /**
17
+ * A tenant's secrets from ONE master key and its slug, with HKDF-SHA256:
18
+ * the slug is the salt and each secret's name the info, so the three are
19
+ * independent of each other and of every other tenant's.
20
+ *
21
+ * Derived, not generated and stored, for the hand-over: a tenant that leaves
22
+ * for a dedicated deployment takes a `pg_dump` whose vault rows and stored
23
+ * git token are encrypted under its `secretsEncKey`. With derivation the key
24
+ * is reproducible from the master key and the slug on the day of the
25
+ * export, and nothing per tenant has to be kept safe in the meantime. The
26
+ * cloud app's registry calls this with the same inputs and gets the same
27
+ * answer.
28
+ */
29
+ export function deriveTenantSecrets(masterKey: string, slug: string): TenantSecrets {
30
+ if (masterKey.length < MIN_MASTER_KEY_LENGTH) {
31
+ throw new Error(`TENANT_MASTER_KEY must be at least ${MIN_MASTER_KEY_LENGTH} characters of random text`);
32
+ }
33
+ if (!slug) throw new Error('A tenant slug is required to derive its secrets');
34
+ const derive = (info: string): string =>
35
+ Buffer.from(hkdfSync('sha256', masterKey, `hexis-tenant:${slug}`, info, 32)).toString('base64');
36
+ return {
37
+ jwtSecret: derive('jwt-secret'),
38
+ secretsEncKey: derive('secrets-enc-key'),
39
+ internalTokenSecret: derive('internal-token-secret'),
40
+ };
41
+ }
@@ -0,0 +1,59 @@
1
+ import type { TenantConfig } from '../core-config.js';
2
+ import type { CorePorts } from '../core/core-ports.js';
3
+ import type { ServerExtensions } from '../core/create-core-server.js';
4
+
5
+ /**
6
+ * A tenant, as the host needs to know it: which host names reach it, what
7
+ * its service graph is built from, and what a distribution adds to that
8
+ * graph. One of these is one `createCoreServices` + `createCoreServer`, run
9
+ * on demand and stopped again when idle — see `tenant-runtime.ts`.
10
+ *
11
+ * `ports` and `extensions` are per tenant on purpose: everything the
12
+ * enterprise overlay does per deployment (its SSO plugin, session sink,
13
+ * erasure participants, extra startup steps) it does per tenant here, through
14
+ * the same two seams, with nothing below the front door knowing the
15
+ * difference.
16
+ */
17
+ export interface TenantDescriptor {
18
+ /** The tenant's stable name: lowercase, `[a-z][a-z0-9-]*`, at most 40 characters. */
19
+ readonly slug: string;
20
+ /** Host names (no port) whose requests belong to this tenant, lowercase. */
21
+ readonly hosts: readonly string[];
22
+ readonly config: TenantConfig;
23
+ readonly ports?: CorePorts;
24
+ readonly extensions?: ServerExtensions;
25
+ }
26
+
27
+ /**
28
+ * Where tenants come from. Core ships {@link StaticTenantSource}, which
29
+ * reads a file, for development and tests; the cloud app implements this
30
+ * over its own registry, where subdomains are provisioned and plans live.
31
+ * A source answers `null` for a host or slug it does not know, and the host
32
+ * turns that into a 404 without building anything.
33
+ */
34
+ export interface TenantSource {
35
+ resolveByHost(host: string): Promise<TenantDescriptor | null>;
36
+ describe(slug: string): Promise<TenantDescriptor | null>;
37
+ }
38
+
39
+ /** What a slug may look like: it names a schema, a folder and a loopback path. */
40
+ export const TENANT_SLUG_PATTERN = /^[a-z][a-z0-9-]{0,39}$/;
41
+
42
+ export function assertTenantSlug(slug: string): string {
43
+ if (!TENANT_SLUG_PATTERN.test(slug)) {
44
+ throw new Error(`Tenant slug must match ${TENANT_SLUG_PATTERN} (lowercase, digits, hyphens); got "${slug}"`);
45
+ }
46
+ return slug;
47
+ }
48
+
49
+ /**
50
+ * A host name the way the host compares it: lowercase, without a port or a
51
+ * trailing dot. `Host` headers and `X-Forwarded-Host` values arrive in every
52
+ * spelling a client or proxy chooses.
53
+ */
54
+ export function normalizeHost(host: string): string {
55
+ const trimmed = host.trim().toLowerCase().replace(/\.$/, '');
56
+ // `[::1]:3001` keeps its brackets; `example.test:3001` loses its port.
57
+ if (trimmed.startsWith('[')) return trimmed.replace(/\]:\d+$/, ']');
58
+ return trimmed.replace(/:\d+$/, '');
59
+ }
@@ -1,34 +0,0 @@
1
- import { WorkflowDomainError } from '../workflow/workflow.errors.js';
2
- export interface AccessDeniedDetails {
3
- /** repo-relative POSIX path the caller tried to write */
4
- path: string;
5
- /** Display names of roles that would grant write at this path. */
6
- eligibleRoles: string[];
7
- /** Direct user grants at this path, in `{name, email}` form. */
8
- eligibleUsers: {
9
- name: string;
10
- email: string;
11
- }[];
12
- }
13
- /**
14
- * Thrown when a user lacks the `write` permission on a path under the
15
- * access-control rules in `roles.yaml` + `access.md`.
16
- *
17
- * Carries enough detail in the JSON payload for the frontend to render
18
- * "you don't have permission to write to <path>; eligible: <roles + users>"
19
- * without a follow-up roundtrip.
20
- */
21
- export declare class AccessDeniedError extends WorkflowDomainError {
22
- readonly access: AccessDeniedDetails;
23
- constructor(details: AccessDeniedDetails);
24
- }
25
- /**
26
- * Thrown when the access-control config (roles.yaml or access.md) is missing
27
- * or malformed at runtime — distinct from AccessDeniedError because the cause
28
- * is a config bug, not a permission decision.
29
- */
30
- export declare class AccessConfigError extends WorkflowDomainError {
31
- readonly errors: string[];
32
- constructor(errors: string[]);
33
- }
34
- //# sourceMappingURL=access-errors.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"access-errors.d.ts","sourceRoot":"","sources":["../../../src/modules/access/access-errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AAErE,MAAM,WAAW,mBAAmB;IAClC,yDAAyD;IACzD,IAAI,EAAE,MAAM,CAAC;IACb,kEAAkE;IAClE,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,gEAAgE;IAChE,aAAa,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAClD;AAED;;;;;;;GAOG;AACH,qBAAa,iBAAkB,SAAQ,mBAAmB;IACxD,QAAQ,CAAC,MAAM,EAAE,mBAAmB,CAAC;gBAEzB,OAAO,EAAE,mBAAmB;CAkBzC;AAED;;;;GAIG;AACH,qBAAa,iBAAkB,SAAQ,mBAAmB;IACxD,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC;gBAEd,MAAM,EAAE,MAAM,EAAE;CAS7B"}
@@ -1,40 +0,0 @@
1
- import { WorkflowDomainError } from '../workflow/workflow.errors.js';
2
- /**
3
- * Thrown when a user lacks the `write` permission on a path under the
4
- * access-control rules in `roles.yaml` + `access.md`.
5
- *
6
- * Carries enough detail in the JSON payload for the frontend to render
7
- * "you don't have permission to write to <path>; eligible: <roles + users>"
8
- * without a follow-up roundtrip.
9
- */
10
- export class AccessDeniedError extends WorkflowDomainError {
11
- access;
12
- constructor(details) {
13
- const rolesPart = details.eligibleRoles.length
14
- ? details.eligibleRoles.join(', ')
15
- : 'none';
16
- const usersPart = details.eligibleUsers.length
17
- ? details.eligibleUsers
18
- .map((u) => (u.name ? `${u.name} <${u.email}>` : u.email))
19
- .join(', ')
20
- : '';
21
- const eligible = [rolesPart, usersPart].filter(Boolean).join('; ');
22
- super(`You don't have permission to write to "${details.path}". Eligible: ${eligible}.`, 403, { access: details });
23
- this.name = 'AccessDeniedError';
24
- this.access = details;
25
- }
26
- }
27
- /**
28
- * Thrown when the access-control config (roles.yaml or access.md) is missing
29
- * or malformed at runtime — distinct from AccessDeniedError because the cause
30
- * is a config bug, not a permission decision.
31
- */
32
- export class AccessConfigError extends WorkflowDomainError {
33
- errors;
34
- constructor(errors) {
35
- super(`Access-control config is invalid: ${errors.join('; ')}`, 500, { accessConfigErrors: errors });
36
- this.name = 'AccessConfigError';
37
- this.errors = errors;
38
- }
39
- }
40
- //# sourceMappingURL=access-errors.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"access-errors.js","sourceRoot":"","sources":["../../../src/modules/access/access-errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AAWrE;;;;;;;GAOG;AACH,MAAM,OAAO,iBAAkB,SAAQ,mBAAmB;IAC/C,MAAM,CAAsB;IAErC,YAAY,OAA4B;QACtC,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM;YAC5C,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC;YAClC,CAAC,CAAC,MAAM,CAAC;QACX,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM;YAC5C,CAAC,CAAC,OAAO,CAAC,aAAa;iBAClB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;iBACzD,IAAI,CAAC,IAAI,CAAC;YACf,CAAC,CAAC,EAAE,CAAC;QACP,MAAM,QAAQ,GAAG,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnE,KAAK,CACH,0CAA0C,OAAO,CAAC,IAAI,gBAAgB,QAAQ,GAAG,EACjF,GAAG,EACH,EAAE,MAAM,EAAE,OAAO,EAAE,CACpB,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;QAChC,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC;IACxB,CAAC;CACF;AAED;;;;GAIG;AACH,MAAM,OAAO,iBAAkB,SAAQ,mBAAmB;IAC/C,MAAM,CAAW;IAE1B,YAAY,MAAgB;QAC1B,KAAK,CACH,qCAAqC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EACxD,GAAG,EACH,EAAE,kBAAkB,EAAE,MAAM,EAAE,CAC/B,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;QAChC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;CACF"}