@bevel-software/platform-core-backend 0.33.0 → 0.34.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 (497) hide show
  1. package/agent-guide/access-control.md +19 -8
  2. package/agent-guide/html-views.md +231 -5
  3. package/agent-guide/tool-manuals.md +1 -1
  4. package/dist/core/catalog-revision.d.ts +12 -1
  5. package/dist/core/catalog-revision.d.ts.map +1 -1
  6. package/dist/core/catalog-revision.js +23 -3
  7. package/dist/core/catalog-revision.js.map +1 -1
  8. package/dist/core/core-ports.d.ts +41 -0
  9. package/dist/core/core-ports.d.ts.map +1 -1
  10. package/dist/core/core-ports.js.map +1 -1
  11. package/dist/core/create-core-server.d.ts.map +1 -1
  12. package/dist/core/create-core-server.js +14 -7
  13. package/dist/core/create-core-server.js.map +1 -1
  14. package/dist/core/create-core-services.d.ts +16 -5
  15. package/dist/core/create-core-services.d.ts.map +1 -1
  16. package/dist/core/create-core-services.js +37 -12
  17. package/dist/core/create-core-services.js.map +1 -1
  18. package/dist/core/lifecycle.d.ts +16 -0
  19. package/dist/core/lifecycle.d.ts.map +1 -1
  20. package/dist/core/lifecycle.js +12 -2
  21. package/dist/core/lifecycle.js.map +1 -1
  22. package/dist/index.d.ts +1 -1
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js.map +1 -1
  25. package/dist/modules/access/access-control.interface.d.ts +17 -9
  26. package/dist/modules/access/access-control.interface.d.ts.map +1 -1
  27. package/dist/modules/access/access-control.service.d.ts +12 -2
  28. package/dist/modules/access/access-control.service.d.ts.map +1 -1
  29. package/dist/modules/access/access-control.service.js +164 -75
  30. package/dist/modules/access/access-control.service.js.map +1 -1
  31. package/dist/modules/access/access-mutation.service.d.ts +22 -24
  32. package/dist/modules/access/access-mutation.service.d.ts.map +1 -1
  33. package/dist/modules/access/access-mutation.service.js +48 -51
  34. package/dist/modules/access/access-mutation.service.js.map +1 -1
  35. package/dist/modules/access/access-view.d.ts.map +1 -1
  36. package/dist/modules/access/access-view.js +12 -11
  37. package/dist/modules/access/access-view.js.map +1 -1
  38. package/dist/modules/access/access.routes.d.ts +3 -0
  39. package/dist/modules/access/access.routes.d.ts.map +1 -1
  40. package/dist/modules/access/access.routes.js +35 -29
  41. package/dist/modules/access/access.routes.js.map +1 -1
  42. package/dist/modules/access/groups-admin.routes.d.ts.map +1 -1
  43. package/dist/modules/access/groups-admin.routes.js +4 -2
  44. package/dist/modules/access/groups-admin.routes.js.map +1 -1
  45. package/dist/modules/access/groups-admin.service.d.ts +44 -13
  46. package/dist/modules/access/groups-admin.service.d.ts.map +1 -1
  47. package/dist/modules/access/groups-admin.service.js +80 -38
  48. package/dist/modules/access/groups-admin.service.js.map +1 -1
  49. package/dist/modules/access/groups-edit.d.ts +1 -1
  50. package/dist/modules/access/groups-edit.d.ts.map +1 -1
  51. package/dist/modules/access/groups-edit.js +1 -1
  52. package/dist/modules/access/groups-edit.js.map +1 -1
  53. package/dist/modules/access/reference-scan.d.ts +116 -24
  54. package/dist/modules/access/reference-scan.d.ts.map +1 -1
  55. package/dist/modules/access/reference-scan.js +305 -44
  56. package/dist/modules/access/reference-scan.js.map +1 -1
  57. package/dist/modules/access/roles-admin.service.d.ts +17 -8
  58. package/dist/modules/access/roles-admin.service.d.ts.map +1 -1
  59. package/dist/modules/access/roles-admin.service.js +32 -23
  60. package/dist/modules/access/roles-admin.service.js.map +1 -1
  61. package/dist/modules/access-model/access-grammar.d.ts +35 -10
  62. package/dist/modules/access-model/access-grammar.d.ts.map +1 -1
  63. package/dist/modules/access-model/access-grammar.js +60 -20
  64. package/dist/modules/access-model/access-grammar.js.map +1 -1
  65. package/dist/modules/access-model/access-splice.d.ts +22 -18
  66. package/dist/modules/access-model/access-splice.d.ts.map +1 -1
  67. package/dist/modules/access-model/access-splice.js +20 -14
  68. package/dist/modules/access-model/access-splice.js.map +1 -1
  69. package/dist/modules/access-model/group-files.d.ts +1 -0
  70. package/dist/modules/access-model/group-files.d.ts.map +1 -1
  71. package/dist/modules/access-model/group-files.js +5 -1
  72. package/dist/modules/access-model/group-files.js.map +1 -1
  73. package/dist/modules/agent-guide/agent-guide.tools.d.ts.map +1 -1
  74. package/dist/modules/agent-guide/agent-guide.tools.js +13 -3
  75. package/dist/modules/agent-guide/agent-guide.tools.js.map +1 -1
  76. package/dist/modules/agent-instructions/compose.d.ts +3 -1
  77. package/dist/modules/agent-instructions/compose.d.ts.map +1 -1
  78. package/dist/modules/agent-instructions/compose.js +3 -1
  79. package/dist/modules/agent-instructions/compose.js.map +1 -1
  80. package/dist/modules/agent-instructions/shared-file-rules.d.ts +5 -1
  81. package/dist/modules/agent-instructions/shared-file-rules.d.ts.map +1 -1
  82. package/dist/modules/agent-instructions/shared-file-rules.js +16 -1
  83. package/dist/modules/agent-instructions/shared-file-rules.js.map +1 -1
  84. package/dist/modules/agent-scope/agent-scope.contract.d.ts +67 -0
  85. package/dist/modules/agent-scope/agent-scope.contract.d.ts.map +1 -0
  86. package/dist/modules/agent-scope/agent-scope.contract.js +27 -0
  87. package/dist/modules/agent-scope/agent-scope.contract.js.map +1 -0
  88. package/dist/modules/agent-scope/connection-scope.d.ts +111 -0
  89. package/dist/modules/agent-scope/connection-scope.d.ts.map +1 -0
  90. package/dist/modules/agent-scope/connection-scope.js +165 -0
  91. package/dist/modules/agent-scope/connection-scope.js.map +1 -0
  92. package/dist/modules/agent-scope/index.d.ts +3 -0
  93. package/dist/modules/agent-scope/index.d.ts.map +1 -0
  94. package/dist/modules/agent-scope/index.js +3 -0
  95. package/dist/modules/agent-scope/index.js.map +1 -0
  96. package/dist/modules/audit/agent-audit.service.d.ts.map +1 -1
  97. package/dist/modules/audit/agent-audit.service.js +2 -0
  98. package/dist/modules/audit/agent-audit.service.js.map +1 -1
  99. package/dist/modules/audit/audit.contract.d.ts +6 -0
  100. package/dist/modules/audit/audit.contract.d.ts.map +1 -1
  101. package/dist/modules/audit/audit.contract.js.map +1 -1
  102. package/dist/modules/auth/account-admission.d.ts +12 -0
  103. package/dist/modules/auth/account-admission.d.ts.map +1 -1
  104. package/dist/modules/auth/account-admission.js +15 -0
  105. package/dist/modules/auth/account-admission.js.map +1 -1
  106. package/dist/modules/auth/auth.middleware.d.ts +27 -1
  107. package/dist/modules/auth/auth.middleware.d.ts.map +1 -1
  108. package/dist/modules/auth/auth.middleware.js +42 -4
  109. package/dist/modules/auth/auth.middleware.js.map +1 -1
  110. package/dist/modules/auth/auth.routes.d.ts +13 -9
  111. package/dist/modules/auth/auth.routes.d.ts.map +1 -1
  112. package/dist/modules/auth/auth.routes.js +35 -29
  113. package/dist/modules/auth/auth.routes.js.map +1 -1
  114. package/dist/modules/auth/auth.service.d.ts +55 -6
  115. package/dist/modules/auth/auth.service.d.ts.map +1 -1
  116. package/dist/modules/auth/auth.service.js +128 -34
  117. package/dist/modules/auth/auth.service.js.map +1 -1
  118. package/dist/modules/auth/index.d.ts +1 -1
  119. package/dist/modules/auth/index.d.ts.map +1 -1
  120. package/dist/modules/auth/index.js +1 -1
  121. package/dist/modules/auth/index.js.map +1 -1
  122. package/dist/modules/auth/oidc-auth-provider.d.ts.map +1 -1
  123. package/dist/modules/auth/oidc-auth-provider.js +2 -9
  124. package/dist/modules/auth/oidc-auth-provider.js.map +1 -1
  125. package/dist/modules/database/core-schema.d.ts +68 -0
  126. package/dist/modules/database/core-schema.d.ts.map +1 -1
  127. package/dist/modules/database/core-schema.js +33 -0
  128. package/dist/modules/database/core-schema.js.map +1 -1
  129. package/dist/modules/declared-variables/declared-variables.routes.d.ts +8 -1
  130. package/dist/modules/declared-variables/declared-variables.routes.d.ts.map +1 -1
  131. package/dist/modules/declared-variables/declared-variables.routes.js +13 -2
  132. package/dist/modules/declared-variables/declared-variables.routes.js.map +1 -1
  133. package/dist/modules/embed/embed.tools.d.ts.map +1 -1
  134. package/dist/modules/embed/embed.tools.js +5 -0
  135. package/dist/modules/embed/embed.tools.js.map +1 -1
  136. package/dist/modules/kb-fs/index.d.ts +2 -0
  137. package/dist/modules/kb-fs/index.d.ts.map +1 -1
  138. package/dist/modules/kb-fs/index.js +1 -0
  139. package/dist/modules/kb-fs/index.js.map +1 -1
  140. package/dist/modules/kb-fs/locking-filesystem.d.ts.map +1 -1
  141. package/dist/modules/kb-fs/locking-filesystem.js +7 -1
  142. package/dist/modules/kb-fs/locking-filesystem.js.map +1 -1
  143. package/dist/modules/kb-fs/repo-path.d.ts +26 -6
  144. package/dist/modules/kb-fs/repo-path.d.ts.map +1 -1
  145. package/dist/modules/kb-fs/repo-path.js +22 -7
  146. package/dist/modules/kb-fs/repo-path.js.map +1 -1
  147. package/dist/modules/kb-fs/tmp-ref.d.ts +36 -0
  148. package/dist/modules/kb-fs/tmp-ref.d.ts.map +1 -0
  149. package/dist/modules/kb-fs/tmp-ref.js +76 -0
  150. package/dist/modules/kb-fs/tmp-ref.js.map +1 -0
  151. package/dist/modules/mcp/mcp-auth.middleware.d.ts +7 -0
  152. package/dist/modules/mcp/mcp-auth.middleware.d.ts.map +1 -1
  153. package/dist/modules/mcp/mcp-auth.middleware.js +14 -1
  154. package/dist/modules/mcp/mcp-auth.middleware.js.map +1 -1
  155. package/dist/modules/mcp/mcp.routes.d.ts +7 -1
  156. package/dist/modules/mcp/mcp.routes.d.ts.map +1 -1
  157. package/dist/modules/mcp/mcp.routes.js +39 -4
  158. package/dist/modules/mcp/mcp.routes.js.map +1 -1
  159. package/dist/modules/mcp/mcp.service.d.ts +11 -0
  160. package/dist/modules/mcp/mcp.service.d.ts.map +1 -1
  161. package/dist/modules/mcp/mcp.service.js +68 -13
  162. package/dist/modules/mcp/mcp.service.js.map +1 -1
  163. package/dist/modules/mcp/oauth/bevel-oauth-provider.d.ts +24 -1
  164. package/dist/modules/mcp/oauth/bevel-oauth-provider.d.ts.map +1 -1
  165. package/dist/modules/mcp/oauth/bevel-oauth-provider.js +45 -10
  166. package/dist/modules/mcp/oauth/bevel-oauth-provider.js.map +1 -1
  167. package/dist/modules/mcp/oauth/oauth-consent.routes.d.ts +9 -0
  168. package/dist/modules/mcp/oauth/oauth-consent.routes.d.ts.map +1 -1
  169. package/dist/modules/mcp/oauth/oauth-consent.routes.js +34 -1
  170. package/dist/modules/mcp/oauth/oauth-consent.routes.js.map +1 -1
  171. package/dist/modules/plugins/index.d.ts +1 -1
  172. package/dist/modules/plugins/index.d.ts.map +1 -1
  173. package/dist/modules/plugins/index.js.map +1 -1
  174. package/dist/modules/plugins/plugin-links.d.ts +18 -2
  175. package/dist/modules/plugins/plugin-links.d.ts.map +1 -1
  176. package/dist/modules/plugins/plugin-links.js.map +1 -1
  177. package/dist/modules/plugins/plugins.routes.d.ts +5 -1
  178. package/dist/modules/plugins/plugins.routes.d.ts.map +1 -1
  179. package/dist/modules/plugins/plugins.routes.js +32 -5
  180. package/dist/modules/plugins/plugins.routes.js.map +1 -1
  181. package/dist/modules/secrets-vault/secrets-vault.routes.d.ts +9 -0
  182. package/dist/modules/secrets-vault/secrets-vault.routes.d.ts.map +1 -1
  183. package/dist/modules/secrets-vault/secrets-vault.routes.js +15 -3
  184. package/dist/modules/secrets-vault/secrets-vault.routes.js.map +1 -1
  185. package/dist/modules/skills/index.d.ts +3 -3
  186. package/dist/modules/skills/index.d.ts.map +1 -1
  187. package/dist/modules/skills/index.js +0 -2
  188. package/dist/modules/skills/index.js.map +1 -1
  189. package/dist/modules/skills/skills.contract.d.ts +16 -0
  190. package/dist/modules/skills/skills.contract.d.ts.map +1 -1
  191. package/dist/modules/skills/skills.service.d.ts.map +1 -1
  192. package/dist/modules/skills/skills.service.js +6 -1
  193. package/dist/modules/skills/skills.service.js.map +1 -1
  194. package/dist/modules/skills/skills.tools.d.ts.map +1 -1
  195. package/dist/modules/skills/skills.tools.js +24 -12
  196. package/dist/modules/skills/skills.tools.js.map +1 -1
  197. package/dist/modules/tool-auth/external-api-key.interface.d.ts +11 -0
  198. package/dist/modules/tool-auth/external-api-key.interface.d.ts.map +1 -1
  199. package/dist/modules/tool-auth/external-api-key.interface.js.map +1 -1
  200. package/dist/modules/tool-auth/external-api-key.service.d.ts +1 -0
  201. package/dist/modules/tool-auth/external-api-key.service.d.ts.map +1 -1
  202. package/dist/modules/tool-auth/external-api-key.service.js +4 -1
  203. package/dist/modules/tool-auth/external-api-key.service.js.map +1 -1
  204. package/dist/modules/tool-auth/index.d.ts +1 -1
  205. package/dist/modules/tool-auth/index.d.ts.map +1 -1
  206. package/dist/modules/tool-auth/internal-token.service.d.ts +9 -0
  207. package/dist/modules/tool-auth/internal-token.service.d.ts.map +1 -1
  208. package/dist/modules/tool-auth/internal-token.service.js +1 -0
  209. package/dist/modules/tool-auth/internal-token.service.js.map +1 -1
  210. package/dist/modules/tool-auth/tool-auth.middleware.d.ts +27 -3
  211. package/dist/modules/tool-auth/tool-auth.middleware.d.ts.map +1 -1
  212. package/dist/modules/tool-auth/tool-auth.middleware.js +32 -6
  213. package/dist/modules/tool-auth/tool-auth.middleware.js.map +1 -1
  214. package/dist/modules/tool-helpers/tool-context.d.ts +7 -0
  215. package/dist/modules/tool-helpers/tool-context.d.ts.map +1 -1
  216. package/dist/modules/tool-helpers/tool-context.js +3 -0
  217. package/dist/modules/tool-helpers/tool-context.js.map +1 -1
  218. package/dist/modules/tool-helpers/tool-handler.d.ts +15 -0
  219. package/dist/modules/tool-helpers/tool-handler.d.ts.map +1 -1
  220. package/dist/modules/tool-helpers/tool-handler.js +19 -0
  221. package/dist/modules/tool-helpers/tool-handler.js.map +1 -1
  222. package/dist/modules/tool-helpers/tool.contract.d.ts +10 -0
  223. package/dist/modules/tool-helpers/tool.contract.d.ts.map +1 -1
  224. package/dist/modules/tool-helpers/tool.contract.js.map +1 -1
  225. package/dist/modules/tool-helpers/validate-token.d.ts +3 -1
  226. package/dist/modules/tool-helpers/validate-token.d.ts.map +1 -1
  227. package/dist/modules/tool-helpers/validate-token.js +1 -1
  228. package/dist/modules/tool-helpers/validate-token.js.map +1 -1
  229. package/dist/modules/tool-manuals/index.d.ts +3 -3
  230. package/dist/modules/tool-manuals/index.d.ts.map +1 -1
  231. package/dist/modules/tool-manuals/index.js +0 -2
  232. package/dist/modules/tool-manuals/index.js.map +1 -1
  233. package/dist/modules/tool-manuals/tool-manuals.contract.d.ts +19 -6
  234. package/dist/modules/tool-manuals/tool-manuals.contract.d.ts.map +1 -1
  235. package/dist/modules/tool-manuals/tool-manuals.routes.d.ts +7 -1
  236. package/dist/modules/tool-manuals/tool-manuals.routes.d.ts.map +1 -1
  237. package/dist/modules/tool-manuals/tool-manuals.routes.js +41 -4
  238. package/dist/modules/tool-manuals/tool-manuals.routes.js.map +1 -1
  239. package/dist/modules/tool-manuals/tool-manuals.service.d.ts +13 -6
  240. package/dist/modules/tool-manuals/tool-manuals.service.d.ts.map +1 -1
  241. package/dist/modules/tool-manuals/tool-manuals.service.js +23 -15
  242. package/dist/modules/tool-manuals/tool-manuals.service.js.map +1 -1
  243. package/dist/modules/tool-manuals/tool-manuals.tools.d.ts.map +1 -1
  244. package/dist/modules/tool-manuals/tool-manuals.tools.js +25 -10
  245. package/dist/modules/tool-manuals/tool-manuals.tools.js.map +1 -1
  246. package/dist/modules/tool-registry/manual.routes.d.ts +8 -1
  247. package/dist/modules/tool-registry/manual.routes.d.ts.map +1 -1
  248. package/dist/modules/tool-registry/manual.routes.js +27 -7
  249. package/dist/modules/tool-registry/manual.routes.js.map +1 -1
  250. package/dist/modules/tool-registry/tool.contract.d.ts +7 -0
  251. package/dist/modules/tool-registry/tool.contract.d.ts.map +1 -1
  252. package/dist/modules/tool-registry/tool.contract.js.map +1 -1
  253. package/dist/modules/workflow/agent-tools/workflow.tools.d.ts.map +1 -1
  254. package/dist/modules/workflow/agent-tools/workflow.tools.js +14 -9
  255. package/dist/modules/workflow/agent-tools/workflow.tools.js.map +1 -1
  256. package/dist/modules/workflow/git/git.service.d.ts +2 -2
  257. package/dist/modules/workflow/git/git.service.d.ts.map +1 -1
  258. package/dist/modules/workflow/git/git.service.js +20 -35
  259. package/dist/modules/workflow/git/git.service.js.map +1 -1
  260. package/dist/modules/workflow/workflow.service.d.ts +2 -1
  261. package/dist/modules/workflow/workflow.service.d.ts.map +1 -1
  262. package/dist/modules/workflow/workflow.service.js +3 -0
  263. package/dist/modules/workflow/workflow.service.js.map +1 -1
  264. package/dist/modules/workspace/file-readers/doc-extract.service.d.ts +28 -4
  265. package/dist/modules/workspace/file-readers/doc-extract.service.d.ts.map +1 -1
  266. package/dist/modules/workspace/file-readers/doc-extract.service.js +61 -40
  267. package/dist/modules/workspace/file-readers/doc-extract.service.js.map +1 -1
  268. package/dist/modules/workspace/index.d.ts +8 -0
  269. package/dist/modules/workspace/index.d.ts.map +1 -1
  270. package/dist/modules/workspace/index.js +8 -0
  271. package/dist/modules/workspace/index.js.map +1 -1
  272. package/dist/modules/workspace/nul-scan.d.ts +19 -0
  273. package/dist/modules/workspace/nul-scan.d.ts.map +1 -0
  274. package/dist/modules/workspace/nul-scan.js +55 -0
  275. package/dist/modules/workspace/nul-scan.js.map +1 -0
  276. package/dist/modules/workspace/pattern-matcher.contract.d.ts +110 -27
  277. package/dist/modules/workspace/pattern-matcher.contract.d.ts.map +1 -1
  278. package/dist/modules/workspace/pattern-matcher.contract.js +30 -13
  279. package/dist/modules/workspace/pattern-matcher.contract.js.map +1 -1
  280. package/dist/modules/workspace/ripgrep-search.d.ts +54 -0
  281. package/dist/modules/workspace/ripgrep-search.d.ts.map +1 -0
  282. package/dist/modules/workspace/ripgrep-search.js +657 -0
  283. package/dist/modules/workspace/ripgrep-search.js.map +1 -0
  284. package/dist/modules/workspace/ripgrep-version.d.ts +15 -0
  285. package/dist/modules/workspace/ripgrep-version.d.ts.map +1 -0
  286. package/dist/modules/workspace/ripgrep-version.js +31 -0
  287. package/dist/modules/workspace/ripgrep-version.js.map +1 -0
  288. package/dist/modules/workspace/startup/beside-checkout.d.ts +8 -5
  289. package/dist/modules/workspace/startup/beside-checkout.d.ts.map +1 -1
  290. package/dist/modules/workspace/startup/beside-checkout.js +14 -5
  291. package/dist/modules/workspace/startup/beside-checkout.js.map +1 -1
  292. package/dist/modules/workspace/worker-pool.d.ts +3 -4
  293. package/dist/modules/workspace/worker-pool.d.ts.map +1 -1
  294. package/dist/modules/workspace/worker-pool.js.map +1 -1
  295. package/dist/modules/workspace/workspace-tmp.d.ts +146 -0
  296. package/dist/modules/workspace/workspace-tmp.d.ts.map +1 -0
  297. package/dist/modules/workspace/workspace-tmp.js +435 -0
  298. package/dist/modules/workspace/workspace-tmp.js.map +1 -0
  299. package/dist/modules/workspace/workspace.routes.d.ts.map +1 -1
  300. package/dist/modules/workspace/workspace.routes.js +5 -26
  301. package/dist/modules/workspace/workspace.routes.js.map +1 -1
  302. package/dist/modules/workspace/workspace.service.d.ts +47 -6
  303. package/dist/modules/workspace/workspace.service.d.ts.map +1 -1
  304. package/dist/modules/workspace/workspace.service.js +86 -6
  305. package/dist/modules/workspace/workspace.service.js.map +1 -1
  306. package/dist/modules/workspace/workspace.tools.d.ts.map +1 -1
  307. package/dist/modules/workspace/workspace.tools.js +460 -116
  308. package/dist/modules/workspace/workspace.tools.js.map +1 -1
  309. package/dist/shared/path-order.d.ts +28 -8
  310. package/dist/shared/path-order.d.ts.map +1 -1
  311. package/dist/shared/path-order.js +37 -8
  312. package/dist/shared/path-order.js.map +1 -1
  313. package/migrations/0022_session_version.sql +6 -0
  314. package/migrations/0023_agent_path.sql +3 -0
  315. package/migrations/meta/0022_snapshot.json +2360 -0
  316. package/migrations/meta/0023_snapshot.json +2378 -0
  317. package/migrations/meta/_journal.json +14 -0
  318. package/package.json +3 -3
  319. package/src/__tests__/pg-scratch.test.ts +69 -0
  320. package/src/__tests__/pg-scratch.ts +31 -0
  321. package/src/__tests__/slow-ripgrep.ts +65 -0
  322. package/src/core/__tests__/boot-without-ripgrep.test.ts +34 -0
  323. package/src/core/__tests__/catalog-revision.test.ts +89 -0
  324. package/src/core/__tests__/damaged-document.tools.test.ts +2 -2
  325. package/src/core/__tests__/gated-boot.test.ts +8 -1
  326. package/src/core/__tests__/lifecycle.test.ts +46 -13
  327. package/src/core/catalog-revision.ts +24 -2
  328. package/src/core/core-ports.ts +42 -0
  329. package/src/core/create-core-server.ts +13 -0
  330. package/src/core/create-core-services.ts +49 -12
  331. package/src/core/lifecycle.ts +26 -2
  332. package/src/index.ts +1 -1
  333. package/src/modules/access/__tests__/access-control.admin-root-floor.test.ts +12 -0
  334. package/src/modules/access/__tests__/access-control.colliding-name-cases.test.ts +113 -0
  335. package/src/modules/access/__tests__/access-control.frontmatter-head.test.ts +117 -0
  336. package/src/modules/access/__tests__/access-control.group-named-admin.test.ts +122 -0
  337. package/src/modules/access/__tests__/access-control.preview-relocation.test.ts +50 -0
  338. package/src/modules/access/__tests__/access-declarations.test.ts +19 -0
  339. package/src/modules/access/__tests__/access-groups.test.ts +55 -22
  340. package/src/modules/access/__tests__/access-mutation.service.test.ts +85 -59
  341. package/src/modules/access/__tests__/access-restrict-here.test.ts +7 -5
  342. package/src/modules/access/__tests__/access.routes.admins.test.ts +1 -0
  343. package/src/modules/access/__tests__/access.routes.batch.test.ts +2 -0
  344. package/src/modules/access/__tests__/access.routes.folder-governs.test.ts +2 -0
  345. package/src/modules/access/__tests__/access.routes.group-grant.test.ts +50 -14
  346. package/src/modules/access/__tests__/access.routes.overrides.test.ts +2 -1
  347. package/src/modules/access/__tests__/access.routes.proposal-branch.test.ts +1 -0
  348. package/src/modules/access/__tests__/access.routes.prospective.test.ts +2 -0
  349. package/src/modules/access/__tests__/access.routes.revoke.test.ts +18 -13
  350. package/src/modules/access/__tests__/access.routes.unknown-email.test.ts +2 -0
  351. package/src/modules/access/__tests__/grant-sources.test.ts +20 -15
  352. package/src/modules/access/__tests__/groups-admin.routes.test.ts +61 -0
  353. package/src/modules/access/__tests__/groups-admin.service.test.ts +211 -18
  354. package/src/modules/access/__tests__/reference-scan.test.ts +366 -14
  355. package/src/modules/access/__tests__/roles-admin.security.test.ts +1 -1
  356. package/src/modules/access/__tests__/roles-admin.service.test.ts +43 -22
  357. package/src/modules/access/__tests__/roles-capabilities.test.ts +6 -2
  358. package/src/modules/access/__tests__/roles.routes.test.ts +1 -1
  359. package/src/modules/access/access-control.interface.ts +17 -10
  360. package/src/modules/access/access-control.service.ts +158 -72
  361. package/src/modules/access/access-mutation.service.ts +48 -53
  362. package/src/modules/access/access-view.ts +12 -10
  363. package/src/modules/access/access.routes.ts +43 -33
  364. package/src/modules/access/groups-admin.routes.ts +4 -2
  365. package/src/modules/access/groups-admin.service.ts +114 -44
  366. package/src/modules/access/groups-edit.ts +1 -1
  367. package/src/modules/access/reference-scan.ts +319 -46
  368. package/src/modules/access/roles-admin.service.ts +43 -26
  369. package/src/modules/access/synced-groups-writer.ts +1 -1
  370. package/src/modules/access-model/__tests__/access-grammar.test.ts +38 -1
  371. package/src/modules/access-model/__tests__/access-splice.test.ts +50 -8
  372. package/src/modules/access-model/access-grammar.ts +65 -20
  373. package/src/modules/access-model/access-splice.ts +31 -23
  374. package/src/modules/access-model/group-files.ts +5 -0
  375. package/src/modules/agent-guide/__tests__/agent-guide.test.ts +31 -0
  376. package/src/modules/agent-guide/agent-guide.tools.ts +13 -2
  377. package/src/modules/agent-instructions/__tests__/shared-file-rules.test.ts +1 -0
  378. package/src/modules/agent-instructions/compose.ts +3 -1
  379. package/src/modules/agent-instructions/shared-file-rules.ts +17 -1
  380. package/src/modules/agent-scope/__tests__/agent-surfaces.connect-as.test.ts +421 -0
  381. package/src/modules/agent-scope/__tests__/connection-scope.test.ts +46 -0
  382. package/src/modules/agent-scope/__tests__/in-memory-kb.ts +148 -0
  383. package/src/modules/agent-scope/agent-scope.contract.ts +83 -0
  384. package/src/modules/agent-scope/connection-scope.ts +199 -0
  385. package/src/modules/agent-scope/index.ts +15 -0
  386. package/src/modules/audit/agent-audit.service.ts +2 -0
  387. package/src/modules/audit/audit.contract.ts +6 -0
  388. package/src/modules/auth/__tests__/auth.middleware.test.ts +30 -2
  389. package/src/modules/auth/__tests__/auth.routes.test.ts +71 -5
  390. package/src/modules/auth/__tests__/auth.service.test.ts +90 -9
  391. package/src/modules/auth/__tests__/password-change-sessions.pg.test.ts +269 -0
  392. package/src/modules/auth/account-admission.ts +19 -0
  393. package/src/modules/auth/auth.middleware.ts +45 -4
  394. package/src/modules/auth/auth.routes.ts +46 -29
  395. package/src/modules/auth/auth.service.ts +135 -34
  396. package/src/modules/auth/index.ts +2 -0
  397. package/src/modules/auth/oidc-auth-provider.ts +2 -9
  398. package/src/modules/database/__tests__/session-version-migration.pg.test.ts +133 -0
  399. package/src/modules/database/core-schema.ts +33 -0
  400. package/src/modules/declared-variables/__tests__/declared-variables.route.test.ts +44 -1
  401. package/src/modules/declared-variables/declared-variables.routes.ts +12 -1
  402. package/src/modules/embed/__tests__/embed.tools.test.ts +12 -0
  403. package/src/modules/embed/embed.tools.ts +5 -0
  404. package/src/modules/kb-fs/__tests__/locking-filesystem.test.ts +25 -0
  405. package/src/modules/kb-fs/__tests__/repo-path.test.ts +53 -8
  406. package/src/modules/kb-fs/index.ts +2 -0
  407. package/src/modules/kb-fs/locking-filesystem.ts +7 -1
  408. package/src/modules/kb-fs/repo-path.ts +33 -7
  409. package/src/modules/kb-fs/tmp-ref.ts +81 -0
  410. package/src/modules/mcp/__tests__/connect-as.pg.test.ts +137 -0
  411. package/src/modules/mcp/__tests__/mcp-auth.middleware.test.ts +29 -5
  412. package/src/modules/mcp/__tests__/mcp-routes-harness.ts +8 -0
  413. package/src/modules/mcp/__tests__/mcp.connect-as.test.ts +195 -0
  414. package/src/modules/mcp/__tests__/mcp.routes.connect-as.test.ts +192 -0
  415. package/src/modules/mcp/__tests__/oauth-consent.connect-as.test.ts +146 -0
  416. package/src/modules/mcp/mcp-auth.middleware.ts +19 -2
  417. package/src/modules/mcp/mcp.routes.ts +39 -3
  418. package/src/modules/mcp/mcp.service.ts +107 -17
  419. package/src/modules/mcp/oauth/bevel-oauth-provider.ts +46 -8
  420. package/src/modules/mcp/oauth/oauth-consent.routes.ts +41 -1
  421. package/src/modules/plugins/__tests__/plugins.tools.test.ts +38 -2
  422. package/src/modules/plugins/index.ts +1 -1
  423. package/src/modules/plugins/plugin-links.ts +19 -2
  424. package/src/modules/plugins/plugins.routes.ts +35 -4
  425. package/src/modules/secrets-vault/__tests__/connect-pending.route.test.ts +113 -0
  426. package/src/modules/secrets-vault/secrets-vault.routes.ts +23 -3
  427. package/src/modules/skills/__tests__/skills.service.test.ts +34 -0
  428. package/src/modules/skills/index.ts +7 -2
  429. package/src/modules/skills/skills.contract.ts +17 -0
  430. package/src/modules/skills/skills.service.ts +5 -1
  431. package/src/modules/skills/skills.tools.ts +44 -13
  432. package/src/modules/tool-auth/__tests__/external-api-key.service.test.ts +4 -0
  433. package/src/modules/tool-auth/external-api-key.interface.ts +11 -1
  434. package/src/modules/tool-auth/external-api-key.service.ts +5 -2
  435. package/src/modules/tool-auth/index.ts +1 -1
  436. package/src/modules/tool-auth/internal-token.service.ts +10 -0
  437. package/src/modules/tool-auth/tool-auth.middleware.ts +45 -3
  438. package/src/modules/tool-helpers/__tests__/can-write.tools.test.ts +3 -1
  439. package/src/modules/tool-helpers/tool-context.ts +10 -0
  440. package/src/modules/tool-helpers/tool-handler.ts +34 -0
  441. package/src/modules/tool-helpers/tool.contract.ts +10 -0
  442. package/src/modules/tool-helpers/validate-token.ts +4 -2
  443. package/src/modules/tool-manuals/__tests__/tool-manuals.archive.route.test.ts +80 -4
  444. package/src/modules/tool-manuals/__tests__/tool-manuals.service.test.ts +42 -0
  445. package/src/modules/tool-manuals/__tests__/tool-manuals.tools.test.ts +3 -3
  446. package/src/modules/tool-manuals/index.ts +6 -2
  447. package/src/modules/tool-manuals/tool-manuals.contract.ts +18 -6
  448. package/src/modules/tool-manuals/tool-manuals.routes.ts +40 -3
  449. package/src/modules/tool-manuals/tool-manuals.service.ts +31 -15
  450. package/src/modules/tool-manuals/tool-manuals.tools.ts +28 -11
  451. package/src/modules/tool-registry/__tests__/tool-description-length.test.ts +2 -2
  452. package/src/modules/tool-registry/manual.routes.ts +26 -5
  453. package/src/modules/tool-registry/tool.contract.ts +7 -0
  454. package/src/modules/workflow/__tests__/workflow.service.facade.test.ts +1 -1
  455. package/src/modules/workflow/__tests__/workflow.service.sync.test.ts +1 -1
  456. package/src/modules/workflow/agent-tools/__tests__/workflow.tools.test.ts +54 -3
  457. package/src/modules/workflow/agent-tools/workflow.tools.ts +14 -9
  458. package/src/modules/workflow/git/__tests__/git.service.list-branches.test.ts +130 -3
  459. package/src/modules/workflow/git/git.service.ts +29 -48
  460. package/src/modules/workflow/workflow.service.ts +5 -0
  461. package/src/modules/workspace/__tests__/git-internals.security.test.ts +2 -2
  462. package/src/modules/workspace/__tests__/holds-nul.test.ts +66 -0
  463. package/src/modules/workspace/__tests__/rest-tool-arguments.test.ts +3 -3
  464. package/src/modules/workspace/__tests__/ripgrep-search.test.ts +570 -0
  465. package/src/modules/workspace/__tests__/ripgrep-version.test.ts +29 -0
  466. package/src/modules/workspace/__tests__/workspace-tmp.tools.test.ts +928 -0
  467. package/src/modules/workspace/__tests__/workspace.routes.read-gate.test.ts +17 -37
  468. package/src/modules/workspace/__tests__/workspace.service.read-filter.test.ts +20 -8
  469. package/src/modules/workspace/__tests__/workspace.tools.agents-file.test.ts +2 -2
  470. package/src/modules/workspace/__tests__/workspace.tools.branch-errors.test.ts +22 -10
  471. package/src/modules/workspace/__tests__/workspace.tools.test.ts +393 -113
  472. package/src/modules/workspace/file-readers/__tests__/doc-extract.service.test.ts +10 -0
  473. package/src/modules/workspace/file-readers/doc-extract.service.ts +71 -38
  474. package/src/modules/workspace/index.ts +20 -0
  475. package/src/modules/workspace/nul-scan.ts +50 -0
  476. package/src/modules/workspace/pattern-matcher.contract.ts +123 -32
  477. package/src/modules/workspace/ripgrep-search.ts +715 -0
  478. package/src/modules/workspace/ripgrep-version.ts +35 -0
  479. package/src/modules/workspace/startup/__tests__/beside-checkout.test.ts +11 -0
  480. package/src/modules/workspace/startup/beside-checkout.ts +13 -5
  481. package/src/modules/workspace/worker-pool.ts +3 -4
  482. package/src/modules/workspace/workspace-tmp.ts +457 -0
  483. package/src/modules/workspace/workspace.routes.ts +6 -27
  484. package/src/modules/workspace/workspace.service.ts +92 -15
  485. package/src/modules/workspace/workspace.tools.ts +500 -155
  486. package/src/shared/path-order.ts +37 -8
  487. package/starter-packs/engineering/Plugins/engineering-starter/access.md +1 -1
  488. package/starter-packs/general/Plugins/general-starter/access.md +1 -1
  489. package/starter-packs/operations/Plugins/operations-starter/access.md +1 -1
  490. package/starter-packs/sales/Plugins/sales-starter/access.md +1 -1
  491. package/starter-packs/support/Plugins/support-starter/access.md +1 -1
  492. package/dist/modules/workspace/bounded-matcher.d.ts +0 -73
  493. package/dist/modules/workspace/bounded-matcher.d.ts.map +0 -1
  494. package/dist/modules/workspace/bounded-matcher.js +0 -200
  495. package/dist/modules/workspace/bounded-matcher.js.map +0 -1
  496. package/src/modules/workspace/__tests__/bounded-matcher.test.ts +0 -213
  497. package/src/modules/workspace/bounded-matcher.ts +0 -271
@@ -9,7 +9,7 @@ Access to any path — reading it as much as writing it — is governed by
9
9
  role to a group* below). Role names are
10
10
  case- and whitespace-insensitive (`Admin` = `admin` = `ADMIN`; `Product Team`
11
11
  = `product team`). The reserved names `deny` and `everyone` cannot be used, and neither can
12
- names starting with `role/` or `plugin/` — those spellings are tokens in
12
+ names starting with `role/`, `group/` or `plugin/` — those spellings are tokens in
13
13
  access entries (below). One exception to the file's authority: the
14
14
  **deployment admin** — the address the server configuration sets as
15
15
  `ADMIN_EMAIL` — is **always an Admin**, whether or not `roles.yaml` lists
@@ -35,8 +35,11 @@ Access to any path — reading it as much as writing it — is governed by
35
35
  denials (the lowercase word `deny`, a space, then the principal).
36
36
  Capitalised forms like `Deny` are *not* triggers; they are treated as part
37
37
  of a name.
38
- - **Principals** are a role name from `roles.yaml`, a group name from
39
- `groups.yaml`, a person as `Name <email>`, a plugin token (above), or
38
+ - **Principals** are a role (`role/<Name>`, from `roles.yaml`), a group
39
+ (`group/<Name>`, from the active group source — `groups.yaml`, or
40
+ `synced-groups.yaml` when groups sync from an identity provider), a person
41
+ as `Name <email>`, a plugin
42
+ token (above), or
40
43
  **`everyone`** — the built-in org-wide principal: every signed-in person and
41
44
  their agents. `read: everyone` in a folder's BODY opens that folder to the
42
45
  whole organisation; it is how an organisation-wide skill or plugin is
@@ -46,8 +49,17 @@ Access to any path — reading it as much as writing it — is governed by
46
49
  to the plugin itself. A person's personal plugin
47
50
  (`{{pluginsDir}}/personal-<id>/`) grants its owner access and denies
48
51
  `everyone` outright, so opening a parent folder never opens it.
49
- When a group and a role share a name, the bare name means the GROUP;
50
- `role/<Name>` (for example `deny role/Reviewer`) always means the role.
52
+ **Write roles as `role/<Name>` and groups as `group/<Name>`** — for
53
+ example `read: group/Platform Team` or `deny role/Reviewer`; the Manage
54
+ access dialog writes them that way too. A bare name (`read: Reviewer`)
55
+ still works and means the ROLE when a role of that name exists, and the
56
+ group otherwise. So a group that shares a role's name is reached only as
57
+ `group/<Name>`: a bare `read: Admin` reaches the `Admin` role, never the
58
+ members of a group named `Admin` (unless `roles.yaml` itself lists that
59
+ group under the role). The same holds for a denial: a bare
60
+ `deny Admin` denies the role, so denying a same-named group needs
61
+ `deny group/Admin`. `role/<Name>` always means the role,
62
+ `group/<Name>` always the group.
51
63
  - **Keep an `access.md` body pure YAML**, with any explanation in `#` comments.
52
64
  A body that does not parse as YAML naming at least one verb is read in the
53
65
  older format instead, where the FRONTMATTER carried the folder's rules — so a
@@ -171,9 +183,8 @@ roles:
171
183
  - **With denials.** Group members hold the role's grants exactly as if they
172
184
  were listed by email. A denial of the role in an `access.md`
173
185
  (`deny role/Reviewer`) therefore removes the role's contribution for
174
- everyone in the group, as it does for the emails. Write the `role/` form:
175
- a bare `deny Reviewer` would deny a group named `Reviewer` instead, if one
176
- exists. The nearest `access.md` that says
186
+ everyone in the group, as it does for the emails. To deny the group
187
+ instead, write `deny group/Platform Team`. The nearest `access.md` that says
177
188
  anything about the person decides: a person granted by name
178
189
  (`Name <email>`) in the SAME `access.md` as the denial keeps that access,
179
190
  because within one file a person's own entry beats a role entry. A grant by
@@ -28,11 +28,17 @@ than by a markdown document.
28
28
 
29
29
  ### `window.bevel`
30
30
 
31
- Core puts four members on it:
31
+ Core puts five members on it:
32
32
 
33
33
  - `window.bevel.openNode(href)` — follow `href` as if the reader had clicked a
34
34
  link to it.
35
35
  - `window.bevel.navigate(href)` — the same function under a second name.
36
+ - `window.bevel.branch` — the branch the page is viewed on, as a string: a
37
+ page that reads its data through the tools and links to what they name
38
+ does both there, so the same page shows a draft's data on the draft and the
39
+ released data on the default branch. `null` where the host has no branch
40
+ for the page (a page embedded on another site); read it as `window.bevel?.branch
41
+ ?? '<default branch>'` so the page still works there.
36
42
  - `window.bevel.tools` — the viewer's tools, or `null` where there are none
37
43
  (next section).
38
44
  - `window.bevel.requireTools()` — ask for the tools when the page cannot work
@@ -147,11 +153,214 @@ if (await window.bevel?.requireTools?.()) {
147
153
  }
148
154
  ```
149
155
 
156
+ ### Live data: a page that stays still while it loads
157
+
158
+ A page that reads its data through `window.bevel.tools` waits on several
159
+ calls before it has anything to show. Write it so the reader never sees the
160
+ page change shape, never sees a half-loaded board as if it were the answer,
161
+ and never loses the board they were reading:
162
+
163
+ - **Render the final page shell in the markup, before any data.** Headings,
164
+ columns, panels and the controls are in the HTML itself, with their size
165
+ reserved in CSS (a grid, a `min-height` per region). The loading treatment —
166
+ placeholder rows, `aria-busy="true"` — sits **inside** the data regions.
167
+ Never start with one "Loading…" line that the script later swaps for the
168
+ whole page: that swap is a full-page layout change, and the first thing the
169
+ reader sees looks broken.
170
+ - **Publish one consistent dataset at a time.** Collect every read into local
171
+ variables first; when ALL of them have succeeded, update every data region
172
+ from that one dataset in one synchronous step. Until then show no counts,
173
+ no cards and no empty columns: "0" or "None" is an answer only a finished
174
+ dataset may give.
175
+ - **Refresh keeps the current board.** A refresh leaves the last published
176
+ dataset on screen, shows a small refreshing state (a status line, the
177
+ Refresh button disabled) and publishes the replacement only when it is
178
+ complete. Never return to the loading placeholders.
179
+ - **A failed read fails the whole load, visibly.** If any read the page needs
180
+ rejects, publish nothing from that load: keep the shell (first load) or the
181
+ last good dataset (refresh), say what failed — the rejection carries the
182
+ tool's own message — and offer a Retry button that runs the same load
183
+ again. Never show the reads that did succeed as if they were the whole
184
+ board.
185
+ - **Read in bounded parallel once the paths are known.** List first
186
+ (`list_files`, `grep`), then read the files it named with a small fixed
187
+ number of `callTool` reads in flight at a time — four is plenty — rather
188
+ than one after another or all at once. Read tools run at once with no
189
+ prompt.
190
+ - **Load with `callTool`, not `callToolChain`.** A chain may write, so the app
191
+ asks the viewer before it runs: a page that loads through `callToolChain`
192
+ shows its reader a "wants to write" card for a read.
193
+ - **The reads are the viewer's own.** Every call answers with exactly what
194
+ the person viewing the page may read: `list_files` and `grep` leave out
195
+ what they may not, and `read_file` of such a file rejects. Build the board
196
+ from what the calls return; never try to widen it (another identity, a
197
+ copied dataset) — the same page shows each reader their own board.
198
+ - **Link to what the tools named by the path they answered.** A path a tool
199
+ answers (`read_file`'s `path`, a listing's `path`) starts with the checkout
200
+ folder, `{{kbDirName}}/Data/Tickets/A.md`, and knows nothing of where the
201
+ page sits. Link to it on the branch the page read it from, each segment of
202
+ the path encoded on its own — `'/workspace/' + encodeURIComponent(BRANCH)
203
+ + '/' + path.split('/').map(encodeURIComponent).join('/')` — so a card and
204
+ its data come from one branch and a name carrying `#`, `?` or `%` stays
205
+ in the path rather than ending the URL at it; a root-relative `'/' +
206
+ path.split('/').map(encodeURIComponent).join('/')` opens it on the branch
207
+ the page is viewed on instead (see *How a link resolves*). Never put the
208
+ checkout folder in front of a path a tool answered: it is already there.
209
+
210
+ A complete page that follows these rules — plain HTML and one inline script,
211
+ no build step and no framework:
212
+
213
+ ```html
214
+ <!doctype html>
215
+ <html>
216
+ <head>
217
+ <style>
218
+ body { font: 14px system-ui, sans-serif; margin: 16px; }
219
+ header { display: flex; align-items: center; gap: 12px; min-height: 40px; }
220
+ #status { color: #555; }
221
+ #status.error { color: #b00020; }
222
+ .board { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; }
223
+ .column { min-height: 320px; border: 1px solid #ddd; border-radius: 6px; padding: 8px; }
224
+ .column ul { list-style: none; margin: 0; padding: 0; }
225
+ .column li { min-height: 20px; padding: 6px; margin-bottom: 6px; border-radius: 4px; background: #f4f4f4; }
226
+ .column li.placeholder { background: #ececec; }
227
+ .count { color: #777; font-weight: normal; }
228
+ </style>
229
+ </head>
230
+ <body>
231
+ <header>
232
+ <h1>Tickets</h1>
233
+ <button id="refresh" type="button" disabled>Refresh</button>
234
+ <span id="status" role="status">Loading…</span>
235
+ <button id="retry" type="button" hidden>Retry</button>
236
+ </header>
237
+ <main id="board" class="board" aria-busy="true">
238
+ <section class="column" data-status="todo"><h2>To do <span class="count"></span></h2><ul><li class="placeholder"></li><li class="placeholder"></li></ul></section>
239
+ <section class="column" data-status="doing"><h2>Doing <span class="count"></span></h2><ul><li class="placeholder"></li><li class="placeholder"></li></ul></section>
240
+ <section class="column" data-status="done"><h2>Done <span class="count"></span></h2><ul><li class="placeholder"></li><li class="placeholder"></li></ul></section>
241
+ </main>
242
+ <script>
243
+ // The branch the page is viewed on: its data and its links both come from
244
+ // there, so the page on a draft shows the draft's tickets. Outside the app
245
+ // (no bridge) it reads the default branch.
246
+ const BRANCH = window.bevel?.branch ?? 'main';
247
+ const FOLDER = 'Data/Tickets';
248
+ const READS_IN_FLIGHT = 4;
249
+ const tools = window.bevel?.tools;
250
+ const board = document.getElementById('board');
251
+ const statusLine = document.getElementById('status');
252
+ const refreshButton = document.getElementById('refresh');
253
+ const retryButton = document.getElementById('retry');
254
+ let published = false;
255
+
256
+ /** The text under `# <heading>` in a node's markdown, whatever its line endings. */
257
+ function field(markdown, heading) {
258
+ const lines = markdown.split(/\r?\n/);
259
+ const at = lines.indexOf('# ' + heading);
260
+ if (at < 0) return '';
261
+ const end = lines.findIndex((line, i) => i > at && line.startsWith('# '));
262
+ return lines.slice(at + 1, end < 0 ? undefined : end).join('\n').trim();
263
+ }
264
+
265
+ /**
266
+ * `fn` over `items`, at most `limit` at a time. After a failure no new item
267
+ * starts; it rejects with the first failure once the calls in flight have
268
+ * settled, so a Retry never overlaps the load that failed.
269
+ */
270
+ async function mapBounded(items, limit, fn) {
271
+ const results = new Array(items.length);
272
+ let next = 0;
273
+ let failure = null;
274
+ async function worker() {
275
+ while (!failure && next < items.length) {
276
+ const i = next++;
277
+ try {
278
+ results[i] = await fn(items[i]);
279
+ } catch (error) {
280
+ failure ??= { error };
281
+ }
282
+ }
283
+ }
284
+ await Promise.all(Array.from({ length: Math.min(limit, items.length) }, worker));
285
+ if (failure) throw failure.error;
286
+ return results;
287
+ }
288
+
289
+ /** The whole dataset, or a rejection. Touches no element. */
290
+ async function readTickets() {
291
+ const listing = await tools.callTool('list_files', { body: { branch: BRANCH, path: FOLDER } });
292
+ const paths = listing.entries
293
+ .filter((entry) => entry.type === 'file' && entry.name.endsWith('.md'))
294
+ .map((entry) => `${FOLDER}/${entry.name}`);
295
+ return mapBounded(paths, READS_IN_FLIGHT, async (path) => {
296
+ const file = await tools.callTool('read_file', { body: { branch: BRANCH, path } });
297
+ // `file.path` is the path as the tool names it, checkout folder first.
298
+ return { path: file.path, name: field(file.content, 'Name') || path, status: field(file.content, 'Status').toLowerCase() };
299
+ });
300
+ }
301
+
302
+ /** Every data region from one dataset, in one synchronous step. */
303
+ function publish(tickets) {
304
+ for (const column of board.querySelectorAll('.column')) {
305
+ const mine = tickets.filter((ticket) => ticket.status === column.dataset.status);
306
+ column.querySelector('.count').textContent = `(${mine.length})`;
307
+ const items = mine.map((ticket) => {
308
+ const link = document.createElement('a');
309
+ // Each segment encoded on its own: a name with `#` in it stays a name.
310
+ link.href = '/workspace/' + encodeURIComponent(BRANCH) + '/' + ticket.path.split('/').map(encodeURIComponent).join('/');
311
+ link.textContent = ticket.name;
312
+ const item = document.createElement('li');
313
+ item.append(link);
314
+ return item;
315
+ });
316
+ if (items.length === 0) {
317
+ const none = document.createElement('li');
318
+ none.textContent = 'None';
319
+ items.push(none);
320
+ }
321
+ column.querySelector('ul').replaceChildren(...items);
322
+ }
323
+ published = true;
324
+ }
325
+
326
+ async function load() {
327
+ refreshButton.disabled = true;
328
+ retryButton.hidden = true;
329
+ board.setAttribute('aria-busy', 'true');
330
+ statusLine.className = '';
331
+ statusLine.textContent = published ? 'Refreshing…' : 'Loading…';
332
+ try {
333
+ publish(await readTickets());
334
+ statusLine.textContent = `Updated ${new Date().toLocaleTimeString()}`;
335
+ } catch (error) {
336
+ statusLine.className = 'error';
337
+ statusLine.textContent = (published ? 'Could not refresh; showing the last loaded board. ' : 'Could not load the tickets. ') + error.message;
338
+ retryButton.hidden = false;
339
+ } finally {
340
+ board.setAttribute('aria-busy', 'false');
341
+ refreshButton.disabled = false;
342
+ }
343
+ }
344
+
345
+ refreshButton.addEventListener('click', load);
346
+ retryButton.addEventListener('click', load);
347
+ if (tools) {
348
+ load();
349
+ } else {
350
+ board.setAttribute('aria-busy', 'false');
351
+ statusLine.textContent = 'Open this page in Bevel to load the tickets.';
352
+ }
353
+ </script>
354
+ </body>
355
+ </html>
356
+ ```
357
+
150
358
  ### Links written in the markup
151
359
 
152
360
  An `<a href>` in the page keeps its address only when it is one of these:
153
361
 
154
362
  - a document of the knowledge base, `.md`, `.html` or `.htm`, with or without a heading — `../Knowledge/Alice.md#goal`, `Q3-Report.html`, `Notes.htm`
363
+ - a root-relative path to such a document, from the checkout folder — `/{{kbDirName}}/Data/Tickets/A.md`
155
364
  - an absolute workspace URL — `/workspace/main/{{knowledgeBaseDir}}/Alice.md`
156
365
  - an external address — `https://example.com/docs`, `http://example.com`, `mailto:team@example.com`
157
366
  - a bare fragment, a place in this page — `#totals`, `#`
@@ -177,10 +386,22 @@ or `window.bevel.navigate(href)`:
177
386
  top" link. The page's own address does not change, so `hashchange` never
178
387
  fires: a page that routes by hash handles its own clicks.
179
388
  - **A relative path** resolves against the folder of the page's own file and
180
- opens that file in the app: from `{{knowledgeBaseDir}}/Reports/Q3.html`,
181
- `../Knowledge/Alice.md#goal` opens `{{knowledgeBaseDir}}/Knowledge/Alice.md`
182
- at its `goal` heading.
183
- - **`/workspace/<branch>/<path>`** opens that file on that branch.
389
+ opens that file in the app, in a new tab, leaving the page where it is:
390
+ from `{{knowledgeBaseDir}}/Reports/Q3.html`, `../Knowledge/Alice.md#goal`
391
+ opens `{{knowledgeBaseDir}}/Knowledge/Alice.md` at its `goal` heading. A
392
+ path that names the page's own file with a fragment (`Q3.html#totals`
393
+ from `Q3.html`) scrolls the page, as `#totals` does.
394
+ - **A root-relative path**, `/{{kbDirName}}/<path>`, opens that file on the
395
+ page's own branch, in a new tab, from a page in any folder. A path a tool
396
+ answered (`read_file`'s `path`, a listing's `path`) already starts with the
397
+ checkout folder, so it is linked as `'/' +
398
+ path.split('/').map(encodeURIComponent).join('/')` — each segment encoded
399
+ on its own, so a name carrying `#`, `?` or `%` stays a name — never with
400
+ the folder put in front of it again; a path the page composed itself,
401
+ without that prefix, gets `'/{{kbDirName}}/'` in front. A link the page's
402
+ script creates after load is kept as written.
403
+ - **`/workspace/<branch>/<path>`** opens that file on that branch, in a new
404
+ tab.
184
405
  - **An external address** (`http:`, `https:`, `mailto:`) opens in a new tab.
185
406
  A call from a script may also open `tel:`, `sms:`, `geo:` and a
186
407
  protocol-relative `//host/path` address in a new tab, though a link
@@ -191,3 +412,8 @@ or `window.bevel.navigate(href)`:
191
412
  A click that a handler of the page has already cancelled with
192
413
  `event.preventDefault()` is left to that handler: the bridge neither scrolls
193
414
  nor opens anything for it.
415
+
416
+ A click on a link with Ctrl, Cmd or Shift held, or with the middle button,
417
+ opens its destination in a new tab, as a browser does with a link: a bare
418
+ fragment opens the page's own file at that section in a new tab, and the
419
+ page stays where it is.
@@ -34,7 +34,7 @@ migration converts such files into `mcp.json` entries; do not write new ones.)
34
34
  ---
35
35
  id: my_tool
36
36
  write:
37
- - Product Team
37
+ - group/Product Team
38
38
  owner:
39
39
  - Jane Doe <jane@x.com>
40
40
  type: http
@@ -2,6 +2,7 @@ import express, { type RequestHandler } from 'express';
2
2
  import type { ISkillService, SkillSummary } from '../modules/skills/skills.contract.js';
3
3
  import type { IToolManualService } from '../modules/tool-manuals/tool-manuals.contract.js';
4
4
  import '../modules/tool-auth/tool-auth.middleware.js';
5
+ import { type IAgentScopeResolver } from '../modules/agent-scope/index.js';
5
6
  /**
6
7
  * The revision of a caller's catalog: a hex digest over the two lists.
7
8
  *
@@ -27,7 +28,15 @@ export declare function catalogRevision(manuals: readonly string[], skills: read
27
28
  views?: readonly {
28
29
  uri: string;
29
30
  text: string;
30
- }[]): string;
31
+ }[],
32
+ /**
33
+ * The connection's agent configuration — its path and the digest of its bytes, or
34
+ * why it cannot be used (`ConnectionScope.fingerprint`) — so an edit of
35
+ * the file is a new revision even when it changes nothing listed (a new
36
+ * skill entry that names nothing yet still moves it). Absent for
37
+ * Everything, whose revision is exactly what it was before agents existed.
38
+ */
39
+ agent?: string | null): string;
31
40
  /**
32
41
  * `GET /agent/catalog-revision` — the caller's catalog fingerprint, plus the
33
42
  * two counts behind it so an operator reading a log can tell a shrinking
@@ -42,6 +51,8 @@ export declare function createCatalogRevisionRoutes(deps: {
42
51
  toolManuals: Pick<IToolManualService, 'catalogFingerprints'>;
43
52
  skills: Pick<ISkillService, 'listSkills'>;
44
53
  manualAuth: RequestHandler;
54
+ /** Resolves the scope of a connection made as an agent configuration (`modules/agent-scope`). */
55
+ agentScope?: Pick<IAgentScopeResolver, 'resolve'>;
45
56
  /** Connection-key/internal-token user id → email, for the per-caller ACL. */
46
57
  resolveUserEmail: (userId: string) => Promise<string | undefined>;
47
58
  /** The MCP App views served; absent on a deployment that serves none. */
@@ -1 +1 @@
1
- {"version":3,"file":"catalog-revision.d.ts","sourceRoot":"","sources":["../../src/core/catalog-revision.ts"],"names":[],"mappings":"AACA,OAAO,OAAO,EAAE,EAAgB,KAAK,cAAc,EAAE,MAAM,SAAS,CAAC;AAErE,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,sCAAsC,CAAC;AACxF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kDAAkD,CAAC;AAC3F,OAAO,8CAA8C,CAAC;AAqCtD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,SAAS,MAAM,EAAE,EAC1B,MAAM,EAAE,SAAS,YAAY,EAAE;AAC/B;;;;GAIG;AACH,KAAK,GAAE,SAAS;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAAO,GACnD,MAAM,CASR;AAED;;;;;;;;;GASG;AACH,wBAAgB,2BAA2B,CAAC,IAAI,EAAE;IAChD,WAAW,EAAE,IAAI,CAAC,kBAAkB,EAAE,qBAAqB,CAAC,CAAC;IAC7D,MAAM,EAAE,IAAI,CAAC,aAAa,EAAE,YAAY,CAAC,CAAC;IAC1C,UAAU,EAAE,cAAc,CAAC;IAC3B,6EAA6E;IAC7E,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAClE,yEAAyE;IACzE,OAAO,CAAC,EAAE;QAAE,QAAQ,IAAI,OAAO,CAAC;YAAE,SAAS,EAAE,SAAS;gBAAE,GAAG,EAAE,MAAM,CAAC;gBAAC,IAAI,EAAE,MAAM,CAAA;aAAE,EAAE,CAAA;SAAE,CAAC,CAAA;KAAE,CAAC;CAC5F,GAAG,OAAO,CAAC,MAAM,CA4BjB"}
1
+ {"version":3,"file":"catalog-revision.d.ts","sourceRoot":"","sources":["../../src/core/catalog-revision.ts"],"names":[],"mappings":"AACA,OAAO,OAAO,EAAE,EAAgB,KAAK,cAAc,EAAE,MAAM,SAAS,CAAC;AAErE,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,sCAAsC,CAAC;AACxF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kDAAkD,CAAC;AAC3F,OAAO,8CAA8C,CAAC;AACtD,OAAO,EAA0B,KAAK,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAqCnG;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,SAAS,MAAM,EAAE,EAC1B,MAAM,EAAE,SAAS,YAAY,EAAE;AAC/B;;;;GAIG;AACH,KAAK,GAAE,SAAS;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAAO;AACpD;;;;;;GAMG;AACH,KAAK,GAAE,MAAM,GAAG,IAAW,GAC1B,MAAM,CAUR;AAED;;;;;;;;;GASG;AACH,wBAAgB,2BAA2B,CAAC,IAAI,EAAE;IAChD,WAAW,EAAE,IAAI,CAAC,kBAAkB,EAAE,qBAAqB,CAAC,CAAC;IAC7D,MAAM,EAAE,IAAI,CAAC,aAAa,EAAE,YAAY,CAAC,CAAC;IAC1C,UAAU,EAAE,cAAc,CAAC;IAC3B,iGAAiG;IACjG,UAAU,CAAC,EAAE,IAAI,CAAC,mBAAmB,EAAE,SAAS,CAAC,CAAC;IAClD,6EAA6E;IAC7E,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAClE,yEAAyE;IACzE,OAAO,CAAC,EAAE;QAAE,QAAQ,IAAI,OAAO,CAAC;YAAE,SAAS,EAAE,SAAS;gBAAE,GAAG,EAAE,MAAM,CAAC;gBAAC,IAAI,EAAE,MAAM,CAAA;aAAE,EAAE,CAAA;SAAE,CAAC,CAAA;KAAE,CAAC;CAC5F,GAAG,OAAO,CAAC,MAAM,CAsCjB"}
@@ -2,6 +2,7 @@ import { createHash } from 'node:crypto';
2
2
  import express from 'express';
3
3
  import { logger } from '../shared/logging.js';
4
4
  import '../modules/tool-auth/tool-auth.middleware.js'; // Express Request augmentation (req.toolAuth)
5
+ import { resolveConnectionScope } from '../modules/agent-scope/index.js';
5
6
  const log = logger('catalog-revision');
6
7
  /**
7
8
  * A fingerprint of ONE caller's released catalog — every tool manual and every
@@ -56,13 +57,22 @@ export function catalogRevision(manuals, skills,
56
57
  * changes a view and nothing else must still move the revision, or a local
57
58
  * server already running keeps serving the view it read at startup.
58
59
  */
59
- views = []) {
60
+ views = [],
61
+ /**
62
+ * The connection's agent configuration — its path and the digest of its bytes, or
63
+ * why it cannot be used (`ConnectionScope.fingerprint`) — so an edit of
64
+ * the file is a new revision even when it changes nothing listed (a new
65
+ * skill entry that names nothing yet still moves it). Absent for
66
+ * Everything, whose revision is exactly what it was before agents existed.
67
+ */
68
+ agent = null) {
60
69
  const lines = [
61
70
  ...[...manuals].sort(),
62
71
  '\u0001', // separates the lists, so a line can never migrate between them
63
72
  ...skills.map(skillFingerprint).sort(),
64
73
  '\u0001',
65
74
  ...views.map((v) => `${v.uri}\u0000${createHash('sha256').update(v.text).digest('hex')}`).sort(),
75
+ ...(agent !== null ? ['\u0001', agent] : []),
66
76
  ];
67
77
  return createHash('sha256').update(lines.join('\n')).digest('hex').slice(0, 32);
68
78
  }
@@ -85,16 +95,26 @@ export function createCatalogRevisionRoutes(deps) {
85
95
  // No resolvable caller is an EMPTY catalog, not a failure: that is what
86
96
  // both list surfaces answer such a caller, so the fingerprint agrees
87
97
  // with them rather than inventing a third verdict.
98
+ // A connection made as an agent configuration is fingerprinted over what IT
99
+ // loads, plus the file itself; Everything asks exactly what it always did.
100
+ const scope = await resolveConnectionScope(deps.agentScope, email, req.toolAuth?.agentPath);
101
+ const connectors = scope.connectorFilter();
102
+ const within = scope.skillFilter();
88
103
  const [manuals, skills] = email
89
- ? await Promise.all([deps.toolManuals.catalogFingerprints(email), deps.skills.listSkills(email)])
104
+ ? await Promise.all([
105
+ connectors ? deps.toolManuals.catalogFingerprints(email, connectors) : deps.toolManuals.catalogFingerprints(email),
106
+ within ? deps.skills.listSkills(email, { within }) : deps.skills.listSkills(email),
107
+ ])
90
108
  : [[], []];
91
109
  // A manifest that cannot be read counts as no views, which is also what
92
110
  // the MCP endpoint serves in that state.
93
111
  const views = deps.mcpApps ? ((await deps.mcpApps.manifest().catch(() => null))?.resources ?? []) : [];
112
+ const connection = scope.toWire();
94
113
  res.json({
95
- revision: catalogRevision(manuals, skills, views),
114
+ revision: catalogRevision(manuals, skills, views, scope.fingerprint()),
96
115
  tools: manuals.length,
97
116
  skills: skills.length,
117
+ ...(connection ? { connection } : {}),
98
118
  });
99
119
  }
100
120
  catch (err) {
@@ -1 +1 @@
1
- {"version":3,"file":"catalog-revision.js","sourceRoot":"","sources":["../../src/core/catalog-revision.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"catalog-revision.js","sourceRoot":"","sources":["../../src/core/catalog-revision.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,OAA8C,MAAM,SAAS,CAAC;AACrE,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAG9C,OAAO,8CAA8C,CAAC,CAAC,8CAA8C;AACrG,OAAO,EAAE,sBAAsB,EAA4B,MAAM,iCAAiC,CAAC;AAEnG,MAAM,GAAG,GAAG,MAAM,CAAC,kBAAkB,CAAC,CAAC;AAEvC;;;;;;;;;;;;;;;;;;;GAmBG;AAEH;;;;;;;GAOG;AACH,SAAS,gBAAgB,CAAC,CAAe;IACvC,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,IAAI,EAAE,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AACzE,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,eAAe,CAC7B,OAA0B,EAC1B,MAA+B;AAC/B;;;;GAIG;AACH,QAAkD,EAAE;AACpD;;;;;;GAMG;AACH,QAAuB,IAAI;IAE3B,MAAM,KAAK,GAAG;QACZ,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,EAAE;QACtB,QAAQ,EAAE,gEAAgE;QAC1E,GAAG,MAAM,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC,IAAI,EAAE;QACtC,QAAQ;QACR,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,GAAG,SAAS,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE;QAChG,GAAG,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;KAC7C,CAAC;IACF,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAClF,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,2BAA2B,CAAC,IAU3C;IACC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAEhC,MAAM,CAAC,GAAG,CAAC,yBAAyB,EAAE,IAAI,CAAC,UAAU,EAAE,KAAK,EAAE,GAAY,EAAE,GAAG,EAAE,EAAE;QACjF,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC;YACpC,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;YAC9F,wEAAwE;YACxE,qEAAqE;YACrE,mDAAmD;YACnD,4EAA4E;YAC5E,2EAA2E;YAC3E,MAAM,KAAK,GAAG,MAAM,sBAAsB,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,EAAE,GAAG,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;YAC5F,MAAM,UAAU,GAAG,KAAK,CAAC,eAAe,EAAE,CAAC;YAC3C,MAAM,MAAM,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;YACnC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,GAAG,KAAK;gBAC7B,CAAC,CAAC,MAAM,OAAO,CAAC,GAAG,CAAC;oBAChB,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,mBAAmB,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,mBAAmB,CAAC,KAAK,CAAC;oBAClH,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC;iBACnF,CAAC;gBACJ,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;YACb,wEAAwE;YACxE,yCAAyC;YACzC,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC,EAAE,SAAS,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACvG,MAAM,UAAU,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;YAClC,GAAG,CAAC,IAAI,CAAC;gBACP,QAAQ,EAAE,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,WAAW,EAAE,CAAC;gBACtE,KAAK,EAAE,OAAO,CAAC,MAAM;gBACrB,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACtC,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,GAAG,CAAC,KAAK,CAAC,0BAA0B,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;YAC/C,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,4BAA4B,EAAE,CAAC,CAAC;QAChE,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -7,7 +7,33 @@ import type { IAccountAdmission } from '../modules/auth/account-admission.js';
7
7
  import type { IWriteAccess } from '../modules/write-access/write-access.js';
8
8
  import type { OnServerStart } from '../modules/workspace/startup/on-server-start.js';
9
9
  import type { AgentGuideHook } from '../modules/agent-guide/agent-guide.js';
10
+ import type { IAgentScopeResolver } from '../modules/agent-scope/index.js';
10
11
  import type { EmbedNodeIdResolver } from '../modules/embed/embed.interface.js';
12
+ import type { IWorkspaceService } from '@bevel-software/platform-shared';
13
+ import type { IAccessControl } from '../modules/access/index.js';
14
+ import type { KbContext } from '../shared/kb-context.js';
15
+ import type { ITreeWalker } from '../shared/fs.contract.js';
16
+ import type { IPluginLinkIndex } from '../modules/plugins/index.js';
17
+ /**
18
+ * The core services a distribution's agent-scope resolver reads through,
19
+ * handed to `CorePorts.agentScope` when core makes it: the clones of the
20
+ * branches, the person's read gate, the branch model and knowledge-base
21
+ * layout, the disk walk that finds its configurations, and the plugin link
22
+ * index that says which plugins a `plugins:`-style entry stands for.
23
+ *
24
+ * Each is the service's CONTRACT, not its class: a resolver written against
25
+ * these runs on any implementation of them — core's own services in a
26
+ * deployment, a stand-in in a distribution's tests — and a resolver that
27
+ * needs more than a contract offers asks for the contract to grow, not for
28
+ * the class.
29
+ */
30
+ export interface AgentScopeCollaborators {
31
+ workspaceService: IWorkspaceService;
32
+ accessControl: IAccessControl;
33
+ kb: KbContext;
34
+ disk: ITreeWalker;
35
+ pluginLinkIndex: IPluginLinkIndex;
36
+ }
11
37
  /**
12
38
  * Every seam the enterprise overlay can fill in the CORE composition
13
39
  * (`createCoreServices`). All fields are optional; each has a safe core-only
@@ -108,6 +134,21 @@ export interface CorePorts {
108
134
  * `modules/agent-guide`.
109
135
  */
110
136
  agentGuide?: AgentGuideHook;
137
+ /**
138
+ * THIS distribution's agent configurations: what "Connect as" offers beside
139
+ * Everything, and what a connection made as one of them loads (see
140
+ * `modules/agent-scope`). Core owns the mechanism and no configuration —
141
+ * the file kind, where it lives and what its definition says are the
142
+ * distribution's, as the file kinds registered for access verbs are. A
143
+ * factory, since a resolver reads through core services that exist only
144
+ * once core is built: called ONCE, during construction, with those
145
+ * services (`AgentScopeCollaborators`), and its answer is the one resolver
146
+ * every surface consults from then on — the tool contexts, which capture it
147
+ * at construction, as much as the routes the server mounts later. Core
148
+ * default: `noAgentConfigurations()` — nothing is offered, and a connection
149
+ * recorded as some path loads nothing, never Everything.
150
+ */
151
+ agentScope?: (core: AgentScopeCollaborators) => IAgentScopeResolver;
111
152
  /**
112
153
  * Mirror this composition's branch model and knowledge-base layout onto the
113
154
  * shared package's PROCESS-WIDE live bindings (`DEFAULT_BRANCH`,
@@ -1 +1 @@
1
- {"version":3,"file":"core-ports.d.ts","sourceRoot":"","sources":["../../src/core/core-ports.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sCAAsC,CAAC;AACzE,OAAO,KAAK,EACV,iBAAiB,EACjB,mBAAmB,EACpB,MAAM,+CAA+C,CAAC;AACvD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yCAAyC,CAAC;AAC9E,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACzE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,4CAA4C,CAAC;AACtF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sCAAsC,CAAC;AAC9E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yCAAyC,CAAC;AAC5E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iDAAiD,CAAC;AACrF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAC5E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAC;AAE/E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,WAAW,SAAS;IACxB;;;;OAIG;IACH,WAAW,CAAC,EAAE,YAAY,CAAC;IAC3B;;;;;OAKG;IACH,aAAa,CAAC,EAAE,mBAAmB,CAAC;IACpC;;;;OAIG;IACH,YAAY,CAAC,EAAE,iBAAiB,CAAC;IACjC;;;;OAIG;IACH,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B;;;;OAIG;IACH,aAAa,CAAC,EAAE,kBAAkB,EAAE,CAAC;IACrC;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,mBAAmB,EAAE,CAAC;IAC5C;;;;;;;;;;;;;OAaG;IACH,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC;;;;OAIG;IACH,cAAc,CAAC,EAAE,SAAS,aAAa,EAAE,CAAC;IAC1C;;;;;;;;OAQG;IACH,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B;;;;;;;OAOG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B;;;;;;;OAOG;IACH,gBAAgB,CAAC,EAAE,iBAAiB,CAAC;IACrC;;;;;;;OAOG;IACH,WAAW,CAAC,EAAE,YAAY,CAAC;IAC3B;;;;;;;OAOG;IACH,mBAAmB,CAAC,EAAE,mBAAmB,CAAC;CAC3C;AAED;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,EAAE,mBAI/B,CAAC"}
1
+ {"version":3,"file":"core-ports.d.ts","sourceRoot":"","sources":["../../src/core/core-ports.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sCAAsC,CAAC;AACzE,OAAO,KAAK,EACV,iBAAiB,EACjB,mBAAmB,EACpB,MAAM,+CAA+C,CAAC;AACvD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yCAAyC,CAAC;AAC9E,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACzE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,4CAA4C,CAAC;AACtF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sCAAsC,CAAC;AAC9E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yCAAyC,CAAC;AAC5E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iDAAiD,CAAC;AACrF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAC5E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAC3E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAC;AAC/E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACzE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAEpE;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,uBAAuB;IACtC,gBAAgB,EAAE,iBAAiB,CAAC;IACpC,aAAa,EAAE,cAAc,CAAC;IAC9B,EAAE,EAAE,SAAS,CAAC;IACd,IAAI,EAAE,WAAW,CAAC;IAClB,eAAe,EAAE,gBAAgB,CAAC;CACnC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,WAAW,SAAS;IACxB;;;;OAIG;IACH,WAAW,CAAC,EAAE,YAAY,CAAC;IAC3B;;;;;OAKG;IACH,aAAa,CAAC,EAAE,mBAAmB,CAAC;IACpC;;;;OAIG;IACH,YAAY,CAAC,EAAE,iBAAiB,CAAC;IACjC;;;;OAIG;IACH,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B;;;;OAIG;IACH,aAAa,CAAC,EAAE,kBAAkB,EAAE,CAAC;IACrC;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,mBAAmB,EAAE,CAAC;IAC5C;;;;;;;;;;;;;OAaG;IACH,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC;;;;OAIG;IACH,cAAc,CAAC,EAAE,SAAS,aAAa,EAAE,CAAC;IAC1C;;;;;;;;OAQG;IACH,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B;;;;;;;;;;;;;OAaG;IACH,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,uBAAuB,KAAK,mBAAmB,CAAC;IACpE;;;;;;;OAOG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B;;;;;;;OAOG;IACH,gBAAgB,CAAC,EAAE,iBAAiB,CAAC;IACrC;;;;;;;OAOG;IACH,WAAW,CAAC,EAAE,YAAY,CAAC;IAC3B;;;;;;;OAOG;IACH,mBAAmB,CAAC,EAAE,mBAAmB,CAAC;CAC3C;AAED;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,EAAE,mBAI/B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"core-ports.js","sourceRoot":"","sources":["../../src/core/core-ports.ts"],"names":[],"mappings":"AAwJA;;;;;GAKG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAwB;IACpD,KAAK,CAAC,GAAG;QACP,yCAAyC;IAC3C,CAAC;CACF,CAAC"}
1
+ {"version":3,"file":"core-ports.js","sourceRoot":"","sources":["../../src/core/core-ports.ts"],"names":[],"mappings":"AAkMA;;;;;GAKG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAwB;IACpD,KAAK,CAAC,GAAG;QACP,yCAAyC;IAC3C,CAAC;CACF,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"create-core-server.d.ts","sourceRoot":"","sources":["../../src/core/create-core-server.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AAG9B,OAAO,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAiDtD,OAAO,EAAwB,KAAK,eAAe,EAAE,MAAM,2CAA2C,CAAC;AAmCvG,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAO9D,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,OAAO,CAAC,CAAC;AAE7C;;;;;;;;;GASG;AACH,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,YAAY,CAAC,cAAc,CAAC,CAAC;IACvC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,cAAc,CAAC;IACzB,WAAW,EAAE,YAAY,CAAC,oBAAoB,CAAC,CAAC;IAChD,kEAAkE;IAClE,eAAe,EAAE,eAAe,CAAC;IACjC,IAAI,EAAE,YAAY,CAAC;CACpB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;;;;;;;;;;OAYG;IACH,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;IACjC;;;;OAIG;IACH,MAAM,CAAC,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAClD,mFAAmF;IACnF,OAAO,CAAC,CAAC,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,YAAY,GAAG,IAAI,CAAC;IACpD;;;;OAIG;IACH,KAAK,CAAC,CAAC,GAAG,EAAE,cAAc,GAAG,IAAI,CAAC;IAClC;;;;OAIG;IACH,SAAS,CAAC,CAAC,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,YAAY,GAAG,IAAI,CAAC;IACtD,2EAA2E;IAC3E,MAAM,CAAC,CAAC,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,YAAY,GAAG,IAAI,CAAC;CACpD;AAED,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,YAAY,EAClB,GAAG,GAAE,gBAAqB,EAC1B,IAAI,GAAE;IACJ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iFAAiF;IACjF,IAAI,CAAC,EAAE,OAAO,CAAC;CACX,GACL,OAAO,CAAC,UAAU,CAAC,CA8wBrB"}
1
+ {"version":3,"file":"create-core-server.d.ts","sourceRoot":"","sources":["../../src/core/create-core-server.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AAG9B,OAAO,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAkDtD,OAAO,EAAwB,KAAK,eAAe,EAAE,MAAM,2CAA2C,CAAC;AAmCvG,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAO9D,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,OAAO,CAAC,CAAC;AAE7C;;;;;;;;;GASG;AACH,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,YAAY,CAAC,cAAc,CAAC,CAAC;IACvC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,cAAc,CAAC;IACzB,WAAW,EAAE,YAAY,CAAC,oBAAoB,CAAC,CAAC;IAChD,kEAAkE;IAClE,eAAe,EAAE,eAAe,CAAC;IACjC,IAAI,EAAE,YAAY,CAAC;CACpB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;;;;;;;;;;OAYG;IACH,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;IACjC;;;;OAIG;IACH,MAAM,CAAC,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAClD,mFAAmF;IACnF,OAAO,CAAC,CAAC,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,YAAY,GAAG,IAAI,CAAC;IACpD;;;;OAIG;IACH,KAAK,CAAC,CAAC,GAAG,EAAE,cAAc,GAAG,IAAI,CAAC;IAClC;;;;OAIG;IACH,SAAS,CAAC,CAAC,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,YAAY,GAAG,IAAI,CAAC;IACtD,2EAA2E;IAC3E,MAAM,CAAC,CAAC,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,YAAY,GAAG,IAAI,CAAC;CACpD;AAED,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,YAAY,EAClB,GAAG,GAAE,gBAAqB,EAC1B,IAAI,GAAE;IACJ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iFAAiF;IACjF,IAAI,CAAC,EAAE,OAAO,CAAC;CACX,GACL,OAAO,CAAC,UAAU,CAAC,CA0xBrB"}
@@ -2,6 +2,7 @@ import express from 'express';
2
2
  import cors from 'cors';
3
3
  import path from 'node:path';
4
4
  import { createAuthRoutes } from '../modules/auth/auth.routes.js';
5
+ import { authCookieSecure } from '../modules/auth/auth.middleware.js';
5
6
  import { createWorkspaceRoutes } from '../modules/workspace/workspace.routes.js';
6
7
  import { createAgentUploadRoutes, isAgentUploadRawBodyPath, } from '../modules/workspace/agent-upload.routes.js';
7
8
  import { createAgentDownloadRoutes } from '../modules/workspace/agent-download.routes.js';
@@ -228,7 +229,10 @@ export async function createCoreServer(core, ext = {}, opts = {}) {
228
229
  if (opts.boot ?? true)
229
230
  await startCore(core, ext);
230
231
  // Auth routes (unprotected — login endpoint must be accessible)
231
- app.use('/api', createAuthRoutes(core.authService, core.authMiddleware, core.authProviders, core.config.loginPasswordEnabled));
232
+ app.use('/api', createAuthRoutes(core.authService, core.authMiddleware, core.authProviders, core.config.loginPasswordEnabled,
233
+ // The cookie's Secure flag follows the scheme the deployment is reached
234
+ // on, as the SSO providers' does: one rule for every sign-in path.
235
+ { cookieSecure: authCookieSecure(core.config.publicBackendUrl) }));
232
236
  // MCP routes must mount BEFORE every `app.use('/api', authMiddleware, …)`
233
237
  // below: Express 5 fires the outer JWT middleware before deciding whether
234
238
  // its router has a matching route, so a request to `POST /api/mcp` carrying
@@ -237,7 +241,7 @@ export async function createCoreServer(core, ext = {}, opts = {}) {
237
241
  app.use('/api', createMcpRoutes(core.mcpService, core.externalApiKeyService, core.mcpAuthMiddleware, core.authMiddleware, core.usageMeter,
238
242
  // The local-token exchange: verifies an MCP OAuth access token and mints
239
243
  // the loopback internal token the local MCP server uses for its REST reads.
240
- core.internalTokenService, core.mcpOAuthProvider, core.mcpResourceMetadataUrl));
244
+ core.internalTokenService, core.mcpOAuthProvider, core.mcpResourceMetadataUrl, core.agentScopeService));
241
245
  // Remote sync — `POST /api/sync`, called by a git host's webhook or a
242
246
  // pipeline with the deployment's sync secret (or by an admin's session).
243
247
  // Same reason as MCP for mounting here: a non-JWT bearer must not meet a
@@ -273,6 +277,7 @@ export async function createCoreServer(core, ext = {}, opts = {}) {
273
277
  toolManualService: core.toolManualService,
274
278
  accessControl: core.accessControl,
275
279
  connectionProbe: core.connectionProbeService,
280
+ agents: core.agentScopeService,
276
281
  stateSecret: core.config.jwtSecret,
277
282
  publicBackendUrl: core.config.publicBackendUrl,
278
283
  publicFrontendUrl: core.config.publicFrontendUrl,
@@ -394,7 +399,7 @@ export async function createCoreServer(core, ext = {}, opts = {}) {
394
399
  // What MCP clients are told about each platform tool's effect: read by the
395
400
  // agent manual (the hosted endpoint) and by `/agent/tool-hints` (hexis-mcp).
396
401
  const { readOnlyHints } = core;
397
- toolsRouter.use(createManualRoutes(core.toolRegistry, core.manualAuthMiddleware, async (userId) => (await core.authService.getUserById(userId))?.email, readOnlyHints));
402
+ toolsRouter.use(createManualRoutes(core.toolRegistry, core.manualAuthMiddleware, async (userId) => (await core.authService.getUserById(userId))?.email, readOnlyHints, core.agentScopeService));
398
403
  toolsRouter.use(createToolHintsAgentRoutes(readOnlyHints, core.manualAuthMiddleware));
399
404
  // The aggregated manual list (KB + the caller's accessible `.tool`s) + inline
400
405
  // `.tool` sub-manuals. Mounted on the tools router so they share `manualAuth`
@@ -405,7 +410,7 @@ export async function createCoreServer(core, ext = {}, opts = {}) {
405
410
  kb: core.kb,
406
411
  disk: core.disk,
407
412
  pluginIndex: core.pluginIndexService,
408
- }));
413
+ }, core.agentScopeService));
409
414
  // What every connected agent is told at session start, as the hosted proxy
410
415
  // composes it: read by the local `hexis-mcp` bridge at startup and by the
411
416
  // External agent access card. Same `manualAuth`, same router, as `all-tools`.
@@ -419,6 +424,7 @@ export async function createCoreServer(core, ext = {}, opts = {}) {
419
424
  skills: core.skillService,
420
425
  manualAuth: core.manualAuthMiddleware,
421
426
  resolveUserEmail: async (userId) => (await core.authService.getUserById(userId))?.email,
427
+ agentScope: core.agentScopeService,
422
428
  // The views move the revision too: a release that changes a view and no
423
429
  // manual would otherwise leave a running local server on the old one.
424
430
  mcpApps: core.mcpAppService,
@@ -428,7 +434,7 @@ export async function createCoreServer(core, ext = {}, opts = {}) {
428
434
  // declaring knowledge-base file server-side, so the file is the allowlist and
429
435
  // the caller cannot widen it. Same `manualAuth` as the rest of the agent
430
436
  // surface.
431
- toolsRouter.use(createDeclaredVariableRoutes(core.toolManualService, core.secretsVaultService, core.manualAuthMiddleware, async (userId) => (await core.authService.getUserById(userId))?.email));
437
+ toolsRouter.use(createDeclaredVariableRoutes(core.toolManualService, core.secretsVaultService, core.manualAuthMiddleware, async (userId) => (await core.authService.getUserById(userId))?.email, core.agentScopeService));
432
438
  app.use('/api', toolsRouter);
433
439
  // The same guard on the PARSED body, for the WHOLE `/workspace/:id` prefix
434
440
  // and ahead of EVERY router under it — the file routes, the review, workflow
@@ -459,7 +465,7 @@ export async function createCoreServer(core, ext = {}, opts = {}) {
459
465
  toolAuth: core.toolAuthMiddleware,
460
466
  isToolCredential: (token) => core.internalTokenService.looksLikeInternalToken(token) ||
461
467
  core.externalApiKeyService.looksLikeExternalApiKey(token),
462
- }), createPluginCreationRoutes(core.pluginProvisionService, async (req) => (req.userId ? ((await core.authService.getUserById(req.userId)) ?? null) : null)));
468
+ }), createPluginCreationRoutes(core.pluginProvisionService, async (req) => (req.userId ? ((await core.authService.getUserById(req.userId)) ?? null) : null), core.agentScopeService));
463
469
  // Protected routes
464
470
  // The same guard again, now BEHIND the JWT check, so an authenticated
465
471
  // request also gets the resolved form judged — a link in the repository that
@@ -490,7 +496,7 @@ export async function createCoreServer(core, ext = {}, opts = {}) {
490
496
  }));
491
497
  app.use('/api', createEventsRoutes(core.eventBus, core.authMiddleware, eventDelivery));
492
498
  app.use('/api', core.authMiddleware, createDiffRoutes(core.diffService, core.authService, core.workflowService, core.accessControl, core.kbDirName));
493
- app.use('/api', core.authMiddleware, createAccessRoutes(core.accessControl, core.workspaceService, core.authService, core.authService, core.workflowService, core.eventBus, core.db, core.kb, [core.config.adminEmail]));
499
+ app.use('/api', core.authMiddleware, createAccessRoutes(core.accessControl, core.workspaceService, core.authService, core.authService, core.workflowService, core.eventBus, core.db, core.kb, core.disk, [core.config.adminEmail]));
494
500
  // Asking for Can edit or Owner on an item from its Manage access dialog, and
495
501
  // the editors' Accept / Decline. Mounted beside the access routes it shares
496
502
  // its gate with: the request is refused by the same canWrite it would
@@ -617,6 +623,7 @@ export async function createCoreServer(core, ext = {}, opts = {}) {
617
623
  clientNameFor: (st) => core.githubFacade.clientNameFor(st),
618
624
  completeConsent: (userId, st) => core.githubFacade.completeConsent(userId, st),
619
625
  },
626
+ agents: core.agentScopeService,
620
627
  }));
621
628
  // What an Owner pastes into Claude's admin settings to register this
622
629
  // deployment as a GitHub Enterprise Server — admins only — plus whether it