@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
@@ -43,6 +43,7 @@ import {
43
43
  EXTERNAL_KB_MANUAL_NAME,
44
44
  MAX_CAPABILITIES,
45
45
  type IToolManualService,
46
+ type ConnectorScope,
46
47
  type ToolManualDescriptor,
47
48
  type ToolManualDescriptorBase,
48
49
  type ToolManualSummary,
@@ -58,6 +59,7 @@ import {
58
59
  type ToolProbeTarget,
59
60
  type ToolVariableScope,
60
61
  type ToolVariableOAuth,
62
+ type LiveDeclaration,
61
63
  } from './tool-manuals.contract.js';
62
64
 
63
65
  const CACHE_TTL_MS = 60_000;
@@ -181,6 +183,19 @@ export function describeManualFault(err: unknown): string {
181
183
  interface ScanResult {
182
184
  manuals: ToolManualDescriptor[];
183
185
  invalid: InvalidToolManual[];
186
+ /**
187
+ * Every manual the parse refused whose file still says which manual it is,
188
+ * by slug, with the reason. Not a listing surface (`invalid` is that, by
189
+ * path): it lets a sign-in started on a refused declaration answer why,
190
+ * where the slug alone would otherwise find nothing.
191
+ */
192
+ refused: RefusedManual[];
193
+ }
194
+
195
+ interface RefusedManual {
196
+ slug: string;
197
+ path: string;
198
+ reason: string;
184
199
  }
185
200
 
186
201
  /**
@@ -190,7 +205,7 @@ interface ScanResult {
190
205
  * convention instance is one push away from every empty scan in the process
191
206
  * inheriting another's contents.
192
207
  */
193
- const emptyScan = (): ScanResult => ({ manuals: [], invalid: [] });
208
+ const emptyScan = (): ScanResult => ({ manuals: [], invalid: [], refused: [] });
194
209
 
195
210
  const manualSerializer = new UtcpManualSerializer();
196
211
  const callTemplateSerializer = new CallTemplateSerializer();
@@ -208,8 +223,8 @@ export interface McpAuthDiscoveryPort {
208
223
  /**
209
224
  * The sign-in endpoints for an OWNER-REGISTERED client: the same metadata
210
225
  * walk as `statusFor`, stopping short of dynamic registration — the manual
211
- * already names its `clientId`. Nothing is persisted; the owner's
212
- * client-secret save pins the completed provider. Optional so a port that
226
+ * already names its `clientId`. Nothing is persisted; every sign-in start
227
+ * completes the declaration afresh (`liveDeclaration`). Optional so a port that
213
228
  * only knows the zero-config path still satisfies the interface.
214
229
  */
215
230
  providerForDeclaredClient?(manualName: string, mcpUrl: string, clientId: string): Promise<McpAuthDiscoveryResult>;
@@ -304,8 +319,8 @@ export class ToolManualService implements IToolManualService {
304
319
  return (await this.accessibleManuals(userEmail)).map(toSummary);
305
320
  }
306
321
 
307
- async listAccessibleCatalog(userEmail: string): Promise<AccessibleCatalog> {
308
- const { manuals, invalid } = await this.accessibleScan(userEmail);
322
+ async listAccessibleCatalog(userEmail: string, within?: ConnectorScope): Promise<AccessibleCatalog> {
323
+ const { manuals, invalid } = await this.accessibleScan(userEmail, within);
309
324
  return { tools: manuals.map(toSummary), invalid };
310
325
  }
311
326
 
@@ -313,8 +328,8 @@ export class ToolManualService implements IToolManualService {
313
328
  return (await this.scan()).manuals.map(toSummary);
314
329
  }
315
330
 
316
- async catalogFingerprints(userEmail: string): Promise<string[]> {
317
- return (await this.accessibleManuals(userEmail)).map(manualFingerprint);
331
+ async catalogFingerprints(userEmail: string, within?: ConnectorScope): Promise<string[]> {
332
+ return (await this.accessibleManuals(userEmail, within)).map(manualFingerprint);
318
333
  }
319
334
 
320
335
  async getDetail(userEmail: string, slug: string): Promise<ToolManualDetail | null> {
@@ -341,14 +356,47 @@ export class ToolManualService implements IToolManualService {
341
356
  };
342
357
  }
343
358
 
344
- async listLocalOnly(userEmail: string): Promise<{ slug: string; name: string; path: string }[]> {
345
- const manuals = await this.accessibleManuals(userEmail);
359
+ async liveDeclaration(
360
+ userEmail: string,
361
+ slug: string,
362
+ varName: string,
363
+ ): Promise<LiveDeclaration | null> {
364
+ // The disk walk the catalog's scan is built from, run afresh and never
365
+ // cached: a sign-in must follow the file as it is, and the catalog's scan
366
+ // can be a refresh behind it. The whole walk rather than the one file, so
367
+ // the descriptor comes out of exactly the parse, plugin discovery and
368
+ // namespace dedup the catalog applies — a sign-in start is rare and
369
+ // interactive, and a second, single-file reading of the same files is a
370
+ // second place for those rules to drift. A workspace that cannot be opened
371
+ // is an error here, never an empty answer: "no sign-in declared" would be
372
+ // the wrong diagnosis for a server that could not read its files.
373
+ const { manuals, refused } = await this.readableBy(await this.scanDisk(undefined, 'throw'), userEmail);
374
+ const m = manuals.find((x) => x.slug === slug);
375
+ if (!m) {
376
+ // The file is there and says it is this manual, but the parse refused
377
+ // it — e.g. its sign-in names an http:// or private token endpoint. That
378
+ // reason is the answer; "not found" would hide the one thing to fix.
379
+ const r = refused.find((x) => x.slug === slug);
380
+ return r ? { refused: r.reason } : null;
381
+ }
382
+ const variable = (m.variables ?? []).find((v) => v.name === varName);
383
+ // Completed by the catalog's own decoration, on this one fresh descriptor.
384
+ // Only when THIS variable is a sign-in: then the manual has a declared one,
385
+ // so the pass completes its endpoints from the server's metadata and never
386
+ // probes for (or registers) a zero-config client.
387
+ if (variable?.oauth) await this.decorateMcpOAuth([m]);
388
+ return { manual: toSummary(m), ...(variable ? { variable } : {}) };
389
+ }
390
+
391
+ async listLocalOnly(userEmail: string, within?: ConnectorScope): Promise<{ slug: string; name: string; path: string }[]> {
392
+ const manuals = await this.accessibleManuals(userEmail, within);
346
393
  return manuals.filter((m) => m.remote === false).map((m) => ({ slug: m.slug, name: m.name, path: m.path }));
347
394
  }
348
395
 
349
396
  async listDeclaredOnlyOnBranch(
350
397
  userEmail: string,
351
398
  branch: string,
399
+ within?: ConnectorScope,
352
400
  ): Promise<{ name: string; path: string; type: ToolManualType }[]> {
353
401
  if (!branch || branch === this.kb.defaultBranch) return [];
354
402
  // Only a draft this process already holds a clone of — the one the caller
@@ -377,7 +425,7 @@ export class ToolManualService implements IToolManualService {
377
425
  pending.map((m) => m.path),
378
426
  );
379
427
  return pending
380
- .filter((m) => allowed.get(m.path) === true)
428
+ .filter((m) => allowed.get(m.path) === true && (within === undefined || within(m.path)))
381
429
  .map((m) => ({ name: m.name, path: m.path, type: m.type }));
382
430
  }
383
431
 
@@ -456,8 +504,11 @@ export class ToolManualService implements IToolManualService {
456
504
  return { name: m.name, type: m.type, remote: m.remote, healthCheck: m.healthCheck, callTemplate };
457
505
  }
458
506
 
459
- async toManualCallTemplates(userEmail: string, opts?: { remoteOnly?: boolean }): Promise<CallTemplate[]> {
460
- const manuals = await this.accessibleManuals(userEmail);
507
+ async toManualCallTemplates(
508
+ userEmail: string,
509
+ opts?: { remoteOnly?: boolean; within?: ConnectorScope },
510
+ ): Promise<CallTemplate[]> {
511
+ const manuals = await this.accessibleManuals(userEmail, opts?.within);
461
512
  const out: CallTemplate[] = [];
462
513
  for (const m of manuals) {
463
514
  // Remote consumers (the hosted MCP proxy) don't get local-only manuals —
@@ -474,11 +525,17 @@ export class ToolManualService implements IToolManualService {
474
525
  return out;
475
526
  }
476
527
 
477
- async resolveInlineManual(userEmail: string, slug: string): Promise<UtcpManualDict | null> {
528
+ async resolveInlineManual(
529
+ userEmail: string,
530
+ slug: string,
531
+ opts?: { within?: ConnectorScope },
532
+ ): Promise<UtcpManualDict | null> {
478
533
  const found = (await this.scan()).manuals.find((m) => m.slug === slug);
479
534
  if (!found || found.type !== 'inline') return null;
480
535
  const wsId = this.kb.defaultWorkspaceId();
481
536
  if (!(await this.accessControl.canRead(wsId, userEmail, found.path))) return null;
537
+ // After the read gate, as every narrowing is: a connection's scope can only take away.
538
+ if (opts?.within && !opts.within(found.path)) return null;
482
539
  try {
483
540
  return manualSerializer.validateDict({
484
541
  utcp_version: '1.1.0',
@@ -590,8 +647,8 @@ export class ToolManualService implements IToolManualService {
590
647
  };
591
648
  }
592
649
 
593
- private async accessibleManuals(userEmail: string): Promise<ToolManualDescriptor[]> {
594
- return (await this.accessibleScan(userEmail)).manuals;
650
+ private async accessibleManuals(userEmail: string, within?: ConnectorScope): Promise<ToolManualDescriptor[]> {
651
+ return (await this.accessibleScan(userEmail, within)).manuals;
595
652
  }
596
653
 
597
654
  /**
@@ -599,22 +656,33 @@ export class ToolManualService implements IToolManualService {
599
656
  * ONE `canReadBatch`. Both halves are paths in the same workspace judged by
600
657
  * the same rule, and splitting them into two calls would pay a second
601
658
  * round-trip to ask the same question.
659
+ *
660
+ * `within` narrows the answer to a connection's connectors, AFTER the read
661
+ * gate: it can take a manual out of what the caller may read, never put one
662
+ * in. Absent, the answer is the caller's whole readable catalog.
602
663
  */
603
- private async accessibleScan(userEmail: string): Promise<ScanResult> {
604
- const { manuals, invalid } = await this.scan();
605
- if (manuals.length === 0 && invalid.length === 0) return emptyScan();
664
+ private async accessibleScan(userEmail: string, within?: ConnectorScope): Promise<ScanResult> {
665
+ return this.readableBy(await this.scan(), userEmail, within);
666
+ }
667
+
668
+ /** A scan cut to what this caller may read — see {@link accessibleScan}. */
669
+ private async readableBy(scan: ScanResult, userEmail: string, within?: ConnectorScope): Promise<ScanResult> {
670
+ const { manuals, invalid, refused } = scan;
671
+ if (manuals.length === 0 && invalid.length === 0 && refused.length === 0) return emptyScan();
606
672
  const wsId = this.kb.defaultWorkspaceId();
607
673
  const allowed = await this.accessControl.canReadBatch(wsId, userEmail, [
608
- ...new Set([...manuals.map((m) => m.path), ...invalid.map((i) => i.path)]),
674
+ ...new Set([...manuals.map((m) => m.path), ...invalid.map((i) => i.path), ...refused.map((r) => r.path)]),
609
675
  ]);
610
676
  // Fail closed: keep an entry only on an explicit `true` verdict (a missing
611
677
  // entry is treated as denied, matching the KB's default-deny read model).
612
678
  // A REFUSED file is gated the same way a listed one is: its path is a fact
613
679
  // about the knowledge base, and "there is a broken tool at this path" is
614
680
  // not something to tell someone who may not read that path.
681
+ const inScope = (p: string) => allowed.get(p) === true && (within === undefined || within(p));
615
682
  return {
616
- manuals: manuals.filter((m) => allowed.get(m.path) === true),
617
- invalid: invalid.filter((i) => allowed.get(i.path) === true),
683
+ manuals: manuals.filter((m) => inScope(m.path)),
684
+ invalid: invalid.filter((i) => inScope(i.path)),
685
+ refused: refused.filter((r) => inScope(r.path)),
618
686
  };
619
687
  }
620
688
 
@@ -639,14 +707,14 @@ export class ToolManualService implements IToolManualService {
639
707
  // See `TtlCache.begin`: taken before the read so an `invalidate()` that
640
708
  // lands mid-scan discards this result instead of being overwritten by it.
641
709
  const token = this.cache.begin();
642
- const { manuals, invalid } = await this.scanDisk();
710
+ const scanned = await this.scanDisk();
711
+ const { manuals } = scanned;
643
712
  await this.decorateMcpOAuth(manuals);
644
713
  // AFTER the oauth decoration, so an injected `${MCP_OAUTH}` header ref is
645
714
  // already declared and isn't re-surfaced as a bare admin key.
646
715
  for (const m of manuals) this.surfaceReferencedVariables(m);
647
- const result = { manuals, invalid };
648
- this.cache.set(result, token);
649
- return result;
716
+ this.cache.set(scanned, token);
717
+ return scanned;
650
718
  }
651
719
 
652
720
  /**
@@ -817,11 +885,12 @@ export class ToolManualService implements IToolManualService {
817
885
  * (the owner registered an app with a provider that offers no dynamic
818
886
  * registration — HubSpot, Google) gets its endpoints, PKCE and resource
819
887
  * indicator from the server's own OAuth metadata, exactly as the zero-config
820
- * path would. The descriptor is completed IN MEMORY: the client-secret route
821
- * reads the completed declaration and pins it with the secret, so nothing
822
- * here persists. When the metadata can't be had, the declaration stays
823
- * incomplete and `setup.reason` says so — the secret route then refuses
824
- * with the same reason instead of pinning a provider with no endpoints.
888
+ * path would. The descriptor is completed IN MEMORY, for the catalog's scan
889
+ * and for every sign-in start (`liveDeclaration`) alike, so nothing here
890
+ * persists. When the metadata can't be had, the declaration stays
891
+ * incomplete and `setup.reason` says so — the client-secret save and the
892
+ * sign-in start then refuse with the same reason instead of running a
893
+ * provider with no endpoints.
825
894
  */
826
895
  private async completeDeclaredOAuth(
827
896
  discovery: McpAuthDiscoveryPort,
@@ -880,11 +949,22 @@ export class ToolManualService implements IToolManualService {
880
949
  * calls: a refusal lives only in the scan it came from, so a fixed file is a
881
950
  * valid manual on the very next scan.
882
951
  */
883
- private async scanDisk(branch: string = this.kb.defaultBranch): Promise<ScanResult> {
952
+ private async scanDisk(
953
+ branch: string = this.kb.defaultBranch,
954
+ /**
955
+ * What a workspace that cannot be opened means. For the catalog, an empty
956
+ * scan: a listing surface answers "nothing released" and the next scan
957
+ * tries again. For a sign-in start (`liveDeclaration`), the error itself:
958
+ * an empty answer there would read as "this tool has no sign-in", a
959
+ * misconfiguration, when the server could not read its files at all.
960
+ */
961
+ workspaceFailure: 'empty' | 'throw' = 'empty',
962
+ ): Promise<ScanResult> {
884
963
  let wsId: string;
885
964
  try {
886
965
  wsId = (await this.workspaceService.getOrCreateForBranch(branch)).id;
887
- } catch {
966
+ } catch (err) {
967
+ if (workspaceFailure === 'throw') throw err;
888
968
  return emptyScan();
889
969
  }
890
970
  const kbRoot = path.join(await this.workspaceService.getWorkspacePath(wsId), this.kbDirName);
@@ -905,6 +985,7 @@ export class ToolManualService implements IToolManualService {
905
985
  // The plugins (and their mcp.json text) come from the configured source, so
906
986
  // a dialect that expands servers from a registry lands here unchanged.
907
987
  const parsed: ToolManualDescriptor[] = [];
988
+ const refused: RefusedManual[] = [];
908
989
  const discovered = await this.source.discover(kbRoot);
909
990
  for (const plugin of discovered.plugins) {
910
991
  if (plugin.mcpJsonText === null) continue; // no servers is the common case, not an error
@@ -913,7 +994,9 @@ export class ToolManualService implements IToolManualService {
913
994
  // (a URL, a header, an added or dropped server, a `local: true` flip)
914
995
  // moves every server's digest — which is correct, if slightly generous.
915
996
  const from = sourceDigest(plugin.mcpJsonText + '\u0000' + (plugin.manifestText ?? ''));
916
- for (const d of descriptorsFromMcpJson(plugin.relFolder, plugin.mcpJsonText, plugin.manifestText, layout)) {
997
+ const onRefused = (slug: string, reason: string, path: string) =>
998
+ refused.push({ slug, path, reason: describeManualFault(reason) });
999
+ for (const d of descriptorsFromMcpJson(plugin.relFolder, plugin.mcpJsonText, plugin.manifestText, layout, onRefused)) {
917
1000
  d.sourceRevision = from;
918
1001
  parsed.push(d);
919
1002
  }
@@ -949,6 +1032,8 @@ export class ToolManualService implements IToolManualService {
949
1032
  // outage from where the author stands: the tool is gone from every
950
1033
  // listing, with nothing anywhere saying which file or why.
951
1034
  invalid.push({ path: f.rel, reason: describeManualFault(err) });
1035
+ const slug = refusedToolManualName(baseName(f.rel), content);
1036
+ if (slug !== null) refused.push({ slug, path: f.rel, reason: describeManualFault(err) });
952
1037
  continue;
953
1038
  }
954
1039
  // The route slug IS the id (unique after dedup below, snake_case → URL-safe),
@@ -997,7 +1082,7 @@ export class ToolManualService implements IToolManualService {
997
1082
  // draft workspace, and a draft's half-written `.tool` is not news about the
998
1083
  // served catalog — it would also flap the log every time an agent saves.
999
1084
  if (branch === this.kb.defaultBranch) this.logInvalidOnChange(invalid);
1000
- return { manuals, invalid };
1085
+ return { manuals, invalid, refused };
1001
1086
  }
1002
1087
  }
1003
1088
 
@@ -1109,6 +1194,54 @@ function manualName(raw: string): string {
1109
1194
  return name;
1110
1195
  }
1111
1196
 
1197
+ /**
1198
+ * The object a `.tool` file holds: its `---` block when fenced, the whole file
1199
+ * when not. Throws when that is not an object.
1200
+ */
1201
+ function toolFileObject(content: string): Record<string, unknown> {
1202
+ const fm = extractFrontmatter(content);
1203
+ const source = fm ? fm.frontmatter : content;
1204
+ const parsed = parseYaml(source) as unknown;
1205
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
1206
+ throw new Error('`.tool` file must be a YAML/JSON object (in the `---` block when fenced)');
1207
+ }
1208
+ return parsed as Record<string, unknown>;
1209
+ }
1210
+
1211
+ /**
1212
+ * A `.tool`'s manual name — its UTCP namespace, and the slug the scan serves it
1213
+ * under. An explicit `id` is used VERBATIM, so it must be lowercase snake_case
1214
+ * (UTCP's namespace grammar). With no explicit id, fall back to `name` then the
1215
+ * filename and sanitize (legacy behaviour — keeps existing tools' namespaces).
1216
+ */
1217
+ function toolManualName(obj: Record<string, unknown>, provisionalSlug: string): string {
1218
+ const explicitId = typeof obj.id === 'string' ? obj.id.trim() : '';
1219
+ if (!explicitId) return manualName(resolveDeclaredId(obj, provisionalSlug));
1220
+ if (!isValidId(explicitId)) {
1221
+ // The rejected id is NOT quoted back — see `describeManualFault`: this
1222
+ // message becomes an `invalid[].reason` on an agent transcript, a browser
1223
+ // and a log, and `id` is a field an author can paste anything into,
1224
+ // including the token they meant for a header. The field name plus the
1225
+ // rule is what the author needs; the value is in front of them.
1226
+ throw new Error('tool `id` must be lowercase snake_case (letters, digits, underscores)');
1227
+ }
1228
+ return explicitId;
1229
+ }
1230
+
1231
+ /**
1232
+ * The manual name of a `.tool` the parser REFUSED, when the file still says
1233
+ * which manual it is — by the same rule {@link normalizeToolManual} names a
1234
+ * manual it accepts. `null` when even that cannot be read (unparseable YAML,
1235
+ * a malformed `id`): then nothing can claim the refusal by name.
1236
+ */
1237
+ function refusedToolManualName(provisionalSlug: string, content: string): string | null {
1238
+ try {
1239
+ return toolManualName(toolFileObject(content), provisionalSlug);
1240
+ } catch {
1241
+ return null;
1242
+ }
1243
+ }
1244
+
1112
1245
  /**
1113
1246
  * Parse + normalize a `.tool` file into a descriptor. THE TOOL IS THE
1114
1247
  * FRONTMATTER: a fenced file's single `---` YAML block carries everything —
@@ -1132,34 +1265,9 @@ export function normalizeToolManual(
1132
1265
  // finds its verbs inside the fence, the id index finds `id`/`name`, and the
1133
1266
  // config keys live in the same object. A fence-less file is the legacy form
1134
1267
  // (the whole file is the object) — JSON `.tool`s can't carry fences.
1135
- const fm = extractFrontmatter(content);
1136
- const source = fm ? fm.frontmatter : content;
1137
- const parsed = parseYaml(source) as unknown;
1138
- if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
1139
- throw new Error('`.tool` file must be a YAML/JSON object (in the `---` block when fenced)');
1140
- }
1141
- const obj = parsed as Record<string, unknown>;
1268
+ const obj = toolFileObject(content);
1142
1269
  const type = normalizeType(obj.type);
1143
-
1144
- // Identity: an explicit `id` is used VERBATIM as the UTCP manual namespace, so
1145
- // it must be lowercase snake_case (UTCP's namespace grammar). With no explicit
1146
- // id, fall back to `name` then the filename and sanitize (legacy behaviour —
1147
- // keeps existing tools' namespaces).
1148
- const explicitId = typeof obj.id === 'string' ? obj.id.trim() : '';
1149
- let name: string;
1150
- if (explicitId) {
1151
- if (!isValidId(explicitId)) {
1152
- // The rejected id is NOT quoted back — see `describeManualFault`: this
1153
- // message becomes an `invalid[].reason` on an agent transcript, a browser
1154
- // and a log, and `id` is a field an author can paste anything into,
1155
- // including the token they meant for a header. The field name plus the
1156
- // rule is what the author needs; the value is in front of them.
1157
- throw new Error('tool `id` must be lowercase snake_case (letters, digits, underscores)');
1158
- }
1159
- name = explicitId;
1160
- } else {
1161
- name = manualName(resolveDeclaredId(obj, provisionalSlug));
1162
- }
1270
+ const name = toolManualName(obj, provisionalSlug);
1163
1271
 
1164
1272
  // A `.tool` may not reproduce a built-in manual's UTCP namespace — that would
1165
1273
  // let it read the loopback creds seeded under that namespace on the agent's
@@ -5,20 +5,34 @@ import type { ToolContext, ToolHandlerFactory } from '../tool-helpers/index.js';
5
5
  import { toolDef, declareRouteTool } from '../tool-helpers/index.js';
6
6
  import type { IAccessControl } from '../access/index.js';
7
7
  import { utcpNamespacedKey } from '../../shared/utcp-namespace.js';
8
- import type { IToolManualService } from './tool-manuals.contract.js';
8
+ import type { ConnectorScope, IToolManualService } from './tool-manuals.contract.js';
9
9
  import type { HiddenToolSource } from '../../shared/hidden-tools.js';
10
+ import { userSecretGap } from '../secrets-vault/index.js';
10
11
 
11
12
  /**
12
13
  * What `list_tool_setup` needs from the secrets vault (structurally satisfied
13
14
  * by `ISecretsVaultService.statusFor`). A local port keeps this module free of
14
- * a secrets-vault import — the same decoupling discipline as
15
- * `McpAuthDiscoveryPort` in the service.
15
+ * the vault service — the same decoupling discipline as
16
+ * `McpAuthDiscoveryPort` in the service. Only the vault's pure readiness rule
17
+ * (`userSecretGap`, its exported contract) is imported, the one the MCP proxy
18
+ * hides tools by.
16
19
  */
17
20
  export interface VariableStatusPort {
18
21
  statusFor(
19
22
  userId: string,
20
23
  keys: string[],
21
- ): Promise<{ key: string; adminConfigured: boolean; userConfigured: boolean; userAuthorized?: boolean }[]>;
24
+ ): Promise<
25
+ {
26
+ key: string;
27
+ adminConfigured: boolean;
28
+ /** What the owner's row is: a sign-in needs an `oauth` one, not a key left from when the variable was static. */
29
+ adminKind?: 'static' | 'oauth' | null;
30
+ userConfigured: boolean;
31
+ userAuthorized?: boolean;
32
+ userKind?: 'static' | 'oauth' | null;
33
+ grantedScopes?: string;
34
+ }[]
35
+ >;
22
36
  }
23
37
 
24
38
  /**
@@ -51,7 +65,9 @@ export function registerToolManualsTools(
51
65
  hiddenTools?: HiddenToolSource;
52
66
  },
53
67
  ): void {
54
- registry.registerExternalTool((ctx) => buildListLocalToolsDef(toolManualService, ctx.userEmail));
68
+ registry.registerExternalTool((ctx) =>
69
+ buildListLocalToolsDef(toolManualService, ctx.userEmail, ctx.connectionScope?.connectorFilter()),
70
+ );
55
71
  registry.registerInternalTool((ctx) => buildListLocalToolsDef(toolManualService, ctx.userEmail));
56
72
  // The def above is built per catalog listing (its description names the
57
73
  // tools configured for THIS caller), so declare the arguments here as well:
@@ -59,12 +75,22 @@ export function registerToolManualsTools(
59
75
  // against them too.
60
76
  declareRouteTool('list_local_tools', LIST_LOCAL_TOOLS_INPUTS);
61
77
 
78
+ // The local server's discovery read (`discovery`): it asks this route at
79
+ // startup for the connectors it must materialize, whatever tools the
80
+ // connection is offered — a connection made as an agent configuration that omits
81
+ // the tool is answered its connectors, not refused, or the local server
82
+ // could not start for that agent at all.
62
83
  router.post(
63
84
  '/agent/tools/list_local_tools',
64
85
  toolAuth,
65
- toolHandler(async (_args, ctx: ToolContext) => ({
66
- tools: await toolManualService.listLocalOnly(ctx.user.email),
67
- })),
86
+ toolHandler(async (_args, ctx: ToolContext) => {
87
+ const within = ctx.connectionScope?.connectorFilter();
88
+ return {
89
+ tools: await (within
90
+ ? toolManualService.listLocalOnly(ctx.user.email, within)
91
+ : toolManualService.listLocalOnly(ctx.user.email)),
92
+ };
93
+ }, { discovery: true }),
68
94
  );
69
95
 
70
96
  // A FUNCTION, not a constant — this factory runs at boot, and on a
@@ -228,7 +254,9 @@ export function registerToolManualsTools(
228
254
  },
229
255
  note: {
230
256
  type: 'string',
231
- description: 'Present when `onBranchOnly` is non-empty: what it takes for those tools to go live.',
257
+ description:
258
+ 'Present when something is left to do: what it takes for the tools in `onBranchOnly` to go live, and for ' +
259
+ 'tools that need your own value or sign-in to work.',
232
260
  },
233
261
  },
234
262
  required: ['tools', 'invalid', 'onBranchOnly'],
@@ -243,12 +271,17 @@ export function registerToolManualsTools(
243
271
  toolHandler(async (args, ctx: ToolContext) => {
244
272
  // The in-app agent is focused on its own draft; an external caller names it.
245
273
  const branch = typeof args.branch === 'string' && args.branch ? args.branch : ctx.focusedBranch;
274
+ const within = ctx.connectionScope?.connectorFilter();
246
275
  // The catalog comes back whole — what parsed AND what was refused — from
247
276
  // ONE scan, so the refused files cost no second walk of the workspace and
248
277
  // the two halves cannot disagree about which files made it.
249
278
  const [{ tools: manuals, invalid }, pending] = await Promise.all([
250
- toolManualService.listAccessibleCatalog(ctx.user.email),
251
- branch ? toolManualService.listDeclaredOnlyOnBranch(ctx.user.email, branch) : Promise.resolve([]),
279
+ // Only the connectors the caller's connection loads: setup is counted
280
+ // for the tools this connection can call, not every one the person can.
281
+ within
282
+ ? toolManualService.listAccessibleCatalog(ctx.user.email, within)
283
+ : toolManualService.listAccessibleCatalog(ctx.user.email),
284
+ branch ? toolManualService.listDeclaredOnlyOnBranch(ctx.user.email, branch, within) : Promise.resolve([]),
252
285
  ]);
253
286
  const allKeys = manuals.flatMap((m) => (m.variables ?? []).map((v) => varKey(m.name, v.name)));
254
287
  const status = await deps.variableStatus.statusFor(ctx.user.id, allKeys);
@@ -285,25 +318,48 @@ export function registerToolManualsTools(
285
318
  }),
286
319
  );
287
320
  const onBranchOnly = pending.map((p) => ({ ...p, branch: branch! }));
288
- if (onBranchOnly.length === 0) return { tools, invalid, onBranchOnly };
289
- return {
290
- tools,
291
- invalid,
292
- onBranchOnly,
293
- note:
321
+ const notes: string[] = [];
322
+ if (onBranchOnly.length > 0) {
323
+ notes.push(
294
324
  `${onBranchOnly.map((p) => `\`${p.name}\``).join(', ')} ${onBranchOnly.length === 1 ? 'is' : 'are'} declared on ` +
295
- `\`${branch}\` only. Tools are served from \`${deps.kb.defaultBranch}\`, so ${onBranchOnly.length === 1 ? 'it stays' : 'they stay'} ` +
296
- 'unlisted, uncallable and without a sign-in until that branch is merged: open a change request with ' +
297
- `\`open_change_request\` (target \`${deps.kb.defaultBranch}\`), then ask the user to review and merge it in the app.`,
298
- };
325
+ `\`${branch}\` only. Tools are served from \`${deps.kb.defaultBranch}\`, so ${onBranchOnly.length === 1 ? 'it stays' : 'they stay'} ` +
326
+ 'unlisted, uncallable and without a sign-in until that branch is merged: open a change request with ' +
327
+ `\`open_change_request\` (target \`${deps.kb.defaultBranch}\`), then ask the user to review and merge it in the app.`,
328
+ );
329
+ }
330
+ // The person's own part, said where the agent is when a tool "does not work": the
331
+ // reconnect step is the one agents leave out (the agent-guide benchmark, 2026-10-26).
332
+ // By the rule the proxy hides a tool by (`userSecretGap`), so the note
333
+ // names every tool that is hidden for want of the caller's own value. A
334
+ // sign-in waits on the owner's provider setup (an OAuth admin row, not a
335
+ // key left from when the variable was static — the Connect page counts
336
+ // that setup incomplete and the sign-in start refuses it): until then
337
+ // there is nothing to sign in to.
338
+ const needYou = manuals.filter((m) =>
339
+ (m.variables ?? []).some((v) => {
340
+ if (v.scope !== 'user') return false;
341
+ const st = statusByKey.get(varKey(m.name, v.name));
342
+ const gap = userSecretGap({ oauth: v.oauth != null, oauthScopes: v.oauth?.scopes }, st);
343
+ return gap !== null && (v.oauth == null || (st?.adminConfigured === true && st.adminKind === 'oauth'));
344
+ }),
345
+ );
346
+ if (needYou.length > 0) {
347
+ notes.push(
348
+ `${needYou.map((t) => `\`${t.name}\``).join(', ')} ${needYou.length === 1 ? 'needs' : 'need'} your own value or sign-in. ` +
349
+ 'Set it yourself on the Connect page, never in the chat; then reconnect your assistant, or start a new chat, ' +
350
+ 'so the tool is listed.',
351
+ );
352
+ }
353
+ if (notes.length === 0) return { tools, invalid, onBranchOnly };
354
+ return { tools, invalid, onBranchOnly, note: notes.join(' ') };
299
355
  }),
300
356
  );
301
357
  }
302
358
 
303
359
  /** "Local-only tools configured for you: `a`, `b`." (or a none note), filtered to what the caller may read. */
304
- async function localToolsLine(svc: IToolManualService, userEmail?: string): Promise<string> {
360
+ async function localToolsLine(svc: IToolManualService, userEmail?: string, within?: ConnectorScope): Promise<string> {
305
361
  if (!userEmail) return 'No local-only tools are currently configured.';
306
- const tools = await svc.listLocalOnly(userEmail);
362
+ const tools = await (within ? svc.listLocalOnly(userEmail, within) : svc.listLocalOnly(userEmail));
307
363
  if (tools.length === 0) return 'No local-only tools are currently configured.';
308
364
  return `Local-only tools configured for you: ${tools.map((t) => `\`${t.name}\``).join(', ')}.`;
309
365
  }
@@ -311,7 +367,7 @@ async function localToolsLine(svc: IToolManualService, userEmail?: string): Prom
311
367
  /** `list_local_tools` takes nothing; a const so the route and the def share one declaration. */
312
368
  const LIST_LOCAL_TOOLS_INPUTS = { type: 'object' as const, properties: {}, additionalProperties: false };
313
369
 
314
- async function buildListLocalToolsDef(svc: IToolManualService, userEmail?: string): Promise<UtcpTool> {
370
+ async function buildListLocalToolsDef(svc: IToolManualService, userEmail?: string, within?: ConnectorScope): Promise<UtcpTool> {
315
371
  return toolDef({
316
372
  name: 'list_local_tools',
317
373
  description:
@@ -324,7 +380,7 @@ async function buildListLocalToolsDef(svc: IToolManualService, userEmail?: strin
324
380
  'machine. Otherwise each entry gives the tool’s name and its `.tool` file ' +
325
381
  'path in the knowledge base — read that file with `read_file` and wire the tool into your local ' +
326
382
  'setup by hand. ' +
327
- (await localToolsLine(svc, userEmail)),
383
+ (await localToolsLine(svc, userEmail, within)),
328
384
  path: '/api/agent/tools/list_local_tools',
329
385
  inputs: LIST_LOCAL_TOOLS_INPUTS,
330
386
  outputs: {