@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
@@ -0,0 +1,421 @@
1
+ import type { Server as HttpServer } from 'node:http';
2
+ import express from 'express';
3
+ import { afterEach, describe, expect, it } from 'vitest';
4
+ import { ToolRegistry } from '../../tool-registry/tool-registry.js';
5
+ import { createManualRoutes } from '../../tool-registry/manual.routes.js';
6
+ import { createToolHandlerFactory } from '../../tool-helpers/tool-handler.js';
7
+ import { NOT_AVAILABLE_TO_CONNECTION } from '../index.js';
8
+ import { createToolContextResolver } from '../../tool-helpers/tool-context.js';
9
+ import { toolDef } from '../../tool-helpers/tool-def.js';
10
+ import { createToolAuthMiddleware } from '../../tool-auth/tool-auth.middleware.js';
11
+ import { InternalTokenService } from '../../tool-auth/internal-token.service.js';
12
+ import type { IExternalApiKeyService } from '../../tool-auth/external-api-key.interface.js';
13
+ import {
14
+ registerSkillsTools,
15
+ type GetSkillOptions,
16
+ type ISkillService,
17
+ type ListSkillsOptions,
18
+ type SkillSummary,
19
+ } from '../../skills/index.js';
20
+ import {
21
+ registerToolManualsTools,
22
+ createToolManualsAgentRoutes,
23
+ type ConnectorScope,
24
+ type IToolManualService,
25
+ type ToolManualSummary,
26
+ } from '../../tool-manuals/index.js';
27
+ import { registerAgentGuideTool } from '../../agent-guide/index.js';
28
+ import { agentFile, agentScopeOver, inMemoryKb } from './in-memory-kb.js';
29
+ import { Client } from '@modelcontextprotocol/sdk/client/index.js';
30
+ import { InMemoryTransport } from '@modelcontextprotocol/sdk/inMemory.js';
31
+ import { tmpdir } from 'node:os';
32
+ import { join } from 'node:path';
33
+ import { McpService } from '../../mcp/mcp.service.js';
34
+ import { SpillStore } from '../../workspace/index.js';
35
+
36
+ /**
37
+ * Every agent surface a connection reaches, behind the REAL auth gate, tool
38
+ * context and tool handler, with the REAL agent-scope service over a
39
+ * knowledge base held in memory. The credential decides the scope: a
40
+ * connection key whose row names an `.agent` file, one that names none
41
+ * (Everything), and one whose file is gone.
42
+ *
43
+ * The skill and tool-manual services are stood in for by catalogs that apply
44
+ * the narrowing they are handed the way the real ones do — after their own
45
+ * read gate, which here lets the reader see everything listed. (The real
46
+ * services' read gate with a narrowing is pinned in their own suites.)
47
+ */
48
+
49
+ const ADA = { id: 'u-ada', email: 'ada@example.com', name: 'Ada' };
50
+
51
+ const SKILLS: SkillSummary[] = [
52
+ { name: 'notes', description: 'Release notes.', path: 'Skills/Release/notes' },
53
+ { name: 'pitch', description: 'Sales pitch.', path: 'Skills/Sales/pitch' },
54
+ { name: 'deploy', description: 'Deploys.', path: 'Plugins/Eng/release/skills/deploy' },
55
+ ];
56
+ const MANUALS: (ToolManualSummary & { remote?: boolean })[] = [
57
+ { slug: 'dash', name: 'dash', path: 'Plugins/Eng/release/dash.tool', type: 'http' },
58
+ { slug: 'crm', name: 'crm', path: 'Plugins/Sales/crm.tool', type: 'http' },
59
+ { slug: 'localgit', name: 'localgit', path: 'Plugins/Eng/release/localgit.tool', type: 'mcp', remote: false },
60
+ { slug: 'localcrm', name: 'localcrm', path: 'Plugins/Sales/localcrm.tool', type: 'mcp', remote: false },
61
+ ];
62
+
63
+ const skillService: ISkillService = {
64
+ listSkills: async (_email?: string, o?: ListSkillsOptions) => SKILLS.filter((s) => !o?.within || o.within(s.path)),
65
+ getSkill: async (_email: string, name: string, _file?: string, o?: GetSkillOptions) => {
66
+ const found = SKILLS.find((s) => s.name === name);
67
+ if (!found || (o?.within && !o.within(found.path))) return { ok: false, error: 'not_found' };
68
+ return { ok: true, kind: 'skill', skill: { ...found, body: `# ${name}`, files: [] } };
69
+ },
70
+ invalidate: () => {},
71
+ };
72
+
73
+ const scoped = (within?: ConnectorScope) => MANUALS.filter((m) => !within || within(m.path));
74
+ const toolManualService = {
75
+ listAccessibleCatalog: async (_e: string, within?: ConnectorScope) => ({ tools: scoped(within), invalid: [] }),
76
+ listLocalOnly: async (_e: string, within?: ConnectorScope) =>
77
+ scoped(within)
78
+ .filter((m) => m.remote === false)
79
+ .map((m) => ({ slug: m.slug, name: m.name, path: m.path })),
80
+ // One draft connector per plugin, declared on a branch only.
81
+ listDeclaredOnlyOnBranch: async (_e: string, _branch: string, within?: ConnectorScope) =>
82
+ [
83
+ { name: 'draftdash', path: 'Plugins/Eng/release/draftdash.tool', type: 'http' },
84
+ { name: 'draftcrm', path: 'Plugins/Sales/draftcrm.tool', type: 'http' },
85
+ ].filter((m) => !within || within(m.path)),
86
+ toManualCallTemplates: async (_e: string, opts?: { within?: ConnectorScope }) =>
87
+ scoped(opts?.within)
88
+ .filter((m) => m.remote !== false)
89
+ .map((m) => ({ name: m.name, call_template_type: 'http', url: `https://x.example/${m.name}`, http_method: 'GET' })),
90
+ } as unknown as IToolManualService;
91
+
92
+ /** Keys by plaintext: what each one's row says it connects as. */
93
+ const KEYS: Record<string, string | null> = {
94
+ bevel_everything: null,
95
+ bevel_narrow: 'Agents/narrow.agent',
96
+ bevel_plugin: 'Agents/plugin.agent',
97
+ bevel_gone: 'Agents/gone.agent',
98
+ bevel_prompts: 'Agents/prompts.agent',
99
+ bevel_hidden: 'Agents/hidden.agent',
100
+ };
101
+
102
+ const kb = inMemoryKb(
103
+ {
104
+ 'Agents/narrow.agent': agentFile(
105
+ 'name: narrow\nplatformTools: [list_skills, get_skill, list_tool_setup, list_local_tools, get_agent_guide]\nskills: [Skills/Release]',
106
+ ),
107
+ 'Agents/plugin.agent': agentFile('name: release\nplugins: [Plugins/Eng]'),
108
+ // Skills to work with, and no skill TOOL offered: its skills are still its prompts.
109
+ 'Agents/prompts.agent': agentFile('name: reader\nplatformTools: [read_file]\nskills: [Skills/Release]'),
110
+ // There, but not for this reader: as unusable as a file that is gone.
111
+ 'Agents/hidden.agent': agentFile('name: hidden\nskills: [Skills/Release]'),
112
+ },
113
+ {
114
+ plugins: [{ folder: 'Plugins/Eng/release', linkedSkills: ['Skills/Sales/pitch'] }],
115
+ hidden: new Set(['Agents/hidden.agent']),
116
+ },
117
+ );
118
+
119
+ let http: HttpServer | undefined;
120
+ afterEach(async () => {
121
+ if (http) await new Promise<void>((r) => http!.close(() => r()));
122
+ http = undefined;
123
+ });
124
+
125
+ async function start(opts: { agentScope?: boolean } = {}): Promise<string> {
126
+ const keys = {
127
+ looksLikeExternalApiKey: (t: string) => t.startsWith('bevel_'),
128
+ verifyAndLoadToken: async (t: string) =>
129
+ t in KEYS ? { tokenId: `id-${t}`, user: ADA, agentPath: KEYS[t] } : null,
130
+ } as unknown as IExternalApiKeyService;
131
+ const agentScope = opts.agentScope === false ? undefined : agentScopeOver(kb);
132
+ const toolAuth = createToolAuthMiddleware(keys, new InternalTokenService({ secret: 's' }));
133
+ const resolve = createToolContextResolver({
134
+ authService: { getUserById: async () => ADA } as never,
135
+ workspaceService: {} as never,
136
+ workflowService: {} as never,
137
+ events: {} as never,
138
+ kbDirName: 'knowledge-base',
139
+ creatorAccess: {} as never,
140
+ ...(agentScope ? { agentScope } : {}),
141
+ });
142
+ const th = createToolHandlerFactory(resolve);
143
+ const registry = new ToolRegistry();
144
+ const router = express.Router();
145
+ registerSkillsTools(registry, router, toolAuth, th, skillService);
146
+ registerToolManualsTools(registry, router, toolAuth, th, toolManualService, {
147
+ accessControl: { canWrite: async () => false } as never,
148
+ variableStatus: { statusFor: async () => [] },
149
+ kb: { defaultBranch: 'main', defaultWorkspaceId: () => 'ws-main' },
150
+ });
151
+ registerAgentGuideTool(registry, router, toolAuth, th, async () => [
152
+ { id: 'introduction', title: 'Introduction', body: '## Introduction\n\nHello.' },
153
+ ]);
154
+ // A platform tool the narrow agent does not list.
155
+ registry.registerExternalTool(
156
+ toolDef({ name: 'write_file', description: 'Write.', path: '/api/agent/tools/write_file', inputs: { type: 'object', properties: {} } }),
157
+ );
158
+ router.post('/agent/tools/write_file', toolAuth, th(async () => ({ written: true })));
159
+ router.use(createManualRoutes(registry, toolAuth, async () => ADA.email, undefined, agentScope));
160
+ router.use(createToolManualsAgentRoutes(toolManualService, toolAuth, async () => ADA.email, undefined, agentScope));
161
+ const app = express();
162
+ app.use(express.json());
163
+ app.use('/api', router);
164
+ http = await new Promise<HttpServer>((r) => {
165
+ const s = app.listen(0, () => r(s));
166
+ });
167
+ return `http://127.0.0.1:${(http.address() as { port: number }).port}`;
168
+ }
169
+
170
+ const call = (base: string, key: string, tool: string, body: unknown = {}) =>
171
+ fetch(`${base}/api/agent/tools/${tool}`, {
172
+ method: 'POST',
173
+ headers: { 'content-type': 'application/json', authorization: `Bearer ${key}` },
174
+ body: JSON.stringify(body),
175
+ });
176
+ const get = async (base: string, key: string, path: string) =>
177
+ (await fetch(`${base}/api${path}`, { headers: { authorization: `Bearer ${key}` } })).json();
178
+
179
+ /** An MCP client of the REAL request server, proxying to the routes above with `key`. */
180
+ async function mcpClient(base: string, key: string): Promise<Client> {
181
+ const mcp = new McpService({
182
+ loopbackBaseUrl: base,
183
+ manualName: 'KNOWLEDGE_BASE',
184
+ spillStore: new SpillStore(join(tmpdir(), 'bevel-test-spills')),
185
+ publicFrontendUrl: 'http://localhost:5173',
186
+ });
187
+ const server = await mcp.createRequestServer(
188
+ { userId: ADA.id, tokenId: `id-${key}`, connectionId: null, bearer: key, agentPath: KEYS[key] },
189
+ { jsonrpc: '2.0', id: 1, method: 'prompts/list', params: {} },
190
+ );
191
+ const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
192
+ await server.connect(serverTransport);
193
+ const client = new Client({ name: 't', version: '0' }, { capabilities: {} });
194
+ await client.connect(clientTransport);
195
+ return client;
196
+ }
197
+
198
+ describe('Everything is byte-for-byte today’s surface', () => {
199
+ it('every surface answers a key with no agent exactly as a deployment that cannot narrow at all', async () => {
200
+ const narrowing = await start();
201
+ const answers = async (base: string) => ({
202
+ utcp: await get(base, 'bevel_everything', '/agent/utcp'),
203
+ allTools: await get(base, 'bevel_everything', '/agent/all-tools'),
204
+ skills: await (await call(base, 'bevel_everything', 'list_skills')).json(),
205
+ setup: await (await call(base, 'bevel_everything', 'list_tool_setup')).json(),
206
+ local: await (await call(base, 'bevel_everything', 'list_local_tools')).json(),
207
+ guide: await (await call(base, 'bevel_everything', 'get_agent_guide')).json(),
208
+ write: await (await call(base, 'bevel_everything', 'write_file')).json(),
209
+ });
210
+ const withScope = await answers(narrowing);
211
+ await new Promise<void>((r) => http!.close(() => r()));
212
+ http = undefined;
213
+ const without = await answers(await start({ agentScope: false }));
214
+ expect(JSON.stringify(withScope)).toBe(JSON.stringify(without));
215
+ expect(withScope.allTools).not.toHaveProperty('connection');
216
+ expect(withScope.guide).not.toHaveProperty('connection');
217
+ expect((withScope.skills as { skills: unknown[] }).skills).toHaveLength(3);
218
+ });
219
+ });
220
+
221
+ describe('a key connected as an .agent file', () => {
222
+ it('platformTools: the manual lists only the platform tools it names', async () => {
223
+ const base = await start();
224
+ const names = ((await get(base, 'bevel_narrow', '/agent/utcp')) as { tools: { name: string }[] }).tools.map((t) => t.name);
225
+ expect(names.sort()).toEqual(['get_agent_guide', 'get_skill', 'list_local_tools', 'list_skills', 'list_tool_setup']);
226
+ });
227
+
228
+ it('a call to a platform tool outside it is refused by name and agent, before the tool runs', async () => {
229
+ const base = await start();
230
+ const res = await call(base, 'bevel_narrow', 'write_file');
231
+ expect(res.status).toBe(403);
232
+ expect(await res.json()).toEqual({
233
+ error:
234
+ 'The tool "write_file" is not available to this connection: it is connected as the agent "narrow" ' +
235
+ '(`Agents/narrow.agent`), which does not load it.',
236
+ code: NOT_AVAILABLE_TO_CONNECTION,
237
+ });
238
+ });
239
+
240
+ it('skills: list_skills, get_skill and the skill tools’ own descriptions name only its skills', async () => {
241
+ const base = await start();
242
+ const listed = (await (await call(base, 'bevel_narrow', 'list_skills')).json()) as { skills: SkillSummary[] };
243
+ expect(listed.skills.map((s) => s.name)).toEqual(['notes']);
244
+ expect(await (await call(base, 'bevel_narrow', 'get_skill', { name: 'pitch' })).json()).toEqual({
245
+ ok: false,
246
+ error: 'not_found',
247
+ });
248
+ expect(((await (await call(base, 'bevel_narrow', 'get_skill', { name: 'notes' })).json()) as { ok: boolean }).ok).toBe(true);
249
+ const tools = ((await get(base, 'bevel_narrow', '/agent/utcp')) as { tools: { name: string; description: string }[] }).tools;
250
+ const listSkills = tools.find((t) => t.name === 'list_skills')!;
251
+ expect(listSkills.description).toContain('`notes`');
252
+ expect(listSkills.description).not.toContain('`pitch`');
253
+ });
254
+
255
+ it('plugins: a plugin folder loads its connectors, its skills and the skills it links — nothing else', async () => {
256
+ const base = await start();
257
+ const all = (await get(base, 'bevel_plugin', '/agent/all-tools')) as {
258
+ manuals: { name: string }[];
259
+ connection: unknown;
260
+ };
261
+ expect(all.manuals.map((m) => m.name)).toEqual(['KNOWLEDGE_BASE', 'dash']);
262
+ expect(all.connection).toEqual({ agent: { path: 'Agents/plugin.agent', name: 'release' } });
263
+ const skills = (await (await call(base, 'bevel_plugin', 'list_skills')).json()) as { skills: SkillSummary[] };
264
+ expect(skills.skills.map((s) => s.name).sort()).toEqual(['deploy', 'pitch']);
265
+ // platformTools absent: every platform tool.
266
+ expect((await call(base, 'bevel_plugin', 'write_file')).status).toBe(200);
267
+ });
268
+
269
+ it('list_tool_setup and list_local_tools count only the connection’s connectors', async () => {
270
+ const base = await start();
271
+ const setup = (await (await call(base, 'bevel_plugin', 'list_tool_setup')).json()) as { tools: { name: string }[] };
272
+ expect(setup.tools.map((t) => t.name)).toEqual(['dash', 'localgit']);
273
+ const local = (await (await call(base, 'bevel_plugin', 'list_local_tools')).json()) as { tools: { name: string }[] };
274
+ expect(local.tools.map((t) => t.name)).toEqual(['localgit']);
275
+ const narrowSetup = (await (await call(base, 'bevel_narrow', 'list_tool_setup')).json()) as { tools: unknown[] };
276
+ expect(narrowSetup.tools).toEqual([]);
277
+ // A draft's declarations too: only those of the connection's connectors.
278
+ const onDraft = (await (await call(base, 'bevel_plugin', 'list_tool_setup', { branch: 'ada/draft' })).json()) as {
279
+ onBranchOnly: { name: string }[];
280
+ };
281
+ expect(onDraft.onBranchOnly.map((p) => p.name)).toEqual(['draftdash']);
282
+ });
283
+
284
+ it('the agent guide opens by saying what the connection is connected as', async () => {
285
+ const base = await start();
286
+ const guide = (await (await call(base, 'bevel_narrow', 'get_agent_guide')).json()) as { guide: string; connection: string };
287
+ expect(guide.connection).toContain('connected as the agent "narrow"');
288
+ expect(guide.guide.startsWith(`> ${guide.connection}\n\n## Introduction`)).toBe(true);
289
+ });
290
+ });
291
+
292
+ describe('a key whose .agent file is gone', () => {
293
+ it('loads nothing — no platform tool, no connector, no skill — and every answer says why', async () => {
294
+ const base = await start();
295
+ expect(((await get(base, 'bevel_gone', '/agent/utcp')) as { tools: unknown[] }).tools).toEqual([]);
296
+ const all = (await get(base, 'bevel_gone', '/agent/all-tools')) as {
297
+ manuals: { name: string }[];
298
+ connection: { unavailable: string };
299
+ };
300
+ expect(all.manuals.map((m) => m.name)).toEqual(['KNOWLEDGE_BASE']);
301
+ expect(all.connection.unavailable).toMatch(/`Agents\/gone\.agent`, which no longer exists or which you can no longer read/);
302
+ const res = await call(base, 'bevel_gone', 'list_skills');
303
+ expect(res.status).toBe(403);
304
+ expect(((await res.json()) as { error: string }).error).toBe(all.connection.unavailable);
305
+ });
306
+ });
307
+
308
+ /**
309
+ * `platformTools` decides which tools an agent is OFFERED, not which skills it
310
+ * has: a file that names skills but no skill tool still serves those skills as
311
+ * prompts. Both MCP servers read prompts through `list_skills` and
312
+ * `get_skill`, so this runs the REAL proxy against the REAL routes above.
313
+ * (Local Testing found `prompts/list` empty for exactly such a file.)
314
+ */
315
+ describe('a key whose .agent file names skills but offers no skill tool', () => {
316
+ it('serves its skills as prompts — prompts/list and prompts/get — and nothing beside them', async () => {
317
+ const base = await start();
318
+ const client = await mcpClient(base, 'bevel_prompts');
319
+ try {
320
+ expect((await client.listPrompts()).prompts.map((p) => p.name)).toEqual(['notes']);
321
+ const prompt = await client.getPrompt({ name: 'notes' });
322
+ expect(JSON.stringify(prompt.messages)).toContain('# notes');
323
+ await expect(client.getPrompt({ name: 'pitch' })).rejects.toThrow(/Unknown skill "pitch"/);
324
+ } finally {
325
+ await client.close();
326
+ }
327
+ });
328
+
329
+ it('still offers no skill tool, and refuses one called through MCP by name', async () => {
330
+ const base = await start();
331
+ const names = ((await get(base, 'bevel_prompts', '/agent/utcp')) as { tools: { name: string }[] }).tools.map((t) => t.name);
332
+ expect(names).toEqual([]);
333
+ expect((await call(base, 'bevel_prompts', 'write_file')).status).toBe(403);
334
+ const client = await mcpClient(base, 'bevel_prompts');
335
+ try {
336
+ expect((await client.listTools()).tools.map((t) => t.name)).not.toContain('list_skills');
337
+ const refused = await client.callTool({ name: 'list_skills', arguments: {} });
338
+ expect(refused.isError).toBe(true);
339
+ expect(JSON.stringify(refused.content)).toContain('not available to this connection');
340
+ } finally {
341
+ await client.close();
342
+ }
343
+ });
344
+
345
+ it('answers the local server’s discovery read of its connectors, though it offers no such tool', async () => {
346
+ // `hexis-mcp` asks `list_local_tools` at startup for the connectors it
347
+ // must materialize, whatever the connection is offered: refused, the
348
+ // local server could not start for this agent. Answered with the
349
+ // connection's local connectors — none, for a file that names none.
350
+ const base = await start();
351
+ const res = await call(base, 'bevel_prompts', 'list_local_tools');
352
+ expect(res.status).toBe(200);
353
+ expect(await res.json()).toEqual({ tools: [] });
354
+ const plugin = (await (await call(base, 'bevel_plugin', 'list_local_tools')).json()) as { tools: { name: string }[] };
355
+ expect(plugin.tools.map((t) => t.name)).toEqual(['localgit']);
356
+ // A connection that loads nothing is refused it like any other route.
357
+ const gone = await call(base, 'bevel_gone', 'list_local_tools');
358
+ expect(gone.status).toBe(403);
359
+ expect(((await gone.json()) as { error: string }).error).toMatch(/which no longer exists or which you can no longer read/);
360
+ });
361
+
362
+ it('answers a direct call of the skill routes with its skills alone — exactly its prompts', async () => {
363
+ const base = await start();
364
+ const listed = (await (await call(base, 'bevel_prompts', 'list_skills')).json()) as { skills: SkillSummary[] };
365
+ expect(listed.skills.map((s) => s.name)).toEqual(['notes']);
366
+ expect(await (await call(base, 'bevel_prompts', 'get_skill', { name: 'pitch' })).json()).toEqual({
367
+ ok: false,
368
+ error: 'not_found',
369
+ });
370
+ });
371
+ });
372
+
373
+ /**
374
+ * The MCP surface itself, through the REAL request server: what the agent
375
+ * sees in `tools/list`, `tools_info` and `prompts/list` when the connection
376
+ * is narrowed, and when its file is unusable — gone, or there but no longer
377
+ * readable — where it must load nothing and say why, never Everything.
378
+ */
379
+ describe('over MCP', () => {
380
+ const toolText = (r: unknown) => ((r as { content: { type: string; text: string }[] }).content[0]?.text ?? '');
381
+
382
+ it('tools_info describes the platform tools the agent lists, and not one it leaves out', async () => {
383
+ const base = await start();
384
+ const client = await mcpClient(base, 'bevel_narrow');
385
+ try {
386
+ const info = JSON.parse(
387
+ toolText(
388
+ await client.callTool({
389
+ name: 'tools_info',
390
+ arguments: { tool_names: ['KNOWLEDGE_BASE.list_skills', 'KNOWLEDGE_BASE.write_file'] },
391
+ }),
392
+ ),
393
+ ) as { interfaces: string; not_found: string[] };
394
+ expect(info.interfaces).toContain('list_skills');
395
+ expect(info.not_found).toEqual(['KNOWLEDGE_BASE.write_file']);
396
+ } finally {
397
+ await client.close();
398
+ }
399
+ });
400
+
401
+ for (const [key, why] of [
402
+ ['bevel_gone', 'a file that is gone'],
403
+ ['bevel_hidden', 'a file the person can no longer read'],
404
+ ] as const) {
405
+ it(`${why}: no tool, no prompt, and the one sentence why`, async () => {
406
+ const base = await start();
407
+ const client = await mcpClient(base, key);
408
+ try {
409
+ const listed = await client.listTools();
410
+ expect(listed.tools).toEqual([]);
411
+ expect(JSON.stringify(listed._meta)).toContain(
412
+ `\`${KEYS[key]}\`, which no longer exists or which you can no longer read`,
413
+ );
414
+ expect((await client.listPrompts()).prompts).toEqual([]);
415
+ await expect(client.getPrompt({ name: 'notes' })).rejects.toThrow();
416
+ } finally {
417
+ await client.close();
418
+ }
419
+ });
420
+ }
421
+ });
@@ -0,0 +1,46 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { ConnectionScope, NOT_AVAILABLE_TO_CONNECTION } from '../index.js';
3
+
4
+ /**
5
+ * The one policy for a platform-tool call by a connection: what every route
6
+ * that is a platform tool answers, hosted by `toolHandler` or mounted on its
7
+ * own. Pinned here so the two kinds of route cannot answer differently.
8
+ */
9
+
10
+ const AGENT = { path: 'Agents/ops.agent', name: 'ops' };
11
+ const narrowedTo = (platformTools: string[] | null) =>
12
+ ConnectionScope.narrowed(AGENT, { skills: [], connectors: [], platformTools }, 'fp');
13
+
14
+ describe('ConnectionScope.platformToolRefusal', () => {
15
+ it('lets Everything call anything', () => {
16
+ expect(ConnectionScope.everything().platformToolRefusal('create_plugin')).toBeNull();
17
+ });
18
+
19
+ it('lets a narrowed connection call the tools its configuration lists, and refuses the rest by name and agent', () => {
20
+ const scope = narrowedTo(['read_file']);
21
+ expect(scope.platformToolRefusal('read_file')).toBeNull();
22
+ expect(scope.platformToolRefusal('create_plugin')).toEqual({
23
+ error:
24
+ 'The tool "create_plugin" is not available to this connection: it is connected as the agent "ops" (`Agents/ops.agent`), which does not load it.',
25
+ code: NOT_AVAILABLE_TO_CONNECTION,
26
+ });
27
+ // A configuration that names no platform tools loads them all.
28
+ expect(narrowedTo(null).platformToolRefusal('create_plugin')).toBeNull();
29
+ });
30
+
31
+ it('answers a discovery read to a narrowed connection whatever tools it is offered, never to one that loads nothing', () => {
32
+ expect(narrowedTo(['read_file']).platformToolRefusal('list_skills', { discovery: true })).toBeNull();
33
+ expect(narrowedTo(['read_file']).platformToolRefusal('list_skills')).not.toBeNull();
34
+ const gone = ConnectionScope.gone('Agents/gone.agent');
35
+ expect(gone.platformToolRefusal('list_skills', { discovery: true })).toEqual({
36
+ error: gone.refusal('list_skills'),
37
+ code: NOT_AVAILABLE_TO_CONNECTION,
38
+ });
39
+ });
40
+
41
+ it('refuses every tool to a connection whose configuration cannot be used, with the sentence that says why', () => {
42
+ const refusal = ConnectionScope.gone('Agents/gone.agent').platformToolRefusal('read_file');
43
+ expect(refusal?.code).toBe(NOT_AVAILABLE_TO_CONNECTION);
44
+ expect(refusal?.error).toMatch(/no longer exists or which you can no longer read/);
45
+ });
46
+ });
@@ -0,0 +1,148 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { parse as parseYaml } from 'yaml';
3
+ import { pathUnderRoot } from '@bevel-software/platform-shared';
4
+ import { ConnectionScope, type IAgentScopeResolver, type AgentChoice } from '../index.js';
5
+
6
+ /**
7
+ * A distribution's agent configurations, held in memory, resolved the way a
8
+ * distribution resolves them — so core's surfaces are driven through the
9
+ * REAL contract (`IAgentScopeResolver`) by a stand-in for the one thing core
10
+ * does not own: what a configuration is. Here it is a `---` fenced YAML
11
+ * definition (`name`, `description`, `plugins`, `skills`, `connectors`,
12
+ * `platformTools`) at a repo-relative path, read through the reader's read
13
+ * gate, its `plugins:` expanded by a link index. Mutate `files`, `hidden` or
14
+ * `plugins` and the next resolve sees it.
15
+ */
16
+ export interface InMemoryKb {
17
+ /** Repo-relative path → content. */
18
+ files: Map<string, string>;
19
+ /** Paths the reader may NOT read. Everything else `reader` may. */
20
+ hidden: Set<string>;
21
+ plugins: { folder: string; linkedSkills: string[] }[];
22
+ /** The one person who may read anything at all. */
23
+ reader: string;
24
+ }
25
+
26
+ export function inMemoryKb(files: Record<string, string>, extra: Partial<InMemoryKb> = {}): InMemoryKb {
27
+ return { files: new Map(Object.entries(files)), hidden: new Set(), plugins: [], reader: 'ada@example.com', ...extra };
28
+ }
29
+
30
+ /** The extension the stand-in distribution gives its configurations. */
31
+ const EXTENSION = '.agent';
32
+
33
+ interface Definition {
34
+ name: string;
35
+ description: string;
36
+ plugins: string[];
37
+ skills: string[];
38
+ connectors: string[];
39
+ platformTools: string[] | null;
40
+ }
41
+
42
+ function list(obj: Record<string, unknown>, key: string): string[] {
43
+ const v = obj[key];
44
+ if (v === undefined || v === null) return [];
45
+ if (typeof v === 'string') return [v];
46
+ if (Array.isArray(v) && v.every((x) => typeof x === 'string')) return v as string[];
47
+ throw new Error(`its \`${key}\` is not a list of names`);
48
+ }
49
+
50
+ const clean = (p: string): string | null => {
51
+ const n = p.trim().replace(/^\/+/, '').replace(/\/+$/, '');
52
+ return n && !n.split('/').some((s) => s === '..' || s === '.') ? n : null;
53
+ };
54
+
55
+ function parse(content: string, path: string): Definition {
56
+ const m = /^---\n([\s\S]*?)\n---/.exec(content);
57
+ if (!m) throw new Error('it has no `---` fenced definition at the top');
58
+ const obj = (parseYaml(m[1]!) ?? {}) as Record<string, unknown>;
59
+ const base = path.slice(path.lastIndexOf('/') + 1).replace(/\.agent$/i, '');
60
+ const fold = (v: unknown) => (typeof v === 'string' ? v.replace(/\s+/g, ' ').trim() : '');
61
+ return {
62
+ name: fold(obj.name) || base,
63
+ description: fold(obj.description),
64
+ plugins: list(obj, 'plugins').map(clean).filter((p): p is string => p !== null),
65
+ skills: list(obj, 'skills').map(clean).filter((p): p is string => p !== null),
66
+ connectors: list(obj, 'connectors').map(clean).filter((p): p is string => p !== null),
67
+ platformTools: Object.prototype.hasOwnProperty.call(obj, 'platformTools')
68
+ ? list(obj, 'platformTools').map((s) => s.trim()).filter((s) => s.length > 0)
69
+ : null,
70
+ };
71
+ }
72
+
73
+ /** The stand-in distribution's resolver over `kb`. */
74
+ export function agentScopeOver(kb: InMemoryKb): IAgentScopeResolver {
75
+ const readable = (email: string | undefined, path: string): boolean => email === kb.reader && !kb.hidden.has(path);
76
+ const normalize = (agentPath: string): string | null => {
77
+ const n = clean(agentPath.replace(/\\/g, '/').replace(/\/{2,}/g, '/'));
78
+ return n !== null && n.endsWith(EXTENSION) ? n : null;
79
+ };
80
+ return {
81
+ async resolve(userEmail, agentPath) {
82
+ if (!agentPath) return ConnectionScope.everything();
83
+ const rel = normalize(agentPath);
84
+ if (rel === null || !readable(userEmail, rel)) return ConnectionScope.gone(rel ?? agentPath);
85
+ const content = kb.files.get(rel);
86
+ if (content === undefined) return ConnectionScope.gone(rel);
87
+ const digest = createHash('sha256').update(content).digest('hex');
88
+ const fingerprint = `agent\u0000${rel}\u0000${digest}`;
89
+ let def: Definition;
90
+ try {
91
+ def = parse(content, rel);
92
+ } catch (err) {
93
+ return ConnectionScope.unavailable(
94
+ { path: rel, name: rel },
95
+ `This connection was made as the agent \`${rel}\`, which is not a valid agent definition ` +
96
+ `(${(err as Error).message}), so it loads no tools and no skills until the file is fixed.`,
97
+ fingerprint,
98
+ );
99
+ }
100
+ const pluginFolders: string[] = [];
101
+ const linked: string[] = [];
102
+ for (const p of kb.plugins) {
103
+ if (!def.plugins.some((entry) => pathUnderRoot(p.folder, entry))) continue;
104
+ pluginFolders.push(p.folder);
105
+ linked.push(...p.linkedSkills);
106
+ }
107
+ return ConnectionScope.narrowed(
108
+ { path: rel, name: def.name },
109
+ {
110
+ skills: [...def.skills, ...pluginFolders, ...linked],
111
+ connectors: [...def.connectors, ...pluginFolders],
112
+ platformTools: def.platformTools,
113
+ },
114
+ fingerprint,
115
+ );
116
+ },
117
+ async listChoices(userEmail) {
118
+ const choices: AgentChoice[] = [];
119
+ for (const [path, content] of kb.files) {
120
+ if (!path.endsWith(EXTENSION) || !readable(userEmail, path)) continue;
121
+ try {
122
+ const def = parse(content, path);
123
+ choices.push({ path, name: def.name, description: def.description });
124
+ } catch {
125
+ // Not a valid definition: not offered.
126
+ }
127
+ }
128
+ return choices.sort((a, b) => a.name.localeCompare(b.name) || a.path.localeCompare(b.path));
129
+ },
130
+ async choosable(userEmail, agentPath) {
131
+ const rel = normalize(agentPath);
132
+ if (rel === null || !readable(userEmail, rel)) return null;
133
+ const content = kb.files.get(rel);
134
+ if (content === undefined) return null;
135
+ try {
136
+ parse(content, rel);
137
+ return rel;
138
+ } catch {
139
+ return null;
140
+ }
141
+ },
142
+ };
143
+ }
144
+
145
+ /** A configuration as the stand-in distribution writes it: the definition in its fence, prose after. */
146
+ export function agentFile(definition: string): string {
147
+ return `---\n${definition}\n---\n\nNotes for people.\n`;
148
+ }