@bevel-software/platform-core-backend 0.33.0 → 0.35.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 (602) hide show
  1. package/agent-guide/access-control.md +146 -289
  2. package/agent-guide/conventions.md +23 -25
  3. package/agent-guide/directory-structure.md +72 -120
  4. package/agent-guide/drafts-and-change-requests.md +92 -0
  5. package/agent-guide/for-git-users.md +47 -0
  6. package/agent-guide/glossary.md +36 -0
  7. package/agent-guide/how-agents-find-things.md +49 -0
  8. package/agent-guide/html-views.md +239 -8
  9. package/agent-guide/new-knowledge-base.md +9 -8
  10. package/agent-guide/skills.md +67 -42
  11. package/agent-guide/start-here.md +65 -0
  12. package/agent-guide/tool-manuals.md +133 -155
  13. package/agent-guide/tools.md +67 -0
  14. package/agent-guide/where-a-new-file-goes.md +45 -28
  15. package/dist/core/catalog-revision.d.ts +12 -1
  16. package/dist/core/catalog-revision.d.ts.map +1 -1
  17. package/dist/core/catalog-revision.js +23 -3
  18. package/dist/core/catalog-revision.js.map +1 -1
  19. package/dist/core/core-ports.d.ts +41 -0
  20. package/dist/core/core-ports.d.ts.map +1 -1
  21. package/dist/core/core-ports.js.map +1 -1
  22. package/dist/core/create-core-server.d.ts.map +1 -1
  23. package/dist/core/create-core-server.js +15 -8
  24. package/dist/core/create-core-server.js.map +1 -1
  25. package/dist/core/create-core-services.d.ts +22 -5
  26. package/dist/core/create-core-services.d.ts.map +1 -1
  27. package/dist/core/create-core-services.js +44 -16
  28. package/dist/core/create-core-services.js.map +1 -1
  29. package/dist/core/lifecycle.d.ts +16 -0
  30. package/dist/core/lifecycle.d.ts.map +1 -1
  31. package/dist/core/lifecycle.js +12 -2
  32. package/dist/core/lifecycle.js.map +1 -1
  33. package/dist/index.d.ts +1 -1
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/index.js.map +1 -1
  36. package/dist/modules/access/access-control.interface.d.ts +39 -9
  37. package/dist/modules/access/access-control.interface.d.ts.map +1 -1
  38. package/dist/modules/access/access-control.service.d.ts +15 -3
  39. package/dist/modules/access/access-control.service.d.ts.map +1 -1
  40. package/dist/modules/access/access-control.service.js +239 -75
  41. package/dist/modules/access/access-control.service.js.map +1 -1
  42. package/dist/modules/access/access-mutation.service.d.ts +22 -24
  43. package/dist/modules/access/access-mutation.service.d.ts.map +1 -1
  44. package/dist/modules/access/access-mutation.service.js +48 -51
  45. package/dist/modules/access/access-mutation.service.js.map +1 -1
  46. package/dist/modules/access/access-view.d.ts.map +1 -1
  47. package/dist/modules/access/access-view.js +12 -11
  48. package/dist/modules/access/access-view.js.map +1 -1
  49. package/dist/modules/access/access.routes.d.ts +3 -0
  50. package/dist/modules/access/access.routes.d.ts.map +1 -1
  51. package/dist/modules/access/access.routes.js +58 -33
  52. package/dist/modules/access/access.routes.js.map +1 -1
  53. package/dist/modules/access/groups-admin.routes.d.ts.map +1 -1
  54. package/dist/modules/access/groups-admin.routes.js +4 -2
  55. package/dist/modules/access/groups-admin.routes.js.map +1 -1
  56. package/dist/modules/access/groups-admin.service.d.ts +44 -13
  57. package/dist/modules/access/groups-admin.service.d.ts.map +1 -1
  58. package/dist/modules/access/groups-admin.service.js +80 -38
  59. package/dist/modules/access/groups-admin.service.js.map +1 -1
  60. package/dist/modules/access/groups-edit.d.ts +1 -1
  61. package/dist/modules/access/groups-edit.d.ts.map +1 -1
  62. package/dist/modules/access/groups-edit.js +1 -1
  63. package/dist/modules/access/groups-edit.js.map +1 -1
  64. package/dist/modules/access/index.d.ts +1 -1
  65. package/dist/modules/access/index.d.ts.map +1 -1
  66. package/dist/modules/access/reference-scan.d.ts +116 -24
  67. package/dist/modules/access/reference-scan.d.ts.map +1 -1
  68. package/dist/modules/access/reference-scan.js +305 -44
  69. package/dist/modules/access/reference-scan.js.map +1 -1
  70. package/dist/modules/access/roles-admin.service.d.ts +17 -8
  71. package/dist/modules/access/roles-admin.service.d.ts.map +1 -1
  72. package/dist/modules/access/roles-admin.service.js +32 -23
  73. package/dist/modules/access/roles-admin.service.js.map +1 -1
  74. package/dist/modules/access-model/access-grammar.d.ts +35 -10
  75. package/dist/modules/access-model/access-grammar.d.ts.map +1 -1
  76. package/dist/modules/access-model/access-grammar.js +60 -20
  77. package/dist/modules/access-model/access-grammar.js.map +1 -1
  78. package/dist/modules/access-model/access-splice.d.ts +22 -18
  79. package/dist/modules/access-model/access-splice.d.ts.map +1 -1
  80. package/dist/modules/access-model/access-splice.js +20 -14
  81. package/dist/modules/access-model/access-splice.js.map +1 -1
  82. package/dist/modules/access-model/group-files.d.ts +1 -0
  83. package/dist/modules/access-model/group-files.d.ts.map +1 -1
  84. package/dist/modules/access-model/group-files.js +5 -1
  85. package/dist/modules/access-model/group-files.js.map +1 -1
  86. package/dist/modules/agent-guide/agent-guide.d.ts +47 -7
  87. package/dist/modules/agent-guide/agent-guide.d.ts.map +1 -1
  88. package/dist/modules/agent-guide/agent-guide.js +103 -13
  89. package/dist/modules/agent-guide/agent-guide.js.map +1 -1
  90. package/dist/modules/agent-guide/agent-guide.tools.d.ts +6 -2
  91. package/dist/modules/agent-guide/agent-guide.tools.d.ts.map +1 -1
  92. package/dist/modules/agent-guide/agent-guide.tools.js +46 -22
  93. package/dist/modules/agent-guide/agent-guide.tools.js.map +1 -1
  94. package/dist/modules/agent-guide/guide-budget.d.ts +48 -0
  95. package/dist/modules/agent-guide/guide-budget.d.ts.map +1 -0
  96. package/dist/modules/agent-guide/guide-budget.js +67 -0
  97. package/dist/modules/agent-guide/guide-budget.js.map +1 -0
  98. package/dist/modules/agent-guide/index.d.ts +2 -1
  99. package/dist/modules/agent-guide/index.d.ts.map +1 -1
  100. package/dist/modules/agent-guide/index.js +2 -1
  101. package/dist/modules/agent-guide/index.js.map +1 -1
  102. package/dist/modules/agent-instructions/compose.d.ts +3 -1
  103. package/dist/modules/agent-instructions/compose.d.ts.map +1 -1
  104. package/dist/modules/agent-instructions/compose.js +7 -1
  105. package/dist/modules/agent-instructions/compose.js.map +1 -1
  106. package/dist/modules/agent-instructions/shared-file-rules.d.ts +5 -1
  107. package/dist/modules/agent-instructions/shared-file-rules.d.ts.map +1 -1
  108. package/dist/modules/agent-instructions/shared-file-rules.js +26 -9
  109. package/dist/modules/agent-instructions/shared-file-rules.js.map +1 -1
  110. package/dist/modules/agent-scope/agent-scope.contract.d.ts +67 -0
  111. package/dist/modules/agent-scope/agent-scope.contract.d.ts.map +1 -0
  112. package/dist/modules/agent-scope/agent-scope.contract.js +27 -0
  113. package/dist/modules/agent-scope/agent-scope.contract.js.map +1 -0
  114. package/dist/modules/agent-scope/connection-scope.d.ts +111 -0
  115. package/dist/modules/agent-scope/connection-scope.d.ts.map +1 -0
  116. package/dist/modules/agent-scope/connection-scope.js +165 -0
  117. package/dist/modules/agent-scope/connection-scope.js.map +1 -0
  118. package/dist/modules/agent-scope/index.d.ts +3 -0
  119. package/dist/modules/agent-scope/index.d.ts.map +1 -0
  120. package/dist/modules/agent-scope/index.js +3 -0
  121. package/dist/modules/agent-scope/index.js.map +1 -0
  122. package/dist/modules/audit/agent-audit.service.d.ts.map +1 -1
  123. package/dist/modules/audit/agent-audit.service.js +2 -0
  124. package/dist/modules/audit/agent-audit.service.js.map +1 -1
  125. package/dist/modules/audit/audit.contract.d.ts +6 -0
  126. package/dist/modules/audit/audit.contract.d.ts.map +1 -1
  127. package/dist/modules/audit/audit.contract.js.map +1 -1
  128. package/dist/modules/auth/account-admission.d.ts +12 -0
  129. package/dist/modules/auth/account-admission.d.ts.map +1 -1
  130. package/dist/modules/auth/account-admission.js +15 -0
  131. package/dist/modules/auth/account-admission.js.map +1 -1
  132. package/dist/modules/auth/auth.middleware.d.ts +27 -1
  133. package/dist/modules/auth/auth.middleware.d.ts.map +1 -1
  134. package/dist/modules/auth/auth.middleware.js +42 -4
  135. package/dist/modules/auth/auth.middleware.js.map +1 -1
  136. package/dist/modules/auth/auth.routes.d.ts +13 -9
  137. package/dist/modules/auth/auth.routes.d.ts.map +1 -1
  138. package/dist/modules/auth/auth.routes.js +35 -29
  139. package/dist/modules/auth/auth.routes.js.map +1 -1
  140. package/dist/modules/auth/auth.service.d.ts +55 -6
  141. package/dist/modules/auth/auth.service.d.ts.map +1 -1
  142. package/dist/modules/auth/auth.service.js +128 -34
  143. package/dist/modules/auth/auth.service.js.map +1 -1
  144. package/dist/modules/auth/index.d.ts +1 -1
  145. package/dist/modules/auth/index.d.ts.map +1 -1
  146. package/dist/modules/auth/index.js +1 -1
  147. package/dist/modules/auth/index.js.map +1 -1
  148. package/dist/modules/auth/oidc-auth-provider.d.ts.map +1 -1
  149. package/dist/modules/auth/oidc-auth-provider.js +2 -9
  150. package/dist/modules/auth/oidc-auth-provider.js.map +1 -1
  151. package/dist/modules/code-mode/code-mode.tool.js +2 -2
  152. package/dist/modules/code-mode/code-mode.tool.js.map +1 -1
  153. package/dist/modules/connection-probe/connection-probe.service.d.ts +0 -12
  154. package/dist/modules/connection-probe/connection-probe.service.d.ts.map +1 -1
  155. package/dist/modules/connection-probe/connection-probe.service.js +1 -38
  156. package/dist/modules/connection-probe/connection-probe.service.js.map +1 -1
  157. package/dist/modules/database/core-schema.d.ts +68 -0
  158. package/dist/modules/database/core-schema.d.ts.map +1 -1
  159. package/dist/modules/database/core-schema.js +33 -0
  160. package/dist/modules/database/core-schema.js.map +1 -1
  161. package/dist/modules/declared-variables/declared-variables.routes.d.ts +8 -1
  162. package/dist/modules/declared-variables/declared-variables.routes.d.ts.map +1 -1
  163. package/dist/modules/declared-variables/declared-variables.routes.js +13 -2
  164. package/dist/modules/declared-variables/declared-variables.routes.js.map +1 -1
  165. package/dist/modules/embed/embed.tools.d.ts.map +1 -1
  166. package/dist/modules/embed/embed.tools.js +5 -0
  167. package/dist/modules/embed/embed.tools.js.map +1 -1
  168. package/dist/modules/kb-fs/index.d.ts +2 -0
  169. package/dist/modules/kb-fs/index.d.ts.map +1 -1
  170. package/dist/modules/kb-fs/index.js +1 -0
  171. package/dist/modules/kb-fs/index.js.map +1 -1
  172. package/dist/modules/kb-fs/locking-filesystem.d.ts.map +1 -1
  173. package/dist/modules/kb-fs/locking-filesystem.js +7 -1
  174. package/dist/modules/kb-fs/locking-filesystem.js.map +1 -1
  175. package/dist/modules/kb-fs/repo-path.d.ts +26 -6
  176. package/dist/modules/kb-fs/repo-path.d.ts.map +1 -1
  177. package/dist/modules/kb-fs/repo-path.js +22 -7
  178. package/dist/modules/kb-fs/repo-path.js.map +1 -1
  179. package/dist/modules/kb-fs/tmp-ref.d.ts +36 -0
  180. package/dist/modules/kb-fs/tmp-ref.d.ts.map +1 -0
  181. package/dist/modules/kb-fs/tmp-ref.js +76 -0
  182. package/dist/modules/kb-fs/tmp-ref.js.map +1 -0
  183. package/dist/modules/mcp/mcp-auth.middleware.d.ts +7 -0
  184. package/dist/modules/mcp/mcp-auth.middleware.d.ts.map +1 -1
  185. package/dist/modules/mcp/mcp-auth.middleware.js +14 -1
  186. package/dist/modules/mcp/mcp-auth.middleware.js.map +1 -1
  187. package/dist/modules/mcp/mcp.routes.d.ts +7 -1
  188. package/dist/modules/mcp/mcp.routes.d.ts.map +1 -1
  189. package/dist/modules/mcp/mcp.routes.js +39 -4
  190. package/dist/modules/mcp/mcp.routes.js.map +1 -1
  191. package/dist/modules/mcp/mcp.service.d.ts +11 -0
  192. package/dist/modules/mcp/mcp.service.d.ts.map +1 -1
  193. package/dist/modules/mcp/mcp.service.js +74 -48
  194. package/dist/modules/mcp/mcp.service.js.map +1 -1
  195. package/dist/modules/mcp/oauth/bevel-oauth-provider.d.ts +24 -1
  196. package/dist/modules/mcp/oauth/bevel-oauth-provider.d.ts.map +1 -1
  197. package/dist/modules/mcp/oauth/bevel-oauth-provider.js +45 -10
  198. package/dist/modules/mcp/oauth/bevel-oauth-provider.js.map +1 -1
  199. package/dist/modules/mcp/oauth/oauth-consent.routes.d.ts +9 -0
  200. package/dist/modules/mcp/oauth/oauth-consent.routes.d.ts.map +1 -1
  201. package/dist/modules/mcp/oauth/oauth-consent.routes.js +34 -1
  202. package/dist/modules/mcp/oauth/oauth-consent.routes.js.map +1 -1
  203. package/dist/modules/plugins/index.d.ts +1 -1
  204. package/dist/modules/plugins/index.d.ts.map +1 -1
  205. package/dist/modules/plugins/index.js.map +1 -1
  206. package/dist/modules/plugins/plugin-links.d.ts +18 -2
  207. package/dist/modules/plugins/plugin-links.d.ts.map +1 -1
  208. package/dist/modules/plugins/plugin-links.js.map +1 -1
  209. package/dist/modules/plugins/plugins.routes.d.ts +5 -1
  210. package/dist/modules/plugins/plugins.routes.d.ts.map +1 -1
  211. package/dist/modules/plugins/plugins.routes.js +32 -5
  212. package/dist/modules/plugins/plugins.routes.js.map +1 -1
  213. package/dist/modules/secrets-vault/db-secrets-vault.service.d.ts +11 -1
  214. package/dist/modules/secrets-vault/db-secrets-vault.service.d.ts.map +1 -1
  215. package/dist/modules/secrets-vault/db-secrets-vault.service.js +159 -24
  216. package/dist/modules/secrets-vault/db-secrets-vault.service.js.map +1 -1
  217. package/dist/modules/secrets-vault/index.d.ts +1 -1
  218. package/dist/modules/secrets-vault/index.d.ts.map +1 -1
  219. package/dist/modules/secrets-vault/index.js +1 -1
  220. package/dist/modules/secrets-vault/index.js.map +1 -1
  221. package/dist/modules/secrets-vault/secrets-vault.contract.d.ts +53 -11
  222. package/dist/modules/secrets-vault/secrets-vault.contract.d.ts.map +1 -1
  223. package/dist/modules/secrets-vault/secrets-vault.contract.js +27 -0
  224. package/dist/modules/secrets-vault/secrets-vault.contract.js.map +1 -1
  225. package/dist/modules/secrets-vault/secrets-vault.routes.d.ts +9 -0
  226. package/dist/modules/secrets-vault/secrets-vault.routes.d.ts.map +1 -1
  227. package/dist/modules/secrets-vault/secrets-vault.routes.js +100 -42
  228. package/dist/modules/secrets-vault/secrets-vault.routes.js.map +1 -1
  229. package/dist/modules/settings/oidc-check.d.ts.map +1 -1
  230. package/dist/modules/settings/oidc-check.js +5 -17
  231. package/dist/modules/settings/oidc-check.js.map +1 -1
  232. package/dist/modules/skills/index.d.ts +3 -3
  233. package/dist/modules/skills/index.d.ts.map +1 -1
  234. package/dist/modules/skills/index.js +0 -2
  235. package/dist/modules/skills/index.js.map +1 -1
  236. package/dist/modules/skills/skills.contract.d.ts +16 -0
  237. package/dist/modules/skills/skills.contract.d.ts.map +1 -1
  238. package/dist/modules/skills/skills.service.d.ts.map +1 -1
  239. package/dist/modules/skills/skills.service.js +6 -1
  240. package/dist/modules/skills/skills.service.js.map +1 -1
  241. package/dist/modules/skills/skills.tools.d.ts.map +1 -1
  242. package/dist/modules/skills/skills.tools.js +25 -13
  243. package/dist/modules/skills/skills.tools.js.map +1 -1
  244. package/dist/modules/tool-auth/external-api-key.interface.d.ts +11 -0
  245. package/dist/modules/tool-auth/external-api-key.interface.d.ts.map +1 -1
  246. package/dist/modules/tool-auth/external-api-key.interface.js.map +1 -1
  247. package/dist/modules/tool-auth/external-api-key.service.d.ts +1 -0
  248. package/dist/modules/tool-auth/external-api-key.service.d.ts.map +1 -1
  249. package/dist/modules/tool-auth/external-api-key.service.js +4 -1
  250. package/dist/modules/tool-auth/external-api-key.service.js.map +1 -1
  251. package/dist/modules/tool-auth/index.d.ts +1 -1
  252. package/dist/modules/tool-auth/index.d.ts.map +1 -1
  253. package/dist/modules/tool-auth/internal-token.service.d.ts +9 -0
  254. package/dist/modules/tool-auth/internal-token.service.d.ts.map +1 -1
  255. package/dist/modules/tool-auth/internal-token.service.js +1 -0
  256. package/dist/modules/tool-auth/internal-token.service.js.map +1 -1
  257. package/dist/modules/tool-auth/tool-auth.middleware.d.ts +27 -3
  258. package/dist/modules/tool-auth/tool-auth.middleware.d.ts.map +1 -1
  259. package/dist/modules/tool-auth/tool-auth.middleware.js +32 -6
  260. package/dist/modules/tool-auth/tool-auth.middleware.js.map +1 -1
  261. package/dist/modules/tool-helpers/tool-context.d.ts +7 -0
  262. package/dist/modules/tool-helpers/tool-context.d.ts.map +1 -1
  263. package/dist/modules/tool-helpers/tool-context.js +3 -0
  264. package/dist/modules/tool-helpers/tool-context.js.map +1 -1
  265. package/dist/modules/tool-helpers/tool-def.js +1 -1
  266. package/dist/modules/tool-helpers/tool-def.js.map +1 -1
  267. package/dist/modules/tool-helpers/tool-handler.d.ts +15 -0
  268. package/dist/modules/tool-helpers/tool-handler.d.ts.map +1 -1
  269. package/dist/modules/tool-helpers/tool-handler.js +19 -0
  270. package/dist/modules/tool-helpers/tool-handler.js.map +1 -1
  271. package/dist/modules/tool-helpers/tool.contract.d.ts +10 -0
  272. package/dist/modules/tool-helpers/tool.contract.d.ts.map +1 -1
  273. package/dist/modules/tool-helpers/tool.contract.js.map +1 -1
  274. package/dist/modules/tool-helpers/validate-token.d.ts +3 -1
  275. package/dist/modules/tool-helpers/validate-token.d.ts.map +1 -1
  276. package/dist/modules/tool-helpers/validate-token.js +1 -1
  277. package/dist/modules/tool-helpers/validate-token.js.map +1 -1
  278. package/dist/modules/tool-manuals/index.d.ts +3 -3
  279. package/dist/modules/tool-manuals/index.d.ts.map +1 -1
  280. package/dist/modules/tool-manuals/index.js +0 -2
  281. package/dist/modules/tool-manuals/index.js.map +1 -1
  282. package/dist/modules/tool-manuals/mcp-json-discovery.d.ts +7 -1
  283. package/dist/modules/tool-manuals/mcp-json-discovery.d.ts.map +1 -1
  284. package/dist/modules/tool-manuals/mcp-json-discovery.js +69 -38
  285. package/dist/modules/tool-manuals/mcp-json-discovery.js.map +1 -1
  286. package/dist/modules/tool-manuals/tool-manuals.contract.d.ts +46 -6
  287. package/dist/modules/tool-manuals/tool-manuals.contract.d.ts.map +1 -1
  288. package/dist/modules/tool-manuals/tool-manuals.routes.d.ts +7 -1
  289. package/dist/modules/tool-manuals/tool-manuals.routes.d.ts.map +1 -1
  290. package/dist/modules/tool-manuals/tool-manuals.routes.js +41 -4
  291. package/dist/modules/tool-manuals/tool-manuals.routes.js.map +1 -1
  292. package/dist/modules/tool-manuals/tool-manuals.service.d.ts +24 -13
  293. package/dist/modules/tool-manuals/tool-manuals.service.d.ts.map +1 -1
  294. package/dist/modules/tool-manuals/tool-manuals.service.js +138 -59
  295. package/dist/modules/tool-manuals/tool-manuals.service.js.map +1 -1
  296. package/dist/modules/tool-manuals/tool-manuals.tools.d.ts +8 -2
  297. package/dist/modules/tool-manuals/tool-manuals.tools.d.ts.map +1 -1
  298. package/dist/modules/tool-manuals/tool-manuals.tools.js +56 -20
  299. package/dist/modules/tool-manuals/tool-manuals.tools.js.map +1 -1
  300. package/dist/modules/tool-registry/manual.routes.d.ts +8 -1
  301. package/dist/modules/tool-registry/manual.routes.d.ts.map +1 -1
  302. package/dist/modules/tool-registry/manual.routes.js +27 -7
  303. package/dist/modules/tool-registry/manual.routes.js.map +1 -1
  304. package/dist/modules/tool-registry/tool.contract.d.ts +7 -0
  305. package/dist/modules/tool-registry/tool.contract.d.ts.map +1 -1
  306. package/dist/modules/tool-registry/tool.contract.js.map +1 -1
  307. package/dist/modules/workflow/agent-tools/workflow.tools.d.ts.map +1 -1
  308. package/dist/modules/workflow/agent-tools/workflow.tools.js +36 -27
  309. package/dist/modules/workflow/agent-tools/workflow.tools.js.map +1 -1
  310. package/dist/modules/workflow/git/git.service.d.ts +2 -2
  311. package/dist/modules/workflow/git/git.service.d.ts.map +1 -1
  312. package/dist/modules/workflow/git/git.service.js +20 -35
  313. package/dist/modules/workflow/git/git.service.js.map +1 -1
  314. package/dist/modules/workflow/workflow.service.d.ts +2 -1
  315. package/dist/modules/workflow/workflow.service.d.ts.map +1 -1
  316. package/dist/modules/workflow/workflow.service.js +3 -0
  317. package/dist/modules/workflow/workflow.service.js.map +1 -1
  318. package/dist/modules/workspace/agent-access.gate.d.ts +1 -1
  319. package/dist/modules/workspace/agent-access.gate.d.ts.map +1 -1
  320. package/dist/modules/workspace/agent-access.gate.js +1 -1
  321. package/dist/modules/workspace/agent-access.gate.js.map +1 -1
  322. package/dist/modules/workspace/file-readers/doc-extract.service.d.ts +28 -4
  323. package/dist/modules/workspace/file-readers/doc-extract.service.d.ts.map +1 -1
  324. package/dist/modules/workspace/file-readers/doc-extract.service.js +61 -40
  325. package/dist/modules/workspace/file-readers/doc-extract.service.js.map +1 -1
  326. package/dist/modules/workspace/index.d.ts +8 -0
  327. package/dist/modules/workspace/index.d.ts.map +1 -1
  328. package/dist/modules/workspace/index.js +8 -0
  329. package/dist/modules/workspace/index.js.map +1 -1
  330. package/dist/modules/workspace/nul-scan.d.ts +19 -0
  331. package/dist/modules/workspace/nul-scan.d.ts.map +1 -0
  332. package/dist/modules/workspace/nul-scan.js +55 -0
  333. package/dist/modules/workspace/nul-scan.js.map +1 -0
  334. package/dist/modules/workspace/pattern-matcher.contract.d.ts +110 -27
  335. package/dist/modules/workspace/pattern-matcher.contract.d.ts.map +1 -1
  336. package/dist/modules/workspace/pattern-matcher.contract.js +30 -13
  337. package/dist/modules/workspace/pattern-matcher.contract.js.map +1 -1
  338. package/dist/modules/workspace/ripgrep-search.d.ts +54 -0
  339. package/dist/modules/workspace/ripgrep-search.d.ts.map +1 -0
  340. package/dist/modules/workspace/ripgrep-search.js +657 -0
  341. package/dist/modules/workspace/ripgrep-search.js.map +1 -0
  342. package/dist/modules/workspace/ripgrep-version.d.ts +15 -0
  343. package/dist/modules/workspace/ripgrep-version.d.ts.map +1 -0
  344. package/dist/modules/workspace/ripgrep-version.js +31 -0
  345. package/dist/modules/workspace/ripgrep-version.js.map +1 -0
  346. package/dist/modules/workspace/startup/beside-checkout.d.ts +8 -5
  347. package/dist/modules/workspace/startup/beside-checkout.d.ts.map +1 -1
  348. package/dist/modules/workspace/startup/beside-checkout.js +14 -5
  349. package/dist/modules/workspace/startup/beside-checkout.js.map +1 -1
  350. package/dist/modules/workspace/worker-pool.d.ts +3 -4
  351. package/dist/modules/workspace/worker-pool.d.ts.map +1 -1
  352. package/dist/modules/workspace/worker-pool.js.map +1 -1
  353. package/dist/modules/workspace/workspace-tmp.d.ts +146 -0
  354. package/dist/modules/workspace/workspace-tmp.d.ts.map +1 -0
  355. package/dist/modules/workspace/workspace-tmp.js +435 -0
  356. package/dist/modules/workspace/workspace-tmp.js.map +1 -0
  357. package/dist/modules/workspace/workspace.routes.d.ts.map +1 -1
  358. package/dist/modules/workspace/workspace.routes.js +5 -26
  359. package/dist/modules/workspace/workspace.routes.js.map +1 -1
  360. package/dist/modules/workspace/workspace.service.d.ts +47 -6
  361. package/dist/modules/workspace/workspace.service.d.ts.map +1 -1
  362. package/dist/modules/workspace/workspace.service.js +86 -6
  363. package/dist/modules/workspace/workspace.service.js.map +1 -1
  364. package/dist/modules/workspace/workspace.tools.d.ts +3 -2
  365. package/dist/modules/workspace/workspace.tools.d.ts.map +1 -1
  366. package/dist/modules/workspace/workspace.tools.js +531 -137
  367. package/dist/modules/workspace/workspace.tools.js.map +1 -1
  368. package/dist/shared/oauth-token-error.d.ts +23 -0
  369. package/dist/shared/oauth-token-error.d.ts.map +1 -0
  370. package/dist/shared/oauth-token-error.js +47 -0
  371. package/dist/shared/oauth-token-error.js.map +1 -0
  372. package/dist/shared/path-order.d.ts +28 -8
  373. package/dist/shared/path-order.d.ts.map +1 -1
  374. package/dist/shared/path-order.js +37 -8
  375. package/dist/shared/path-order.js.map +1 -1
  376. package/dist/shared/read-capped.d.ts +19 -0
  377. package/dist/shared/read-capped.d.ts.map +1 -0
  378. package/dist/shared/read-capped.js +45 -0
  379. package/dist/shared/read-capped.js.map +1 -0
  380. package/migrations/0022_session_version.sql +6 -0
  381. package/migrations/0023_agent_path.sql +3 -0
  382. package/migrations/meta/0022_snapshot.json +2360 -0
  383. package/migrations/meta/0023_snapshot.json +2378 -0
  384. package/migrations/meta/_journal.json +14 -0
  385. package/package.json +4 -3
  386. package/src/__tests__/hexis-catalog.ts +144 -0
  387. package/src/__tests__/pg-scratch.test.ts +69 -0
  388. package/src/__tests__/pg-scratch.ts +31 -0
  389. package/src/__tests__/real-disk.ts +21 -0
  390. package/src/__tests__/slow-ripgrep.ts +65 -0
  391. package/src/__tests__/tokens.ts +19 -0
  392. package/src/__tests__/tool-manuals.ts +32 -0
  393. package/src/__tests__/tool-wiring.ts +25 -0
  394. package/src/core/__tests__/boot-without-ripgrep.test.ts +34 -0
  395. package/src/core/__tests__/catalog-revision.test.ts +89 -0
  396. package/src/core/__tests__/damaged-document.tools.test.ts +2 -2
  397. package/src/core/__tests__/gated-boot.test.ts +8 -1
  398. package/src/core/__tests__/lifecycle.test.ts +46 -13
  399. package/src/core/__tests__/oauth-sign-in-real-file.test.ts +179 -0
  400. package/src/core/catalog-revision.ts +24 -2
  401. package/src/core/core-ports.ts +42 -0
  402. package/src/core/create-core-server.ts +14 -1
  403. package/src/core/create-core-services.ts +62 -15
  404. package/src/core/lifecycle.ts +26 -2
  405. package/src/index.ts +1 -1
  406. package/src/modules/access/__tests__/access-control.admin-root-floor.test.ts +12 -0
  407. package/src/modules/access/__tests__/access-control.colliding-name-cases.test.ts +113 -0
  408. package/src/modules/access/__tests__/access-control.frontmatter-head.test.ts +117 -0
  409. package/src/modules/access/__tests__/access-control.group-named-admin.test.ts +122 -0
  410. package/src/modules/access/__tests__/access-control.preview-relocation.test.ts +50 -0
  411. package/src/modules/access/__tests__/access-declarations.test.ts +19 -0
  412. package/src/modules/access/__tests__/access-groups.test.ts +55 -22
  413. package/src/modules/access/__tests__/access-mutation.service.test.ts +85 -59
  414. package/src/modules/access/__tests__/access-restrict-here.test.ts +7 -5
  415. package/src/modules/access/__tests__/access.routes.admins.test.ts +1 -0
  416. package/src/modules/access/__tests__/access.routes.batch.test.ts +2 -0
  417. package/src/modules/access/__tests__/access.routes.folder-governs.test.ts +2 -0
  418. package/src/modules/access/__tests__/access.routes.group-grant.test.ts +50 -14
  419. package/src/modules/access/__tests__/access.routes.overrides.test.ts +2 -1
  420. package/src/modules/access/__tests__/access.routes.proposal-branch.test.ts +1 -0
  421. package/src/modules/access/__tests__/access.routes.prospective.test.ts +52 -10
  422. package/src/modules/access/__tests__/access.routes.revoke.test.ts +18 -13
  423. package/src/modules/access/__tests__/access.routes.unknown-email.test.ts +2 -0
  424. package/src/modules/access/__tests__/grant-sources.test.ts +20 -15
  425. package/src/modules/access/__tests__/groups-admin.routes.test.ts +61 -0
  426. package/src/modules/access/__tests__/groups-admin.service.test.ts +211 -18
  427. package/src/modules/access/__tests__/holder-changes.test.ts +127 -0
  428. package/src/modules/access/__tests__/reference-scan.test.ts +366 -14
  429. package/src/modules/access/__tests__/roles-admin.security.test.ts +1 -1
  430. package/src/modules/access/__tests__/roles-admin.service.test.ts +43 -22
  431. package/src/modules/access/__tests__/roles-capabilities.test.ts +6 -2
  432. package/src/modules/access/__tests__/roles.routes.test.ts +1 -1
  433. package/src/modules/access/access-control.interface.ts +43 -10
  434. package/src/modules/access/access-control.service.ts +250 -72
  435. package/src/modules/access/access-mutation.service.ts +48 -53
  436. package/src/modules/access/access-view.ts +12 -10
  437. package/src/modules/access/access.routes.ts +66 -37
  438. package/src/modules/access/groups-admin.routes.ts +4 -2
  439. package/src/modules/access/groups-admin.service.ts +114 -44
  440. package/src/modules/access/groups-edit.ts +1 -1
  441. package/src/modules/access/index.ts +1 -1
  442. package/src/modules/access/reference-scan.ts +319 -46
  443. package/src/modules/access/roles-admin.service.ts +43 -26
  444. package/src/modules/access/synced-groups-writer.ts +1 -1
  445. package/src/modules/access-model/__tests__/access-grammar.test.ts +38 -1
  446. package/src/modules/access-model/__tests__/access-splice.test.ts +50 -8
  447. package/src/modules/access-model/access-grammar.ts +65 -20
  448. package/src/modules/access-model/access-splice.ts +31 -23
  449. package/src/modules/access-model/group-files.ts +5 -0
  450. package/src/modules/agent-guide/__tests__/agent-guide.test.ts +110 -25
  451. package/src/modules/agent-guide/__tests__/agent-guide.tools.test.ts +38 -11
  452. package/src/modules/agent-guide/__tests__/guide-budget.test.ts +95 -0
  453. package/src/modules/agent-guide/__tests__/guide-eval.test.ts +182 -0
  454. package/src/modules/agent-guide/__tests__/guide-matches-code.test.ts +263 -0
  455. package/src/modules/agent-guide/__tests__/tool-surface.json +514 -0
  456. package/src/modules/agent-guide/__tests__/tool-surface.test.ts +75 -0
  457. package/src/modules/agent-guide/agent-guide.tools.ts +51 -22
  458. package/src/modules/agent-guide/agent-guide.ts +120 -13
  459. package/src/modules/agent-guide/guide-budget.ts +73 -0
  460. package/src/modules/agent-guide/index.ts +12 -0
  461. package/src/modules/agent-instructions/__tests__/shared-file-rules.test.ts +5 -4
  462. package/src/modules/agent-instructions/compose.ts +7 -1
  463. package/src/modules/agent-instructions/shared-file-rules.ts +27 -9
  464. package/src/modules/agent-scope/__tests__/agent-surfaces.connect-as.test.ts +421 -0
  465. package/src/modules/agent-scope/__tests__/connection-scope.test.ts +46 -0
  466. package/src/modules/agent-scope/__tests__/in-memory-kb.ts +148 -0
  467. package/src/modules/agent-scope/agent-scope.contract.ts +83 -0
  468. package/src/modules/agent-scope/connection-scope.ts +199 -0
  469. package/src/modules/agent-scope/index.ts +15 -0
  470. package/src/modules/audit/agent-audit.service.ts +2 -0
  471. package/src/modules/audit/audit.contract.ts +6 -0
  472. package/src/modules/auth/__tests__/auth.middleware.test.ts +30 -2
  473. package/src/modules/auth/__tests__/auth.routes.test.ts +71 -5
  474. package/src/modules/auth/__tests__/auth.service.test.ts +90 -9
  475. package/src/modules/auth/__tests__/password-change-sessions.pg.test.ts +269 -0
  476. package/src/modules/auth/account-admission.ts +19 -0
  477. package/src/modules/auth/auth.middleware.ts +45 -4
  478. package/src/modules/auth/auth.routes.ts +46 -29
  479. package/src/modules/auth/auth.service.ts +135 -34
  480. package/src/modules/auth/index.ts +2 -0
  481. package/src/modules/auth/oidc-auth-provider.ts +2 -9
  482. package/src/modules/code-mode/code-mode.tool.ts +2 -2
  483. package/src/modules/connection-probe/__tests__/connection-probe.service.test.ts +5 -24
  484. package/src/modules/connection-probe/connection-probe.service.ts +1 -34
  485. package/src/modules/database/__tests__/session-version-migration.pg.test.ts +133 -0
  486. package/src/modules/database/core-schema.ts +33 -0
  487. package/src/modules/declared-variables/__tests__/declared-variables.route.test.ts +44 -1
  488. package/src/modules/declared-variables/declared-variables.routes.ts +12 -1
  489. package/src/modules/embed/__tests__/embed.tools.test.ts +12 -0
  490. package/src/modules/embed/embed.tools.ts +5 -0
  491. package/src/modules/kb-fs/__tests__/locking-filesystem.test.ts +25 -0
  492. package/src/modules/kb-fs/__tests__/repo-path.test.ts +53 -8
  493. package/src/modules/kb-fs/index.ts +2 -0
  494. package/src/modules/kb-fs/locking-filesystem.ts +7 -1
  495. package/src/modules/kb-fs/repo-path.ts +33 -7
  496. package/src/modules/kb-fs/tmp-ref.ts +81 -0
  497. package/src/modules/mcp/__tests__/connect-as.pg.test.ts +137 -0
  498. package/src/modules/mcp/__tests__/mcp-auth.middleware.test.ts +29 -5
  499. package/src/modules/mcp/__tests__/mcp-routes-harness.ts +8 -0
  500. package/src/modules/mcp/__tests__/mcp.connect-as.test.ts +195 -0
  501. package/src/modules/mcp/__tests__/mcp.routes.connect-as.test.ts +192 -0
  502. package/src/modules/mcp/__tests__/oauth-consent.connect-as.test.ts +146 -0
  503. package/src/modules/mcp/mcp-auth.middleware.ts +19 -2
  504. package/src/modules/mcp/mcp.routes.ts +39 -3
  505. package/src/modules/mcp/mcp.service.ts +112 -52
  506. package/src/modules/mcp/oauth/bevel-oauth-provider.ts +46 -8
  507. package/src/modules/mcp/oauth/oauth-consent.routes.ts +41 -1
  508. package/src/modules/plugins/__tests__/plugins.tools.test.ts +38 -2
  509. package/src/modules/plugins/index.ts +1 -1
  510. package/src/modules/plugins/plugin-links.ts +19 -2
  511. package/src/modules/plugins/plugins.routes.ts +35 -4
  512. package/src/modules/secrets-vault/__tests__/connect-pending.route.test.ts +113 -0
  513. package/src/modules/secrets-vault/__tests__/db-secrets-vault.oauth.test.ts +430 -3
  514. package/src/modules/secrets-vault/__tests__/oauth-live-declaration.route.test.ts +218 -0
  515. package/src/modules/secrets-vault/__tests__/oauth-return-to.route.test.ts +39 -6
  516. package/src/modules/secrets-vault/db-secrets-vault.service.ts +170 -27
  517. package/src/modules/secrets-vault/index.ts +1 -1
  518. package/src/modules/secrets-vault/secrets-vault.contract.ts +61 -11
  519. package/src/modules/secrets-vault/secrets-vault.routes.ts +114 -42
  520. package/src/modules/settings/oidc-check.ts +5 -18
  521. package/src/modules/skills/__tests__/skills.service.test.ts +34 -0
  522. package/src/modules/skills/index.ts +7 -2
  523. package/src/modules/skills/skills.contract.ts +17 -0
  524. package/src/modules/skills/skills.service.ts +5 -1
  525. package/src/modules/skills/skills.tools.ts +45 -14
  526. package/src/modules/tool-auth/__tests__/external-api-key.service.test.ts +4 -0
  527. package/src/modules/tool-auth/external-api-key.interface.ts +11 -1
  528. package/src/modules/tool-auth/external-api-key.service.ts +5 -2
  529. package/src/modules/tool-auth/index.ts +1 -1
  530. package/src/modules/tool-auth/internal-token.service.ts +10 -0
  531. package/src/modules/tool-auth/tool-auth.middleware.ts +45 -3
  532. package/src/modules/tool-helpers/__tests__/agent-roles-write.test.ts +19 -11
  533. package/src/modules/tool-helpers/__tests__/can-write.tools.test.ts +3 -1
  534. package/src/modules/tool-helpers/__tests__/route-tool-schemas.catalog.test.ts +38 -0
  535. package/src/modules/tool-helpers/tool-context.ts +10 -0
  536. package/src/modules/tool-helpers/tool-def.ts +1 -1
  537. package/src/modules/tool-helpers/tool-handler.ts +34 -0
  538. package/src/modules/tool-helpers/tool.contract.ts +10 -0
  539. package/src/modules/tool-helpers/validate-token.ts +4 -2
  540. package/src/modules/tool-manuals/__tests__/tool-manuals.archive.route.test.ts +80 -4
  541. package/src/modules/tool-manuals/__tests__/tool-manuals.mcp-oauth.test.ts +197 -11
  542. package/src/modules/tool-manuals/__tests__/tool-manuals.service.test.ts +42 -0
  543. package/src/modules/tool-manuals/__tests__/tool-manuals.tools.test.ts +99 -8
  544. package/src/modules/tool-manuals/index.ts +6 -2
  545. package/src/modules/tool-manuals/mcp-json-discovery.ts +73 -34
  546. package/src/modules/tool-manuals/tool-manuals.contract.ts +40 -6
  547. package/src/modules/tool-manuals/tool-manuals.routes.ts +40 -3
  548. package/src/modules/tool-manuals/tool-manuals.service.ts +169 -61
  549. package/src/modules/tool-manuals/tool-manuals.tools.ts +81 -25
  550. package/src/modules/tool-registry/__tests__/tool-description-length.test.ts +6 -113
  551. package/src/modules/tool-registry/manual.routes.ts +26 -5
  552. package/src/modules/tool-registry/tool.contract.ts +7 -0
  553. package/src/modules/workflow/__tests__/workflow.service.facade.test.ts +1 -1
  554. package/src/modules/workflow/__tests__/workflow.service.sync.test.ts +1 -1
  555. package/src/modules/workflow/agent-tools/__tests__/workflow.tools.test.ts +54 -3
  556. package/src/modules/workflow/agent-tools/workflow.tools.ts +36 -27
  557. package/src/modules/workflow/git/__tests__/git.service.list-branches.test.ts +130 -3
  558. package/src/modules/workflow/git/git.service.ts +29 -48
  559. package/src/modules/workflow/workflow.service.ts +5 -0
  560. package/src/modules/workspace/__tests__/git-internals.security.test.ts +2 -2
  561. package/src/modules/workspace/__tests__/holds-nul.test.ts +66 -0
  562. package/src/modules/workspace/__tests__/rest-tool-arguments.test.ts +3 -3
  563. package/src/modules/workspace/__tests__/ripgrep-search.test.ts +570 -0
  564. package/src/modules/workspace/__tests__/ripgrep-version.test.ts +29 -0
  565. package/src/modules/workspace/__tests__/workspace-tmp.tools.test.ts +928 -0
  566. package/src/modules/workspace/__tests__/workspace.routes.read-gate.test.ts +17 -37
  567. package/src/modules/workspace/__tests__/workspace.service.read-filter.test.ts +20 -8
  568. package/src/modules/workspace/__tests__/workspace.tools.agents-file.test.ts +10 -12
  569. package/src/modules/workspace/__tests__/workspace.tools.branch-errors.test.ts +22 -10
  570. package/src/modules/workspace/__tests__/workspace.tools.test.ts +549 -162
  571. package/src/modules/workspace/agent-access.gate.ts +1 -1
  572. package/src/modules/workspace/file-readers/__tests__/doc-extract.service.test.ts +10 -0
  573. package/src/modules/workspace/file-readers/doc-extract.service.ts +71 -38
  574. package/src/modules/workspace/index.ts +20 -0
  575. package/src/modules/workspace/nul-scan.ts +50 -0
  576. package/src/modules/workspace/pattern-matcher.contract.ts +123 -32
  577. package/src/modules/workspace/ripgrep-search.ts +715 -0
  578. package/src/modules/workspace/ripgrep-version.ts +35 -0
  579. package/src/modules/workspace/startup/__tests__/beside-checkout.test.ts +11 -0
  580. package/src/modules/workspace/startup/beside-checkout.ts +13 -5
  581. package/src/modules/workspace/worker-pool.ts +3 -4
  582. package/src/modules/workspace/workspace-tmp.ts +457 -0
  583. package/src/modules/workspace/workspace.routes.ts +6 -27
  584. package/src/modules/workspace/workspace.service.ts +92 -15
  585. package/src/modules/workspace/workspace.tools.ts +574 -176
  586. package/src/shared/__tests__/read-capped.test.ts +68 -0
  587. package/src/shared/oauth-token-error.ts +46 -0
  588. package/src/shared/path-order.ts +37 -8
  589. package/src/shared/read-capped.ts +40 -0
  590. package/starter-packs/engineering/Plugins/engineering-starter/access.md +1 -1
  591. package/starter-packs/general/Plugins/general-starter/access.md +1 -1
  592. package/starter-packs/operations/Plugins/operations-starter/access.md +1 -1
  593. package/starter-packs/sales/Plugins/sales-starter/access.md +1 -1
  594. package/starter-packs/support/Plugins/support-starter/access.md +1 -1
  595. package/agent-guide/finding-things.md +0 -7
  596. package/agent-guide/introduction.md +0 -27
  597. package/dist/modules/workspace/bounded-matcher.d.ts +0 -73
  598. package/dist/modules/workspace/bounded-matcher.d.ts.map +0 -1
  599. package/dist/modules/workspace/bounded-matcher.js +0 -200
  600. package/dist/modules/workspace/bounded-matcher.js.map +0 -1
  601. package/src/modules/workspace/__tests__/bounded-matcher.test.ts +0 -213
  602. package/src/modules/workspace/bounded-matcher.ts +0 -271
@@ -11,6 +11,9 @@ import { DEFAULT_BRANCH } from '@bevel-software/platform-shared';
11
11
  import { AccessControlService } from '../access-control.service.js';
12
12
  import { GroupsAdminService, GroupsAdminError } from '../groups-admin.service.js';
13
13
  import { createGroup, addGroupMember, GroupsEditError } from '../groups-edit.js';
14
+ import { workspaceIdForBranch } from '../../../shared/workspace-id.js';
15
+ import { AccessDeniedError } from '../../access-model/index.js';
16
+ import { UNSHOWN_REFERENCE_REFUSAL } from '../reference-scan.js';
14
17
 
15
18
  const KB = 'knowledge-base';
16
19
  const ADMIN: AuthUser = { id: 'u-admin', email: 'admin@x.io', name: 'Admin' } as AuthUser;
@@ -108,6 +111,7 @@ describe('GroupsAdminService', () => {
108
111
  workspace,
109
112
  workflow.svc,
110
113
  new AccessControlService(workspace as never, KB, new NodeFs()),
114
+ new NodeFs(),
111
115
  KB,
112
116
  () => DEFAULT_BRANCH,
113
117
  );
@@ -126,7 +130,7 @@ describe('GroupsAdminService', () => {
126
130
  'roles.yaml',
127
131
  'roles:\n Admin:\n - admin@x.io\n Reviewer:\n - rev@x.io\n - group:gtm team\n',
128
132
  );
129
- const roster = await service.getRoster();
133
+ const roster = await service.getRoster('admin@x.io');
130
134
  expect(roster.mode).toBe('manual');
131
135
  expect(roster.groupsHealth).toEqual({ ok: true });
132
136
  expect(roster.groups.map((g) => g.displayName).sort()).toEqual(['GTM Team', 'Product']);
@@ -141,7 +145,7 @@ describe('GroupsAdminService', () => {
141
145
 
142
146
  it('a broken MANUAL groups.yaml answers the roster with 422 + the parse message', async () => {
143
147
  await write(repo, 'groups.yaml', 'groups:\n - not\n - a\n - mapping\n');
144
- const err = await service.getRoster().catch((e: unknown) => e);
148
+ const err = await service.getRoster('admin@x.io').catch((e: unknown) => e);
145
149
  expect(err).toBeInstanceOf(GroupsAdminError);
146
150
  expect((err as GroupsAdminError).status).toBe(422);
147
151
  expect((err as GroupsAdminError).message).toMatch(/groups.yaml/);
@@ -152,7 +156,7 @@ describe('GroupsAdminService', () => {
152
156
 
153
157
  it('a broken SYNCED file keeps IdP mode: empty roster + groupsHealth marker (no manual fallback)', async () => {
154
158
  await write(repo, 'synced-groups.yaml', 'groups:\n - not\n - a\n - mapping\n');
155
- const roster = await service.getRoster();
159
+ const roster = await service.getRoster('admin@x.io');
156
160
  expect(roster.mode).toBe('idp');
157
161
  // Falling back to groups.yaml would resurrect retired manual groups.
158
162
  expect(roster.groups).toEqual([]);
@@ -218,7 +222,7 @@ describe('GroupsAdminService', () => {
218
222
 
219
223
  it('IdP mode: mutations refuse with the typed 409; reads still work', async () => {
220
224
  await write(repo, 'synced-groups.yaml', 'groups:\n Engineering:\n - ada@x.io\n');
221
- const roster = await service.getRoster();
225
+ const roster = await service.getRoster('admin@x.io');
222
226
  expect(roster.mode).toBe('idp');
223
227
  // The roster IS the synced file now — not the retired manual list.
224
228
  expect(roster.groups.map((g) => g.canonical)).toEqual(['engineering']);
@@ -241,18 +245,106 @@ describe('GroupsAdminService', () => {
241
245
  });
242
246
 
243
247
  it('canonical-changing rename rewrites grant references in ONE commit', async () => {
244
- await write(repo, 'Knowledge/Sales/access.md', '---\nread:\n - GTM Team\nwrite:\n - deny GTM Team\n---\n');
248
+ await write(
249
+ repo,
250
+ 'Knowledge/Sales/access.md',
251
+ '---\nread:\n - GTM Team\n - group/GTM Team\nwrite:\n - deny GTM Team\n---\n',
252
+ );
245
253
  await service.renameGroup(ADMIN, 'gtm team', 'Go To Market');
246
254
 
247
255
  expect(await groupsYaml()).toContain('Go To Market:');
248
256
  const rewritten = await fs.readFile(path.join(repo, 'Knowledge/Sales/access.md'), 'utf-8');
249
- expect(rewritten).toContain('- Go To Market');
250
- expect(rewritten).toContain('- deny Go To Market');
257
+ // Rewritten as the explicit group token, whatever the old spelling.
258
+ expect(rewritten).toContain('- group/Go To Market');
259
+ expect(rewritten).toContain('- deny group/Go To Market');
251
260
  expect(rewritten).not.toContain('GTM Team');
252
261
  expect(commits).toHaveLength(1);
253
262
  expect(commits[0].summary).toContain('gtm team → Go To Market');
254
263
  });
255
264
 
265
+ // Another person's private plugin is closed to the Admin: the rewrite still
266
+ // covers it (no reference left behind). Whether the Admin may WRITE it is
267
+ // the commit gate's call — see the gated cases below; this stub allows it.
268
+ it('rename rewrites a file the Admin cannot read when the commit allows it', async () => {
269
+ await write(
270
+ repo,
271
+ 'Plugins/Sara/access.md',
272
+ '---\nread:\n - deny everyone\n - Sara <sara@x.io>\nwrite:\n - Sara <sara@x.io>\n---\n',
273
+ );
274
+ await write(repo, 'Plugins/Sara/Notes.md', "---\nread: ['group/GTM Team']\n---\n# Notes\n");
275
+ const access = new AccessControlService(stubWorkspace(root) as never, KB, new NodeFs());
276
+ expect(await access.canRead(workspaceIdForBranch(DEFAULT_BRANCH), ADMIN.email, 'Plugins/Sara/Notes.md')).toBe(false);
277
+
278
+ await service.renameGroup(ADMIN, 'gtm team', 'Go To Market');
279
+
280
+ expect(await fs.readFile(path.join(repo, 'Plugins/Sara/Notes.md'), 'utf-8')).toBe(
281
+ "---\nread: ['group/Go To Market']\n---\n# Notes\n",
282
+ );
283
+ expect(commits).toHaveLength(1);
284
+ });
285
+
286
+ describe('rename against the commit write gate', () => {
287
+ // The real commit gates every touched path on the actor's write rules and
288
+ // refuses the first one they may not write (git.service
289
+ // `assertCanWriteAtRef`); this stub does the same through the live model.
290
+ function gatedService(): { gated: GroupsAdminService; gatedCommits: { summary: string }[] } {
291
+ const workspace = stubWorkspace(root);
292
+ const access = new AccessControlService(workspace as never, KB, new NodeFs());
293
+ const workflow = stubWorkflow();
294
+ const svc = workflow.svc as unknown as Record<string, unknown>;
295
+ svc.commitChanges = async (ws: string, user: AuthUser, summary: string, onlyPaths: string[] = []) => {
296
+ const rel = onlyPaths.map((p) => p.slice(KB.length + 1));
297
+ const verdicts = await access.canWriteBatch(ws, user.email, rel);
298
+ const denied = rel.find((p) => verdicts.get(p) !== true);
299
+ if (denied) throw new AccessDeniedError({ path: denied, eligibleRoles: [], eligibleUsers: [] });
300
+ workflow.commits.push({ summary });
301
+ return {} as unknown;
302
+ };
303
+ const gated = new GroupsAdminService(workspace, workflow.svc, access, new NodeFs(), KB, () => DEFAULT_BRANCH);
304
+ return { gated, gatedCommits: workflow.commits };
305
+ }
306
+
307
+ const SARA_ACCESS = '---\nread:\n - deny everyone\n - Sara <sara@x.io>\nwrite:\n - Sara <sara@x.io>\n---\n';
308
+
309
+ it('a file the Admin cannot read refuses generically, never naming it, and writes nothing', async () => {
310
+ await write(repo, 'Plugins/Sara/access.md', SARA_ACCESS);
311
+ const notes = "---\nread: ['group/GTM Team']\n---\n# Notes\n";
312
+ await write(repo, 'Plugins/Sara/Notes.md', notes);
313
+ const { gated, gatedCommits } = gatedService();
314
+
315
+ const err = await gated.renameGroup(ADMIN, 'gtm team', 'Go To Market').catch((e: unknown) => e);
316
+ expect(err).toBeInstanceOf(GroupsAdminError);
317
+ expect((err as GroupsAdminError).status).toBe(422);
318
+ expect((err as Error).message).toBe(UNSHOWN_REFERENCE_REFUSAL);
319
+ expect((err as Error).message).not.toContain('Sara');
320
+ // Restored: the hidden file, and the roster, as they were.
321
+ expect(await fs.readFile(path.join(repo, 'Plugins/Sara/Notes.md'), 'utf-8')).toBe(notes);
322
+ expect(await groupsYaml()).toBe(GROUPS);
323
+ expect(gatedCommits).toHaveLength(0);
324
+ });
325
+
326
+ it('a file the Admin can read but not write keeps the refusal that names it', async () => {
327
+ await write(repo, 'Knowledge/Locked/access.md', '---\nread:\n - everyone\nwrite:\n - deny Admin\n---\n');
328
+ await write(repo, 'Knowledge/Locked/Plan.md', '---\nread:\n - group/GTM Team\n---\n# Plan\n');
329
+ const { gated } = gatedService();
330
+
331
+ const err = await gated.renameGroup(ADMIN, 'gtm team', 'Go To Market').catch((e: unknown) => e);
332
+ expect(err).toBeInstanceOf(AccessDeniedError);
333
+ expect((err as AccessDeniedError).access.path).toMatch(/^Knowledge\/Locked\//);
334
+ });
335
+
336
+ it('a hidden file that names something else does not block the rename', async () => {
337
+ await write(repo, 'Plugins/Sara/access.md', SARA_ACCESS);
338
+ await write(repo, 'Plugins/Sara/Notes.md', "---\nread: ['group/Product']\n---\n# Notes\n");
339
+ await write(repo, 'Knowledge/Sales/access.md', '---\nread:\n - group/GTM Team\n---\n');
340
+ const { gated, gatedCommits } = gatedService();
341
+
342
+ await gated.renameGroup(ADMIN, 'gtm team', 'Go To Market');
343
+ expect(await fs.readFile(path.join(repo, 'Knowledge/Sales/access.md'), 'utf-8')).toContain('group/Go To Market');
344
+ expect(gatedCommits).toHaveLength(1);
345
+ });
346
+ });
347
+
256
348
  it('rename rewrites a BODY-GOVERNED access.md (rules live below the frontmatter)', async () => {
257
349
  // New-format file: frontmatter governs access.md itself, the body is the
258
350
  // folder's rules — exactly what the resolver enforces.
@@ -262,14 +354,15 @@ describe('GroupsAdminService', () => {
262
354
  '---\nwrite:\n - Admin\n---\nread:\n - GTM Team\nwrite:\n - deny GTM Team\n',
263
355
  );
264
356
  // The scan must see the body rule too (delete warnings / referencedBy).
265
- const roster = await service.getRoster();
357
+ const roster = await service.getRoster('admin@x.io');
266
358
  const gtm = roster.groups.find((g) => g.canonical === 'gtm team');
267
359
  expect(gtm?.referencedBy).toContainEqual({ path: 'Knowledge/Sales/access.md', verb: 'read' });
268
360
 
269
361
  await service.renameGroup(ADMIN, 'gtm team', 'Go To Market');
270
362
  const rewritten = await fs.readFile(path.join(repo, 'Knowledge/Sales/access.md'), 'utf-8');
271
- expect(rewritten).toContain('- Go To Market');
272
- expect(rewritten).toContain('- deny Go To Market');
363
+ // Rewritten as the explicit group token, whatever the old spelling.
364
+ expect(rewritten).toContain('- group/Go To Market');
365
+ expect(rewritten).toContain('- deny group/Go To Market');
273
366
  expect(rewritten).not.toContain('GTM Team');
274
367
  // The frontmatter self-rule is a rule source too, and Admin is untouched.
275
368
  expect(rewritten).toContain('- Admin');
@@ -303,6 +396,7 @@ describe('GroupsAdminService', () => {
303
396
  workspace,
304
397
  workflow.svc,
305
398
  new AccessControlService(workspace as never, KB, new NodeFs()),
399
+ new NodeFs(),
306
400
  KB,
307
401
  () => DEFAULT_BRANCH,
308
402
  );
@@ -349,6 +443,7 @@ describe('GroupsAdminService', () => {
349
443
  workspace,
350
444
  workflow.svc,
351
445
  new AccessControlService(workspace as never, KB, new NodeFs()),
446
+ new NodeFs(),
352
447
  KB,
353
448
  () => DEFAULT_BRANCH,
354
449
  );
@@ -388,6 +483,7 @@ describe('GroupsAdminService', () => {
388
483
  workspace,
389
484
  workflow.svc,
390
485
  new AccessControlService(workspace as never, KB, new NodeFs()),
486
+ new NodeFs(),
391
487
  KB,
392
488
  () => DEFAULT_BRANCH,
393
489
  );
@@ -421,27 +517,124 @@ describe('groups-edit guardrails', () => {
421
517
  });
422
518
 
423
519
  describe('groups roster referencedBy — the mirror of the roles roster attribution', () => {
424
- it('a group shadowed BY a role name still owns its bare-token hits; role/<name> hits are never the group’s', async () => {
520
+ it('a group sharing a role name owns only its group/ hits; bare and role/ hits are the role’s', async () => {
425
521
  const root2 = await fs.mkdtemp(path.join(os.tmpdir(), 'bevel-groups-shadow-'));
426
522
  try {
427
523
  const repo2 = path.join(root2, KB);
428
- // A group named Reviewer shares the Reviewer role's name. Group-first
429
- // precedence gives the GROUP the bare key, so the bare hit is its
430
- // reference; the explicit role/ hit belongs to the ROLE roster only.
524
+ // A group named Reviewer shares the Reviewer role's name. Role-first
525
+ // precedence gives the ROLE the bare key, so the bare and role/ hits
526
+ // belong to the ROLE roster; the group's reference is its group/ hit.
527
+ // The bare hit is reported so an Admin can rewrite it if the group
528
+ // was meant.
431
529
  await write(repo2, 'roles.yaml', ROLES); // declares role Reviewer
432
- await write(repo2, 'groups.yaml', 'groups:\n Reviewer:\n - pat@x.io\n');
433
- await write(repo2, 'team/access.md', '---\nread:\n - Reviewer\nwrite:\n - role/Reviewer\n---\n');
530
+ await write(repo2, 'groups.yaml', 'groups:\n Reviewer:\n - pat@x.io\n Ops:\n - ops@x.io\n');
531
+ await write(repo2, 'ops/access.md', '---\nread:\n - Ops\nwrite:\n - group/Ops\n---\n');
532
+ await write(
533
+ repo2,
534
+ 'team/access.md',
535
+ '---\nread:\n - Reviewer\nwrite:\n - role/Reviewer\nowner:\n - group/Reviewer\ndownload:\n - deny Reviewer\n---\n',
536
+ );
434
537
  const workspace = stubWorkspace(root2);
435
538
  const svc = new GroupsAdminService(
436
539
  workspace,
437
540
  stubWorkflow().svc,
438
541
  new AccessControlService(workspace as never, KB, new NodeFs()),
542
+ new NodeFs(),
439
543
  KB,
440
544
  () => DEFAULT_BRANCH,
441
545
  );
442
- const roster = await svc.getRoster();
546
+ // rev@x.io holds the Reviewer role, so it can read team/access.md.
547
+ const roster = await svc.getRoster('rev@x.io');
443
548
  const reviewer = roster.groups.find((g) => g.canonical === 'reviewer')!;
444
- expect(reviewer.referencedBy).toEqual([{ path: 'team/access.md', verb: 'read' }]);
549
+ expect(reviewer.referencedBy).toEqual([{ path: 'team/access.md', verb: 'owner' }]);
550
+ // A bare DENIAL changed meaning too (it now denies the role, not the
551
+ // group), so it is reported alongside the bare grant.
552
+ expect(reviewer.bareNameResolvesToRole).toEqual([
553
+ { path: 'team/access.md', verb: 'read' },
554
+ { path: 'team/access.md', verb: 'download' },
555
+ ]);
556
+ // A group no role shares a name with keeps its bare hits, and has nothing
557
+ // to report. ops@x.io is in Ops, so it can read ops/access.md.
558
+ const ops = (await svc.getRoster('ops@x.io')).groups.find((g) => g.canonical === 'ops')!;
559
+ expect(ops.referencedBy).toEqual(
560
+ expect.arrayContaining([
561
+ { path: 'ops/access.md', verb: 'read' },
562
+ { path: 'ops/access.md', verb: 'write' },
563
+ ]),
564
+ );
565
+ expect(ops.referencedBy).toHaveLength(2);
566
+ expect(ops.bareNameResolvesToRole).toEqual([]);
567
+ } finally {
568
+ await fs.rm(root2, { recursive: true, force: true });
569
+ }
570
+ });
571
+
572
+ it('bareNameResolvesToRole names only the files the viewer can read', async () => {
573
+ const root2 = await fs.mkdtemp(path.join(os.tmpdir(), 'bevel-groups-disclose-'));
574
+ try {
575
+ const repo2 = path.join(root2, KB);
576
+ await write(repo2, 'roles.yaml', ROLES); // Admin: admin@x.io, Reviewer: rev@x.io
577
+ await write(repo2, 'groups.yaml', 'groups:\n Reviewer:\n - pat@x.io\n');
578
+ await write(repo2, 'access.md', '---\nread:\n - everyone\nwrite:\n - Admin\n---\n');
579
+ // Two bare Reviewer rules: one in an open folder, one in a node only
580
+ // the Reviewer role may read.
581
+ await write(repo2, 'team/access.md', '---\nwrite:\n - Reviewer\n---\n');
582
+ await write(repo2, 'secret/Plan.md', '---\nread:\n - deny everyone\n - Reviewer\n---\n# Plan\n');
583
+ const workspace = stubWorkspace(root2);
584
+ const access = new AccessControlService(workspace as never, KB, new NodeFs());
585
+ const svc = new GroupsAdminService(workspace, stubWorkflow().svc, access, new NodeFs(), KB, () => DEFAULT_BRANCH);
586
+ const rowsFor = async (email: string) =>
587
+ (await svc.getRoster(email)).groups.find((g) => g.canonical === 'reviewer')!.bareNameResolvesToRole;
588
+
589
+ expect(await rowsFor('rev@x.io')).toEqual(
590
+ expect.arrayContaining([
591
+ { path: 'team/access.md', verb: 'write' },
592
+ { path: 'secret/Plan.md', verb: 'read' },
593
+ ]),
594
+ );
595
+ // pat@x.io is in the Reviewer GROUP, not the role: the bare grant is the
596
+ // role's, so the secret file is closed to pat, and so is its path.
597
+ expect(await access.canRead(workspaceIdForBranch(DEFAULT_BRANCH), 'pat@x.io', 'secret/Plan.md')).toBe(false);
598
+ expect(await rowsFor('pat@x.io')).toEqual([{ path: 'team/access.md', verb: 'write' }]);
599
+ } finally {
600
+ await fs.rm(root2, { recursive: true, force: true });
601
+ }
602
+ });
603
+
604
+ it('referencedBy names only the files the viewer can read and omits the rest entirely, uncounted', async () => {
605
+ const root2 = await fs.mkdtemp(path.join(os.tmpdir(), 'bevel-groups-disclose-refs-'));
606
+ try {
607
+ const repo2 = path.join(root2, KB);
608
+ await write(repo2, 'roles.yaml', ROLES); // Admin: admin@x.io, Reviewer: rev@x.io
609
+ await write(repo2, 'groups.yaml', 'groups:\n Ops:\n - ops@x.io\n');
610
+ await write(repo2, 'access.md', '---\nread:\n - everyone\nwrite:\n - Admin\n---\n');
611
+ // Two group/Ops rules: one in an open folder, one in a node only the
612
+ // Reviewer role may read.
613
+ await write(repo2, 'team/access.md', '---\nwrite:\n - group/Ops\n---\n');
614
+ await write(
615
+ repo2,
616
+ 'secret/Plan.md',
617
+ '---\nread:\n - deny everyone\n - Reviewer\nowner:\n - deny group/Ops\n---\n# Plan\n',
618
+ );
619
+ const workspace = stubWorkspace(root2);
620
+ const svc = new GroupsAdminService(
621
+ workspace,
622
+ stubWorkflow().svc,
623
+ new AccessControlService(workspace as never, KB, new NodeFs()),
624
+ new NodeFs(),
625
+ KB,
626
+ () => DEFAULT_BRANCH,
627
+ );
628
+ const opsFor = async (email: string) =>
629
+ (await svc.getRoster(email)).groups.find((g) => g.canonical === 'ops')!;
630
+
631
+ const asReviewer = await opsFor('rev@x.io');
632
+ expect(asReviewer.referencedBy.map((r) => r.path).sort()).toEqual(['secret/Plan.md', 'team/access.md']);
633
+ // The Admin cannot read secret/Plan.md: its rule is left out entirely —
634
+ // not named, and not counted either (Admin status does not grant read).
635
+ const asAdmin = await opsFor('admin@x.io');
636
+ expect(asAdmin.referencedBy).toEqual([{ path: 'team/access.md', verb: 'write' }]);
637
+ expect(asAdmin).not.toHaveProperty('referencesHidden');
445
638
  } finally {
446
639
  await fs.rm(root2, { recursive: true, force: true });
447
640
  }
@@ -0,0 +1,127 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
+ import fs from 'node:fs/promises';
3
+ import path from 'node:path';
4
+ import os from 'node:os';
5
+
6
+ import { realDisk } from '../../../__tests__/real-disk.js';
7
+ import type { WorkspaceService } from '../../workspace/index.js';
8
+ import { AccessControlService } from '../access-control.service.js';
9
+
10
+ /**
11
+ * `prospectiveHolderChanges`: who loses and who gains opening or editing a
12
+ * file or folder in a move, over a real on-disk tree. The holder lists name
13
+ * grants, so these tests are about the cases a list comparison gets wrong: a
14
+ * group still covered by `everyone` where it lands, and someone a rule there
15
+ * denies by name, even when their only access before was `everyone`.
16
+ */
17
+
18
+ const KB_DIR = 'knowledge-base';
19
+ const rules = (body: string) => `---\n${body}---\n`;
20
+
21
+ describe('AccessControlService.prospectiveHolderChanges', () => {
22
+ let root: string;
23
+ let repo: string;
24
+ const workspaceId = 'ws-holder-changes';
25
+
26
+ beforeEach(async () => {
27
+ root = await fs.mkdtemp(path.join(os.tmpdir(), 'bevel-holder-changes-'));
28
+ repo = path.join(root, workspaceId, KB_DIR);
29
+ });
30
+ afterEach(async () => {
31
+ if (root) await fs.rm(root, { recursive: true, force: true });
32
+ });
33
+
34
+ async function write(files: Record<string, string>): Promise<void> {
35
+ for (const [rel, contents] of Object.entries(files)) {
36
+ const abs = path.join(repo, rel);
37
+ await fs.mkdir(path.dirname(abs), { recursive: true });
38
+ await fs.writeFile(abs, contents);
39
+ }
40
+ }
41
+
42
+ const service = () =>
43
+ new AccessControlService(
44
+ {
45
+ getWorkspacePath: async () => path.join(root, workspaceId),
46
+ ensureRemotesFetched: async () => undefined,
47
+ } as unknown as WorkspaceService,
48
+ KB_DIR,
49
+ realDisk(),
50
+ );
51
+
52
+ /** Everyone reads; Support and Operations each edit their own folder. */
53
+ const BASE = {
54
+ 'roles.yaml': 'roles:\n Admin:\n - admin@x.io\n',
55
+ 'groups.yaml': 'groups:\n Support:\n - bea@x.io\n Operations:\n - jonas@x.io\n',
56
+ 'access.md': rules('read:\n - everyone\n'),
57
+ 'Support/access.md': rules('write:\n - Support\n'),
58
+ 'Support/Runbooks/Warranty claim.md': '# Warranty claim\n',
59
+ 'Operations/access.md': rules('write:\n - Operations\n'),
60
+ };
61
+
62
+ it('a folder handed to another team: the old team loses editing, the new one gains it, and nobody loses opening it', async () => {
63
+ await write(BASE);
64
+ const changes = await service().prospectiveHolderChanges(workspaceId, 'Support/Runbooks', 'Operations/Runbooks');
65
+ expect(changes).toEqual({
66
+ lose: [{ kind: 'group', name: 'Support', verb: 'write' }],
67
+ gain: [{ kind: 'group', name: 'Operations', verb: 'write' }],
68
+ });
69
+ });
70
+
71
+ it('a person the destination denies by name loses access, though everyone may still read there', async () => {
72
+ await write({
73
+ ...BASE,
74
+ 'Team/access.md': rules('write:\n - Ana <ana@x.io>\n'),
75
+ 'Team/plan.md': '# Plan\n',
76
+ 'Closed/access.md': rules('read:\n - everyone\n - deny Ana <ana@x.io>\n'),
77
+ });
78
+ const changes = await service().prospectiveHolderChanges(workspaceId, 'Team/plan.md', 'Closed/plan.md');
79
+ expect(changes.lose).toEqual(
80
+ expect.arrayContaining([
81
+ { kind: 'person', name: 'ana@x.io', email: 'ana@x.io', verb: 'read' },
82
+ { kind: 'person', name: 'ana@x.io', email: 'ana@x.io', verb: 'write' },
83
+ ]),
84
+ );
85
+ });
86
+
87
+ it('a person whose only access was everyone, and whom the destination denies by name, loses it', async () => {
88
+ await write({
89
+ ...BASE,
90
+ 'Closed/access.md': rules('read:\n - everyone\n - deny Leo <leo@x.io>\n'),
91
+ });
92
+ const changes = await service().prospectiveHolderChanges(workspaceId, 'Support/Runbooks', 'Closed/Runbooks');
93
+ expect(changes.lose).toContainEqual({ kind: 'person', name: 'leo@x.io', email: 'leo@x.io', verb: 'read' });
94
+ });
95
+
96
+ it('a group whose only read was everyone, and which the destination denies, loses it', async () => {
97
+ await write({
98
+ ...BASE,
99
+ 'Closed/access.md': rules('read:\n - everyone\n - deny Operations\n'),
100
+ });
101
+ const changes = await service().prospectiveHolderChanges(workspaceId, 'Support/Runbooks', 'Closed/Runbooks');
102
+ expect(changes.lose).toContainEqual({ kind: 'group', name: 'Operations', verb: 'read' });
103
+ });
104
+
105
+ it('a group the destination denies loses opening it, though everyone may still read there', async () => {
106
+ await write({
107
+ ...BASE,
108
+ 'Closed/access.md': rules('read:\n - everyone\n - deny Support\n'),
109
+ });
110
+ const changes = await service().prospectiveHolderChanges(workspaceId, 'Support/Runbooks', 'Closed/Runbooks');
111
+ expect(changes.lose).toEqual(
112
+ expect.arrayContaining([
113
+ { kind: 'group', name: 'Support', verb: 'read' },
114
+ { kind: 'group', name: 'Support', verb: 'write' },
115
+ ]),
116
+ );
117
+ });
118
+
119
+ it('a rename that carries its own rules changes nobody', async () => {
120
+ await write({
121
+ ...BASE,
122
+ 'Sales/access.md': rules('read:\n - Support\nwrite:\n - Support\n'),
123
+ 'Sales/deal.md': '# Deal\n',
124
+ });
125
+ expect(await service().prospectiveHolderChanges(workspaceId, 'Sales', 'Revenue')).toEqual({ lose: [], gain: [] });
126
+ });
127
+ });