@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
@@ -1,4 +1,5 @@
1
1
  import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
2
+ import { testKbContext } from '../../../__tests__/kb-context.js';
2
3
  import { execFile } from 'node:child_process';
3
4
  import { promisify } from 'node:util';
4
5
  import fs from 'node:fs/promises';
@@ -63,7 +64,7 @@ describe('WorkspaceService — a branch origin does not have', () => {
63
64
  const deleteOnHost = (branch: string): Promise<void> => runGit(upstream, ['branch', '-D', branch]);
64
65
 
65
66
  const service = (repoUrl = upstream): WorkspaceService =>
66
- new WorkspaceService(workspacesRoot, repoUrl, 'knowledge-base', new NodeFs());
67
+ new WorkspaceService(workspacesRoot, repoUrl, testKbContext(), new NodeFs());
67
68
 
68
69
  it('a name nothing has ever cloned or listed is a 404 that names only the branch', async () => {
69
70
  const svc = service();
@@ -76,6 +77,49 @@ describe('WorkspaceService — a branch origin does not have', () => {
76
77
  });
77
78
  });
78
79
 
80
+ /**
81
+ * The second defect on this ticket. A bootstrap that fails to clone used to
82
+ * leave its workspace directory behind, and a directory named after a branch
83
+ * is one of the ways the platform remembers having KNOWN a branch. So the
84
+ * first attempt at a typo answered 404 and then quietly created the evidence
85
+ * that turned every later attempt into 410 — the reader was told a branch
86
+ * they had invented "no longer exists on the remote".
87
+ */
88
+ it('leaves nothing on disk when the clone fails, so a second attempt is still a 404', async () => {
89
+ const svc = service();
90
+
91
+ await expect(svc.getOrCreateForBranch('nobody/never-made-this')).rejects.toMatchObject({
92
+ name: 'BranchNotFoundError',
93
+ status: 404,
94
+ });
95
+ // The failed bootstrap rolled back completely — not the clone directory,
96
+ // not the workspace shell around it.
97
+ expect(await fs.readdir(workspacesRoot)).toEqual([]);
98
+
99
+ // The same name again, on the same instance that has now already failed on
100
+ // it once. Nothing about the first failure may change this answer.
101
+ await expect(svc.getOrCreateForBranch('nobody/never-made-this')).rejects.toMatchObject({
102
+ name: 'BranchNotFoundError',
103
+ status: 404,
104
+ message: 'There is no branch named nobody/never-made-this.',
105
+ payload: { kind: 'branch-not-found', branch: 'nobody/never-made-this' },
106
+ });
107
+ expect(await fs.readdir(workspacesRoot)).toEqual([]);
108
+ });
109
+
110
+ it('does not count a bare directory with no clone in it as a branch it knew', async () => {
111
+ // A shell left by an older process (one that crashed mid-bootstrap, or that
112
+ // predates the rollback above). The "have I heard of this branch" probe asks
113
+ // for a COMPLETED clone, so a directory with no `.git` under it is absence:
114
+ // the honest 404 survives whatever is lying around the workspaces root.
115
+ await fs.mkdir(path.join(workspacesRoot, workspaceIdForBranch('nobody/never-made-this')), { recursive: true });
116
+
117
+ await expect(service().getOrCreateForBranch('nobody/never-made-this')).rejects.toMatchObject({
118
+ name: 'BranchNotFoundError',
119
+ status: 404,
120
+ });
121
+ });
122
+
79
123
  it('a name a listing showed us, and origin no longer has, stays a 410', async () => {
80
124
  const svc = service();
81
125
  // What the branch selector saw while the draft still existed.
@@ -2,7 +2,8 @@ import express from 'express';
2
2
  import { afterEach, describe, expect, it } from 'vitest';
3
3
  import { join } from 'node:path';
4
4
  import { tmpdir } from 'node:os';
5
- import { DEFAULT_KB_LAYOUT, configureKbLayout } from '@bevel-software/platform-shared';
5
+ import { DEFAULT_KB_LAYOUT } from '@bevel-software/platform-shared';
6
+ import { testKbContext } from '../../../__tests__/kb-context.js';
6
7
  import { ToolRegistry } from '../../tool-registry/tool-registry.js';
7
8
  import { createToolHandlerFactory } from '../../tool-helpers/tool-handler.js';
8
9
  import type { ToolAuth } from '../../tool-auth/tool-auth.middleware.js';
@@ -24,6 +25,8 @@ import { registerWorkspaceTools } from '../workspace.tools.js';
24
25
  * for it.
25
26
  */
26
27
  const KB_DIR = 'knowledge-base';
28
+ /** The context the tools read; a case applies a deployment's own names to it. */
29
+ const kb = testKbContext({ kbDirName: KB_DIR });
27
30
 
28
31
  /** Every workspace tool's description, keyed by name, under the layout in effect. */
29
32
  async function descriptions(registry: ToolRegistry = new ToolRegistry()): Promise<Map<string, string>> {
@@ -37,11 +40,11 @@ async function descriptions(registry: ToolRegistry = new ToolRegistry()): Promis
37
40
  new SpillStore(join(tmpdir(), 'bevel-test-spills')),
38
41
  new DocExtractService(join(tmpdir(), 'bevel-test-doc-extract')),
39
42
  {} as unknown as IAccessControl,
40
- KB_DIR,
43
+ kb,
41
44
  {
42
45
  service: {} as never,
43
46
  enabled: false,
44
- kbDirName: KB_DIR,
47
+ kb,
45
48
  recoveryBotEmail: 'recovery-bot@bevel.local',
46
49
  hooks: new WorkflowHooks(),
47
50
  },
@@ -57,7 +60,7 @@ async function listed(registry: ToolRegistry): Promise<Map<string, string>> {
57
60
  return new Map(tools.map((t) => [t.name, t.description ?? '']));
58
61
  }
59
62
 
60
- afterEach(() => configureKbLayout({ ...DEFAULT_KB_LAYOUT }));
63
+ afterEach(() => kb.applyLayout({ ...DEFAULT_KB_LAYOUT }));
61
64
 
62
65
  describe('the conventions note every workspace tool carries', () => {
63
66
  it('names AGENTS.md, and CLAUDE.md beside it, under the default name', async () => {
@@ -71,7 +74,7 @@ describe('the conventions note every workspace tool carries', () => {
71
74
  });
72
75
 
73
76
  it('names the configured file first and the organisation\'s own AGENTS.md second', async () => {
74
- configureKbLayout({ ...DEFAULT_KB_LAYOUT, agentsFile: 'HEXIS.md' });
77
+ kb.applyLayout({ ...DEFAULT_KB_LAYOUT, agentsFile: 'HEXIS.md' });
75
78
  const byName = await descriptions();
76
79
  const note = byName.get('grep') ?? '';
77
80
  expect(note).toContain('read `HEXIS.md` at the KB root, then `AGENTS.md` if it also exists');
@@ -83,7 +86,7 @@ describe('the conventions note every workspace tool carries', () => {
83
86
  });
84
87
 
85
88
  it('describes the platform files under the configured name, and no longer under AGENTS.md', async () => {
86
- configureKbLayout({ ...DEFAULT_KB_LAYOUT, agentsFile: 'HEXIS.md' });
89
+ kb.applyLayout({ ...DEFAULT_KB_LAYOUT, agentsFile: 'HEXIS.md' });
87
90
  const byName = await descriptions();
88
91
  const stat = byName.get('file_stat') ?? '';
89
92
  expect(stat).toContain('`access.md`, `roles.yaml`, `.bevelignore`, `HEXIS.md`');
@@ -117,7 +120,7 @@ describe('the conventions note every workspace tool carries', () => {
117
120
  const atMount = await descriptions(registry);
118
121
  expect(atMount.get('grep')).toContain('read `AGENTS.md` at the KB root');
119
122
 
120
- configureKbLayout({ ...DEFAULT_KB_LAYOUT, agentsFile: 'HEXIS.md' });
123
+ kb.applyLayout({ ...DEFAULT_KB_LAYOUT, agentsFile: 'HEXIS.md' });
121
124
 
122
125
  const now = await listed(registry);
123
126
  expect(now.get('grep')).toContain('read `HEXIS.md` at the KB root, then `AGENTS.md` if it also exists');
@@ -1,11 +1,16 @@
1
1
  import type { Server as HttpServer } from 'node:http';
2
2
  import { execFile } from 'node:child_process';
3
- import { mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises';
3
+ import { mkdir, mkdtemp, readdir, rm, writeFile } from 'node:fs/promises';
4
4
  import { tmpdir } from 'node:os';
5
5
  import { join } from 'node:path';
6
6
  import { promisify } from 'node:util';
7
7
  import express from 'express';
8
8
  import { afterEach, describe, expect, it } from 'vitest';
9
+ import '@utcp/http'; // registers the http CallTemplate serializer + protocol
10
+ import { UtcpManualSerializer } from '@utcp/sdk';
11
+ import { HttpCallTemplateSerializer } from '@utcp/http';
12
+ import { CodeModeUtcpClient } from '../../code-mode/index.js';
13
+ import { testKbContext } from '../../../__tests__/kb-context.js';
9
14
  import { NodeFs } from '../../kb-fs/node-fs.js';
10
15
  import { ToolRegistry } from '../../tool-registry/tool-registry.js';
11
16
  import { createToolHandlerFactory } from '../../tool-helpers/tool-handler.js';
@@ -85,7 +90,12 @@ describe('workspace tools — a branch that cannot be opened', () => {
85
90
  * real tool-context resolver — so a tool call clones (or fails to clone)
86
91
  * exactly as it does in production.
87
92
  */
88
- async function start(opts: { repoUrl?: 'origin' | 'unreachable' } = {}): Promise<string> {
93
+ /** The tool defs the mounted registry serves, kept for the sweep below. */
94
+ let internalTools: { name: string; inputs: unknown }[] = [];
95
+
96
+ async function start(
97
+ opts: { repoUrl?: 'origin' | 'unreachable'; scope?: 'read' | 'write'; source?: 'internal' | 'external' } = {},
98
+ ): Promise<string> {
89
99
  root = await mkdtemp(join(tmpdir(), 'ws-tools-branch-'));
90
100
  spillRoot = await mkdtemp(join(tmpdir(), 'ws-tools-spill-'));
91
101
  docCacheDir = await mkdtemp(join(tmpdir(), 'ws-tools-doc-'));
@@ -109,7 +119,7 @@ describe('workspace tools — a branch that cannot be opened', () => {
109
119
  workspaces = new WorkspaceService(
110
120
  workspacesRoot,
111
121
  opts.repoUrl === 'unreachable' ? join(root, 'no-such-repo.git') : upstream,
112
- KB_DIR,
122
+ testKbContext({ kbDirName: KB_DIR }),
113
123
  new NodeFs(),
114
124
  );
115
125
 
@@ -127,22 +137,44 @@ describe('workspace tools — a branch that cannot be opened', () => {
127
137
  const app = express();
128
138
  app.use(express.json());
129
139
  const router = express.Router();
140
+ const registry = new ToolRegistry();
141
+ // The internal discovery endpoint, exactly as `manual.routes` serves it —
142
+ // what a real `CodeModeUtcpClient` reads to learn the tools it can call
143
+ // from inside a chain. Served here so the chain test below drives the SAME
144
+ // routes as every direct call in this file.
145
+ router.get('/agent/internal/utcp', async (_req, res) => {
146
+ res.json(
147
+ new UtcpManualSerializer().validateDict({
148
+ utcp_version: '1.1.0',
149
+ manual_version: '1.0.0',
150
+ tools: await registry.listInternal(),
151
+ }),
152
+ );
153
+ });
130
154
  registerWorkspaceTools(
131
- new ToolRegistry(),
155
+ registry,
132
156
  router,
133
157
  (req: express.Request, _res: express.Response, next: express.NextFunction) => {
134
- req.toolAuth = { source: 'external', userId: 'u', scope: 'read' } as ToolAuth;
158
+ req.toolAuth = {
159
+ // The sweep below asks for `internal` + `write`, which is what reaches
160
+ // the internal-only tools and gets past the write-scope refusal that
161
+ // sits in FRONT of every handler. Everything else in this file stays
162
+ // on the external read surface the bug was reported from.
163
+ source: opts.source ?? 'external',
164
+ userId: 'u',
165
+ scope: opts.scope ?? 'read',
166
+ } as ToolAuth;
135
167
  next();
136
168
  },
137
169
  createToolHandlerFactory(resolve),
138
170
  new SpillStore(spillRoot),
139
171
  new DocExtractService(docCacheDir),
140
172
  allowAll,
141
- KB_DIR,
173
+ testKbContext({ kbDirName: KB_DIR }),
142
174
  {
143
175
  service: {} as never,
144
176
  enabled: false,
145
- kbDirName: KB_DIR,
177
+ kb: testKbContext({ kbDirName: KB_DIR }),
146
178
  recoveryBotEmail: 'recovery-bot@bevel.local',
147
179
  hooks: new WorkflowHooks(),
148
180
  },
@@ -150,21 +182,34 @@ describe('workspace tools — a branch that cannot be opened', () => {
150
182
  {} as never,
151
183
  );
152
184
  app.use('/api', router);
185
+ internalTools = (await registry.listInternal()) as unknown as { name: string; inputs: unknown }[];
153
186
  httpServer = await new Promise<HttpServer>((r) => {
154
187
  const s = app.listen(0, () => r(s));
155
188
  });
156
189
  return `http://127.0.0.1:${(httpServer.address() as { port: number }).port}`;
157
190
  }
158
191
 
159
- const listFiles = async (base: string, branch: string): Promise<{ status: number; body: Record<string, unknown> }> => {
160
- const res = await fetch(`${base}/api/agent/tools/list_files`, {
192
+ /** Call a tool with an arbitrary body — including one that omits `branch`. */
193
+ const callTool = async (
194
+ base: string,
195
+ tool: string,
196
+ body: unknown,
197
+ ): Promise<{ status: number; body: Record<string, unknown> }> => {
198
+ const res = await fetch(`${base}/api/agent/tools/${tool}`, {
161
199
  method: 'POST',
162
200
  headers: { 'content-type': 'application/json', authorization: 'Bearer x' },
163
- body: JSON.stringify({ branch, path: '' }),
201
+ body: JSON.stringify(body),
164
202
  });
165
203
  return { status: res.status, body: (await res.json()) as Record<string, unknown> };
166
204
  };
167
205
 
206
+ const listFiles = async (base: string, branch: string): Promise<{ status: number; body: Record<string, unknown> }> =>
207
+ callTool(base, 'list_files', { branch, path: '' });
208
+
209
+ /** Every entry currently under the workspaces root. */
210
+ const workspaceDirs = async (): Promise<string[]> =>
211
+ (await readdir(join(root, 'workspaces'))).sort();
212
+
168
213
  const deleteOnHost = (branch: string): Promise<void> =>
169
214
  runGit(join(root, 'upstream.git'), ['branch', '-D', branch]);
170
215
 
@@ -181,6 +226,188 @@ describe('workspace tools — a branch that cannot be opened', () => {
181
226
  });
182
227
  });
183
228
 
229
+ /**
230
+ * The reported bug, from the outside: every tool call made without a
231
+ * `branch` answered `Branch "undefined" no longer exists on the remote.` —
232
+ * the missing input was carried all the way down, turned into a workspace
233
+ * directory named `undefined`, and the failed clone of that "branch" was
234
+ * then explained as a branch that had been deleted.
235
+ *
236
+ * The input is refused BY NAME instead, at the boundary, before any of that
237
+ * can happen. `list_files` stands in for every knowledge-base tool here
238
+ * because they share the one choke point (`getFilesystem`) — the refusal is
239
+ * the context resolver's, not this tool's.
240
+ */
241
+ describe('a call that names no branch', () => {
242
+ // Every shape of "the caller sent no branch". The literals are in here
243
+ // because a client that interpolates a variable it never set sends the
244
+ // STRING "undefined" — indistinguishable, in intent, from omitting it, and
245
+ // the one value that must never reach a clone.
246
+ const absent: Array<[label: string, body: Record<string, unknown>]> = [
247
+ ['the field is missing entirely', { path: '' }],
248
+ ['the field is empty', { branch: '', path: '' }],
249
+ ['the field is null', { branch: null, path: '' }],
250
+ ['the field is a number', { branch: 42, path: '' }],
251
+ ['the field is an object', { branch: { name: 'main' }, path: '' }],
252
+ ['the field is an array', { branch: ['main'], path: '' }],
253
+ ['the field is the literal "undefined"', { branch: 'undefined', path: '' }],
254
+ ['the field is the literal "null"', { branch: 'null', path: '' }],
255
+ ];
256
+
257
+ for (const [label, body] of absent) {
258
+ it(`400s branch-required when ${label}`, async () => {
259
+ const base = await start();
260
+
261
+ const res = await callTool(base, 'list_files', body);
262
+
263
+ expect(res.status).toBe(400);
264
+ expect(res.body).toEqual({
265
+ kind: 'branch-required',
266
+ error: '`branch` is required: pass the branch (draft) you are working on.',
267
+ });
268
+ // The refusal is the whole story: nothing was created and nothing was
269
+ // cloned. An empty workspaces root is the strongest form of that
270
+ // claim — there is no directory named for any branch, least of all one
271
+ // named `undefined`.
272
+ expect(await workspaceDirs()).toEqual([]);
273
+ });
274
+ }
275
+
276
+ it('never writes `undefined` or `null` as a branch name into the answer', async () => {
277
+ const base = await start();
278
+
279
+ const res = await callTool(base, 'list_files', { path: '' });
280
+
281
+ // AC3, checked against the whole response rather than one field: the
282
+ // message names the INPUT and what to pass, never a stringified value of
283
+ // what was missing. `Branch "undefined" no longer exists` is exactly the
284
+ // sentence this must never produce again.
285
+ const serialized = JSON.stringify(res.body);
286
+ expect(serialized).not.toContain('undefined');
287
+ expect(serialized).not.toContain('null');
288
+ });
289
+
290
+ /**
291
+ * `call_tool_chain` is the other way every one of these tools gets called,
292
+ * and it is where the bug was reported from just as often. It is not a
293
+ * second implementation to guard: the chain's UTCP http transport POSTs to
294
+ * the SAME `/agent/tools/...` route this file has been calling directly, so
295
+ * the one refusal covers both. This test is what proves that claim rather
296
+ * than assuming it — with a real `CodeModeUtcpClient` reading a real
297
+ * manual and running real JavaScript.
298
+ */
299
+ it('400s branch-required from inside call_tool_chain, and creates no workspace', async () => {
300
+ const base = await start();
301
+ const client = await CodeModeUtcpClient.create(process.cwd(), {
302
+ variables: { bevel_API_URL: base, bevel_CONNECTION_KEY: 'internal-token' },
303
+ } as never);
304
+ await client.registerManual(
305
+ new HttpCallTemplateSerializer().validateDict({
306
+ name: 'bevel',
307
+ call_template_type: 'http',
308
+ http_method: 'GET',
309
+ url: '${API_URL}/api/agent/internal/utcp',
310
+ content_type: 'application/json',
311
+ headers: { Authorization: 'Bearer ${CONNECTION_KEY}' },
312
+ }),
313
+ );
314
+
315
+ // The exact call from the specification: a chain that names the path and
316
+ // forgets the branch. The tool THROWS inside the chain, so the failure is
317
+ // caught and its message returned — the runtime's own contract for
318
+ // surfacing a tool error to the model.
319
+ const { result } = await client.callToolChain(
320
+ `try { return { ok: bevel.list_files({ body: { path: 'knowledge-base' } }) }; }
321
+ catch (err) { return { failed: err.message }; }`,
322
+ 30_000,
323
+ );
324
+
325
+ // The tool did not run.
326
+ expect(result.ok).toBeUndefined();
327
+ // The message the chain hands the model carries the whole refusal: the
328
+ // status, the sentence, and the `kind` the direct caller switches on.
329
+ // (The status and payload are IN the message rather than on the thrown
330
+ // object — the sandboxed error exposes no own properties — which is why
331
+ // this asserts on the text the model actually reads.)
332
+ expect(result.failed).toContain('HTTP 400');
333
+ expect(result.failed).toContain('`branch` is required: pass the branch (draft) you are working on.');
334
+ expect(result.failed).toContain('"kind":"branch-required"');
335
+ // Not the sentence the bug produced — and no invented branch name in it.
336
+ expect(result.failed).not.toContain('no longer exists');
337
+ expect(result.failed).not.toContain('undefined');
338
+ // And the chain path refuses just as early: nothing was cloned.
339
+ expect(await workspaceDirs()).toEqual([]);
340
+ });
341
+
342
+ /**
343
+ * AC1 says "any knowledge-base tool", so this asserts it of EVERY tool the
344
+ * module mounts rather than of the one this file otherwise drives. The list
345
+ * comes from the registry, so a tool added later is swept in automatically
346
+ * and cannot quietly reintroduce the bug on its own route. The guard runs
347
+ * ahead of every other check, which is what lets one empty body stand in
348
+ * for a valid call to each of them.
349
+ */
350
+ it('400s branch-required on every mounted tool that declares `branch`', async () => {
351
+ const base = await start({ source: 'internal', scope: 'write' });
352
+ const declaresBranch = internalTools
353
+ .filter((t) => {
354
+ const body = (t.inputs as { properties?: { body?: { required?: string[] } } }).properties?.body;
355
+ return (body?.required ?? []).includes('branch');
356
+ })
357
+ .map((t) => t.name);
358
+
359
+ // The whole branch-taking surface, not a sample of it.
360
+ expect(declaresBranch.length).toBeGreaterThan(10);
361
+
362
+ for (const tool of declaresBranch) {
363
+ const res = await callTool(base, tool, {});
364
+ expect(res.status, `${tool} must 400 on a branch-less call`).toBe(400);
365
+ expect(res.body.kind, `${tool} must answer kind branch-required`).toBe('branch-required');
366
+ // No tool's refusal may name the value it did not get.
367
+ expect(JSON.stringify(res.body), `${tool} must not echo an absent value`).not.toContain('undefined');
368
+ }
369
+ expect(await workspaceDirs()).toEqual([]);
370
+ });
371
+
372
+ it('still serves the same tool once a branch is named', async () => {
373
+ const base = await start();
374
+ // The guard refuses an absent input, not the tool: the same call with a
375
+ // real branch works, so the refusal cannot be a tool that simply broke.
376
+ expect((await callTool(base, 'list_files', { path: '' })).status).toBe(400);
377
+
378
+ const { status, body } = await listFiles(base, 'alice/draft');
379
+
380
+ expect(status).toBe(200);
381
+ expect((body.entries as { name: string }[]).map((e) => e.name)).toContain(KB_DIR);
382
+ });
383
+ });
384
+
385
+ /**
386
+ * The second half of the bug: a bootstrap that failed to clone used to leave
387
+ * a directory behind, and a directory named after a branch is how the
388
+ * platform remembers having known one. The first attempt's leftovers turned
389
+ * the second attempt's honest "no such branch" into "it was deleted".
390
+ */
391
+ it('answers 404 again on a second attempt at a name that never existed', async () => {
392
+ const base = await start();
393
+
394
+ const first = await listFiles(base, 'nobody/never-made-this');
395
+ expect(first.status).toBe(404);
396
+ // Nothing survived the failed clone — not the repo directory, not the
397
+ // workspace shell around it. This is what keeps the next attempt honest.
398
+ expect(await workspaceDirs()).toEqual([]);
399
+
400
+ const second = await listFiles(base, 'nobody/never-made-this');
401
+
402
+ expect(second.status).toBe(404);
403
+ expect(second.body).toEqual({
404
+ kind: 'branch-not-found',
405
+ branch: 'nobody/never-made-this',
406
+ error: 'There is no branch named nobody/never-made-this.',
407
+ });
408
+ expect(await workspaceDirs()).toEqual([]);
409
+ });
410
+
184
411
  it('410s a branch a listing showed us and origin no longer has', async () => {
185
412
  const base = await start();
186
413
  workspaces!.noteBranchesListed(['target-company-state', 'alice/draft']);
@@ -7,6 +7,7 @@ import { promisify } from 'node:util';
7
7
  import AdmZip from 'adm-zip';
8
8
  import express from 'express';
9
9
  import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
10
+ import { testKbContext } from '../../../__tests__/kb-context.js';
10
11
  import { LocalFilesystem } from '@mastra/core/workspace';
11
12
  import { ToolRegistry } from '../../tool-registry/tool-registry.js';
12
13
  import { createToolHandlerFactory } from '../../tool-helpers/tool-handler.js';
@@ -218,10 +219,10 @@ async function start(
218
219
  const app = express();
219
220
  app.use(express.json());
220
221
  const router = express.Router();
221
- registerWorkspaceTools(registry, router, fakeAuth, toolHandler, new SpillStore(join(tmpdir(), 'bevel-test-spills')), new DocExtractService(docCacheDir), access, KB_DIR, {
222
+ registerWorkspaceTools(registry, router, fakeAuth, toolHandler, new SpillStore(join(tmpdir(), 'bevel-test-spills')), new DocExtractService(docCacheDir), access, testKbContext({ kbDirName: KB_DIR }), {
222
223
  service: {} as never,
223
224
  enabled: false, // these tests predate and don't exercise the ontology boundary
224
- kbDirName: KB_DIR,
225
+ kb: testKbContext({ kbDirName: KB_DIR }),
225
226
  recoveryBotEmail: 'recovery-bot@bevel.local',
226
227
  hooks: new WorkflowHooks(),
227
228
  }, writePolicy, {} as never /* sessionSink — start_session not exercised here */);
@@ -232,9 +233,24 @@ async function start(
232
233
  return `http://127.0.0.1:${(httpServer.address() as { port: number }).port}`;
233
234
  }
234
235
 
235
- const post = (url: string, body: unknown = {}) =>
236
+ /** POST a body EXACTLY as given — for the tests about a malformed call. */
237
+ const postRaw = (url: string, body: unknown = {}) =>
236
238
  fetch(url, { method: 'POST', headers: { 'content-type': 'application/json', authorization: 'Bearer x' }, body: JSON.stringify(body) });
237
239
 
240
+ /**
241
+ * POST a well-formed call. Every KB tool requires `branch` — a call that names
242
+ * none is refused at the mount with 400 `branch-required` — so this names one
243
+ * unless the test already did. A test ABOUT the missing input uses `postRaw`,
244
+ * so the thing under test is never papered over by the helper.
245
+ */
246
+ const post = (url: string, body: unknown = {}) =>
247
+ postRaw(
248
+ url,
249
+ body !== null && typeof body === 'object' && !Array.isArray(body) && !('branch' in body)
250
+ ? { branch: 'main', ...body }
251
+ : body,
252
+ );
253
+
238
254
  beforeEach(() => {
239
255
  /* fresh per test via start() */
240
256
  });
@@ -455,7 +471,8 @@ describe('workspace file primitives', () => {
455
471
  // named "undefined" — it fails closed with a clear 4xx naming the missing
456
472
  // branch context, BEFORE any workspace resolve.
457
473
  expect(focusedBranch).toBeUndefined();
458
- const res = await post(`${base}/api/agent/tools/execute_command`, { command: 'echo should-not-run' });
474
+ // `postRaw`: the absent field IS the test here, so the body goes as written.
475
+ const res = await postRaw(`${base}/api/agent/tools/execute_command`, { command: 'echo should-not-run' });
459
476
  expect(res.status).toBe(400);
460
477
  expect((await res.json()).error).toMatch(/branch/i);
461
478
  // The guard runs before `getOrCreateForBranch`, so no workspace (least of all
@@ -470,7 +487,7 @@ describe('workspace file primitives', () => {
470
487
  // against that branch's workspace and returns output end to end (AC2) —
471
488
  // rather than failing closed the way a context-less external call does.
472
489
  focusedBranch = 'main';
473
- const res = (await (await post(`${base}/api/agent/tools/execute_command`, { command: 'echo hello-exec' })).json()) as { stdout: string; exitCode: number };
490
+ const res = (await (await postRaw(`${base}/api/agent/tools/execute_command`, { command: 'echo hello-exec' })).json()) as { stdout: string; exitCode: number };
474
491
  expect(res.exitCode).toBe(0);
475
492
  expect(res.stdout).toContain('hello-exec');
476
493
  // Resolved against the focused branch — never an "undefined" workspace.
@@ -554,6 +571,20 @@ describe('workspace file primitives', () => {
554
571
  expect(workspacePathCalls).toEqual([]);
555
572
  });
556
573
 
574
+ it('answers a branch-less call with the same kind every other KB tool uses', async () => {
575
+ const base = await start();
576
+ // The MESSAGE here is this tool's own — only `execute_command` has a
577
+ // focused-branch fallback to explain. The DISCRIMINATOR is shared, so a
578
+ // client switches on one kind across the whole surface instead of matching
579
+ // prose per tool.
580
+ for (const body of [{ command: 'x' }, { branch: '', command: 'x' }, { branch: 'undefined', command: 'x' }]) {
581
+ const res = await postRaw(`${base}/api/agent/tools/execute_command`, body);
582
+ expect(res.status).toBe(400);
583
+ expect((await res.json()).kind).toBe('branch-required');
584
+ }
585
+ expect(workspacePathCalls).toEqual([]);
586
+ });
587
+
557
588
  it('execute_command validates the branch BEFORE the write-policy gate', async () => {
558
589
  const base = await start();
559
590
  // A routine-restricted session is refused by `assertUnrestricted` with 403.
@@ -1831,8 +1862,8 @@ describe('start_session', () => {
1831
1862
  const router = express.Router();
1832
1863
  registerWorkspaceTools(
1833
1864
  registry, router, auth, toolHandler,
1834
- new SpillStore(join(tmpdir(), 'bevel-test-spills')), new DocExtractService(join(tmpdir(), 'bevel-test-doc-extract')), allowAll, KB_DIR,
1835
- { service: {} as never, enabled: false, kbDirName: KB_DIR, recoveryBotEmail: 'recovery-bot@bevel.local', hooks: new WorkflowHooks() },
1865
+ new SpillStore(join(tmpdir(), 'bevel-test-spills')), new DocExtractService(join(tmpdir(), 'bevel-test-doc-extract')), allowAll, testKbContext({ kbDirName: KB_DIR }),
1866
+ { service: {} as never, enabled: false, kb: testKbContext({ kbDirName: KB_DIR }), recoveryBotEmail: 'recovery-bot@bevel.local', hooks: new WorkflowHooks() },
1836
1867
  new RoutineWritePolicyService(),
1837
1868
  sink ?? fakeSessionSink,
1838
1869
  );
@@ -1956,8 +1987,8 @@ describe('start_session', () => {
1956
1987
  const noopAuth: express.RequestHandler = (_req, _res, next) => next();
1957
1988
  registerWorkspaceTools(
1958
1989
  registry, router, noopAuth, (() => () => {}) as never,
1959
- new SpillStore(join(tmpdir(), 'bevel-test-spills')), new DocExtractService(join(tmpdir(), 'bevel-test-doc-extract')), allowAll, KB_DIR,
1960
- { service: {} as never, enabled: false, kbDirName: KB_DIR, recoveryBotEmail: 'recovery-bot@bevel.local', hooks: new WorkflowHooks() },
1990
+ new SpillStore(join(tmpdir(), 'bevel-test-spills')), new DocExtractService(join(tmpdir(), 'bevel-test-doc-extract')), allowAll, testKbContext({ kbDirName: KB_DIR }),
1991
+ { service: {} as never, enabled: false, kb: testKbContext({ kbDirName: KB_DIR }), recoveryBotEmail: 'recovery-bot@bevel.local', hooks: new WorkflowHooks() },
1961
1992
  new RoutineWritePolicyService(),
1962
1993
  {} as never,
1963
1994
  );
@@ -1998,8 +2029,8 @@ describe('branch is a required parameter in the tool contract', () => {
1998
2029
  new SpillStore(join(tmpdir(), 'bevel-test-spills')),
1999
2030
  new DocExtractService(join(tmpdir(), 'bevel-test-doc-extract')),
2000
2031
  allowAll,
2001
- KB_DIR,
2002
- { service: {} as never, enabled: false, kbDirName: KB_DIR, recoveryBotEmail: 'recovery-bot@bevel.local', hooks: new WorkflowHooks() },
2032
+ testKbContext({ kbDirName: KB_DIR }),
2033
+ { service: {} as never, enabled: false, kb: testKbContext({ kbDirName: KB_DIR }), recoveryBotEmail: 'recovery-bot@bevel.local', hooks: new WorkflowHooks() },
2003
2034
  new RoutineWritePolicyService(),
2004
2035
  {} as never,
2005
2036
  );
@@ -2265,6 +2296,8 @@ describe('the tools place an unprefixed path inside the repository', () => {
2265
2296
  describe('folders never vanish', () => {
2266
2297
  const KB = (p: string) => `${KB_DIR}/${p}`;
2267
2298
  const tool = async (base: string, name: string, body: Record<string, unknown>) => {
2299
+ // `post` names the branch every KB tool requires; these tests are about
2300
+ // folders, not about the branch input.
2268
2301
  const res = await post(`${base}/api/agent/tools/${name}`, body);
2269
2302
  return { status: res.status, body: (await res.json()) as Record<string, unknown> };
2270
2303
  };
@@ -1,4 +1,5 @@
1
1
  import { describe, it, expect, vi } from 'vitest';
2
+ import { testKbContext } from '../../../__tests__/kb-context.js';
2
3
  import { writeDenial } from '../write-denial.js';
3
4
  import { AccessDeniedError } from '../../access-model/access-errors.js';
4
5
  import type { ChangeReadVerdict, IChangeReadGate } from '../../access-model/change-gate.js';
@@ -34,7 +35,7 @@ describe('writeDenial asks the read gate about the refused path as the refuser s
34
35
  eligibleUsers: [],
35
36
  targetKind: 'dir',
36
37
  });
37
- const out = await writeDenial(err, INPUT, noAccess, KB, gate);
38
+ const out = await writeDenial(err, INPUT, noAccess, testKbContext({ kbDirName: KB }), gate);
38
39
  expect(judge).toHaveBeenCalledWith(
39
40
  'target-company-state',
40
41
  'alice@example.com',
@@ -48,7 +49,7 @@ describe('writeDenial asks the read gate about the refused path as the refuser s
48
49
  it('a refusal that says nothing about its kind is judged as a file', async () => {
49
50
  const { gate, judge } = gateThat({ allowed: false, unreadable: 'KnowledgeBase' });
50
51
  const err = new AccessDeniedError({ path: `${KB}/KnowledgeBase/loose.md`, eligibleRoles: [], eligibleUsers: [] });
51
- const out = await writeDenial(err, INPUT, noAccess, KB, gate);
52
+ const out = await writeDenial(err, INPUT, noAccess, testKbContext({ kbDirName: KB }), gate);
52
53
  expect(judge).toHaveBeenCalledWith(expect.any(String), 'alice@example.com', `${KB}/KnowledgeBase/loose.md`, 'file');
53
54
  expect(out.details).toMatchObject({
54
55
  kind: 'write-denied',
@@ -60,7 +61,7 @@ describe('writeDenial asks the read gate about the refused path as the refuser s
60
61
  it('without a gate the read verdict alone decides, as before', async () => {
61
62
  const accessControl = { canRead: vi.fn(async () => true) } as unknown as IAccessControl;
62
63
  const err = new AccessDeniedError({ path: `${KB}/KnowledgeBase/Sales/deal.md`, eligibleRoles: [], eligibleUsers: [] });
63
- const out = await writeDenial(err, INPUT, accessControl, KB);
64
+ const out = await writeDenial(err, INPUT, accessControl, testKbContext({ kbDirName: KB }));
64
65
  expect(accessControl.canRead).toHaveBeenCalledWith('target-company-state', 'alice@example.com', 'KnowledgeBase/Sales/deal.md');
65
66
  expect(out.details).toMatchObject({ kind: 'write-denied', canPropose: true });
66
67
  });
@@ -68,7 +69,7 @@ describe('writeDenial asks the read gate about the refused path as the refuser s
68
69
  it('a gate that cannot answer refuses to offer the route', async () => {
69
70
  const gate: IChangeReadGate = { judge: vi.fn(async () => { throw new Error('git down'); }), assertMayChange: vi.fn() };
70
71
  const err = new AccessDeniedError({ path: `${KB}/KnowledgeBase/Sales/deal.md`, eligibleRoles: [], eligibleUsers: [] });
71
- const out = await writeDenial(err, INPUT, noAccess, KB, gate);
72
+ const out = await writeDenial(err, INPUT, noAccess, testKbContext({ kbDirName: KB }), gate);
72
73
  expect(out.details).toMatchObject({ canPropose: false });
73
74
  expect(out.details?.cannotProposeReason).toContain('could not be determined');
74
75
  });