@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
@@ -21,10 +21,10 @@ import { defaultKbTemplateDir } from '../../../../../assets.js';
21
21
  import {
22
22
  DEFAULT_KB_LAYOUT,
23
23
  agentsFilePointerSentence,
24
- configureKbLayout,
25
24
  renderKbLayoutPlaceholders,
26
25
  } from '@bevel-software/platform-shared';
27
26
  import { PLATFORM_HEADER, TOOL_PREFIX_LINE, composeAgentInstructions } from '../../../../agent-instructions/index.js';
27
+ import { testKbContext } from '../../../../../__tests__/kb-context.js';
28
28
 
29
29
  const execFileAsync = promisify(execFile);
30
30
 
@@ -38,6 +38,13 @@ const execFileAsync = promisify(execFile);
38
38
  /** The real seed template shipped inside this package (see assets.ts). */
39
39
  const TEMPLATE_DIR = defaultKbTemplateDir();
40
40
 
41
+ /**
42
+ * The context every step under test reads its layout from. A case that needs
43
+ * other names applies them to it — as the completing setup save does on a
44
+ * fresh deployment — and `afterEach` puts the defaults back.
45
+ */
46
+ const kbContext = testKbContext();
47
+
41
48
  const PROTECTED = ['current-company-state', 'target-company-state'];
42
49
  const DEFAULT_BRANCH = 'current-company-state';
43
50
 
@@ -67,7 +74,7 @@ beforeEach(async () => {
67
74
 
68
75
  afterEach(async () => {
69
76
  vi.restoreAllMocks();
70
- configureKbLayout({ ...DEFAULT_KB_LAYOUT });
77
+ kbContext.applyLayout({ ...DEFAULT_KB_LAYOUT });
71
78
  await fs.rm(root, { recursive: true, force: true });
72
79
  });
73
80
 
@@ -102,7 +109,6 @@ function makeRunner(steps: OnServerStart[], templateDir: string = TEMPLATE_DIR)
102
109
  return new KbStartupRunner({
103
110
  gitRunner: new NodeGitRunner(),
104
111
  kbRepoUrl: () => upstream,
105
- gitUsername: () => 'x-access-token',
106
112
  workspacesRoot,
107
113
  kbDirName: 'knowledge-base',
108
114
  templateDir,
@@ -162,7 +168,7 @@ async function fullScaffold(): Promise<Record<string, string>> {
162
168
  describe('TemplateFilesStep', () => {
163
169
  it('adds the missing scaffolding — .gitignore arriving from its packable template spelling', async () => {
164
170
  await seedUpstream({ 'marker.txt': 'seeded' });
165
- await makeRunner([new TemplateFilesStep(new NodeFs())]).runAll();
171
+ await makeRunner([new TemplateFilesStep(new NodeFs(), kbContext)]).runAll();
166
172
 
167
173
  for (const b of PROTECTED) {
168
174
  const dir = await checkout(b);
@@ -188,9 +194,9 @@ describe('TemplateFilesStep', () => {
188
194
  it('renders the managed files with the deployment\'s own root names', async () => {
189
195
  // A deployment that renamed its roots must hand the agent a guide naming
190
196
  // the folders it will find, and an ignore file hiding the real ones.
191
- configureKbLayout({ knowledgeBaseDir: 'docs', skillsDir: 'skills', pluginsDir: 'plugins' });
197
+ kbContext.applyLayout({ knowledgeBaseDir: 'docs', skillsDir: 'skills', pluginsDir: 'plugins' });
192
198
  await seedUpstream({ 'marker.txt': 'seeded' });
193
- await makeRunner([new TemplateFilesStep(new NodeFs())]).runAll();
199
+ await makeRunner([new TemplateFilesStep(new NodeFs(), kbContext)]).runAll();
194
200
 
195
201
  const dir = await checkout(DEFAULT_BRANCH);
196
202
  const agents = norm(await fs.readFile(path.join(dir, 'AGENTS.md'), 'utf8'));
@@ -208,7 +214,7 @@ describe('TemplateFilesStep', () => {
208
214
  expect(await exists(dir, 'docs/.gitkeep')).toBe(true);
209
215
 
210
216
  // And a second boot sees the rendered guide as current: no churn commit.
211
- await makeRunner([new TemplateFilesStep(new NodeFs())]).runAll();
217
+ await makeRunner([new TemplateFilesStep(new NodeFs(), kbContext)]).runAll();
212
218
  const again = await checkout(DEFAULT_BRANCH);
213
219
  expect((await git(again, ['rev-list', '--count', 'HEAD'])).trim()).toBe('2'); // init + scaffolding
214
220
  });
@@ -223,9 +229,9 @@ describe('TemplateFilesStep', () => {
223
229
  * deployment's own root names rather than the placeholders.
224
230
  */
225
231
  it('writes the "Where a new file goes" placement rule, named for the deployment\'s roots', async () => {
226
- configureKbLayout({ knowledgeBaseDir: 'Docs', skillsDir: 'Abilities', pluginsDir: 'Extensions' });
232
+ kbContext.applyLayout({ knowledgeBaseDir: 'Docs', skillsDir: 'Abilities', pluginsDir: 'Extensions' });
227
233
  await seedUpstream({ 'marker.txt': 'seeded' });
228
- await makeRunner([new TemplateFilesStep(new NodeFs())]).runAll();
234
+ await makeRunner([new TemplateFilesStep(new NodeFs(), kbContext)]).runAll();
229
235
 
230
236
  const dir = await checkout(DEFAULT_BRANCH);
231
237
  const agents = norm(await fs.readFile(path.join(dir, 'AGENTS.md'), 'utf8'));
@@ -261,9 +267,9 @@ describe('TemplateFilesStep', () => {
261
267
  * `skills/` they had just chosen — the very bug the names exist to avoid.
262
268
  */
263
269
  it('scaffolds the layout in effect when it RUNS, not the one it was built under', async () => {
264
- const builtAtBoot = new TemplateFilesStep(new NodeFs());
270
+ const builtAtBoot = new TemplateFilesStep(new NodeFs(), kbContext);
265
271
  await seedUpstream({ 'skills/deploy/SKILL.md': '# deploy\n' });
266
- configureKbLayout({ knowledgeBaseDir: 'Docs', skillsDir: 'skills', pluginsDir: 'Plugins' });
272
+ kbContext.applyLayout({ knowledgeBaseDir: 'Docs', skillsDir: 'skills', pluginsDir: 'Plugins' });
267
273
  await makeRunner([builtAtBoot]).runAll();
268
274
 
269
275
  const dir = await checkout(DEFAULT_BRANCH);
@@ -283,7 +289,7 @@ describe('TemplateFilesStep', () => {
283
289
 
284
290
  it('replaces a drifted AGENTS.md, and says so when that is the only change', async () => {
285
291
  await seedUpstream({ ...(await fullScaffold()), 'AGENTS.md': 'stale conventions\n' });
286
- await makeRunner([new TemplateFilesStep(new NodeFs())]).runAll();
292
+ await makeRunner([new TemplateFilesStep(new NodeFs(), kbContext)]).runAll();
287
293
 
288
294
  const dir = await checkout(DEFAULT_BRANCH);
289
295
  expect(norm(await fs.readFile(path.join(dir, 'AGENTS.md'), 'utf8'))).toBe(norm(await template('AGENTS.md')));
@@ -305,7 +311,7 @@ describe('TemplateFilesStep', () => {
305
311
 
306
312
  // An existing deployment's AGENTS.md from before the guide existed.
307
313
  await seedUpstream({ ...(await fullScaffold()), 'AGENTS.md': guide.replace(section, '') });
308
- await makeRunner([new TemplateFilesStep(new NodeFs())]).runAll();
314
+ await makeRunner([new TemplateFilesStep(new NodeFs(), kbContext)]).runAll();
309
315
 
310
316
  const dir = await checkout(DEFAULT_BRANCH);
311
317
  expect(norm(await fs.readFile(path.join(dir, 'AGENTS.md'), 'utf8'))).toContain('**Agents never create roles.**');
@@ -351,7 +357,7 @@ describe('TemplateFilesStep', () => {
351
357
 
352
358
  // What the step writes — the file agents read through the MCP server — carries it.
353
359
  await seedUpstream({ ...(await fullScaffold()), 'AGENTS.md': guide.replace(section, '') });
354
- await makeRunner([new TemplateFilesStep(new NodeFs())]).runAll();
360
+ await makeRunner([new TemplateFilesStep(new NodeFs(), kbContext)]).runAll();
355
361
  const written = norm(await fs.readFile(path.join(await checkout(DEFAULT_BRANCH), 'AGENTS.md'), 'utf8'));
356
362
  expect(written).toContain('### Giving a role to a group');
357
363
  expect(written).toContain(example);
@@ -359,7 +365,7 @@ describe('TemplateFilesStep', () => {
359
365
 
360
366
  it('rejects the git folder — in any spelling — as a reserved root name', async () => {
361
367
  for (const bad of ['.git', '.GIT', '.Git', '.git.', '%2egit']) {
362
- expect(() => new TemplateFilesStep(new NodeFs(), [bad]), bad).toThrow(/must not name the git folder/);
368
+ expect(() => new TemplateFilesStep(new NodeFs(), kbContext, [bad]), bad).toThrow(/must not name the git folder/);
363
369
  }
364
370
  });
365
371
 
@@ -375,7 +381,7 @@ describe('TemplateFilesStep', () => {
375
381
  delete scaffold['.bevelignore']; // the one file the step will declare from the template
376
382
  await seedUpstream(scaffold);
377
383
 
378
- await makeRunner([new TemplateFilesStep(new NodeFs())], customTemplate).runAll();
384
+ await makeRunner([new TemplateFilesStep(new NodeFs(), kbContext)], customTemplate).runAll();
379
385
 
380
386
  const dir = await checkout(DEFAULT_BRANCH);
381
387
  const lines = norm(await fs.readFile(path.join(dir, '.bevelignore'), 'utf8')).split('\n').map((l) => l.trim());
@@ -395,14 +401,14 @@ describe('TemplateFilesStep', () => {
395
401
  '# mine\n.git/\nAGENTS.md\nPlugins/\n\n# Added by the platform: the conventions doc is not node content.\nSkills/\n';
396
402
  await seedUpstream(scaffold);
397
403
 
398
- await makeRunner([new TemplateFilesStep(new NodeFs())]).runAll();
404
+ await makeRunner([new TemplateFilesStep(new NodeFs(), kbContext)]).runAll();
399
405
 
400
406
  const dir = await checkout(DEFAULT_BRANCH);
401
407
  const text = norm(await fs.readFile(path.join(dir, '.bevelignore'), 'utf8'));
402
408
  // The plugins-root rule goes with it — the same sidebar draws that root now.
403
409
  expect(text).toBe('# mine\n.git/\nAGENTS.md\n' + PREAMBLE_IGNORE_BLOCK);
404
410
  // Idempotent: a second boot has nothing to change.
405
- await makeRunner([new TemplateFilesStep(new NodeFs())]).runAll();
411
+ await makeRunner([new TemplateFilesStep(new NodeFs(), kbContext)]).runAll();
406
412
  const again = await checkout(DEFAULT_BRANCH);
407
413
  expect(norm(await fs.readFile(path.join(again, '.bevelignore'), 'utf8'))).toBe(text);
408
414
  });
@@ -416,7 +422,7 @@ describe('TemplateFilesStep', () => {
416
422
  'AGENTS.md\nPlugins/\n# The shared-skills root is rendered by the Skills & Tools app, like Groups/.\nSkills/\n';
417
423
  await seedUpstream(scaffold);
418
424
 
419
- await makeRunner([new TemplateFilesStep(new NodeFs())]).runAll();
425
+ await makeRunner([new TemplateFilesStep(new NodeFs(), kbContext)]).runAll();
420
426
 
421
427
  const dir = await checkout(DEFAULT_BRANCH);
422
428
  expect(norm(await fs.readFile(path.join(dir, '.bevelignore'), 'utf8'))).toBe(
@@ -433,7 +439,7 @@ describe('TemplateFilesStep', () => {
433
439
  'AGENTS.md\nPlugins/\n# The shared-skills root is rendered by the Skills & Tools app, like My Plugins/.\nSkills/\n';
434
440
  await seedUpstream(scaffold);
435
441
 
436
- await makeRunner([new TemplateFilesStep(new NodeFs())]).runAll();
442
+ await makeRunner([new TemplateFilesStep(new NodeFs(), kbContext)]).runAll();
437
443
 
438
444
  const dir = await checkout(DEFAULT_BRANCH);
439
445
  expect(norm(await fs.readFile(path.join(dir, '.bevelignore'), 'utf8'))).toBe(
@@ -450,7 +456,7 @@ describe('TemplateFilesStep', () => {
450
456
  scaffold['.bevelignore'] = text;
451
457
  await seedUpstream(scaffold);
452
458
 
453
- await makeRunner([new TemplateFilesStep(new NodeFs())]).runAll();
459
+ await makeRunner([new TemplateFilesStep(new NodeFs(), kbContext)]).runAll();
454
460
 
455
461
  const dir = await checkout(DEFAULT_BRANCH);
456
462
  expect(norm(await fs.readFile(path.join(dir, '.bevelignore'), 'utf8'))).toBe(
@@ -463,7 +469,7 @@ describe('TemplateFilesStep', () => {
463
469
  scaffold['.bevelignore'] = 'AGENTS.md\n# I hide skills on purpose\nSkills/\n';
464
470
  await seedUpstream(scaffold);
465
471
 
466
- await makeRunner([new TemplateFilesStep(new NodeFs())]).runAll();
472
+ await makeRunner([new TemplateFilesStep(new NodeFs(), kbContext)]).runAll();
467
473
 
468
474
  const dir = await checkout(DEFAULT_BRANCH);
469
475
  expect(norm(await fs.readFile(path.join(dir, '.bevelignore'), 'utf8'))).toBe(
@@ -482,13 +488,13 @@ describe('TemplateFilesStep', () => {
482
488
  '# mine\nAGENTS.md\nPlugins/\nMy-Own-Rule/\n# Added by the platform: the conventions doc is not node content.\nPlugins/\n!Plugins/\n';
483
489
  await seedUpstream(scaffold);
484
490
 
485
- await makeRunner([new TemplateFilesStep(new NodeFs())]).runAll();
491
+ await makeRunner([new TemplateFilesStep(new NodeFs(), kbContext)]).runAll();
486
492
 
487
493
  const dir = await checkout(DEFAULT_BRANCH);
488
494
  const text = norm(await fs.readFile(path.join(dir, '.bevelignore'), 'utf8'));
489
495
  expect(text).toBe('# mine\nAGENTS.md\nMy-Own-Rule/\n!Plugins/\n' + PREAMBLE_IGNORE_BLOCK);
490
496
  // Idempotent: a second boot has nothing to change.
491
- await makeRunner([new TemplateFilesStep(new NodeFs())]).runAll();
497
+ await makeRunner([new TemplateFilesStep(new NodeFs(), kbContext)]).runAll();
492
498
  const again = await checkout(DEFAULT_BRANCH);
493
499
  expect(norm(await fs.readFile(path.join(again, '.bevelignore'), 'utf8'))).toBe(text);
494
500
  });
@@ -501,7 +507,7 @@ describe('TemplateFilesStep', () => {
501
507
  await fs.writeFile(path.join(customTemplate, '.bevelignore'), '.git/\nAGENTS.md\n\nPlugins/\n');
502
508
  await seedUpstream({ 'marker.txt': 'seeded' });
503
509
 
504
- await makeRunner([new TemplateFilesStep(new NodeFs())], customTemplate).runAll();
510
+ await makeRunner([new TemplateFilesStep(new NodeFs(), kbContext)], customTemplate).runAll();
505
511
 
506
512
  const dir = await checkout(DEFAULT_BRANCH);
507
513
  const lines = norm(await fs.readFile(path.join(dir, '.bevelignore'), 'utf8')).split('\n').map((l) => l.trim());
@@ -520,7 +526,7 @@ describe('TemplateFilesStep', () => {
520
526
 
521
527
  const dir = path.join(root, 'seeded-gitlink');
522
528
  await fs.mkdir(dir, { recursive: true });
523
- await buildSeedTree(new NodeFs(), customTemplate, [], ['admin@example.com'])(dir);
529
+ await buildSeedTree(new NodeFs(), customTemplate, [], ['admin@example.com'], kbContext)(dir);
524
530
 
525
531
  await expect(fs.readFile(path.join(dir, 'notes.md'), 'utf8')).rejects.toMatchObject({ code: 'ENOENT' });
526
532
  await expect(fs.readdir(path.join(dir, '.git'))).rejects.toMatchObject({ code: 'ENOENT' });
@@ -542,7 +548,7 @@ describe('TemplateFilesStep', () => {
542
548
  // The empty-remote seed is the one path that copies a whole template.
543
549
  const dir = path.join(root, 'seeded-bytes');
544
550
  await fs.mkdir(dir, { recursive: true });
545
- await buildSeedTree(new NodeFs(),customTemplate, [], ['admin@example.com'])(dir);
551
+ await buildSeedTree(new NodeFs(), customTemplate, [], ['admin@example.com'], kbContext)(dir);
546
552
 
547
553
  expect(await fs.readFile(path.join(dir, 'assets', '.logo.bin'))).toEqual(binary);
548
554
  expect(norm(await fs.readFile(path.join(dir, 'scripts', 'run.sh'), 'utf8'))).toBe('#!/bin/sh\necho Skills\n');
@@ -568,7 +574,7 @@ describe('TemplateFilesStep', () => {
568
574
  delete scaffold['.bevelignore'];
569
575
  await seedUpstream(scaffold);
570
576
 
571
- await makeRunner([new TemplateFilesStep(new NodeFs())], customTemplate).runAll();
577
+ await makeRunner([new TemplateFilesStep(new NodeFs(), kbContext)], customTemplate).runAll();
572
578
 
573
579
  const dir = await checkout(DEFAULT_BRANCH);
574
580
  const text = norm(await fs.readFile(path.join(dir, '.bevelignore'), 'utf8'));
@@ -582,7 +588,7 @@ describe('TemplateFilesStep', () => {
582
588
  scaffold['.bevelignore'] = 'AGENTS.md\n!Skills/\n';
583
589
  await seedUpstream(scaffold);
584
590
 
585
- await makeRunner([new TemplateFilesStep(new NodeFs())]).runAll();
591
+ await makeRunner([new TemplateFilesStep(new NodeFs(), kbContext)]).runAll();
586
592
 
587
593
  const dir = await checkout(DEFAULT_BRANCH);
588
594
  expect(norm(await fs.readFile(path.join(dir, '.bevelignore'), 'utf8'))).toBe(
@@ -597,7 +603,7 @@ describe('TemplateFilesStep', () => {
597
603
  scaffold['.bevelignore'] = '# operator wants the doc visible\n!AGENTS.md\nMyStuff/\n';
598
604
  await seedUpstream(scaffold);
599
605
 
600
- await makeRunner([new TemplateFilesStep(new NodeFs())]).runAll();
606
+ await makeRunner([new TemplateFilesStep(new NodeFs(), kbContext)]).runAll();
601
607
 
602
608
  const dir = await checkout(DEFAULT_BRANCH);
603
609
  expect(norm(await fs.readFile(path.join(dir, '.bevelignore'), 'utf8'))).toBe(
@@ -610,7 +616,7 @@ describe('TemplateFilesStep', () => {
610
616
  scaffold['.bevelignore'] = 'AGENTS.md\n!mcp-description.md\n';
611
617
  await seedUpstream(scaffold);
612
618
 
613
- await makeRunner([new TemplateFilesStep(new NodeFs())]).runAll();
619
+ await makeRunner([new TemplateFilesStep(new NodeFs(), kbContext)]).runAll();
614
620
 
615
621
  const dir = await checkout(DEFAULT_BRANCH);
616
622
  expect(norm(await fs.readFile(path.join(dir, '.bevelignore'), 'utf8'))).toBe(
@@ -627,14 +633,14 @@ describe('TemplateFilesStep', () => {
627
633
  'AGENTS.md\n# Added by the platform: agent instructions are edited from External agent access.\nmcp-description.md\n';
628
634
  await seedUpstream(scaffold);
629
635
 
630
- await makeRunner([new TemplateFilesStep(new NodeFs())]).runAll();
636
+ await makeRunner([new TemplateFilesStep(new NodeFs(), kbContext)]).runAll();
631
637
 
632
638
  const dir = await checkout(DEFAULT_BRANCH);
633
639
  expect(norm(await fs.readFile(path.join(dir, '.bevelignore'), 'utf8'))).toBe(
634
640
  'AGENTS.md\n# Added by the platform: agent instructions are edited from External agent access.\n/mcp-description.md\n',
635
641
  );
636
642
  // Idempotent: a second boot has nothing to change.
637
- await makeRunner([new TemplateFilesStep(new NodeFs())]).runAll();
643
+ await makeRunner([new TemplateFilesStep(new NodeFs(), kbContext)]).runAll();
638
644
  const again = await checkout(DEFAULT_BRANCH);
639
645
  expect(norm(await fs.readFile(path.join(again, '.bevelignore'), 'utf8'))).toBe(
640
646
  'AGENTS.md\n# Added by the platform: agent instructions are edited from External agent access.\n/mcp-description.md\n',
@@ -646,7 +652,7 @@ describe('TemplateFilesStep', () => {
646
652
  scaffold['.bevelignore'] = 'AGENTS.md\n# I hide it everywhere on purpose\nmcp-description.md\n';
647
653
  await seedUpstream(scaffold);
648
654
 
649
- await makeRunner([new TemplateFilesStep(new NodeFs())]).runAll();
655
+ await makeRunner([new TemplateFilesStep(new NodeFs(), kbContext)]).runAll();
650
656
 
651
657
  const dir = await checkout(DEFAULT_BRANCH);
652
658
  expect(norm(await fs.readFile(path.join(dir, '.bevelignore'), 'utf8'))).toBe(
@@ -658,7 +664,7 @@ describe('TemplateFilesStep', () => {
658
664
  const scaffold = await fullScaffold();
659
665
  delete scaffold['mcp-description.md'];
660
666
  await seedUpstream(scaffold);
661
- await makeRunner([new TemplateFilesStep(new NodeFs())]).runAll();
667
+ await makeRunner([new TemplateFilesStep(new NodeFs(), kbContext)]).runAll();
662
668
 
663
669
  for (const b of PROTECTED) {
664
670
  const dir = await checkout(b);
@@ -673,7 +679,7 @@ describe('TemplateFilesStep', () => {
673
679
  it('leaves an existing mcp-description.md untouched: seeded once, never refreshed', async () => {
674
680
  const mine = 'Acme builds solar farms.\n\n## What is where\n\n- Projects/\n';
675
681
  await seedUpstream({ ...(await fullScaffold()), 'mcp-description.md': mine });
676
- await makeRunner([new TemplateFilesStep(new NodeFs())]).runAll();
682
+ await makeRunner([new TemplateFilesStep(new NodeFs(), kbContext)]).runAll();
677
683
 
678
684
  const dir = await checkout(DEFAULT_BRANCH);
679
685
  expect(norm(await fs.readFile(path.join(dir, 'mcp-description.md'), 'utf8'))).toBe(mine);
@@ -682,7 +688,7 @@ describe('TemplateFilesStep', () => {
682
688
 
683
689
  it('keeps a deliberately emptied mcp-description.md empty: the top-up restores only a MISSING file', async () => {
684
690
  await seedUpstream({ ...(await fullScaffold()), 'mcp-description.md': '' });
685
- await makeRunner([new TemplateFilesStep(new NodeFs())]).runAll();
691
+ await makeRunner([new TemplateFilesStep(new NodeFs(), kbContext)]).runAll();
686
692
 
687
693
  const dir = await checkout(DEFAULT_BRANCH);
688
694
  expect(await fs.readFile(path.join(dir, 'mcp-description.md'), 'utf8')).toBe('');
@@ -718,7 +724,7 @@ describe('TemplateFilesStep', () => {
718
724
  await seedUpstream(scaffold);
719
725
  const warn = vi.spyOn(console, 'warn').mockImplementation(() => {});
720
726
 
721
- await makeRunner([new TemplateFilesStep(new NodeFs())], customTemplate).runAll();
727
+ await makeRunner([new TemplateFilesStep(new NodeFs(), kbContext)], customTemplate).runAll();
722
728
 
723
729
  const dir = await checkout(DEFAULT_BRANCH);
724
730
  expect(norm(await fs.readFile(path.join(dir, 'mcp-description.md'), 'utf8'))).toBe(
@@ -734,7 +740,7 @@ describe('TemplateFilesStep', () => {
734
740
  const scaffold = await fullScaffold();
735
741
  delete scaffold['access.md'];
736
742
  await seedUpstream(scaffold);
737
- await expect(makeRunner([new TemplateFilesStep(new NodeFs())], stricter).runAll()).rejects.toThrow(/ENOENT/);
743
+ await expect(makeRunner([new TemplateFilesStep(new NodeFs(), kbContext)], stricter).runAll()).rejects.toThrow(/ENOENT/);
738
744
  });
739
745
 
740
746
  it('points a clone at mcp-description.md from the managed AGENTS.md, before the platform mechanics', async () => {
@@ -749,7 +755,7 @@ describe('TemplateFilesStep', () => {
749
755
  const scaffold = await fullScaffold();
750
756
  scaffold['AGENTS.md'] = norm(scaffold['AGENTS.md']!).replace(/\n/g, '\r\n');
751
757
  await seedUpstream(scaffold);
752
- await makeRunner([new TemplateFilesStep(new NodeFs())]).runAll();
758
+ await makeRunner([new TemplateFilesStep(new NodeFs(), kbContext)]).runAll();
753
759
 
754
760
  const dir = await checkout(DEFAULT_BRANCH);
755
761
  expect((await git(dir, ['rev-list', '--count', 'HEAD'])).trim()).toBe('1'); // init only
@@ -770,9 +776,9 @@ describe('TemplateFilesStep', () => {
770
776
  const CUSTOMER_GUIDE = '# Acme conventions\n\nWrite tickets in the present tense.\n';
771
777
 
772
778
  it('writes and refreshes the guide under the configured name, on every protected branch', async () => {
773
- configureKbLayout({ ...DEFAULT_KB_LAYOUT, agentsFile: 'HEXIS.md' });
779
+ kbContext.applyLayout({ ...DEFAULT_KB_LAYOUT, agentsFile: 'HEXIS.md' });
774
780
  await seedUpstream({ 'marker.txt': 'seeded' });
775
- await makeRunner([new TemplateFilesStep(new NodeFs())]).runAll();
781
+ await makeRunner([new TemplateFilesStep(new NodeFs(), kbContext)]).runAll();
776
782
 
777
783
  for (const branch of PROTECTED) {
778
784
  const dir = await checkout(branch);
@@ -784,7 +790,7 @@ describe('TemplateFilesStep', () => {
784
790
  }
785
791
 
786
792
  // A second boot sees the rendered guide as current: no churn commit…
787
- await makeRunner([new TemplateFilesStep(new NodeFs())]).runAll();
793
+ await makeRunner([new TemplateFilesStep(new NodeFs(), kbContext)]).runAll();
788
794
  expect((await git(await checkout(DEFAULT_BRANCH), ['rev-list', '--count', 'HEAD'])).trim()).toBe('2');
789
795
 
790
796
  // …and a drifted copy is replaced, exactly as `AGENTS.md` is by default.
@@ -792,7 +798,7 @@ describe('TemplateFilesStep', () => {
792
798
  await fs.writeFile(path.join(dir, 'HEXIS.md'), 'stale conventions\n', 'utf8');
793
799
  await git(dir, ['commit', '-am', 'drift']);
794
800
  await git(dir, ['push', 'origin', DEFAULT_BRANCH]);
795
- await makeRunner([new TemplateFilesStep(new NodeFs())]).runAll();
801
+ await makeRunner([new TemplateFilesStep(new NodeFs(), kbContext)]).runAll();
796
802
  const after = await checkout(DEFAULT_BRANCH);
797
803
  expect(norm(await fs.readFile(path.join(after, 'HEXIS.md'), 'utf8'))).toContain('# Knowledge base');
798
804
  expect((await git(after, ['log', '--format=%s', '-1'])).trim()).toBe(
@@ -801,12 +807,12 @@ describe('TemplateFilesStep', () => {
801
807
  });
802
808
 
803
809
  it('leaves a customer AGENTS.md byte for byte alone, and shows it in the tree', async () => {
804
- configureKbLayout({ ...DEFAULT_KB_LAYOUT, agentsFile: 'HEXIS.md' });
810
+ kbContext.applyLayout({ ...DEFAULT_KB_LAYOUT, agentsFile: 'HEXIS.md' });
805
811
  // Their file already names the guide, so the pointer has nothing to add
806
812
  // — this test is about the bytes and the ignore rules alone.
807
813
  const theirs = `${CUSTOMER_GUIDE}\nSee HEXIS.md for the platform.\n`;
808
814
  await seedUpstream({ ...(await scaffoldWithoutGuide()), 'AGENTS.md': theirs });
809
- await makeRunner([new TemplateFilesStep(new NodeFs())]).runAll();
815
+ await makeRunner([new TemplateFilesStep(new NodeFs(), kbContext)]).runAll();
810
816
 
811
817
  const dir = await checkout(DEFAULT_BRANCH);
812
818
  expect(norm(await fs.readFile(path.join(dir, 'AGENTS.md'), 'utf8'))).toBe(theirs);
@@ -822,11 +828,11 @@ describe('TemplateFilesStep', () => {
822
828
  it('removes the platform-written AGENTS.md — only its own header proves it ours', async () => {
823
829
  // A knowledge base the platform seeded, whose admin then renames the guide.
824
830
  await seedUpstream({ 'marker.txt': 'seeded' });
825
- await makeRunner([new TemplateFilesStep(new NodeFs())]).runAll();
831
+ await makeRunner([new TemplateFilesStep(new NodeFs(), kbContext)]).runAll();
826
832
  expect(await exists(await checkout(DEFAULT_BRANCH), 'AGENTS.md')).toBe(true);
827
833
 
828
- configureKbLayout({ ...DEFAULT_KB_LAYOUT, agentsFile: 'HEXIS.md' });
829
- await makeRunner([new TemplateFilesStep(new NodeFs())]).runAll();
834
+ kbContext.applyLayout({ ...DEFAULT_KB_LAYOUT, agentsFile: 'HEXIS.md' });
835
+ await makeRunner([new TemplateFilesStep(new NodeFs(), kbContext)]).runAll();
830
836
 
831
837
  // On EVERY protected branch: the step tops up each one, and a rename
832
838
  // that only reached the default branch would leave the others carrying a
@@ -843,11 +849,11 @@ describe('TemplateFilesStep', () => {
843
849
  });
844
850
 
845
851
  it('keeps an AGENTS.md it cannot prove it wrote, and says so', async () => {
846
- configureKbLayout({ ...DEFAULT_KB_LAYOUT, agentsFile: 'HEXIS.md' });
852
+ kbContext.applyLayout({ ...DEFAULT_KB_LAYOUT, agentsFile: 'HEXIS.md' });
847
853
  // Edited by the customer: the managed header is gone, so it is theirs.
848
854
  const edited = `${CUSTOMER_GUIDE}\nMentions HEXIS.md already.\n`;
849
855
  await seedUpstream({ ...(await scaffoldWithoutGuide()), 'AGENTS.md': edited });
850
- await makeRunner([new TemplateFilesStep(new NodeFs())]).runAll();
856
+ await makeRunner([new TemplateFilesStep(new NodeFs(), kbContext)]).runAll();
851
857
 
852
858
  for (const branch of PROTECTED) {
853
859
  const dir = await checkout(branch);
@@ -860,7 +866,7 @@ describe('TemplateFilesStep', () => {
860
866
  // Following the link would read the managed header at the other end and
861
867
  // delete the customer's entry — or, with the pointer on, write our
862
868
  // sentence into a file nobody asked us to edit.
863
- configureKbLayout({ ...DEFAULT_KB_LAYOUT, agentsFile: 'HEXIS.md' });
869
+ kbContext.applyLayout({ ...DEFAULT_KB_LAYOUT, agentsFile: 'HEXIS.md' });
864
870
  await seedUpstream({ ...(await scaffoldWithoutGuide()), 'conventions/ours.md': await template('AGENTS.md') });
865
871
  // Committed as a link, so every checkout the step makes carries one.
866
872
  const seeding = await checkout(DEFAULT_BRANCH);
@@ -869,7 +875,7 @@ describe('TemplateFilesStep', () => {
869
875
  await git(seeding, ['commit', '-m', 'link AGENTS.md at our own file']);
870
876
  await git(seeding, ['push', 'origin', DEFAULT_BRANCH]);
871
877
 
872
- await makeRunner([new TemplateFilesStep(new NodeFs())]).runAll();
878
+ await makeRunner([new TemplateFilesStep(new NodeFs(), kbContext)]).runAll();
873
879
 
874
880
  const dir = await checkout(DEFAULT_BRANCH);
875
881
  expect((await fs.lstat(path.join(dir, 'AGENTS.md'))).isSymbolicLink()).toBe(true);
@@ -881,13 +887,13 @@ describe('TemplateFilesStep', () => {
881
887
  });
882
888
 
883
889
  it("keeps an operator's own AGENTS.md ignore rule while dropping the platform's", async () => {
884
- configureKbLayout({ ...DEFAULT_KB_LAYOUT, agentsFile: 'HEXIS.md' });
890
+ kbContext.applyLayout({ ...DEFAULT_KB_LAYOUT, agentsFile: 'HEXIS.md' });
885
891
  const scaffold = await scaffoldWithoutGuide();
886
892
  // Their own rule, written by hand, nowhere near the template's slot.
887
893
  scaffold['.bevelignore'] = '# mine\nAGENTS.md\nMyStuff/\n';
888
894
  scaffold['AGENTS.md'] = `${CUSTOMER_GUIDE}\nSee HEXIS.md.\n`;
889
895
  await seedUpstream(scaffold);
890
- await makeRunner([new TemplateFilesStep(new NodeFs())]).runAll();
896
+ await makeRunner([new TemplateFilesStep(new NodeFs(), kbContext)]).runAll();
891
897
 
892
898
  const text = norm(
893
899
  await fs.readFile(path.join(await checkout(DEFAULT_BRANCH), '.bevelignore'), 'utf8'),
@@ -897,7 +903,7 @@ describe('TemplateFilesStep', () => {
897
903
  });
898
904
 
899
905
  it("keeps an operator's rule that merely happens to sit under .gitattributes", async () => {
900
- configureKbLayout({ ...DEFAULT_KB_LAYOUT, agentsFile: 'HEXIS.md' });
906
+ kbContext.applyLayout({ ...DEFAULT_KB_LAYOUT, agentsFile: 'HEXIS.md' });
901
907
  const scaffold = await scaffoldWithoutGuide();
902
908
  // Hand-written, and by coincidence in the position the template's own
903
909
  // rule used to occupy. One matching line above is not provenance — the
@@ -905,7 +911,7 @@ describe('TemplateFilesStep', () => {
905
911
  scaffold['.bevelignore'] = '# ours\n.gitattributes\nAGENTS.md\nMyStuff/\n';
906
912
  scaffold['AGENTS.md'] = `${CUSTOMER_GUIDE}\nSee HEXIS.md.\n`;
907
913
  await seedUpstream(scaffold);
908
- await makeRunner([new TemplateFilesStep(new NodeFs())]).runAll();
914
+ await makeRunner([new TemplateFilesStep(new NodeFs(), kbContext)]).runAll();
909
915
 
910
916
  const text = norm(
911
917
  await fs.readFile(path.join(await checkout(DEFAULT_BRANCH), '.bevelignore'), 'utf8'),
@@ -915,7 +921,7 @@ describe('TemplateFilesStep', () => {
915
921
  });
916
922
 
917
923
  it("drops the bare rule an earlier release seeded in the template's hygiene block", async () => {
918
- configureKbLayout({ ...DEFAULT_KB_LAYOUT, agentsFile: 'HEXIS.md' });
924
+ kbContext.applyLayout({ ...DEFAULT_KB_LAYOUT, agentsFile: 'HEXIS.md' });
919
925
  const scaffold = await scaffoldWithoutGuide();
920
926
  // The `.bevelignore` of a knowledge base seeded before the rule had a
921
927
  // comment above it: bare, at the end of the template's own block.
@@ -924,7 +930,7 @@ describe('TemplateFilesStep', () => {
924
930
  '.gitignore\n.gitattributes\nAGENTS.md\nroles.yaml\n';
925
931
  scaffold['AGENTS.md'] = `${CUSTOMER_GUIDE}\nSee HEXIS.md.\n`;
926
932
  await seedUpstream(scaffold);
927
- await makeRunner([new TemplateFilesStep(new NodeFs())]).runAll();
933
+ await makeRunner([new TemplateFilesStep(new NodeFs(), kbContext)]).runAll();
928
934
 
929
935
  const lines = norm(
930
936
  await fs.readFile(path.join(await checkout(DEFAULT_BRANCH), '.bevelignore'), 'utf8'),
@@ -941,11 +947,11 @@ describe('TemplateFilesStep', () => {
941
947
  describe('the pointer in the customer\'s own AGENTS.md', () => {
942
948
  /** Boot once with the guide renamed, against a root `AGENTS.md` holding `theirs`. */
943
949
  async function bootWith(theirs: string | null, link = true): Promise<string> {
944
- configureKbLayout({ ...DEFAULT_KB_LAYOUT, agentsFile: 'HEXIS.md' });
950
+ kbContext.applyLayout({ ...DEFAULT_KB_LAYOUT, agentsFile: 'HEXIS.md' });
945
951
  const scaffold = await scaffoldWithoutGuide();
946
952
  if (theirs !== null) scaffold['AGENTS.md'] = theirs;
947
953
  await seedUpstream(scaffold);
948
- await makeRunner([new TemplateFilesStep(new NodeFs(), [], () => link)]).runAll();
954
+ await makeRunner([new TemplateFilesStep(new NodeFs(), kbContext, [], () => link)]).runAll();
949
955
  return checkout(DEFAULT_BRANCH);
950
956
  }
951
957
 
@@ -969,9 +975,9 @@ describe('TemplateFilesStep', () => {
969
975
  */
970
976
  it('appends once and only once, even when the name is nothing but punctuation', async () => {
971
977
  const guide = 'Our [Agent] Guide (v2).md';
972
- configureKbLayout({ ...DEFAULT_KB_LAYOUT, agentsFile: guide });
978
+ kbContext.applyLayout({ ...DEFAULT_KB_LAYOUT, agentsFile: guide });
973
979
  await seedUpstream({ ...(await scaffoldWithoutGuide()), 'AGENTS.md': CUSTOMER_GUIDE });
974
- const boot = () => makeRunner([new TemplateFilesStep(new NodeFs())]).runAll();
980
+ const boot = () => makeRunner([new TemplateFilesStep(new NodeFs(), kbContext)]).runAll();
975
981
 
976
982
  await boot();
977
983
  const once = norm(await fs.readFile(path.join(await checkout(DEFAULT_BRANCH), 'AGENTS.md'), 'utf8'));
@@ -994,16 +1000,16 @@ describe('TemplateFilesStep', () => {
994
1000
  * says no and an unaimed sentence would be joined by a second one.
995
1001
  */
996
1002
  it('aims the sentence it already wrote at the new guide, rather than adding another', async () => {
997
- configureKbLayout({ ...DEFAULT_KB_LAYOUT, agentsFile: 'HEXIS.md' });
1003
+ kbContext.applyLayout({ ...DEFAULT_KB_LAYOUT, agentsFile: 'HEXIS.md' });
998
1004
  await seedUpstream({ ...(await scaffoldWithoutGuide()), 'AGENTS.md': CUSTOMER_GUIDE });
999
- await makeRunner([new TemplateFilesStep(new NodeFs())]).runAll();
1005
+ await makeRunner([new TemplateFilesStep(new NodeFs(), kbContext)]).runAll();
1000
1006
  expect(norm(await fs.readFile(path.join(await checkout(DEFAULT_BRANCH), 'AGENTS.md'), 'utf8'))).toContain(
1001
1007
  agentsFilePointerSentence('HEXIS.md'),
1002
1008
  );
1003
1009
 
1004
1010
  // The admin renames the guide a second time.
1005
- configureKbLayout({ ...DEFAULT_KB_LAYOUT, agentsFile: 'GUIDE.md' });
1006
- await makeRunner([new TemplateFilesStep(new NodeFs())]).runAll();
1011
+ kbContext.applyLayout({ ...DEFAULT_KB_LAYOUT, agentsFile: 'GUIDE.md' });
1012
+ await makeRunner([new TemplateFilesStep(new NodeFs(), kbContext)]).runAll();
1007
1013
 
1008
1014
  const dir = await checkout(DEFAULT_BRANCH);
1009
1015
  const text = norm(await fs.readFile(path.join(dir, 'AGENTS.md'), 'utf8'));
@@ -1044,7 +1050,7 @@ describe('TemplateFilesStep', () => {
1044
1050
  // The default guide IS AGENTS.md, so the platform owns that file and
1045
1051
  // the pointer question never arises: the drifted copy is replaced.
1046
1052
  await seedUpstream({ ...(await fullScaffold()), 'AGENTS.md': theirs });
1047
- await makeRunner([new TemplateFilesStep(new NodeFs())]).runAll();
1053
+ await makeRunner([new TemplateFilesStep(new NodeFs(), kbContext)]).runAll();
1048
1054
  const dir = await checkout(DEFAULT_BRANCH);
1049
1055
  const text = norm(await fs.readFile(path.join(dir, 'AGENTS.md'), 'utf8'));
1050
1056
  expect(text).toBe(norm(await template('AGENTS.md')));
@@ -1057,7 +1063,7 @@ describe('TemplateFilesStep', () => {
1057
1063
  describe('RolesYamlStep', () => {
1058
1064
  it('generates roles.yaml with the configured admins on every protected branch', async () => {
1059
1065
  await seedUpstream({ 'marker.txt': 'seeded' });
1060
- await makeRunner([new RolesYamlStep(new NodeFs(), ['admin@example.com'])]).runAll();
1066
+ await makeRunner([new RolesYamlStep(new NodeFs(), ['admin@example.com'], kbContext)]).runAll();
1061
1067
 
1062
1068
  for (const b of PROTECTED) {
1063
1069
  const dir = await checkout(b);
@@ -1075,7 +1081,7 @@ describe('RolesYamlStep', () => {
1075
1081
  // skip-if-present check, reporting success over a KB whose access roster
1076
1082
  // cannot be read. Fail closed instead.
1077
1083
  await seedUpstream({ 'roles.yaml/placeholder.txt': 'squatter' });
1078
- await expect(makeRunner([new RolesYamlStep(new NodeFs(), ['admin@example.com'])]).runAll()).rejects.toThrow(
1084
+ await expect(makeRunner([new RolesYamlStep(new NodeFs(), ['admin@example.com'], kbContext)]).runAll()).rejects.toThrow(
1079
1085
  /"roles\.yaml" on branch "current-company-state" exists but is not a regular file \(directory\)/,
1080
1086
  );
1081
1087
  });
@@ -1129,7 +1135,7 @@ describe('buildSeedTree', () => {
1129
1135
 
1130
1136
  const dest = path.join(root, 'seed-dest');
1131
1137
  await fs.mkdir(dest, { recursive: true });
1132
- const generated = await buildSeedTree(new NodeFs(),templateDir, [], ['admin@example.com'])(dest);
1138
+ const generated = await buildSeedTree(new NodeFs(),templateDir, [], ['admin@example.com'], kbContext)(dest);
1133
1139
 
1134
1140
  expect(await exists(dest, '.git')).toBe(false);
1135
1141
  expect(await exists(dest, 'docs/.git')).toBe(false);
@@ -1145,9 +1151,9 @@ describe('buildSeedTree', () => {
1145
1151
  await fs.mkdir(templateDir, { recursive: true });
1146
1152
  await fs.writeFile(path.join(templateDir, 'access.md'), 'policy', 'utf8');
1147
1153
  // Composed at boot, under the defaults…
1148
- const seed = buildSeedTree(new NodeFs(), templateDir, [], ['admin@example.com']);
1154
+ const seed = buildSeedTree(new NodeFs(), templateDir, [], ['admin@example.com'], kbContext);
1149
1155
  // …and run after the completing save applied the admin's names.
1150
- configureKbLayout({ knowledgeBaseDir: 'Docs', skillsDir: 'skills', pluginsDir: 'Plugins' });
1156
+ kbContext.applyLayout({ knowledgeBaseDir: 'Docs', skillsDir: 'skills', pluginsDir: 'Plugins' });
1151
1157
  const dest = path.join(root, 'seed-dest-layout');
1152
1158
  await fs.mkdir(dest, { recursive: true });
1153
1159
  const generated = await seed(dest);
@@ -1161,10 +1167,10 @@ describe('buildSeedTree', () => {
1161
1167
  * things about a knowledge base nobody has used yet.
1162
1168
  */
1163
1169
  it('seeds the packaged guide under the configured name, and no AGENTS.md beside it', async () => {
1164
- configureKbLayout({ ...DEFAULT_KB_LAYOUT, agentsFile: 'HEXIS.md' });
1170
+ kbContext.applyLayout({ ...DEFAULT_KB_LAYOUT, agentsFile: 'HEXIS.md' });
1165
1171
  const dest = path.join(root, 'seed-dest-guide');
1166
1172
  await fs.mkdir(dest, { recursive: true });
1167
- await buildSeedTree(new NodeFs(), TEMPLATE_DIR, [], ['admin@example.com'])(dest);
1173
+ await buildSeedTree(new NodeFs(), TEMPLATE_DIR, [], ['admin@example.com'], kbContext)(dest);
1168
1174
  expect(await exists(dest, 'AGENTS.md')).toBe(false);
1169
1175
  const guide = norm(await fs.readFile(path.join(dest, 'HEXIS.md'), 'utf8'));
1170
1176
  expect(guide).toContain('`HEXIS.md`');
@@ -1186,10 +1192,10 @@ describe('buildSeedTree', () => {
1186
1192
  await fs.cp(TEMPLATE_DIR, customTemplate, { recursive: true });
1187
1193
  await fs.writeFile(path.join(customTemplate, 'HEXIS.md'), '# Not the platform guide\n', 'utf8');
1188
1194
 
1189
- configureKbLayout({ ...DEFAULT_KB_LAYOUT, agentsFile: 'HEXIS.md' });
1195
+ kbContext.applyLayout({ ...DEFAULT_KB_LAYOUT, agentsFile: 'HEXIS.md' });
1190
1196
  const dest = path.join(root, 'seed-dest-guide-clash');
1191
1197
  await fs.mkdir(dest, { recursive: true });
1192
- await buildSeedTree(new NodeFs(), customTemplate, [], ['admin@example.com'])(dest);
1198
+ await buildSeedTree(new NodeFs(), customTemplate, [], ['admin@example.com'], kbContext)(dest);
1193
1199
 
1194
1200
  const guide = norm(await fs.readFile(path.join(dest, 'HEXIS.md'), 'utf8'));
1195
1201
  expect(guide).toContain('`HEXIS.md`');
@@ -1200,7 +1206,7 @@ describe('buildSeedTree', () => {
1200
1206
  it('names a template that is not there — a missing directory is a broken build, not an empty seed', async () => {
1201
1207
  const dest = path.join(root, 'seed-dest-missing');
1202
1208
  await fs.mkdir(dest, { recursive: true });
1203
- await expect(buildSeedTree(new NodeFs(),path.join(root, 'no-such-template'), [], ['admin@example.com'])(dest)).rejects.toThrow(
1209
+ await expect(buildSeedTree(new NodeFs(),path.join(root, 'no-such-template'), [], ['admin@example.com'], kbContext)(dest)).rejects.toThrow(
1204
1210
  /KB template ".*no-such-template" is not a directory/,
1205
1211
  );
1206
1212
  });
@@ -1216,7 +1222,7 @@ describe('buildSeedTree', () => {
1216
1222
 
1217
1223
  const dest = path.join(root, 'seed-dest-links');
1218
1224
  await fs.mkdir(dest, { recursive: true });
1219
- await buildSeedTree(new NodeFs(),templateDir, [], ['admin@example.com'])(dest);
1225
+ await buildSeedTree(new NodeFs(),templateDir, [], ['admin@example.com'], kbContext)(dest);
1220
1226
  // The link's CONTENT, under the link's own name, as a real file.
1221
1227
  expect(await fs.readFile(path.join(dest, 'docs/linked.md'), 'utf8')).toBe('shared');
1222
1228
  expect((await fs.lstat(path.join(dest, 'docs/linked.md'))).isSymbolicLink()).toBe(false);
@@ -1225,7 +1231,7 @@ describe('buildSeedTree', () => {
1225
1231
  await fs.symlink(path.join(root, 'nowhere.md'), path.join(templateDir, 'dangling.md'), 'file');
1226
1232
  const dest2 = path.join(root, 'seed-dest-links-2');
1227
1233
  await fs.mkdir(dest2, { recursive: true });
1228
- await expect(buildSeedTree(new NodeFs(),templateDir, [], ['admin@example.com'])(dest2)).rejects.toThrow(
1234
+ await expect(buildSeedTree(new NodeFs(),templateDir, [], ['admin@example.com'], kbContext)(dest2)).rejects.toThrow(
1229
1235
  /KB template entry "dangling.md" links to nothing/,
1230
1236
  );
1231
1237
  // …and so is a link to a folder, named for what it is.
@@ -1233,7 +1239,7 @@ describe('buildSeedTree', () => {
1233
1239
  await fs.symlink(elsewhere, path.join(templateDir, 'dirlink'), process.platform === 'win32' ? 'junction' : 'dir');
1234
1240
  const dest3 = path.join(root, 'seed-dest-links-3');
1235
1241
  await fs.mkdir(dest3, { recursive: true });
1236
- await expect(buildSeedTree(new NodeFs(),templateDir, [], ['admin@example.com'])(dest3)).rejects.toThrow(
1242
+ await expect(buildSeedTree(new NodeFs(),templateDir, [], ['admin@example.com'], kbContext)(dest3)).rejects.toThrow(
1237
1243
  /KB template entry "dirlink" links to a directory/,
1238
1244
  );
1239
1245
  });
@@ -1251,7 +1257,7 @@ describe('buildSeedTree', () => {
1251
1257
 
1252
1258
  const dest = path.join(root, 'proto-dest');
1253
1259
  await fs.mkdir(dest, { recursive: true });
1254
- await buildSeedTree(new NodeFs(), templateDir, [], ['admin@example.com'])(dest);
1260
+ await buildSeedTree(new NodeFs(), templateDir, [], ['admin@example.com'], kbContext)(dest);
1255
1261
  expect(await fs.readFile(path.join(dest, 'constructor'), 'utf8')).toBe('not a function');
1256
1262
  expect(await fs.readFile(path.join(dest, 'toString'), 'utf8')).toBe('nor this');
1257
1263
  });
@@ -1283,7 +1289,7 @@ describe('PluginManifestsStep', () => {
1283
1289
  'Plugins/deps/node_modules/some-pkg/SKILL.md': '---\ndescription: z\n---\n',
1284
1290
  });
1285
1291
 
1286
- await makeRunner([new PluginManifestsStep(new NodeFs())]).runAll();
1292
+ await makeRunner([new PluginManifestsStep(new NodeFs(), kbContext)]).runAll();
1287
1293
 
1288
1294
  for (const branch of PROTECTED) {
1289
1295
  const dir = await checkout(branch);
@@ -1302,7 +1308,7 @@ describe('PluginManifestsStep', () => {
1302
1308
  expect(log).toContain('Plugins/GTM: plugin.json written');
1303
1309
 
1304
1310
  // Idempotent: nothing left to write on the next boot.
1305
- await makeRunner([new PluginManifestsStep(new NodeFs())]).runAll();
1311
+ await makeRunner([new PluginManifestsStep(new NodeFs(), kbContext)]).runAll();
1306
1312
  const again = await checkout(DEFAULT_BRANCH);
1307
1313
  expect((await git(again, ['rev-list', '--count', 'HEAD'])).trim()).toBe('2'); // init + one migration commit
1308
1314
  });
@@ -1337,7 +1343,7 @@ describe('PluginDisplayNamesStep', () => {
1337
1343
  'Plugins/functional/cluster/example/plugin.bundle.json': '{"name":"example"}',
1338
1344
  });
1339
1345
 
1340
- await makeRunner([new PluginDisplayNamesStep(new NodeFs())]).runAll();
1346
+ await makeRunner([new PluginDisplayNamesStep(new NodeFs(), kbContext)]).runAll();
1341
1347
 
1342
1348
  for (const branch of PROTECTED) {
1343
1349
  const dir = await checkout(branch);
@@ -1369,7 +1375,7 @@ describe('PluginDisplayNamesStep', () => {
1369
1375
  expect(log).toContain('Plugins/Sales Team: displayName "Sales Team"');
1370
1376
 
1371
1377
  // Idempotent: every manifest it would touch now carries the field.
1372
- await makeRunner([new PluginDisplayNamesStep(new NodeFs())]).runAll();
1378
+ await makeRunner([new PluginDisplayNamesStep(new NodeFs(), kbContext)]).runAll();
1373
1379
  const again = await checkout(DEFAULT_BRANCH);
1374
1380
  expect((await git(again, ['rev-list', '--count', 'HEAD'])).trim()).toBe('2'); // init + one backfill commit
1375
1381
  });
@@ -1406,7 +1412,7 @@ describe('PluginDisplayNamesStep', () => {
1406
1412
  { 'Plugins/Kit Pro/plugin.json': '../../vendor-manifest.json' },
1407
1413
  );
1408
1414
 
1409
- await makeRunner([new PluginDisplayNamesStep(new NodeFs())]).runAll();
1415
+ await makeRunner([new PluginDisplayNamesStep(new NodeFs(), kbContext)]).runAll();
1410
1416
 
1411
1417
  const dir = await checkout(DEFAULT_BRANCH);
1412
1418
  expect(await readJson(dir, 'Plugins/Growth Team/plugin.json')).toEqual({
@@ -1428,7 +1434,7 @@ describe('PluginDisplayNamesStep', () => {
1428
1434
  expect(log).not.toContain('Kit Pro');
1429
1435
 
1430
1436
  // Idempotent over all of it: the next boot finds nothing to write.
1431
- await makeRunner([new PluginDisplayNamesStep(new NodeFs())]).runAll();
1437
+ await makeRunner([new PluginDisplayNamesStep(new NodeFs(), kbContext)]).runAll();
1432
1438
  const again = await checkout(DEFAULT_BRANCH);
1433
1439
  expect((await git(again, ['rev-list', '--count', 'HEAD'])).trim()).toBe('2'); // init + one backfill commit
1434
1440
  });
@@ -1442,7 +1448,7 @@ describe('PluginDisplayNamesStep', () => {
1442
1448
  'Plugins/Sales Team/access.md': '---\n---\nread:\n - everyone\n',
1443
1449
  });
1444
1450
 
1445
- await makeRunner([new PluginManifestsStep(new NodeFs()), new PluginDisplayNamesStep(new NodeFs())]).runAll();
1451
+ await makeRunner([new PluginManifestsStep(new NodeFs(), kbContext), new PluginDisplayNamesStep(new NodeFs(), kbContext)]).runAll();
1446
1452
 
1447
1453
  const dir = await checkout(DEFAULT_BRANCH);
1448
1454
  expect(await readJson(dir, 'Plugins/Sales Team/plugin.json')).toEqual({
@@ -1500,7 +1506,7 @@ describe('PersonalSpacesStep', () => {
1500
1506
  await git(seed, ['checkout', '-b', 'ali/draft']);
1501
1507
  await git(seed, ['push', 'origin', 'ali/draft']);
1502
1508
 
1503
- await makeRunner([new PersonalSpacesStep(new NodeFs())]).runAll();
1509
+ await makeRunner([new PersonalSpacesStep(new NodeFs(), kbContext)]).runAll();
1504
1510
 
1505
1511
  for (const branch of [...PROTECTED, 'ali/draft']) {
1506
1512
  const dir = await checkout(branch);
@@ -1556,7 +1562,7 @@ describe('PersonalSpacesStep', () => {
1556
1562
  expect(log).toContain('Plugins/personal-u5/access.md: read denies everyone');
1557
1563
 
1558
1564
  // Idempotent: the next boot finds every space already closed.
1559
- await makeRunner([new PersonalSpacesStep(new NodeFs())]).runAll();
1565
+ await makeRunner([new PersonalSpacesStep(new NodeFs(), kbContext)]).runAll();
1560
1566
  const again = await checkout(DEFAULT_BRANCH);
1561
1567
  expect((await git(again, ['rev-list', '--count', 'HEAD'])).trim()).toBe('2');
1562
1568
  });
@@ -1585,7 +1591,7 @@ describe('GroupsToPluginsStep', () => {
1585
1591
  await git(seed, ['checkout', '-b', 'alice/draft']);
1586
1592
  await git(seed, ['push', 'origin', 'alice/draft']);
1587
1593
 
1588
- await makeRunner([new GroupsToPluginsStep(new NodeFs())]).runAll();
1594
+ await makeRunner([new GroupsToPluginsStep(new NodeFs(), kbContext)]).runAll();
1589
1595
 
1590
1596
  for (const b of [DEFAULT_BRANCH, 'alice/draft']) {
1591
1597
  const dir = await checkout(b);
@@ -1620,7 +1626,7 @@ describe('GroupsToPluginsStep', () => {
1620
1626
  // silently skipping a branch whose reserved root cannot be a plugin tree
1621
1627
  // (and on a draft nothing later would ever report it).
1622
1628
  await seedUpstream({ Plugins: 'i am a file, not a folder' });
1623
- await expect(makeRunner([new GroupsToPluginsStep(new NodeFs())]).runAll()).rejects.toThrow(
1629
+ await expect(makeRunner([new GroupsToPluginsStep(new NodeFs(), kbContext)]).runAll()).rejects.toThrow(
1624
1630
  /"Plugins" exists but is not a directory/,
1625
1631
  );
1626
1632
  });
@@ -1632,7 +1638,7 @@ describe('GroupsToPluginsStep', () => {
1632
1638
  'Plugins/B/y.md': 'new',
1633
1639
  });
1634
1640
  await makeRunner([
1635
- new GroupsToPluginsStep(new NodeFs()),
1641
+ new GroupsToPluginsStep(new NodeFs(), kbContext),
1636
1642
  // A later step dirties the branch so the refusal note surfaces in the commit.
1637
1643
  step('dirty', async (ctx) => {
1638
1644
  for (const b of await ctx.protectedBranches()) {
@@ -1662,7 +1668,7 @@ describe('GroupsToPluginsStep', () => {
1662
1668
  */
1663
1669
  describe('GroupsToPluginsStep — migration edge cases', () => {
1664
1670
  async function migrate(): Promise<void> {
1665
- await makeRunner([new GroupsToPluginsStep(new NodeFs())]).runAll();
1671
+ await makeRunner([new GroupsToPluginsStep(new NodeFs(), kbContext)]).runAll();
1666
1672
  }
1667
1673
 
1668
1674
  /** What the runner's `partial` warning carried — the named refusals. */
@@ -1976,9 +1982,9 @@ describe('GroupsToPluginsStep — migration edge cases', () => {
1976
1982
  */
1977
1983
  describe('TemplateFilesStep: a guide named with gitignore syntax', () => {
1978
1984
  it('escapes the name in the ignore rule it writes, and keeps it escaped on the next boot', async () => {
1979
- configureKbLayout({ ...DEFAULT_KB_LAYOUT, agentsFile: '#Guide[1].md' });
1985
+ kbContext.applyLayout({ ...DEFAULT_KB_LAYOUT, agentsFile: '#Guide[1].md' });
1980
1986
  await seedUpstream({ 'marker.txt': 'seeded' });
1981
- await makeRunner([new TemplateFilesStep(new NodeFs())]).runAll();
1987
+ await makeRunner([new TemplateFilesStep(new NodeFs(), kbContext)]).runAll();
1982
1988
  const dir = await checkout(DEFAULT_BRANCH);
1983
1989
  const ignore = norm(await fs.readFile(path.join(dir, '.bevelignore'), 'utf8')).split('\n').map((l) => l.trim());
1984
1990
  const escaped = String.raw`\#Guide\[1\].md`;
@@ -1986,7 +1992,7 @@ describe('TemplateFilesStep: a guide named with gitignore syntax', () => {
1986
1992
  expect(ignore).not.toContain('#Guide[1].md');
1987
1993
  expect(await exists(dir, '#Guide[1].md')).toBe(true);
1988
1994
  // A second boot sees the escaped rule as present and adds no second line.
1989
- await makeRunner([new TemplateFilesStep(new NodeFs())]).runAll();
1995
+ await makeRunner([new TemplateFilesStep(new NodeFs(), kbContext)]).runAll();
1990
1996
  const again = norm(await fs.readFile(path.join(await checkout(DEFAULT_BRANCH), '.bevelignore'), 'utf8'));
1991
1997
  expect(again.split('\n').filter((l) => l.trim() === escaped)).toHaveLength(1);
1992
1998
  });