@bevel-software/platform-core-backend 0.20.0 → 0.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (576) hide show
  1. package/dist/core/catalog-cache-invalidation.d.ts +7 -2
  2. package/dist/core/catalog-cache-invalidation.d.ts.map +1 -1
  3. package/dist/core/catalog-cache-invalidation.js +8 -9
  4. package/dist/core/catalog-cache-invalidation.js.map +1 -1
  5. package/dist/core/core-ports.d.ts +19 -0
  6. package/dist/core/core-ports.d.ts.map +1 -1
  7. package/dist/core/core-ports.js.map +1 -1
  8. package/dist/core/create-core-server.d.ts +2 -0
  9. package/dist/core/create-core-server.d.ts.map +1 -1
  10. package/dist/core/create-core-server.js +23 -105
  11. package/dist/core/create-core-server.js.map +1 -1
  12. package/dist/core/create-core-services.d.ts +30 -5
  13. package/dist/core/create-core-services.d.ts.map +1 -1
  14. package/dist/core/create-core-services.js +136 -81
  15. package/dist/core/create-core-services.js.map +1 -1
  16. package/dist/core/lifecycle.d.ts +74 -28
  17. package/dist/core/lifecycle.d.ts.map +1 -1
  18. package/dist/core/lifecycle.js +157 -20
  19. package/dist/core/lifecycle.js.map +1 -1
  20. package/dist/core/public-config.d.ts +5 -1
  21. package/dist/core/public-config.d.ts.map +1 -1
  22. package/dist/core/public-config.js +7 -5
  23. package/dist/core/public-config.js.map +1 -1
  24. package/dist/core-config.d.ts +95 -1
  25. package/dist/core-config.d.ts.map +1 -1
  26. package/dist/core-config.js +24 -8
  27. package/dist/core-config.js.map +1 -1
  28. package/dist/index.d.ts +5 -3
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +6 -3
  31. package/dist/index.js.map +1 -1
  32. package/dist/modules/access/access-control.service.d.ts +18 -1
  33. package/dist/modules/access/access-control.service.d.ts.map +1 -1
  34. package/dist/modules/access/access-control.service.js +19 -8
  35. package/dist/modules/access/access-control.service.js.map +1 -1
  36. package/dist/modules/access/access.routes.d.ts +2 -1
  37. package/dist/modules/access/access.routes.d.ts.map +1 -1
  38. package/dist/modules/access/access.routes.js +10 -10
  39. package/dist/modules/access/access.routes.js.map +1 -1
  40. package/dist/modules/access/change-read-gate.d.ts +6 -3
  41. package/dist/modules/access/change-read-gate.d.ts.map +1 -1
  42. package/dist/modules/access/change-read-gate.js +9 -6
  43. package/dist/modules/access/change-read-gate.js.map +1 -1
  44. package/dist/modules/access/creator-access.d.ts +4 -2
  45. package/dist/modules/access/creator-access.d.ts.map +1 -1
  46. package/dist/modules/access/creator-access.js +7 -4
  47. package/dist/modules/access/creator-access.js.map +1 -1
  48. package/dist/modules/agent-instructions/read-preamble.d.ts +2 -1
  49. package/dist/modules/agent-instructions/read-preamble.d.ts.map +1 -1
  50. package/dist/modules/agent-instructions/read-preamble.js +6 -9
  51. package/dist/modules/agent-instructions/read-preamble.js.map +1 -1
  52. package/dist/modules/auth/account-admission.d.ts +40 -0
  53. package/dist/modules/auth/account-admission.d.ts.map +1 -0
  54. package/dist/modules/auth/account-admission.js +17 -0
  55. package/dist/modules/auth/account-admission.js.map +1 -0
  56. package/dist/modules/auth/account.routes.d.ts.map +1 -1
  57. package/dist/modules/auth/account.routes.js +4 -1
  58. package/dist/modules/auth/account.routes.js.map +1 -1
  59. package/dist/modules/auth/auth.service.d.ts +19 -1
  60. package/dist/modules/auth/auth.service.d.ts.map +1 -1
  61. package/dist/modules/auth/auth.service.js +33 -1
  62. package/dist/modules/auth/auth.service.js.map +1 -1
  63. package/dist/modules/auth/oidc-auth-provider.d.ts.map +1 -1
  64. package/dist/modules/auth/oidc-auth-provider.js +9 -0
  65. package/dist/modules/auth/oidc-auth-provider.js.map +1 -1
  66. package/dist/modules/connection-probe/connection-probe.service.d.ts +13 -1
  67. package/dist/modules/connection-probe/connection-probe.service.d.ts.map +1 -1
  68. package/dist/modules/connection-probe/connection-probe.service.js +10 -2
  69. package/dist/modules/connection-probe/connection-probe.service.js.map +1 -1
  70. package/dist/modules/database/advisory-lock.d.ts +17 -0
  71. package/dist/modules/database/advisory-lock.d.ts.map +1 -1
  72. package/dist/modules/database/advisory-lock.js +24 -3
  73. package/dist/modules/database/advisory-lock.js.map +1 -1
  74. package/dist/modules/database/connection.d.ts +67 -2
  75. package/dist/modules/database/connection.d.ts.map +1 -1
  76. package/dist/modules/database/connection.js +118 -12
  77. package/dist/modules/database/connection.js.map +1 -1
  78. package/dist/modules/database/migrate.d.ts +1 -1
  79. package/dist/modules/database/migrate.d.ts.map +1 -1
  80. package/dist/modules/database/migrate.js +27 -3
  81. package/dist/modules/database/migrate.js.map +1 -1
  82. package/dist/modules/kb-fs/branch-name.d.ts +0 -1
  83. package/dist/modules/kb-fs/branch-name.d.ts.map +1 -1
  84. package/dist/modules/kb-fs/branch-name.js +3 -3
  85. package/dist/modules/kb-fs/branch-name.js.map +1 -1
  86. package/dist/modules/kb-fs/clone-config.d.ts +9 -8
  87. package/dist/modules/kb-fs/clone-config.d.ts.map +1 -1
  88. package/dist/modules/kb-fs/clone-config.js +14 -12
  89. package/dist/modules/kb-fs/clone-config.js.map +1 -1
  90. package/dist/modules/mcp/mcp.service.d.ts +7 -0
  91. package/dist/modules/mcp/mcp.service.d.ts.map +1 -1
  92. package/dist/modules/mcp/mcp.service.js +4 -4
  93. package/dist/modules/mcp/mcp.service.js.map +1 -1
  94. package/dist/modules/plugins/compile/marketplace-compiler.service.d.ts +4 -4
  95. package/dist/modules/plugins/compile/marketplace-compiler.service.d.ts.map +1 -1
  96. package/dist/modules/plugins/compile/marketplace-compiler.service.js +7 -10
  97. package/dist/modules/plugins/compile/marketplace-compiler.service.js.map +1 -1
  98. package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.d.ts +4 -1
  99. package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.d.ts.map +1 -1
  100. package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.js +5 -3
  101. package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.js.map +1 -1
  102. package/dist/modules/plugins/discovery/kb-plugin-source.d.ts +6 -1
  103. package/dist/modules/plugins/discovery/kb-plugin-source.d.ts.map +1 -1
  104. package/dist/modules/plugins/discovery/kb-plugin-source.js +14 -9
  105. package/dist/modules/plugins/discovery/kb-plugin-source.js.map +1 -1
  106. package/dist/modules/plugins/discovery/native.source.d.ts +4 -1
  107. package/dist/modules/plugins/discovery/native.source.d.ts.map +1 -1
  108. package/dist/modules/plugins/discovery/native.source.js +4 -2
  109. package/dist/modules/plugins/discovery/native.source.js.map +1 -1
  110. package/dist/modules/plugins/index.d.ts +1 -1
  111. package/dist/modules/plugins/index.d.ts.map +1 -1
  112. package/dist/modules/plugins/index.js +1 -1
  113. package/dist/modules/plugins/index.js.map +1 -1
  114. package/dist/modules/plugins/join-request-jobs.service.d.ts +3 -1
  115. package/dist/modules/plugins/join-request-jobs.service.d.ts.map +1 -1
  116. package/dist/modules/plugins/join-request-jobs.service.js +6 -6
  117. package/dist/modules/plugins/join-request-jobs.service.js.map +1 -1
  118. package/dist/modules/plugins/join-requests.service.d.ts +3 -1
  119. package/dist/modules/plugins/join-requests.service.d.ts.map +1 -1
  120. package/dist/modules/plugins/join-requests.service.js +9 -8
  121. package/dist/modules/plugins/join-requests.service.js.map +1 -1
  122. package/dist/modules/plugins/plugin-links.d.ts +65 -10
  123. package/dist/modules/plugins/plugin-links.d.ts.map +1 -1
  124. package/dist/modules/plugins/plugin-links.js +136 -31
  125. package/dist/modules/plugins/plugin-links.js.map +1 -1
  126. package/dist/modules/plugins/plugin-links.service.d.ts +107 -5
  127. package/dist/modules/plugins/plugin-links.service.d.ts.map +1 -1
  128. package/dist/modules/plugins/plugin-links.service.js +151 -21
  129. package/dist/modules/plugins/plugin-links.service.js.map +1 -1
  130. package/dist/modules/plugins/plugin-provision.service.d.ts +10 -3
  131. package/dist/modules/plugins/plugin-provision.service.d.ts.map +1 -1
  132. package/dist/modules/plugins/plugin-provision.service.js +33 -26
  133. package/dist/modules/plugins/plugin-provision.service.js.map +1 -1
  134. package/dist/modules/plugins/plugin-rename.service.d.ts +4 -2
  135. package/dist/modules/plugins/plugin-rename.service.d.ts.map +1 -1
  136. package/dist/modules/plugins/plugin-rename.service.js +10 -12
  137. package/dist/modules/plugins/plugin-rename.service.js.map +1 -1
  138. package/dist/modules/plugins/plugins.routes.d.ts +3 -0
  139. package/dist/modules/plugins/plugins.routes.d.ts.map +1 -1
  140. package/dist/modules/plugins/plugins.routes.js +45 -15
  141. package/dist/modules/plugins/plugins.routes.js.map +1 -1
  142. package/dist/modules/plugins/plugins.service.d.ts +4 -4
  143. package/dist/modules/plugins/plugins.service.d.ts.map +1 -1
  144. package/dist/modules/plugins/plugins.service.js +7 -10
  145. package/dist/modules/plugins/plugins.service.js.map +1 -1
  146. package/dist/modules/plugins/teams.routes.d.ts +4 -1
  147. package/dist/modules/plugins/teams.routes.d.ts.map +1 -1
  148. package/dist/modules/plugins/teams.routes.js +11 -9
  149. package/dist/modules/plugins/teams.routes.js.map +1 -1
  150. package/dist/modules/secrets-vault/index.d.ts +1 -1
  151. package/dist/modules/secrets-vault/index.d.ts.map +1 -1
  152. package/dist/modules/secrets-vault/index.js +1 -1
  153. package/dist/modules/secrets-vault/index.js.map +1 -1
  154. package/dist/modules/secrets-vault/secrets-variable-loader.d.ts +29 -11
  155. package/dist/modules/secrets-vault/secrets-variable-loader.d.ts.map +1 -1
  156. package/dist/modules/secrets-vault/secrets-variable-loader.js +46 -21
  157. package/dist/modules/secrets-vault/secrets-variable-loader.js.map +1 -1
  158. package/dist/modules/secrets-vault/secrets-vault.routes.d.ts +3 -0
  159. package/dist/modules/secrets-vault/secrets-vault.routes.d.ts.map +1 -1
  160. package/dist/modules/secrets-vault/secrets-vault.routes.js +4 -6
  161. package/dist/modules/secrets-vault/secrets-vault.routes.js.map +1 -1
  162. package/dist/modules/settings/deployment-settings.service.d.ts +12 -8
  163. package/dist/modules/settings/deployment-settings.service.d.ts.map +1 -1
  164. package/dist/modules/settings/deployment-settings.service.js +20 -22
  165. package/dist/modules/settings/deployment-settings.service.js.map +1 -1
  166. package/dist/modules/settings/setup.routes.d.ts +9 -2
  167. package/dist/modules/settings/setup.routes.d.ts.map +1 -1
  168. package/dist/modules/settings/setup.routes.js +20 -14
  169. package/dist/modules/settings/setup.routes.js.map +1 -1
  170. package/dist/modules/skills/allowed-tools-check.d.ts +4 -3
  171. package/dist/modules/skills/allowed-tools-check.d.ts.map +1 -1
  172. package/dist/modules/skills/allowed-tools-check.js +8 -8
  173. package/dist/modules/skills/allowed-tools-check.js.map +1 -1
  174. package/dist/modules/skills/pending-skills.service.d.ts +3 -1
  175. package/dist/modules/skills/pending-skills.service.d.ts.map +1 -1
  176. package/dist/modules/skills/pending-skills.service.js +9 -6
  177. package/dist/modules/skills/pending-skills.service.js.map +1 -1
  178. package/dist/modules/skills/skill-access-requests.routes.d.ts +2 -1
  179. package/dist/modules/skills/skill-access-requests.routes.d.ts.map +1 -1
  180. package/dist/modules/skills/skill-access-requests.routes.js +6 -6
  181. package/dist/modules/skills/skill-access-requests.routes.js.map +1 -1
  182. package/dist/modules/skills/skills.routes.d.ts +4 -1
  183. package/dist/modules/skills/skills.routes.d.ts.map +1 -1
  184. package/dist/modules/skills/skills.routes.js +4 -4
  185. package/dist/modules/skills/skills.routes.js.map +1 -1
  186. package/dist/modules/skills/skills.service.d.ts +4 -2
  187. package/dist/modules/skills/skills.service.d.ts.map +1 -1
  188. package/dist/modules/skills/skills.service.js +13 -11
  189. package/dist/modules/skills/skills.service.js.map +1 -1
  190. package/dist/modules/tool-manuals/mcp-json-discovery.d.ts +2 -1
  191. package/dist/modules/tool-manuals/mcp-json-discovery.d.ts.map +1 -1
  192. package/dist/modules/tool-manuals/mcp-json-discovery.js +6 -5
  193. package/dist/modules/tool-manuals/mcp-json-discovery.js.map +1 -1
  194. package/dist/modules/tool-manuals/mcp-server-edit.service.d.ts +4 -2
  195. package/dist/modules/tool-manuals/mcp-server-edit.service.d.ts.map +1 -1
  196. package/dist/modules/tool-manuals/mcp-server-edit.service.js +12 -10
  197. package/dist/modules/tool-manuals/mcp-server-edit.service.js.map +1 -1
  198. package/dist/modules/tool-manuals/pending-tools.service.d.ts +3 -1
  199. package/dist/modules/tool-manuals/pending-tools.service.d.ts.map +1 -1
  200. package/dist/modules/tool-manuals/pending-tools.service.js +19 -16
  201. package/dist/modules/tool-manuals/pending-tools.service.js.map +1 -1
  202. package/dist/modules/tool-manuals/tool-delete.service.d.ts +4 -2
  203. package/dist/modules/tool-manuals/tool-delete.service.d.ts.map +1 -1
  204. package/dist/modules/tool-manuals/tool-delete.service.js +14 -12
  205. package/dist/modules/tool-manuals/tool-delete.service.js.map +1 -1
  206. package/dist/modules/tool-manuals/tool-manuals.routes.d.ts +3 -1
  207. package/dist/modules/tool-manuals/tool-manuals.routes.d.ts.map +1 -1
  208. package/dist/modules/tool-manuals/tool-manuals.routes.js +7 -7
  209. package/dist/modules/tool-manuals/tool-manuals.routes.js.map +1 -1
  210. package/dist/modules/tool-manuals/tool-manuals.service.d.ts +4 -2
  211. package/dist/modules/tool-manuals/tool-manuals.service.d.ts.map +1 -1
  212. package/dist/modules/tool-manuals/tool-manuals.service.js +15 -12
  213. package/dist/modules/tool-manuals/tool-manuals.service.js.map +1 -1
  214. package/dist/modules/tool-manuals/tool-manuals.tools.d.ts +3 -0
  215. package/dist/modules/tool-manuals/tool-manuals.tools.d.ts.map +1 -1
  216. package/dist/modules/tool-manuals/tool-manuals.tools.js +4 -6
  217. package/dist/modules/tool-manuals/tool-manuals.tools.js.map +1 -1
  218. package/dist/modules/workflow/agent-tools/workflow.tools.d.ts +3 -2
  219. package/dist/modules/workflow/agent-tools/workflow.tools.d.ts.map +1 -1
  220. package/dist/modules/workflow/agent-tools/workflow.tools.js +9 -9
  221. package/dist/modules/workflow/agent-tools/workflow.tools.js.map +1 -1
  222. package/dist/modules/workflow/git/git.service.d.ts +11 -5
  223. package/dist/modules/workflow/git/git.service.d.ts.map +1 -1
  224. package/dist/modules/workflow/git/git.service.js +23 -14
  225. package/dist/modules/workflow/git/git.service.js.map +1 -1
  226. package/dist/modules/workflow/git/node-git-runner.d.ts +26 -2
  227. package/dist/modules/workflow/git/node-git-runner.d.ts.map +1 -1
  228. package/dist/modules/workflow/git/node-git-runner.js +35 -5
  229. package/dist/modules/workflow/git/node-git-runner.js.map +1 -1
  230. package/dist/modules/workflow/review-workflow/review-workflow.service.d.ts.map +1 -1
  231. package/dist/modules/workflow/review-workflow/review-workflow.service.js +9 -4
  232. package/dist/modules/workflow/review-workflow/review-workflow.service.js.map +1 -1
  233. package/dist/modules/workflow/session-ontology.service.d.ts +6 -1
  234. package/dist/modules/workflow/session-ontology.service.d.ts.map +1 -1
  235. package/dist/modules/workflow/session-ontology.service.js +6 -2
  236. package/dist/modules/workflow/session-ontology.service.js.map +1 -1
  237. package/dist/modules/workflow/workflow.service.d.ts +8 -3
  238. package/dist/modules/workflow/workflow.service.d.ts.map +1 -1
  239. package/dist/modules/workflow/workflow.service.js +33 -23
  240. package/dist/modules/workflow/workflow.service.js.map +1 -1
  241. package/dist/modules/workspace/session-ontology.gate.d.ts +3 -1
  242. package/dist/modules/workspace/session-ontology.gate.d.ts.map +1 -1
  243. package/dist/modules/workspace/session-ontology.gate.js +3 -3
  244. package/dist/modules/workspace/session-ontology.gate.js.map +1 -1
  245. package/dist/modules/workspace/startup/kb-git.d.ts +4 -3
  246. package/dist/modules/workspace/startup/kb-git.d.ts.map +1 -1
  247. package/dist/modules/workspace/startup/kb-git.js +15 -13
  248. package/dist/modules/workspace/startup/kb-git.js.map +1 -1
  249. package/dist/modules/workspace/startup/kb-startup-runner.d.ts +5 -8
  250. package/dist/modules/workspace/startup/kb-startup-runner.d.ts.map +1 -1
  251. package/dist/modules/workspace/startup/kb-startup-runner.js +35 -38
  252. package/dist/modules/workspace/startup/kb-startup-runner.js.map +1 -1
  253. package/dist/modules/workspace/startup/steps/groups-to-plugins.step.d.ts +7 -1
  254. package/dist/modules/workspace/startup/steps/groups-to-plugins.step.d.ts.map +1 -1
  255. package/dist/modules/workspace/startup/steps/groups-to-plugins.step.js +23 -16
  256. package/dist/modules/workspace/startup/steps/groups-to-plugins.step.js.map +1 -1
  257. package/dist/modules/workspace/startup/steps/personal-spaces.step.d.ts +7 -1
  258. package/dist/modules/workspace/startup/steps/personal-spaces.step.d.ts.map +1 -1
  259. package/dist/modules/workspace/startup/steps/personal-spaces.step.js +12 -5
  260. package/dist/modules/workspace/startup/steps/personal-spaces.step.js.map +1 -1
  261. package/dist/modules/workspace/startup/steps/plugin-display-names.step.d.ts +7 -1
  262. package/dist/modules/workspace/startup/steps/plugin-display-names.step.d.ts.map +1 -1
  263. package/dist/modules/workspace/startup/steps/plugin-display-names.step.js +12 -5
  264. package/dist/modules/workspace/startup/steps/plugin-display-names.step.js.map +1 -1
  265. package/dist/modules/workspace/startup/steps/plugin-manifests.step.d.ts +7 -1
  266. package/dist/modules/workspace/startup/steps/plugin-manifests.step.d.ts.map +1 -1
  267. package/dist/modules/workspace/startup/steps/plugin-manifests.step.js +12 -5
  268. package/dist/modules/workspace/startup/steps/plugin-manifests.step.js.map +1 -1
  269. package/dist/modules/workspace/startup/steps/seed-tree.d.ts +4 -1
  270. package/dist/modules/workspace/startup/steps/seed-tree.d.ts.map +1 -1
  271. package/dist/modules/workspace/startup/steps/seed-tree.js +14 -11
  272. package/dist/modules/workspace/startup/steps/seed-tree.js.map +1 -1
  273. package/dist/modules/workspace/startup/steps/template-files.step.d.ts +17 -3
  274. package/dist/modules/workspace/startup/steps/template-files.step.d.ts.map +1 -1
  275. package/dist/modules/workspace/startup/steps/template-files.step.js +36 -30
  276. package/dist/modules/workspace/startup/steps/template-files.step.js.map +1 -1
  277. package/dist/modules/workspace/startup/steps/template-source.d.ts +6 -1
  278. package/dist/modules/workspace/startup/steps/template-source.d.ts.map +1 -1
  279. package/dist/modules/workspace/startup/steps/template-source.js +10 -6
  280. package/dist/modules/workspace/startup/steps/template-source.js.map +1 -1
  281. package/dist/modules/workspace/workspace.routes.d.ts +2 -1
  282. package/dist/modules/workspace/workspace.routes.d.ts.map +1 -1
  283. package/dist/modules/workspace/workspace.routes.js +8 -7
  284. package/dist/modules/workspace/workspace.routes.js.map +1 -1
  285. package/dist/modules/workspace/workspace.service.d.ts +18 -12
  286. package/dist/modules/workspace/workspace.service.d.ts.map +1 -1
  287. package/dist/modules/workspace/workspace.service.js +32 -28
  288. package/dist/modules/workspace/workspace.service.js.map +1 -1
  289. package/dist/modules/workspace/workspace.tools.d.ts +2 -1
  290. package/dist/modules/workspace/workspace.tools.d.ts.map +1 -1
  291. package/dist/modules/workspace/workspace.tools.js +20 -18
  292. package/dist/modules/workspace/workspace.tools.js.map +1 -1
  293. package/dist/modules/workspace/write-denial.d.ts +3 -2
  294. package/dist/modules/workspace/write-denial.d.ts.map +1 -1
  295. package/dist/modules/workspace/write-denial.js +6 -5
  296. package/dist/modules/workspace/write-denial.js.map +1 -1
  297. package/dist/shared/git.contract.d.ts +52 -7
  298. package/dist/shared/git.contract.d.ts.map +1 -1
  299. package/dist/shared/git.contract.js +30 -8
  300. package/dist/shared/git.contract.js.map +1 -1
  301. package/dist/shared/kb-context.d.ts +76 -0
  302. package/dist/shared/kb-context.d.ts.map +1 -0
  303. package/dist/shared/kb-context.js +108 -0
  304. package/dist/shared/kb-context.js.map +1 -0
  305. package/dist/shared/kb-layout.d.ts +3 -2
  306. package/dist/shared/kb-layout.d.ts.map +1 -1
  307. package/dist/shared/kb-layout.js +4 -3
  308. package/dist/shared/kb-layout.js.map +1 -1
  309. package/dist/shared/kb-layout.test.js +35 -27
  310. package/dist/shared/kb-layout.test.js.map +1 -1
  311. package/dist/shared/pending-proposals.d.ts +4 -1
  312. package/dist/shared/pending-proposals.d.ts.map +1 -1
  313. package/dist/shared/pending-proposals.js +3 -4
  314. package/dist/shared/pending-proposals.js.map +1 -1
  315. package/dist/shared/redact-secret.d.ts +5 -5
  316. package/dist/shared/redact-secret.js +5 -5
  317. package/dist/tenancy/index.d.ts +13 -0
  318. package/dist/tenancy/index.d.ts.map +1 -0
  319. package/dist/tenancy/index.js +13 -0
  320. package/dist/tenancy/index.js.map +1 -0
  321. package/dist/tenancy/static-tenant-source.d.ts +98 -0
  322. package/dist/tenancy/static-tenant-source.d.ts.map +1 -0
  323. package/dist/tenancy/static-tenant-source.js +220 -0
  324. package/dist/tenancy/static-tenant-source.js.map +1 -0
  325. package/dist/tenancy/tenant-host.d.ts +80 -0
  326. package/dist/tenancy/tenant-host.d.ts.map +1 -0
  327. package/dist/tenancy/tenant-host.js +217 -0
  328. package/dist/tenancy/tenant-host.js.map +1 -0
  329. package/dist/tenancy/tenant-runtime.d.ts +91 -0
  330. package/dist/tenancy/tenant-runtime.d.ts.map +1 -0
  331. package/dist/tenancy/tenant-runtime.js +174 -0
  332. package/dist/tenancy/tenant-runtime.js.map +1 -0
  333. package/dist/tenancy/tenant-secrets.d.ts +24 -0
  334. package/dist/tenancy/tenant-secrets.d.ts.map +1 -0
  335. package/dist/tenancy/tenant-secrets.js +30 -0
  336. package/dist/tenancy/tenant-secrets.js.map +1 -0
  337. package/dist/tenancy/tenant-source.contract.d.ts +45 -0
  338. package/dist/tenancy/tenant-source.contract.d.ts.map +1 -0
  339. package/dist/tenancy/tenant-source.contract.js +21 -0
  340. package/dist/tenancy/tenant-source.contract.js.map +1 -0
  341. package/migrations/0000_core_init.sql +14 -14
  342. package/migrations/0003_deployment_settings.sql +1 -1
  343. package/migrations/0005_github_facade.sql +1 -1
  344. package/migrations/0012_agent_audit.sql +6 -6
  345. package/package.json +3 -3
  346. package/src/__tests__/branch-model.test.ts +7 -6
  347. package/src/__tests__/kb-context.ts +30 -0
  348. package/src/__tests__/kb-layout-config.test.ts +35 -30
  349. package/src/core/__tests__/catalog-cache-invalidation.test.ts +2 -1
  350. package/src/core/__tests__/lifecycle.test.ts +78 -1
  351. package/src/core/__tests__/public-config.test.ts +5 -1
  352. package/src/core/catalog-cache-invalidation.ts +16 -11
  353. package/src/core/core-ports.ts +19 -0
  354. package/src/core/create-core-server.ts +27 -106
  355. package/src/core/create-core-services.ts +180 -95
  356. package/src/core/lifecycle.ts +214 -29
  357. package/src/core/public-config.ts +8 -5
  358. package/src/core-config.ts +107 -8
  359. package/src/index.ts +25 -2
  360. package/src/modules/access/__tests__/access-control.admin-root-floor.test.ts +2 -1
  361. package/src/modules/access/__tests__/access.routes.batch.test.ts +2 -1
  362. package/src/modules/access/__tests__/access.routes.folder-governs.test.ts +2 -1
  363. package/src/modules/access/__tests__/access.routes.group-grant.test.ts +2 -1
  364. package/src/modules/access/__tests__/access.routes.overrides.test.ts +2 -1
  365. package/src/modules/access/__tests__/access.routes.proposal-branch.test.ts +2 -1
  366. package/src/modules/access/__tests__/access.routes.prospective.test.ts +2 -1
  367. package/src/modules/access/__tests__/access.routes.revoke.test.ts +2 -1
  368. package/src/modules/access/__tests__/access.routes.unknown-email.test.ts +2 -1
  369. package/src/modules/access/__tests__/change-read-gate.test.ts +13 -11
  370. package/src/modules/access/__tests__/creator-access.test.ts +3 -2
  371. package/src/modules/access/__tests__/roles.routes.test.ts +2 -1
  372. package/src/modules/access/access-control.service.ts +20 -6
  373. package/src/modules/access/access.routes.ts +10 -13
  374. package/src/modules/access/change-read-gate.ts +10 -4
  375. package/src/modules/access/creator-access.ts +7 -2
  376. package/src/modules/agent-instructions/__tests__/read-preamble.test.ts +13 -12
  377. package/src/modules/agent-instructions/read-preamble.ts +10 -12
  378. package/src/modules/auth/__tests__/account.routes.test.ts +15 -0
  379. package/src/modules/auth/__tests__/auth.service.test.ts +60 -0
  380. package/src/modules/auth/account-admission.ts +44 -0
  381. package/src/modules/auth/account.routes.ts +4 -1
  382. package/src/modules/auth/auth.service.ts +33 -1
  383. package/src/modules/auth/oidc-auth-provider.ts +9 -0
  384. package/src/modules/connection-probe/connection-probe.service.ts +7 -1
  385. package/src/modules/database/__tests__/advisory-lock.test.ts +23 -1
  386. package/src/modules/database/__tests__/connection.test.ts +98 -0
  387. package/src/modules/database/__tests__/migrations-unqualified.test.ts +32 -0
  388. package/src/modules/database/advisory-lock.ts +28 -4
  389. package/src/modules/database/connection.ts +143 -13
  390. package/src/modules/database/migrate.ts +48 -14
  391. package/src/modules/diff/__tests__/diff.service.seed-atomicity.test.ts +2 -1
  392. package/src/modules/diff/__tests__/diff.service.test.ts +2 -1
  393. package/src/modules/kb-fs/__tests__/branch-name.test.ts +6 -6
  394. package/src/modules/kb-fs/__tests__/clone-config.test.ts +24 -20
  395. package/src/modules/kb-fs/branch-name.ts +3 -3
  396. package/src/modules/kb-fs/clone-config.ts +15 -12
  397. package/src/modules/marketplace/__tests__/marketplace-repo.head.test.ts +2 -1
  398. package/src/modules/mcp/mcp.service.ts +11 -4
  399. package/src/modules/plugins/__tests__/bundle-dialect.e2e.test.ts +12 -11
  400. package/src/modules/plugins/__tests__/bundle-dialect.test.ts +2 -1
  401. package/src/modules/plugins/__tests__/compile-marketplace.test.ts +6 -4
  402. package/src/modules/plugins/__tests__/join-request-jobs.service.test.ts +2 -1
  403. package/src/modules/plugins/__tests__/join-requests.service.test.ts +2 -1
  404. package/src/modules/plugins/__tests__/plugin-creation-display-name.test.ts +4 -3
  405. package/src/modules/plugins/__tests__/plugin-index.service.test.ts +6 -4
  406. package/src/modules/plugins/__tests__/plugin-links.service.test.ts +220 -5
  407. package/src/modules/plugins/__tests__/plugin-provision.service.test.ts +3 -1
  408. package/src/modules/plugins/__tests__/plugin-rename.service.test.ts +7 -6
  409. package/src/modules/plugins/__tests__/plugins.routes.test.ts +11 -2
  410. package/src/modules/plugins/__tests__/teams.routes.test.ts +2 -1
  411. package/src/modules/plugins/compile/marketplace-compiler.service.ts +7 -9
  412. package/src/modules/plugins/discovery/__tests__/kb-plugin-source.test.ts +20 -16
  413. package/src/modules/plugins/discovery/bundle-dialect/bundle.source.ts +9 -2
  414. package/src/modules/plugins/discovery/kb-plugin-source.ts +15 -8
  415. package/src/modules/plugins/discovery/native.source.ts +4 -1
  416. package/src/modules/plugins/index.ts +1 -1
  417. package/src/modules/plugins/join-request-jobs.service.ts +8 -7
  418. package/src/modules/plugins/join-requests.service.ts +7 -7
  419. package/src/modules/plugins/plugin-links.service.ts +192 -19
  420. package/src/modules/plugins/plugin-links.ts +147 -27
  421. package/src/modules/plugins/plugin-provision.service.ts +54 -27
  422. package/src/modules/plugins/plugin-rename.service.ts +10 -10
  423. package/src/modules/plugins/plugins.routes.ts +45 -15
  424. package/src/modules/plugins/plugins.service.ts +7 -11
  425. package/src/modules/plugins/teams.routes.ts +16 -8
  426. package/src/modules/secrets-vault/__tests__/connect-pending.route.test.ts +7 -0
  427. package/src/modules/secrets-vault/__tests__/secrets-variable-loader.test.ts +40 -0
  428. package/src/modules/secrets-vault/__tests__/tool-owner-gate.route.test.ts +2 -0
  429. package/src/modules/secrets-vault/index.ts +2 -0
  430. package/src/modules/secrets-vault/secrets-variable-loader.ts +51 -21
  431. package/src/modules/secrets-vault/secrets-vault.routes.ts +7 -6
  432. package/src/modules/settings/__tests__/deployment-settings.service.test.ts +24 -11
  433. package/src/modules/settings/__tests__/git-root-folders.test.ts +2 -1
  434. package/src/modules/settings/__tests__/setup.routes.boot-failure.test.ts +2 -1
  435. package/src/modules/settings/__tests__/setup.routes.layout-phase.test.ts +7 -4
  436. package/src/modules/settings/__tests__/setup.routes.oidc.test.ts +2 -0
  437. package/src/modules/settings/__tests__/setup.routes.sync-status.test.ts +2 -0
  438. package/src/modules/settings/__tests__/setup.routes.test.ts +33 -52
  439. package/src/modules/settings/deployment-settings.service.ts +21 -20
  440. package/src/modules/settings/setup.routes.ts +26 -16
  441. package/src/modules/skills/__tests__/allowed-tools-check.test.ts +11 -10
  442. package/src/modules/skills/__tests__/allowed-tools-warn.tools.test.ts +4 -3
  443. package/src/modules/skills/__tests__/pending-skills.service.test.ts +3 -1
  444. package/src/modules/skills/__tests__/skill-access-requests.routes.test.ts +2 -1
  445. package/src/modules/skills/__tests__/skills.routes.warnings.test.ts +2 -1
  446. package/src/modules/skills/__tests__/skills.service.test.ts +3 -2
  447. package/src/modules/skills/allowed-tools-check.ts +7 -6
  448. package/src/modules/skills/pending-skills.service.ts +9 -8
  449. package/src/modules/skills/skill-access-requests.routes.ts +7 -7
  450. package/src/modules/skills/skills.routes.ts +4 -3
  451. package/src/modules/skills/skills.service.ts +13 -9
  452. package/src/modules/tool-helpers/__tests__/agent-roles-write.test.ts +3 -2
  453. package/src/modules/tool-helpers/__tests__/phase4-tools.test.ts +3 -2
  454. package/src/modules/tool-manuals/__tests__/mcp-json-discovery.test.ts +17 -12
  455. package/src/modules/tool-manuals/__tests__/mcp-server-edit.service.test.ts +2 -1
  456. package/src/modules/tool-manuals/__tests__/pending-tools.service.test.ts +4 -1
  457. package/src/modules/tool-manuals/__tests__/tool-delete.service.test.ts +2 -1
  458. package/src/modules/tool-manuals/__tests__/tool-manuals.archive.route.test.ts +2 -1
  459. package/src/modules/tool-manuals/__tests__/tool-manuals.cli.test.ts +5 -4
  460. package/src/modules/tool-manuals/__tests__/tool-manuals.detail.route.test.ts +2 -1
  461. package/src/modules/tool-manuals/__tests__/tool-manuals.invalid.routes.test.ts +4 -2
  462. package/src/modules/tool-manuals/__tests__/tool-manuals.invalid.test.ts +13 -5
  463. package/src/modules/tool-manuals/__tests__/tool-manuals.mcp-oauth.test.ts +2 -1
  464. package/src/modules/tool-manuals/__tests__/tool-manuals.restart.test.ts +9 -1
  465. package/src/modules/tool-manuals/__tests__/tool-manuals.service.test.ts +3 -2
  466. package/src/modules/tool-manuals/__tests__/tool-manuals.tools.test.ts +2 -0
  467. package/src/modules/tool-manuals/mcp-json-discovery.ts +6 -4
  468. package/src/modules/tool-manuals/mcp-server-edit.service.ts +13 -11
  469. package/src/modules/tool-manuals/pending-tools.service.ts +19 -16
  470. package/src/modules/tool-manuals/tool-delete.service.ts +13 -10
  471. package/src/modules/tool-manuals/tool-manuals.routes.ts +10 -8
  472. package/src/modules/tool-manuals/tool-manuals.service.ts +15 -13
  473. package/src/modules/tool-manuals/tool-manuals.tools.ts +7 -6
  474. package/src/modules/workflow/__tests__/apply-failure.test.ts +2 -1
  475. package/src/modules/workflow/__tests__/merge-announces-tree.test.ts +14 -26
  476. package/src/modules/workflow/__tests__/preserve-roles-yaml.test.ts +2 -1
  477. package/src/modules/workflow/__tests__/session-ontology.service.test.ts +3 -2
  478. package/src/modules/workflow/__tests__/workflow.routes.lock-path.test.ts +2 -1
  479. package/src/modules/workflow/__tests__/workflow.service.branch-in-use.test.ts +3 -10
  480. package/src/modules/workflow/__tests__/workflow.service.commitFileWhileLocked.test.ts +2 -1
  481. package/src/modules/workflow/__tests__/workflow.service.deleted-branch-sweep.test.ts +3 -10
  482. package/src/modules/workflow/__tests__/workflow.service.facade.test.ts +28 -27
  483. package/src/modules/workflow/__tests__/workflow.service.folder-proposals.test.ts +2 -1
  484. package/src/modules/workflow/__tests__/workflow.service.platform-restore.test.ts +2 -1
  485. package/src/modules/workflow/__tests__/workflow.service.read-gate.test.ts +3 -2
  486. package/src/modules/workflow/__tests__/workflow.service.releaseLock.test.ts +2 -1
  487. package/src/modules/workflow/__tests__/workflow.service.sync.test.ts +5 -4
  488. package/src/modules/workflow/__tests__/workflow.service.update-from-target.test.ts +2 -1
  489. package/src/modules/workflow/agent-tools/__tests__/workflow.tools.test.ts +2 -1
  490. package/src/modules/workflow/agent-tools/workflow.tools.ts +11 -9
  491. package/src/modules/workflow/git/__tests__/git.service.accessGating.test.ts +5 -4
  492. package/src/modules/workflow/git/__tests__/git.service.changedFilesForPr.test.ts +12 -11
  493. package/src/modules/workflow/git/__tests__/git.service.commitChanges.test.ts +9 -8
  494. package/src/modules/workflow/git/__tests__/git.service.commitFile.strayPath.test.ts +8 -7
  495. package/src/modules/workflow/git/__tests__/git.service.commitFile.test.ts +6 -5
  496. package/src/modules/workflow/git/__tests__/git.service.createBranch.test.ts +3 -2
  497. package/src/modules/workflow/git/__tests__/git.service.deleteBranch.test.ts +3 -2
  498. package/src/modules/workflow/git/__tests__/git.service.diffFileAtCommit.test.ts +7 -6
  499. package/src/modules/workflow/git/__tests__/git.service.diffFileBetweenBranches.test.ts +16 -15
  500. package/src/modules/workflow/git/__tests__/git.service.fileContentsAtCommit.test.ts +3 -2
  501. package/src/modules/workflow/git/__tests__/git.service.forkPoint.test.ts +2 -1
  502. package/src/modules/workflow/git/__tests__/git.service.history-guards.test.ts +2 -1
  503. package/src/modules/workflow/git/__tests__/git.service.list-branches.test.ts +10 -9
  504. package/src/modules/workflow/git/__tests__/git.service.listTrackedFiles.test.ts +2 -1
  505. package/src/modules/workflow/git/__tests__/git.service.logForFile.test.ts +6 -5
  506. package/src/modules/workflow/git/__tests__/git.service.mergeChangeRequest.test.ts +9 -8
  507. package/src/modules/workflow/git/__tests__/git.service.pendingChanges.test.ts +2 -1
  508. package/src/modules/workflow/git/__tests__/git.service.postMergePull.test.ts +4 -3
  509. package/src/modules/workflow/git/__tests__/git.service.pull.test.ts +9 -8
  510. package/src/modules/workflow/git/__tests__/git.service.readFileAtRef.test.ts +2 -1
  511. package/src/modules/workflow/git/__tests__/git.service.revertPathsAndPush.test.ts +2 -1
  512. package/src/modules/workflow/git/__tests__/git.service.status.test.ts +4 -3
  513. package/src/modules/workflow/git/__tests__/git.service.syncFromRemote.test.ts +8 -7
  514. package/src/modules/workflow/git/__tests__/node-git-runner.test.ts +41 -3
  515. package/src/modules/workflow/git/git.service.ts +24 -13
  516. package/src/modules/workflow/git/node-git-runner.ts +37 -4
  517. package/src/modules/workflow/review-workflow/review-workflow.service.ts +9 -6
  518. package/src/modules/workflow/session-ontology.service.ts +7 -2
  519. package/src/modules/workflow/workflow.service.ts +31 -24
  520. package/src/modules/workspace/__tests__/file-stat-access.test.ts +3 -2
  521. package/src/modules/workspace/__tests__/git-internals.security.test.ts +10 -9
  522. package/src/modules/workspace/__tests__/session-ontology.gate.test.ts +4 -2
  523. package/src/modules/workspace/__tests__/workspace-paths-inside-the-repo.test.ts +3 -2
  524. package/src/modules/workspace/__tests__/workspace.routes.branch-errors.test.ts +2 -1
  525. package/src/modules/workspace/__tests__/workspace.routes.create-grant.test.ts +2 -1
  526. package/src/modules/workspace/__tests__/workspace.routes.delete.test.ts +2 -1
  527. package/src/modules/workspace/__tests__/workspace.routes.download-implies-read.test.ts +2 -1
  528. package/src/modules/workspace/__tests__/workspace.routes.download.test.ts +2 -1
  529. package/src/modules/workspace/__tests__/workspace.routes.file-writes.test.ts +2 -1
  530. package/src/modules/workspace/__tests__/workspace.routes.folders.test.ts +5 -4
  531. package/src/modules/workspace/__tests__/workspace.routes.move-platform-files.test.ts +2 -1
  532. package/src/modules/workspace/__tests__/workspace.routes.read-gate.test.ts +2 -1
  533. package/src/modules/workspace/__tests__/workspace.service.ensure-remotes-fetched.test.ts +2 -2
  534. package/src/modules/workspace/__tests__/workspace.service.list-cloned.test.ts +6 -5
  535. package/src/modules/workspace/__tests__/workspace.service.move-never-overwrites.test.ts +2 -1
  536. package/src/modules/workspace/__tests__/workspace.service.read-filter.test.ts +2 -1
  537. package/src/modules/workspace/__tests__/workspace.service.test.ts +84 -50
  538. package/src/modules/workspace/__tests__/workspace.service.unknown-branch.test.ts +2 -1
  539. package/src/modules/workspace/__tests__/workspace.tools.agents-file.test.ts +10 -7
  540. package/src/modules/workspace/__tests__/workspace.tools.branch-errors.test.ts +4 -3
  541. package/src/modules/workspace/__tests__/workspace.tools.test.ts +9 -8
  542. package/src/modules/workspace/__tests__/write-denial.test.ts +5 -4
  543. package/src/modules/workspace/session-ontology.gate.ts +6 -4
  544. package/src/modules/workspace/startup/__tests__/kb-startup-runner.degraded.test.ts +6 -2
  545. package/src/modules/workspace/startup/__tests__/kb-startup-runner.test.ts +29 -21
  546. package/src/modules/workspace/startup/kb-git.ts +15 -22
  547. package/src/modules/workspace/startup/kb-startup-runner.ts +40 -46
  548. package/src/modules/workspace/startup/steps/__tests__/steps.test.ts +104 -98
  549. package/src/modules/workspace/startup/steps/groups-to-plugins.step.ts +24 -16
  550. package/src/modules/workspace/startup/steps/personal-spaces.step.ts +14 -5
  551. package/src/modules/workspace/startup/steps/plugin-display-names.step.ts +13 -5
  552. package/src/modules/workspace/startup/steps/plugin-manifests.step.ts +14 -5
  553. package/src/modules/workspace/startup/steps/seed-tree.ts +11 -9
  554. package/src/modules/workspace/startup/steps/template-files.step.ts +43 -34
  555. package/src/modules/workspace/startup/steps/template-source.ts +8 -5
  556. package/src/modules/workspace/workspace.routes.ts +8 -7
  557. package/src/modules/workspace/workspace.service.ts +30 -27
  558. package/src/modules/workspace/workspace.tools.ts +21 -20
  559. package/src/modules/workspace/write-denial.ts +7 -5
  560. package/src/shared/__tests__/kb-layout.plugin.test.ts +19 -16
  561. package/src/shared/git.contract.ts +70 -8
  562. package/src/shared/kb-context.ts +130 -0
  563. package/src/shared/kb-layout.test.ts +37 -27
  564. package/src/shared/kb-layout.ts +4 -3
  565. package/src/shared/pending-proposals.ts +7 -4
  566. package/src/shared/redact-secret.ts +5 -5
  567. package/src/tenancy/__tests__/static-tenant-source.test.ts +177 -0
  568. package/src/tenancy/__tests__/tenant-host.test.ts +372 -0
  569. package/src/tenancy/__tests__/tenant-runtime.test.ts +221 -0
  570. package/src/tenancy/__tests__/tenant-secrets.test.ts +35 -0
  571. package/src/tenancy/index.ts +35 -0
  572. package/src/tenancy/static-tenant-source.ts +296 -0
  573. package/src/tenancy/tenant-host.ts +261 -0
  574. package/src/tenancy/tenant-runtime.ts +208 -0
  575. package/src/tenancy/tenant-secrets.ts +41 -0
  576. package/src/tenancy/tenant-source.contract.ts +59 -0
@@ -5,6 +5,7 @@ import path from 'node:path';
5
5
  import os from 'node:os';
6
6
  import express from 'express';
7
7
  import { describe, it, expect, beforeEach, afterEach } from 'vitest';
8
+ import { testKbContext } from '../../../__tests__/kb-context.js';
8
9
 
9
10
  import { NodeFs } from '../../kb-fs/node-fs.js';
10
11
  import type { IWorkflowService } from '@bevel-software/platform-shared';
@@ -103,7 +104,7 @@ describe('GET /file/raw on a download-only path (real resolver)', () => {
103
104
  {} as unknown as IWorkflowService,
104
105
  {} as unknown as WorkflowEventBus,
105
106
  accessControl,
106
- KB,
107
+ testKbContext({ kbDirName: KB }),
107
108
  stubCreatorAccess,
108
109
  { isAdmin: async () => false } as unknown as IAdminAccessService,
109
110
  new NodeFs(),
@@ -2,6 +2,7 @@ import { get as httpGet, type Server } from 'node:http';
2
2
  import type { AddressInfo } from 'node:net';
3
3
  import express from 'express';
4
4
  import { describe, it, expect, afterEach, vi } from 'vitest';
5
+ import { testKbContext } from '../../../__tests__/kb-context.js';
5
6
  import { NodeFs } from '../../kb-fs/node-fs.js';
6
7
  import { PathTraversalError } from '../../../shared/domain-errors.js';
7
8
  import type { IWorkflowService } from '@bevel-software/platform-shared';
@@ -129,7 +130,7 @@ async function makeHarness(opts: {
129
130
  workflowService,
130
131
  eventBus,
131
132
  accessControl,
132
- KB,
133
+ testKbContext({ kbDirName: KB }),
133
134
  stubCreatorAccess,
134
135
  // Not exercised here — only `.bevelignore`'s tree visibility consults it.
135
136
  { isAdmin: async () => false } as unknown as IAdminAccessService,
@@ -2,6 +2,7 @@ import type { Server } from 'node:http';
2
2
  import type { AddressInfo } from 'node:net';
3
3
  import express from 'express';
4
4
  import { describe, it, expect, afterEach, vi } from 'vitest';
5
+ import { testKbContext } from '../../../__tests__/kb-context.js';
5
6
  import { NodeFs } from '../../kb-fs/node-fs.js';
6
7
  import { PathTraversalError } from '../../../shared/domain-errors.js';
7
8
  import { EntryExistsError } from '../workspace.service.js';
@@ -149,7 +150,7 @@ async function makeHarness(opts: { canRead?: boolean; skillSaveCheck?: SkillSave
149
150
  workflowService,
150
151
  { emit: vi.fn() } as unknown as WorkflowEventBus,
151
152
  accessControl,
152
- KB,
153
+ testKbContext({ kbDirName: KB }),
153
154
  stubCreatorAccess,
154
155
  { isAdmin: async () => true } as unknown as IAdminAccessService,
155
156
  new NodeFs(),
@@ -5,6 +5,7 @@ import path from 'node:path';
5
5
  import os from 'node:os';
6
6
  import express from 'express';
7
7
  import { describe, it, expect, afterEach, vi } from 'vitest';
8
+ import { testKbContext } from '../../../__tests__/kb-context.js';
8
9
  import type { FileTreeEntry, IWorkflowService } from '@bevel-software/platform-shared';
9
10
  import { NodeFs } from '../../kb-fs/node-fs.js';
10
11
  import type { IAccessControl } from '../../access/access-control.interface.js';
@@ -55,7 +56,7 @@ async function makeHarness(): Promise<Harness> {
55
56
  const workspaceDir = path.join(root, workspaceId);
56
57
  // The inner `.git` lets the service accept the workspace without cloning.
57
58
  await fs.mkdir(path.join(workspaceDir, KB, '.git'), { recursive: true });
58
- const workspaceService = new WorkspaceService(root, 'https://example.invalid/kb.git', KB, new NodeFs());
59
+ const workspaceService = new WorkspaceService(root, 'https://example.invalid/kb.git', testKbContext({ kbDirName: KB }), new NodeFs());
59
60
  await workspaceService.getWorkspacePath(workspaceId);
60
61
 
61
62
  const releaseLock = vi.fn<(...args: unknown[]) => Promise<never>>(async () => undefined as never);
@@ -85,7 +86,7 @@ async function makeHarness(): Promise<Harness> {
85
86
  workflowService,
86
87
  { emit } as unknown as WorkflowEventBus,
87
88
  allowAll,
88
- KB,
89
+ testKbContext({ kbDirName: KB }),
89
90
  stubCreatorAccess,
90
91
  { isAdmin: async () => false } as unknown as IAdminAccessService,
91
92
  new NodeFs(),
@@ -334,7 +335,7 @@ describe('WorkspaceService.writeFolderPlaceholder', () => {
334
335
  const workspaceId = workspaceIdForBranch('placeholders');
335
336
  const kbDir = path.join(root, workspaceId, KB);
336
337
  await fs.mkdir(path.join(kbDir, '.git'), { recursive: true });
337
- return { svc: new WorkspaceService(root, 'https://example.invalid/kb.git', KB, new NodeFs()), workspaceId, kbDir };
338
+ return { svc: new WorkspaceService(root, 'https://example.invalid/kb.git', testKbContext({ kbDirName: KB }), new NodeFs()), workspaceId, kbDir };
338
339
  }
339
340
 
340
341
  it('writes into an empty folder, and leaves a full or a vanished one alone', async () => {
@@ -377,7 +378,7 @@ describe('WorkspaceService.withFolderTurn', () => {
377
378
  root = await fs.mkdtemp(path.join(os.tmpdir(), 'folder-turn-'));
378
379
  const workspaceId = workspaceIdForBranch('turns');
379
380
  await fs.mkdir(path.join(root, workspaceId, KB, '.git'), { recursive: true });
380
- const svc = new WorkspaceService(root, 'https://example.invalid/kb.git', KB, new NodeFs());
381
+ const svc = new WorkspaceService(root, 'https://example.invalid/kb.git', testKbContext({ kbDirName: KB }), new NodeFs());
381
382
 
382
383
  const events: string[] = [];
383
384
  let open!: () => void;
@@ -5,6 +5,7 @@ import path from 'node:path';
5
5
  import os from 'node:os';
6
6
  import express from 'express';
7
7
  import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
8
+ import { testKbContext } from '../../../__tests__/kb-context.js';
8
9
  import { NodeFs } from '../../kb-fs/node-fs.js';
9
10
  import type { IWorkflowService } from '@bevel-software/platform-shared';
10
11
  import type { IAccessControl } from '../../access/access-control.interface.js';
@@ -95,7 +96,7 @@ async function makeHarness(): Promise<Harness> {
95
96
  workflowService,
96
97
  eventBus,
97
98
  accessControl,
98
- KB,
99
+ testKbContext({ kbDirName: KB }),
99
100
  creatorAccess,
100
101
  { isAdmin: async () => false } as unknown as IAdminAccessService,
101
102
  new NodeFs(),
@@ -2,6 +2,7 @@ import type { Server } from 'node:http';
2
2
  import type { AddressInfo } from 'node:net';
3
3
  import express from 'express';
4
4
  import { describe, it, expect, afterEach, vi } from 'vitest';
5
+ import { testKbContext } from '../../../__tests__/kb-context.js';
5
6
  import { NodeFs } from '../../kb-fs/node-fs.js';
6
7
  import type { IWorkflowService } from '@bevel-software/platform-shared';
7
8
  import type { IAccessControl } from '../../access/access-control.interface.js';
@@ -93,7 +94,7 @@ async function makeHarness(opts: {
93
94
  {} as unknown as IWorkflowService,
94
95
  {} as unknown as WorkflowEventBus,
95
96
  accessControl,
96
- KB,
97
+ testKbContext({ kbDirName: KB }),
97
98
  stubCreatorAccess,
98
99
  { isAdmin: async () => opts.isAdmin === true } as unknown as IAdminAccessService,
99
100
  new NodeFs(),
@@ -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 fs from 'node:fs/promises';
3
4
  import path from 'node:path';
4
5
  import os from 'node:os';
@@ -44,9 +45,8 @@ describe('WorkspaceService.ensureRemotesFetched', () => {
44
45
  new WorkspaceService(
45
46
  root,
46
47
  'https://example.test/kb.git',
47
- 'knowledge-base',
48
+ testKbContext(),
48
49
  new NodeFs(),
49
- 'x-access-token',
50
50
  runner,
51
51
  );
52
52
 
@@ -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 { NodeFs } from '../../kb-fs/node-fs.js';
3
4
  import fs from 'node:fs/promises';
4
5
  import path from 'node:path';
@@ -36,7 +37,7 @@ describe('WorkspaceService.listClonedWorkspaces', () => {
36
37
  // A stray file at the root is ignored.
37
38
  await fs.writeFile(path.join(root, 'notes.txt'), 'x');
38
39
 
39
- const svc = new WorkspaceService(root, 'https://example.test/kb.git', 'knowledge-base', new NodeFs());
40
+ const svc = new WorkspaceService(root, 'https://example.test/kb.git', testKbContext(), new NodeFs());
40
41
  const found = await svc.listClonedWorkspaces();
41
42
  expect(found.sort((a, b) => a.branch.localeCompare(b.branch))).toEqual([
42
43
  { id: 'ali%2Fnew-skill', branch: 'ali/new-skill' },
@@ -45,7 +46,7 @@ describe('WorkspaceService.listClonedWorkspaces', () => {
45
46
  });
46
47
 
47
48
  it('is empty when the workspaces root does not exist yet', async () => {
48
- const svc = new WorkspaceService(path.join(root, 'missing'), 'https://example.test/kb.git', 'knowledge-base', new NodeFs());
49
+ const svc = new WorkspaceService(path.join(root, 'missing'), 'https://example.test/kb.git', testKbContext(), new NodeFs());
49
50
  expect(await svc.listClonedWorkspaces()).toEqual([]);
50
51
  });
51
52
  });
@@ -66,14 +67,14 @@ describe('WorkspaceService.listClonedWorkspaces — what is not a clone', () =>
66
67
  for (const name of ['main', 'foo!', '-leading-dash', 'a..b', 'has space']) {
67
68
  await fs.mkdir(path.join(root, name, 'knowledge-base', '.git'), { recursive: true });
68
69
  }
69
- const svc = new WorkspaceService(root, 'https://example.test/kb.git', 'knowledge-base', new NodeFs());
70
+ const svc = new WorkspaceService(root, 'https://example.test/kb.git', testKbContext(), new NodeFs());
70
71
  expect(await svc.listClonedWorkspaces()).toEqual([{ id: 'main', branch: 'main' }]);
71
72
  });
72
73
 
73
74
  it('a branch whose bootstrap is in flight right now', async () => {
74
75
  await fs.mkdir(path.join(root, 'main', 'knowledge-base', '.git'), { recursive: true });
75
76
  await fs.mkdir(path.join(root, 'ali%2Fx', 'knowledge-base', '.git'), { recursive: true });
76
- const svc = new WorkspaceService(root, 'https://example.test/kb.git', 'knowledge-base', new NodeFs());
77
+ const svc = new WorkspaceService(root, 'https://example.test/kb.git', testKbContext(), new NodeFs());
77
78
  // While a clone runs, `.git` exists but the tree is not checked out yet.
78
79
  // The listing asks the public predicate, which is stubbed here rather than
79
80
  // the tracker behind it — no public seam can hold a real clone open.
@@ -88,7 +89,7 @@ describe('WorkspaceService.listClonedWorkspaces — what is not a clone', () =>
88
89
  // to stage one in a temp dir; the code path is the same `throw err`.
89
90
  const file = path.join(root, 'not-a-dir');
90
91
  await fs.writeFile(file, 'x');
91
- const svc = new WorkspaceService(file, 'https://example.test/kb.git', 'knowledge-base', new NodeFs());
92
+ const svc = new WorkspaceService(file, 'https://example.test/kb.git', testKbContext(), new NodeFs());
92
93
  expect(await svc.listClonedWorkspaces()).toEqual([]);
93
94
  });
94
95
  });
@@ -1,4 +1,5 @@
1
1
  import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
+ import { testKbContext } from '../../../__tests__/kb-context.js';
2
3
  import fs from 'node:fs/promises';
3
4
  import path from 'node:path';
4
5
  import os from 'node:os';
@@ -57,7 +58,7 @@ describe('WorkspaceService.moveEntry — a name that is taken is refused, never
57
58
  svc = new WorkspaceService(
58
59
  root,
59
60
  'https://github.com/Bevel-Software/knowledge-base.git',
60
- KB,
61
+ testKbContext({ kbDirName: KB }),
61
62
  new NodeFs(),
62
63
  );
63
64
  });
@@ -1,4 +1,5 @@
1
1
  import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
+ import { testKbContext } from '../../../__tests__/kb-context.js';
2
3
  import { NodeFs } from '../../kb-fs/node-fs.js';
3
4
  import fs from 'node:fs/promises';
4
5
  import path from 'node:path';
@@ -47,7 +48,7 @@ describe('WorkspaceService.listFiles — read filter', () => {
47
48
  // readers, say), and its files are readable.
48
49
  await mkFile(workspaceDir, 'Scopes/Deploy/SKILL.md');
49
50
  await mkFile(workspaceDir, 'Scopes/other.md');
50
- svc = new WorkspaceService(root, 'https://example.invalid/repo.git', KB, new NodeFs());
51
+ svc = new WorkspaceService(root, 'https://example.invalid/repo.git', testKbContext({ kbDirName: KB }), new NodeFs());
51
52
  await svc.getWorkspacePath(workspaceId);
52
53
  });
53
54
 
@@ -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 { NodeFs } from '../../kb-fs/node-fs.js';
3
4
  import { execFile } from 'node:child_process';
4
5
  import { promisify } from 'node:util';
@@ -65,7 +66,7 @@ describe('WorkspaceService — branch-keyed identity', () => {
65
66
  });
66
67
 
67
68
  it('a malformed workspace id (bad percent-escape) rejects as a 400 BranchNameError, not a 500', async () => {
68
- const svc = new WorkspaceService(root, 'https://github.com/Bevel-Software/knowledge-base.git', 'knowledge-base', new NodeFs());
69
+ const svc = new WorkspaceService(root, 'https://github.com/Bevel-Software/knowledge-base.git', testKbContext(), new NodeFs());
69
70
  // `%zz` fails decodeURIComponent, falls back to itself, and `%` never
70
71
  // passes the branch-name rules — the cold-path bootstrap must surface
71
72
  // that as the status-carrying domain error, not a wrapped plain Error.
@@ -77,7 +78,7 @@ describe('WorkspaceService — branch-keyed identity', () => {
77
78
 
78
79
  it('returns workspace info derived from the branch — no .workspace.json on disk', async () => {
79
80
  const { workspaceId, workspaceDir } = await seedBranchWorkspace(root, 'target-company-state');
80
- const svc = new WorkspaceService(root, 'https://github.com/Bevel-Software/knowledge-base.git', 'knowledge-base', new NodeFs());
81
+ const svc = new WorkspaceService(root, 'https://github.com/Bevel-Software/knowledge-base.git', testKbContext(), new NodeFs());
81
82
  const info = await svc.getOrCreateForBranch('target-company-state');
82
83
 
83
84
  expect(info.id).toBe(workspaceId);
@@ -90,7 +91,7 @@ describe('WorkspaceService — branch-keyed identity', () => {
90
91
  it('two branches map to distinct directories', async () => {
91
92
  const a = await seedBranchWorkspace(root, 'target-company-state');
92
93
  const b = await seedBranchWorkspace(root, 'alice/feature');
93
- const svc = new WorkspaceService(root, 'https://github.com/Bevel-Software/knowledge-base.git', 'knowledge-base', new NodeFs());
94
+ const svc = new WorkspaceService(root, 'https://github.com/Bevel-Software/knowledge-base.git', testKbContext(), new NodeFs());
94
95
 
95
96
  const infoA = await svc.getOrCreateForBranch('target-company-state');
96
97
  const infoB = await svc.getOrCreateForBranch('alice/feature');
@@ -113,7 +114,7 @@ describe('WorkspaceService — branch-keyed identity', () => {
113
114
  const squatter = path.join(workspaceDir, 'knowledge-base');
114
115
  await fs.writeFile(squatter, 'not a clone', 'utf8');
115
116
 
116
- const svc = new WorkspaceService(root, 'https://github.com/Bevel-Software/knowledge-base.git', 'knowledge-base', new NodeFs());
117
+ const svc = new WorkspaceService(root, 'https://github.com/Bevel-Software/knowledge-base.git', testKbContext(), new NodeFs());
117
118
  await expect(svc.getOrCreateForBranch('target-company-state')).rejects.toThrow(
118
119
  /"knowledge-base" in this workspace exists but is not a directory/,
119
120
  );
@@ -121,21 +122,21 @@ describe('WorkspaceService — branch-keyed identity', () => {
121
122
  });
122
123
 
123
124
  it('rejects invalid branch names before touching disk', async () => {
124
- const svc = new WorkspaceService(root, 'https://github.com/Bevel-Software/knowledge-base.git', 'knowledge-base', new NodeFs());
125
+ const svc = new WorkspaceService(root, 'https://github.com/Bevel-Software/knowledge-base.git', testKbContext(), new NodeFs());
125
126
  await expect(svc.getOrCreateForBranch('')).rejects.toThrow();
126
127
  await expect(svc.getOrCreateForBranch('-bad-leading-dash')).rejects.toThrow();
127
128
  });
128
129
 
129
130
  it('getOrCreateForUser falls back to target-company-state when no branch is supplied', async () => {
130
131
  await seedBranchWorkspace(root, 'target-company-state');
131
- const svc = new WorkspaceService(root, 'https://github.com/Bevel-Software/knowledge-base.git', 'knowledge-base', new NodeFs());
132
+ const svc = new WorkspaceService(root, 'https://github.com/Bevel-Software/knowledge-base.git', testKbContext(), new NodeFs());
132
133
  const info = await svc.getOrCreateForUser({ id: 'u', email: 'a@b.c', name: 'A' });
133
134
  expect(info.id).toBe(workspaceIdForBranch('target-company-state'));
134
135
  });
135
136
 
136
137
  it('getOrCreateForUser respects an explicit branch override', async () => {
137
138
  await seedBranchWorkspace(root, 'alice/feature');
138
- const svc = new WorkspaceService(root, 'https://github.com/Bevel-Software/knowledge-base.git', 'knowledge-base', new NodeFs());
139
+ const svc = new WorkspaceService(root, 'https://github.com/Bevel-Software/knowledge-base.git', testKbContext(), new NodeFs());
139
140
  const info = await svc.getOrCreateForUser({ id: 'u', email: 'a@b.c', name: 'A' }, 'alice/feature');
140
141
  expect(info.id).toBe(workspaceIdForBranch('alice/feature'));
141
142
  });
@@ -155,7 +156,7 @@ describe('WorkspaceService.createDirectory', () => {
155
156
  workspaceDir = seeded.workspaceDir;
156
157
  repoDir = path.join(workspaceDir, 'knowledge-base');
157
158
  workspaceId = seeded.workspaceId;
158
- svc = new WorkspaceService(root, 'https://github.com/Bevel-Software/knowledge-base.git', 'knowledge-base', new NodeFs());
159
+ svc = new WorkspaceService(root, 'https://github.com/Bevel-Software/knowledge-base.git', testKbContext(), new NodeFs());
159
160
  // Hydrate the in-memory map so subsequent ops resolve fast.
160
161
  await svc.getWorkspacePath(workspaceId);
161
162
  });
@@ -266,7 +267,7 @@ describe('WorkspaceService.writeFile — expectedContent', () => {
266
267
  const seeded = await seedBranchWorkspace(root, 'target-company-state');
267
268
  workspaceDir = seeded.workspaceDir;
268
269
  workspaceId = seeded.workspaceId;
269
- svc = new WorkspaceService(root, 'https://github.com/Bevel-Software/knowledge-base.git', 'knowledge-base', new NodeFs());
270
+ svc = new WorkspaceService(root, 'https://github.com/Bevel-Software/knowledge-base.git', testKbContext(), new NodeFs());
270
271
  });
271
272
 
272
273
  afterEach(async () => {
@@ -407,7 +408,7 @@ describe('WorkspaceService.withPathTurn', () => {
407
408
  const seeded = await seedBranchWorkspace(root, 'target-company-state');
408
409
  workspaceDir = seeded.workspaceDir;
409
410
  workspaceId = seeded.workspaceId;
410
- svc = new WorkspaceService(root, 'https://github.com/Bevel-Software/knowledge-base.git', 'knowledge-base', new NodeFs());
411
+ svc = new WorkspaceService(root, 'https://github.com/Bevel-Software/knowledge-base.git', testKbContext(), new NodeFs());
411
412
  });
412
413
 
413
414
  afterEach(async () => {
@@ -420,51 +421,68 @@ describe('WorkspaceService.withPathTurn', () => {
420
421
  await Promise.resolve();
421
422
  };
422
423
 
423
- it('runs one turn at a time, so two bodies never interleave', async () => {
424
- const order: string[] = [];
424
+ /**
425
+ * A turn whose body records when it runs — and, for the FIRST one, tells
426
+ * the test when it HOLDS the turn, so the next can be issued behind it.
427
+ *
428
+ * What the queue guarantees is one body at a time per file. It does NOT
429
+ * guarantee that turns issued together chain in the order they were
430
+ * issued: before a turn joins the queue its spelling is resolved and judged
431
+ * against the git folder on disk, and those probes finish in whatever order
432
+ * the disk answers, so a later call can join first. Asserting on names in a
433
+ * fixed order therefore needs the earlier turn to be HELD before the later
434
+ * one is issued; interleaving is then the only thing that could reorder.
435
+ */
436
+ const recorder = (order: string[]) => {
437
+ let holding: (() => void) | undefined;
438
+ const held = new Promise<void>((resolve) => { holding = resolve; });
425
439
  const body = (name: string) => async (): Promise<void> => {
426
440
  order.push(`${name}:enter`);
441
+ holding?.();
427
442
  await yieldTwice();
428
443
  order.push(`${name}:exit`);
429
444
  };
445
+ return { body, held };
446
+ };
447
+
448
+ /** Each name's exit follows its own enter at once: no body ran inside another. */
449
+ const expectNoInterleaving = (order: string[], names: string[]): void => {
450
+ for (const name of names) {
451
+ const enter = order.indexOf(`${name}:enter`);
452
+ expect(enter).toBeGreaterThanOrEqual(0);
453
+ expect(order[enter + 1]).toBe(`${name}:exit`);
454
+ }
455
+ };
430
456
 
431
- // Warm the workspace lookup first, for the reason the next test gives:
432
- // a COLD lookup resolves its callers in disk order rather than call
433
- // order, so `b` can reach the queue first and this assertion — which
434
- // names `a` as the one that goes first — fails for a scheduling reason
435
- // rather than an interleaving one.
436
- await svc.withPathTurn(workspaceId, 'knowledge-base/mcp-description.md', async () => undefined);
457
+ it('runs one turn at a time, so two bodies never interleave', async () => {
458
+ const order: string[] = [];
459
+ const { body, held } = recorder(order);
437
460
 
438
- await Promise.all([
439
- svc.withPathTurn(workspaceId, 'knowledge-base/mcp-description.md', body('a')),
440
- svc.withPathTurn(workspaceId, 'knowledge-base/mcp-description.md', body('b')),
441
- ]);
461
+ const a = svc.withPathTurn(workspaceId, 'knowledge-base/mcp-description.md', body('a'));
462
+ await held;
463
+ const b = svc.withPathTurn(workspaceId, 'knowledge-base/mcp-description.md', body('b'));
464
+ await Promise.all([a, b]);
442
465
 
443
466
  expect(order).toEqual(['a:enter', 'a:exit', 'b:enter', 'b:exit']);
444
467
  });
445
468
 
446
469
  it('treats two spellings of one file as one queue', async () => {
447
470
  const order: string[] = [];
448
- const body = (name: string) => async (): Promise<void> => {
449
- order.push(`${name}:enter`);
450
- await yieldTwice();
451
- order.push(`${name}:exit`);
452
- };
453
-
454
- // Warm the workspace lookup first: a turn chains onto the queue only after
455
- // it, and a COLD lookup resolves its three callers in disk order rather
456
- // than call order — the queue is one either way, but this asserts FIFO.
457
- await svc.withPathTurn(workspaceId, 'knowledge-base/mcp-description.md', async () => undefined);
471
+ const { body, held } = recorder(order);
458
472
 
473
+ const plain = svc.withPathTurn(workspaceId, 'knowledge-base/mcp-description.md', body('plain'));
474
+ await held;
475
+ // Issued together: they may join in either order, but each waits for
476
+ // `plain` and for each other, because all three name one file.
459
477
  await Promise.all([
460
- svc.withPathTurn(workspaceId, 'knowledge-base/mcp-description.md', body('plain')),
478
+ plain,
461
479
  svc.withPathTurn(workspaceId, './knowledge-base/mcp-description.md', body('dotted')),
462
480
  svc.withPathTurn(workspaceId, 'knowledge-base//mcp-description.md', body('doubled')),
463
481
  ]);
464
482
 
465
- expect(order).toEqual([
466
- 'plain:enter', 'plain:exit', 'dotted:enter', 'dotted:exit', 'doubled:enter', 'doubled:exit',
467
- ]);
483
+ expect(order.slice(0, 2)).toEqual(['plain:enter', 'plain:exit']);
484
+ expect(order).toHaveLength(6);
485
+ expectNoInterleaving(order, ['plain', 'dotted', 'doubled']);
468
486
  });
469
487
 
470
488
  it('lets another file run while one path is held: a turn is per file', async () => {
@@ -506,10 +524,16 @@ describe('WorkspaceService.withPathTurn', () => {
506
524
  svc.writeFile(workspaceId, rel, 'From B.', { expectedContent: '' }),
507
525
  ]),
508
526
  );
527
+ const [a] = results;
509
528
  expect(results.filter((r) => r.status === 'fulfilled')).toHaveLength(1);
510
529
  const refused = results.find((r) => r.status === 'rejected') as PromiseRejectedResult;
511
530
  expect(refused.reason).toMatchObject({ status: 409 });
512
- expect(await fs.readFile(path.join(workspaceDir, rel), 'utf-8')).toBe('From A.');
531
+ // Which of the two goes first is not promised (each resolves its path
532
+ // before it chains onto the held turn's tail); what is, is that the file
533
+ // holds the winner's text whole and the loser was refused.
534
+ expect(await fs.readFile(path.join(workspaceDir, rel), 'utf-8')).toBe(
535
+ a.status === 'fulfilled' ? 'From A.' : 'From B.',
536
+ );
513
537
  });
514
538
 
515
539
  it('updates the diff baseline inside the turn, in the order the mutations landed', async () => {
@@ -612,7 +636,7 @@ describe('WorkspaceService.assertContentMatches', () => {
612
636
  const seeded = await seedBranchWorkspace(root, 'target-company-state');
613
637
  workspaceDir = seeded.workspaceDir;
614
638
  workspaceId = seeded.workspaceId;
615
- svc = new WorkspaceService(root, 'https://github.com/Bevel-Software/knowledge-base.git', 'knowledge-base', new NodeFs());
639
+ svc = new WorkspaceService(root, 'https://github.com/Bevel-Software/knowledge-base.git', testKbContext(), new NodeFs());
616
640
  });
617
641
 
618
642
  afterEach(async () => {
@@ -657,7 +681,7 @@ describe('WorkspaceService.createFolderZip', () => {
657
681
  workspaceDir = seeded.workspaceDir;
658
682
  repoDir = path.join(workspaceDir, 'knowledge-base');
659
683
  workspaceId = seeded.workspaceId;
660
- svc = new WorkspaceService(root, 'https://github.com/Bevel-Software/knowledge-base.git', 'knowledge-base', new NodeFs());
684
+ svc = new WorkspaceService(root, 'https://github.com/Bevel-Software/knowledge-base.git', testKbContext(), new NodeFs());
661
685
  await svc.getWorkspacePath(workspaceId);
662
686
  });
663
687
 
@@ -813,7 +837,7 @@ describe('WorkspaceService — clone bootstrap & sibling reference', () => {
813
837
  });
814
838
 
815
839
  it('clones a branch on first bootstrap and checks out the right ref', async () => {
816
- const svc = new WorkspaceService(workspacesRoot, upstream, 'knowledge-base', new NodeFs());
840
+ const svc = new WorkspaceService(workspacesRoot, upstream, testKbContext(), new NodeFs());
817
841
  const info = await svc.getOrCreateForBranch('target-company-state');
818
842
 
819
843
  const repo = path.join(info.absolutePath, 'knowledge-base');
@@ -822,7 +846,7 @@ describe('WorkspaceService — clone bootstrap & sibling reference', () => {
822
846
  });
823
847
 
824
848
  it('uses an existing sibling clone as a --reference and stays dissociated', async () => {
825
- const svc = new WorkspaceService(workspacesRoot, upstream, 'knowledge-base', new NodeFs());
849
+ const svc = new WorkspaceService(workspacesRoot, upstream, testKbContext(), new NodeFs());
826
850
  // First branch: plain clone — becomes the sibling for the next bootstrap.
827
851
  await svc.getOrCreateForBranch('target-company-state');
828
852
  // Second branch: should borrow the first clone's objects, then dissociate.
@@ -850,7 +874,7 @@ describe('WorkspaceService — clone bootstrap & sibling reference', () => {
850
874
  // post-merge pull of a target branch. Every clone this service hands out must
851
875
  // therefore track exactly one upstream ref through exactly one refspec.
852
876
  it('stamps a single fetch refspec and upstream ref on a fresh clone', async () => {
853
- const svc = new WorkspaceService(workspacesRoot, upstream, 'knowledge-base', new NodeFs());
877
+ const svc = new WorkspaceService(workspacesRoot, upstream, testKbContext(), new NodeFs());
854
878
  const info = await svc.getOrCreateForBranch('target-company-state');
855
879
  const repo = path.join(info.absolutePath, 'knowledge-base');
856
880
 
@@ -874,7 +898,7 @@ describe('WorkspaceService — clone bootstrap & sibling reference', () => {
874
898
  await runGit(repo, ['config', '--add', 'remote.origin.fetch', '+refs/heads/*:refs/remotes/origin/*']);
875
899
  await runGit(repo, ['config', '--add', 'branch.alice/draft.merge', 'refs/heads/target-company-state']);
876
900
 
877
- const svc = new WorkspaceService(workspacesRoot, upstream, 'knowledge-base', new NodeFs());
901
+ const svc = new WorkspaceService(workspacesRoot, upstream, testKbContext(), new NodeFs());
878
902
  await svc.getOrCreateForBranch('alice/draft');
879
903
 
880
904
  expect(await gitOut(repo, ['config', '--get-all', 'remote.origin.fetch']))
@@ -886,7 +910,7 @@ describe('WorkspaceService — clone bootstrap & sibling reference', () => {
886
910
  });
887
911
 
888
912
  it('notifies the cloned-workspace listener with the workspace id after a clone', async () => {
889
- const svc = new WorkspaceService(workspacesRoot, upstream, 'knowledge-base', new NodeFs());
913
+ const svc = new WorkspaceService(workspacesRoot, upstream, testKbContext(), new NodeFs());
890
914
  const cloned: string[] = [];
891
915
  svc.setWorkspaceClonedListener((id) => cloned.push(id));
892
916
 
@@ -914,7 +938,7 @@ describe('WorkspaceService — symbolic links', () => {
914
938
  const seeded = await seedBranchWorkspace(root, 'main');
915
939
  workspaceDir = seeded.workspaceDir;
916
940
  workspaceId = seeded.workspaceId;
917
- svc = new WorkspaceService(root, 'https://github.com/Bevel-Software/knowledge-base.git', 'knowledge-base', new NodeFs());
941
+ svc = new WorkspaceService(root, 'https://github.com/Bevel-Software/knowledge-base.git', testKbContext(), new NodeFs());
918
942
  });
919
943
 
920
944
  afterEach(async () => {
@@ -999,7 +1023,7 @@ describe('WorkspaceService — symbolic links', () => {
999
1023
  // A mounted-volume shape: the whole workspaces root reached through a link.
1000
1024
  const mount = path.join(root, 'mount');
1001
1025
  await fs.symlink(root, mount, linkType);
1002
- const viaMount = new WorkspaceService(mount, 'https://github.com/Bevel-Software/knowledge-base.git', 'knowledge-base', new NodeFs());
1026
+ const viaMount = new WorkspaceService(mount, 'https://github.com/Bevel-Software/knowledge-base.git', testKbContext(), new NodeFs());
1003
1027
  expect(await viaMount.readFile(workspaceId, rel)).toBe('Hello.');
1004
1028
  await viaMount.writeFile(workspaceId, rel, 'Hello again.');
1005
1029
  expect(await fs.readFile(path.join(workspaceDir, rel), 'utf-8')).toBe('Hello again.');
@@ -1032,7 +1056,7 @@ describe('WorkspaceService.sweepOrphanedWorkspaces', () => {
1032
1056
 
1033
1057
  it('removes the clone of a branch that is not in the known set', async () => {
1034
1058
  const { workspaceId, workspaceDir } = await seedBranchWorkspace(root, 'target-company-state');
1035
- const svc = new WorkspaceService(root, 'https://github.com/Bevel-Software/knowledge-base.git', 'knowledge-base', new NodeFs());
1059
+ const svc = new WorkspaceService(root, 'https://github.com/Bevel-Software/knowledge-base.git', testKbContext(), new NodeFs());
1036
1060
  await svc.getOrCreateForBranch('target-company-state');
1037
1061
 
1038
1062
  // The branch vanishes from the known set; the sweep reclaims its clone.
@@ -1053,7 +1077,7 @@ describe('WorkspaceService.readAllKbFiles', () => {
1053
1077
  const seeded = await seedBranchWorkspace(root, 'target-company-state');
1054
1078
  repoRoot = path.join(seeded.workspaceDir, 'knowledge-base');
1055
1079
  workspaceId = seeded.workspaceId;
1056
- svc = new WorkspaceService(root, 'https://github.com/Bevel-Software/knowledge-base.git', 'knowledge-base', new NodeFs());
1080
+ svc = new WorkspaceService(root, 'https://github.com/Bevel-Software/knowledge-base.git', testKbContext(), new NodeFs());
1057
1081
  await svc.getWorkspacePath(workspaceId);
1058
1082
  });
1059
1083
 
@@ -1112,7 +1136,7 @@ describe('WorkspaceService.unzipFile — ontology-session write guard', () => {
1112
1136
  workspaceDir = seeded.workspaceDir;
1113
1137
  repoDir = path.join(workspaceDir, 'knowledge-base');
1114
1138
  workspaceId = seeded.workspaceId;
1115
- svc = new WorkspaceService(root, 'https://github.com/Bevel-Software/knowledge-base.git', 'knowledge-base', new NodeFs());
1139
+ svc = new WorkspaceService(root, 'https://github.com/Bevel-Software/knowledge-base.git', testKbContext(), new NodeFs());
1116
1140
  await svc.getWorkspacePath(workspaceId);
1117
1141
  });
1118
1142
 
@@ -1255,7 +1279,7 @@ describe('WorkspaceService — every operation resolves inside the repository',
1255
1279
  workspaceDir = seeded.workspaceDir;
1256
1280
  repoDir = path.join(workspaceDir, 'knowledge-base');
1257
1281
  workspaceId = seeded.workspaceId;
1258
- svc = new WorkspaceService(root, 'https://example.invalid/kb.git', 'knowledge-base', new NodeFs());
1282
+ svc = new WorkspaceService(root, 'https://example.invalid/kb.git', testKbContext(), new NodeFs());
1259
1283
  await svc.getWorkspacePath(workspaceId);
1260
1284
  });
1261
1285
 
@@ -1294,11 +1318,21 @@ describe('WorkspaceService — every operation resolves inside the repository',
1294
1318
  });
1295
1319
 
1296
1320
  it('takes its path and folder turns on the repository path, so two spellings are one queue', async () => {
1321
+ // The second spelling is issued only once the first HOLDS its turn. What
1322
+ // is asserted is the queue — the second waits for the first to finish —
1323
+ // not the order two calls enter it: before the queue each spelling is
1324
+ // judged against the git folder on disk, and those probes take as long as
1325
+ // the spelling makes them, so two calls issued together can chain in
1326
+ // either order (the FIFO case is pinned above, on warmed equal spellings).
1297
1327
  const order: string[] = [];
1328
+ let holding!: () => void;
1329
+ const held = new Promise<void>((r) => { holding = r; });
1298
1330
  const slow = svc.withPathTurn(workspaceId, 'contended.md', async () => {
1331
+ holding();
1299
1332
  await new Promise((r) => setTimeout(r, 20));
1300
1333
  order.push('first');
1301
1334
  });
1335
+ await held;
1302
1336
  const fast = svc.withPathTurn(workspaceId, 'knowledge-base/contended.md', async () => {
1303
1337
  order.push('second');
1304
1338
  });
@@ -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();