@bevel-software/platform-core-backend 0.15.1 → 0.19.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 (1220) hide show
  1. package/THIRD-PARTY-NOTICES.md +4 -4
  2. package/dist/core/catalog-cache-invalidation.d.ts +16 -0
  3. package/dist/core/catalog-cache-invalidation.d.ts.map +1 -1
  4. package/dist/core/catalog-cache-invalidation.js +6 -1
  5. package/dist/core/catalog-cache-invalidation.js.map +1 -1
  6. package/dist/core/catalog-revision.d.ts +39 -0
  7. package/dist/core/catalog-revision.d.ts.map +1 -0
  8. package/dist/core/catalog-revision.js +94 -0
  9. package/dist/core/catalog-revision.js.map +1 -0
  10. package/dist/core/create-core-server.d.ts +7 -0
  11. package/dist/core/create-core-server.d.ts.map +1 -1
  12. package/dist/core/create-core-server.js +199 -75
  13. package/dist/core/create-core-server.js.map +1 -1
  14. package/dist/core/create-core-services.d.ts +49 -2
  15. package/dist/core/create-core-services.d.ts.map +1 -1
  16. package/dist/core/create-core-services.js +212 -86
  17. package/dist/core/create-core-services.js.map +1 -1
  18. package/dist/core/lifecycle.d.ts +138 -0
  19. package/dist/core/lifecycle.d.ts.map +1 -0
  20. package/dist/core/lifecycle.js +218 -0
  21. package/dist/core/lifecycle.js.map +1 -0
  22. package/dist/core/public-config.d.ts +82 -0
  23. package/dist/core/public-config.d.ts.map +1 -0
  24. package/dist/core/public-config.js +78 -0
  25. package/dist/core/public-config.js.map +1 -0
  26. package/dist/core/readiness.d.ts +86 -0
  27. package/dist/core/readiness.d.ts.map +1 -0
  28. package/dist/core/readiness.js +56 -0
  29. package/dist/core/readiness.js.map +1 -0
  30. package/dist/core-config.d.ts +30 -0
  31. package/dist/core-config.d.ts.map +1 -1
  32. package/dist/core-config.js +64 -2
  33. package/dist/core-config.js.map +1 -1
  34. package/dist/index.d.ts +4 -1
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +6 -0
  37. package/dist/index.js.map +1 -1
  38. package/dist/modules/access/access-control.interface.d.ts +215 -11
  39. package/dist/modules/access/access-control.interface.d.ts.map +1 -1
  40. package/dist/modules/access/access-control.service.d.ts +57 -11
  41. package/dist/modules/access/access-control.service.d.ts.map +1 -1
  42. package/dist/modules/access/access-control.service.js +616 -155
  43. package/dist/modules/access/access-control.service.js.map +1 -1
  44. package/dist/modules/access/access-mutation.service.d.ts +71 -5
  45. package/dist/modules/access/access-mutation.service.d.ts.map +1 -1
  46. package/dist/modules/access/access-mutation.service.js +161 -13
  47. package/dist/modules/access/access-mutation.service.js.map +1 -1
  48. package/dist/modules/access/access-view.d.ts +147 -0
  49. package/dist/modules/access/access-view.d.ts.map +1 -0
  50. package/dist/modules/access/access-view.js +211 -0
  51. package/dist/modules/access/access-view.js.map +1 -0
  52. package/dist/modules/access/access.routes.d.ts.map +1 -1
  53. package/dist/modules/access/access.routes.js +255 -79
  54. package/dist/modules/access/access.routes.js.map +1 -1
  55. package/dist/modules/access/admin-locked-commit.d.ts +2 -3
  56. package/dist/modules/access/admin-locked-commit.d.ts.map +1 -1
  57. package/dist/modules/access/admin-locked-commit.js +9 -8
  58. package/dist/modules/access/admin-locked-commit.js.map +1 -1
  59. package/dist/modules/access/admin-route-helpers.d.ts.map +1 -1
  60. package/dist/modules/access/admin-route-helpers.js +4 -4
  61. package/dist/modules/access/admin-route-helpers.js.map +1 -1
  62. package/dist/modules/access/change-read-gate.d.ts +53 -0
  63. package/dist/modules/access/change-read-gate.d.ts.map +1 -0
  64. package/dist/modules/access/change-read-gate.js +134 -0
  65. package/dist/modules/access/change-read-gate.js.map +1 -0
  66. package/dist/modules/access/creator-access.d.ts +33 -39
  67. package/dist/modules/access/creator-access.d.ts.map +1 -1
  68. package/dist/modules/access/creator-access.js +92 -119
  69. package/dist/modules/access/creator-access.js.map +1 -1
  70. package/dist/modules/access/directory-sync-bot.d.ts.map +1 -1
  71. package/dist/modules/access/directory-sync-bot.js +3 -1
  72. package/dist/modules/access/directory-sync-bot.js.map +1 -1
  73. package/dist/modules/access/groups-admin.service.d.ts +3 -3
  74. package/dist/modules/access/groups-admin.service.js +2 -2
  75. package/dist/modules/access/reference-scan.d.ts +1 -1
  76. package/dist/modules/access/reference-scan.d.ts.map +1 -1
  77. package/dist/modules/access/reference-scan.js +5 -4
  78. package/dist/modules/access/reference-scan.js.map +1 -1
  79. package/dist/modules/access/roles-admin.service.d.ts +72 -13
  80. package/dist/modules/access/roles-admin.service.d.ts.map +1 -1
  81. package/dist/modules/access/roles-admin.service.js +71 -13
  82. package/dist/modules/access/roles-admin.service.js.map +1 -1
  83. package/dist/modules/access/synced-groups-committer.d.ts.map +1 -1
  84. package/dist/modules/access/synced-groups-committer.js +8 -6
  85. package/dist/modules/access/synced-groups-committer.js.map +1 -1
  86. package/dist/modules/access/synced-groups-writer.d.ts.map +1 -1
  87. package/dist/modules/access/synced-groups-writer.js +3 -8
  88. package/dist/modules/access/synced-groups-writer.js.map +1 -1
  89. package/dist/modules/access/user-access-removal.service.d.ts +209 -0
  90. package/dist/modules/access/user-access-removal.service.d.ts.map +1 -0
  91. package/dist/modules/access/user-access-removal.service.js +662 -0
  92. package/dist/modules/access/user-access-removal.service.js.map +1 -0
  93. package/dist/modules/access-model/access-errors.d.ts +32 -1
  94. package/dist/modules/access-model/access-errors.d.ts.map +1 -1
  95. package/dist/modules/access-model/access-errors.js +38 -11
  96. package/dist/modules/access-model/access-errors.js.map +1 -1
  97. package/dist/modules/access-model/access-grammar.d.ts +49 -24
  98. package/dist/modules/access-model/access-grammar.d.ts.map +1 -1
  99. package/dist/modules/access-model/access-grammar.js +68 -48
  100. package/dist/modules/access-model/access-grammar.js.map +1 -1
  101. package/dist/modules/access-model/access-splice.d.ts.map +1 -1
  102. package/dist/modules/access-model/access-splice.js +18 -18
  103. package/dist/modules/access-model/access-splice.js.map +1 -1
  104. package/dist/modules/access-model/access-template.d.ts +22 -0
  105. package/dist/modules/access-model/access-template.d.ts.map +1 -0
  106. package/dist/modules/access-model/access-template.js +42 -0
  107. package/dist/modules/access-model/access-template.js.map +1 -0
  108. package/dist/modules/access-model/change-gate.d.ts +65 -0
  109. package/dist/modules/access-model/change-gate.d.ts.map +1 -0
  110. package/dist/modules/access-model/change-gate.js +25 -0
  111. package/dist/modules/access-model/change-gate.js.map +1 -0
  112. package/dist/modules/access-model/creator.d.ts +13 -16
  113. package/dist/modules/access-model/creator.d.ts.map +1 -1
  114. package/dist/modules/access-model/creator.js.map +1 -1
  115. package/dist/modules/access-model/frontmatter-lines.d.ts +27 -0
  116. package/dist/modules/access-model/frontmatter-lines.d.ts.map +1 -0
  117. package/dist/modules/access-model/frontmatter-lines.js +74 -0
  118. package/dist/modules/access-model/frontmatter-lines.js.map +1 -0
  119. package/dist/modules/access-model/plugin-principals.d.ts +5 -3
  120. package/dist/modules/access-model/plugin-principals.d.ts.map +1 -1
  121. package/dist/modules/access-model/plugin-principals.js +11 -17
  122. package/dist/modules/access-model/plugin-principals.js.map +1 -1
  123. package/dist/modules/access-model/roles-yaml-guard.d.ts +73 -2
  124. package/dist/modules/access-model/roles-yaml-guard.d.ts.map +1 -1
  125. package/dist/modules/access-model/roles-yaml-guard.js +153 -3
  126. package/dist/modules/access-model/roles-yaml-guard.js.map +1 -1
  127. package/dist/modules/admin/admin-access.service.d.ts.map +1 -1
  128. package/dist/modules/admin/admin-access.service.js +5 -2
  129. package/dist/modules/admin/admin-access.service.js.map +1 -1
  130. package/dist/modules/agent-instructions/agent-instructions.routes.d.ts +21 -0
  131. package/dist/modules/agent-instructions/agent-instructions.routes.d.ts.map +1 -0
  132. package/dist/modules/agent-instructions/agent-instructions.routes.js +38 -0
  133. package/dist/modules/agent-instructions/agent-instructions.routes.js.map +1 -0
  134. package/dist/modules/agent-instructions/compose.d.ts +71 -0
  135. package/dist/modules/agent-instructions/compose.d.ts.map +1 -0
  136. package/dist/modules/agent-instructions/compose.js +234 -0
  137. package/dist/modules/agent-instructions/compose.js.map +1 -0
  138. package/dist/modules/agent-instructions/index.d.ts +4 -0
  139. package/dist/modules/agent-instructions/index.d.ts.map +1 -0
  140. package/dist/modules/agent-instructions/index.js +4 -0
  141. package/dist/modules/agent-instructions/index.js.map +1 -0
  142. package/dist/modules/agent-instructions/read-preamble.d.ts +37 -0
  143. package/dist/modules/agent-instructions/read-preamble.d.ts.map +1 -0
  144. package/dist/modules/agent-instructions/read-preamble.js +81 -0
  145. package/dist/modules/agent-instructions/read-preamble.js.map +1 -0
  146. package/dist/modules/auth/account-erasure.service.d.ts +30 -4
  147. package/dist/modules/auth/account-erasure.service.d.ts.map +1 -1
  148. package/dist/modules/auth/account-erasure.service.js +96 -10
  149. package/dist/modules/auth/account-erasure.service.js.map +1 -1
  150. package/dist/modules/auth/account.routes.d.ts +6 -3
  151. package/dist/modules/auth/account.routes.d.ts.map +1 -1
  152. package/dist/modules/auth/account.routes.js +109 -10
  153. package/dist/modules/auth/account.routes.js.map +1 -1
  154. package/dist/modules/auth/auth.routes.d.ts +10 -3
  155. package/dist/modules/auth/auth.routes.d.ts.map +1 -1
  156. package/dist/modules/auth/auth.routes.js +9 -4
  157. package/dist/modules/auth/auth.routes.js.map +1 -1
  158. package/dist/modules/auth/auth.service.d.ts +89 -5
  159. package/dist/modules/auth/auth.service.d.ts.map +1 -1
  160. package/dist/modules/auth/auth.service.js +160 -25
  161. package/dist/modules/auth/auth.service.js.map +1 -1
  162. package/dist/modules/auth/oidc-auth-provider.d.ts +46 -3
  163. package/dist/modules/auth/oidc-auth-provider.d.ts.map +1 -1
  164. package/dist/modules/auth/oidc-auth-provider.js +99 -21
  165. package/dist/modules/auth/oidc-auth-provider.js.map +1 -1
  166. package/dist/modules/code-mode/code-mode.tool.d.ts.map +1 -1
  167. package/dist/modules/code-mode/code-mode.tool.js +14 -2
  168. package/dist/modules/code-mode/code-mode.tool.js.map +1 -1
  169. package/dist/modules/connection-probe/connection-probe.service.d.ts.map +1 -1
  170. package/dist/modules/connection-probe/connection-probe.service.js +56 -7
  171. package/dist/modules/connection-probe/connection-probe.service.js.map +1 -1
  172. package/dist/modules/database/advisory-lock.d.ts +103 -0
  173. package/dist/modules/database/advisory-lock.d.ts.map +1 -0
  174. package/dist/modules/database/advisory-lock.js +320 -0
  175. package/dist/modules/database/advisory-lock.js.map +1 -0
  176. package/dist/modules/database/connection.d.ts.map +1 -1
  177. package/dist/modules/database/connection.js +9 -1
  178. package/dist/modules/database/connection.js.map +1 -1
  179. package/dist/modules/database/core-schema.d.ts +346 -0
  180. package/dist/modules/database/core-schema.d.ts.map +1 -1
  181. package/dist/modules/database/core-schema.js +119 -0
  182. package/dist/modules/database/core-schema.js.map +1 -1
  183. package/dist/modules/database/migrate.d.ts.map +1 -1
  184. package/dist/modules/database/migrate.js +26 -6
  185. package/dist/modules/database/migrate.js.map +1 -1
  186. package/dist/modules/declared-variables/declared-variables.routes.d.ts.map +1 -1
  187. package/dist/modules/declared-variables/declared-variables.routes.js +4 -2
  188. package/dist/modules/declared-variables/declared-variables.routes.js.map +1 -1
  189. package/dist/modules/diff/diff.routes.d.ts.map +1 -1
  190. package/dist/modules/diff/diff.routes.js +2 -4
  191. package/dist/modules/diff/diff.routes.js.map +1 -1
  192. package/dist/modules/diff/diff.service.d.ts +4 -1
  193. package/dist/modules/diff/diff.service.d.ts.map +1 -1
  194. package/dist/modules/diff/diff.service.js +79 -81
  195. package/dist/modules/diff/diff.service.js.map +1 -1
  196. package/dist/modules/kb-fs/bevel-ignore.d.ts +35 -0
  197. package/dist/modules/kb-fs/bevel-ignore.d.ts.map +1 -0
  198. package/dist/modules/kb-fs/bevel-ignore.js +71 -0
  199. package/dist/modules/kb-fs/bevel-ignore.js.map +1 -0
  200. package/dist/modules/kb-fs/file-change-notifier.d.ts.map +1 -1
  201. package/dist/modules/kb-fs/file-change-notifier.js +3 -1
  202. package/dist/modules/kb-fs/file-change-notifier.js.map +1 -1
  203. package/dist/modules/kb-fs/git-guarded-filesystem.d.ts +37 -0
  204. package/dist/modules/kb-fs/git-guarded-filesystem.d.ts.map +1 -0
  205. package/dist/modules/kb-fs/git-guarded-filesystem.js +104 -0
  206. package/dist/modules/kb-fs/git-guarded-filesystem.js.map +1 -0
  207. package/dist/modules/kb-fs/locking-filesystem.d.ts +113 -18
  208. package/dist/modules/kb-fs/locking-filesystem.d.ts.map +1 -1
  209. package/dist/modules/kb-fs/locking-filesystem.js +353 -76
  210. package/dist/modules/kb-fs/locking-filesystem.js.map +1 -1
  211. package/dist/modules/kb-fs/node-fs.d.ts +23 -0
  212. package/dist/modules/kb-fs/node-fs.d.ts.map +1 -0
  213. package/dist/modules/kb-fs/node-fs.js +158 -0
  214. package/dist/modules/kb-fs/node-fs.js.map +1 -0
  215. package/dist/modules/kb-fs/read-only-filesystem.d.ts +10 -9
  216. package/dist/modules/kb-fs/read-only-filesystem.d.ts.map +1 -1
  217. package/dist/modules/kb-fs/read-only-filesystem.js +18 -9
  218. package/dist/modules/kb-fs/read-only-filesystem.js.map +1 -1
  219. package/dist/modules/kb-fs/repo-path.d.ts +100 -3
  220. package/dist/modules/kb-fs/repo-path.d.ts.map +1 -1
  221. package/dist/modules/kb-fs/repo-path.js +195 -3
  222. package/dist/modules/kb-fs/repo-path.js.map +1 -1
  223. package/dist/modules/kb-sync/kb-sync.routes.d.ts.map +1 -1
  224. package/dist/modules/kb-sync/kb-sync.routes.js +4 -2
  225. package/dist/modules/kb-sync/kb-sync.routes.js.map +1 -1
  226. package/dist/modules/kb-sync/kb-sync.service.d.ts.map +1 -1
  227. package/dist/modules/kb-sync/kb-sync.service.js +7 -5
  228. package/dist/modules/kb-sync/kb-sync.service.js.map +1 -1
  229. package/dist/modules/marketplace/git-http.routes.d.ts.map +1 -1
  230. package/dist/modules/marketplace/git-http.routes.js +6 -4
  231. package/dist/modules/marketplace/git-http.routes.js.map +1 -1
  232. package/dist/modules/marketplace/github-facade/github-facade-admin.routes.d.ts +12 -2
  233. package/dist/modules/marketplace/github-facade/github-facade-admin.routes.d.ts.map +1 -1
  234. package/dist/modules/marketplace/github-facade/github-facade-admin.routes.js +32 -3
  235. package/dist/modules/marketplace/github-facade/github-facade-admin.routes.js.map +1 -1
  236. package/dist/modules/marketplace/github-facade/github-facade-credentials.service.d.ts +27 -0
  237. package/dist/modules/marketplace/github-facade/github-facade-credentials.service.d.ts.map +1 -1
  238. package/dist/modules/marketplace/github-facade/github-facade-credentials.service.js +45 -0
  239. package/dist/modules/marketplace/github-facade/github-facade-credentials.service.js.map +1 -1
  240. package/dist/modules/marketplace/github-facade/github-facade.routes.d.ts.map +1 -1
  241. package/dist/modules/marketplace/github-facade/github-facade.routes.js +30 -6
  242. package/dist/modules/marketplace/github-facade/github-facade.routes.js.map +1 -1
  243. package/dist/modules/marketplace/github-facade/github-facade.service.d.ts +21 -9
  244. package/dist/modules/marketplace/github-facade/github-facade.service.d.ts.map +1 -1
  245. package/dist/modules/marketplace/github-facade/github-facade.service.js +60 -19
  246. package/dist/modules/marketplace/github-facade/github-facade.service.js.map +1 -1
  247. package/dist/modules/marketplace/github-facade/index.d.ts +1 -1
  248. package/dist/modules/marketplace/github-facade/index.d.ts.map +1 -1
  249. package/dist/modules/marketplace/github-facade/index.js +1 -1
  250. package/dist/modules/marketplace/github-facade/index.js.map +1 -1
  251. package/dist/modules/marketplace/marketplace-repo.service.d.ts +14 -1
  252. package/dist/modules/marketplace/marketplace-repo.service.d.ts.map +1 -1
  253. package/dist/modules/marketplace/marketplace-repo.service.js +26 -8
  254. package/dist/modules/marketplace/marketplace-repo.service.js.map +1 -1
  255. package/dist/modules/mcp/downstream-pool.d.ts +107 -0
  256. package/dist/modules/mcp/downstream-pool.d.ts.map +1 -0
  257. package/dist/modules/mcp/downstream-pool.js +221 -0
  258. package/dist/modules/mcp/downstream-pool.js.map +1 -0
  259. package/dist/modules/mcp/downstream-token-refresh.d.ts +77 -0
  260. package/dist/modules/mcp/downstream-token-refresh.d.ts.map +1 -0
  261. package/dist/modules/mcp/downstream-token-refresh.js +166 -0
  262. package/dist/modules/mcp/downstream-token-refresh.js.map +1 -0
  263. package/dist/modules/mcp/first-call-probe.cli-args.d.ts +78 -0
  264. package/dist/modules/mcp/first-call-probe.cli-args.d.ts.map +1 -0
  265. package/dist/modules/mcp/first-call-probe.cli-args.js +151 -0
  266. package/dist/modules/mcp/first-call-probe.cli-args.js.map +1 -0
  267. package/dist/modules/mcp/first-call-probe.cli.d.ts +2 -0
  268. package/dist/modules/mcp/first-call-probe.cli.d.ts.map +1 -0
  269. package/dist/modules/mcp/first-call-probe.cli.js +62 -0
  270. package/dist/modules/mcp/first-call-probe.cli.js.map +1 -0
  271. package/dist/modules/mcp/first-call-probe.d.ts +165 -0
  272. package/dist/modules/mcp/first-call-probe.d.ts.map +1 -0
  273. package/dist/modules/mcp/first-call-probe.js +298 -0
  274. package/dist/modules/mcp/first-call-probe.js.map +1 -0
  275. package/dist/modules/mcp/manual-failure-memo.d.ts +42 -17
  276. package/dist/modules/mcp/manual-failure-memo.d.ts.map +1 -1
  277. package/dist/modules/mcp/manual-failure-memo.js +79 -23
  278. package/dist/modules/mcp/manual-failure-memo.js.map +1 -1
  279. package/dist/modules/mcp/mcp-auth.middleware.d.ts +9 -5
  280. package/dist/modules/mcp/mcp-auth.middleware.d.ts.map +1 -1
  281. package/dist/modules/mcp/mcp-auth.middleware.js +24 -16
  282. package/dist/modules/mcp/mcp-auth.middleware.js.map +1 -1
  283. package/dist/modules/mcp/mcp.routes.d.ts +4 -4
  284. package/dist/modules/mcp/mcp.routes.d.ts.map +1 -1
  285. package/dist/modules/mcp/mcp.routes.js +83 -179
  286. package/dist/modules/mcp/mcp.routes.js.map +1 -1
  287. package/dist/modules/mcp/mcp.service.d.ts +218 -61
  288. package/dist/modules/mcp/mcp.service.d.ts.map +1 -1
  289. package/dist/modules/mcp/mcp.service.js +713 -159
  290. package/dist/modules/mcp/mcp.service.js.map +1 -1
  291. package/dist/modules/mcp/oauth/bevel-oauth-provider.d.ts.map +1 -1
  292. package/dist/modules/mcp/oauth/bevel-oauth-provider.js +4 -2
  293. package/dist/modules/mcp/oauth/bevel-oauth-provider.js.map +1 -1
  294. package/dist/modules/mcp/oauth/oauth-consent.routes.d.ts.map +1 -1
  295. package/dist/modules/mcp/oauth/oauth-consent.routes.js +3 -1
  296. package/dist/modules/mcp/oauth/oauth-consent.routes.js.map +1 -1
  297. package/dist/modules/mcp/surface-log-throttle.d.ts +59 -0
  298. package/dist/modules/mcp/surface-log-throttle.d.ts.map +1 -0
  299. package/dist/modules/mcp/surface-log-throttle.js +94 -0
  300. package/dist/modules/mcp/surface-log-throttle.js.map +1 -0
  301. package/dist/modules/plugins/compile/compile-marketplace.d.ts +13 -6
  302. package/dist/modules/plugins/compile/compile-marketplace.d.ts.map +1 -1
  303. package/dist/modules/plugins/compile/compile-marketplace.js +119 -36
  304. package/dist/modules/plugins/compile/compile-marketplace.js.map +1 -1
  305. package/dist/modules/plugins/compile/marketplace-compiler.service.d.ts +8 -1
  306. package/dist/modules/plugins/compile/marketplace-compiler.service.d.ts.map +1 -1
  307. package/dist/modules/plugins/compile/marketplace-compiler.service.js +9 -6
  308. package/dist/modules/plugins/compile/marketplace-compiler.service.js.map +1 -1
  309. package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.d.ts.map +1 -1
  310. package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.js +32 -9
  311. package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.js.map +1 -1
  312. package/dist/modules/plugins/discovery/bundle-dialect/registry.d.ts +26 -6
  313. package/dist/modules/plugins/discovery/bundle-dialect/registry.d.ts.map +1 -1
  314. package/dist/modules/plugins/discovery/bundle-dialect/registry.js +71 -14
  315. package/dist/modules/plugins/discovery/bundle-dialect/registry.js.map +1 -1
  316. package/dist/modules/plugins/discovery/kb-plugin-source.d.ts +4 -2
  317. package/dist/modules/plugins/discovery/kb-plugin-source.d.ts.map +1 -1
  318. package/dist/modules/plugins/discovery/kb-plugin-source.js +9 -6
  319. package/dist/modules/plugins/discovery/kb-plugin-source.js.map +1 -1
  320. package/dist/modules/plugins/discovery/native.source.d.ts +2 -1
  321. package/dist/modules/plugins/discovery/native.source.d.ts.map +1 -1
  322. package/dist/modules/plugins/discovery/native.source.js +22 -4
  323. package/dist/modules/plugins/discovery/native.source.js.map +1 -1
  324. package/dist/modules/plugins/discovery/plugin-source.d.ts +17 -3
  325. package/dist/modules/plugins/discovery/plugin-source.d.ts.map +1 -1
  326. package/dist/modules/plugins/index.d.ts +6 -3
  327. package/dist/modules/plugins/index.d.ts.map +1 -1
  328. package/dist/modules/plugins/index.js +6 -3
  329. package/dist/modules/plugins/index.js.map +1 -1
  330. package/dist/modules/plugins/join-request-jobs.service.d.ts +250 -0
  331. package/dist/modules/plugins/join-request-jobs.service.d.ts.map +1 -0
  332. package/dist/modules/plugins/join-request-jobs.service.js +602 -0
  333. package/dist/modules/plugins/join-request-jobs.service.js.map +1 -0
  334. package/dist/modules/plugins/join-request-records.store.d.ts +161 -0
  335. package/dist/modules/plugins/join-request-records.store.d.ts.map +1 -0
  336. package/dist/modules/plugins/join-request-records.store.js +179 -0
  337. package/dist/modules/plugins/join-request-records.store.js.map +1 -0
  338. package/dist/modules/plugins/join-requests.service.d.ts.map +1 -1
  339. package/dist/modules/plugins/join-requests.service.js +4 -2
  340. package/dist/modules/plugins/join-requests.service.js.map +1 -1
  341. package/dist/modules/plugins/plugin-links.d.ts +4 -1
  342. package/dist/modules/plugins/plugin-links.d.ts.map +1 -1
  343. package/dist/modules/plugins/plugin-links.js +6 -3
  344. package/dist/modules/plugins/plugin-links.js.map +1 -1
  345. package/dist/modules/plugins/plugin-links.service.d.ts +2 -5
  346. package/dist/modules/plugins/plugin-links.service.d.ts.map +1 -1
  347. package/dist/modules/plugins/plugin-links.service.js +4 -13
  348. package/dist/modules/plugins/plugin-links.service.js.map +1 -1
  349. package/dist/modules/plugins/plugin-provision.service.d.ts +91 -19
  350. package/dist/modules/plugins/plugin-provision.service.d.ts.map +1 -1
  351. package/dist/modules/plugins/plugin-provision.service.js +183 -38
  352. package/dist/modules/plugins/plugin-provision.service.js.map +1 -1
  353. package/dist/modules/plugins/plugin-rename.service.d.ts +3 -1
  354. package/dist/modules/plugins/plugin-rename.service.d.ts.map +1 -1
  355. package/dist/modules/plugins/plugin-rename.service.js +20 -11
  356. package/dist/modules/plugins/plugin-rename.service.js.map +1 -1
  357. package/dist/modules/plugins/plugins.contract.d.ts +52 -4
  358. package/dist/modules/plugins/plugins.contract.d.ts.map +1 -1
  359. package/dist/modules/plugins/plugins.routes.d.ts +38 -5
  360. package/dist/modules/plugins/plugins.routes.d.ts.map +1 -1
  361. package/dist/modules/plugins/plugins.routes.js +190 -116
  362. package/dist/modules/plugins/plugins.routes.js.map +1 -1
  363. package/dist/modules/plugins/plugins.service.d.ts +38 -6
  364. package/dist/modules/plugins/plugins.service.d.ts.map +1 -1
  365. package/dist/modules/plugins/plugins.service.js +86 -17
  366. package/dist/modules/plugins/plugins.service.js.map +1 -1
  367. package/dist/modules/plugins/plugins.tools.d.ts +25 -0
  368. package/dist/modules/plugins/plugins.tools.d.ts.map +1 -0
  369. package/dist/modules/plugins/plugins.tools.js +82 -0
  370. package/dist/modules/plugins/plugins.tools.js.map +1 -0
  371. package/dist/modules/plugins/teams.routes.d.ts +42 -0
  372. package/dist/modules/plugins/teams.routes.d.ts.map +1 -0
  373. package/dist/modules/plugins/teams.routes.js +79 -0
  374. package/dist/modules/plugins/teams.routes.js.map +1 -0
  375. package/dist/modules/secrets-vault/db-secrets-vault.service.d.ts +40 -1
  376. package/dist/modules/secrets-vault/db-secrets-vault.service.d.ts.map +1 -1
  377. package/dist/modules/secrets-vault/db-secrets-vault.service.js +202 -37
  378. package/dist/modules/secrets-vault/db-secrets-vault.service.js.map +1 -1
  379. package/dist/modules/secrets-vault/index.d.ts +1 -1
  380. package/dist/modules/secrets-vault/index.d.ts.map +1 -1
  381. package/dist/modules/secrets-vault/index.js.map +1 -1
  382. package/dist/modules/secrets-vault/mcp-oauth-discovery.service.d.ts.map +1 -1
  383. package/dist/modules/secrets-vault/mcp-oauth-discovery.service.js +5 -3
  384. package/dist/modules/secrets-vault/mcp-oauth-discovery.service.js.map +1 -1
  385. package/dist/modules/secrets-vault/secrets-variable-loader.d.ts.map +1 -1
  386. package/dist/modules/secrets-vault/secrets-variable-loader.js +3 -1
  387. package/dist/modules/secrets-vault/secrets-variable-loader.js.map +1 -1
  388. package/dist/modules/secrets-vault/secrets-vault.contract.d.ts +78 -0
  389. package/dist/modules/secrets-vault/secrets-vault.contract.d.ts.map +1 -1
  390. package/dist/modules/secrets-vault/secrets-vault.contract.js +40 -0
  391. package/dist/modules/secrets-vault/secrets-vault.contract.js.map +1 -1
  392. package/dist/modules/secrets-vault/secrets-vault.routes.d.ts.map +1 -1
  393. package/dist/modules/secrets-vault/secrets-vault.routes.js +106 -52
  394. package/dist/modules/secrets-vault/secrets-vault.routes.js.map +1 -1
  395. package/dist/modules/settings/connection-check.d.ts +118 -0
  396. package/dist/modules/settings/connection-check.d.ts.map +1 -0
  397. package/dist/modules/settings/connection-check.js +287 -0
  398. package/dist/modules/settings/connection-check.js.map +1 -0
  399. package/dist/modules/settings/deployment-settings.service.d.ts +153 -7
  400. package/dist/modules/settings/deployment-settings.service.d.ts.map +1 -1
  401. package/dist/modules/settings/deployment-settings.service.js +348 -51
  402. package/dist/modules/settings/deployment-settings.service.js.map +1 -1
  403. package/dist/modules/settings/git-root-folders.d.ts +54 -0
  404. package/dist/modules/settings/git-root-folders.d.ts.map +1 -0
  405. package/dist/modules/settings/git-root-folders.js +130 -0
  406. package/dist/modules/settings/git-root-folders.js.map +1 -0
  407. package/dist/modules/settings/oidc-check.d.ts +85 -0
  408. package/dist/modules/settings/oidc-check.d.ts.map +1 -0
  409. package/dist/modules/settings/oidc-check.js +172 -0
  410. package/dist/modules/settings/oidc-check.js.map +1 -0
  411. package/dist/modules/settings/setup.routes.d.ts +31 -1
  412. package/dist/modules/settings/setup.routes.d.ts.map +1 -1
  413. package/dist/modules/settings/setup.routes.js +400 -108
  414. package/dist/modules/settings/setup.routes.js.map +1 -1
  415. package/dist/modules/skills/allowed-tools-check.d.ts +132 -0
  416. package/dist/modules/skills/allowed-tools-check.d.ts.map +1 -0
  417. package/dist/modules/skills/allowed-tools-check.js +260 -0
  418. package/dist/modules/skills/allowed-tools-check.js.map +1 -0
  419. package/dist/modules/skills/index.d.ts +3 -1
  420. package/dist/modules/skills/index.d.ts.map +1 -1
  421. package/dist/modules/skills/index.js +1 -0
  422. package/dist/modules/skills/index.js.map +1 -1
  423. package/dist/modules/skills/pending-skills.service.d.ts +6 -11
  424. package/dist/modules/skills/pending-skills.service.d.ts.map +1 -1
  425. package/dist/modules/skills/pending-skills.service.js +18 -70
  426. package/dist/modules/skills/pending-skills.service.js.map +1 -1
  427. package/dist/modules/skills/skill-access-requests.routes.d.ts.map +1 -1
  428. package/dist/modules/skills/skill-access-requests.routes.js +9 -6
  429. package/dist/modules/skills/skill-access-requests.routes.js.map +1 -1
  430. package/dist/modules/skills/skills.contract.d.ts +44 -10
  431. package/dist/modules/skills/skills.contract.d.ts.map +1 -1
  432. package/dist/modules/skills/skills.routes.d.ts +8 -1
  433. package/dist/modules/skills/skills.routes.d.ts.map +1 -1
  434. package/dist/modules/skills/skills.routes.js +16 -2
  435. package/dist/modules/skills/skills.routes.js.map +1 -1
  436. package/dist/modules/skills/skills.service.d.ts +31 -7
  437. package/dist/modules/skills/skills.service.d.ts.map +1 -1
  438. package/dist/modules/skills/skills.service.js +191 -81
  439. package/dist/modules/skills/skills.service.js.map +1 -1
  440. package/dist/modules/skills/skills.tools.d.ts +4 -1
  441. package/dist/modules/skills/skills.tools.d.ts.map +1 -1
  442. package/dist/modules/skills/skills.tools.js +41 -6
  443. package/dist/modules/skills/skills.tools.js.map +1 -1
  444. package/dist/modules/tool-auth/connection-key-rejection.d.ts +18 -0
  445. package/dist/modules/tool-auth/connection-key-rejection.d.ts.map +1 -0
  446. package/dist/modules/tool-auth/connection-key-rejection.js +20 -0
  447. package/dist/modules/tool-auth/connection-key-rejection.js.map +1 -0
  448. package/dist/modules/tool-auth/connection-keys-admin.routes.d.ts +14 -0
  449. package/dist/modules/tool-auth/connection-keys-admin.routes.d.ts.map +1 -0
  450. package/dist/modules/tool-auth/connection-keys-admin.routes.js +67 -0
  451. package/dist/modules/tool-auth/connection-keys-admin.routes.js.map +1 -0
  452. package/dist/modules/tool-auth/external-api-key.interface.d.ts +51 -3
  453. package/dist/modules/tool-auth/external-api-key.interface.d.ts.map +1 -1
  454. package/dist/modules/tool-auth/external-api-key.interface.js.map +1 -1
  455. package/dist/modules/tool-auth/external-api-key.service.d.ts +16 -6
  456. package/dist/modules/tool-auth/external-api-key.service.d.ts.map +1 -1
  457. package/dist/modules/tool-auth/external-api-key.service.js +61 -18
  458. package/dist/modules/tool-auth/external-api-key.service.js.map +1 -1
  459. package/dist/modules/tool-auth/internal-token.service.d.ts +5 -2
  460. package/dist/modules/tool-auth/internal-token.service.d.ts.map +1 -1
  461. package/dist/modules/tool-auth/internal-token.service.js +5 -2
  462. package/dist/modules/tool-auth/internal-token.service.js.map +1 -1
  463. package/dist/modules/tool-auth/key-or-session.middleware.d.ts +23 -0
  464. package/dist/modules/tool-auth/key-or-session.middleware.d.ts.map +1 -0
  465. package/dist/modules/tool-auth/key-or-session.middleware.js +39 -0
  466. package/dist/modules/tool-auth/key-or-session.middleware.js.map +1 -0
  467. package/dist/modules/tool-auth/tool-auth.middleware.d.ts +7 -1
  468. package/dist/modules/tool-auth/tool-auth.middleware.d.ts.map +1 -1
  469. package/dist/modules/tool-auth/tool-auth.middleware.js +8 -5
  470. package/dist/modules/tool-auth/tool-auth.middleware.js.map +1 -1
  471. package/dist/modules/tool-helpers/tool-context.d.ts +14 -0
  472. package/dist/modules/tool-helpers/tool-context.d.ts.map +1 -1
  473. package/dist/modules/tool-helpers/tool-context.js +28 -6
  474. package/dist/modules/tool-helpers/tool-context.js.map +1 -1
  475. package/dist/modules/tool-helpers/tool-handler.d.ts.map +1 -1
  476. package/dist/modules/tool-helpers/tool-handler.js +22 -5
  477. package/dist/modules/tool-helpers/tool-handler.js.map +1 -1
  478. package/dist/modules/tool-helpers/tool.contract.d.ts +6 -1
  479. package/dist/modules/tool-helpers/tool.contract.d.ts.map +1 -1
  480. package/dist/modules/tool-helpers/tool.contract.js +7 -1
  481. package/dist/modules/tool-helpers/tool.contract.js.map +1 -1
  482. package/dist/modules/tool-manuals/index.d.ts +2 -1
  483. package/dist/modules/tool-manuals/index.d.ts.map +1 -1
  484. package/dist/modules/tool-manuals/index.js +1 -0
  485. package/dist/modules/tool-manuals/index.js.map +1 -1
  486. package/dist/modules/tool-manuals/mcp-json-discovery.d.ts.map +1 -1
  487. package/dist/modules/tool-manuals/mcp-json-discovery.js +8 -6
  488. package/dist/modules/tool-manuals/mcp-json-discovery.js.map +1 -1
  489. package/dist/modules/tool-manuals/mcp-server-edit.service.d.ts +10 -2
  490. package/dist/modules/tool-manuals/mcp-server-edit.service.d.ts.map +1 -1
  491. package/dist/modules/tool-manuals/mcp-server-edit.service.js +12 -15
  492. package/dist/modules/tool-manuals/mcp-server-edit.service.js.map +1 -1
  493. package/dist/modules/tool-manuals/pending-tools.service.d.ts +50 -0
  494. package/dist/modules/tool-manuals/pending-tools.service.d.ts.map +1 -0
  495. package/dist/modules/tool-manuals/pending-tools.service.js +149 -0
  496. package/dist/modules/tool-manuals/pending-tools.service.js.map +1 -0
  497. package/dist/modules/tool-manuals/tool-delete.service.d.ts +135 -0
  498. package/dist/modules/tool-manuals/tool-delete.service.d.ts.map +1 -0
  499. package/dist/modules/tool-manuals/tool-delete.service.js +303 -0
  500. package/dist/modules/tool-manuals/tool-delete.service.js.map +1 -0
  501. package/dist/modules/tool-manuals/tool-manuals.contract.d.ts +161 -0
  502. package/dist/modules/tool-manuals/tool-manuals.contract.d.ts.map +1 -1
  503. package/dist/modules/tool-manuals/tool-manuals.contract.js +9 -0
  504. package/dist/modules/tool-manuals/tool-manuals.contract.js.map +1 -1
  505. package/dist/modules/tool-manuals/tool-manuals.routes.d.ts +19 -2
  506. package/dist/modules/tool-manuals/tool-manuals.routes.d.ts.map +1 -1
  507. package/dist/modules/tool-manuals/tool-manuals.routes.js +127 -57
  508. package/dist/modules/tool-manuals/tool-manuals.routes.js.map +1 -1
  509. package/dist/modules/tool-manuals/tool-manuals.service.d.ts +119 -5
  510. package/dist/modules/tool-manuals/tool-manuals.service.d.ts.map +1 -1
  511. package/dist/modules/tool-manuals/tool-manuals.service.js +404 -74
  512. package/dist/modules/tool-manuals/tool-manuals.service.js.map +1 -1
  513. package/dist/modules/tool-manuals/tool-manuals.tools.d.ts.map +1 -1
  514. package/dist/modules/tool-manuals/tool-manuals.tools.js +78 -6
  515. package/dist/modules/tool-manuals/tool-manuals.tools.js.map +1 -1
  516. package/dist/modules/workflow/agent-tools/workflow.tools.d.ts.map +1 -1
  517. package/dist/modules/workflow/agent-tools/workflow.tools.js +88 -54
  518. package/dist/modules/workflow/agent-tools/workflow.tools.js.map +1 -1
  519. package/dist/modules/workflow/event-bus.d.ts +10 -4
  520. package/dist/modules/workflow/event-bus.d.ts.map +1 -1
  521. package/dist/modules/workflow/event-bus.js +14 -11
  522. package/dist/modules/workflow/event-bus.js.map +1 -1
  523. package/dist/modules/workflow/events.routes.d.ts +17 -2
  524. package/dist/modules/workflow/events.routes.d.ts.map +1 -1
  525. package/dist/modules/workflow/events.routes.js +31 -12
  526. package/dist/modules/workflow/events.routes.js.map +1 -1
  527. package/dist/modules/workflow/file-lock.service.d.ts +22 -4
  528. package/dist/modules/workflow/file-lock.service.d.ts.map +1 -1
  529. package/dist/modules/workflow/file-lock.service.js +27 -4
  530. package/dist/modules/workflow/file-lock.service.js.map +1 -1
  531. package/dist/modules/workflow/git/change-request-link.d.ts +20 -0
  532. package/dist/modules/workflow/git/change-request-link.d.ts.map +1 -0
  533. package/dist/modules/workflow/git/change-request-link.js +34 -0
  534. package/dist/modules/workflow/git/change-request-link.js.map +1 -0
  535. package/dist/modules/workflow/git/git-version.d.ts.map +1 -1
  536. package/dist/modules/workflow/git/git-version.js +3 -1
  537. package/dist/modules/workflow/git/git-version.js.map +1 -1
  538. package/dist/modules/workflow/git/git.service.d.ts +263 -4
  539. package/dist/modules/workflow/git/git.service.d.ts.map +1 -1
  540. package/dist/modules/workflow/git/git.service.js +528 -118
  541. package/dist/modules/workflow/git/git.service.js.map +1 -1
  542. package/dist/modules/workflow/git/node-git-runner.d.ts +36 -0
  543. package/dist/modules/workflow/git/node-git-runner.d.ts.map +1 -0
  544. package/dist/modules/workflow/git/node-git-runner.js +273 -0
  545. package/dist/modules/workflow/git/node-git-runner.js.map +1 -0
  546. package/dist/modules/workflow/git/pull-request.service.d.ts +51 -2
  547. package/dist/modules/workflow/git/pull-request.service.d.ts.map +1 -1
  548. package/dist/modules/workflow/git/pull-request.service.js +157 -25
  549. package/dist/modules/workflow/git/pull-request.service.js.map +1 -1
  550. package/dist/modules/workflow/pending-commits.service.d.ts +11 -0
  551. package/dist/modules/workflow/pending-commits.service.d.ts.map +1 -1
  552. package/dist/modules/workflow/pending-commits.service.js +24 -4
  553. package/dist/modules/workflow/pending-commits.service.js.map +1 -1
  554. package/dist/modules/workflow/pending-commits.worker.d.ts +15 -8
  555. package/dist/modules/workflow/pending-commits.worker.d.ts.map +1 -1
  556. package/dist/modules/workflow/pending-commits.worker.js +107 -58
  557. package/dist/modules/workflow/pending-commits.worker.js.map +1 -1
  558. package/dist/modules/workflow/recovery-bot.d.ts.map +1 -1
  559. package/dist/modules/workflow/recovery-bot.js +3 -1
  560. package/dist/modules/workflow/recovery-bot.js.map +1 -1
  561. package/dist/modules/workflow/review-workflow/approval-lock.d.ts +60 -0
  562. package/dist/modules/workflow/review-workflow/approval-lock.d.ts.map +1 -0
  563. package/dist/modules/workflow/review-workflow/approval-lock.js +116 -0
  564. package/dist/modules/workflow/review-workflow/approval-lock.js.map +1 -0
  565. package/dist/modules/workflow/review-workflow/review-workflow.interface.d.ts +54 -7
  566. package/dist/modules/workflow/review-workflow/review-workflow.interface.d.ts.map +1 -1
  567. package/dist/modules/workflow/review-workflow/review-workflow.service.d.ts +64 -0
  568. package/dist/modules/workflow/review-workflow/review-workflow.service.d.ts.map +1 -1
  569. package/dist/modules/workflow/review-workflow/review-workflow.service.js +269 -90
  570. package/dist/modules/workflow/review-workflow/review-workflow.service.js.map +1 -1
  571. package/dist/modules/workflow/sanitize-error.d.ts +5 -2
  572. package/dist/modules/workflow/sanitize-error.d.ts.map +1 -1
  573. package/dist/modules/workflow/sanitize-error.js +8 -4
  574. package/dist/modules/workflow/sanitize-error.js.map +1 -1
  575. package/dist/modules/workflow/workflow.routes.d.ts +2 -0
  576. package/dist/modules/workflow/workflow.routes.d.ts.map +1 -1
  577. package/dist/modules/workflow/workflow.routes.js +259 -29
  578. package/dist/modules/workflow/workflow.routes.js.map +1 -1
  579. package/dist/modules/workflow/workflow.service.d.ts +166 -14
  580. package/dist/modules/workflow/workflow.service.d.ts.map +1 -1
  581. package/dist/modules/workflow/workflow.service.js +906 -106
  582. package/dist/modules/workflow/workflow.service.js.map +1 -1
  583. package/dist/modules/workspace/empty-dirs.d.ts +15 -0
  584. package/dist/modules/workspace/empty-dirs.d.ts.map +1 -0
  585. package/dist/modules/workspace/empty-dirs.js +90 -0
  586. package/dist/modules/workspace/empty-dirs.js.map +1 -0
  587. package/dist/modules/workspace/file-readers/content-mode.d.ts +50 -0
  588. package/dist/modules/workspace/file-readers/content-mode.d.ts.map +1 -0
  589. package/dist/modules/workspace/file-readers/content-mode.js +55 -0
  590. package/dist/modules/workspace/file-readers/content-mode.js.map +1 -0
  591. package/dist/modules/workspace/file-readers/doc-extract.service.d.ts +4 -1
  592. package/dist/modules/workspace/file-readers/doc-extract.service.d.ts.map +1 -1
  593. package/dist/modules/workspace/file-readers/doc-extract.service.js +4 -1
  594. package/dist/modules/workspace/file-readers/doc-extract.service.js.map +1 -1
  595. package/dist/modules/workspace/file-readers/doc-extract.types.d.ts +5 -2
  596. package/dist/modules/workspace/file-readers/doc-extract.types.d.ts.map +1 -1
  597. package/dist/modules/workspace/file-readers/doc-extract.types.js +7 -4
  598. package/dist/modules/workspace/file-readers/doc-extract.types.js.map +1 -1
  599. package/dist/modules/workspace/file-readers/document-reader.d.ts +2 -0
  600. package/dist/modules/workspace/file-readers/document-reader.d.ts.map +1 -1
  601. package/dist/modules/workspace/file-readers/document-reader.js +5 -0
  602. package/dist/modules/workspace/file-readers/document-reader.js.map +1 -1
  603. package/dist/modules/workspace/file-readers/extract-docx.d.ts +6 -0
  604. package/dist/modules/workspace/file-readers/extract-docx.d.ts.map +1 -1
  605. package/dist/modules/workspace/file-readers/extract-docx.js +6 -0
  606. package/dist/modules/workspace/file-readers/extract-docx.js.map +1 -1
  607. package/dist/modules/workspace/file-readers/file-reader.d.ts +24 -5
  608. package/dist/modules/workspace/file-readers/file-reader.d.ts.map +1 -1
  609. package/dist/modules/workspace/file-readers/file-reader.js +11 -6
  610. package/dist/modules/workspace/file-readers/file-reader.js.map +1 -1
  611. package/dist/modules/workspace/file-readers/file-reader.registry.d.ts.map +1 -1
  612. package/dist/modules/workspace/file-readers/file-reader.registry.js +6 -1
  613. package/dist/modules/workspace/file-readers/file-reader.registry.js.map +1 -1
  614. package/dist/modules/workspace/file-readers/image-reader.d.ts +7 -5
  615. package/dist/modules/workspace/file-readers/image-reader.d.ts.map +1 -1
  616. package/dist/modules/workspace/file-readers/image-reader.js +9 -5
  617. package/dist/modules/workspace/file-readers/image-reader.js.map +1 -1
  618. package/dist/modules/workspace/file-readers/ooxml-text.d.ts +3 -0
  619. package/dist/modules/workspace/file-readers/ooxml-text.d.ts.map +1 -1
  620. package/dist/modules/workspace/file-readers/ooxml-text.js +39 -2
  621. package/dist/modules/workspace/file-readers/ooxml-text.js.map +1 -1
  622. package/dist/modules/workspace/file-readers/text-reader.d.ts +29 -1
  623. package/dist/modules/workspace/file-readers/text-reader.d.ts.map +1 -1
  624. package/dist/modules/workspace/file-readers/text-reader.js +57 -3
  625. package/dist/modules/workspace/file-readers/text-reader.js.map +1 -1
  626. package/dist/modules/workspace/git-internals.middleware.d.ts +28 -0
  627. package/dist/modules/workspace/git-internals.middleware.d.ts.map +1 -0
  628. package/dist/modules/workspace/git-internals.middleware.js +93 -0
  629. package/dist/modules/workspace/git-internals.middleware.js.map +1 -0
  630. package/dist/modules/workspace/not-found.d.ts +80 -0
  631. package/dist/modules/workspace/not-found.d.ts.map +1 -0
  632. package/dist/modules/workspace/not-found.js +112 -0
  633. package/dist/modules/workspace/not-found.js.map +1 -0
  634. package/dist/modules/workspace/session-ontology.gate.d.ts +1 -1
  635. package/dist/modules/workspace/session-ontology.gate.d.ts.map +1 -1
  636. package/dist/modules/workspace/session-ontology.gate.js +1 -1
  637. package/dist/modules/workspace/session-ontology.gate.js.map +1 -1
  638. package/dist/modules/workspace/startup/beside-checkout.d.ts +42 -0
  639. package/dist/modules/workspace/startup/beside-checkout.d.ts.map +1 -0
  640. package/dist/modules/workspace/startup/beside-checkout.js +110 -0
  641. package/dist/modules/workspace/startup/beside-checkout.js.map +1 -0
  642. package/dist/modules/workspace/startup/kb-git.d.ts +7 -12
  643. package/dist/modules/workspace/startup/kb-git.d.ts.map +1 -1
  644. package/dist/modules/workspace/startup/kb-git.js +34 -35
  645. package/dist/modules/workspace/startup/kb-git.js.map +1 -1
  646. package/dist/modules/workspace/startup/kb-startup-runner.d.ts +95 -0
  647. package/dist/modules/workspace/startup/kb-startup-runner.d.ts.map +1 -1
  648. package/dist/modules/workspace/startup/kb-startup-runner.js +257 -55
  649. package/dist/modules/workspace/startup/kb-startup-runner.js.map +1 -1
  650. package/dist/modules/workspace/startup/steps/groups-to-plugins.step.d.ts +45 -0
  651. package/dist/modules/workspace/startup/steps/groups-to-plugins.step.d.ts.map +1 -1
  652. package/dist/modules/workspace/startup/steps/groups-to-plugins.step.js +417 -385
  653. package/dist/modules/workspace/startup/steps/groups-to-plugins.step.js.map +1 -1
  654. package/dist/modules/workspace/startup/steps/personal-spaces.step.d.ts +48 -0
  655. package/dist/modules/workspace/startup/steps/personal-spaces.step.d.ts.map +1 -0
  656. package/dist/modules/workspace/startup/steps/personal-spaces.step.js +183 -0
  657. package/dist/modules/workspace/startup/steps/personal-spaces.step.js.map +1 -0
  658. package/dist/modules/workspace/startup/steps/plugin-display-names.step.d.ts +51 -0
  659. package/dist/modules/workspace/startup/steps/plugin-display-names.step.d.ts.map +1 -0
  660. package/dist/modules/workspace/startup/steps/plugin-display-names.step.js +158 -0
  661. package/dist/modules/workspace/startup/steps/plugin-display-names.step.js.map +1 -0
  662. package/dist/modules/workspace/startup/steps/plugin-layout.d.ts +64 -0
  663. package/dist/modules/workspace/startup/steps/plugin-layout.d.ts.map +1 -0
  664. package/dist/modules/workspace/startup/steps/plugin-layout.js +97 -0
  665. package/dist/modules/workspace/startup/steps/plugin-layout.js.map +1 -0
  666. package/dist/modules/workspace/startup/steps/plugin-manifests.step.d.ts +7 -1
  667. package/dist/modules/workspace/startup/steps/plugin-manifests.step.d.ts.map +1 -1
  668. package/dist/modules/workspace/startup/steps/plugin-manifests.step.js +45 -81
  669. package/dist/modules/workspace/startup/steps/plugin-manifests.step.js.map +1 -1
  670. package/dist/modules/workspace/startup/steps/roles-yaml.step.d.ts +3 -1
  671. package/dist/modules/workspace/startup/steps/roles-yaml.step.d.ts.map +1 -1
  672. package/dist/modules/workspace/startup/steps/roles-yaml.step.js +4 -12
  673. package/dist/modules/workspace/startup/steps/roles-yaml.step.js.map +1 -1
  674. package/dist/modules/workspace/startup/steps/seed-tree.d.ts +6 -1
  675. package/dist/modules/workspace/startup/steps/seed-tree.d.ts.map +1 -1
  676. package/dist/modules/workspace/startup/steps/seed-tree.js +154 -78
  677. package/dist/modules/workspace/startup/steps/seed-tree.js.map +1 -1
  678. package/dist/modules/workspace/startup/steps/template-files.step.d.ts +96 -24
  679. package/dist/modules/workspace/startup/steps/template-files.step.d.ts.map +1 -1
  680. package/dist/modules/workspace/startup/steps/template-files.step.js +446 -138
  681. package/dist/modules/workspace/startup/steps/template-files.step.js.map +1 -1
  682. package/dist/modules/workspace/startup/steps/template-source.d.ts +94 -0
  683. package/dist/modules/workspace/startup/steps/template-source.d.ts.map +1 -0
  684. package/dist/modules/workspace/startup/steps/template-source.js +160 -0
  685. package/dist/modules/workspace/startup/steps/template-source.js.map +1 -0
  686. package/dist/modules/workspace/workspace.routes.d.ts +14 -2
  687. package/dist/modules/workspace/workspace.routes.d.ts.map +1 -1
  688. package/dist/modules/workspace/workspace.routes.js +649 -238
  689. package/dist/modules/workspace/workspace.routes.js.map +1 -1
  690. package/dist/modules/workspace/workspace.service.d.ts +290 -12
  691. package/dist/modules/workspace/workspace.service.d.ts.map +1 -1
  692. package/dist/modules/workspace/workspace.service.js +924 -269
  693. package/dist/modules/workspace/workspace.service.js.map +1 -1
  694. package/dist/modules/workspace/workspace.tools.d.ts +42 -1
  695. package/dist/modules/workspace/workspace.tools.d.ts.map +1 -1
  696. package/dist/modules/workspace/workspace.tools.js +1590 -146
  697. package/dist/modules/workspace/workspace.tools.js.map +1 -1
  698. package/dist/modules/workspace/write-denial.d.ts +76 -0
  699. package/dist/modules/workspace/write-denial.d.ts.map +1 -0
  700. package/dist/modules/workspace/write-denial.js +138 -0
  701. package/dist/modules/workspace/write-denial.js.map +1 -0
  702. package/dist/shared/canonical-file-identity.d.ts +64 -0
  703. package/dist/shared/canonical-file-identity.d.ts.map +1 -0
  704. package/dist/shared/canonical-file-identity.js +92 -0
  705. package/dist/shared/canonical-file-identity.js.map +1 -0
  706. package/dist/shared/domain-errors.d.ts +108 -0
  707. package/dist/shared/domain-errors.d.ts.map +1 -1
  708. package/dist/shared/domain-errors.js +137 -0
  709. package/dist/shared/domain-errors.js.map +1 -1
  710. package/dist/shared/email-identity.d.ts +32 -0
  711. package/dist/shared/email-identity.d.ts.map +1 -0
  712. package/dist/shared/email-identity.js +37 -0
  713. package/dist/shared/email-identity.js.map +1 -0
  714. package/dist/shared/fs.contract.d.ts +206 -0
  715. package/dist/shared/fs.contract.d.ts.map +1 -0
  716. package/dist/shared/fs.contract.js +79 -0
  717. package/dist/shared/fs.contract.js.map +1 -0
  718. package/dist/shared/git-failure.d.ts +80 -0
  719. package/dist/shared/git-failure.d.ts.map +1 -0
  720. package/dist/shared/git-failure.js +139 -0
  721. package/dist/shared/git-failure.js.map +1 -0
  722. package/dist/shared/git-internals.d.ts +17 -0
  723. package/dist/shared/git-internals.d.ts.map +1 -0
  724. package/dist/shared/git-internals.js +123 -0
  725. package/dist/shared/git-internals.js.map +1 -0
  726. package/dist/shared/git.contract.d.ts +157 -0
  727. package/dist/shared/git.contract.d.ts.map +1 -0
  728. package/dist/shared/git.contract.js +103 -0
  729. package/dist/shared/git.contract.js.map +1 -0
  730. package/dist/shared/http-errors.d.ts +33 -0
  731. package/dist/shared/http-errors.d.ts.map +1 -0
  732. package/dist/shared/http-errors.js +35 -0
  733. package/dist/shared/http-errors.js.map +1 -0
  734. package/dist/shared/logger.contract.d.ts +63 -0
  735. package/dist/shared/logger.contract.d.ts.map +1 -0
  736. package/dist/shared/logger.contract.js +126 -0
  737. package/dist/shared/logger.contract.js.map +1 -0
  738. package/dist/shared/logging.d.ts +31 -0
  739. package/dist/shared/logging.d.ts.map +1 -0
  740. package/dist/shared/logging.js +92 -0
  741. package/dist/shared/logging.js.map +1 -0
  742. package/dist/shared/path-containment.d.ts +21 -0
  743. package/dist/shared/path-containment.d.ts.map +1 -0
  744. package/dist/shared/path-containment.js +34 -0
  745. package/dist/shared/path-containment.js.map +1 -0
  746. package/dist/shared/pending-proposals.d.ts +71 -0
  747. package/dist/shared/pending-proposals.d.ts.map +1 -0
  748. package/dist/shared/pending-proposals.js +98 -0
  749. package/dist/shared/pending-proposals.js.map +1 -0
  750. package/dist/shared/printable.d.ts +22 -0
  751. package/dist/shared/printable.d.ts.map +1 -0
  752. package/dist/shared/printable.js +65 -0
  753. package/dist/shared/printable.js.map +1 -0
  754. package/dist/shared/redact-secret.d.ts +30 -0
  755. package/dist/shared/redact-secret.d.ts.map +1 -0
  756. package/dist/shared/redact-secret.js +114 -0
  757. package/dist/shared/redact-secret.js.map +1 -0
  758. package/dist/shared/rename-no-replace.d.ts +119 -0
  759. package/dist/shared/rename-no-replace.d.ts.map +1 -0
  760. package/dist/shared/rename-no-replace.js +323 -0
  761. package/dist/shared/rename-no-replace.js.map +1 -0
  762. package/dist/shared/ssrf.d.ts.map +1 -1
  763. package/dist/shared/ssrf.js +49 -18
  764. package/dist/shared/ssrf.js.map +1 -1
  765. package/dist/version.d.ts +10 -6
  766. package/dist/version.d.ts.map +1 -1
  767. package/dist/version.js +10 -6
  768. package/dist/version.js.map +1 -1
  769. package/kb-template/.bevelignore +4 -3
  770. package/kb-template/AGENTS.md +281 -36
  771. package/kb-template/KnowledgeBase/How to get started.md +1 -1
  772. package/kb-template/access.md +5 -3
  773. package/kb-template/mcp-description.md +27 -0
  774. package/migrations/0006_api_tokens_revoked_by.sql +1 -0
  775. package/migrations/0007_github_facade_registered.sql +1 -0
  776. package/migrations/0008_change_request_apply_failure.sql +4 -0
  777. package/migrations/0009_change_request_apply_failure_kind.sql +13 -0
  778. package/migrations/0010_plugin_join_requests.sql +15 -0
  779. package/migrations/0011_plugin_join_request_claim.sql +11 -0
  780. package/migrations/meta/0006_snapshot.json +1723 -0
  781. package/migrations/meta/0007_snapshot.json +1729 -0
  782. package/migrations/meta/0008_snapshot.json +1753 -0
  783. package/migrations/meta/0009_snapshot.json +1759 -0
  784. package/migrations/meta/0010_snapshot.json +1872 -0
  785. package/migrations/meta/0011_snapshot.json +1884 -0
  786. package/migrations/meta/_journal.json +42 -0
  787. package/package.json +6 -5
  788. package/src/__tests__/core-config.domain.test.ts +67 -2
  789. package/src/__tests__/kb-layout-config.test.ts +186 -1
  790. package/src/__tests__/open-change-gate.ts +15 -0
  791. package/src/core/__tests__/catalog-cache-invalidation.test.ts +83 -3
  792. package/src/core/__tests__/catalog-revision.test.ts +190 -0
  793. package/src/core/__tests__/lifecycle.test.ts +369 -0
  794. package/src/core/__tests__/public-config.test.ts +30 -0
  795. package/src/core/__tests__/readiness.test.ts +109 -0
  796. package/src/core/catalog-cache-invalidation.ts +20 -1
  797. package/src/core/catalog-revision.ts +110 -0
  798. package/src/core/create-core-server.ts +258 -79
  799. package/src/core/create-core-services.ts +302 -81
  800. package/src/core/lifecycle.ts +312 -0
  801. package/src/core/public-config.ts +86 -0
  802. package/src/core/readiness.ts +123 -0
  803. package/src/core-config.ts +70 -4
  804. package/src/index.ts +15 -0
  805. package/src/modules/access/__tests__/access-control.admin-root-floor.test.ts +362 -0
  806. package/src/modules/access/__tests__/access-control.atref-batch.test.ts +2 -1
  807. package/src/modules/access/__tests__/access-control.atref-cache.test.ts +46 -22
  808. package/src/modules/access/__tests__/access-control.deny-dependents.test.ts +215 -0
  809. package/src/modules/access/__tests__/access-control.download-read.test.ts +268 -0
  810. package/src/modules/access/__tests__/access-control.everyone-read.test.ts +145 -0
  811. package/src/modules/access/__tests__/access-control.group-read.test.ts +163 -0
  812. package/src/modules/access/__tests__/access-control.invalidate-race.test.ts +2 -0
  813. package/src/modules/access/__tests__/access-control.platform-restore.test.ts +152 -0
  814. package/src/modules/access/__tests__/access-control.prospective.test.ts +189 -0
  815. package/src/modules/access/__tests__/access-control.read-batch.test.ts +2 -1
  816. package/src/modules/access/__tests__/access-control.service.test.ts +123 -78
  817. package/src/modules/access/__tests__/access-groups.test.ts +47 -14
  818. package/src/modules/access/__tests__/access-md-format.test.ts +2 -1
  819. package/src/modules/access/__tests__/access-mutation.service.test.ts +52 -4
  820. package/src/modules/access/__tests__/access-own-read-grant.test.ts +2 -0
  821. package/src/modules/access/__tests__/access-personal-plugin.test.ts +153 -0
  822. package/src/modules/access/__tests__/access-plugin-principals.test.ts +18 -1
  823. package/src/modules/access/__tests__/access-restrict-here.test.ts +450 -0
  824. package/src/modules/access/__tests__/access.routes.batch.test.ts +139 -0
  825. package/src/modules/access/__tests__/access.routes.folder-governs.test.ts +394 -0
  826. package/src/modules/access/__tests__/access.routes.group-grant.test.ts +6 -2
  827. package/src/modules/access/__tests__/access.routes.overrides.test.ts +3 -2
  828. package/src/modules/access/__tests__/access.routes.proposal-branch.test.ts +234 -0
  829. package/src/modules/access/__tests__/access.routes.prospective.test.ts +216 -0
  830. package/src/modules/access/__tests__/access.routes.revoke.test.ts +7 -2
  831. package/src/modules/access/__tests__/access.routes.unknown-email.test.ts +360 -0
  832. package/src/modules/access/__tests__/change-read-gate.test.ts +272 -0
  833. package/src/modules/access/__tests__/creator-access.test.ts +81 -83
  834. package/src/modules/access/__tests__/grant-sources.test.ts +3 -2
  835. package/src/modules/access/__tests__/groups-admin.service.test.ts +6 -5
  836. package/src/modules/access/__tests__/roles-admin.security.test.ts +196 -0
  837. package/src/modules/access/__tests__/roles-admin.service.test.ts +127 -2
  838. package/src/modules/access/__tests__/roles-capabilities.test.ts +5 -4
  839. package/src/modules/access/__tests__/roles.routes.test.ts +5 -2
  840. package/src/modules/access/__tests__/user-access-removal.service.test.ts +402 -0
  841. package/src/modules/access/__tests__/users-db-double.ts +63 -0
  842. package/src/modules/access/access-control.interface.ts +251 -11
  843. package/src/modules/access/access-control.service.ts +719 -164
  844. package/src/modules/access/access-mutation.service.ts +182 -13
  845. package/src/modules/access/access-view.ts +316 -0
  846. package/src/modules/access/access.routes.ts +293 -95
  847. package/src/modules/access/admin-locked-commit.ts +12 -14
  848. package/src/modules/access/admin-route-helpers.ts +4 -4
  849. package/src/modules/access/change-read-gate.ts +148 -0
  850. package/src/modules/access/creator-access.ts +89 -124
  851. package/src/modules/access/directory-sync-bot.ts +4 -1
  852. package/src/modules/access/groups-admin.service.ts +3 -3
  853. package/src/modules/access/reference-scan.ts +5 -5
  854. package/src/modules/access/roles-admin.service.ts +94 -15
  855. package/src/modules/access/synced-groups-committer.ts +10 -15
  856. package/src/modules/access/synced-groups-writer.ts +3 -12
  857. package/src/modules/access/user-access-removal.service.ts +711 -0
  858. package/src/modules/access-model/__tests__/access-splice.test.ts +63 -1
  859. package/src/modules/access-model/__tests__/frontmatter-fences.test.ts +71 -0
  860. package/src/modules/access-model/__tests__/roles-yaml-guard.test.ts +131 -0
  861. package/src/modules/access-model/access-errors.ts +56 -15
  862. package/src/modules/access-model/access-grammar.ts +85 -48
  863. package/src/modules/access-model/access-splice.ts +18 -18
  864. package/src/modules/access-model/access-template.ts +44 -0
  865. package/src/modules/access-model/change-gate.ts +80 -0
  866. package/src/modules/access-model/creator.ts +18 -21
  867. package/src/modules/access-model/frontmatter-lines.ts +98 -0
  868. package/src/modules/access-model/plugin-principals.ts +12 -19
  869. package/src/modules/access-model/roles-yaml-guard.ts +182 -4
  870. package/src/modules/admin/admin-access.service.ts +6 -2
  871. package/src/modules/agent-instructions/__tests__/agent-instructions.route.test.ts +100 -0
  872. package/src/modules/agent-instructions/__tests__/compose.test.ts +256 -0
  873. package/src/modules/agent-instructions/__tests__/read-preamble.test.ts +135 -0
  874. package/src/modules/agent-instructions/agent-instructions.routes.ts +41 -0
  875. package/src/modules/agent-instructions/compose.ts +271 -0
  876. package/src/modules/agent-instructions/index.ts +14 -0
  877. package/src/modules/agent-instructions/read-preamble.ts +88 -0
  878. package/src/modules/auth/__tests__/account-erasure.approval-gate.test.ts +209 -0
  879. package/src/modules/auth/__tests__/account.routes.test.ts +178 -2
  880. package/src/modules/auth/__tests__/auth.middleware.test.ts +78 -0
  881. package/src/modules/auth/__tests__/auth.service.test.ts +338 -5
  882. package/src/modules/auth/__tests__/oidc-auth-provider.test.ts +352 -12
  883. package/src/modules/auth/__tests__/onboarding-done.route.test.ts +3 -1
  884. package/src/modules/auth/account-erasure.service.ts +117 -10
  885. package/src/modules/auth/account.routes.ts +115 -14
  886. package/src/modules/auth/auth.routes.ts +20 -7
  887. package/src/modules/auth/auth.service.ts +187 -28
  888. package/src/modules/auth/oidc-auth-provider.ts +120 -22
  889. package/src/modules/code-mode/__tests__/code-mode.tool.test.ts +109 -1
  890. package/src/modules/code-mode/code-mode.tool.ts +13 -2
  891. package/src/modules/connection-probe/__tests__/connection-probe.service.test.ts +78 -0
  892. package/src/modules/connection-probe/connection-probe.service.ts +59 -7
  893. package/src/modules/database/__tests__/advisory-lease.test.ts +152 -0
  894. package/src/modules/database/__tests__/advisory-lock.test.ts +147 -0
  895. package/src/modules/database/advisory-lock.ts +346 -0
  896. package/src/modules/database/connection.ts +9 -1
  897. package/src/modules/database/core-schema.ts +123 -0
  898. package/src/modules/database/migrate.ts +27 -6
  899. package/src/modules/declared-variables/declared-variables.routes.ts +6 -3
  900. package/src/modules/diff/__tests__/diff.service.seed-atomicity.test.ts +3 -0
  901. package/src/modules/diff/__tests__/diff.service.test.ts +3 -0
  902. package/src/modules/diff/diff.routes.ts +2 -4
  903. package/src/modules/diff/diff.service.ts +75 -79
  904. package/src/modules/kb-fs/__tests__/locking-filesystem.test.ts +472 -9
  905. package/src/modules/kb-fs/__tests__/node-fs.test.ts +409 -0
  906. package/src/modules/kb-fs/__tests__/repo-path.test.ts +210 -1
  907. package/src/modules/{workspace → kb-fs}/bevel-ignore.ts +22 -15
  908. package/src/modules/kb-fs/file-change-notifier.ts +4 -1
  909. package/src/modules/kb-fs/git-guarded-filesystem.ts +123 -0
  910. package/src/modules/kb-fs/locking-filesystem.ts +399 -109
  911. package/src/modules/kb-fs/node-fs.ts +165 -0
  912. package/src/modules/kb-fs/read-only-filesystem.ts +18 -9
  913. package/src/modules/kb-fs/repo-path.ts +213 -3
  914. package/src/modules/kb-sync/kb-sync.routes.ts +5 -2
  915. package/src/modules/kb-sync/kb-sync.service.ts +8 -5
  916. package/src/modules/marketplace/__tests__/github-facade.test.ts +134 -2
  917. package/src/modules/marketplace/__tests__/marketplace-git.test.ts +2 -1
  918. package/src/modules/marketplace/__tests__/marketplace-repo.head.test.ts +47 -0
  919. package/src/modules/marketplace/git-http.routes.ts +7 -4
  920. package/src/modules/marketplace/github-facade/github-facade-admin.routes.ts +35 -3
  921. package/src/modules/marketplace/github-facade/github-facade-credentials.service.ts +55 -0
  922. package/src/modules/marketplace/github-facade/github-facade.routes.ts +32 -6
  923. package/src/modules/marketplace/github-facade/github-facade.service.ts +80 -19
  924. package/src/modules/marketplace/github-facade/index.ts +1 -0
  925. package/src/modules/marketplace/marketplace-repo.service.ts +23 -8
  926. package/src/modules/mcp/__tests__/downstream-pool.test.ts +278 -0
  927. package/src/modules/mcp/__tests__/downstream-token-refresh.test.ts +178 -0
  928. package/src/modules/mcp/__tests__/fake-downstream-mcp-server.ts +156 -0
  929. package/src/modules/mcp/__tests__/first-call-probe.cli-args.test.ts +178 -0
  930. package/src/modules/mcp/__tests__/first-call-probe.test.ts +414 -0
  931. package/src/modules/mcp/__tests__/manual-failure-memo.test.ts +98 -6
  932. package/src/modules/mcp/__tests__/mcp-auth.middleware.test.ts +8 -5
  933. package/src/modules/mcp/__tests__/mcp-routes-harness.ts +1 -3
  934. package/src/modules/mcp/__tests__/mcp.e2e.test.ts +1055 -59
  935. package/src/modules/mcp/__tests__/mcp.routes.stateless.test.ts +182 -0
  936. package/src/modules/mcp/__tests__/mcp.service.test.ts +274 -6
  937. package/src/modules/mcp/__tests__/surface-log-throttle.test.ts +169 -0
  938. package/src/modules/mcp/downstream-pool.ts +256 -0
  939. package/src/modules/mcp/downstream-token-refresh.ts +170 -0
  940. package/src/modules/mcp/first-call-probe.cli-args.ts +159 -0
  941. package/src/modules/mcp/first-call-probe.cli.ts +60 -0
  942. package/src/modules/mcp/first-call-probe.ts +418 -0
  943. package/src/modules/mcp/manual-failure-memo.ts +81 -23
  944. package/src/modules/mcp/mcp-auth.middleware.ts +25 -16
  945. package/src/modules/mcp/mcp.routes.ts +376 -482
  946. package/src/modules/mcp/mcp.service.ts +846 -176
  947. package/src/modules/mcp/oauth/bevel-oauth-provider.ts +5 -2
  948. package/src/modules/mcp/oauth/oauth-consent.routes.ts +4 -4
  949. package/src/modules/mcp/surface-log-throttle.ts +120 -0
  950. package/src/modules/plugins/__tests__/bundle-dialect.e2e.test.ts +10 -7
  951. package/src/modules/plugins/__tests__/bundle-dialect.test.ts +165 -0
  952. package/src/modules/plugins/__tests__/compile-marketplace.test.ts +139 -10
  953. package/src/modules/plugins/__tests__/fake-join-request-store.ts +189 -0
  954. package/src/modules/plugins/__tests__/join-request-jobs.service.test.ts +608 -0
  955. package/src/modules/plugins/__tests__/plugin-creation-display-name.test.ts +241 -0
  956. package/src/modules/plugins/__tests__/plugin-index.service.test.ts +148 -7
  957. package/src/modules/plugins/__tests__/plugin-links.service.test.ts +10 -13
  958. package/src/modules/plugins/__tests__/plugin-names.test.ts +77 -0
  959. package/src/modules/plugins/__tests__/plugin-provision.service.test.ts +129 -19
  960. package/src/modules/plugins/__tests__/plugin-rename.service.test.ts +91 -29
  961. package/src/modules/plugins/__tests__/plugins.routes.test.ts +370 -19
  962. package/src/modules/plugins/__tests__/plugins.tools.test.ts +131 -0
  963. package/src/modules/plugins/__tests__/teams.routes.test.ts +248 -0
  964. package/src/modules/plugins/compile/compile-marketplace.ts +143 -46
  965. package/src/modules/plugins/compile/marketplace-compiler.service.ts +8 -7
  966. package/src/modules/plugins/discovery/__tests__/kb-plugin-source.test.ts +56 -20
  967. package/src/modules/plugins/discovery/bundle-dialect/bundle.source.ts +30 -9
  968. package/src/modules/plugins/discovery/bundle-dialect/registry.ts +93 -18
  969. package/src/modules/plugins/discovery/kb-plugin-source.ts +10 -7
  970. package/src/modules/plugins/discovery/native.source.ts +21 -3
  971. package/src/modules/plugins/discovery/plugin-source.ts +17 -3
  972. package/src/modules/plugins/index.ts +16 -3
  973. package/src/modules/plugins/join-request-jobs.service.ts +675 -0
  974. package/src/modules/plugins/join-request-records.store.ts +353 -0
  975. package/src/modules/plugins/join-requests.service.ts +7 -4
  976. package/src/modules/plugins/plugin-links.service.ts +4 -17
  977. package/src/modules/plugins/plugin-links.ts +6 -3
  978. package/src/modules/plugins/plugin-provision.service.ts +209 -37
  979. package/src/modules/plugins/plugin-rename.service.ts +21 -9
  980. package/src/modules/plugins/plugins.contract.ts +52 -4
  981. package/src/modules/plugins/plugins.routes.ts +204 -124
  982. package/src/modules/plugins/plugins.service.ts +92 -18
  983. package/src/modules/plugins/plugins.tools.ts +88 -0
  984. package/src/modules/plugins/teams.routes.ts +129 -0
  985. package/src/modules/secrets-vault/__tests__/connect-pending.route.test.ts +359 -15
  986. package/src/modules/secrets-vault/__tests__/db-secrets-vault.oauth.test.ts +248 -0
  987. package/src/modules/secrets-vault/__tests__/namespace-secrets.test.ts +202 -0
  988. package/src/modules/secrets-vault/db-secrets-vault.service.ts +217 -35
  989. package/src/modules/secrets-vault/index.ts +1 -0
  990. package/src/modules/secrets-vault/mcp-oauth-discovery.service.ts +6 -3
  991. package/src/modules/secrets-vault/secrets-variable-loader.ts +4 -4
  992. package/src/modules/secrets-vault/secrets-vault.contract.ts +93 -0
  993. package/src/modules/secrets-vault/secrets-vault.routes.ts +99 -38
  994. package/src/modules/settings/__tests__/connection-check.test.ts +233 -0
  995. package/src/modules/settings/__tests__/deployment-settings.service.test.ts +188 -6
  996. package/src/modules/settings/__tests__/git-root-folders.test.ts +247 -0
  997. package/src/modules/settings/__tests__/oidc-check.test.ts +185 -0
  998. package/src/modules/settings/__tests__/setup.routes.boot-failure.test.ts +119 -0
  999. package/src/modules/settings/__tests__/setup.routes.layout-phase.test.ts +170 -0
  1000. package/src/modules/settings/__tests__/setup.routes.oidc.test.ts +555 -0
  1001. package/src/modules/settings/__tests__/setup.routes.test.ts +667 -16
  1002. package/src/modules/settings/connection-check.ts +351 -0
  1003. package/src/modules/settings/deployment-settings.service.ts +403 -57
  1004. package/src/modules/settings/git-root-folders.ts +171 -0
  1005. package/src/modules/settings/oidc-check.ts +229 -0
  1006. package/src/modules/settings/setup.routes.ts +456 -110
  1007. package/src/modules/skills/__tests__/allowed-tools-check.test.ts +224 -0
  1008. package/src/modules/skills/__tests__/allowed-tools-warn.tools.test.ts +210 -0
  1009. package/src/modules/skills/__tests__/pending-skills.service.test.ts +3 -3
  1010. package/src/modules/skills/__tests__/skills.routes.warnings.test.ts +91 -0
  1011. package/src/modules/skills/__tests__/skills.service.test.ts +223 -2
  1012. package/src/modules/skills/allowed-tools-check.ts +352 -0
  1013. package/src/modules/skills/index.ts +4 -0
  1014. package/src/modules/skills/pending-skills.service.ts +21 -82
  1015. package/src/modules/skills/skill-access-requests.routes.ts +10 -6
  1016. package/src/modules/skills/skills.contract.ts +43 -11
  1017. package/src/modules/skills/skills.routes.ts +16 -1
  1018. package/src/modules/skills/skills.service.ts +214 -84
  1019. package/src/modules/skills/skills.tools.ts +43 -5
  1020. package/src/modules/tool-auth/__tests__/connection-key-rejection.test.ts +192 -0
  1021. package/src/modules/tool-auth/__tests__/connection-keys-admin.routes.test.ts +116 -0
  1022. package/src/modules/tool-auth/__tests__/external-api-key.service.test.ts +124 -0
  1023. package/src/modules/tool-auth/connection-key-rejection.ts +25 -0
  1024. package/src/modules/tool-auth/connection-keys-admin.routes.ts +76 -0
  1025. package/src/modules/tool-auth/external-api-key.interface.ts +56 -3
  1026. package/src/modules/tool-auth/external-api-key.service.ts +73 -25
  1027. package/src/modules/tool-auth/internal-token.service.ts +5 -2
  1028. package/src/modules/tool-auth/key-or-session.middleware.ts +45 -0
  1029. package/src/modules/tool-auth/tool-auth.middleware.ts +16 -7
  1030. package/src/modules/tool-helpers/__tests__/agent-roles-write.test.ts +228 -0
  1031. package/src/modules/tool-helpers/__tests__/phase4-tools.test.ts +33 -4
  1032. package/src/modules/tool-helpers/tool-context.ts +46 -7
  1033. package/src/modules/tool-helpers/tool-handler.ts +23 -5
  1034. package/src/modules/tool-helpers/tool.contract.ts +5 -0
  1035. package/src/modules/tool-manuals/__tests__/mcp-server-edit.service.test.ts +2 -1
  1036. package/src/modules/tool-manuals/__tests__/pending-tools.service.test.ts +411 -0
  1037. package/src/modules/tool-manuals/__tests__/tool-delete.route.test.ts +133 -0
  1038. package/src/modules/tool-manuals/__tests__/tool-delete.service.test.ts +469 -0
  1039. package/src/modules/tool-manuals/__tests__/tool-manuals.archive.route.test.ts +21 -2
  1040. package/src/modules/tool-manuals/__tests__/tool-manuals.cli.test.ts +9 -4
  1041. package/src/modules/tool-manuals/__tests__/tool-manuals.detail.route.test.ts +6 -1
  1042. package/src/modules/tool-manuals/__tests__/tool-manuals.invalid.routes.test.ts +254 -0
  1043. package/src/modules/tool-manuals/__tests__/tool-manuals.invalid.test.ts +577 -0
  1044. package/src/modules/tool-manuals/__tests__/tool-manuals.mcp-oauth.test.ts +6 -1
  1045. package/src/modules/tool-manuals/__tests__/tool-manuals.pending.route.test.ts +102 -0
  1046. package/src/modules/tool-manuals/__tests__/tool-manuals.restart.test.ts +285 -0
  1047. package/src/modules/tool-manuals/__tests__/tool-manuals.service.test.ts +178 -2
  1048. package/src/modules/tool-manuals/__tests__/tool-manuals.tools.test.ts +114 -2
  1049. package/src/modules/tool-manuals/index.ts +3 -0
  1050. package/src/modules/tool-manuals/mcp-json-discovery.ts +13 -10
  1051. package/src/modules/tool-manuals/mcp-server-edit.service.ts +11 -14
  1052. package/src/modules/tool-manuals/pending-tools.service.ts +179 -0
  1053. package/src/modules/tool-manuals/tool-delete.service.ts +401 -0
  1054. package/src/modules/tool-manuals/tool-manuals.contract.ts +165 -0
  1055. package/src/modules/tool-manuals/tool-manuals.routes.ts +138 -54
  1056. package/src/modules/tool-manuals/tool-manuals.service.ts +432 -87
  1057. package/src/modules/tool-manuals/tool-manuals.tools.ts +81 -6
  1058. package/src/modules/workflow/__tests__/apply-failure.test.ts +1038 -0
  1059. package/src/modules/workflow/__tests__/event-bus.test.ts +61 -9
  1060. package/src/modules/workflow/__tests__/fake-file-lock-db.ts +199 -0
  1061. package/src/modules/workflow/__tests__/file-lock.service.path-identity.test.ts +237 -0
  1062. package/src/modules/workflow/__tests__/format-affected-owners.test.ts +18 -0
  1063. package/src/modules/workflow/__tests__/merge-announces-tree.test.ts +220 -0
  1064. package/src/modules/workflow/__tests__/pending-commits.worker.concurrency.test.ts +187 -0
  1065. package/src/modules/workflow/__tests__/preserve-roles-yaml.test.ts +2 -0
  1066. package/src/modules/workflow/__tests__/sanitize-error.test.ts +10 -0
  1067. package/src/modules/workflow/__tests__/workflow.routes.folder-proposals.test.ts +128 -0
  1068. package/src/modules/workflow/__tests__/workflow.routes.fork-point-file.test.ts +149 -0
  1069. package/src/modules/workflow/__tests__/workflow.routes.lock-path.test.ts +305 -0
  1070. package/src/modules/workflow/__tests__/workflow.service.branch-in-use.test.ts +2 -0
  1071. package/src/modules/workflow/__tests__/workflow.service.commitFileWhileLocked.test.ts +2 -0
  1072. package/src/modules/workflow/__tests__/workflow.service.deleted-branch-sweep.test.ts +2 -0
  1073. package/src/modules/workflow/__tests__/workflow.service.facade.test.ts +294 -25
  1074. package/src/modules/workflow/__tests__/workflow.service.folder-proposals.test.ts +564 -0
  1075. package/src/modules/workflow/__tests__/workflow.service.platform-restore.test.ts +135 -0
  1076. package/src/modules/workflow/__tests__/workflow.service.read-gate.test.ts +172 -0
  1077. package/src/modules/workflow/__tests__/workflow.service.releaseLock.test.ts +14 -0
  1078. package/src/modules/workflow/__tests__/workflow.service.sync.test.ts +5 -0
  1079. package/src/modules/workflow/__tests__/workflow.service.update-from-target.test.ts +281 -0
  1080. package/src/modules/workflow/agent-tools/__tests__/workflow.tools.test.ts +158 -7
  1081. package/src/modules/workflow/agent-tools/workflow.tools.ts +93 -64
  1082. package/src/modules/workflow/event-bus.ts +26 -28
  1083. package/src/modules/workflow/events.routes.ts +56 -21
  1084. package/src/modules/workflow/file-lock.service.ts +27 -4
  1085. package/src/modules/workflow/git/__tests__/change-request-link.test.ts +43 -0
  1086. package/src/modules/workflow/git/__tests__/git.service.accessGating.test.ts +1 -0
  1087. package/src/modules/workflow/git/__tests__/git.service.changedFilesForPr.test.ts +238 -1
  1088. package/src/modules/workflow/git/__tests__/git.service.forkPoint.test.ts +245 -0
  1089. package/src/modules/workflow/git/__tests__/git.service.list-branches.test.ts +35 -0
  1090. package/src/modules/workflow/git/__tests__/git.service.mergeChangeRequest.test.ts +149 -0
  1091. package/src/modules/workflow/git/__tests__/git.service.revertPathsAndPush.test.ts +177 -0
  1092. package/src/modules/workflow/git/__tests__/node-git-runner.test.ts +114 -0
  1093. package/src/modules/workflow/git/__tests__/pull-request.service.getPrDetail.test.ts +69 -2
  1094. package/src/modules/workflow/git/__tests__/pull-request.service.list-fetch.test.ts +121 -0
  1095. package/src/modules/workflow/git/__tests__/pull-request.service.placeholder.test.ts +79 -0
  1096. package/src/modules/workflow/git/__tests__/pull-request.service.test.ts +1 -1
  1097. package/src/modules/workflow/git/__tests__/pull-request.service.viewer-can-cancel.test.ts +1 -1
  1098. package/src/modules/workflow/git/__tests__/pull-request.service.viewer-can-update.test.ts +111 -0
  1099. package/src/modules/workflow/git/change-request-link.ts +35 -0
  1100. package/src/modules/workflow/git/git-version.ts +5 -2
  1101. package/src/modules/workflow/git/git.service.ts +684 -144
  1102. package/src/modules/workflow/git/node-git-runner.ts +315 -0
  1103. package/src/modules/workflow/git/pull-request.service.ts +179 -27
  1104. package/src/modules/workflow/pending-commits.service.ts +26 -7
  1105. package/src/modules/workflow/pending-commits.worker.ts +114 -69
  1106. package/src/modules/workflow/recovery-bot.ts +4 -1
  1107. package/src/modules/workflow/review-workflow/__tests__/approval-states.test.ts +180 -1
  1108. package/src/modules/workflow/review-workflow/__tests__/cancel-pr.test.ts +1 -1
  1109. package/src/modules/workflow/review-workflow/__tests__/carry-approvals-forward.test.ts +520 -0
  1110. package/src/modules/workflow/review-workflow/__tests__/erase-approver.test.ts +84 -0
  1111. package/src/modules/workflow/review-workflow/__tests__/merge-gate.test.ts +89 -77
  1112. package/src/modules/workflow/review-workflow/approval-lock.ts +122 -0
  1113. package/src/modules/workflow/review-workflow/review-workflow.interface.ts +59 -7
  1114. package/src/modules/workflow/review-workflow/review-workflow.service.ts +309 -105
  1115. package/src/modules/workflow/sanitize-error.ts +9 -4
  1116. package/src/modules/workflow/workflow.routes.ts +273 -29
  1117. package/src/modules/workflow/workflow.service.ts +1087 -171
  1118. package/src/modules/workspace/__tests__/empty-dirs.test.ts +44 -0
  1119. package/src/modules/workspace/__tests__/file-stat-access.test.ts +301 -0
  1120. package/src/modules/workspace/__tests__/git-internals.security.test.ts +792 -0
  1121. package/src/modules/workspace/__tests__/workspace-paths-inside-the-repo.test.ts +464 -0
  1122. package/src/modules/workspace/__tests__/workspace.routes.branch-errors.test.ts +139 -0
  1123. package/src/modules/workspace/__tests__/workspace.routes.create-grant.test.ts +189 -37
  1124. package/src/modules/workspace/__tests__/workspace.routes.delete.test.ts +51 -11
  1125. package/src/modules/workspace/__tests__/workspace.routes.download-implies-read.test.ts +161 -0
  1126. package/src/modules/workspace/__tests__/workspace.routes.download.test.ts +109 -10
  1127. package/src/modules/workspace/__tests__/workspace.routes.file-writes.test.ts +624 -0
  1128. package/src/modules/workspace/__tests__/workspace.routes.folders.test.ts +409 -0
  1129. package/src/modules/workspace/__tests__/workspace.routes.move-platform-files.test.ts +327 -0
  1130. package/src/modules/workspace/__tests__/workspace.routes.read-gate.test.ts +25 -6
  1131. package/src/modules/workspace/__tests__/workspace.service.ensure-remotes-fetched.test.ts +109 -0
  1132. package/src/modules/workspace/__tests__/workspace.service.list-cloned.test.ts +6 -5
  1133. package/src/modules/workspace/__tests__/workspace.service.move-never-overwrites.test.ts +218 -0
  1134. package/src/modules/workspace/__tests__/workspace.service.read-filter.test.ts +56 -1
  1135. package/src/modules/workspace/__tests__/workspace.service.test.ts +811 -42
  1136. package/src/modules/workspace/__tests__/workspace.service.unknown-branch.test.ts +197 -0
  1137. package/src/modules/workspace/__tests__/workspace.tools.agents-file.test.ts +128 -0
  1138. package/src/modules/workspace/__tests__/workspace.tools.branch-errors.test.ts +212 -0
  1139. package/src/modules/workspace/__tests__/workspace.tools.test.ts +2632 -110
  1140. package/src/modules/workspace/__tests__/write-denial.test.ts +75 -0
  1141. package/src/modules/workspace/empty-dirs.ts +79 -0
  1142. package/src/modules/workspace/file-readers/README.md +32 -0
  1143. package/src/modules/workspace/file-readers/__tests__/doc-extract.test.ts +59 -2
  1144. package/src/modules/workspace/file-readers/__tests__/file-reader.registry.test.ts +133 -4
  1145. package/src/modules/workspace/file-readers/__tests__/fixtures/soft-break.docx +0 -0
  1146. package/src/modules/workspace/file-readers/__tests__/fixtures/tab.docx +0 -0
  1147. package/src/modules/workspace/file-readers/content-mode.ts +87 -0
  1148. package/src/modules/workspace/file-readers/doc-extract.service.ts +4 -1
  1149. package/src/modules/workspace/file-readers/doc-extract.types.ts +8 -4
  1150. package/src/modules/workspace/file-readers/document-reader.ts +6 -0
  1151. package/src/modules/workspace/file-readers/extract-docx.ts +6 -0
  1152. package/src/modules/workspace/file-readers/file-reader.registry.ts +9 -1
  1153. package/src/modules/workspace/file-readers/file-reader.ts +27 -6
  1154. package/src/modules/workspace/file-readers/image-reader.ts +10 -5
  1155. package/src/modules/workspace/file-readers/ooxml-text.ts +38 -2
  1156. package/src/modules/workspace/file-readers/text-reader.ts +61 -4
  1157. package/src/modules/workspace/git-internals.middleware.ts +86 -0
  1158. package/src/modules/workspace/not-found.ts +119 -0
  1159. package/src/modules/workspace/session-ontology.gate.ts +1 -1
  1160. package/src/modules/workspace/startup/__tests__/beside-checkout.test.ts +181 -0
  1161. package/src/modules/workspace/startup/__tests__/kb-startup-runner.degraded.test.ts +361 -0
  1162. package/src/modules/workspace/startup/__tests__/kb-startup-runner.test.ts +53 -16
  1163. package/src/modules/workspace/startup/beside-checkout.ts +112 -0
  1164. package/src/modules/workspace/startup/kb-git.ts +43 -36
  1165. package/src/modules/workspace/startup/kb-startup-runner.ts +303 -63
  1166. package/src/modules/workspace/startup/steps/__tests__/steps.test.ts +1215 -73
  1167. package/src/modules/workspace/startup/steps/groups-to-plugins.step.ts +460 -417
  1168. package/src/modules/workspace/startup/steps/personal-spaces.step.ts +191 -0
  1169. package/src/modules/workspace/startup/steps/plugin-display-names.step.ts +169 -0
  1170. package/src/modules/workspace/startup/steps/plugin-layout.ts +110 -0
  1171. package/src/modules/workspace/startup/steps/plugin-manifests.step.ts +46 -85
  1172. package/src/modules/workspace/startup/steps/roles-yaml.step.ts +6 -12
  1173. package/src/modules/workspace/startup/steps/seed-tree.ts +159 -78
  1174. package/src/modules/workspace/startup/steps/template-files.step.ts +492 -141
  1175. package/src/modules/workspace/startup/steps/template-source.ts +168 -0
  1176. package/src/modules/workspace/workspace.routes.ts +687 -257
  1177. package/src/modules/workspace/workspace.service.ts +991 -303
  1178. package/src/modules/workspace/workspace.tools.ts +1787 -180
  1179. package/src/modules/workspace/write-denial.ts +189 -0
  1180. package/src/shared/__tests__/canonical-file-identity.test.ts +154 -0
  1181. package/src/shared/__tests__/email-identity.test.ts +35 -0
  1182. package/src/shared/__tests__/filename.test.ts +0 -0
  1183. package/src/shared/__tests__/frontmatter-id.test.ts +5 -0
  1184. package/src/shared/__tests__/git-failure.test.ts +198 -0
  1185. package/src/shared/__tests__/git-internals.test.ts +115 -0
  1186. package/src/shared/__tests__/http-errors.test.ts +42 -0
  1187. package/src/shared/__tests__/logging.test.ts +185 -0
  1188. package/src/shared/__tests__/path-containment.test.ts +60 -0
  1189. package/src/shared/__tests__/pending-proposals.readAt.test.ts +102 -0
  1190. package/src/shared/__tests__/printable.test.ts +64 -0
  1191. package/src/shared/__tests__/redact-secret.test.ts +122 -0
  1192. package/src/shared/__tests__/rename-no-replace.test.ts +466 -0
  1193. package/src/shared/__tests__/ssrf.test.ts +20 -0
  1194. package/src/shared/canonical-file-identity.ts +92 -0
  1195. package/src/shared/domain-errors.ts +149 -0
  1196. package/src/shared/email-identity.ts +38 -0
  1197. package/src/shared/fs.contract.ts +225 -0
  1198. package/src/shared/git-failure.ts +196 -0
  1199. package/src/shared/git-internals.ts +124 -0
  1200. package/src/shared/git.contract.ts +170 -0
  1201. package/src/shared/http-errors.ts +36 -0
  1202. package/src/shared/logger.contract.ts +141 -0
  1203. package/src/shared/logging.ts +96 -0
  1204. package/src/shared/path-containment.ts +34 -0
  1205. package/src/shared/pending-proposals.ts +161 -0
  1206. package/src/shared/printable.ts +68 -0
  1207. package/src/shared/redact-secret.ts +118 -0
  1208. package/src/shared/rename-no-replace.ts +386 -0
  1209. package/src/shared/ssrf.ts +44 -16
  1210. package/src/version.ts +10 -6
  1211. package/src/modules/diff/diff-paths.ts +0 -9
  1212. package/src/modules/mcp/__tests__/mcp-session-store.test.ts +0 -151
  1213. package/src/modules/mcp/__tests__/mcp.routes.session.test.ts +0 -226
  1214. package/src/modules/mcp/mcp-session-store.ts +0 -162
  1215. package/src/shared/__tests__/fs-walk.test.ts +0 -63
  1216. package/src/shared/__tests__/kb-walk.test.ts +0 -107
  1217. package/src/shared/fs-errors.ts +0 -10
  1218. package/src/shared/fs-walk.ts +0 -45
  1219. package/src/shared/hash-email.ts +0 -14
  1220. package/src/shared/kb-walk.ts +0 -95
@@ -1,4 +1,5 @@
1
1
  import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
+ import { NodeFs } from '../../kb-fs/node-fs.js';
2
3
  import fs from 'node:fs/promises';
3
4
  import path from 'node:path';
4
5
  import os from 'node:os';
@@ -68,7 +69,7 @@ describe('AccessControlService', () => {
68
69
  await writeFile(repo, 'roles.yaml', ROLES_YAML);
69
70
  await writeFile(repo, 'access.md', '---\nwrite:\n - Admin\n---\n');
70
71
 
71
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
72
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
72
73
  expect(await svc.canWrite(workspaceId, 'razvan@bevel.software', 'Knowledge/Foo.md')).toBe(true);
73
74
  expect(await svc.canWrite(workspaceId, 'felix@example.com', 'Knowledge/Foo.md')).toBe(false);
74
75
  });
@@ -84,7 +85,7 @@ describe('AccessControlService', () => {
84
85
  '---\nid: weather\nwrite:\n - Product Manager\n---\ntype: http\nurl: https://x/m\n',
85
86
  );
86
87
 
87
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
88
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
88
89
  // The file-own `write: Product Manager` grants felix write on THIS tool…
89
90
  expect(await svc.canWrite(workspaceId, 'felix@example.com', 'Tools/weather.tool')).toBe(true);
90
91
  // …but nowhere else (root access.md is Admin-only).
@@ -99,7 +100,7 @@ describe('AccessControlService', () => {
99
100
  await writeFile(repo, 'access.md', '---\nwrite:\n - Admin\n---\n');
100
101
  await writeFile(repo, 'Knowledge/Sales/access.md', '---\nwrite:\n - Product Manager\n---\n');
101
102
 
102
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
103
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
103
104
  expect(await svc.canWrite(workspaceId, 'felix@example.com', 'Knowledge/Sales/Foo.md')).toBe(true);
104
105
  expect(await svc.canWrite(workspaceId, 'felix@example.com', 'Knowledge/Other/Foo.md')).toBe(false);
105
106
  // Admin grant from root flows through.
@@ -116,7 +117,7 @@ describe('AccessControlService', () => {
116
117
  '---\nwrite:\n - Product Manager\n - deny Felix Kissel <felix@example.com>\n---\n',
117
118
  );
118
119
 
119
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
120
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
120
121
  expect(await svc.canWrite(workspaceId, 'felix@example.com', 'Knowledge/Sales/Foo.md')).toBe(false);
121
122
  expect(await svc.canWrite(workspaceId, 'sara@example.com', 'Knowledge/Sales/Foo.md')).toBe(true);
122
123
  });
@@ -126,7 +127,7 @@ describe('AccessControlService', () => {
126
127
  await writeFile(repo, 'roles.yaml', ROLES_YAML);
127
128
  await writeFile(repo, 'access.md', '---\nwrite:\n - Admin\n - deny Engineer\n---\n');
128
129
 
129
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
130
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
130
131
  // razvan is both Admin and Engineer; Admin grant must still apply.
131
132
  expect(await svc.canWrite(workspaceId, 'razvan@bevel.software', 'Knowledge/Foo.md')).toBe(true);
132
133
  // ali is only Engineer — denied.
@@ -142,7 +143,7 @@ describe('AccessControlService', () => {
142
143
  '---\nwrite:\n - Admin\n - Product Manager\n - Engineer\n---\n',
143
144
  );
144
145
 
145
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
146
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
146
147
  expect(await svc.canWrite(workspaceId, 'razvan@bevel.software', 'roles.yaml')).toBe(true);
147
148
  expect(await svc.canWrite(workspaceId, 'felix@example.com', 'roles.yaml')).toBe(false);
148
149
  expect(await svc.canWrite(workspaceId, 'ali@bevel.software', 'roles.yaml')).toBe(false);
@@ -154,7 +155,7 @@ describe('AccessControlService', () => {
154
155
  await writeFile(repo, 'access.md', '---\nwrite:\n - Admin\n---\n');
155
156
  await writeFile(repo, 'Knowledge/Sales/access.md', '---\nwrite:\n - Product Manager\n---\n');
156
157
 
157
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
158
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
158
159
  const result = await svc.canWriteBatch(workspaceId, 'felix@example.com', [
159
160
  'Knowledge/Sales/A.md',
160
161
  'Knowledge/Other/B.md',
@@ -174,15 +175,16 @@ describe('AccessControlService', () => {
174
175
  '---\nwrite:\n - everyone\ndownload:\n - everyone\nowner:\n - everyone\n---\n',
175
176
  );
176
177
 
177
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
178
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
178
179
  expect(await svc.canWrite(workspaceId, 'nobody@example.com', 'Knowledge/Foo.md')).toBe(true);
179
180
  expect(await svc.canDownload(workspaceId, 'nobody@example.com', 'Knowledge/Foo.md')).toBe(true);
180
181
  expect(await svc.canOwner(workspaceId, 'nobody@example.com', 'Knowledge/Foo.md')).toBe(true);
181
182
  // read is granted via the implicit owner→read fold, not an explicit `read: everyone`.
182
183
  expect(await svc.canRead(workspaceId, 'nobody@example.com', 'Knowledge/Foo.md')).toBe(true);
183
184
 
185
+ // Admin is listed too: the root write floor holds it whatever the root says.
184
186
  const writers = await svc.eligibleWriters(workspaceId, 'Knowledge/Foo.md');
185
- expect(writers.roles).toEqual(['everyone']);
187
+ expect(writers.roles).toEqual(['Admin', 'everyone']);
186
188
  });
187
189
 
188
190
  it('deny everyone can narrow a non-read public grant', async () => {
@@ -195,7 +197,7 @@ describe('AccessControlService', () => {
195
197
  '---\nwrite:\n - deny everyone\n - Product Manager\n---\n',
196
198
  );
197
199
 
198
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
200
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
199
201
  expect(await svc.canWrite(workspaceId, 'nobody@example.com', 'Knowledge/Public.md')).toBe(true);
200
202
  expect(await svc.canWrite(workspaceId, 'nobody@example.com', 'Knowledge/Secret/Foo.md')).toBe(false);
201
203
  expect(await svc.canWrite(workspaceId, 'felix@example.com', 'Knowledge/Secret/Foo.md')).toBe(true);
@@ -207,7 +209,7 @@ describe('AccessControlService', () => {
207
209
  await writeFile(repo, 'access.md', '---\nwrite:\n - everyone\n---\n');
208
210
  await writeFile(repo, 'Knowledge/Secret/access.md', '---\nwrite:\n - deny Engineer\n---\n');
209
211
 
210
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
212
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
211
213
  // everyone grants write at the root; a closer `deny Engineer` carves out
212
214
  // Engineers — a role-level denial, not an email one.
213
215
  expect(await svc.canWrite(workspaceId, 'nobody@example.com', 'Knowledge/Secret/Foo.md')).toBe(true);
@@ -222,7 +224,7 @@ describe('AccessControlService', () => {
222
224
  // A closer scope opens the subtree to everyone (the least specific tier).
223
225
  await writeFile(repo, 'Knowledge/Open/access.md', '---\nread:\n - everyone\n---\n');
224
226
 
225
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
227
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
226
228
  // Closeness wins over tier: the closer `read: everyone` grant beats the
227
229
  // farther by-name deny.
228
230
  expect(await svc.canRead(workspaceId, 'felix@example.com', 'Knowledge/Open/Foo.md')).toBe(true);
@@ -240,7 +242,7 @@ describe('AccessControlService', () => {
240
242
  '---\nread:\n - Ali <ali@bevel.software>\nwrite:\n - Engineer\n - deny Ali <ali@bevel.software>\n---\n',
241
243
  );
242
244
 
243
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
245
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
244
246
  // razvan is an Engineer (write) and has no explicit read grant → can read
245
247
  // solely via the write ⊇ read fold.
246
248
  expect(await svc.canRead(workspaceId, 'razvan@bevel.software', 'Knowledge/Foo.md')).toBe(true);
@@ -264,7 +266,7 @@ describe('AccessControlService', () => {
264
266
  );
265
267
  await writeFile(repo, 'access.md', '---\nwrite:\n - Admin\n---\n');
266
268
 
267
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
269
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
268
270
  await expect(
269
271
  svc.canWrite(workspaceId, 'razvan@bevel.software', 'Knowledge/Foo.md'),
270
272
  ).rejects.toBeInstanceOf(AccessConfigError);
@@ -279,7 +281,7 @@ describe('AccessControlService', () => {
279
281
  '---\nwrite:\n - Admin\n - Felix Kissel <felix@example.com>\n - deny Engineer\n---\n',
280
282
  );
281
283
 
282
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
284
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
283
285
  const e = await svc.eligibleWriters(workspaceId, 'Knowledge/Foo.md');
284
286
  expect(e.roles).toEqual(['Admin']);
285
287
  expect(e.users.map((u) => u.email)).toEqual(['felix@example.com']);
@@ -295,7 +297,7 @@ describe('AccessControlService', () => {
295
297
  const { workspaceDir, repo } = await seedWorkspace(root, workspaceId);
296
298
  await writeFile(repo, 'access.md', '---\nwrite:\n - Admin\n---\n');
297
299
 
298
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
300
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
299
301
  await expect(
300
302
  svc.canWrite(workspaceId, 'razvan@bevel.software', 'Knowledge/Foo.md'),
301
303
  ).rejects.toBeInstanceOf(AccessConfigError);
@@ -313,7 +315,7 @@ describe('AccessControlService', () => {
313
315
  await writeFile(repo, 'roles.yaml', ROLES_YAML);
314
316
  await writeFile(repo, 'access.md', '---\nwrite:\n - Admin\n - Ghost Role\n---\n');
315
317
 
316
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
318
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
317
319
  // Admin grant survives the parse; Ghost Role entry is silently dropped.
318
320
  expect(await svc.canWrite(workspaceId, 'razvan@bevel.software', 'Knowledge/Foo.md')).toBe(true);
319
321
  expect(await svc.canWrite(workspaceId, 'felix@example.com', 'Knowledge/Foo.md')).toBe(false);
@@ -329,7 +331,7 @@ describe('AccessControlService', () => {
329
331
  '---\nwrite:\n - Admin\ndownload:\n - Product Manager\n---\n',
330
332
  );
331
333
 
332
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
334
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
333
335
  expect(await svc.canDownload(workspaceId, 'felix@example.com', 'Knowledge/Foo.md')).toBe(true);
334
336
  expect(await svc.canDownload(workspaceId, 'sara@example.com', 'Knowledge/Foo.md')).toBe(true);
335
337
  });
@@ -339,7 +341,7 @@ describe('AccessControlService', () => {
339
341
  await writeFile(repo, 'roles.yaml', ROLES_YAML);
340
342
  await writeFile(repo, 'access.md', '---\nwrite:\n - Admin\ndownload:\n - Admin\n---\n');
341
343
 
342
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
344
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
343
345
  // ali is an Engineer; neither admin nor download.
344
346
  expect(await svc.canDownload(workspaceId, 'ali@bevel.software', 'Knowledge/Foo.md')).toBe(false);
345
347
  expect(await svc.canDownload(workspaceId, 'unknown@example.com', 'Knowledge/Foo.md')).toBe(false);
@@ -358,7 +360,7 @@ describe('AccessControlService', () => {
358
360
  '---\nwrite:\n - Admin\ndownload:\n - Product Manager\n---\n',
359
361
  );
360
362
 
361
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
363
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
362
364
  expect(await svc.canWrite(workspaceId, 'razvan@bevel.software', 'Knowledge/Foo.md')).toBe(true);
363
365
  expect(await svc.canDownload(workspaceId, 'razvan@bevel.software', 'Knowledge/Foo.md')).toBe(false);
364
366
  });
@@ -373,7 +375,7 @@ describe('AccessControlService', () => {
373
375
  '---\ndownload:\n - Product Manager\n---\n',
374
376
  );
375
377
 
376
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
378
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
377
379
  expect(await svc.canDownload(workspaceId, 'felix@example.com', 'Knowledge/Sales/Foo.md')).toBe(true);
378
380
  expect(await svc.canDownload(workspaceId, 'felix@example.com', 'Knowledge/Other/Foo.md')).toBe(false);
379
381
  });
@@ -384,7 +386,7 @@ describe('AccessControlService', () => {
384
386
  // write only — no download verb anywhere in the tree.
385
387
  await writeFile(repo, 'access.md', '---\nwrite:\n - Admin\n---\n');
386
388
 
387
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
389
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
388
390
  expect(await svc.canDownload(workspaceId, 'razvan@bevel.software', 'Knowledge/Foo.md')).toBe(false);
389
391
  });
390
392
 
@@ -393,7 +395,7 @@ describe('AccessControlService', () => {
393
395
  // surfaces identically to canWrite. The download route catches and
394
396
  // routes through sendError so the caller sees the rich payload.
395
397
  const { workspaceDir } = await seedWorkspace(root, workspaceId);
396
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
398
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
397
399
  await expect(svc.canDownload(workspaceId, 'razvan@bevel.software', 'Knowledge/Foo.md'))
398
400
  .rejects.toBeInstanceOf(AccessConfigError);
399
401
  });
@@ -409,7 +411,7 @@ describe('AccessControlService', () => {
409
411
  '---\nwrite:\n - Admin\ndownload:\n - Product Manager\n - Ana <ana@example.com>\n---\n',
410
412
  );
411
413
 
412
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
414
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
413
415
  const d = await svc.eligibleDownloaders(workspaceId, 'Knowledge/Foo.md');
414
416
  expect(d.roles).toEqual(['Product Manager']);
415
417
  expect(d.users.map((u) => u.email)).toEqual(['ana@example.com']);
@@ -424,7 +426,7 @@ describe('AccessControlService', () => {
424
426
  '---\nowner:\n - Product Manager\n---\n',
425
427
  );
426
428
 
427
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
429
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
428
430
  const d = await svc.eligibleDownloaders(workspaceId, 'Knowledge/Foo.md');
429
431
  expect(d.roles).toEqual(['Product Manager']);
430
432
  });
@@ -434,7 +436,7 @@ describe('AccessControlService', () => {
434
436
  await writeFile(repo, 'roles.yaml', ROLES_YAML);
435
437
  await writeFile(repo, 'access.md', '---\nwrite:\n - Admin\n---\n');
436
438
 
437
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
439
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
438
440
  const d = await svc.eligibleDownloaders(workspaceId, 'Knowledge/Foo.md');
439
441
  expect(d.roles).toEqual([]);
440
442
  expect(d.users).toEqual([]);
@@ -445,7 +447,7 @@ describe('AccessControlService', () => {
445
447
  await writeFile(repo, 'roles.yaml', ROLES_YAML);
446
448
  await writeFile(repo, 'access.md', '---\ndownload:\n - everyone\n---\n');
447
449
 
448
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
450
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
449
451
  const d = await svc.eligibleDownloaders(workspaceId, 'Knowledge/Foo.md');
450
452
  expect(d.roles).toContain('everyone');
451
453
  });
@@ -462,7 +464,7 @@ describe('AccessControlService', () => {
462
464
  '---\nwrite:\n - Admin\nowner:\n - Product Manager\n---\n',
463
465
  );
464
466
 
465
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
467
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
466
468
  // felix is a Product Manager → owner → both write and download.
467
469
  expect(await svc.canWrite(workspaceId, 'felix@example.com', 'Knowledge/Foo.md')).toBe(true);
468
470
  expect(await svc.canDownload(workspaceId, 'felix@example.com', 'Knowledge/Foo.md')).toBe(true);
@@ -474,12 +476,49 @@ describe('AccessControlService', () => {
474
476
  await writeFile(repo, 'roles.yaml', ROLES_YAML);
475
477
  await writeFile(repo, 'access.md', '---\nwrite:\n - Admin\nowner:\n - Product Manager\n---\n');
476
478
 
477
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
479
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
478
480
  // razvan (Admin) can write but is not designated an owner here.
479
481
  expect(await svc.canWrite(workspaceId, 'razvan@bevel.software', 'Knowledge/Foo.md')).toBe(true);
480
482
  expect(await svc.canOwner(workspaceId, 'razvan@bevel.software', 'Knowledge/Foo.md')).toBe(false);
481
483
  });
482
484
 
485
+ it('canOwnerBatch is the Owner pill: owner-listed yes, writers and role-derived Admins no, ownerless nobody', async () => {
486
+ const { workspaceDir, repo } = await seedWorkspace(root, workspaceId);
487
+ await writeFile(repo, 'roles.yaml', ROLES_YAML);
488
+ // Admin writes everywhere by role. `owned` names Product Manager (a role)
489
+ // and ali by email; `ownerless` grants write but no owner at any scope.
490
+ await writeFile(repo, 'access.md', '---\nwrite:\n - Admin\n---\n');
491
+ await writeFile(
492
+ repo,
493
+ 'Skills/owned/access.md',
494
+ '---\nwrite:\n - Engineer\nowner:\n - Product Manager\n - Ali <ali@bevel.software>\n---\n',
495
+ );
496
+ await writeFile(repo, 'Skills/ownerless/access.md', '---\nwrite:\n - Product Manager\n---\n');
497
+ const paths = ['Skills/owned/SKILL.md', 'Skills/ownerless/SKILL.md', 'Tools/weather.tool'];
498
+
499
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
500
+ const verdicts = async (email: string) =>
501
+ Object.fromEntries(await svc.canOwnerBatch(workspaceId, email, paths));
502
+
503
+ // Via a role named in `owner:`, and directly by email.
504
+ expect((await verdicts('felix@example.com'))['Skills/owned/SKILL.md']).toBe(true);
505
+ expect((await verdicts('ali@bevel.software'))['Skills/owned/SKILL.md']).toBe(true);
506
+ // razvan is Admin (+ Engineer): write on all three, owner on none.
507
+ expect(await svc.canWrite(workspaceId, 'razvan@bevel.software', 'Skills/owned/SKILL.md')).toBe(true);
508
+ expect(await verdicts('razvan@bevel.software')).toEqual({
509
+ 'Skills/owned/SKILL.md': false,
510
+ 'Skills/ownerless/SKILL.md': false,
511
+ 'Tools/weather.tool': false,
512
+ });
513
+ // A writer with no owner grant anywhere in scope owns nothing.
514
+ expect(await svc.canWrite(workspaceId, 'sara@example.com', 'Skills/ownerless/SKILL.md')).toBe(true);
515
+ expect((await verdicts('sara@example.com'))['Skills/ownerless/SKILL.md']).toBe(false);
516
+ for (const email of ['felix@example.com', 'ali@bevel.software', 'razvan@bevel.software', 'sara@example.com']) {
517
+ const v = await verdicts(email);
518
+ expect([v['Skills/ownerless/SKILL.md'], v['Tools/weather.tool']]).toEqual([false, false]);
519
+ }
520
+ });
521
+
483
522
  it('owners are folded into the write-eligibility (approval) set', async () => {
484
523
  const { workspaceDir, repo } = await seedWorkspace(root, workspaceId);
485
524
  await writeFile(repo, 'roles.yaml', ROLES_YAML);
@@ -489,7 +528,7 @@ describe('AccessControlService', () => {
489
528
  '---\nwrite:\n - Admin\nowner:\n - Sara Lee <sara@example.com>\n---\n',
490
529
  );
491
530
 
492
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
531
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
493
532
  const writers = await svc.eligibleWriters(workspaceId, 'Knowledge/Foo.md');
494
533
  // Admin role (write) + the owner user both appear — owners can approve.
495
534
  expect(writers.roles).toEqual(['Admin']);
@@ -505,7 +544,7 @@ describe('AccessControlService', () => {
505
544
  '---\nwrite:\n - Admin\nowner:\n - Product Manager\n - Sara Lee <sara@example.com>\n---\n',
506
545
  );
507
546
 
508
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
547
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
509
548
  const owners = await svc.eligibleOwners(workspaceId, 'Knowledge/Foo.md');
510
549
  expect(owners.roles).toEqual(['Product Manager']);
511
550
  expect(owners.users.map((u) => u.email)).toEqual(['sara@example.com']);
@@ -521,7 +560,7 @@ describe('AccessControlService', () => {
521
560
  '---\nowner:\n - Product Manager\n---\n',
522
561
  );
523
562
 
524
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
563
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
525
564
  // felix owns inside Sales → can write + download there, but not elsewhere.
526
565
  expect(await svc.canWrite(workspaceId, 'felix@example.com', 'Knowledge/Sales/Foo.md')).toBe(true);
527
566
  expect(await svc.canDownload(workspaceId, 'felix@example.com', 'Knowledge/Sales/Foo.md')).toBe(true);
@@ -541,7 +580,7 @@ describe('AccessControlService', () => {
541
580
  await writeFile(repo, 'Knowledge/Sales/Foo.md', NODE('owner:\n - Product Manager\n'));
542
581
  await writeFile(repo, 'Knowledge/Sales/Bar.md', NODE(''));
543
582
 
544
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
583
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
545
584
  // Foo's own owner: grant lifts felix to write + download + owner there.
546
585
  expect(await svc.canWrite(workspaceId, 'felix@example.com', 'Knowledge/Sales/Foo.md')).toBe(true);
547
586
  expect(await svc.canDownload(workspaceId, 'felix@example.com', 'Knowledge/Sales/Foo.md')).toBe(true);
@@ -557,7 +596,7 @@ describe('AccessControlService', () => {
557
596
  // Scalar (not a list) — the natural way to name one owner in a node.
558
597
  await writeFile(repo, 'NodeTypes/Process.md', NODE('owner: Test <test@test.com>\n'));
559
598
 
560
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
599
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
561
600
  expect(await svc.canWrite(workspaceId, 'test@test.com', 'NodeTypes/Process.md')).toBe(true);
562
601
  expect(await svc.canDownload(workspaceId, 'test@test.com', 'NodeTypes/Process.md')).toBe(true);
563
602
  expect(await svc.canOwner(workspaceId, 'test@test.com', 'NodeTypes/Process.md')).toBe(true);
@@ -572,7 +611,7 @@ describe('AccessControlService', () => {
572
611
  await writeFile(repo, 'Knowledge/W.md', NODE('write: Product Manager\n'));
573
612
  await writeFile(repo, 'Knowledge/D.md', NODE('download: Felix Kissel <felix@example.com>\n'));
574
613
 
575
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
614
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
576
615
  expect(await svc.canWrite(workspaceId, 'felix@example.com', 'Knowledge/W.md')).toBe(true);
577
616
  // write scalar does not confer download
578
617
  expect(await svc.canDownload(workspaceId, 'felix@example.com', 'Knowledge/W.md')).toBe(false);
@@ -585,7 +624,7 @@ describe('AccessControlService', () => {
585
624
  await writeFile(repo, 'access.md', '---\nwrite:\n - Admin\n---\n');
586
625
  await writeFile(repo, 'Knowledge/Foo.md', NODE('write:\n - Product Manager\n'));
587
626
 
588
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
627
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
589
628
  expect(await svc.canWrite(workspaceId, 'felix@example.com', 'Knowledge/Foo.md')).toBe(true);
590
629
  expect(await svc.canDownload(workspaceId, 'felix@example.com', 'Knowledge/Foo.md')).toBe(false);
591
630
  expect(await svc.canOwner(workspaceId, 'felix@example.com', 'Knowledge/Foo.md')).toBe(false);
@@ -600,7 +639,7 @@ describe('AccessControlService', () => {
600
639
  await writeFile(repo, 'Knowledge/Sales/Foo.md', NODE('write:\n - deny Product Manager\n'));
601
640
  await writeFile(repo, 'Knowledge/Sales/Bar.md', NODE(''));
602
641
 
603
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
642
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
604
643
  expect(await svc.canWrite(workspaceId, 'felix@example.com', 'Knowledge/Sales/Foo.md')).toBe(false);
605
644
  // Sibling still inherits the folder grant.
606
645
  expect(await svc.canWrite(workspaceId, 'felix@example.com', 'Knowledge/Sales/Bar.md')).toBe(true);
@@ -616,7 +655,7 @@ describe('AccessControlService', () => {
616
655
  NODE('owner:\n - Sara Lee <sara@example.com>\n'),
617
656
  );
618
657
 
619
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
658
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
620
659
  const writers = await svc.eligibleWriters(workspaceId, 'Knowledge/Foo.md');
621
660
  // Admin (folder write) + the per-file owner can both approve this file.
622
661
  expect(writers.roles).toEqual(['Admin']);
@@ -634,7 +673,7 @@ describe('AccessControlService', () => {
634
673
  // Only nodeType in frontmatter — no access verbs → folder rule applies.
635
674
  await writeFile(repo, 'Knowledge/Foo.md', NODE(''));
636
675
 
637
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
676
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
638
677
  expect(await svc.canWrite(workspaceId, 'razvan@bevel.software', 'Knowledge/Foo.md')).toBe(true);
639
678
  expect(await svc.canWrite(workspaceId, 'felix@example.com', 'Knowledge/Foo.md')).toBe(false);
640
679
  });
@@ -646,7 +685,7 @@ describe('AccessControlService', () => {
646
685
  // Plain free-form note — no leading `---` block whatsoever.
647
686
  await writeFile(repo, 'Knowledge/Plain.md', '# Just a note\n\nSome prose, no frontmatter.\n');
648
687
 
649
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
688
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
650
689
  // Folder rule (Admin) still governs; no per-file override, no throw.
651
690
  expect(await svc.canWrite(workspaceId, 'razvan@bevel.software', 'Knowledge/Plain.md')).toBe(true);
652
691
  expect(await svc.canWrite(workspaceId, 'felix@example.com', 'Knowledge/Plain.md')).toBe(false);
@@ -659,7 +698,7 @@ describe('AccessControlService', () => {
659
698
  await writeFile(repo, 'roles.yaml', ROLES_YAML);
660
699
  await writeFile(repo, 'access.md', '---\nwrite:\n - Admin\n---\n');
661
700
 
662
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
701
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
663
702
  // No Ghost.md on disk — readOwnEntries swallows the ENOENT and falls back.
664
703
  expect(await svc.canWrite(workspaceId, 'razvan@bevel.software', 'Knowledge/Ghost.md')).toBe(true);
665
704
  expect(await svc.canWrite(workspaceId, 'felix@example.com', 'Knowledge/Ghost.md')).toBe(false);
@@ -677,7 +716,7 @@ describe('AccessControlService', () => {
677
716
  '---\nwrite:\n - Admin\narchive:\n - Admin\nnotes: skip-me\n---\n',
678
717
  );
679
718
 
680
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
719
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
681
720
  expect(await svc.canWrite(workspaceId, 'razvan@bevel.software', 'Knowledge/Foo.md')).toBe(true);
682
721
  expect(await svc.canWrite(workspaceId, 'felix@example.com', 'Knowledge/Foo.md')).toBe(false);
683
722
  });
@@ -694,7 +733,7 @@ describe('AccessControlService', () => {
694
733
  '---\nwrite:\n - Admin\n - Ghost Role\n---\n',
695
734
  );
696
735
 
697
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
736
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
698
737
  // Admin still has write (Ghost Role entry was dropped, Admin remained).
699
738
  expect(await svc.canWrite(workspaceId, 'razvan@bevel.software', 'Knowledge/Foo.md')).toBe(true);
700
739
  });
@@ -706,7 +745,7 @@ describe('AccessControlService', () => {
706
745
  await writeFile(repo, 'roles.yaml', ROLES_YAML);
707
746
  await writeFile(repo, 'access.md', '---\nwrite: not-a-list\n---\n');
708
747
 
709
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
748
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
710
749
  // Default-deny for non-admins on the rest of the tree (no rules in force),
711
750
  // but admins keep their rescue.
712
751
  expect(await svc.canWrite(workspaceId, 'razvan@bevel.software', 'access.md')).toBe(true);
@@ -723,7 +762,7 @@ describe('AccessControlService', () => {
723
762
  // Note: Admin NOT in write list.
724
763
  await writeFile(repo, 'access.md', '---\nwrite:\n - Product Manager\n---\n');
725
764
 
726
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
765
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
727
766
  expect(await svc.canWrite(workspaceId, 'razvan@bevel.software', 'access.md')).toBe(true);
728
767
  // Non-admins still gated normally.
729
768
  expect(await svc.canWrite(workspaceId, 'ali@bevel.software', 'access.md')).toBe(false);
@@ -740,7 +779,7 @@ describe('AccessControlService', () => {
740
779
  '---\nwrite:\n - Product Manager\n---\n',
741
780
  );
742
781
 
743
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
782
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
744
783
  expect(await svc.canWrite(workspaceId, 'razvan@bevel.software', 'Knowledge/Sales/access.md')).toBe(true);
745
784
  });
746
785
 
@@ -749,7 +788,7 @@ describe('AccessControlService', () => {
749
788
  await writeFile(repo, 'roles.yaml', ROLES_YAML);
750
789
  await writeFile(repo, 'access.md', '---\nwrite:\n - Admin\ndownload:\n - Product Manager\n---\n');
751
790
 
752
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
791
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
753
792
  // Admin still can't download access.md — they aren't listed under download.
754
793
  expect(await svc.canDownload(workspaceId, 'razvan@bevel.software', 'access.md')).toBe(false);
755
794
  });
@@ -760,7 +799,7 @@ describe('AccessControlService', () => {
760
799
  await writeFile(repo, 'roles.yaml', ROLES_YAML);
761
800
  await writeFile(repo, 'access.md', '---\nwrite:\n - Admin\n---\n');
762
801
 
763
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
802
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
764
803
  expect(await svc.canWrite(workspaceId, 'felix@example.com', 'Knowledge/Foo.md')).toBe(false);
765
804
 
766
805
  // Broaden access — but cache will still say false until we invalidate.
@@ -777,7 +816,7 @@ describe('AccessControlService', () => {
777
816
  await writeFile(repo, 'roles.yaml', ROLES_YAML);
778
817
  await writeFile(repo, 'access.md', '---\nwrite:\n - Admin\n---\n');
779
818
 
780
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
819
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
781
820
  expect(await svc.canRead(workspaceId, 'felix@example.com', 'Knowledge/Foo.md')).toBe(false);
782
821
  expect(await svc.canRead(workspaceId, 'nobody@example.com', 'Knowledge/Foo.md')).toBe(false);
783
822
  // razvan is Admin, so the root `write: Admin` confers read (write ⊇ read).
@@ -789,7 +828,7 @@ describe('AccessControlService', () => {
789
828
  await writeFile(repo, 'roles.yaml', ROLES_YAML);
790
829
  await writeFile(repo, 'access.md', '---\nwrite:\n - Admin\nread:\n - everyone\n---\n');
791
830
 
792
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
831
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
793
832
  expect(await svc.canRead(workspaceId, 'felix@example.com', 'Knowledge/Foo.md')).toBe(true);
794
833
  expect(await svc.canRead(workspaceId, 'nobody@example.com', 'Knowledge/Foo.md')).toBe(true);
795
834
  });
@@ -804,7 +843,7 @@ describe('AccessControlService', () => {
804
843
  await writeFile(repo, 'access.md', '---\nwrite:\n - Admin\nread:\n - everyone\n---\n');
805
844
  await writeFile(repo, 'Knowledge/Secret/access.md', '---\nread:\n - deny Product Manager\n---\n');
806
845
 
807
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
846
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
808
847
  // felix is a Product Manager, denied at the closer child scope → no read.
809
848
  expect(await svc.canRead(workspaceId, 'felix@example.com', 'Knowledge/Secret/Foo.md')).toBe(false);
810
849
  // A user with no roles has no verdict at the child scope, so resolution
@@ -818,7 +857,7 @@ describe('AccessControlService', () => {
818
857
  await writeFile(repo, 'access.md', '---\nwrite:\n - Admin\n---\n');
819
858
  await writeFile(repo, 'Knowledge/Sales/access.md', '---\nread:\n - Product Manager\n---\n');
820
859
 
821
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
860
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
822
861
  // Inside the restricted subtree: only Product Managers may read.
823
862
  expect(await svc.canRead(workspaceId, 'felix@example.com', 'Knowledge/Sales/Foo.md')).toBe(true);
824
863
  expect(await svc.canRead(workspaceId, 'ali@bevel.software', 'Knowledge/Sales/Foo.md')).toBe(false);
@@ -836,7 +875,7 @@ describe('AccessControlService', () => {
836
875
  '---\nread:\n - deny everyone\n - Product Manager\n---\n',
837
876
  );
838
877
 
839
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
878
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
840
879
  expect(await svc.canRead(workspaceId, 'nobody@example.com', 'Knowledge/Public.md')).toBe(true);
841
880
  expect(await svc.canRead(workspaceId, 'ali@bevel.software', 'Knowledge/Secret/Foo.md')).toBe(false);
842
881
  expect(await svc.canRead(workspaceId, 'felix@example.com', 'Knowledge/Secret/Foo.md')).toBe(true);
@@ -848,7 +887,7 @@ describe('AccessControlService', () => {
848
887
  await writeFile(repo, 'access.md', '---\nwrite:\n - Admin\n---\n');
849
888
  await writeFile(repo, 'Knowledge/Secret/access.md', '---\nread:\n - Product Manager\n---\n');
850
889
 
851
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
890
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
852
891
  // The leaf directory is included in the chain, so its own access.md applies
853
892
  // to the folder node — not just to files beneath it.
854
893
  expect(await svc.canRead(workspaceId, 'felix@example.com', 'Knowledge/Secret')).toBe(true);
@@ -865,7 +904,7 @@ describe('AccessControlService', () => {
865
904
  '---\nwrite:\n - Admin\nread:\n - Admin\nowner:\n - Felix Kissel <felix@example.com>\n---\n',
866
905
  );
867
906
 
868
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
907
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
869
908
  expect(await svc.canRead(workspaceId, 'felix@example.com', 'Knowledge/Foo.md')).toBe(true); // owner → read
870
909
  expect(await svc.canRead(workspaceId, 'razvan@bevel.software', 'Knowledge/Foo.md')).toBe(true); // Admin
871
910
  expect(await svc.canRead(workspaceId, 'sara@example.com', 'Knowledge/Foo.md')).toBe(false); // neither
@@ -880,7 +919,7 @@ describe('AccessControlService', () => {
880
919
  '---\nwrite:\n - Admin\nread:\n - Product Manager\n - deny Felix Kissel <felix@example.com>\n---\n',
881
920
  );
882
921
 
883
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
922
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
884
923
  expect(await svc.canRead(workspaceId, 'felix@example.com', 'Knowledge/Foo.md')).toBe(false);
885
924
  expect(await svc.canRead(workspaceId, 'sara@example.com', 'Knowledge/Foo.md')).toBe(true);
886
925
  });
@@ -892,7 +931,7 @@ describe('AccessControlService', () => {
892
931
  // writer here, so there's no rescue path to read (unlike write on access.md).
893
932
  await writeFile(repo, 'access.md', '---\nwrite:\n - Product Manager\nread:\n - Product Manager\n---\n');
894
933
 
895
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
934
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
896
935
  // razvan is Admin but not a Product Manager — restricted read denies him.
897
936
  expect(await svc.canRead(workspaceId, 'razvan@bevel.software', 'Knowledge/Foo.md')).toBe(false);
898
937
  });
@@ -906,7 +945,7 @@ describe('AccessControlService', () => {
906
945
  await writeFile(repo, 'Knowledge/Secret.md', NODE('read:\n - Product Manager\n'));
907
946
  await writeFile(repo, 'Knowledge/Plain.md', NODE(''));
908
947
 
909
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
948
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
910
949
  expect(await svc.canRead(workspaceId, 'felix@example.com', 'Knowledge/Secret.md')).toBe(true);
911
950
  expect(await svc.canRead(workspaceId, 'ali@bevel.software', 'Knowledge/Secret.md')).toBe(false);
912
951
  // The sibling without a read: rule remains default-denied.
@@ -919,7 +958,7 @@ describe('AccessControlService', () => {
919
958
  await writeFile(repo, 'access.md', '---\nwrite:\n - Admin\n---\n');
920
959
  await writeFile(repo, 'Knowledge/Sales/access.md', '---\nread:\n - Product Manager\n---\n');
921
960
 
922
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
961
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
923
962
  const result = await svc.canReadBatch(workspaceId, 'ali@bevel.software', [
924
963
  'Knowledge/Open.md',
925
964
  'Knowledge/Sales/Restricted.md',
@@ -934,7 +973,7 @@ describe('AccessControlService', () => {
934
973
  await writeFile(repo, 'access.md', '---\nwrite:\n - Admin\nread:\n - everyone\n---\n');
935
974
  await writeFile(repo, 'Knowledge/Sales/access.md', '---\nread:\n - deny everyone\n - Product Manager\n---\n');
936
975
 
937
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
976
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
938
977
  const result = await svc.canReadBatch(workspaceId, 'ali@bevel.software', [
939
978
  'Knowledge/Open.md',
940
979
  'Knowledge/Sales/Restricted.md',
@@ -947,11 +986,12 @@ describe('AccessControlService', () => {
947
986
  it('reports restricted=true with no readers for a default-denied node', async () => {
948
987
  const { workspaceDir, repo } = await seedWorkspace(root, workspaceId);
949
988
  await writeFile(repo, 'roles.yaml', ROLES_YAML);
950
- // Only `download` is granted — it does not confer read (read ⊄ download),
951
- // so no principal can read this node.
952
- await writeFile(repo, 'access.md', '---\ndownload:\n - Admin\n---\n');
989
+ // The only line in the tree is a DENIAL — a denial grants nobody, and
990
+ // no verb that folds into read grants anyone either, so the node is
991
+ // default-denied with no readers to name.
992
+ await writeFile(repo, 'access.md', '---\nread:\n - deny everyone\n---\n');
953
993
 
954
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
994
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
955
995
  const e = await svc.eligibleReaders(workspaceId, 'Knowledge/Foo.md');
956
996
  expect(e).toEqual({ restricted: true, principals: [], roles: [], users: [], publicVia: [] });
957
997
  });
@@ -961,7 +1001,7 @@ describe('AccessControlService', () => {
961
1001
  await writeFile(repo, 'roles.yaml', ROLES_YAML);
962
1002
  await writeFile(repo, 'access.md', '---\nwrite:\n - Admin\nread:\n - everyone\n---\n');
963
1003
 
964
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
1004
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
965
1005
  const e = await svc.eligibleReaders(workspaceId, 'Knowledge/Foo.md');
966
1006
  // The flag says public; the lists still name the grants (write folds into read).
967
1007
  expect(e).toEqual({
@@ -983,7 +1023,7 @@ describe('AccessControlService', () => {
983
1023
  await writeFile(repo, 'access.md', '---\nread:\n - deny Felix Kissel <felix@example.com>\n---\n');
984
1024
  await writeFile(repo, 'Knowledge/Open/access.md', '---\nread:\n - everyone\n---\n');
985
1025
 
986
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
1026
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
987
1027
  // felix actually reads here (the closer everyone grant wins), so the
988
1028
  // node really is readable by everyone — not restricted.
989
1029
  expect(await svc.canRead(workspaceId, 'felix@example.com', 'Knowledge/Open/Foo.md')).toBe(true);
@@ -1006,7 +1046,7 @@ describe('AccessControlService', () => {
1006
1046
  '---\nread:\n - everyone\n - deny Felix Kissel <felix@example.com>\n---\n',
1007
1047
  );
1008
1048
 
1009
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
1049
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
1010
1050
  // felix is carved out (email tier beats everyone within the scope), so
1011
1051
  // it's not readable by *everyone*.
1012
1052
  expect(await svc.canRead(workspaceId, 'felix@example.com', 'Knowledge/Foo.md')).toBe(false);
@@ -1022,7 +1062,7 @@ describe('AccessControlService', () => {
1022
1062
  '---\nwrite:\n - Admin\nread:\n - Product Manager\nowner:\n - Ada Lovelace <ada@example.com>\n---\n',
1023
1063
  );
1024
1064
 
1025
- const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
1065
+ const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR, new NodeFs());
1026
1066
  const e = await svc.eligibleReaders(workspaceId, 'Knowledge/Foo.md');
1027
1067
  expect(e.restricted).toBe(true);
1028
1068
  expect(e.roles).toContain('Product Manager');
@@ -1063,30 +1103,35 @@ describe('AccessControlService', () => {
1063
1103
 
1064
1104
  it('may write roles.yaml even when roles.yaml does not list them', async () => {
1065
1105
  const ws = await seeded();
1066
- const svc = new AccessControlService(ws, PROCESS_MAP_DIR, [OWNER]);
1106
+ const svc = new AccessControlService(ws, PROCESS_MAP_DIR, new NodeFs(), [OWNER]);
1067
1107
  expect(await svc.canWrite(workspaceId, OWNER, 'roles.yaml')).toBe(true);
1068
1108
  });
1069
1109
 
1070
1110
  it('may write an access.md — the same rescue the Admin role gets', async () => {
1071
1111
  const ws = await seeded();
1072
- const svc = new AccessControlService(ws, PROCESS_MAP_DIR, [OWNER]);
1112
+ const svc = new AccessControlService(ws, PROCESS_MAP_DIR, new NodeFs(), [OWNER]);
1073
1113
  expect(await svc.canWrite(workspaceId, OWNER, 'Knowledge/access.md')).toBe(true);
1074
1114
  });
1075
1115
 
1076
1116
  /**
1077
- * The rescue is exactly two files wide. It is not a general grant: the
1078
- * owner is admitted to the hardcoded `write` overrides and to nothing
1079
- * else, so ordinary content still answers to the access tree.
1117
+ * Beyond the two rescue files, the owner gets exactly what the Admin role
1118
+ * gets: the root write floor, and nothing a nearer rule takes away. Read
1119
+ * and download still answer to the access tree.
1080
1120
  */
1081
- it('gets no ordinary write from being the owner', async () => {
1121
+ it('gets write only through the root floor, never past a subfolder that excludes Admin', async () => {
1082
1122
  const ws = await seeded();
1083
- const svc = new AccessControlService(ws, PROCESS_MAP_DIR, [OWNER]);
1084
- expect(await svc.canWrite(workspaceId, OWNER, 'Knowledge/Foo.md')).toBe(false);
1123
+ const { repo } = await seedWorkspace(root, workspaceId);
1124
+ await writeFile(repo, 'HR/access.md', '---\nwrite:\n - deny Admin\n---\n');
1125
+ const svc = new AccessControlService(ws, PROCESS_MAP_DIR, new NodeFs(), [OWNER]);
1126
+ expect(await svc.canWrite(workspaceId, OWNER, 'Knowledge/Foo.md')).toBe(true);
1127
+ expect(await svc.canWrite(workspaceId, OWNER, 'HR/Salaries.md')).toBe(false);
1128
+ expect(await svc.canRead(workspaceId, OWNER, 'Knowledge/Foo.md')).toBe(false);
1129
+ expect(await svc.canDownload(workspaceId, OWNER, 'Knowledge/Foo.md')).toBe(false);
1085
1130
  });
1086
1131
 
1087
1132
  it('is matched case-insensitively, like every other email here', async () => {
1088
1133
  const ws = await seeded();
1089
- const svc = new AccessControlService(ws, PROCESS_MAP_DIR, ['OWNER@Bevel.Software']);
1134
+ const svc = new AccessControlService(ws, PROCESS_MAP_DIR, new NodeFs(), ['OWNER@Bevel.Software']);
1090
1135
  expect(await svc.canWrite(workspaceId, OWNER, 'roles.yaml')).toBe(true);
1091
1136
  });
1092
1137
 
@@ -1097,7 +1142,7 @@ describe('AccessControlService', () => {
1097
1142
  */
1098
1143
  it('changes nothing when no owner is configured', async () => {
1099
1144
  const ws = await seeded();
1100
- const svc = new AccessControlService(ws, PROCESS_MAP_DIR);
1145
+ const svc = new AccessControlService(ws, PROCESS_MAP_DIR, new NodeFs());
1101
1146
  expect(await svc.canWrite(workspaceId, OWNER, 'roles.yaml')).toBe(false);
1102
1147
  expect(await svc.canWrite(workspaceId, 'someone-else@example.com', 'roles.yaml')).toBe(true);
1103
1148
  });