@bevel-software/platform-core-backend 0.20.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 (576) 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 +23 -105
  11. package/dist/core/create-core-server.js.map +1 -1
  12. package/dist/core/create-core-services.d.ts +30 -5
  13. package/dist/core/create-core-services.d.ts.map +1 -1
  14. package/dist/core/create-core-services.js +136 -81
  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/auth/account-admission.d.ts +40 -0
  53. package/dist/modules/auth/account-admission.d.ts.map +1 -0
  54. package/dist/modules/auth/account-admission.js +17 -0
  55. package/dist/modules/auth/account-admission.js.map +1 -0
  56. package/dist/modules/auth/account.routes.d.ts.map +1 -1
  57. package/dist/modules/auth/account.routes.js +4 -1
  58. package/dist/modules/auth/account.routes.js.map +1 -1
  59. package/dist/modules/auth/auth.service.d.ts +19 -1
  60. package/dist/modules/auth/auth.service.d.ts.map +1 -1
  61. package/dist/modules/auth/auth.service.js +33 -1
  62. package/dist/modules/auth/auth.service.js.map +1 -1
  63. package/dist/modules/auth/oidc-auth-provider.d.ts.map +1 -1
  64. package/dist/modules/auth/oidc-auth-provider.js +9 -0
  65. package/dist/modules/auth/oidc-auth-provider.js.map +1 -1
  66. package/dist/modules/connection-probe/connection-probe.service.d.ts +13 -1
  67. package/dist/modules/connection-probe/connection-probe.service.d.ts.map +1 -1
  68. package/dist/modules/connection-probe/connection-probe.service.js +10 -2
  69. package/dist/modules/connection-probe/connection-probe.service.js.map +1 -1
  70. package/dist/modules/database/advisory-lock.d.ts +17 -0
  71. package/dist/modules/database/advisory-lock.d.ts.map +1 -1
  72. package/dist/modules/database/advisory-lock.js +24 -3
  73. package/dist/modules/database/advisory-lock.js.map +1 -1
  74. package/dist/modules/database/connection.d.ts +67 -2
  75. package/dist/modules/database/connection.d.ts.map +1 -1
  76. package/dist/modules/database/connection.js +118 -12
  77. package/dist/modules/database/connection.js.map +1 -1
  78. package/dist/modules/database/migrate.d.ts +1 -1
  79. package/dist/modules/database/migrate.d.ts.map +1 -1
  80. package/dist/modules/database/migrate.js +27 -3
  81. package/dist/modules/database/migrate.js.map +1 -1
  82. package/dist/modules/kb-fs/branch-name.d.ts +0 -1
  83. package/dist/modules/kb-fs/branch-name.d.ts.map +1 -1
  84. package/dist/modules/kb-fs/branch-name.js +3 -3
  85. package/dist/modules/kb-fs/branch-name.js.map +1 -1
  86. package/dist/modules/kb-fs/clone-config.d.ts +9 -8
  87. package/dist/modules/kb-fs/clone-config.d.ts.map +1 -1
  88. package/dist/modules/kb-fs/clone-config.js +14 -12
  89. package/dist/modules/kb-fs/clone-config.js.map +1 -1
  90. package/dist/modules/mcp/mcp.service.d.ts +7 -0
  91. package/dist/modules/mcp/mcp.service.d.ts.map +1 -1
  92. package/dist/modules/mcp/mcp.service.js +4 -4
  93. package/dist/modules/mcp/mcp.service.js.map +1 -1
  94. package/dist/modules/plugins/compile/marketplace-compiler.service.d.ts +4 -4
  95. package/dist/modules/plugins/compile/marketplace-compiler.service.d.ts.map +1 -1
  96. package/dist/modules/plugins/compile/marketplace-compiler.service.js +7 -10
  97. package/dist/modules/plugins/compile/marketplace-compiler.service.js.map +1 -1
  98. package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.d.ts +4 -1
  99. package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.d.ts.map +1 -1
  100. package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.js +5 -3
  101. package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.js.map +1 -1
  102. package/dist/modules/plugins/discovery/kb-plugin-source.d.ts +6 -1
  103. package/dist/modules/plugins/discovery/kb-plugin-source.d.ts.map +1 -1
  104. package/dist/modules/plugins/discovery/kb-plugin-source.js +14 -9
  105. package/dist/modules/plugins/discovery/kb-plugin-source.js.map +1 -1
  106. package/dist/modules/plugins/discovery/native.source.d.ts +4 -1
  107. package/dist/modules/plugins/discovery/native.source.d.ts.map +1 -1
  108. package/dist/modules/plugins/discovery/native.source.js +4 -2
  109. package/dist/modules/plugins/discovery/native.source.js.map +1 -1
  110. package/dist/modules/plugins/index.d.ts +1 -1
  111. package/dist/modules/plugins/index.d.ts.map +1 -1
  112. package/dist/modules/plugins/index.js +1 -1
  113. package/dist/modules/plugins/index.js.map +1 -1
  114. package/dist/modules/plugins/join-request-jobs.service.d.ts +3 -1
  115. package/dist/modules/plugins/join-request-jobs.service.d.ts.map +1 -1
  116. package/dist/modules/plugins/join-request-jobs.service.js +6 -6
  117. package/dist/modules/plugins/join-request-jobs.service.js.map +1 -1
  118. package/dist/modules/plugins/join-requests.service.d.ts +3 -1
  119. package/dist/modules/plugins/join-requests.service.d.ts.map +1 -1
  120. package/dist/modules/plugins/join-requests.service.js +9 -8
  121. package/dist/modules/plugins/join-requests.service.js.map +1 -1
  122. package/dist/modules/plugins/plugin-links.d.ts +65 -10
  123. package/dist/modules/plugins/plugin-links.d.ts.map +1 -1
  124. package/dist/modules/plugins/plugin-links.js +136 -31
  125. package/dist/modules/plugins/plugin-links.js.map +1 -1
  126. package/dist/modules/plugins/plugin-links.service.d.ts +107 -5
  127. package/dist/modules/plugins/plugin-links.service.d.ts.map +1 -1
  128. package/dist/modules/plugins/plugin-links.service.js +151 -21
  129. package/dist/modules/plugins/plugin-links.service.js.map +1 -1
  130. package/dist/modules/plugins/plugin-provision.service.d.ts +10 -3
  131. package/dist/modules/plugins/plugin-provision.service.d.ts.map +1 -1
  132. package/dist/modules/plugins/plugin-provision.service.js +33 -26
  133. package/dist/modules/plugins/plugin-provision.service.js.map +1 -1
  134. package/dist/modules/plugins/plugin-rename.service.d.ts +4 -2
  135. package/dist/modules/plugins/plugin-rename.service.d.ts.map +1 -1
  136. package/dist/modules/plugins/plugin-rename.service.js +10 -12
  137. package/dist/modules/plugins/plugin-rename.service.js.map +1 -1
  138. package/dist/modules/plugins/plugins.routes.d.ts +3 -0
  139. package/dist/modules/plugins/plugins.routes.d.ts.map +1 -1
  140. package/dist/modules/plugins/plugins.routes.js +45 -15
  141. package/dist/modules/plugins/plugins.routes.js.map +1 -1
  142. package/dist/modules/plugins/plugins.service.d.ts +4 -4
  143. package/dist/modules/plugins/plugins.service.d.ts.map +1 -1
  144. package/dist/modules/plugins/plugins.service.js +7 -10
  145. package/dist/modules/plugins/plugins.service.js.map +1 -1
  146. package/dist/modules/plugins/teams.routes.d.ts +4 -1
  147. package/dist/modules/plugins/teams.routes.d.ts.map +1 -1
  148. package/dist/modules/plugins/teams.routes.js +11 -9
  149. package/dist/modules/plugins/teams.routes.js.map +1 -1
  150. package/dist/modules/secrets-vault/index.d.ts +1 -1
  151. package/dist/modules/secrets-vault/index.d.ts.map +1 -1
  152. package/dist/modules/secrets-vault/index.js +1 -1
  153. package/dist/modules/secrets-vault/index.js.map +1 -1
  154. package/dist/modules/secrets-vault/secrets-variable-loader.d.ts +29 -11
  155. package/dist/modules/secrets-vault/secrets-variable-loader.d.ts.map +1 -1
  156. package/dist/modules/secrets-vault/secrets-variable-loader.js +46 -21
  157. package/dist/modules/secrets-vault/secrets-variable-loader.js.map +1 -1
  158. package/dist/modules/secrets-vault/secrets-vault.routes.d.ts +3 -0
  159. package/dist/modules/secrets-vault/secrets-vault.routes.d.ts.map +1 -1
  160. package/dist/modules/secrets-vault/secrets-vault.routes.js +4 -6
  161. package/dist/modules/secrets-vault/secrets-vault.routes.js.map +1 -1
  162. package/dist/modules/settings/deployment-settings.service.d.ts +12 -8
  163. package/dist/modules/settings/deployment-settings.service.d.ts.map +1 -1
  164. package/dist/modules/settings/deployment-settings.service.js +20 -22
  165. package/dist/modules/settings/deployment-settings.service.js.map +1 -1
  166. package/dist/modules/settings/setup.routes.d.ts +9 -2
  167. package/dist/modules/settings/setup.routes.d.ts.map +1 -1
  168. package/dist/modules/settings/setup.routes.js +20 -14
  169. package/dist/modules/settings/setup.routes.js.map +1 -1
  170. package/dist/modules/skills/allowed-tools-check.d.ts +4 -3
  171. package/dist/modules/skills/allowed-tools-check.d.ts.map +1 -1
  172. package/dist/modules/skills/allowed-tools-check.js +8 -8
  173. package/dist/modules/skills/allowed-tools-check.js.map +1 -1
  174. package/dist/modules/skills/pending-skills.service.d.ts +3 -1
  175. package/dist/modules/skills/pending-skills.service.d.ts.map +1 -1
  176. package/dist/modules/skills/pending-skills.service.js +9 -6
  177. package/dist/modules/skills/pending-skills.service.js.map +1 -1
  178. package/dist/modules/skills/skill-access-requests.routes.d.ts +2 -1
  179. package/dist/modules/skills/skill-access-requests.routes.d.ts.map +1 -1
  180. package/dist/modules/skills/skill-access-requests.routes.js +6 -6
  181. package/dist/modules/skills/skill-access-requests.routes.js.map +1 -1
  182. package/dist/modules/skills/skills.routes.d.ts +4 -1
  183. package/dist/modules/skills/skills.routes.d.ts.map +1 -1
  184. package/dist/modules/skills/skills.routes.js +4 -4
  185. package/dist/modules/skills/skills.routes.js.map +1 -1
  186. package/dist/modules/skills/skills.service.d.ts +4 -2
  187. package/dist/modules/skills/skills.service.d.ts.map +1 -1
  188. package/dist/modules/skills/skills.service.js +13 -11
  189. package/dist/modules/skills/skills.service.js.map +1 -1
  190. package/dist/modules/tool-manuals/mcp-json-discovery.d.ts +2 -1
  191. package/dist/modules/tool-manuals/mcp-json-discovery.d.ts.map +1 -1
  192. package/dist/modules/tool-manuals/mcp-json-discovery.js +6 -5
  193. package/dist/modules/tool-manuals/mcp-json-discovery.js.map +1 -1
  194. package/dist/modules/tool-manuals/mcp-server-edit.service.d.ts +4 -2
  195. package/dist/modules/tool-manuals/mcp-server-edit.service.d.ts.map +1 -1
  196. package/dist/modules/tool-manuals/mcp-server-edit.service.js +12 -10
  197. package/dist/modules/tool-manuals/mcp-server-edit.service.js.map +1 -1
  198. package/dist/modules/tool-manuals/pending-tools.service.d.ts +3 -1
  199. package/dist/modules/tool-manuals/pending-tools.service.d.ts.map +1 -1
  200. package/dist/modules/tool-manuals/pending-tools.service.js +19 -16
  201. package/dist/modules/tool-manuals/pending-tools.service.js.map +1 -1
  202. package/dist/modules/tool-manuals/tool-delete.service.d.ts +4 -2
  203. package/dist/modules/tool-manuals/tool-delete.service.d.ts.map +1 -1
  204. package/dist/modules/tool-manuals/tool-delete.service.js +14 -12
  205. package/dist/modules/tool-manuals/tool-delete.service.js.map +1 -1
  206. package/dist/modules/tool-manuals/tool-manuals.routes.d.ts +3 -1
  207. package/dist/modules/tool-manuals/tool-manuals.routes.d.ts.map +1 -1
  208. package/dist/modules/tool-manuals/tool-manuals.routes.js +7 -7
  209. package/dist/modules/tool-manuals/tool-manuals.routes.js.map +1 -1
  210. package/dist/modules/tool-manuals/tool-manuals.service.d.ts +4 -2
  211. package/dist/modules/tool-manuals/tool-manuals.service.d.ts.map +1 -1
  212. package/dist/modules/tool-manuals/tool-manuals.service.js +15 -12
  213. package/dist/modules/tool-manuals/tool-manuals.service.js.map +1 -1
  214. package/dist/modules/tool-manuals/tool-manuals.tools.d.ts +3 -0
  215. package/dist/modules/tool-manuals/tool-manuals.tools.d.ts.map +1 -1
  216. package/dist/modules/tool-manuals/tool-manuals.tools.js +4 -6
  217. package/dist/modules/tool-manuals/tool-manuals.tools.js.map +1 -1
  218. package/dist/modules/workflow/agent-tools/workflow.tools.d.ts +3 -2
  219. package/dist/modules/workflow/agent-tools/workflow.tools.d.ts.map +1 -1
  220. package/dist/modules/workflow/agent-tools/workflow.tools.js +9 -9
  221. package/dist/modules/workflow/agent-tools/workflow.tools.js.map +1 -1
  222. package/dist/modules/workflow/git/git.service.d.ts +11 -5
  223. package/dist/modules/workflow/git/git.service.d.ts.map +1 -1
  224. package/dist/modules/workflow/git/git.service.js +23 -14
  225. package/dist/modules/workflow/git/git.service.js.map +1 -1
  226. package/dist/modules/workflow/git/node-git-runner.d.ts +26 -2
  227. package/dist/modules/workflow/git/node-git-runner.d.ts.map +1 -1
  228. package/dist/modules/workflow/git/node-git-runner.js +35 -5
  229. package/dist/modules/workflow/git/node-git-runner.js.map +1 -1
  230. package/dist/modules/workflow/review-workflow/review-workflow.service.d.ts.map +1 -1
  231. package/dist/modules/workflow/review-workflow/review-workflow.service.js +9 -4
  232. package/dist/modules/workflow/review-workflow/review-workflow.service.js.map +1 -1
  233. package/dist/modules/workflow/session-ontology.service.d.ts +6 -1
  234. package/dist/modules/workflow/session-ontology.service.d.ts.map +1 -1
  235. package/dist/modules/workflow/session-ontology.service.js +6 -2
  236. package/dist/modules/workflow/session-ontology.service.js.map +1 -1
  237. package/dist/modules/workflow/workflow.service.d.ts +8 -3
  238. package/dist/modules/workflow/workflow.service.d.ts.map +1 -1
  239. package/dist/modules/workflow/workflow.service.js +33 -23
  240. package/dist/modules/workflow/workflow.service.js.map +1 -1
  241. package/dist/modules/workspace/session-ontology.gate.d.ts +3 -1
  242. package/dist/modules/workspace/session-ontology.gate.d.ts.map +1 -1
  243. package/dist/modules/workspace/session-ontology.gate.js +3 -3
  244. package/dist/modules/workspace/session-ontology.gate.js.map +1 -1
  245. package/dist/modules/workspace/startup/kb-git.d.ts +4 -3
  246. package/dist/modules/workspace/startup/kb-git.d.ts.map +1 -1
  247. package/dist/modules/workspace/startup/kb-git.js +15 -13
  248. package/dist/modules/workspace/startup/kb-git.js.map +1 -1
  249. package/dist/modules/workspace/startup/kb-startup-runner.d.ts +5 -8
  250. package/dist/modules/workspace/startup/kb-startup-runner.d.ts.map +1 -1
  251. package/dist/modules/workspace/startup/kb-startup-runner.js +35 -38
  252. package/dist/modules/workspace/startup/kb-startup-runner.js.map +1 -1
  253. package/dist/modules/workspace/startup/steps/groups-to-plugins.step.d.ts +7 -1
  254. package/dist/modules/workspace/startup/steps/groups-to-plugins.step.d.ts.map +1 -1
  255. package/dist/modules/workspace/startup/steps/groups-to-plugins.step.js +23 -16
  256. package/dist/modules/workspace/startup/steps/groups-to-plugins.step.js.map +1 -1
  257. package/dist/modules/workspace/startup/steps/personal-spaces.step.d.ts +7 -1
  258. package/dist/modules/workspace/startup/steps/personal-spaces.step.d.ts.map +1 -1
  259. package/dist/modules/workspace/startup/steps/personal-spaces.step.js +12 -5
  260. package/dist/modules/workspace/startup/steps/personal-spaces.step.js.map +1 -1
  261. package/dist/modules/workspace/startup/steps/plugin-display-names.step.d.ts +7 -1
  262. package/dist/modules/workspace/startup/steps/plugin-display-names.step.d.ts.map +1 -1
  263. package/dist/modules/workspace/startup/steps/plugin-display-names.step.js +12 -5
  264. package/dist/modules/workspace/startup/steps/plugin-display-names.step.js.map +1 -1
  265. package/dist/modules/workspace/startup/steps/plugin-manifests.step.d.ts +7 -1
  266. package/dist/modules/workspace/startup/steps/plugin-manifests.step.d.ts.map +1 -1
  267. package/dist/modules/workspace/startup/steps/plugin-manifests.step.js +12 -5
  268. package/dist/modules/workspace/startup/steps/plugin-manifests.step.js.map +1 -1
  269. package/dist/modules/workspace/startup/steps/seed-tree.d.ts +4 -1
  270. package/dist/modules/workspace/startup/steps/seed-tree.d.ts.map +1 -1
  271. package/dist/modules/workspace/startup/steps/seed-tree.js +14 -11
  272. package/dist/modules/workspace/startup/steps/seed-tree.js.map +1 -1
  273. package/dist/modules/workspace/startup/steps/template-files.step.d.ts +17 -3
  274. package/dist/modules/workspace/startup/steps/template-files.step.d.ts.map +1 -1
  275. package/dist/modules/workspace/startup/steps/template-files.step.js +36 -30
  276. package/dist/modules/workspace/startup/steps/template-files.step.js.map +1 -1
  277. package/dist/modules/workspace/startup/steps/template-source.d.ts +6 -1
  278. package/dist/modules/workspace/startup/steps/template-source.d.ts.map +1 -1
  279. package/dist/modules/workspace/startup/steps/template-source.js +10 -6
  280. package/dist/modules/workspace/startup/steps/template-source.js.map +1 -1
  281. package/dist/modules/workspace/workspace.routes.d.ts +2 -1
  282. package/dist/modules/workspace/workspace.routes.d.ts.map +1 -1
  283. package/dist/modules/workspace/workspace.routes.js +8 -7
  284. package/dist/modules/workspace/workspace.routes.js.map +1 -1
  285. package/dist/modules/workspace/workspace.service.d.ts +18 -12
  286. package/dist/modules/workspace/workspace.service.d.ts.map +1 -1
  287. package/dist/modules/workspace/workspace.service.js +32 -28
  288. package/dist/modules/workspace/workspace.service.js.map +1 -1
  289. package/dist/modules/workspace/workspace.tools.d.ts +2 -1
  290. package/dist/modules/workspace/workspace.tools.d.ts.map +1 -1
  291. package/dist/modules/workspace/workspace.tools.js +20 -18
  292. package/dist/modules/workspace/workspace.tools.js.map +1 -1
  293. package/dist/modules/workspace/write-denial.d.ts +3 -2
  294. package/dist/modules/workspace/write-denial.d.ts.map +1 -1
  295. package/dist/modules/workspace/write-denial.js +6 -5
  296. package/dist/modules/workspace/write-denial.js.map +1 -1
  297. package/dist/shared/git.contract.d.ts +52 -7
  298. package/dist/shared/git.contract.d.ts.map +1 -1
  299. package/dist/shared/git.contract.js +30 -8
  300. package/dist/shared/git.contract.js.map +1 -1
  301. package/dist/shared/kb-context.d.ts +76 -0
  302. package/dist/shared/kb-context.d.ts.map +1 -0
  303. package/dist/shared/kb-context.js +108 -0
  304. package/dist/shared/kb-context.js.map +1 -0
  305. package/dist/shared/kb-layout.d.ts +3 -2
  306. package/dist/shared/kb-layout.d.ts.map +1 -1
  307. package/dist/shared/kb-layout.js +4 -3
  308. package/dist/shared/kb-layout.js.map +1 -1
  309. package/dist/shared/kb-layout.test.js +35 -27
  310. package/dist/shared/kb-layout.test.js.map +1 -1
  311. package/dist/shared/pending-proposals.d.ts +4 -1
  312. package/dist/shared/pending-proposals.d.ts.map +1 -1
  313. package/dist/shared/pending-proposals.js +3 -4
  314. package/dist/shared/pending-proposals.js.map +1 -1
  315. package/dist/shared/redact-secret.d.ts +5 -5
  316. package/dist/shared/redact-secret.js +5 -5
  317. package/dist/tenancy/index.d.ts +13 -0
  318. package/dist/tenancy/index.d.ts.map +1 -0
  319. package/dist/tenancy/index.js +13 -0
  320. package/dist/tenancy/index.js.map +1 -0
  321. package/dist/tenancy/static-tenant-source.d.ts +98 -0
  322. package/dist/tenancy/static-tenant-source.d.ts.map +1 -0
  323. package/dist/tenancy/static-tenant-source.js +220 -0
  324. package/dist/tenancy/static-tenant-source.js.map +1 -0
  325. package/dist/tenancy/tenant-host.d.ts +80 -0
  326. package/dist/tenancy/tenant-host.d.ts.map +1 -0
  327. package/dist/tenancy/tenant-host.js +217 -0
  328. package/dist/tenancy/tenant-host.js.map +1 -0
  329. package/dist/tenancy/tenant-runtime.d.ts +91 -0
  330. package/dist/tenancy/tenant-runtime.d.ts.map +1 -0
  331. package/dist/tenancy/tenant-runtime.js +174 -0
  332. package/dist/tenancy/tenant-runtime.js.map +1 -0
  333. package/dist/tenancy/tenant-secrets.d.ts +24 -0
  334. package/dist/tenancy/tenant-secrets.d.ts.map +1 -0
  335. package/dist/tenancy/tenant-secrets.js +30 -0
  336. package/dist/tenancy/tenant-secrets.js.map +1 -0
  337. package/dist/tenancy/tenant-source.contract.d.ts +45 -0
  338. package/dist/tenancy/tenant-source.contract.d.ts.map +1 -0
  339. package/dist/tenancy/tenant-source.contract.js +21 -0
  340. package/dist/tenancy/tenant-source.contract.js.map +1 -0
  341. package/migrations/0000_core_init.sql +14 -14
  342. package/migrations/0003_deployment_settings.sql +1 -1
  343. package/migrations/0005_github_facade.sql +1 -1
  344. package/migrations/0012_agent_audit.sql +6 -6
  345. package/package.json +3 -3
  346. package/src/__tests__/branch-model.test.ts +7 -6
  347. package/src/__tests__/kb-context.ts +30 -0
  348. package/src/__tests__/kb-layout-config.test.ts +35 -30
  349. package/src/core/__tests__/catalog-cache-invalidation.test.ts +2 -1
  350. package/src/core/__tests__/lifecycle.test.ts +78 -1
  351. package/src/core/__tests__/public-config.test.ts +5 -1
  352. package/src/core/catalog-cache-invalidation.ts +16 -11
  353. package/src/core/core-ports.ts +19 -0
  354. package/src/core/create-core-server.ts +27 -106
  355. package/src/core/create-core-services.ts +180 -95
  356. package/src/core/lifecycle.ts +214 -29
  357. package/src/core/public-config.ts +8 -5
  358. package/src/core-config.ts +107 -8
  359. package/src/index.ts +25 -2
  360. package/src/modules/access/__tests__/access-control.admin-root-floor.test.ts +2 -1
  361. package/src/modules/access/__tests__/access.routes.batch.test.ts +2 -1
  362. package/src/modules/access/__tests__/access.routes.folder-governs.test.ts +2 -1
  363. package/src/modules/access/__tests__/access.routes.group-grant.test.ts +2 -1
  364. package/src/modules/access/__tests__/access.routes.overrides.test.ts +2 -1
  365. package/src/modules/access/__tests__/access.routes.proposal-branch.test.ts +2 -1
  366. package/src/modules/access/__tests__/access.routes.prospective.test.ts +2 -1
  367. package/src/modules/access/__tests__/access.routes.revoke.test.ts +2 -1
  368. package/src/modules/access/__tests__/access.routes.unknown-email.test.ts +2 -1
  369. package/src/modules/access/__tests__/change-read-gate.test.ts +13 -11
  370. package/src/modules/access/__tests__/creator-access.test.ts +3 -2
  371. package/src/modules/access/__tests__/roles.routes.test.ts +2 -1
  372. package/src/modules/access/access-control.service.ts +20 -6
  373. package/src/modules/access/access.routes.ts +10 -13
  374. package/src/modules/access/change-read-gate.ts +10 -4
  375. package/src/modules/access/creator-access.ts +7 -2
  376. package/src/modules/agent-instructions/__tests__/read-preamble.test.ts +13 -12
  377. package/src/modules/agent-instructions/read-preamble.ts +10 -12
  378. package/src/modules/auth/__tests__/account.routes.test.ts +15 -0
  379. package/src/modules/auth/__tests__/auth.service.test.ts +60 -0
  380. package/src/modules/auth/account-admission.ts +44 -0
  381. package/src/modules/auth/account.routes.ts +4 -1
  382. package/src/modules/auth/auth.service.ts +33 -1
  383. package/src/modules/auth/oidc-auth-provider.ts +9 -0
  384. package/src/modules/connection-probe/connection-probe.service.ts +7 -1
  385. package/src/modules/database/__tests__/advisory-lock.test.ts +23 -1
  386. package/src/modules/database/__tests__/connection.test.ts +98 -0
  387. package/src/modules/database/__tests__/migrations-unqualified.test.ts +32 -0
  388. package/src/modules/database/advisory-lock.ts +28 -4
  389. package/src/modules/database/connection.ts +143 -13
  390. package/src/modules/database/migrate.ts +48 -14
  391. package/src/modules/diff/__tests__/diff.service.seed-atomicity.test.ts +2 -1
  392. package/src/modules/diff/__tests__/diff.service.test.ts +2 -1
  393. package/src/modules/kb-fs/__tests__/branch-name.test.ts +6 -6
  394. package/src/modules/kb-fs/__tests__/clone-config.test.ts +24 -20
  395. package/src/modules/kb-fs/branch-name.ts +3 -3
  396. package/src/modules/kb-fs/clone-config.ts +15 -12
  397. package/src/modules/marketplace/__tests__/marketplace-repo.head.test.ts +2 -1
  398. package/src/modules/mcp/mcp.service.ts +11 -4
  399. package/src/modules/plugins/__tests__/bundle-dialect.e2e.test.ts +12 -11
  400. package/src/modules/plugins/__tests__/bundle-dialect.test.ts +2 -1
  401. package/src/modules/plugins/__tests__/compile-marketplace.test.ts +6 -4
  402. package/src/modules/plugins/__tests__/join-request-jobs.service.test.ts +2 -1
  403. package/src/modules/plugins/__tests__/join-requests.service.test.ts +2 -1
  404. package/src/modules/plugins/__tests__/plugin-creation-display-name.test.ts +4 -3
  405. package/src/modules/plugins/__tests__/plugin-index.service.test.ts +6 -4
  406. package/src/modules/plugins/__tests__/plugin-links.service.test.ts +220 -5
  407. package/src/modules/plugins/__tests__/plugin-provision.service.test.ts +3 -1
  408. package/src/modules/plugins/__tests__/plugin-rename.service.test.ts +7 -6
  409. package/src/modules/plugins/__tests__/plugins.routes.test.ts +11 -2
  410. package/src/modules/plugins/__tests__/teams.routes.test.ts +2 -1
  411. package/src/modules/plugins/compile/marketplace-compiler.service.ts +7 -9
  412. package/src/modules/plugins/discovery/__tests__/kb-plugin-source.test.ts +20 -16
  413. package/src/modules/plugins/discovery/bundle-dialect/bundle.source.ts +9 -2
  414. package/src/modules/plugins/discovery/kb-plugin-source.ts +15 -8
  415. package/src/modules/plugins/discovery/native.source.ts +4 -1
  416. package/src/modules/plugins/index.ts +1 -1
  417. package/src/modules/plugins/join-request-jobs.service.ts +8 -7
  418. package/src/modules/plugins/join-requests.service.ts +7 -7
  419. package/src/modules/plugins/plugin-links.service.ts +192 -19
  420. package/src/modules/plugins/plugin-links.ts +147 -27
  421. package/src/modules/plugins/plugin-provision.service.ts +54 -27
  422. package/src/modules/plugins/plugin-rename.service.ts +10 -10
  423. package/src/modules/plugins/plugins.routes.ts +45 -15
  424. package/src/modules/plugins/plugins.service.ts +7 -11
  425. package/src/modules/plugins/teams.routes.ts +16 -8
  426. package/src/modules/secrets-vault/__tests__/connect-pending.route.test.ts +7 -0
  427. package/src/modules/secrets-vault/__tests__/secrets-variable-loader.test.ts +40 -0
  428. package/src/modules/secrets-vault/__tests__/tool-owner-gate.route.test.ts +2 -0
  429. package/src/modules/secrets-vault/index.ts +2 -0
  430. package/src/modules/secrets-vault/secrets-variable-loader.ts +51 -21
  431. package/src/modules/secrets-vault/secrets-vault.routes.ts +7 -6
  432. package/src/modules/settings/__tests__/deployment-settings.service.test.ts +24 -11
  433. package/src/modules/settings/__tests__/git-root-folders.test.ts +2 -1
  434. package/src/modules/settings/__tests__/setup.routes.boot-failure.test.ts +2 -1
  435. package/src/modules/settings/__tests__/setup.routes.layout-phase.test.ts +7 -4
  436. package/src/modules/settings/__tests__/setup.routes.oidc.test.ts +2 -0
  437. package/src/modules/settings/__tests__/setup.routes.sync-status.test.ts +2 -0
  438. package/src/modules/settings/__tests__/setup.routes.test.ts +33 -52
  439. package/src/modules/settings/deployment-settings.service.ts +21 -20
  440. package/src/modules/settings/setup.routes.ts +26 -16
  441. package/src/modules/skills/__tests__/allowed-tools-check.test.ts +11 -10
  442. package/src/modules/skills/__tests__/allowed-tools-warn.tools.test.ts +4 -3
  443. package/src/modules/skills/__tests__/pending-skills.service.test.ts +3 -1
  444. package/src/modules/skills/__tests__/skill-access-requests.routes.test.ts +2 -1
  445. package/src/modules/skills/__tests__/skills.routes.warnings.test.ts +2 -1
  446. package/src/modules/skills/__tests__/skills.service.test.ts +3 -2
  447. package/src/modules/skills/allowed-tools-check.ts +7 -6
  448. package/src/modules/skills/pending-skills.service.ts +9 -8
  449. package/src/modules/skills/skill-access-requests.routes.ts +7 -7
  450. package/src/modules/skills/skills.routes.ts +4 -3
  451. package/src/modules/skills/skills.service.ts +13 -9
  452. package/src/modules/tool-helpers/__tests__/agent-roles-write.test.ts +3 -2
  453. package/src/modules/tool-helpers/__tests__/phase4-tools.test.ts +3 -2
  454. package/src/modules/tool-manuals/__tests__/mcp-json-discovery.test.ts +17 -12
  455. package/src/modules/tool-manuals/__tests__/mcp-server-edit.service.test.ts +2 -1
  456. package/src/modules/tool-manuals/__tests__/pending-tools.service.test.ts +4 -1
  457. package/src/modules/tool-manuals/__tests__/tool-delete.service.test.ts +2 -1
  458. package/src/modules/tool-manuals/__tests__/tool-manuals.archive.route.test.ts +2 -1
  459. package/src/modules/tool-manuals/__tests__/tool-manuals.cli.test.ts +5 -4
  460. package/src/modules/tool-manuals/__tests__/tool-manuals.detail.route.test.ts +2 -1
  461. package/src/modules/tool-manuals/__tests__/tool-manuals.invalid.routes.test.ts +4 -2
  462. package/src/modules/tool-manuals/__tests__/tool-manuals.invalid.test.ts +13 -5
  463. package/src/modules/tool-manuals/__tests__/tool-manuals.mcp-oauth.test.ts +2 -1
  464. package/src/modules/tool-manuals/__tests__/tool-manuals.restart.test.ts +9 -1
  465. package/src/modules/tool-manuals/__tests__/tool-manuals.service.test.ts +3 -2
  466. package/src/modules/tool-manuals/__tests__/tool-manuals.tools.test.ts +2 -0
  467. package/src/modules/tool-manuals/mcp-json-discovery.ts +6 -4
  468. package/src/modules/tool-manuals/mcp-server-edit.service.ts +13 -11
  469. package/src/modules/tool-manuals/pending-tools.service.ts +19 -16
  470. package/src/modules/tool-manuals/tool-delete.service.ts +13 -10
  471. package/src/modules/tool-manuals/tool-manuals.routes.ts +10 -8
  472. package/src/modules/tool-manuals/tool-manuals.service.ts +15 -13
  473. package/src/modules/tool-manuals/tool-manuals.tools.ts +7 -6
  474. package/src/modules/workflow/__tests__/apply-failure.test.ts +2 -1
  475. package/src/modules/workflow/__tests__/merge-announces-tree.test.ts +14 -26
  476. package/src/modules/workflow/__tests__/preserve-roles-yaml.test.ts +2 -1
  477. package/src/modules/workflow/__tests__/session-ontology.service.test.ts +3 -2
  478. package/src/modules/workflow/__tests__/workflow.routes.lock-path.test.ts +2 -1
  479. package/src/modules/workflow/__tests__/workflow.service.branch-in-use.test.ts +3 -10
  480. package/src/modules/workflow/__tests__/workflow.service.commitFileWhileLocked.test.ts +2 -1
  481. package/src/modules/workflow/__tests__/workflow.service.deleted-branch-sweep.test.ts +3 -10
  482. package/src/modules/workflow/__tests__/workflow.service.facade.test.ts +28 -27
  483. package/src/modules/workflow/__tests__/workflow.service.folder-proposals.test.ts +2 -1
  484. package/src/modules/workflow/__tests__/workflow.service.platform-restore.test.ts +2 -1
  485. package/src/modules/workflow/__tests__/workflow.service.read-gate.test.ts +3 -2
  486. package/src/modules/workflow/__tests__/workflow.service.releaseLock.test.ts +2 -1
  487. package/src/modules/workflow/__tests__/workflow.service.sync.test.ts +5 -4
  488. package/src/modules/workflow/__tests__/workflow.service.update-from-target.test.ts +2 -1
  489. package/src/modules/workflow/agent-tools/__tests__/workflow.tools.test.ts +2 -1
  490. package/src/modules/workflow/agent-tools/workflow.tools.ts +11 -9
  491. package/src/modules/workflow/git/__tests__/git.service.accessGating.test.ts +5 -4
  492. package/src/modules/workflow/git/__tests__/git.service.changedFilesForPr.test.ts +12 -11
  493. package/src/modules/workflow/git/__tests__/git.service.commitChanges.test.ts +9 -8
  494. package/src/modules/workflow/git/__tests__/git.service.commitFile.strayPath.test.ts +8 -7
  495. package/src/modules/workflow/git/__tests__/git.service.commitFile.test.ts +6 -5
  496. package/src/modules/workflow/git/__tests__/git.service.createBranch.test.ts +3 -2
  497. package/src/modules/workflow/git/__tests__/git.service.deleteBranch.test.ts +3 -2
  498. package/src/modules/workflow/git/__tests__/git.service.diffFileAtCommit.test.ts +7 -6
  499. package/src/modules/workflow/git/__tests__/git.service.diffFileBetweenBranches.test.ts +16 -15
  500. package/src/modules/workflow/git/__tests__/git.service.fileContentsAtCommit.test.ts +3 -2
  501. package/src/modules/workflow/git/__tests__/git.service.forkPoint.test.ts +2 -1
  502. package/src/modules/workflow/git/__tests__/git.service.history-guards.test.ts +2 -1
  503. package/src/modules/workflow/git/__tests__/git.service.list-branches.test.ts +10 -9
  504. package/src/modules/workflow/git/__tests__/git.service.listTrackedFiles.test.ts +2 -1
  505. package/src/modules/workflow/git/__tests__/git.service.logForFile.test.ts +6 -5
  506. package/src/modules/workflow/git/__tests__/git.service.mergeChangeRequest.test.ts +9 -8
  507. package/src/modules/workflow/git/__tests__/git.service.pendingChanges.test.ts +2 -1
  508. package/src/modules/workflow/git/__tests__/git.service.postMergePull.test.ts +4 -3
  509. package/src/modules/workflow/git/__tests__/git.service.pull.test.ts +9 -8
  510. package/src/modules/workflow/git/__tests__/git.service.readFileAtRef.test.ts +2 -1
  511. package/src/modules/workflow/git/__tests__/git.service.revertPathsAndPush.test.ts +2 -1
  512. package/src/modules/workflow/git/__tests__/git.service.status.test.ts +4 -3
  513. package/src/modules/workflow/git/__tests__/git.service.syncFromRemote.test.ts +8 -7
  514. package/src/modules/workflow/git/__tests__/node-git-runner.test.ts +41 -3
  515. package/src/modules/workflow/git/git.service.ts +24 -13
  516. package/src/modules/workflow/git/node-git-runner.ts +37 -4
  517. package/src/modules/workflow/review-workflow/review-workflow.service.ts +9 -6
  518. package/src/modules/workflow/session-ontology.service.ts +7 -2
  519. package/src/modules/workflow/workflow.service.ts +31 -24
  520. package/src/modules/workspace/__tests__/file-stat-access.test.ts +3 -2
  521. package/src/modules/workspace/__tests__/git-internals.security.test.ts +10 -9
  522. package/src/modules/workspace/__tests__/session-ontology.gate.test.ts +4 -2
  523. package/src/modules/workspace/__tests__/workspace-paths-inside-the-repo.test.ts +3 -2
  524. package/src/modules/workspace/__tests__/workspace.routes.branch-errors.test.ts +2 -1
  525. package/src/modules/workspace/__tests__/workspace.routes.create-grant.test.ts +2 -1
  526. package/src/modules/workspace/__tests__/workspace.routes.delete.test.ts +2 -1
  527. package/src/modules/workspace/__tests__/workspace.routes.download-implies-read.test.ts +2 -1
  528. package/src/modules/workspace/__tests__/workspace.routes.download.test.ts +2 -1
  529. package/src/modules/workspace/__tests__/workspace.routes.file-writes.test.ts +2 -1
  530. package/src/modules/workspace/__tests__/workspace.routes.folders.test.ts +5 -4
  531. package/src/modules/workspace/__tests__/workspace.routes.move-platform-files.test.ts +2 -1
  532. package/src/modules/workspace/__tests__/workspace.routes.read-gate.test.ts +2 -1
  533. package/src/modules/workspace/__tests__/workspace.service.ensure-remotes-fetched.test.ts +2 -2
  534. package/src/modules/workspace/__tests__/workspace.service.list-cloned.test.ts +6 -5
  535. package/src/modules/workspace/__tests__/workspace.service.move-never-overwrites.test.ts +2 -1
  536. package/src/modules/workspace/__tests__/workspace.service.read-filter.test.ts +2 -1
  537. package/src/modules/workspace/__tests__/workspace.service.test.ts +84 -50
  538. package/src/modules/workspace/__tests__/workspace.service.unknown-branch.test.ts +2 -1
  539. package/src/modules/workspace/__tests__/workspace.tools.agents-file.test.ts +10 -7
  540. package/src/modules/workspace/__tests__/workspace.tools.branch-errors.test.ts +4 -3
  541. package/src/modules/workspace/__tests__/workspace.tools.test.ts +9 -8
  542. package/src/modules/workspace/__tests__/write-denial.test.ts +5 -4
  543. package/src/modules/workspace/session-ontology.gate.ts +6 -4
  544. package/src/modules/workspace/startup/__tests__/kb-startup-runner.degraded.test.ts +6 -2
  545. package/src/modules/workspace/startup/__tests__/kb-startup-runner.test.ts +29 -21
  546. package/src/modules/workspace/startup/kb-git.ts +15 -22
  547. package/src/modules/workspace/startup/kb-startup-runner.ts +40 -46
  548. package/src/modules/workspace/startup/steps/__tests__/steps.test.ts +104 -98
  549. package/src/modules/workspace/startup/steps/groups-to-plugins.step.ts +24 -16
  550. package/src/modules/workspace/startup/steps/personal-spaces.step.ts +14 -5
  551. package/src/modules/workspace/startup/steps/plugin-display-names.step.ts +13 -5
  552. package/src/modules/workspace/startup/steps/plugin-manifests.step.ts +14 -5
  553. package/src/modules/workspace/startup/steps/seed-tree.ts +11 -9
  554. package/src/modules/workspace/startup/steps/template-files.step.ts +43 -34
  555. package/src/modules/workspace/startup/steps/template-source.ts +8 -5
  556. package/src/modules/workspace/workspace.routes.ts +8 -7
  557. package/src/modules/workspace/workspace.service.ts +30 -27
  558. package/src/modules/workspace/workspace.tools.ts +21 -20
  559. package/src/modules/workspace/write-denial.ts +7 -5
  560. package/src/shared/__tests__/kb-layout.plugin.test.ts +19 -16
  561. package/src/shared/git.contract.ts +70 -8
  562. package/src/shared/kb-context.ts +130 -0
  563. package/src/shared/kb-layout.test.ts +37 -27
  564. package/src/shared/kb-layout.ts +4 -3
  565. package/src/shared/pending-proposals.ts +7 -4
  566. package/src/shared/redact-secret.ts +5 -5
  567. package/src/tenancy/__tests__/static-tenant-source.test.ts +177 -0
  568. package/src/tenancy/__tests__/tenant-host.test.ts +372 -0
  569. package/src/tenancy/__tests__/tenant-runtime.test.ts +221 -0
  570. package/src/tenancy/__tests__/tenant-secrets.test.ts +35 -0
  571. package/src/tenancy/index.ts +35 -0
  572. package/src/tenancy/static-tenant-source.ts +296 -0
  573. package/src/tenancy/tenant-host.ts +261 -0
  574. package/src/tenancy/tenant-runtime.ts +208 -0
  575. package/src/tenancy/tenant-secrets.ts +41 -0
  576. package/src/tenancy/tenant-source.contract.ts +59 -0
@@ -9,7 +9,6 @@ import type { IAdminAccessService } from '../admin/admin.interface.js';
9
9
  import express from 'express';
10
10
  import type { AuthUser, IWorkflowService } from '@bevel-software/platform-shared';
11
11
  import {
12
- DEFAULT_BRANCH,
13
12
  KNOWLEDGE_DIR,
14
13
  canonicalRelativePath,
15
14
  folderPlaceholderPath,
@@ -21,6 +20,7 @@ import {
21
20
  } from '@bevel-software/platform-shared';
22
21
  import { FolderTooLargeError, type ReadTreeFilter } from './workspace.service.js';
23
22
  import { branchForWorkspaceId } from '../../shared/workspace-id.js';
23
+ import type { KbContext } from '../../shared/kb-context.js';
24
24
  import { EntryExistsError, type WorkspaceService } from './workspace.service.js';
25
25
  import type { AuthService } from '../auth/auth.service.js';
26
26
  import type { IAccessControl } from '../access/access-control.interface.js';
@@ -82,7 +82,7 @@ export function createWorkspaceRoutes(
82
82
  workflowService: IWorkflowService,
83
83
  eventBus: WorkflowEventBus,
84
84
  accessControl: IAccessControl,
85
- kbDirName: string,
85
+ kb: KbContext,
86
86
  creatorAccess: ICreatorAccess,
87
87
  adminAccess: IAdminAccessService,
88
88
  disk: ITreeWalker,
@@ -97,6 +97,7 @@ export function createWorkspaceRoutes(
97
97
  changeGate?: IChangeReadGate,
98
98
  ): express.Router {
99
99
  const router = express.Router();
100
+ const { kbDirName } = kb;
100
101
  const gitInternalsRouteGuard = createGitInternalsRouteGuard(workspaceService);
101
102
 
102
103
  // The git folder is refused ahead of every route here by
@@ -463,7 +464,7 @@ export function createWorkspaceRoutes(
463
464
  }
464
465
  const branch = typeof req.query.branch === 'string' && req.query.branch.length > 0
465
466
  ? req.query.branch
466
- : DEFAULT_BRANCH;
467
+ : kb.defaultBranch;
467
468
  const workspace = await workspaceService.getOrCreateForBranch(branch);
468
469
  // Bootstrap must use the same read-filtered tree as GET /workspace/:id/files.
469
470
  // Otherwise the first sidebar render can expose restricted nodes until the
@@ -663,7 +664,7 @@ export function createWorkspaceRoutes(
663
664
  // same treatment so legacy clones don't collapse. Only the folders
664
665
  // themselves are forced visible — their contents stay gated by the
665
666
  // verdict above.
666
- const structuralRoots = new Set([...reservedRootDirNames(), KNOWLEDGE_DIR]);
667
+ const structuralRoots = new Set([...reservedRootDirNames(kb.layout), KNOWLEDGE_DIR]);
667
668
  for (const wp of wsRelPaths) {
668
669
  const rel = toKbRelative(wp, kbDirName);
669
670
  if (rel !== null && structuralRoots.has(rel)) verdict.set(wp, true);
@@ -1128,11 +1129,11 @@ export function createWorkspaceRoutes(
1128
1129
  const oldRel = toKbRelative(oldPath, kbDirName);
1129
1130
  const newRel = toKbRelative(newPath, kbDirName);
1130
1131
  let platformRestore = false;
1131
- if (oldRel !== null && newRel !== null && isPlatformRestoreShape(oldRel, newRel)) {
1132
+ if (oldRel !== null && newRel !== null && isPlatformRestoreShape(oldRel, newRel, kb.layout)) {
1132
1133
  platformRestore = await accessControl.canRestorePlatformFile(id, user.email, newRel);
1133
1134
  }
1134
1135
  // A platform file stays where the platform reads it …
1135
- if (oldRel !== null && isPlatformFile(oldRel) && !platformRestore) {
1136
+ if (oldRel !== null && isPlatformFile(oldRel, kb.layout) && !platformRestore) {
1136
1137
  res.status(409).json({ error: platformFileRefusal(oldRel) });
1137
1138
  return;
1138
1139
  }
@@ -1145,7 +1146,7 @@ export function createWorkspaceRoutes(
1145
1146
  // from the same place. Only the restore lands on a platform path, and
1146
1147
  // only where the file is missing (`canRestorePlatformFile` checked the
1147
1148
  // disk; the destination lock below checks it again, under the lock).
1148
- if (newRel !== null && isPlatformFile(newRel) && !platformRestore) {
1149
+ if (newRel !== null && isPlatformFile(newRel, kb.layout) && !platformRestore) {
1149
1150
  res.status(409).json({ error: platformFileCreationRefusal(newRel) });
1150
1151
  return;
1151
1152
  }
@@ -9,7 +9,6 @@ import { AsyncLocalStorage } from 'node:async_hooks';
9
9
  import {
10
10
  validateRelativePath,
11
11
  validateFilename,
12
- DEFAULT_BRANCH,
13
12
  FOLDER_PLACEHOLDER,
14
13
  isFolderPlaceholder,
15
14
  entryExistsMessage,
@@ -22,6 +21,7 @@ import {
22
21
  renameNoReplace,
23
22
  } from '../../shared/rename-no-replace.js';
24
23
  import type { IGitRunner } from '../../shared/git.contract.js';
24
+ import type { KbContext } from '../../shared/kb-context.js';
25
25
  import { NodeGitRunner } from '../workflow/git/node-git-runner.js';
26
26
  import { assertWithinDirectory } from '../../shared/path-containment.js';
27
27
  import { assertRepoRootNameFree, normalizeWorkspacePath } from '../kb-fs/repo-path.js';
@@ -149,9 +149,8 @@ const CLONE_TIMEOUT_MS = 600_000;
149
149
  const BOT_NAME = 'Bevel Workflow';
150
150
  const BOT_EMAIL = 'bevel-workflow@bevel.software';
151
151
 
152
- /** Redact any token that might leak into an error message. */
153
- function redactError(err: unknown): string {
154
- const token = process.env.GITHUB_TOKEN;
152
+ /** Redact the token the runner authenticates with from an error message. */
153
+ function redactError(err: unknown, token: string | null): string {
155
154
  const msg = err instanceof Error ? err.message : String(err);
156
155
  return token ? msg.replaceAll(token, '***') : msg;
157
156
  }
@@ -297,23 +296,26 @@ export class WorkspaceService implements IWorkspaceService {
297
296
  * buy an inconsistency rather than a feature.
298
297
  */
299
298
  kbRepoUrl: string | (() => string),
300
- private readonly kbDirName: string,
299
+ /** The checkout folder's name, and which branch a caller lands on when naming none. */
300
+ private readonly kb: Pick<KbContext, 'kbDirName' | 'defaultBranch'>,
301
301
  private readonly disk: ITreeWalker,
302
- gitUsername: string | (() => string) = 'x-access-token',
303
302
  /**
304
303
  * How git is run — see `shared/git.contract.ts`. The composition root
305
- * passes the one runner carrying the deployment's deadline; the default
306
- * is the same runner on its default deadline, for a directly constructed
307
- * service.
304
+ * passes the one runner carrying the deployment's deadline and the
305
+ * credentials every clone authenticates with; the default is the same
306
+ * runner on its default deadline and no token, for a directly
307
+ * constructed service.
308
308
  */
309
309
  private readonly gitRunner: IGitRunner = new NodeGitRunner(),
310
310
  ) {
311
311
  this.kbRepoUrl = typeof kbRepoUrl === 'function' ? kbRepoUrl : () => kbRepoUrl;
312
- this.gitUsername = typeof gitUsername === 'function' ? gitUsername : () => gitUsername;
312
+ }
313
+
314
+ private get kbDirName(): string {
315
+ return this.kb.kbDirName;
313
316
  }
314
317
 
315
318
  private readonly kbRepoUrl: () => string;
316
- private readonly gitUsername: () => string;
317
319
 
318
320
  setDiffService(diffService: IDiffService): void {
319
321
  this.diffService = diffService;
@@ -417,7 +419,7 @@ export class WorkspaceService implements IWorkspaceService {
417
419
  // Persisted into the new repo's config (`clone --config`), not just applied
418
420
  // to this invocation — every later push from this clone depends on finding
419
421
  // the helper there. See `cloneCredentialArgs`.
420
- args.push(...cloneCredentialArgs(this.gitUsername()));
422
+ args.push(...cloneCredentialArgs(this.gitRunner.credentials));
421
423
  args.push(this.kbRepoUrl(), targetDir);
422
424
  return args;
423
425
  }
@@ -531,7 +533,7 @@ export class WorkspaceService implements IWorkspaceService {
531
533
  cloned.push({
532
534
  id: entry.name,
533
535
  branch,
534
- unreadable: `Could not read this branch's clone: ${redactError(err)}`,
536
+ unreadable: `Could not read this branch's clone: ${redactError(err, this.gitRunner.credentials.token())}`,
535
537
  });
536
538
  continue;
537
539
  }
@@ -566,7 +568,7 @@ export class WorkspaceService implements IWorkspaceService {
566
568
  return;
567
569
  } catch (err) {
568
570
  log.warn(`referenced clone for "${branch}" failed, retrying without reference:`, {
569
- detail: redactError(err),
571
+ detail: redactError(err, this.gitRunner.credentials.token()),
570
572
  });
571
573
  // Clear any partial output so the retry clones into a clean dir.
572
574
  await fs.rm(targetDir, { recursive: true, force: true }).catch(() => {});
@@ -675,7 +677,7 @@ export class WorkspaceService implements IWorkspaceService {
675
677
  * `branch` is passed.
676
678
  */
677
679
  async getOrCreateForUser(_user: AuthUser, branch?: string): Promise<WorkspaceInfo> {
678
- return this.getOrCreateForBranch(branch ?? DEFAULT_BRANCH);
680
+ return this.getOrCreateForBranch(branch ?? this.kb.defaultBranch);
679
681
  }
680
682
 
681
683
  private buildWorkspaceInfo(branch: string, workspaceDir: string): WorkspaceInfo {
@@ -741,7 +743,7 @@ export class WorkspaceService implements IWorkspaceService {
741
743
  } catch (err) {
742
744
  // One line per branch, not per key: every key writes to the same
743
745
  // `.git/config`, so what fails for one fails for all.
744
- log.warn(`could not normalize the config of the "${branch}" clone:`, { detail: redactError(err) });
746
+ log.warn(`could not normalize the config of the "${branch}" clone:`, { detail: redactError(err, this.gitRunner.credentials.token()) });
745
747
  }
746
748
  await this.stampCredentialHelper(repoDir, branch);
747
749
  }
@@ -750,12 +752,13 @@ export class WorkspaceService implements IWorkspaceService {
750
752
  * Fingerprint of the credential state a clone's helper is derived from: the
751
753
  * username (baked into the helper literal) and whether a token exists at all
752
754
  * (the helper is present-or-absent on that). The token VALUE is deliberately
753
- * excluded — the helper reads `$GITHUB_TOKEN` at call time, so rotating the
754
- * token needs no re-stamp; only a username change or a token appearing /
755
- * disappearing does.
755
+ * excluded — the helper reads `$GITHUB_TOKEN` from the environment the
756
+ * runner hands each git call, so rotating the token needs no re-stamp; only
757
+ * a username change or a token appearing / disappearing does.
756
758
  */
757
759
  private credentialFingerprint(): string {
758
- return `${this.gitUsername()}::${process.env.GITHUB_TOKEN ? '1' : '0'}`;
760
+ const { credentials } = this.gitRunner;
761
+ return `${credentials.username()}::${credentials.token() ? '1' : '0'}`;
759
762
  }
760
763
 
761
764
  /** Last credential fingerprint stamped into each branch's clone, this process. */
@@ -772,7 +775,7 @@ export class WorkspaceService implements IWorkspaceService {
772
775
  private async stampCredentialHelper(repoDir: string, branch: string): Promise<void> {
773
776
  let argLists: string[][];
774
777
  try {
775
- argLists = cloneCredentialConfigArgs(this.gitUsername());
778
+ argLists = cloneCredentialConfigArgs(this.gitRunner.credentials);
776
779
  } catch (err) {
777
780
  // `credentialHelperValue` fails closed on a username outside its safe
778
781
  // charset. Normally unreachable (CoreConfig and the settings service
@@ -782,7 +785,7 @@ export class WorkspaceService implements IWorkspaceService {
782
785
  // re-clone that fails on the same validation — masking the real cause.
783
786
  // Contain it as a loud non-stamp instead; `normalizeCloneConfig`'s
784
787
  // never-throws contract stays true.
785
- log.warn(`refusing to stamp the credential helper of the "${branch}" clone:`, { detail: redactError(err) });
788
+ log.warn(`refusing to stamp the credential helper of the "${branch}" clone:`, { detail: redactError(err, this.gitRunner.credentials.token()) });
786
789
  this.stampedCredentialFingerprint.delete(branch);
787
790
  return;
788
791
  }
@@ -798,7 +801,7 @@ export class WorkspaceService implements IWorkspaceService {
798
801
  if (!(args.includes('--unset-all') && code === 5)) {
799
802
  stamped = false;
800
803
  log.warn(`could not stamp the credential helper of the "${branch}" clone:`, {
801
- detail: redactError(err),
804
+ detail: redactError(err, this.gitRunner.credentials.token()),
802
805
  });
803
806
  }
804
807
  }
@@ -914,11 +917,11 @@ export class WorkspaceService implements IWorkspaceService {
914
917
  this.onWorkspaceCloned?.(workspaceIdForBranch(branch));
915
918
  } catch (listenerErr) {
916
919
  log.error(`onWorkspaceCloned listener failed for branch "${branch}":`, {
917
- detail: redactError(listenerErr),
920
+ detail: redactError(listenerErr, this.gitRunner.credentials.token()),
918
921
  });
919
922
  }
920
923
  } catch (err) {
921
- const redacted = redactError(err);
924
+ const redacted = redactError(err, this.gitRunner.credentials.token());
922
925
  // Roll back partial state so the next bootstrap retries cleanly.
923
926
  await fs.rm(targetDir, { recursive: true, force: true }).catch(() => {});
924
927
  // A branch origin does not have is a fact about the branch, not a
@@ -936,7 +939,7 @@ export class WorkspaceService implements IWorkspaceService {
936
939
  // two stories this is — and guessing either one states something
937
940
  // about the branch that we do not know. Our failure, so: 500.
938
941
  log.error(`Could not tell whether branch "${branch}" was ever known here:`, {
939
- detail: redactError(probeErr),
942
+ detail: redactError(probeErr, this.gitRunner.credentials.token()),
940
943
  });
941
944
  throw new Error(`Failed to clone process map: ${redacted}`);
942
945
  }
@@ -1255,7 +1258,7 @@ export class WorkspaceService implements IWorkspaceService {
1255
1258
  })
1256
1259
  .catch((err) => {
1257
1260
  this.lastFetchOk.set(repoDir, false);
1258
- log.warn('git fetch origin failed:', { detail: redactError(err) });
1261
+ log.warn('git fetch origin failed:', { detail: redactError(err, this.gitRunner.credentials.token()) });
1259
1262
  })
1260
1263
  .finally(() => {
1261
1264
  if (this.inFlightFetches.get(repoDir) === promise) {
@@ -39,21 +39,20 @@ import { createFileReaderRegistry } from './file-readers/file-reader.registry.js
39
39
  import { DocumentReader } from './file-readers/document-reader.js';
40
40
  import { mcpImageResult } from '@bevel-software/platform-mcp-core';
41
41
  import {
42
- AGENTS_FILE,
43
42
  LEGACY_AGENTS_FILE,
44
43
  folderPlaceholderPath,
45
44
  isFolderPlaceholder,
46
45
  isPlatformFile,
47
46
  isPlatformFolder,
48
- isProtectedBranch,
49
- onKbLayoutApplied,
50
47
  platformFileCreationRefusal,
51
48
  platformFileNames,
52
49
  platformFileRefusal,
53
50
  platformFolderRefusal,
54
51
  entryExistsMessage,
55
52
  type ExistingEntryKind,
53
+ type KbLayout,
56
54
  } from '@bevel-software/platform-shared';
55
+ import type { KbContext } from '../../shared/kb-context.js';
57
56
  import { AccessDeniedError } from '../access-model/access-errors.js';
58
57
  import { removeEmptyDirs } from './empty-dirs.js';
59
58
  import { PROPOSAL_ROUTE_NOTE, rethrowAsWriteDenial } from './write-denial.js';
@@ -216,22 +215,23 @@ async function keepFolderOf(
216
215
  * working in their knowledge base. Under the default name the wording collapses
217
216
  * to the one file it has always named.
218
217
  *
219
- * A FUNCTION, called at mount time: the name is a deployment setting applied at
220
- * boot, and a module-scope string would snapshot the default.
218
+ * A FUNCTION of the layout, called when a description is built: the name is a
219
+ * deployment setting, and a module-scope string would snapshot the default.
221
220
  */
222
- function kbConventionsNote(): string {
223
- if (AGENTS_FILE === LEGACY_AGENTS_FILE) {
221
+ function kbConventionsNote(layout: KbLayout): string {
222
+ const agentsFile = layout.agentsFile ?? LEGACY_AGENTS_FILE;
223
+ if (agentsFile === LEGACY_AGENTS_FILE) {
224
224
  return ' Before your first read or change in a workspace, read `AGENTS.md` at the KB root — or `CLAUDE.md` on a knowledge base seeded before it was renamed — if either exists: it holds the author\'s conventions for this knowledge base, and you should follow them.';
225
225
  }
226
226
  return (
227
- ` Before your first read or change in a workspace, read \`${AGENTS_FILE}\` at the KB root, then ` +
227
+ ` Before your first read or change in a workspace, read \`${agentsFile}\` at the KB root, then ` +
228
228
  '`AGENTS.md` if it also exists (the organisation\'s own conventions) — or `CLAUDE.md` on a knowledge base seeded before it was renamed: together they hold the conventions for this knowledge base, and you should follow them.'
229
229
  );
230
230
  }
231
231
 
232
232
  /** The platform files as a tool description lists them — the guide under its own name. */
233
- function platformFileList(): string {
234
- return platformFileNames()
233
+ function platformFileList(layout: KbLayout): string {
234
+ return platformFileNames(layout)
235
235
  .map((name) => `\`${name}\``)
236
236
  .join(', ');
237
237
  }
@@ -679,7 +679,7 @@ export function registerWorkspaceTools(
679
679
  spillStore: SpillStore,
680
680
  docExtract: DocExtractService,
681
681
  accessControl: IAccessControl,
682
- kbDirName: string,
682
+ kb: KbContext,
683
683
  sessionOntologyGate: SessionOntologyGate,
684
684
  writePolicy: IRoutineWritePolicy,
685
685
  sessionSink: ISessionSink,
@@ -697,6 +697,7 @@ export function registerWorkspaceTools(
697
697
  */
698
698
  changeGate?: IChangeReadGate,
699
699
  ): void {
700
+ const { kbDirName } = kb;
700
701
  /**
701
702
  * The one extension→reader registry every read-shaped decision routes
702
703
  * through: read_file dispatches on it, grep asks it for searchable text,
@@ -871,7 +872,7 @@ export function registerWorkspaceTools(
871
872
  * branch only through a change request.
872
873
  */
873
874
  const writeBlocked = async (branch: string, ctx: ToolContext, paths: string[]): Promise<string[]> => {
874
- if (!isProtectedBranch(branch)) return [];
875
+ if (!kb.isProtectedBranch(branch)) return [];
875
876
  const byRel = new Map<string, string>();
876
877
  for (const p of paths) {
877
878
  const rel = toKbRelative(p, kbDirName);
@@ -934,11 +935,11 @@ export function registerWorkspaceTools(
934
935
  if (isGitMetadata(norm)) return `"${norm}" is git metadata and cannot be moved or deleted.`;
935
936
  if (kind === 'file') {
936
937
  const rel = toKbRelative(norm, kbDirName);
937
- return rel !== null && isPlatformFile(rel) ? platformFileRefusal(rel) : undefined;
938
+ return rel !== null && isPlatformFile(rel, kb.layout) ? platformFileRefusal(rel) : undefined;
938
939
  }
939
940
  if (norm === '' || norm === kbDirName) return platformFolderRefusal('');
940
941
  const rel = toKbRelative(norm, kbDirName);
941
- return rel !== null && isPlatformFolder(rel) ? platformFolderRefusal(rel) : undefined;
942
+ return rel !== null && isPlatformFolder(rel, kb.layout) ? platformFolderRefusal(rel) : undefined;
942
943
  };
943
944
 
944
945
  /** The workspace root on disk for `branch`. */
@@ -1181,7 +1182,7 @@ export function registerWorkspaceTools(
1181
1182
  (typeof spec.description === 'function' ? spec.description() : spec.description) +
1182
1183
  (spec.proposable ? PROPOSAL_ROUTE_NOTE : '') +
1183
1184
  (spec.fileTool === false ? '' : CONTENT_RULE) +
1184
- kbConventionsNote();
1185
+ kbConventionsNote(kb.layout);
1185
1186
  const def = toolDef({
1186
1187
  name: spec.name,
1187
1188
  description: describe(),
@@ -1199,7 +1200,7 @@ export function registerWorkspaceTools(
1199
1200
  // move the text with them. Rewritten in place: the registry holds this
1200
1201
  // object, both surfaces hold the same one, and re-registering would be a
1201
1202
  // duplicate name.
1202
- onKbLayoutApplied(() => {
1203
+ kb.onLayoutApplied(() => {
1203
1204
  def.description = describe();
1204
1205
  });
1205
1206
  // Internal-only tools (e.g. `execute_command`) keep their route mounted —
@@ -1250,7 +1251,7 @@ export function registerWorkspaceTools(
1250
1251
  err,
1251
1252
  { tool: spec.name, branch: args.branch, userEmail: ctx.user.email, userId: ctx.user.id },
1252
1253
  accessControl,
1253
- kbDirName,
1254
+ kb,
1254
1255
  changeGate,
1255
1256
  );
1256
1257
  }
@@ -1432,7 +1433,7 @@ export function registerWorkspaceTools(
1432
1433
  description: () =>
1433
1434
  'Get a file/directory\'s metadata (name, type, size, …) without returning content. A file also reports `contentMode`: `text` (read, write and edit it as text), `document` (read returns an extraction; replace it by upload) or `binary` (bytes: copy, move, delete, or replace by upload), plus `kind` (`text` | `document` | `image` | `binary`), `mime`, `mimeSource` and `textEditable` — decided by the same file readers read_file, grep and the write tools use, so an extensionless text file is `text/plain`.' +
1434
1435
  ' Every entry also reports what you may DO with it. ' +
1435
- `\`managed\` is true for a platform item — a platform file (${platformFileList()}) or a platform folder (the repository root or a reserved root folder such as \`KnowledgeBase/\`); managed items are never movable or deletable through these tools. ` +
1436
+ `\`managed\` is true for a platform item — a platform file (${platformFileList(kb.layout)}) or a platform folder (the repository root or a reserved root folder such as \`KnowledgeBase/\`); managed items are never movable or deletable through these tools. ` +
1436
1437
  '`access: { read, write, download, owner }` is your own verdict under the access rules; pass `explainAccess: true` to learn why, and who else holds each verb. `movable` and `deletable` say whether `move_file` / `delete_file` / `delete_folder` would be allowed for you, judged like their dry runs: not managed, no symbolic link, and on a protected branch you hold write on the item AND on every file under a folder (on a draft branch writes are not gated). `movable` judges the source side only; the destination is judged by a `move_file` dry run. ' +
1437
1438
  'For a folder, `descendants` is the number of files under it at any depth; counting stops at 10000 and `descendantsTruncated` says so, and past that point `movable` and `deletable` are false because a folder that large was not judged in full — run the `move_file` or `delete_folder` dry run for the real verdict. ' +
1438
1439
  'Call this before a move or delete to see what it would touch.' +
@@ -2042,7 +2043,7 @@ export function registerWorkspaceTools(
2042
2043
  name: 'delete_file',
2043
2044
  description: () =>
2044
2045
  'Delete ONE workspace file (a symbolic link is refused: links are never followed or removed). Committed + pushed as you. Its folder stays, even when this was its last file. Files only: a folder is refused with a pointer to `delete_folder`. ' +
2045
- `A platform file (\`access.md\` or \`.bevelignore\` in any folder, \`roles.yaml\` or \`${AGENTS_FILE}\` at the repository root) and git metadata are refused.` +
2046
+ `A platform file (\`access.md\` or \`.bevelignore\` in any folder, \`roles.yaml\` or \`${kb.layout.agentsFile}\` at the repository root) and git metadata are refused.` +
2046
2047
  ONTOLOGY_BOUNDARY_NOTE,
2047
2048
  inputs: {
2048
2049
  type: 'object',
@@ -2262,7 +2263,7 @@ export function registerWorkspaceTools(
2262
2263
  name: 'move_file',
2263
2264
  description: () =>
2264
2265
  'Move or rename a workspace FILE or FOLDER; a folder moves recursively, with everything under it. `dest` is the full new path, not the folder to move into. Lands as a delete + create, committed + pushed as you. ' +
2265
- `Rules: the destination must not exist — a move never overwrites a file or merges into a folder; a platform file (\`access.md\` or \`.bevelignore\` in any folder, \`roles.yaml\` or \`${AGENTS_FILE}\` at the repository root) is refused with "<name> is a platform file and stays in its folder." — a folder that moves takes its own platform files along, still in their folder; a platform folder (the repository root or a reserved root folder such as \`KnowledgeBase/\`) and git metadata are refused; a move cannot create a platform file or folder at \`dest\` either (renaming a note to \`access.md\` is refused); a path through a symbolic link is refused, since links are never followed; on a protected branch you must be able to write both ends — for a folder, every file under it at its old and its new path. ` +
2266
+ `Rules: the destination must not exist — a move never overwrites a file or merges into a folder; a platform file (\`access.md\` or \`.bevelignore\` in any folder, \`roles.yaml\` or \`${kb.layout.agentsFile}\` at the repository root) is refused with "<name> is a platform file and stays in its folder." — a folder that moves takes its own platform files along, still in their folder; a platform folder (the repository root or a reserved root folder such as \`KnowledgeBase/\`) and git metadata are refused; a move cannot create a platform file or folder at \`dest\` either (renaming a note to \`access.md\` is refused); a path through a symbolic link is refused, since links are never followed; on a protected branch you must be able to write both ends — for a folder, every file under it at its old and its new path. ` +
2266
2267
  'Access follows the destination folder. Preflight first: `dryRun: true` changes nothing and answers `{ src, dest, kind, descendants, access: { before, after }, accessChanges, allowed, reason? }` — `access` is your own `{ read, write, download, owner }` at the source and at the destination. ' +
2267
2268
  'A move whose `accessChanges` is true runs only with `confirm: true`; without it the call moves nothing and returns the same impact with `confirmationRequired: true`. Do NOT set `confirm: true` on your first call — dry-run, check the impact, then confirm.' +
2268
2269
  ONTOLOGY_BOUNDARY_NOTE,
@@ -1,4 +1,5 @@
1
- import { branchAuthorLocalpart, isProtectedBranch, suggestionsBranchPrefixFor } from '@bevel-software/platform-shared';
1
+ import { branchAuthorLocalpart, suggestionsBranchPrefixFor } from '@bevel-software/platform-shared';
2
+ import type { KbContext } from '../../shared/kb-context.js';
2
3
  import { ToolError } from '../tool-helpers/tool.contract.js';
3
4
  import { AccessDeniedError } from '../access-model/access-errors.js';
4
5
  import type { IChangeReadGate } from '../access-model/change-gate.js';
@@ -111,9 +112,10 @@ export async function writeDenial(
111
112
  err: AccessDeniedError,
112
113
  input: { tool: string; branch: string; userEmail: string; userId: string },
113
114
  accessControl: IAccessControl,
114
- kbDirName: string,
115
+ kb: Pick<KbContext, 'kbDirName' | 'isProtectedBranch'>,
115
116
  changeGate?: IChangeReadGate,
116
117
  ): Promise<ToolError> {
118
+ const { kbDirName } = kb;
117
119
  const path = err.access.path;
118
120
  const base = { kind: 'write-denied' as const, path, reason: reasonOf(err) };
119
121
  const refuse = (cannotProposeReason: string): ToolError => {
@@ -121,7 +123,7 @@ export async function writeDenial(
121
123
  return new ToolError(`${err.message} ${cannotProposeReason}`, 403, { ...details });
122
124
  };
123
125
 
124
- if (!isProtectedBranch(input.branch)) {
126
+ if (!kb.isProtectedBranch(input.branch)) {
125
127
  return refuse(`Proposing is not available: "${input.branch}" is not a branch that accepts change requests.`);
126
128
  }
127
129
  // The lock gate reports workspace paths, the git gates repo-relative ones.
@@ -179,11 +181,11 @@ export async function rethrowAsWriteDenial(
179
181
  err: unknown,
180
182
  input: { tool: string; branch: unknown; userEmail: string; userId: string },
181
183
  accessControl: IAccessControl,
182
- kbDirName: string,
184
+ kb: Pick<KbContext, 'kbDirName' | 'isProtectedBranch'>,
183
185
  changeGate?: IChangeReadGate,
184
186
  ): Promise<never> {
185
187
  if (err instanceof AccessDeniedError && typeof input.branch === 'string') {
186
- throw await writeDenial(err, { ...input, branch: input.branch }, accessControl, kbDirName, changeGate);
188
+ throw await writeDenial(err, { ...input, branch: input.branch }, accessControl, kb, changeGate);
187
189
  }
188
190
  throw err;
189
191
  }
@@ -1,5 +1,8 @@
1
1
  import { describe, it, expect } from 'vitest';
2
- import { pluginOfPath, PLUGINS_DIR } from '@bevel-software/platform-shared';
2
+ import { DEFAULT_KB_LAYOUT, pluginOfPath, PLUGINS_DIR } from '@bevel-software/platform-shared';
3
+
4
+ /** `pluginOfPath` under the default layout, which these cases are written against. */
5
+ const plugin = (path: string) => pluginOfPath(path, DEFAULT_KB_LAYOUT);
3
6
 
4
7
  /**
5
8
  * `pluginOfPath` is the whole of the grouping contract — the sidebar, the
@@ -9,9 +12,9 @@ import { pluginOfPath, PLUGINS_DIR } from '@bevel-software/platform-shared';
9
12
  */
10
13
  describe('pluginOfPath', () => {
11
14
  it('reads the plugin from the Plugins root', () => {
12
- expect(pluginOfPath(`${PLUGINS_DIR}/GTM/heyreach-campaign/SKILL.md`)).toBe('GTM');
13
- expect(pluginOfPath(`${PLUGINS_DIR}/GTM/heyreach.tool`)).toBe('GTM');
14
- expect(pluginOfPath(`${PLUGINS_DIR}/Engineering/review/architecture-review`)).toBe(
15
+ expect(plugin(`${PLUGINS_DIR}/GTM/heyreach-campaign/SKILL.md`)).toBe('GTM');
16
+ expect(plugin(`${PLUGINS_DIR}/GTM/heyreach.tool`)).toBe('GTM');
17
+ expect(plugin(`${PLUGINS_DIR}/Engineering/review/architecture-review`)).toBe(
15
18
  'Engineering',
16
19
  );
17
20
  });
@@ -19,27 +22,27 @@ describe('pluginOfPath', () => {
19
22
  it('returns null for content directly under the root — it has no plugin folder', () => {
20
23
  // The regression this guards: `Plugins/slack.tool` must NOT report a plugin
21
24
  // called "slack.tool", and `Plugins/GTM` must not report itself.
22
- expect(pluginOfPath(`${PLUGINS_DIR}/slack.tool`)).toBeNull();
23
- expect(pluginOfPath(`${PLUGINS_DIR}/GTM`)).toBeNull();
24
- expect(pluginOfPath(PLUGINS_DIR)).toBeNull();
25
+ expect(plugin(`${PLUGINS_DIR}/slack.tool`)).toBeNull();
26
+ expect(plugin(`${PLUGINS_DIR}/GTM`)).toBeNull();
27
+ expect(plugin(PLUGINS_DIR)).toBeNull();
25
28
  });
26
29
 
27
30
  it('returns null outside the plugin root', () => {
28
- expect(pluginOfPath('KnowledgeBase/Product/Knowledge/Foo.md')).toBeNull();
29
- expect(pluginOfPath('Data/Engineering/Knowledge/Bar.md')).toBeNull();
31
+ expect(plugin('KnowledgeBase/Product/Knowledge/Foo.md')).toBeNull();
32
+ expect(plugin('Data/Engineering/Knowledge/Bar.md')).toBeNull();
30
33
  // The retired pre-merge roots are ordinary non-plugin folders now.
31
- expect(pluginOfPath('Skills/GTM/heyreach-campaign')).toBeNull();
32
- expect(pluginOfPath('Tools/NewsAgent/serper.tool')).toBeNull();
33
- expect(pluginOfPath('access.md')).toBeNull();
34
- expect(pluginOfPath('')).toBeNull();
34
+ expect(plugin('Skills/GTM/heyreach-campaign')).toBeNull();
35
+ expect(plugin('Tools/NewsAgent/serper.tool')).toBeNull();
36
+ expect(plugin('access.md')).toBeNull();
37
+ expect(plugin('')).toBeNull();
35
38
  });
36
39
 
37
40
  it('is not fooled by a prefix match on the root name', () => {
38
- expect(pluginOfPath('PluginsOld/GTM/x')).toBeNull();
41
+ expect(plugin('PluginsOld/GTM/x')).toBeNull();
39
42
  });
40
43
 
41
44
  it('tolerates leading and doubled separators', () => {
42
- expect(pluginOfPath(`/${PLUGINS_DIR}/GTM/x`)).toBe('GTM');
43
- expect(pluginOfPath(`${PLUGINS_DIR}//GTM//x`)).toBe('GTM');
45
+ expect(plugin(`/${PLUGINS_DIR}/GTM/x`)).toBe('GTM');
46
+ expect(plugin(`${PLUGINS_DIR}//GTM//x`)).toBe('GTM');
44
47
  });
45
48
  });
@@ -39,21 +39,76 @@
39
39
  */
40
40
 
41
41
  /**
42
- * Strip the configured git token out of text on its way into an error, a log
43
- * line or a response.
42
+ * The credential git authenticates a knowledge base's remote with: the
43
+ * Basic-auth username the host expects and the token that is its password.
44
+ *
45
+ * A PROVIDER, read at every call, not a value captured at boot: the setup
46
+ * screen can supply a token after the graph is built, and a token rotated in
47
+ * the settings has to be the one the next push carries. The runner puts the
48
+ * token into the child's environment under {@link GIT_TOKEN_ENV}, which is
49
+ * the only place git reads it from (the inline credential helper spells
50
+ * `password=$GITHUB_TOKEN`), so the value never enters argv, a clone's
51
+ * config, or a message that quotes either. Nothing writes it into THIS
52
+ * process's environment: a server hosting several knowledge bases has one
53
+ * environment and several tokens.
54
+ */
55
+ export interface GitCredentials {
56
+ /**
57
+ * The username sent in the Basic credential: GitHub `x-access-token`,
58
+ * GitLab `oauth2`, Bitbucket `x-token-auth`. Interpolated into the helper
59
+ * snippet, so callers validate it against `[A-Za-z0-9._-]+` before it
60
+ * gets here.
61
+ */
62
+ username(): string;
63
+ /** The token in effect, or null when the deployment has none configured. */
64
+ token(): string | null;
65
+ }
66
+
67
+ /** The username git is given when a deployment names none. */
68
+ export const DEFAULT_GIT_USERNAME = 'x-access-token';
69
+
70
+ /**
71
+ * The environment variable the child git process reads the token from. The
72
+ * name is historical (the first supported host), and it is the literal every
73
+ * app-stamped credential helper carries, which is what lets a re-stamp find
74
+ * its own helpers in a clone's config and leave an operator's alone.
75
+ */
76
+ export const GIT_TOKEN_ENV = 'GITHUB_TOKEN';
77
+
78
+ /** No token, the default username: an unauthenticated runner. */
79
+ export const NO_GIT_CREDENTIALS: GitCredentials = Object.freeze({
80
+ username: () => DEFAULT_GIT_USERNAME,
81
+ token: () => null,
82
+ });
83
+
84
+ /** A provider from values or thunks, for a composition root or a test. */
85
+ export function gitCredentials(
86
+ username: string | (() => string) = DEFAULT_GIT_USERNAME,
87
+ token: string | null | (() => string | null) = null,
88
+ ): GitCredentials {
89
+ const user = typeof username === 'function' ? username : () => username;
90
+ const secret = typeof token === 'function' ? token : () => token;
91
+ return {
92
+ username: () => user() || DEFAULT_GIT_USERNAME,
93
+ token: () => secret() || null,
94
+ };
95
+ }
96
+
97
+ /**
98
+ * Strip a git token out of text on its way into an error, a log line or a
99
+ * response.
44
100
  *
45
101
  * git puts the remote URL into a great many of its messages, and on a
46
102
  * token-authenticated remote that URL carries the credential. Without this, a
47
103
  * push failure writes the deployment's token into the container log, the API
48
104
  * response, and any change request the recovery agent opens about it.
49
105
  *
50
- * Read from the environment at call time rather than captured: the setup screen
51
- * can supply a token after boot, and `DeploymentSettingsService.syncGitTokenEnv`
52
- * puts it here — a value captured at module load would be the empty string for
53
- * exactly the deployments that configure their token that way.
106
+ * The token is the caller's to name (the runner names its own), never read
107
+ * from this process's environment: the environment holds no per-knowledge-
108
+ * base token any more, and a scrub that silently found none there would look
109
+ * like one that worked.
54
110
  */
55
- export function redactGitToken(text: string): string {
56
- const token = process.env.GITHUB_TOKEN;
111
+ export function redactGitToken(text: string, token: string | null | undefined): string {
57
112
  const scrubbed = token ? text.replaceAll(token, '***') : text;
58
113
  // URL userinfo as well: a remote spelled `https://user:pass@host` would
59
114
  // otherwise leak `pass` verbatim through every git failure that quotes the
@@ -165,6 +220,13 @@ export interface IGitRunner {
165
220
  * constant.
166
221
  */
167
222
  readonly defaultTimeoutMs: number;
223
+ /**
224
+ * The credential every call through this runner authenticates with — see
225
+ * {@link GitCredentials}. Exposed so the code that stamps a clone's helper
226
+ * or scrubs a message can ask the same runner it runs git through whether
227
+ * a token is in effect, rather than a second source that could disagree.
228
+ */
229
+ readonly credentials: GitCredentials;
168
230
  run(cwd: string, args: string[], opts: GitRunOptions & { encoding: 'buffer' }): Promise<GitRunResult<Buffer>>;
169
231
  run(cwd: string, args: string[], opts?: GitRunOptions & { encoding?: 'utf8' }): Promise<GitRunResult>;
170
232
  }