@bevel-software/platform-core-backend 0.20.0 → 0.22.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 (666) 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 +55 -107
  11. package/dist/core/create-core-server.js.map +1 -1
  12. package/dist/core/create-core-services.d.ts +41 -4
  13. package/dist/core/create-core-services.d.ts.map +1 -1
  14. package/dist/core/create-core-services.js +183 -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-requests.contract.d.ts +75 -0
  37. package/dist/modules/access/access-requests.contract.d.ts.map +1 -0
  38. package/dist/modules/access/access-requests.contract.js +20 -0
  39. package/dist/modules/access/access-requests.contract.js.map +1 -0
  40. package/dist/modules/access/access-requests.routes.d.ts +35 -0
  41. package/dist/modules/access/access-requests.routes.d.ts.map +1 -0
  42. package/dist/modules/access/access-requests.routes.js +237 -0
  43. package/dist/modules/access/access-requests.routes.js.map +1 -0
  44. package/dist/modules/access/access-requests.service.d.ts +123 -0
  45. package/dist/modules/access/access-requests.service.d.ts.map +1 -0
  46. package/dist/modules/access/access-requests.service.js +337 -0
  47. package/dist/modules/access/access-requests.service.js.map +1 -0
  48. package/dist/modules/access/access.routes.d.ts +2 -1
  49. package/dist/modules/access/access.routes.d.ts.map +1 -1
  50. package/dist/modules/access/access.routes.js +10 -10
  51. package/dist/modules/access/access.routes.js.map +1 -1
  52. package/dist/modules/access/change-read-gate.d.ts +6 -3
  53. package/dist/modules/access/change-read-gate.d.ts.map +1 -1
  54. package/dist/modules/access/change-read-gate.js +9 -6
  55. package/dist/modules/access/change-read-gate.js.map +1 -1
  56. package/dist/modules/access/creator-access.d.ts +4 -2
  57. package/dist/modules/access/creator-access.d.ts.map +1 -1
  58. package/dist/modules/access/creator-access.js +7 -4
  59. package/dist/modules/access/creator-access.js.map +1 -1
  60. package/dist/modules/access-model/access-grammar.d.ts +12 -0
  61. package/dist/modules/access-model/access-grammar.d.ts.map +1 -1
  62. package/dist/modules/access-model/access-grammar.js +24 -0
  63. package/dist/modules/access-model/access-grammar.js.map +1 -1
  64. package/dist/modules/agent-instructions/read-preamble.d.ts +2 -1
  65. package/dist/modules/agent-instructions/read-preamble.d.ts.map +1 -1
  66. package/dist/modules/agent-instructions/read-preamble.js +6 -9
  67. package/dist/modules/agent-instructions/read-preamble.js.map +1 -1
  68. package/dist/modules/auth/account-admission.d.ts +40 -0
  69. package/dist/modules/auth/account-admission.d.ts.map +1 -0
  70. package/dist/modules/auth/account-admission.js +17 -0
  71. package/dist/modules/auth/account-admission.js.map +1 -0
  72. package/dist/modules/auth/account.routes.d.ts.map +1 -1
  73. package/dist/modules/auth/account.routes.js +4 -1
  74. package/dist/modules/auth/account.routes.js.map +1 -1
  75. package/dist/modules/auth/auth.service.d.ts +45 -2
  76. package/dist/modules/auth/auth.service.d.ts.map +1 -1
  77. package/dist/modules/auth/auth.service.js +44 -3
  78. package/dist/modules/auth/auth.service.js.map +1 -1
  79. package/dist/modules/auth/oidc-auth-provider.d.ts.map +1 -1
  80. package/dist/modules/auth/oidc-auth-provider.js +9 -0
  81. package/dist/modules/auth/oidc-auth-provider.js.map +1 -1
  82. package/dist/modules/connection-probe/connection-probe.service.d.ts +13 -1
  83. package/dist/modules/connection-probe/connection-probe.service.d.ts.map +1 -1
  84. package/dist/modules/connection-probe/connection-probe.service.js +10 -2
  85. package/dist/modules/connection-probe/connection-probe.service.js.map +1 -1
  86. package/dist/modules/database/advisory-lock.d.ts +17 -0
  87. package/dist/modules/database/advisory-lock.d.ts.map +1 -1
  88. package/dist/modules/database/advisory-lock.js +24 -3
  89. package/dist/modules/database/advisory-lock.js.map +1 -1
  90. package/dist/modules/database/connection.d.ts +67 -2
  91. package/dist/modules/database/connection.d.ts.map +1 -1
  92. package/dist/modules/database/connection.js +118 -12
  93. package/dist/modules/database/connection.js.map +1 -1
  94. package/dist/modules/database/migrate.d.ts +1 -1
  95. package/dist/modules/database/migrate.d.ts.map +1 -1
  96. package/dist/modules/database/migrate.js +27 -3
  97. package/dist/modules/database/migrate.js.map +1 -1
  98. package/dist/modules/github-app/github-app.client.d.ts +101 -0
  99. package/dist/modules/github-app/github-app.client.d.ts.map +1 -0
  100. package/dist/modules/github-app/github-app.client.js +222 -0
  101. package/dist/modules/github-app/github-app.client.js.map +1 -0
  102. package/dist/modules/github-app/github-app.connection.d.ts +102 -0
  103. package/dist/modules/github-app/github-app.connection.d.ts.map +1 -0
  104. package/dist/modules/github-app/github-app.connection.js +185 -0
  105. package/dist/modules/github-app/github-app.connection.js.map +1 -0
  106. package/dist/modules/github-app/github-app.routes.d.ts +59 -0
  107. package/dist/modules/github-app/github-app.routes.d.ts.map +1 -0
  108. package/dist/modules/github-app/github-app.routes.js +323 -0
  109. package/dist/modules/github-app/github-app.routes.js.map +1 -0
  110. package/dist/modules/github-app/index.d.ts +4 -0
  111. package/dist/modules/github-app/index.d.ts.map +1 -0
  112. package/dist/modules/github-app/index.js +4 -0
  113. package/dist/modules/github-app/index.js.map +1 -0
  114. package/dist/modules/kb-fs/branch-name.d.ts +0 -1
  115. package/dist/modules/kb-fs/branch-name.d.ts.map +1 -1
  116. package/dist/modules/kb-fs/branch-name.js +3 -3
  117. package/dist/modules/kb-fs/branch-name.js.map +1 -1
  118. package/dist/modules/kb-fs/clone-config.d.ts +9 -8
  119. package/dist/modules/kb-fs/clone-config.d.ts.map +1 -1
  120. package/dist/modules/kb-fs/clone-config.js +14 -12
  121. package/dist/modules/kb-fs/clone-config.js.map +1 -1
  122. package/dist/modules/kb-fs/remote-url.d.ts +22 -0
  123. package/dist/modules/kb-fs/remote-url.d.ts.map +1 -0
  124. package/dist/modules/kb-fs/remote-url.js +35 -0
  125. package/dist/modules/kb-fs/remote-url.js.map +1 -0
  126. package/dist/modules/mcp/mcp.service.d.ts +7 -0
  127. package/dist/modules/mcp/mcp.service.d.ts.map +1 -1
  128. package/dist/modules/mcp/mcp.service.js +4 -4
  129. package/dist/modules/mcp/mcp.service.js.map +1 -1
  130. package/dist/modules/plugins/compile/marketplace-compiler.service.d.ts +4 -4
  131. package/dist/modules/plugins/compile/marketplace-compiler.service.d.ts.map +1 -1
  132. package/dist/modules/plugins/compile/marketplace-compiler.service.js +7 -10
  133. package/dist/modules/plugins/compile/marketplace-compiler.service.js.map +1 -1
  134. package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.d.ts +4 -1
  135. package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.d.ts.map +1 -1
  136. package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.js +5 -3
  137. package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.js.map +1 -1
  138. package/dist/modules/plugins/discovery/kb-plugin-source.d.ts +6 -1
  139. package/dist/modules/plugins/discovery/kb-plugin-source.d.ts.map +1 -1
  140. package/dist/modules/plugins/discovery/kb-plugin-source.js +14 -9
  141. package/dist/modules/plugins/discovery/kb-plugin-source.js.map +1 -1
  142. package/dist/modules/plugins/discovery/native.source.d.ts +4 -1
  143. package/dist/modules/plugins/discovery/native.source.d.ts.map +1 -1
  144. package/dist/modules/plugins/discovery/native.source.js +4 -2
  145. package/dist/modules/plugins/discovery/native.source.js.map +1 -1
  146. package/dist/modules/plugins/index.d.ts +1 -1
  147. package/dist/modules/plugins/index.d.ts.map +1 -1
  148. package/dist/modules/plugins/index.js +1 -1
  149. package/dist/modules/plugins/index.js.map +1 -1
  150. package/dist/modules/plugins/join-proposals.d.ts +17 -5
  151. package/dist/modules/plugins/join-proposals.d.ts.map +1 -1
  152. package/dist/modules/plugins/join-proposals.js +76 -22
  153. package/dist/modules/plugins/join-proposals.js.map +1 -1
  154. package/dist/modules/plugins/join-request-jobs.service.d.ts +3 -1
  155. package/dist/modules/plugins/join-request-jobs.service.d.ts.map +1 -1
  156. package/dist/modules/plugins/join-request-jobs.service.js +6 -6
  157. package/dist/modules/plugins/join-request-jobs.service.js.map +1 -1
  158. package/dist/modules/plugins/join-requests.service.d.ts +113 -18
  159. package/dist/modules/plugins/join-requests.service.d.ts.map +1 -1
  160. package/dist/modules/plugins/join-requests.service.js +178 -33
  161. package/dist/modules/plugins/join-requests.service.js.map +1 -1
  162. package/dist/modules/plugins/plugin-links.d.ts +65 -10
  163. package/dist/modules/plugins/plugin-links.d.ts.map +1 -1
  164. package/dist/modules/plugins/plugin-links.js +136 -31
  165. package/dist/modules/plugins/plugin-links.js.map +1 -1
  166. package/dist/modules/plugins/plugin-links.service.d.ts +107 -5
  167. package/dist/modules/plugins/plugin-links.service.d.ts.map +1 -1
  168. package/dist/modules/plugins/plugin-links.service.js +151 -21
  169. package/dist/modules/plugins/plugin-links.service.js.map +1 -1
  170. package/dist/modules/plugins/plugin-provision.service.d.ts +10 -3
  171. package/dist/modules/plugins/plugin-provision.service.d.ts.map +1 -1
  172. package/dist/modules/plugins/plugin-provision.service.js +33 -26
  173. package/dist/modules/plugins/plugin-provision.service.js.map +1 -1
  174. package/dist/modules/plugins/plugin-rename.service.d.ts +4 -2
  175. package/dist/modules/plugins/plugin-rename.service.d.ts.map +1 -1
  176. package/dist/modules/plugins/plugin-rename.service.js +10 -12
  177. package/dist/modules/plugins/plugin-rename.service.js.map +1 -1
  178. package/dist/modules/plugins/plugins.routes.d.ts +3 -0
  179. package/dist/modules/plugins/plugins.routes.d.ts.map +1 -1
  180. package/dist/modules/plugins/plugins.routes.js +48 -17
  181. package/dist/modules/plugins/plugins.routes.js.map +1 -1
  182. package/dist/modules/plugins/plugins.service.d.ts +4 -4
  183. package/dist/modules/plugins/plugins.service.d.ts.map +1 -1
  184. package/dist/modules/plugins/plugins.service.js +7 -10
  185. package/dist/modules/plugins/plugins.service.js.map +1 -1
  186. package/dist/modules/plugins/teams.routes.d.ts +4 -1
  187. package/dist/modules/plugins/teams.routes.d.ts.map +1 -1
  188. package/dist/modules/plugins/teams.routes.js +11 -9
  189. package/dist/modules/plugins/teams.routes.js.map +1 -1
  190. package/dist/modules/secrets-vault/index.d.ts +1 -1
  191. package/dist/modules/secrets-vault/index.d.ts.map +1 -1
  192. package/dist/modules/secrets-vault/index.js +1 -1
  193. package/dist/modules/secrets-vault/index.js.map +1 -1
  194. package/dist/modules/secrets-vault/secrets-variable-loader.d.ts +29 -11
  195. package/dist/modules/secrets-vault/secrets-variable-loader.d.ts.map +1 -1
  196. package/dist/modules/secrets-vault/secrets-variable-loader.js +46 -21
  197. package/dist/modules/secrets-vault/secrets-variable-loader.js.map +1 -1
  198. package/dist/modules/secrets-vault/secrets-vault.routes.d.ts +3 -0
  199. package/dist/modules/secrets-vault/secrets-vault.routes.d.ts.map +1 -1
  200. package/dist/modules/secrets-vault/secrets-vault.routes.js +4 -6
  201. package/dist/modules/secrets-vault/secrets-vault.routes.js.map +1 -1
  202. package/dist/modules/settings/deployment-settings.service.d.ts +34 -9
  203. package/dist/modules/settings/deployment-settings.service.d.ts.map +1 -1
  204. package/dist/modules/settings/deployment-settings.service.js +113 -26
  205. package/dist/modules/settings/deployment-settings.service.js.map +1 -1
  206. package/dist/modules/settings/managed-repository.d.ts +43 -0
  207. package/dist/modules/settings/managed-repository.d.ts.map +1 -0
  208. package/dist/modules/settings/managed-repository.js +60 -0
  209. package/dist/modules/settings/managed-repository.js.map +1 -0
  210. package/dist/modules/settings/repository-source.d.ts +128 -0
  211. package/dist/modules/settings/repository-source.d.ts.map +1 -0
  212. package/dist/modules/settings/repository-source.js +150 -0
  213. package/dist/modules/settings/repository-source.js.map +1 -0
  214. package/dist/modules/settings/setup.routes.d.ts +34 -4
  215. package/dist/modules/settings/setup.routes.d.ts.map +1 -1
  216. package/dist/modules/settings/setup.routes.js +198 -18
  217. package/dist/modules/settings/setup.routes.js.map +1 -1
  218. package/dist/modules/skills/allowed-tools-check.d.ts +4 -3
  219. package/dist/modules/skills/allowed-tools-check.d.ts.map +1 -1
  220. package/dist/modules/skills/allowed-tools-check.js +8 -8
  221. package/dist/modules/skills/allowed-tools-check.js.map +1 -1
  222. package/dist/modules/skills/pending-skills.service.d.ts +3 -1
  223. package/dist/modules/skills/pending-skills.service.d.ts.map +1 -1
  224. package/dist/modules/skills/pending-skills.service.js +9 -6
  225. package/dist/modules/skills/pending-skills.service.js.map +1 -1
  226. package/dist/modules/skills/skill-access-requests.routes.d.ts +8 -9
  227. package/dist/modules/skills/skill-access-requests.routes.d.ts.map +1 -1
  228. package/dist/modules/skills/skill-access-requests.routes.js +26 -65
  229. package/dist/modules/skills/skill-access-requests.routes.js.map +1 -1
  230. package/dist/modules/skills/skills.routes.d.ts +4 -1
  231. package/dist/modules/skills/skills.routes.d.ts.map +1 -1
  232. package/dist/modules/skills/skills.routes.js +4 -4
  233. package/dist/modules/skills/skills.routes.js.map +1 -1
  234. package/dist/modules/skills/skills.service.d.ts +4 -2
  235. package/dist/modules/skills/skills.service.d.ts.map +1 -1
  236. package/dist/modules/skills/skills.service.js +13 -11
  237. package/dist/modules/skills/skills.service.js.map +1 -1
  238. package/dist/modules/tool-helpers/tool-context.d.ts.map +1 -1
  239. package/dist/modules/tool-helpers/tool-context.js +15 -0
  240. package/dist/modules/tool-helpers/tool-context.js.map +1 -1
  241. package/dist/modules/tool-manuals/mcp-json-discovery.d.ts +2 -1
  242. package/dist/modules/tool-manuals/mcp-json-discovery.d.ts.map +1 -1
  243. package/dist/modules/tool-manuals/mcp-json-discovery.js +6 -5
  244. package/dist/modules/tool-manuals/mcp-json-discovery.js.map +1 -1
  245. package/dist/modules/tool-manuals/mcp-server-edit.service.d.ts +4 -2
  246. package/dist/modules/tool-manuals/mcp-server-edit.service.d.ts.map +1 -1
  247. package/dist/modules/tool-manuals/mcp-server-edit.service.js +12 -10
  248. package/dist/modules/tool-manuals/mcp-server-edit.service.js.map +1 -1
  249. package/dist/modules/tool-manuals/pending-tools.service.d.ts +3 -1
  250. package/dist/modules/tool-manuals/pending-tools.service.d.ts.map +1 -1
  251. package/dist/modules/tool-manuals/pending-tools.service.js +19 -16
  252. package/dist/modules/tool-manuals/pending-tools.service.js.map +1 -1
  253. package/dist/modules/tool-manuals/tool-delete.service.d.ts +4 -2
  254. package/dist/modules/tool-manuals/tool-delete.service.d.ts.map +1 -1
  255. package/dist/modules/tool-manuals/tool-delete.service.js +14 -12
  256. package/dist/modules/tool-manuals/tool-delete.service.js.map +1 -1
  257. package/dist/modules/tool-manuals/tool-manuals.routes.d.ts +3 -1
  258. package/dist/modules/tool-manuals/tool-manuals.routes.d.ts.map +1 -1
  259. package/dist/modules/tool-manuals/tool-manuals.routes.js +7 -7
  260. package/dist/modules/tool-manuals/tool-manuals.routes.js.map +1 -1
  261. package/dist/modules/tool-manuals/tool-manuals.service.d.ts +4 -2
  262. package/dist/modules/tool-manuals/tool-manuals.service.d.ts.map +1 -1
  263. package/dist/modules/tool-manuals/tool-manuals.service.js +15 -12
  264. package/dist/modules/tool-manuals/tool-manuals.service.js.map +1 -1
  265. package/dist/modules/tool-manuals/tool-manuals.tools.d.ts +3 -0
  266. package/dist/modules/tool-manuals/tool-manuals.tools.d.ts.map +1 -1
  267. package/dist/modules/tool-manuals/tool-manuals.tools.js +4 -6
  268. package/dist/modules/tool-manuals/tool-manuals.tools.js.map +1 -1
  269. package/dist/modules/workflow/agent-tools/workflow.tools.d.ts +3 -2
  270. package/dist/modules/workflow/agent-tools/workflow.tools.d.ts.map +1 -1
  271. package/dist/modules/workflow/agent-tools/workflow.tools.js +47 -11
  272. package/dist/modules/workflow/agent-tools/workflow.tools.js.map +1 -1
  273. package/dist/modules/workflow/git/git.service.d.ts +14 -6
  274. package/dist/modules/workflow/git/git.service.d.ts.map +1 -1
  275. package/dist/modules/workflow/git/git.service.js +40 -18
  276. package/dist/modules/workflow/git/git.service.js.map +1 -1
  277. package/dist/modules/workflow/git/node-git-runner.d.ts +26 -2
  278. package/dist/modules/workflow/git/node-git-runner.d.ts.map +1 -1
  279. package/dist/modules/workflow/git/node-git-runner.js +40 -5
  280. package/dist/modules/workflow/git/node-git-runner.js.map +1 -1
  281. package/dist/modules/workflow/git/pull-request.service.d.ts +45 -0
  282. package/dist/modules/workflow/git/pull-request.service.d.ts.map +1 -1
  283. package/dist/modules/workflow/git/pull-request.service.js +99 -0
  284. package/dist/modules/workflow/git/pull-request.service.js.map +1 -1
  285. package/dist/modules/workflow/review-workflow/review-workflow.service.d.ts.map +1 -1
  286. package/dist/modules/workflow/review-workflow/review-workflow.service.js +9 -4
  287. package/dist/modules/workflow/review-workflow/review-workflow.service.js.map +1 -1
  288. package/dist/modules/workflow/session-ontology.service.d.ts +6 -1
  289. package/dist/modules/workflow/session-ontology.service.d.ts.map +1 -1
  290. package/dist/modules/workflow/session-ontology.service.js +6 -2
  291. package/dist/modules/workflow/session-ontology.service.js.map +1 -1
  292. package/dist/modules/workflow/workflow.routes.d.ts.map +1 -1
  293. package/dist/modules/workflow/workflow.routes.js +3 -1
  294. package/dist/modules/workflow/workflow.routes.js.map +1 -1
  295. package/dist/modules/workflow/workflow.service.d.ts +42 -10
  296. package/dist/modules/workflow/workflow.service.d.ts.map +1 -1
  297. package/dist/modules/workflow/workflow.service.js +181 -71
  298. package/dist/modules/workflow/workflow.service.js.map +1 -1
  299. package/dist/modules/workspace/session-ontology.gate.d.ts +3 -1
  300. package/dist/modules/workspace/session-ontology.gate.d.ts.map +1 -1
  301. package/dist/modules/workspace/session-ontology.gate.js +3 -3
  302. package/dist/modules/workspace/session-ontology.gate.js.map +1 -1
  303. package/dist/modules/workspace/startup/kb-git.d.ts +4 -3
  304. package/dist/modules/workspace/startup/kb-git.d.ts.map +1 -1
  305. package/dist/modules/workspace/startup/kb-git.js +15 -13
  306. package/dist/modules/workspace/startup/kb-git.js.map +1 -1
  307. package/dist/modules/workspace/startup/kb-startup-runner.d.ts +70 -7
  308. package/dist/modules/workspace/startup/kb-startup-runner.d.ts.map +1 -1
  309. package/dist/modules/workspace/startup/kb-startup-runner.js +183 -38
  310. package/dist/modules/workspace/startup/kb-startup-runner.js.map +1 -1
  311. package/dist/modules/workspace/startup/steps/groups-to-plugins.step.d.ts +7 -1
  312. package/dist/modules/workspace/startup/steps/groups-to-plugins.step.d.ts.map +1 -1
  313. package/dist/modules/workspace/startup/steps/groups-to-plugins.step.js +23 -16
  314. package/dist/modules/workspace/startup/steps/groups-to-plugins.step.js.map +1 -1
  315. package/dist/modules/workspace/startup/steps/personal-spaces.step.d.ts +7 -1
  316. package/dist/modules/workspace/startup/steps/personal-spaces.step.d.ts.map +1 -1
  317. package/dist/modules/workspace/startup/steps/personal-spaces.step.js +12 -5
  318. package/dist/modules/workspace/startup/steps/personal-spaces.step.js.map +1 -1
  319. package/dist/modules/workspace/startup/steps/plugin-display-names.step.d.ts +7 -1
  320. package/dist/modules/workspace/startup/steps/plugin-display-names.step.d.ts.map +1 -1
  321. package/dist/modules/workspace/startup/steps/plugin-display-names.step.js +12 -5
  322. package/dist/modules/workspace/startup/steps/plugin-display-names.step.js.map +1 -1
  323. package/dist/modules/workspace/startup/steps/plugin-manifests.step.d.ts +7 -1
  324. package/dist/modules/workspace/startup/steps/plugin-manifests.step.d.ts.map +1 -1
  325. package/dist/modules/workspace/startup/steps/plugin-manifests.step.js +12 -5
  326. package/dist/modules/workspace/startup/steps/plugin-manifests.step.js.map +1 -1
  327. package/dist/modules/workspace/startup/steps/seed-tree.d.ts +4 -1
  328. package/dist/modules/workspace/startup/steps/seed-tree.d.ts.map +1 -1
  329. package/dist/modules/workspace/startup/steps/seed-tree.js +14 -11
  330. package/dist/modules/workspace/startup/steps/seed-tree.js.map +1 -1
  331. package/dist/modules/workspace/startup/steps/template-files.step.d.ts +17 -3
  332. package/dist/modules/workspace/startup/steps/template-files.step.d.ts.map +1 -1
  333. package/dist/modules/workspace/startup/steps/template-files.step.js +36 -30
  334. package/dist/modules/workspace/startup/steps/template-files.step.js.map +1 -1
  335. package/dist/modules/workspace/startup/steps/template-source.d.ts +6 -1
  336. package/dist/modules/workspace/startup/steps/template-source.d.ts.map +1 -1
  337. package/dist/modules/workspace/startup/steps/template-source.js +10 -6
  338. package/dist/modules/workspace/startup/steps/template-source.js.map +1 -1
  339. package/dist/modules/workspace/workspace.routes.d.ts +2 -1
  340. package/dist/modules/workspace/workspace.routes.d.ts.map +1 -1
  341. package/dist/modules/workspace/workspace.routes.js +8 -7
  342. package/dist/modules/workspace/workspace.routes.js.map +1 -1
  343. package/dist/modules/workspace/workspace.service.d.ts +18 -12
  344. package/dist/modules/workspace/workspace.service.d.ts.map +1 -1
  345. package/dist/modules/workspace/workspace.service.js +49 -29
  346. package/dist/modules/workspace/workspace.service.js.map +1 -1
  347. package/dist/modules/workspace/workspace.tools.d.ts +2 -1
  348. package/dist/modules/workspace/workspace.tools.d.ts.map +1 -1
  349. package/dist/modules/workspace/workspace.tools.js +48 -20
  350. package/dist/modules/workspace/workspace.tools.js.map +1 -1
  351. package/dist/modules/workspace/write-denial.d.ts +3 -2
  352. package/dist/modules/workspace/write-denial.d.ts.map +1 -1
  353. package/dist/modules/workspace/write-denial.js +6 -5
  354. package/dist/modules/workspace/write-denial.js.map +1 -1
  355. package/dist/shared/domain-errors.d.ts +39 -0
  356. package/dist/shared/domain-errors.d.ts.map +1 -1
  357. package/dist/shared/domain-errors.js +55 -0
  358. package/dist/shared/domain-errors.js.map +1 -1
  359. package/dist/shared/git.contract.d.ts +62 -7
  360. package/dist/shared/git.contract.d.ts.map +1 -1
  361. package/dist/shared/git.contract.js +30 -8
  362. package/dist/shared/git.contract.js.map +1 -1
  363. package/dist/shared/kb-context.d.ts +76 -0
  364. package/dist/shared/kb-context.d.ts.map +1 -0
  365. package/dist/shared/kb-context.js +108 -0
  366. package/dist/shared/kb-context.js.map +1 -0
  367. package/dist/shared/kb-layout.d.ts +3 -2
  368. package/dist/shared/kb-layout.d.ts.map +1 -1
  369. package/dist/shared/kb-layout.js +4 -3
  370. package/dist/shared/kb-layout.js.map +1 -1
  371. package/dist/shared/kb-layout.test.js +35 -27
  372. package/dist/shared/kb-layout.test.js.map +1 -1
  373. package/dist/shared/pending-proposals.d.ts +4 -1
  374. package/dist/shared/pending-proposals.d.ts.map +1 -1
  375. package/dist/shared/pending-proposals.js +3 -4
  376. package/dist/shared/pending-proposals.js.map +1 -1
  377. package/dist/shared/redact-secret.d.ts +5 -5
  378. package/dist/shared/redact-secret.js +5 -5
  379. package/dist/tenancy/index.d.ts +13 -0
  380. package/dist/tenancy/index.d.ts.map +1 -0
  381. package/dist/tenancy/index.js +13 -0
  382. package/dist/tenancy/index.js.map +1 -0
  383. package/dist/tenancy/static-tenant-source.d.ts +98 -0
  384. package/dist/tenancy/static-tenant-source.d.ts.map +1 -0
  385. package/dist/tenancy/static-tenant-source.js +220 -0
  386. package/dist/tenancy/static-tenant-source.js.map +1 -0
  387. package/dist/tenancy/tenant-host.d.ts +80 -0
  388. package/dist/tenancy/tenant-host.d.ts.map +1 -0
  389. package/dist/tenancy/tenant-host.js +217 -0
  390. package/dist/tenancy/tenant-host.js.map +1 -0
  391. package/dist/tenancy/tenant-runtime.d.ts +91 -0
  392. package/dist/tenancy/tenant-runtime.d.ts.map +1 -0
  393. package/dist/tenancy/tenant-runtime.js +174 -0
  394. package/dist/tenancy/tenant-runtime.js.map +1 -0
  395. package/dist/tenancy/tenant-secrets.d.ts +24 -0
  396. package/dist/tenancy/tenant-secrets.d.ts.map +1 -0
  397. package/dist/tenancy/tenant-secrets.js +30 -0
  398. package/dist/tenancy/tenant-secrets.js.map +1 -0
  399. package/dist/tenancy/tenant-source.contract.d.ts +45 -0
  400. package/dist/tenancy/tenant-source.contract.d.ts.map +1 -0
  401. package/dist/tenancy/tenant-source.contract.js +21 -0
  402. package/dist/tenancy/tenant-source.contract.js.map +1 -0
  403. package/migrations/0000_core_init.sql +14 -14
  404. package/migrations/0003_deployment_settings.sql +1 -1
  405. package/migrations/0005_github_facade.sql +1 -1
  406. package/migrations/0012_agent_audit.sql +6 -6
  407. package/package.json +3 -3
  408. package/src/__tests__/branch-model.test.ts +7 -6
  409. package/src/__tests__/kb-context.ts +30 -0
  410. package/src/__tests__/kb-layout-config.test.ts +35 -30
  411. package/src/core/__tests__/catalog-cache-invalidation.test.ts +2 -1
  412. package/src/core/__tests__/lifecycle.test.ts +78 -1
  413. package/src/core/__tests__/public-config.test.ts +5 -1
  414. package/src/core/catalog-cache-invalidation.ts +16 -11
  415. package/src/core/core-ports.ts +19 -0
  416. package/src/core/create-core-server.ts +64 -107
  417. package/src/core/create-core-services.ts +238 -96
  418. package/src/core/lifecycle.ts +214 -29
  419. package/src/core/public-config.ts +8 -5
  420. package/src/core-config.ts +107 -8
  421. package/src/index.ts +25 -2
  422. package/src/modules/access/__tests__/access-control.admin-root-floor.test.ts +2 -1
  423. package/src/modules/access/__tests__/access-requests.recut.test.ts +134 -0
  424. package/src/modules/access/__tests__/access-requests.routes.test.ts +610 -0
  425. package/src/modules/access/__tests__/access.routes.batch.test.ts +2 -1
  426. package/src/modules/access/__tests__/access.routes.folder-governs.test.ts +2 -1
  427. package/src/modules/access/__tests__/access.routes.group-grant.test.ts +2 -1
  428. package/src/modules/access/__tests__/access.routes.overrides.test.ts +2 -1
  429. package/src/modules/access/__tests__/access.routes.proposal-branch.test.ts +2 -1
  430. package/src/modules/access/__tests__/access.routes.prospective.test.ts +2 -1
  431. package/src/modules/access/__tests__/access.routes.revoke.test.ts +2 -1
  432. package/src/modules/access/__tests__/access.routes.unknown-email.test.ts +2 -1
  433. package/src/modules/access/__tests__/change-read-gate.test.ts +13 -11
  434. package/src/modules/access/__tests__/creator-access.test.ts +3 -2
  435. package/src/modules/access/__tests__/roles.routes.test.ts +2 -1
  436. package/src/modules/access/access-control.service.ts +20 -6
  437. package/src/modules/access/access-requests.contract.ts +93 -0
  438. package/src/modules/access/access-requests.routes.ts +286 -0
  439. package/src/modules/access/access-requests.service.ts +420 -0
  440. package/src/modules/access/access.routes.ts +10 -13
  441. package/src/modules/access/change-read-gate.ts +10 -4
  442. package/src/modules/access/creator-access.ts +7 -2
  443. package/src/modules/access-model/access-grammar.ts +22 -0
  444. package/src/modules/agent-instructions/__tests__/read-preamble.test.ts +13 -12
  445. package/src/modules/agent-instructions/read-preamble.ts +10 -12
  446. package/src/modules/auth/__tests__/account.routes.test.ts +15 -0
  447. package/src/modules/auth/__tests__/auth.service.test.ts +98 -0
  448. package/src/modules/auth/account-admission.ts +44 -0
  449. package/src/modules/auth/account.routes.ts +4 -1
  450. package/src/modules/auth/auth.service.ts +61 -2
  451. package/src/modules/auth/oidc-auth-provider.ts +9 -0
  452. package/src/modules/connection-probe/connection-probe.service.ts +7 -1
  453. package/src/modules/database/__tests__/advisory-lock.test.ts +23 -1
  454. package/src/modules/database/__tests__/connection.test.ts +98 -0
  455. package/src/modules/database/__tests__/migrations-unqualified.test.ts +32 -0
  456. package/src/modules/database/advisory-lock.ts +28 -4
  457. package/src/modules/database/connection.ts +143 -13
  458. package/src/modules/database/migrate.ts +48 -14
  459. package/src/modules/diff/__tests__/diff.service.seed-atomicity.test.ts +2 -1
  460. package/src/modules/diff/__tests__/diff.service.test.ts +2 -1
  461. package/src/modules/github-app/__tests__/github-app.test.ts +848 -0
  462. package/src/modules/github-app/github-app.client.ts +268 -0
  463. package/src/modules/github-app/github-app.connection.ts +204 -0
  464. package/src/modules/github-app/github-app.routes.ts +359 -0
  465. package/src/modules/github-app/index.ts +19 -0
  466. package/src/modules/kb-fs/__tests__/branch-name.test.ts +6 -6
  467. package/src/modules/kb-fs/__tests__/clone-config.test.ts +24 -20
  468. package/src/modules/kb-fs/__tests__/remote-url.test.ts +38 -0
  469. package/src/modules/kb-fs/branch-name.ts +3 -3
  470. package/src/modules/kb-fs/clone-config.ts +15 -12
  471. package/src/modules/kb-fs/remote-url.ts +35 -0
  472. package/src/modules/marketplace/__tests__/marketplace-repo.head.test.ts +2 -1
  473. package/src/modules/mcp/mcp.service.ts +11 -4
  474. package/src/modules/plugins/__tests__/bundle-dialect.e2e.test.ts +12 -11
  475. package/src/modules/plugins/__tests__/bundle-dialect.test.ts +2 -1
  476. package/src/modules/plugins/__tests__/compile-marketplace.test.ts +6 -4
  477. package/src/modules/plugins/__tests__/join-proposals.test.ts +100 -19
  478. package/src/modules/plugins/__tests__/join-request-jobs.service.test.ts +2 -1
  479. package/src/modules/plugins/__tests__/join-requests.service.test.ts +28 -11
  480. package/src/modules/plugins/__tests__/join-requests.settlement.test.ts +371 -0
  481. package/src/modules/plugins/__tests__/plugin-creation-display-name.test.ts +4 -3
  482. package/src/modules/plugins/__tests__/plugin-index.service.test.ts +6 -4
  483. package/src/modules/plugins/__tests__/plugin-links.service.test.ts +220 -5
  484. package/src/modules/plugins/__tests__/plugin-provision.service.test.ts +3 -1
  485. package/src/modules/plugins/__tests__/plugin-rename.service.test.ts +7 -6
  486. package/src/modules/plugins/__tests__/plugins.routes.test.ts +12 -3
  487. package/src/modules/plugins/__tests__/teams.routes.test.ts +2 -1
  488. package/src/modules/plugins/compile/marketplace-compiler.service.ts +7 -9
  489. package/src/modules/plugins/discovery/__tests__/kb-plugin-source.test.ts +20 -16
  490. package/src/modules/plugins/discovery/bundle-dialect/bundle.source.ts +9 -2
  491. package/src/modules/plugins/discovery/kb-plugin-source.ts +15 -8
  492. package/src/modules/plugins/discovery/native.source.ts +4 -1
  493. package/src/modules/plugins/index.ts +1 -1
  494. package/src/modules/plugins/join-proposals.ts +87 -19
  495. package/src/modules/plugins/join-request-jobs.service.ts +8 -7
  496. package/src/modules/plugins/join-requests.service.ts +203 -43
  497. package/src/modules/plugins/plugin-links.service.ts +192 -19
  498. package/src/modules/plugins/plugin-links.ts +147 -27
  499. package/src/modules/plugins/plugin-provision.service.ts +54 -27
  500. package/src/modules/plugins/plugin-rename.service.ts +10 -10
  501. package/src/modules/plugins/plugins.routes.ts +48 -17
  502. package/src/modules/plugins/plugins.service.ts +7 -11
  503. package/src/modules/plugins/teams.routes.ts +16 -8
  504. package/src/modules/secrets-vault/__tests__/connect-pending.route.test.ts +7 -0
  505. package/src/modules/secrets-vault/__tests__/secrets-variable-loader.test.ts +40 -0
  506. package/src/modules/secrets-vault/__tests__/tool-owner-gate.route.test.ts +2 -0
  507. package/src/modules/secrets-vault/index.ts +2 -0
  508. package/src/modules/secrets-vault/secrets-variable-loader.ts +51 -21
  509. package/src/modules/secrets-vault/secrets-vault.routes.ts +7 -6
  510. package/src/modules/settings/__tests__/deployment-settings.service.test.ts +24 -11
  511. package/src/modules/settings/__tests__/git-root-folders.test.ts +2 -1
  512. package/src/modules/settings/__tests__/repository-source.test.ts +191 -0
  513. package/src/modules/settings/__tests__/setup.routes.boot-failure.test.ts +2 -1
  514. package/src/modules/settings/__tests__/setup.routes.git-mode.test.ts +353 -0
  515. package/src/modules/settings/__tests__/setup.routes.github-app.test.ts +282 -0
  516. package/src/modules/settings/__tests__/setup.routes.layout-phase.test.ts +7 -4
  517. package/src/modules/settings/__tests__/setup.routes.managed-phase.test.ts +233 -0
  518. package/src/modules/settings/__tests__/setup.routes.oidc.test.ts +2 -0
  519. package/src/modules/settings/__tests__/setup.routes.sync-status.test.ts +2 -0
  520. package/src/modules/settings/__tests__/setup.routes.test.ts +33 -52
  521. package/src/modules/settings/deployment-settings.service.ts +130 -23
  522. package/src/modules/settings/managed-repository.ts +68 -0
  523. package/src/modules/settings/repository-source.ts +197 -0
  524. package/src/modules/settings/setup.routes.ts +233 -19
  525. package/src/modules/skills/__tests__/allowed-tools-check.test.ts +11 -10
  526. package/src/modules/skills/__tests__/allowed-tools-warn.tools.test.ts +4 -3
  527. package/src/modules/skills/__tests__/pending-skills.service.test.ts +3 -1
  528. package/src/modules/skills/__tests__/skill-access-requests.routes.test.ts +7 -2
  529. package/src/modules/skills/__tests__/skills.routes.warnings.test.ts +2 -1
  530. package/src/modules/skills/__tests__/skills.service.test.ts +3 -2
  531. package/src/modules/skills/allowed-tools-check.ts +7 -6
  532. package/src/modules/skills/pending-skills.service.ts +9 -8
  533. package/src/modules/skills/skill-access-requests.routes.ts +29 -79
  534. package/src/modules/skills/skills.routes.ts +4 -3
  535. package/src/modules/skills/skills.service.ts +13 -9
  536. package/src/modules/tool-helpers/__tests__/agent-roles-write.test.ts +3 -2
  537. package/src/modules/tool-helpers/__tests__/phase4-tools.test.ts +3 -2
  538. package/src/modules/tool-helpers/tool-context.ts +15 -0
  539. package/src/modules/tool-manuals/__tests__/mcp-json-discovery.test.ts +17 -12
  540. package/src/modules/tool-manuals/__tests__/mcp-server-edit.service.test.ts +2 -1
  541. package/src/modules/tool-manuals/__tests__/pending-tools.service.test.ts +4 -1
  542. package/src/modules/tool-manuals/__tests__/tool-delete.service.test.ts +2 -1
  543. package/src/modules/tool-manuals/__tests__/tool-manuals.archive.route.test.ts +2 -1
  544. package/src/modules/tool-manuals/__tests__/tool-manuals.cli.test.ts +5 -4
  545. package/src/modules/tool-manuals/__tests__/tool-manuals.detail.route.test.ts +2 -1
  546. package/src/modules/tool-manuals/__tests__/tool-manuals.invalid.routes.test.ts +4 -2
  547. package/src/modules/tool-manuals/__tests__/tool-manuals.invalid.test.ts +13 -5
  548. package/src/modules/tool-manuals/__tests__/tool-manuals.mcp-oauth.test.ts +2 -1
  549. package/src/modules/tool-manuals/__tests__/tool-manuals.restart.test.ts +9 -1
  550. package/src/modules/tool-manuals/__tests__/tool-manuals.service.test.ts +3 -2
  551. package/src/modules/tool-manuals/__tests__/tool-manuals.tools.test.ts +2 -0
  552. package/src/modules/tool-manuals/mcp-json-discovery.ts +6 -4
  553. package/src/modules/tool-manuals/mcp-server-edit.service.ts +13 -11
  554. package/src/modules/tool-manuals/pending-tools.service.ts +19 -16
  555. package/src/modules/tool-manuals/tool-delete.service.ts +13 -10
  556. package/src/modules/tool-manuals/tool-manuals.routes.ts +10 -8
  557. package/src/modules/tool-manuals/tool-manuals.service.ts +15 -13
  558. package/src/modules/tool-manuals/tool-manuals.tools.ts +7 -6
  559. package/src/modules/workflow/__tests__/apply-failure.test.ts +11 -2
  560. package/src/modules/workflow/__tests__/merge-announces-tree.test.ts +14 -26
  561. package/src/modules/workflow/__tests__/preserve-roles-yaml.test.ts +2 -1
  562. package/src/modules/workflow/__tests__/session-ontology.service.test.ts +3 -2
  563. package/src/modules/workflow/__tests__/workflow.routes.lock-path.test.ts +2 -1
  564. package/src/modules/workflow/__tests__/workflow.service.branch-in-use.test.ts +3 -10
  565. package/src/modules/workflow/__tests__/workflow.service.commitFileWhileLocked.test.ts +2 -1
  566. package/src/modules/workflow/__tests__/workflow.service.deleted-branch-sweep.test.ts +3 -10
  567. package/src/modules/workflow/__tests__/workflow.service.facade.test.ts +187 -35
  568. package/src/modules/workflow/__tests__/workflow.service.folder-proposals.test.ts +2 -1
  569. package/src/modules/workflow/__tests__/workflow.service.platform-restore.test.ts +2 -1
  570. package/src/modules/workflow/__tests__/workflow.service.read-gate.test.ts +3 -2
  571. package/src/modules/workflow/__tests__/workflow.service.releaseLock.test.ts +2 -1
  572. package/src/modules/workflow/__tests__/workflow.service.sync.test.ts +5 -4
  573. package/src/modules/workflow/__tests__/workflow.service.update-from-target.test.ts +148 -41
  574. package/src/modules/workflow/agent-tools/__tests__/workflow.tools.test.ts +143 -2
  575. package/src/modules/workflow/agent-tools/workflow.tools.ts +60 -12
  576. package/src/modules/workflow/git/__tests__/git.service.accessGating.test.ts +5 -4
  577. package/src/modules/workflow/git/__tests__/git.service.changedFilesForPr.test.ts +12 -11
  578. package/src/modules/workflow/git/__tests__/git.service.commitChanges.test.ts +9 -8
  579. package/src/modules/workflow/git/__tests__/git.service.commitFile.strayPath.test.ts +8 -7
  580. package/src/modules/workflow/git/__tests__/git.service.commitFile.test.ts +6 -5
  581. package/src/modules/workflow/git/__tests__/git.service.createBranch.test.ts +3 -2
  582. package/src/modules/workflow/git/__tests__/git.service.deleteBranch.test.ts +3 -2
  583. package/src/modules/workflow/git/__tests__/git.service.diffFileAtCommit.test.ts +7 -6
  584. package/src/modules/workflow/git/__tests__/git.service.diffFileBetweenBranches.test.ts +16 -15
  585. package/src/modules/workflow/git/__tests__/git.service.fileContentsAtCommit.test.ts +3 -2
  586. package/src/modules/workflow/git/__tests__/git.service.forkPoint.test.ts +2 -1
  587. package/src/modules/workflow/git/__tests__/git.service.history-guards.test.ts +2 -1
  588. package/src/modules/workflow/git/__tests__/git.service.list-branches.test.ts +10 -9
  589. package/src/modules/workflow/git/__tests__/git.service.listTrackedFiles.test.ts +2 -1
  590. package/src/modules/workflow/git/__tests__/git.service.logForFile.test.ts +6 -5
  591. package/src/modules/workflow/git/__tests__/git.service.mergeChangeRequest.test.ts +9 -8
  592. package/src/modules/workflow/git/__tests__/git.service.pendingChanges.test.ts +2 -1
  593. package/src/modules/workflow/git/__tests__/git.service.postMergePull.test.ts +4 -3
  594. package/src/modules/workflow/git/__tests__/git.service.pull.test.ts +130 -8
  595. package/src/modules/workflow/git/__tests__/git.service.readFileAtRef.test.ts +2 -1
  596. package/src/modules/workflow/git/__tests__/git.service.revertPathsAndPush.test.ts +2 -1
  597. package/src/modules/workflow/git/__tests__/git.service.status.test.ts +4 -3
  598. package/src/modules/workflow/git/__tests__/git.service.syncFromRemote.test.ts +8 -7
  599. package/src/modules/workflow/git/__tests__/node-git-runner.test.ts +41 -3
  600. package/src/modules/workflow/git/__tests__/pull-request.service.getPrDetail.test.ts +145 -2
  601. package/src/modules/workflow/git/__tests__/pull-request.service.viewer-can-delete.test.ts +166 -0
  602. package/src/modules/workflow/git/git.service.ts +49 -17
  603. package/src/modules/workflow/git/node-git-runner.ts +43 -4
  604. package/src/modules/workflow/git/pull-request.service.ts +119 -0
  605. package/src/modules/workflow/review-workflow/review-workflow.service.ts +9 -6
  606. package/src/modules/workflow/session-ontology.service.ts +7 -2
  607. package/src/modules/workflow/workflow.routes.ts +3 -1
  608. package/src/modules/workflow/workflow.service.ts +201 -76
  609. package/src/modules/workspace/__tests__/file-stat-access.test.ts +3 -2
  610. package/src/modules/workspace/__tests__/git-internals.security.test.ts +10 -9
  611. package/src/modules/workspace/__tests__/session-ontology.gate.test.ts +4 -2
  612. package/src/modules/workspace/__tests__/workspace-paths-inside-the-repo.test.ts +3 -2
  613. package/src/modules/workspace/__tests__/workspace.routes.branch-errors.test.ts +2 -1
  614. package/src/modules/workspace/__tests__/workspace.routes.create-grant.test.ts +2 -1
  615. package/src/modules/workspace/__tests__/workspace.routes.delete.test.ts +2 -1
  616. package/src/modules/workspace/__tests__/workspace.routes.download-implies-read.test.ts +2 -1
  617. package/src/modules/workspace/__tests__/workspace.routes.download.test.ts +2 -1
  618. package/src/modules/workspace/__tests__/workspace.routes.file-writes.test.ts +2 -1
  619. package/src/modules/workspace/__tests__/workspace.routes.folders.test.ts +5 -4
  620. package/src/modules/workspace/__tests__/workspace.routes.move-platform-files.test.ts +2 -1
  621. package/src/modules/workspace/__tests__/workspace.routes.read-gate.test.ts +2 -1
  622. package/src/modules/workspace/__tests__/workspace.service.ensure-remotes-fetched.test.ts +2 -2
  623. package/src/modules/workspace/__tests__/workspace.service.list-cloned.test.ts +6 -5
  624. package/src/modules/workspace/__tests__/workspace.service.move-never-overwrites.test.ts +2 -1
  625. package/src/modules/workspace/__tests__/workspace.service.read-filter.test.ts +2 -1
  626. package/src/modules/workspace/__tests__/workspace.service.test.ts +84 -50
  627. package/src/modules/workspace/__tests__/workspace.service.unknown-branch.test.ts +45 -1
  628. package/src/modules/workspace/__tests__/workspace.tools.agents-file.test.ts +10 -7
  629. package/src/modules/workspace/__tests__/workspace.tools.branch-errors.test.ts +237 -10
  630. package/src/modules/workspace/__tests__/workspace.tools.test.ts +44 -11
  631. package/src/modules/workspace/__tests__/write-denial.test.ts +5 -4
  632. package/src/modules/workspace/session-ontology.gate.ts +6 -4
  633. package/src/modules/workspace/startup/__tests__/kb-startup-runner.degraded.test.ts +6 -2
  634. package/src/modules/workspace/startup/__tests__/kb-startup-runner.test.ts +240 -21
  635. package/src/modules/workspace/startup/kb-git.ts +15 -22
  636. package/src/modules/workspace/startup/kb-startup-runner.ts +198 -45
  637. package/src/modules/workspace/startup/steps/__tests__/steps.test.ts +104 -98
  638. package/src/modules/workspace/startup/steps/groups-to-plugins.step.ts +24 -16
  639. package/src/modules/workspace/startup/steps/personal-spaces.step.ts +14 -5
  640. package/src/modules/workspace/startup/steps/plugin-display-names.step.ts +13 -5
  641. package/src/modules/workspace/startup/steps/plugin-manifests.step.ts +14 -5
  642. package/src/modules/workspace/startup/steps/seed-tree.ts +11 -9
  643. package/src/modules/workspace/startup/steps/template-files.step.ts +43 -34
  644. package/src/modules/workspace/startup/steps/template-source.ts +8 -5
  645. package/src/modules/workspace/workspace.routes.ts +8 -7
  646. package/src/modules/workspace/workspace.service.ts +47 -28
  647. package/src/modules/workspace/workspace.tools.ts +56 -20
  648. package/src/modules/workspace/write-denial.ts +7 -5
  649. package/src/shared/__tests__/kb-layout.plugin.test.ts +19 -16
  650. package/src/shared/domain-errors.ts +58 -0
  651. package/src/shared/git.contract.ts +80 -8
  652. package/src/shared/kb-context.ts +130 -0
  653. package/src/shared/kb-layout.test.ts +37 -27
  654. package/src/shared/kb-layout.ts +4 -3
  655. package/src/shared/pending-proposals.ts +7 -4
  656. package/src/shared/redact-secret.ts +5 -5
  657. package/src/tenancy/__tests__/static-tenant-source.test.ts +177 -0
  658. package/src/tenancy/__tests__/tenant-host.test.ts +372 -0
  659. package/src/tenancy/__tests__/tenant-runtime.test.ts +221 -0
  660. package/src/tenancy/__tests__/tenant-secrets.test.ts +35 -0
  661. package/src/tenancy/index.ts +35 -0
  662. package/src/tenancy/static-tenant-source.ts +296 -0
  663. package/src/tenancy/tenant-host.ts +261 -0
  664. package/src/tenancy/tenant-runtime.ts +208 -0
  665. package/src/tenancy/tenant-secrets.ts +41 -0
  666. package/src/tenancy/tenant-source.contract.ts +59 -0
@@ -3,7 +3,7 @@ import fs from 'node:fs/promises';
3
3
  import os from 'node:os';
4
4
  import path from 'node:path';
5
5
  import { NodeGitRunner } from '../node-git-runner.js';
6
- import { GitRunError, isGitTimeout } from '../../../../shared/git.contract.js';
6
+ import { GitRunError, gitCredentials, isGitTimeout } from '../../../../shared/git.contract.js';
7
7
 
8
8
  /**
9
9
  * These run REAL git, like the rest of this module's suites: the behaviours
@@ -94,10 +94,48 @@ describe('NodeGitRunner', () => {
94
94
  expect(true).toBe(true);
95
95
  });
96
96
 
97
+ /**
98
+ * The helper the runner's callers stamp into a clone, reduced to the one
99
+ * thing under test here: what `$GITHUB_TOKEN` is in the child. `credential
100
+ * fill` runs it through git's own shell and prints what it answered, which
101
+ * is the same path a push takes to its password.
102
+ */
103
+ const ECHO_TOKEN_HELPER = `!f() { printf '%s\\n' "username=u" "password=\${GITHUB_TOKEN-none}"; }; f`;
104
+ const fill = (runner: NodeGitRunner, env?: NodeJS.ProcessEnv) =>
105
+ runner.run(dir, ['-c', `credential.helper=${ECHO_TOKEN_HELPER}`, 'credential', 'fill'], {
106
+ input: 'protocol=https\nhost=example.test\n\n',
107
+ env,
108
+ });
109
+
110
+ it('hands its token to the child, where the helper reads it, and never puts it in argv', async () => {
111
+ const runner = new NodeGitRunner(undefined, gitCredentials('x-access-token', 'ghp_child_secret'));
112
+ const { stdout } = await fill(runner);
113
+ expect(stdout).toContain('password=ghp_child_secret');
114
+ });
115
+
116
+ it('drops a token this process inherited: only the credentials in effect reach git', async () => {
117
+ const previous = process.env.GITHUB_TOKEN;
118
+ process.env.GITHUB_TOKEN = 'ghp_stale_in_process_env';
119
+ try {
120
+ const { stdout } = await fill(new NodeGitRunner());
121
+ expect(stdout).toContain('password=none');
122
+ expect(stdout).not.toContain('ghp_stale_in_process_env');
123
+ } finally {
124
+ if (previous === undefined) delete process.env.GITHUB_TOKEN;
125
+ else process.env.GITHUB_TOKEN = previous;
126
+ }
127
+ });
128
+
129
+ it('lets a per-call environment entry win over its own token: the setup probe checks the token it was given', async () => {
130
+ const runner = new NodeGitRunner(undefined, gitCredentials('x-access-token', 'ghp_in_effect'));
131
+ const { stdout } = await fill(runner, { GITHUB_TOKEN: 'ghp_being_checked' });
132
+ expect(stdout).toContain('password=ghp_being_checked');
133
+ });
134
+
97
135
  it('keeps the configured git token out of failures', async () => {
98
- const runner = new NodeGitRunner();
136
+ const runner = new NodeGitRunner(undefined, gitCredentials('x-access-token', 'ghp_secret_value_here'));
99
137
  const previous = process.env.GITHUB_TOKEN;
100
- process.env.GITHUB_TOKEN = 'ghp_secret_value_here';
138
+ delete process.env.GITHUB_TOKEN;
101
139
  try {
102
140
  const err = await runner
103
141
  .run(dir, ['ls-remote', 'https://x-access-token:ghp_secret_value_here@127.0.0.1:1/r.git'], {
@@ -49,7 +49,13 @@ describe('PullRequestService.getPrDetail — git work per read', () => {
49
49
  const resolvePrShas = vi.fn(async () => ({ baseSha: BASE, headSha: HEAD }));
50
50
  const changedFilesForPr = vi.fn(async () => []);
51
51
  const forkPointForPr = vi.fn(async () => ({ mergeBaseSha: FORK, behind: true }));
52
- const git = { resolvePrShas, changedFilesForPr, forkPointForPr } as unknown as GitService;
52
+ const pathsChangedBetween = vi.fn(async () => []);
53
+ const git = {
54
+ resolvePrShas,
55
+ changedFilesForPr,
56
+ forkPointForPr,
57
+ pathsChangedBetween,
58
+ } as unknown as GitService;
53
59
  const workspace = {
54
60
  findAnyWorkspaceId: async () => 'ws-main',
55
61
  ensureRemotesFetched: async () => undefined,
@@ -63,7 +69,14 @@ describe('PullRequestService.getPrDetail — git work per read', () => {
63
69
  getApprovalStates,
64
70
  evaluateMergeGate: () => ({ mergeable: false, reasons: [], warnings: [] }),
65
71
  });
66
- return { svc, resolvePrShas, changedFilesForPr, forkPointForPr, getApprovalStates };
72
+ return {
73
+ svc,
74
+ resolvePrShas,
75
+ changedFilesForPr,
76
+ forkPointForPr,
77
+ pathsChangedBetween,
78
+ getApprovalStates,
79
+ };
67
80
  }
68
81
 
69
82
  it('pins the file list to the SHAs it just resolved, and keeps patches for a client read', async () => {
@@ -179,3 +192,133 @@ describe('PullRequestService — change request link', () => {
179
192
  expect(detail?.urlNote).toBe('Set PUBLIC_FRONTEND_URL to get absolute links.');
180
193
  });
181
194
  });
195
+
196
+ /**
197
+ * `needsUpdate` — the answer the dialog acts on, as distinct from `behind`.
198
+ *
199
+ * `behind` is the honest git fact that the two branches have diverged. On a
200
+ * knowledge base where every shared save commits to the default branch it is
201
+ * true again minutes after every update, and acting on it made opening a
202
+ * request pay for a merge on almost every open — for changes to files the
203
+ * request does not contain. `needsUpdate` adds the half that matters: the
204
+ * target changed a file THIS request also changes.
205
+ */
206
+ describe('PullRequestService.getPrDetail — needsUpdate', () => {
207
+ const FILE = 'Sales/Deal.md';
208
+ const OTHER = 'Ops/Runbook.md';
209
+
210
+ function harness(opts: {
211
+ behind?: boolean;
212
+ mergeBaseSha?: string | null;
213
+ files?: { path: string; previousPath?: string }[];
214
+ changedOnTarget?: string[];
215
+ changedOnTargetError?: Error;
216
+ state?: string;
217
+ } = {}) {
218
+ const resolvePrShas = vi.fn(async () => ({ baseSha: BASE, headSha: HEAD }));
219
+ const changedFilesForPr = vi.fn(async () => (opts.files ?? [{ path: FILE }]) as never);
220
+ const forkPointForPr = vi.fn(async () => ({
221
+ mergeBaseSha: opts.mergeBaseSha === undefined ? FORK : opts.mergeBaseSha,
222
+ behind: opts.behind ?? true,
223
+ }));
224
+ const pathsChangedBetween = opts.changedOnTargetError
225
+ ? vi.fn().mockRejectedValue(opts.changedOnTargetError)
226
+ : vi.fn(async () => opts.changedOnTarget ?? []);
227
+ const git = {
228
+ resolvePrShas,
229
+ changedFilesForPr,
230
+ forkPointForPr,
231
+ pathsChangedBetween,
232
+ } as unknown as GitService;
233
+ const workspace = {
234
+ findAnyWorkspaceId: async () => 'ws-main',
235
+ ensureRemotesFetched: async () => undefined,
236
+ } as unknown as WorkspaceService;
237
+ const access = { canWriteAtRef: async () => false } as unknown as IAccessControl;
238
+ const db = {
239
+ select: () => ({
240
+ from: () => ({
241
+ where: () => ({ limit: async () => [{ ...ROW, state: opts.state ?? 'open' }] }),
242
+ }),
243
+ }),
244
+ } as unknown as Database;
245
+ const svc = new PullRequestService(db, workspace, access, git);
246
+ svc.setDetailEnricher({
247
+ listComments: async () => [],
248
+ getApprovalStates: async () => [],
249
+ evaluateMergeGate: () => ({ mergeable: false, reasons: [], warnings: [] }),
250
+ });
251
+ return { svc, pathsChangedBetween };
252
+ }
253
+
254
+ it('is false when the target moved in files this request does not change', async () => {
255
+ // The case that made the message appear on essentially every open: a
256
+ // shared save somewhere else in the knowledge base.
257
+ const h = harness({ files: [{ path: FILE }], changedOnTarget: [OTHER] });
258
+ const detail = await h.svc.getPrDetail(7, { fresh: true });
259
+ expect(detail?.behind).toBe(true);
260
+ expect(detail?.needsUpdate).toBe(false);
261
+ });
262
+
263
+ it('is true when the target changed a file this request also changes', async () => {
264
+ const h = harness({ files: [{ path: FILE }], changedOnTarget: [OTHER, FILE] });
265
+ const detail = await h.svc.getPrDetail(7, { fresh: true });
266
+ expect(detail?.needsUpdate).toBe(true);
267
+ // Intersected over the fork point → the target's tip: the same two
268
+ // commits the rest of the detail is pinned to.
269
+ expect(h.pathsChangedBetween).toHaveBeenCalledWith('ws-main', FORK, BASE);
270
+ });
271
+
272
+ it('asks git nothing at all when the request is not behind', async () => {
273
+ // The common case, and the one that has to stay free.
274
+ const h = harness({ behind: false });
275
+ const detail = await h.svc.getPrDetail(7, { fresh: true });
276
+ expect(detail?.needsUpdate).toBe(false);
277
+ expect(h.pathsChangedBetween).not.toHaveBeenCalled();
278
+ });
279
+
280
+ it('asks git nothing when the request changes no files', async () => {
281
+ const h = harness({ files: [], changedOnTarget: [FILE] });
282
+ const detail = await h.svc.getPrDetail(7, { fresh: true });
283
+ expect(detail?.needsUpdate).toBe(false);
284
+ expect(h.pathsChangedBetween).not.toHaveBeenCalled();
285
+ });
286
+
287
+ it('counts a file the target RENAMED, under either of its names', async () => {
288
+ // `pathsChangedBetween` runs without rename detection, so the target's
289
+ // rename reports the path it left as well as the one it arrived at — and
290
+ // a request still editing the old name is affected.
291
+ const h = harness({
292
+ files: [{ path: FILE }],
293
+ changedOnTarget: [FILE, 'Sales/Deal-2026.md'],
294
+ });
295
+ expect((await h.svc.getPrDetail(7, { fresh: true }))?.needsUpdate).toBe(true);
296
+ });
297
+
298
+ it('counts a file THIS request renamed, under the name it came from', async () => {
299
+ const h = harness({
300
+ files: [{ path: 'Sales/Deal-final.md', previousPath: FILE }],
301
+ changedOnTarget: [FILE],
302
+ });
303
+ expect((await h.svc.getPrDetail(7, { fresh: true }))?.needsUpdate).toBe(true);
304
+ });
305
+
306
+ it('is true when the branches share no history — there is nothing to intersect', async () => {
307
+ const h = harness({ mergeBaseSha: null });
308
+ const detail = await h.svc.getPrDetail(7, { fresh: true });
309
+ expect(detail?.needsUpdate).toBe(true);
310
+ expect(h.pathsChangedBetween).not.toHaveBeenCalled();
311
+ });
312
+
313
+ it('is true when the comparison itself fails — an infra error is not "this is fine"', async () => {
314
+ const h = harness({ changedOnTargetError: new Error('git exploded') });
315
+ expect((await h.svc.getPrDetail(7, { fresh: true }))?.needsUpdate).toBe(true);
316
+ });
317
+
318
+ it('is false for a request that is not open, whatever git says', async () => {
319
+ const h = harness({ state: 'merged', changedOnTarget: [FILE] });
320
+ const detail = await h.svc.getPrDetail(7, { fresh: true });
321
+ expect(detail?.needsUpdate).toBe(false);
322
+ expect(detail?.behind).toBe(false);
323
+ });
324
+ });
@@ -0,0 +1,166 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { computeViewerCanDelete } from '../pull-request.service.js';
3
+ import { hashEmail } from '../../../../shared/email-identity.js';
4
+
5
+ const EMAIL = 'juan@bevel.software';
6
+ const AUTHOR_HASH = hashEmail(EMAIL);
7
+ const OTHER_AUTHOR_HASH = hashEmail('someone-else@bevel.software');
8
+
9
+ /**
10
+ * The truth table for who may delete a request outright — close it AND retire
11
+ * its branch. It must mirror `deleteChangeRequest`'s own check, which is why
12
+ * the interesting rows here are the ones where it DIFFERS from its siblings:
13
+ * an owner of every changed file is absent (they decline, they do not
14
+ * destroy), and a closed request still says yes (its leftover branch is still
15
+ * the server's to retire).
16
+ */
17
+ describe('computeViewerCanDelete', () => {
18
+ it('lets the author delete their own open request', () => {
19
+ expect(
20
+ computeViewerCanDelete({
21
+ state: 'open',
22
+ authorId: AUTHOR_HASH,
23
+ viewerEmail: EMAIL,
24
+ viewerCanBypassMerge: false,
25
+ }),
26
+ ).toBe(true);
27
+ });
28
+
29
+ it('lets an admin delete someone else’s open request', () => {
30
+ expect(
31
+ computeViewerCanDelete({
32
+ state: 'open',
33
+ authorId: OTHER_AUTHOR_HASH,
34
+ viewerEmail: EMAIL,
35
+ viewerCanBypassMerge: true,
36
+ }),
37
+ ).toBe(true);
38
+ });
39
+
40
+ it('says yes once for a viewer who is both author and admin', () => {
41
+ expect(
42
+ computeViewerCanDelete({
43
+ state: 'open',
44
+ authorId: AUTHOR_HASH,
45
+ viewerEmail: EMAIL,
46
+ viewerCanBypassMerge: true,
47
+ }),
48
+ ).toBe(true);
49
+ });
50
+
51
+ it('refuses a signed-in user who is neither author nor admin', () => {
52
+ expect(
53
+ computeViewerCanDelete({
54
+ state: 'open',
55
+ authorId: OTHER_AUTHOR_HASH,
56
+ viewerEmail: EMAIL,
57
+ viewerCanBypassMerge: false,
58
+ }),
59
+ ).toBe(false);
60
+ });
61
+
62
+ it('fails closed with no viewer, even on one’s own-looking request', () => {
63
+ expect(
64
+ computeViewerCanDelete({
65
+ state: 'open',
66
+ authorId: AUTHOR_HASH,
67
+ viewerEmail: undefined,
68
+ viewerCanBypassMerge: false,
69
+ }),
70
+ ).toBe(false);
71
+ });
72
+
73
+ it('fails closed for an anonymous admin-flagged read', () => {
74
+ expect(
75
+ computeViewerCanDelete({
76
+ state: 'open',
77
+ authorId: OTHER_AUTHOR_HASH,
78
+ viewerEmail: undefined,
79
+ viewerCanBypassMerge: true,
80
+ }),
81
+ ).toBe(false);
82
+ });
83
+
84
+ it('refuses an APPLIED request to its author — applied history is nobody’s to delete', () => {
85
+ expect(
86
+ computeViewerCanDelete({
87
+ state: 'merged',
88
+ authorId: AUTHOR_HASH,
89
+ viewerEmail: EMAIL,
90
+ viewerCanBypassMerge: false,
91
+ }),
92
+ ).toBe(false);
93
+ });
94
+
95
+ it('refuses an APPLIED request to an admin too', () => {
96
+ expect(
97
+ computeViewerCanDelete({
98
+ state: 'merged',
99
+ authorId: OTHER_AUTHOR_HASH,
100
+ viewerEmail: EMAIL,
101
+ viewerCanBypassMerge: true,
102
+ }),
103
+ ).toBe(false);
104
+ });
105
+
106
+ it('still says yes on a CLOSED request: the leftover branch is the delete’s job', () => {
107
+ // Withdrawn in another tab. The server's delete still succeeds there and
108
+ // removes the branch the withdraw left behind, so the hint must not go
109
+ // quiet the moment the row flips — unlike `viewerCanCancel`, which is
110
+ // open-only because there is nothing left to cancel.
111
+ expect(
112
+ computeViewerCanDelete({
113
+ state: 'closed',
114
+ authorId: AUTHOR_HASH,
115
+ viewerEmail: EMAIL,
116
+ viewerCanBypassMerge: false,
117
+ }),
118
+ ).toBe(true);
119
+ expect(
120
+ computeViewerCanDelete({
121
+ state: 'closed',
122
+ authorId: OTHER_AUTHOR_HASH,
123
+ viewerEmail: EMAIL,
124
+ viewerCanBypassMerge: true,
125
+ }),
126
+ ).toBe(true);
127
+ });
128
+
129
+ it('refuses a request with no stored author to a non-admin (opened outside this backend)', () => {
130
+ expect(
131
+ computeViewerCanDelete({
132
+ state: 'open',
133
+ authorId: undefined,
134
+ viewerEmail: EMAIL,
135
+ viewerCanBypassMerge: false,
136
+ }),
137
+ ).toBe(false);
138
+ });
139
+
140
+ it('leaves normalization to hashEmail, exactly as its siblings do', () => {
141
+ expect(
142
+ computeViewerCanDelete({
143
+ state: 'open',
144
+ authorId: AUTHOR_HASH,
145
+ viewerEmail: ' Juan@Bevel.Software ',
146
+ viewerCanBypassMerge: false,
147
+ }),
148
+ ).toBe(true);
149
+ });
150
+
151
+ it('does NOT grant the owner of every changed file — it takes no such input', () => {
152
+ // Decision 4. The owner of every changed file is exactly the person
153
+ // `computeViewerCanCancel` says yes to and this predicate must not: they
154
+ // may decline the request, which leaves the author's branch to rework.
155
+ // There is no input here to express that grant, and the row a
156
+ // file-owning non-admin produces reads false.
157
+ expect(
158
+ computeViewerCanDelete({
159
+ state: 'open',
160
+ authorId: OTHER_AUTHOR_HASH,
161
+ viewerEmail: EMAIL,
162
+ viewerCanBypassMerge: false,
163
+ }),
164
+ ).toBe(false);
165
+ });
166
+ });
@@ -26,9 +26,8 @@ import {
26
26
  assertValidRelativePath,
27
27
  isBranchAuthoredBy,
28
28
  isOwnSuggestionsBranch,
29
- isProtectedBranch,
30
- PROTECTED_BRANCHES,
31
29
  } from '../../kb-fs/branch-name.js';
30
+ import type { KbContext } from '../../../shared/kb-context.js';
32
31
  import {
33
32
  BranchAuthorshipError,
34
33
  WorkflowDomainError,
@@ -42,6 +41,7 @@ import {
42
41
  GitRunError,
43
42
  isGitTimeout,
44
43
  redactGitToken,
44
+ type GitCredentials,
45
45
  type GitRunOptions,
46
46
  type GitRunResult,
47
47
  type IGitRunner,
@@ -296,7 +296,7 @@ export class GitService implements IGitService {
296
296
  * safe because validation is advisory and never blocks a commit.
297
297
  */
298
298
  private readonly hooks: WorkflowHooks,
299
- private readonly kbDirName: string,
299
+ private readonly kb: KbContext,
300
300
  private readonly mutex: WorkspaceMutex = new WorkspaceMutex(),
301
301
  private readonly accessControl: IAccessControl | null = null,
302
302
  /**
@@ -309,6 +309,18 @@ export class GitService implements IGitService {
309
309
  private readonly gitRunner: IGitRunner = new NodeGitRunner(),
310
310
  ) {}
311
311
 
312
+ private get kbDirName(): string {
313
+ return this.kb.kbDirName;
314
+ }
315
+
316
+ /**
317
+ * The credentials the runner authenticates with — for the services above
318
+ * this one that scrub a message git or the host echoed a token into.
319
+ */
320
+ get credentials(): GitCredentials {
321
+ return this.gitRunner.credentials;
322
+ }
323
+
312
324
  /**
313
325
  * "Does the pending-commits queue hold rows for this workspace?" — used by
314
326
  * `statusInternal` to tell an expected dirty tree (queued saves still
@@ -552,7 +564,7 @@ export class GitService implements IGitService {
552
564
  );
553
565
  infos[i] = {
554
566
  name: row.shortName,
555
- isProtected: isProtectedBranch(row.shortName),
567
+ isProtected: this.kb.isProtectedBranch(row.shortName),
556
568
  ahead,
557
569
  behind,
558
570
  hasRemote: row.hasRemote,
@@ -655,7 +667,7 @@ export class GitService implements IGitService {
655
667
  fromBase?: string,
656
668
  ): Promise<BranchInfo> {
657
669
  assertValidBranchName(name);
658
- if (isProtectedBranch(name)) {
670
+ if (this.kb.isProtectedBranch(name)) {
659
671
  throw new ProtectedBranchError(name, 'creating a protected branch');
660
672
  }
661
673
  if (fromBase) assertValidBranchName(fromBase);
@@ -731,7 +743,7 @@ export class GitService implements IGitService {
731
743
  opts: { onlyIfNoRemote?: boolean; systemCleanup?: boolean } = {},
732
744
  ): Promise<void> {
733
745
  assertValidBranchName(name);
734
- if (isProtectedBranch(name)) {
746
+ if (this.kb.isProtectedBranch(name)) {
735
747
  throw new ProtectedBranchError(name, 'deleting a protected branch');
736
748
  }
737
749
  return this.mutex.run(workspaceId, async () => {
@@ -895,7 +907,7 @@ export class GitService implements IGitService {
895
907
  // boundary. Without this guard, the standard "fork to draft then
896
908
  // propose" workflow would 403 for non-admins — they can't write
897
909
  // protected, can't write the draft they forked from it either.
898
- if (isProtectedBranch(branch)) {
910
+ if (this.kb.isProtectedBranch(branch)) {
899
911
  // Gate against the access tree as it exists at HEAD — the pre-commit
900
912
  // state. Reading from the working tree would let the user broaden
901
913
  // their own access by editing access.md alongside the change they're
@@ -1172,7 +1184,7 @@ export class GitService implements IGitService {
1172
1184
  // Protected-branch access gate (defence in depth — callers already gate at
1173
1185
  // lock-acquire / upload-mint, but this primitive is generic). Gate every
1174
1186
  // touched path against the access tree at HEAD, like `commit()`.
1175
- if (isProtectedBranch(branch)) {
1187
+ if (this.kb.isProtectedBranch(branch)) {
1176
1188
  await this.assertCanWriteAtRef(workspaceId, 'HEAD', user.email, touched);
1177
1189
  }
1178
1190
 
@@ -1292,7 +1304,7 @@ export class GitService implements IGitService {
1292
1304
  // decided the write is legitimate (unused name, exclusive create);
1293
1305
  // gating it here again just refuses every non-admin the product
1294
1306
  // promised a plugin to.
1295
- if (isProtectedBranch(branch) && !opts?.systemAuthorized) {
1307
+ if (this.kb.isProtectedBranch(branch) && !opts?.systemAuthorized) {
1296
1308
  const touched = await this.unpushedTouchedPaths(cwd);
1297
1309
  await this.assertCanWriteAtRef(
1298
1310
  workspaceId,
@@ -1542,6 +1554,7 @@ export class GitService implements IGitService {
1542
1554
  throw new Error(
1543
1555
  `git merge failed without detectable conflicts: ${redactGitToken(
1544
1556
  err instanceof Error ? err.message : String(err),
1557
+ this.credentials.token(),
1545
1558
  )}`,
1546
1559
  );
1547
1560
  }
@@ -1747,7 +1760,12 @@ export class GitService implements IGitService {
1747
1760
  * conflict into the typed error the workflow layer queues recovery for.
1748
1761
  * Shared by `pull` and `syncFromRemote` so the two cannot drift.
1749
1762
  */
1750
- private async rebaseOntoRemote(cwd: string, branch: string, remoteRef: string): Promise<void> {
1763
+ private async rebaseOntoRemote(
1764
+ cwd: string,
1765
+ branch: string,
1766
+ remoteRef: string,
1767
+ opts: { preserveMerges?: boolean } = {},
1768
+ ): Promise<void> {
1751
1769
  // An UNBORN HEAD (a clone of an upstream that was empty when cloned) has
1752
1770
  // no commit to replay and `git rebase` refuses to start from it, so the
1753
1771
  // branch is moved to the remote commit instead. That is only safe while
@@ -1785,7 +1803,20 @@ export class GitService implements IGitService {
1785
1803
  // the local commits onto origin, then reapplies them, so the retry
1786
1804
  // push can fast-forward. Untracked files don't block rebase and are
1787
1805
  // left untouched.
1788
- await this.git(cwd, ['rebase', '--autostash', remoteRef]);
1806
+ // `--rebase-merges` is what keeps an unpushed MERGE a merge. Plain
1807
+ // rebase replays `--no-merges upstream..HEAD`, which turns a merge
1808
+ // commit the clone holds but origin has not seen into cherry-picks of
1809
+ // the commits it merged — the merged branch stops being a parent, so
1810
+ // "does the published head contain the target's head" answers no
1811
+ // however many times the update runs. Only the change-request update
1812
+ // asks for it; every other pull replays plain saves, where the two
1813
+ // spellings produce the same history.
1814
+ await this.git(cwd, [
1815
+ 'rebase',
1816
+ '--autostash',
1817
+ ...(opts.preserveMerges ? ['--rebase-merges'] : []),
1818
+ remoteRef,
1819
+ ]);
1789
1820
  } catch (err) {
1790
1821
  // Capture the contested paths BEFORE the abort wipes the rebase
1791
1822
  // state — `--diff-filter=U` lists exactly the files whose replay
@@ -1909,7 +1940,10 @@ export class GitService implements IGitService {
1909
1940
  });
1910
1941
  }
1911
1942
 
1912
- async pull(workspaceId: string): Promise<{ treeChanged: boolean }> {
1943
+ async pull(
1944
+ workspaceId: string,
1945
+ opts: { preserveMerges?: boolean } = {},
1946
+ ): Promise<{ treeChanged: boolean }> {
1913
1947
  return this.mutex.run(workspaceId, async () => {
1914
1948
  const cwd = await this.repoDir(workspaceId);
1915
1949
  const branch = await this.checkedOutBranch(cwd);
@@ -1922,7 +1956,7 @@ export class GitService implements IGitService {
1922
1956
  // Refresh WITHOUT `git pull`, and without touching `FETCH_HEAD` — see
1923
1957
  // `refreshRemoteBranchRef` for why both halves are load-bearing.
1924
1958
  const remoteRef = await this.refreshRemoteBranchRef(cwd, branch);
1925
- await this.rebaseOntoRemote(cwd, branch, remoteRef);
1959
+ await this.rebaseOntoRemote(cwd, branch, remoteRef, opts);
1926
1960
  this.accessControl?.invalidate(workspaceId);
1927
1961
  const treeAfter = (await this.revParseOrNull(cwd, 'HEAD^{tree}')) ?? '';
1928
1962
  return { treeChanged: treeAfter !== treeBefore };
@@ -2109,7 +2143,7 @@ export class GitService implements IGitService {
2109
2143
  return this.mutex.run(workspaceId, async () => {
2110
2144
  const cwd = await this.repoDir(workspaceId);
2111
2145
  let best: { base: string; ahead: number } | null = null;
2112
- for (const p of PROTECTED_BRANCHES) {
2146
+ for (const p of this.kb.protectedBranches) {
2113
2147
  if (p === branch) continue;
2114
2148
  const res = await this.tryAheadBehind(cwd, branch, `origin/${p}`);
2115
2149
  if (res && (best === null || res.ahead < best.ahead)) {
@@ -3133,7 +3167,7 @@ export class GitService implements IGitService {
3133
3167
  }
3134
3168
 
3135
3169
  let best: { ahead: number; behind: number } | null = null;
3136
- for (const p of PROTECTED_BRANCHES) {
3170
+ for (const p of this.kb.protectedBranches) {
3137
3171
  if (p === shortName) continue;
3138
3172
  const res = await this.tryAheadBehind(cwd, ref, `refs/remotes/origin/${p}`);
3139
3173
  if (res && (best === null || res.ahead < best.ahead)) best = res;
@@ -3447,5 +3481,3 @@ export function parseNumstatZ(out: string): NumstatEntry[] {
3447
3481
  }
3448
3482
  return entries;
3449
3483
  }
3450
-
3451
- export { PROTECTED_BRANCHES };
@@ -1,7 +1,10 @@
1
1
  import { spawn, type ChildProcess, type SpawnOptions } from 'node:child_process';
2
2
  import {
3
+ GIT_TOKEN_ENV,
3
4
  GitRunError,
5
+ NO_GIT_CREDENTIALS,
4
6
  redactGitToken,
7
+ type GitCredentials,
5
8
  type GitRunOptions,
6
9
  type GitRunResult,
7
10
  type IGitRunner,
@@ -212,7 +215,33 @@ function spawnGit(args: string[], options: SpawnOptions & { maxBuffer: number })
212
215
  * `WorkspaceMutex`'s job and stays the caller's to have done.
213
216
  */
214
217
  export class NodeGitRunner implements IGitRunner {
215
- constructor(readonly defaultTimeoutMs: number = DEFAULT_GIT_TIMEOUT_MS) {}
218
+ constructor(
219
+ readonly defaultTimeoutMs: number = DEFAULT_GIT_TIMEOUT_MS,
220
+ /**
221
+ * What every call authenticates with. The token goes into the CHILD's
222
+ * environment only (see {@link childEnv}); a runner built without one
223
+ * runs git unauthenticated, which is what a directly constructed service
224
+ * in a test gets.
225
+ */
226
+ readonly credentials: GitCredentials = NO_GIT_CREDENTIALS,
227
+ ) {}
228
+
229
+ /**
230
+ * The environment one invocation runs under. The token in effect goes in
231
+ * under {@link GIT_TOKEN_ENV}, and a stale one this process inherited from
232
+ * its own environment goes OUT: a server hosting several knowledge bases
233
+ * must never let one knowledge base's git call find another's token, or an
234
+ * operator's, lying in `process.env`. A caller's per-call entry still wins
235
+ * over the provider's (the setup probe runs with the token it is checking,
236
+ * not the one in effect), and the fixed entries win over everything.
237
+ */
238
+ private childEnv(overrides: NodeJS.ProcessEnv | undefined): NodeJS.ProcessEnv {
239
+ const env: NodeJS.ProcessEnv = { ...process.env };
240
+ delete env[GIT_TOKEN_ENV];
241
+ const token = this.credentials.token();
242
+ if (token) env[GIT_TOKEN_ENV] = token;
243
+ return { ...env, ...overrides, ...FIXED_ENV };
244
+ }
216
245
 
217
246
  run(cwd: string, args: string[], opts: GitRunOptions & { encoding: 'buffer' }): Promise<GitRunResult<Buffer>>;
218
247
  run(cwd: string, args: string[], opts?: GitRunOptions & { encoding?: 'utf8' }): Promise<GitRunResult>;
@@ -221,10 +250,16 @@ export class NodeGitRunner implements IGitRunner {
221
250
  const timers: NodeJS.Timeout[] = [];
222
251
  let timedOut = false;
223
252
 
253
+ // A credential that expires is renewed before it is read. Renewing is
254
+ // the credential's own business and its failure is not this call's:
255
+ // plenty of git never leaves the disk, and a call that does is told by
256
+ // the host what the token in hand is worth.
257
+ await this.credentials.prepare?.().catch(() => undefined);
258
+
224
259
  try {
225
260
  const { promise: pending, child } = spawnGit(args, {
226
261
  cwd,
227
- env: { ...process.env, ...opts.env, ...FIXED_ENV },
262
+ env: this.childEnv(opts.env),
228
263
  maxBuffer: MAX_OUTPUT_BYTES,
229
264
  // Makes the child a process-group leader so that `killTree` can signal
230
265
  // the transport helpers it spawns, not just git itself. Not on Windows,
@@ -291,9 +326,13 @@ export class NodeGitRunner implements IGitRunner {
291
326
  : Buffer.isBuffer(original.stderr)
292
327
  ? original.stderr.toString()
293
328
  : undefined;
294
- throw new GitRunError(`git ${subcommand} failed: ${redactGitToken(message)}`, {
329
+ // Scrubbed with the token THIS runner handed the child, and the one a
330
+ // caller laid over it for the call: both can be echoed back by git.
331
+ const secrets = [this.credentials.token(), opts.env?.[GIT_TOKEN_ENV]];
332
+ const scrub = (text: string): string => secrets.reduce<string>((out, token) => redactGitToken(out, token), text);
333
+ throw new GitRunError(`git ${subcommand} failed: ${scrub(message)}`, {
295
334
  exitCode: typeof original.code === 'number' ? original.code : undefined,
296
- stderr: stderr === undefined ? undefined : redactGitToken(stderr),
335
+ stderr: stderr === undefined ? undefined : scrub(stderr),
297
336
  });
298
337
  } finally {
299
338
  // Every timer is cleared on every path. The later ones in particular