@bevel-software/platform-core-backend 0.14.0 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1307) hide show
  1. package/THIRD-PARTY-NOTICES.md +8 -8
  2. package/dist/core/catalog-cache-invalidation.d.ts +45 -0
  3. package/dist/core/catalog-cache-invalidation.d.ts.map +1 -0
  4. package/dist/core/catalog-cache-invalidation.js +76 -0
  5. package/dist/core/catalog-cache-invalidation.js.map +1 -0
  6. package/dist/core/catalog-revision.d.ts +39 -0
  7. package/dist/core/catalog-revision.d.ts.map +1 -0
  8. package/dist/core/catalog-revision.js +94 -0
  9. package/dist/core/catalog-revision.js.map +1 -0
  10. package/dist/core/create-core-server.d.ts +7 -0
  11. package/dist/core/create-core-server.d.ts.map +1 -1
  12. package/dist/core/create-core-server.js +279 -64
  13. package/dist/core/create-core-server.js.map +1 -1
  14. package/dist/core/create-core-services.d.ts +66 -2
  15. package/dist/core/create-core-services.d.ts.map +1 -1
  16. package/dist/core/create-core-services.js +290 -111
  17. package/dist/core/create-core-services.js.map +1 -1
  18. package/dist/core/lifecycle.d.ts +138 -0
  19. package/dist/core/lifecycle.d.ts.map +1 -0
  20. package/dist/core/lifecycle.js +218 -0
  21. package/dist/core/lifecycle.js.map +1 -0
  22. package/dist/core/public-config.d.ts +82 -0
  23. package/dist/core/public-config.d.ts.map +1 -0
  24. package/dist/core/public-config.js +78 -0
  25. package/dist/core/public-config.js.map +1 -0
  26. package/dist/core/readiness.d.ts +86 -0
  27. package/dist/core/readiness.d.ts.map +1 -0
  28. package/dist/core/readiness.js +56 -0
  29. package/dist/core/readiness.js.map +1 -0
  30. package/dist/core-config.d.ts +30 -0
  31. package/dist/core-config.d.ts.map +1 -1
  32. package/dist/core-config.js +64 -2
  33. package/dist/core-config.js.map +1 -1
  34. package/dist/index.d.ts +4 -1
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +6 -0
  37. package/dist/index.js.map +1 -1
  38. package/dist/modules/access/access-control.interface.d.ts +231 -15
  39. package/dist/modules/access/access-control.interface.d.ts.map +1 -1
  40. package/dist/modules/access/access-control.service.d.ts +83 -12
  41. package/dist/modules/access/access-control.service.d.ts.map +1 -1
  42. package/dist/modules/access/access-control.service.js +815 -212
  43. package/dist/modules/access/access-control.service.js.map +1 -1
  44. package/dist/modules/access/access-mutation.service.d.ts +71 -5
  45. package/dist/modules/access/access-mutation.service.d.ts.map +1 -1
  46. package/dist/modules/access/access-mutation.service.js +161 -13
  47. package/dist/modules/access/access-mutation.service.js.map +1 -1
  48. package/dist/modules/access/access-view.d.ts +147 -0
  49. package/dist/modules/access/access-view.d.ts.map +1 -0
  50. package/dist/modules/access/access-view.js +211 -0
  51. package/dist/modules/access/access-view.js.map +1 -0
  52. package/dist/modules/access/access.routes.d.ts.map +1 -1
  53. package/dist/modules/access/access.routes.js +312 -84
  54. package/dist/modules/access/access.routes.js.map +1 -1
  55. package/dist/modules/access/admin-locked-commit.d.ts +2 -3
  56. package/dist/modules/access/admin-locked-commit.d.ts.map +1 -1
  57. package/dist/modules/access/admin-locked-commit.js +9 -8
  58. package/dist/modules/access/admin-locked-commit.js.map +1 -1
  59. package/dist/modules/access/admin-route-helpers.d.ts.map +1 -1
  60. package/dist/modules/access/admin-route-helpers.js +4 -4
  61. package/dist/modules/access/admin-route-helpers.js.map +1 -1
  62. package/dist/modules/access/change-read-gate.d.ts +53 -0
  63. package/dist/modules/access/change-read-gate.d.ts.map +1 -0
  64. package/dist/modules/access/change-read-gate.js +134 -0
  65. package/dist/modules/access/change-read-gate.js.map +1 -0
  66. package/dist/modules/access/creator-access.d.ts +33 -39
  67. package/dist/modules/access/creator-access.d.ts.map +1 -1
  68. package/dist/modules/access/creator-access.js +92 -119
  69. package/dist/modules/access/creator-access.js.map +1 -1
  70. package/dist/modules/access/directory-sync-bot.d.ts.map +1 -1
  71. package/dist/modules/access/directory-sync-bot.js +3 -1
  72. package/dist/modules/access/directory-sync-bot.js.map +1 -1
  73. package/dist/modules/access/groups-admin.service.d.ts +3 -3
  74. package/dist/modules/access/groups-admin.service.js +2 -2
  75. package/dist/modules/access/reference-scan.d.ts +1 -1
  76. package/dist/modules/access/reference-scan.d.ts.map +1 -1
  77. package/dist/modules/access/reference-scan.js +5 -4
  78. package/dist/modules/access/reference-scan.js.map +1 -1
  79. package/dist/modules/access/roles-admin.service.d.ts +72 -13
  80. package/dist/modules/access/roles-admin.service.d.ts.map +1 -1
  81. package/dist/modules/access/roles-admin.service.js +71 -13
  82. package/dist/modules/access/roles-admin.service.js.map +1 -1
  83. package/dist/modules/access/synced-groups-committer.d.ts.map +1 -1
  84. package/dist/modules/access/synced-groups-committer.js +8 -6
  85. package/dist/modules/access/synced-groups-committer.js.map +1 -1
  86. package/dist/modules/access/synced-groups-writer.d.ts.map +1 -1
  87. package/dist/modules/access/synced-groups-writer.js +3 -8
  88. package/dist/modules/access/synced-groups-writer.js.map +1 -1
  89. package/dist/modules/access/user-access-removal.service.d.ts +209 -0
  90. package/dist/modules/access/user-access-removal.service.d.ts.map +1 -0
  91. package/dist/modules/access/user-access-removal.service.js +662 -0
  92. package/dist/modules/access/user-access-removal.service.js.map +1 -0
  93. package/dist/modules/access-model/access-errors.d.ts +32 -1
  94. package/dist/modules/access-model/access-errors.d.ts.map +1 -1
  95. package/dist/modules/access-model/access-errors.js +38 -11
  96. package/dist/modules/access-model/access-errors.js.map +1 -1
  97. package/dist/modules/access-model/access-grammar.d.ts +100 -25
  98. package/dist/modules/access-model/access-grammar.d.ts.map +1 -1
  99. package/dist/modules/access-model/access-grammar.js +162 -48
  100. package/dist/modules/access-model/access-grammar.js.map +1 -1
  101. package/dist/modules/access-model/access-splice.d.ts.map +1 -1
  102. package/dist/modules/access-model/access-splice.js +18 -18
  103. package/dist/modules/access-model/access-splice.js.map +1 -1
  104. package/dist/modules/access-model/access-template.d.ts +22 -0
  105. package/dist/modules/access-model/access-template.d.ts.map +1 -0
  106. package/dist/modules/access-model/access-template.js +42 -0
  107. package/dist/modules/access-model/access-template.js.map +1 -0
  108. package/dist/modules/access-model/change-gate.d.ts +65 -0
  109. package/dist/modules/access-model/change-gate.d.ts.map +1 -0
  110. package/dist/modules/access-model/change-gate.js +25 -0
  111. package/dist/modules/access-model/change-gate.js.map +1 -0
  112. package/dist/modules/access-model/creator.d.ts +13 -16
  113. package/dist/modules/access-model/creator.d.ts.map +1 -1
  114. package/dist/modules/access-model/creator.js.map +1 -1
  115. package/dist/modules/access-model/frontmatter-lines.d.ts +27 -0
  116. package/dist/modules/access-model/frontmatter-lines.d.ts.map +1 -0
  117. package/dist/modules/access-model/frontmatter-lines.js +74 -0
  118. package/dist/modules/access-model/frontmatter-lines.js.map +1 -0
  119. package/dist/modules/access-model/group-files.d.ts.map +1 -1
  120. package/dist/modules/access-model/group-files.js +4 -1
  121. package/dist/modules/access-model/group-files.js.map +1 -1
  122. package/dist/modules/access-model/plugin-principals.d.ts +51 -0
  123. package/dist/modules/access-model/plugin-principals.d.ts.map +1 -0
  124. package/dist/modules/access-model/plugin-principals.js +119 -0
  125. package/dist/modules/access-model/plugin-principals.js.map +1 -0
  126. package/dist/modules/access-model/roles-yaml-guard.d.ts +73 -2
  127. package/dist/modules/access-model/roles-yaml-guard.d.ts.map +1 -1
  128. package/dist/modules/access-model/roles-yaml-guard.js +153 -3
  129. package/dist/modules/access-model/roles-yaml-guard.js.map +1 -1
  130. package/dist/modules/admin/admin-access.service.d.ts.map +1 -1
  131. package/dist/modules/admin/admin-access.service.js +5 -2
  132. package/dist/modules/admin/admin-access.service.js.map +1 -1
  133. package/dist/modules/agent-instructions/agent-instructions.routes.d.ts +21 -0
  134. package/dist/modules/agent-instructions/agent-instructions.routes.d.ts.map +1 -0
  135. package/dist/modules/agent-instructions/agent-instructions.routes.js +38 -0
  136. package/dist/modules/agent-instructions/agent-instructions.routes.js.map +1 -0
  137. package/dist/modules/agent-instructions/compose.d.ts +71 -0
  138. package/dist/modules/agent-instructions/compose.d.ts.map +1 -0
  139. package/dist/modules/agent-instructions/compose.js +234 -0
  140. package/dist/modules/agent-instructions/compose.js.map +1 -0
  141. package/dist/modules/agent-instructions/index.d.ts +4 -0
  142. package/dist/modules/agent-instructions/index.d.ts.map +1 -0
  143. package/dist/modules/agent-instructions/index.js +4 -0
  144. package/dist/modules/agent-instructions/index.js.map +1 -0
  145. package/dist/modules/agent-instructions/read-preamble.d.ts +37 -0
  146. package/dist/modules/agent-instructions/read-preamble.d.ts.map +1 -0
  147. package/dist/modules/agent-instructions/read-preamble.js +81 -0
  148. package/dist/modules/agent-instructions/read-preamble.js.map +1 -0
  149. package/dist/modules/auth/account-erasure.service.d.ts +30 -4
  150. package/dist/modules/auth/account-erasure.service.d.ts.map +1 -1
  151. package/dist/modules/auth/account-erasure.service.js +96 -10
  152. package/dist/modules/auth/account-erasure.service.js.map +1 -1
  153. package/dist/modules/auth/account.routes.d.ts +6 -3
  154. package/dist/modules/auth/account.routes.d.ts.map +1 -1
  155. package/dist/modules/auth/account.routes.js +109 -10
  156. package/dist/modules/auth/account.routes.js.map +1 -1
  157. package/dist/modules/auth/auth.routes.d.ts +10 -3
  158. package/dist/modules/auth/auth.routes.d.ts.map +1 -1
  159. package/dist/modules/auth/auth.routes.js +9 -4
  160. package/dist/modules/auth/auth.routes.js.map +1 -1
  161. package/dist/modules/auth/auth.service.d.ts +89 -5
  162. package/dist/modules/auth/auth.service.d.ts.map +1 -1
  163. package/dist/modules/auth/auth.service.js +160 -25
  164. package/dist/modules/auth/auth.service.js.map +1 -1
  165. package/dist/modules/auth/oidc-auth-provider.d.ts +46 -3
  166. package/dist/modules/auth/oidc-auth-provider.d.ts.map +1 -1
  167. package/dist/modules/auth/oidc-auth-provider.js +99 -21
  168. package/dist/modules/auth/oidc-auth-provider.js.map +1 -1
  169. package/dist/modules/code-mode/code-mode.tool.d.ts.map +1 -1
  170. package/dist/modules/code-mode/code-mode.tool.js +14 -2
  171. package/dist/modules/code-mode/code-mode.tool.js.map +1 -1
  172. package/dist/modules/connection-probe/connection-probe.service.d.ts.map +1 -1
  173. package/dist/modules/connection-probe/connection-probe.service.js +56 -7
  174. package/dist/modules/connection-probe/connection-probe.service.js.map +1 -1
  175. package/dist/modules/database/advisory-lock.d.ts +103 -0
  176. package/dist/modules/database/advisory-lock.d.ts.map +1 -0
  177. package/dist/modules/database/advisory-lock.js +320 -0
  178. package/dist/modules/database/advisory-lock.js.map +1 -0
  179. package/dist/modules/database/connection.d.ts.map +1 -1
  180. package/dist/modules/database/connection.js +9 -1
  181. package/dist/modules/database/connection.js.map +1 -1
  182. package/dist/modules/database/core-schema.d.ts +672 -0
  183. package/dist/modules/database/core-schema.d.ts.map +1 -1
  184. package/dist/modules/database/core-schema.js +171 -0
  185. package/dist/modules/database/core-schema.js.map +1 -1
  186. package/dist/modules/database/migrate.d.ts.map +1 -1
  187. package/dist/modules/database/migrate.js +26 -6
  188. package/dist/modules/database/migrate.js.map +1 -1
  189. package/dist/modules/declared-variables/declared-variables.routes.d.ts.map +1 -1
  190. package/dist/modules/declared-variables/declared-variables.routes.js +4 -2
  191. package/dist/modules/declared-variables/declared-variables.routes.js.map +1 -1
  192. package/dist/modules/diff/diff.routes.d.ts.map +1 -1
  193. package/dist/modules/diff/diff.routes.js +2 -4
  194. package/dist/modules/diff/diff.routes.js.map +1 -1
  195. package/dist/modules/diff/diff.service.d.ts +4 -1
  196. package/dist/modules/diff/diff.service.d.ts.map +1 -1
  197. package/dist/modules/diff/diff.service.js +79 -81
  198. package/dist/modules/diff/diff.service.js.map +1 -1
  199. package/dist/modules/kb-fs/bevel-ignore.d.ts +35 -0
  200. package/dist/modules/kb-fs/bevel-ignore.d.ts.map +1 -0
  201. package/dist/modules/kb-fs/bevel-ignore.js +71 -0
  202. package/dist/modules/kb-fs/bevel-ignore.js.map +1 -0
  203. package/dist/modules/kb-fs/file-change-notifier.d.ts.map +1 -1
  204. package/dist/modules/kb-fs/file-change-notifier.js +3 -1
  205. package/dist/modules/kb-fs/file-change-notifier.js.map +1 -1
  206. package/dist/modules/kb-fs/git-guarded-filesystem.d.ts +37 -0
  207. package/dist/modules/kb-fs/git-guarded-filesystem.d.ts.map +1 -0
  208. package/dist/modules/kb-fs/git-guarded-filesystem.js +104 -0
  209. package/dist/modules/kb-fs/git-guarded-filesystem.js.map +1 -0
  210. package/dist/modules/kb-fs/locking-filesystem.d.ts +113 -18
  211. package/dist/modules/kb-fs/locking-filesystem.d.ts.map +1 -1
  212. package/dist/modules/kb-fs/locking-filesystem.js +353 -76
  213. package/dist/modules/kb-fs/locking-filesystem.js.map +1 -1
  214. package/dist/modules/kb-fs/node-fs.d.ts +23 -0
  215. package/dist/modules/kb-fs/node-fs.d.ts.map +1 -0
  216. package/dist/modules/kb-fs/node-fs.js +158 -0
  217. package/dist/modules/kb-fs/node-fs.js.map +1 -0
  218. package/dist/modules/kb-fs/read-only-filesystem.d.ts +10 -9
  219. package/dist/modules/kb-fs/read-only-filesystem.d.ts.map +1 -1
  220. package/dist/modules/kb-fs/read-only-filesystem.js +18 -9
  221. package/dist/modules/kb-fs/read-only-filesystem.js.map +1 -1
  222. package/dist/modules/kb-fs/repo-path.d.ts +100 -3
  223. package/dist/modules/kb-fs/repo-path.d.ts.map +1 -1
  224. package/dist/modules/kb-fs/repo-path.js +195 -3
  225. package/dist/modules/kb-fs/repo-path.js.map +1 -1
  226. package/dist/modules/kb-sync/index.d.ts +6 -0
  227. package/dist/modules/kb-sync/index.d.ts.map +1 -0
  228. package/dist/modules/kb-sync/index.js +5 -0
  229. package/dist/modules/kb-sync/index.js.map +1 -0
  230. package/dist/modules/kb-sync/kb-sync.interface.d.ts +77 -0
  231. package/dist/modules/kb-sync/kb-sync.interface.d.ts.map +1 -0
  232. package/dist/modules/kb-sync/kb-sync.interface.js +2 -0
  233. package/dist/modules/kb-sync/kb-sync.interface.js.map +1 -0
  234. package/dist/modules/kb-sync/kb-sync.routes.d.ts +70 -0
  235. package/dist/modules/kb-sync/kb-sync.routes.d.ts.map +1 -0
  236. package/dist/modules/kb-sync/kb-sync.routes.js +137 -0
  237. package/dist/modules/kb-sync/kb-sync.routes.js.map +1 -0
  238. package/dist/modules/kb-sync/kb-sync.service.d.ts +45 -0
  239. package/dist/modules/kb-sync/kb-sync.service.d.ts.map +1 -0
  240. package/dist/modules/kb-sync/kb-sync.service.js +185 -0
  241. package/dist/modules/kb-sync/kb-sync.service.js.map +1 -0
  242. package/dist/modules/kb-sync/sync-auth.d.ts +59 -0
  243. package/dist/modules/kb-sync/sync-auth.d.ts.map +1 -0
  244. package/dist/modules/kb-sync/sync-auth.js +62 -0
  245. package/dist/modules/kb-sync/sync-auth.js.map +1 -0
  246. package/dist/modules/kb-sync/sync-payload.d.ts +32 -0
  247. package/dist/modules/kb-sync/sync-payload.d.ts.map +1 -0
  248. package/dist/modules/kb-sync/sync-payload.js +105 -0
  249. package/dist/modules/kb-sync/sync-payload.js.map +1 -0
  250. package/dist/modules/marketplace/git-http.routes.d.ts +42 -0
  251. package/dist/modules/marketplace/git-http.routes.d.ts.map +1 -0
  252. package/dist/modules/marketplace/git-http.routes.js +192 -0
  253. package/dist/modules/marketplace/git-http.routes.js.map +1 -0
  254. package/dist/modules/marketplace/github-facade/github-facade-admin.routes.d.ts +33 -0
  255. package/dist/modules/marketplace/github-facade/github-facade-admin.routes.d.ts.map +1 -0
  256. package/dist/modules/marketplace/github-facade/github-facade-admin.routes.js +88 -0
  257. package/dist/modules/marketplace/github-facade/github-facade-admin.routes.js.map +1 -0
  258. package/dist/modules/marketplace/github-facade/github-facade-codes.store.d.ts +59 -0
  259. package/dist/modules/marketplace/github-facade/github-facade-codes.store.d.ts.map +1 -0
  260. package/dist/modules/marketplace/github-facade/github-facade-codes.store.js +96 -0
  261. package/dist/modules/marketplace/github-facade/github-facade-codes.store.js.map +1 -0
  262. package/dist/modules/marketplace/github-facade/github-facade-credentials.service.d.ts +126 -0
  263. package/dist/modules/marketplace/github-facade/github-facade-credentials.service.d.ts.map +1 -0
  264. package/dist/modules/marketplace/github-facade/github-facade-credentials.service.js +192 -0
  265. package/dist/modules/marketplace/github-facade/github-facade-credentials.service.js.map +1 -0
  266. package/dist/modules/marketplace/github-facade/github-facade.routes.d.ts +47 -0
  267. package/dist/modules/marketplace/github-facade/github-facade.routes.d.ts.map +1 -0
  268. package/dist/modules/marketplace/github-facade/github-facade.routes.js +252 -0
  269. package/dist/modules/marketplace/github-facade/github-facade.routes.js.map +1 -0
  270. package/dist/modules/marketplace/github-facade/github-facade.service.d.ts +121 -0
  271. package/dist/modules/marketplace/github-facade/github-facade.service.d.ts.map +1 -0
  272. package/dist/modules/marketplace/github-facade/github-facade.service.js +213 -0
  273. package/dist/modules/marketplace/github-facade/github-facade.service.js.map +1 -0
  274. package/dist/modules/marketplace/github-facade/index.d.ts +6 -0
  275. package/dist/modules/marketplace/github-facade/index.d.ts.map +1 -0
  276. package/dist/modules/marketplace/github-facade/index.js +6 -0
  277. package/dist/modules/marketplace/github-facade/index.js.map +1 -0
  278. package/dist/modules/marketplace/index.d.ts +4 -0
  279. package/dist/modules/marketplace/index.d.ts.map +1 -0
  280. package/dist/modules/marketplace/index.js +4 -0
  281. package/dist/modules/marketplace/index.js.map +1 -0
  282. package/dist/modules/marketplace/marketplace-repo.service.d.ts +135 -0
  283. package/dist/modules/marketplace/marketplace-repo.service.d.ts.map +1 -0
  284. package/dist/modules/marketplace/marketplace-repo.service.js +318 -0
  285. package/dist/modules/marketplace/marketplace-repo.service.js.map +1 -0
  286. package/dist/modules/mcp/downstream-pool.d.ts +107 -0
  287. package/dist/modules/mcp/downstream-pool.d.ts.map +1 -0
  288. package/dist/modules/mcp/downstream-pool.js +221 -0
  289. package/dist/modules/mcp/downstream-pool.js.map +1 -0
  290. package/dist/modules/mcp/downstream-token-refresh.d.ts +77 -0
  291. package/dist/modules/mcp/downstream-token-refresh.d.ts.map +1 -0
  292. package/dist/modules/mcp/downstream-token-refresh.js +166 -0
  293. package/dist/modules/mcp/downstream-token-refresh.js.map +1 -0
  294. package/dist/modules/mcp/first-call-probe.cli-args.d.ts +78 -0
  295. package/dist/modules/mcp/first-call-probe.cli-args.d.ts.map +1 -0
  296. package/dist/modules/mcp/first-call-probe.cli-args.js +151 -0
  297. package/dist/modules/mcp/first-call-probe.cli-args.js.map +1 -0
  298. package/dist/modules/mcp/first-call-probe.cli.d.ts +2 -0
  299. package/dist/modules/mcp/first-call-probe.cli.d.ts.map +1 -0
  300. package/dist/modules/mcp/first-call-probe.cli.js +62 -0
  301. package/dist/modules/mcp/first-call-probe.cli.js.map +1 -0
  302. package/dist/modules/mcp/first-call-probe.d.ts +165 -0
  303. package/dist/modules/mcp/first-call-probe.d.ts.map +1 -0
  304. package/dist/modules/mcp/first-call-probe.js +298 -0
  305. package/dist/modules/mcp/first-call-probe.js.map +1 -0
  306. package/dist/modules/mcp/manual-failure-memo.d.ts +42 -17
  307. package/dist/modules/mcp/manual-failure-memo.d.ts.map +1 -1
  308. package/dist/modules/mcp/manual-failure-memo.js +79 -23
  309. package/dist/modules/mcp/manual-failure-memo.js.map +1 -1
  310. package/dist/modules/mcp/mcp-auth.middleware.d.ts +9 -5
  311. package/dist/modules/mcp/mcp-auth.middleware.d.ts.map +1 -1
  312. package/dist/modules/mcp/mcp-auth.middleware.js +24 -16
  313. package/dist/modules/mcp/mcp-auth.middleware.js.map +1 -1
  314. package/dist/modules/mcp/mcp.routes.d.ts +4 -4
  315. package/dist/modules/mcp/mcp.routes.d.ts.map +1 -1
  316. package/dist/modules/mcp/mcp.routes.js +83 -179
  317. package/dist/modules/mcp/mcp.routes.js.map +1 -1
  318. package/dist/modules/mcp/mcp.service.d.ts +218 -61
  319. package/dist/modules/mcp/mcp.service.d.ts.map +1 -1
  320. package/dist/modules/mcp/mcp.service.js +713 -159
  321. package/dist/modules/mcp/mcp.service.js.map +1 -1
  322. package/dist/modules/mcp/oauth/bevel-oauth-provider.d.ts.map +1 -1
  323. package/dist/modules/mcp/oauth/bevel-oauth-provider.js +8 -2
  324. package/dist/modules/mcp/oauth/bevel-oauth-provider.js.map +1 -1
  325. package/dist/modules/mcp/oauth/oauth-consent.routes.d.ts +14 -8
  326. package/dist/modules/mcp/oauth/oauth-consent.routes.d.ts.map +1 -1
  327. package/dist/modules/mcp/oauth/oauth-consent.routes.js +16 -2
  328. package/dist/modules/mcp/oauth/oauth-consent.routes.js.map +1 -1
  329. package/dist/modules/mcp/oauth/oauth-state.d.ts +13 -2
  330. package/dist/modules/mcp/oauth/oauth-state.d.ts.map +1 -1
  331. package/dist/modules/mcp/oauth/oauth-state.js +3 -1
  332. package/dist/modules/mcp/oauth/oauth-state.js.map +1 -1
  333. package/dist/modules/mcp/surface-log-throttle.d.ts +59 -0
  334. package/dist/modules/mcp/surface-log-throttle.d.ts.map +1 -0
  335. package/dist/modules/mcp/surface-log-throttle.js +94 -0
  336. package/dist/modules/mcp/surface-log-throttle.js.map +1 -0
  337. package/dist/modules/plugins/compile/compile-marketplace.d.ts +104 -0
  338. package/dist/modules/plugins/compile/compile-marketplace.d.ts.map +1 -0
  339. package/dist/modules/plugins/compile/compile-marketplace.js +323 -0
  340. package/dist/modules/plugins/compile/compile-marketplace.js.map +1 -0
  341. package/dist/modules/plugins/compile/marketplace-compiler.service.d.ts +73 -0
  342. package/dist/modules/plugins/compile/marketplace-compiler.service.d.ts.map +1 -0
  343. package/dist/modules/plugins/compile/marketplace-compiler.service.js +135 -0
  344. package/dist/modules/plugins/compile/marketplace-compiler.service.js.map +1 -0
  345. package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.d.ts +37 -0
  346. package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.d.ts.map +1 -0
  347. package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.js +158 -0
  348. package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.js.map +1 -0
  349. package/dist/modules/plugins/discovery/bundle-dialect/registry.d.ts +65 -0
  350. package/dist/modules/plugins/discovery/bundle-dialect/registry.d.ts.map +1 -0
  351. package/dist/modules/plugins/discovery/bundle-dialect/registry.js +204 -0
  352. package/dist/modules/plugins/discovery/bundle-dialect/registry.js.map +1 -0
  353. package/dist/modules/plugins/discovery/kb-plugin-source.d.ts +39 -0
  354. package/dist/modules/plugins/discovery/kb-plugin-source.d.ts.map +1 -0
  355. package/dist/modules/plugins/discovery/kb-plugin-source.js +110 -0
  356. package/dist/modules/plugins/discovery/kb-plugin-source.js.map +1 -0
  357. package/dist/modules/plugins/discovery/native.source.d.ts +16 -0
  358. package/dist/modules/plugins/discovery/native.source.d.ts.map +1 -0
  359. package/dist/modules/plugins/discovery/native.source.js +120 -0
  360. package/dist/modules/plugins/discovery/native.source.js.map +1 -0
  361. package/dist/modules/plugins/discovery/plugin-source.d.ts +110 -0
  362. package/dist/modules/plugins/discovery/plugin-source.d.ts.map +1 -0
  363. package/dist/modules/plugins/discovery/plugin-source.js +2 -0
  364. package/dist/modules/plugins/discovery/plugin-source.js.map +1 -0
  365. package/dist/modules/plugins/index.d.ts +15 -3
  366. package/dist/modules/plugins/index.d.ts.map +1 -1
  367. package/dist/modules/plugins/index.js +13 -2
  368. package/dist/modules/plugins/index.js.map +1 -1
  369. package/dist/modules/plugins/join-request-jobs.service.d.ts +250 -0
  370. package/dist/modules/plugins/join-request-jobs.service.d.ts.map +1 -0
  371. package/dist/modules/plugins/join-request-jobs.service.js +602 -0
  372. package/dist/modules/plugins/join-request-jobs.service.js.map +1 -0
  373. package/dist/modules/plugins/join-request-records.store.d.ts +161 -0
  374. package/dist/modules/plugins/join-request-records.store.d.ts.map +1 -0
  375. package/dist/modules/plugins/join-request-records.store.js +179 -0
  376. package/dist/modules/plugins/join-request-records.store.js.map +1 -0
  377. package/dist/modules/plugins/join-requests.service.d.ts.map +1 -1
  378. package/dist/modules/plugins/join-requests.service.js +4 -2
  379. package/dist/modules/plugins/join-requests.service.js.map +1 -1
  380. package/dist/modules/plugins/plugin-links.d.ts +69 -0
  381. package/dist/modules/plugins/plugin-links.d.ts.map +1 -0
  382. package/dist/modules/plugins/plugin-links.js +163 -0
  383. package/dist/modules/plugins/plugin-links.js.map +1 -0
  384. package/dist/modules/plugins/plugin-links.service.d.ts +111 -0
  385. package/dist/modules/plugins/plugin-links.service.d.ts.map +1 -0
  386. package/dist/modules/plugins/plugin-links.service.js +295 -0
  387. package/dist/modules/plugins/plugin-links.service.js.map +1 -0
  388. package/dist/modules/plugins/plugin-provision.service.d.ts +129 -21
  389. package/dist/modules/plugins/plugin-provision.service.d.ts.map +1 -1
  390. package/dist/modules/plugins/plugin-provision.service.js +320 -75
  391. package/dist/modules/plugins/plugin-provision.service.js.map +1 -1
  392. package/dist/modules/plugins/plugin-rename.service.d.ts +71 -0
  393. package/dist/modules/plugins/plugin-rename.service.d.ts.map +1 -0
  394. package/dist/modules/plugins/plugin-rename.service.js +254 -0
  395. package/dist/modules/plugins/plugin-rename.service.js.map +1 -0
  396. package/dist/modules/plugins/plugins.contract.d.ts +78 -4
  397. package/dist/modules/plugins/plugins.contract.d.ts.map +1 -1
  398. package/dist/modules/plugins/plugins.routes.d.ts +44 -5
  399. package/dist/modules/plugins/plugins.routes.d.ts.map +1 -1
  400. package/dist/modules/plugins/plugins.routes.js +297 -115
  401. package/dist/modules/plugins/plugins.routes.js.map +1 -1
  402. package/dist/modules/plugins/plugins.service.d.ts +82 -3
  403. package/dist/modules/plugins/plugins.service.d.ts.map +1 -1
  404. package/dist/modules/plugins/plugins.service.js +178 -48
  405. package/dist/modules/plugins/plugins.service.js.map +1 -1
  406. package/dist/modules/plugins/plugins.tools.d.ts +25 -0
  407. package/dist/modules/plugins/plugins.tools.d.ts.map +1 -0
  408. package/dist/modules/plugins/plugins.tools.js +82 -0
  409. package/dist/modules/plugins/plugins.tools.js.map +1 -0
  410. package/dist/modules/plugins/teams.routes.d.ts +42 -0
  411. package/dist/modules/plugins/teams.routes.d.ts.map +1 -0
  412. package/dist/modules/plugins/teams.routes.js +79 -0
  413. package/dist/modules/plugins/teams.routes.js.map +1 -0
  414. package/dist/modules/secrets-vault/db-secrets-vault.service.d.ts +40 -1
  415. package/dist/modules/secrets-vault/db-secrets-vault.service.d.ts.map +1 -1
  416. package/dist/modules/secrets-vault/db-secrets-vault.service.js +202 -37
  417. package/dist/modules/secrets-vault/db-secrets-vault.service.js.map +1 -1
  418. package/dist/modules/secrets-vault/index.d.ts +1 -1
  419. package/dist/modules/secrets-vault/index.d.ts.map +1 -1
  420. package/dist/modules/secrets-vault/index.js.map +1 -1
  421. package/dist/modules/secrets-vault/mcp-oauth-discovery.service.d.ts.map +1 -1
  422. package/dist/modules/secrets-vault/mcp-oauth-discovery.service.js +5 -3
  423. package/dist/modules/secrets-vault/mcp-oauth-discovery.service.js.map +1 -1
  424. package/dist/modules/secrets-vault/secrets-variable-loader.d.ts.map +1 -1
  425. package/dist/modules/secrets-vault/secrets-variable-loader.js +3 -1
  426. package/dist/modules/secrets-vault/secrets-variable-loader.js.map +1 -1
  427. package/dist/modules/secrets-vault/secrets-vault.contract.d.ts +78 -0
  428. package/dist/modules/secrets-vault/secrets-vault.contract.d.ts.map +1 -1
  429. package/dist/modules/secrets-vault/secrets-vault.contract.js +40 -0
  430. package/dist/modules/secrets-vault/secrets-vault.contract.js.map +1 -1
  431. package/dist/modules/secrets-vault/secrets-vault.routes.d.ts.map +1 -1
  432. package/dist/modules/secrets-vault/secrets-vault.routes.js +106 -52
  433. package/dist/modules/secrets-vault/secrets-vault.routes.js.map +1 -1
  434. package/dist/modules/settings/connection-check.d.ts +118 -0
  435. package/dist/modules/settings/connection-check.d.ts.map +1 -0
  436. package/dist/modules/settings/connection-check.js +287 -0
  437. package/dist/modules/settings/connection-check.js.map +1 -0
  438. package/dist/modules/settings/deployment-settings.service.d.ts +157 -2
  439. package/dist/modules/settings/deployment-settings.service.d.ts.map +1 -1
  440. package/dist/modules/settings/deployment-settings.service.js +412 -35
  441. package/dist/modules/settings/deployment-settings.service.js.map +1 -1
  442. package/dist/modules/settings/git-root-folders.d.ts +54 -0
  443. package/dist/modules/settings/git-root-folders.d.ts.map +1 -0
  444. package/dist/modules/settings/git-root-folders.js +130 -0
  445. package/dist/modules/settings/git-root-folders.js.map +1 -0
  446. package/dist/modules/settings/oidc-check.d.ts +85 -0
  447. package/dist/modules/settings/oidc-check.d.ts.map +1 -0
  448. package/dist/modules/settings/oidc-check.js +172 -0
  449. package/dist/modules/settings/oidc-check.js.map +1 -0
  450. package/dist/modules/settings/setup.routes.d.ts +57 -1
  451. package/dist/modules/settings/setup.routes.d.ts.map +1 -1
  452. package/dist/modules/settings/setup.routes.js +408 -108
  453. package/dist/modules/settings/setup.routes.js.map +1 -1
  454. package/dist/modules/skills/allowed-tools-check.d.ts +132 -0
  455. package/dist/modules/skills/allowed-tools-check.d.ts.map +1 -0
  456. package/dist/modules/skills/allowed-tools-check.js +260 -0
  457. package/dist/modules/skills/allowed-tools-check.js.map +1 -0
  458. package/dist/modules/skills/index.d.ts +4 -1
  459. package/dist/modules/skills/index.d.ts.map +1 -1
  460. package/dist/modules/skills/index.js +2 -0
  461. package/dist/modules/skills/index.js.map +1 -1
  462. package/dist/modules/skills/pending-skills.service.d.ts +6 -11
  463. package/dist/modules/skills/pending-skills.service.d.ts.map +1 -1
  464. package/dist/modules/skills/pending-skills.service.js +24 -71
  465. package/dist/modules/skills/pending-skills.service.js.map +1 -1
  466. package/dist/modules/skills/skill-access-requests.routes.d.ts +38 -0
  467. package/dist/modules/skills/skill-access-requests.routes.d.ts.map +1 -0
  468. package/dist/modules/skills/skill-access-requests.routes.js +171 -0
  469. package/dist/modules/skills/skill-access-requests.routes.js.map +1 -0
  470. package/dist/modules/skills/skills.contract.d.ts +67 -2
  471. package/dist/modules/skills/skills.contract.d.ts.map +1 -1
  472. package/dist/modules/skills/skills.routes.d.ts +35 -3
  473. package/dist/modules/skills/skills.routes.d.ts.map +1 -1
  474. package/dist/modules/skills/skills.routes.js +57 -4
  475. package/dist/modules/skills/skills.routes.js.map +1 -1
  476. package/dist/modules/skills/skills.service.d.ts +31 -3
  477. package/dist/modules/skills/skills.service.d.ts.map +1 -1
  478. package/dist/modules/skills/skills.service.js +236 -65
  479. package/dist/modules/skills/skills.service.js.map +1 -1
  480. package/dist/modules/skills/skills.tools.d.ts +4 -1
  481. package/dist/modules/skills/skills.tools.d.ts.map +1 -1
  482. package/dist/modules/skills/skills.tools.js +41 -6
  483. package/dist/modules/skills/skills.tools.js.map +1 -1
  484. package/dist/modules/tool-auth/connection-key-rejection.d.ts +18 -0
  485. package/dist/modules/tool-auth/connection-key-rejection.d.ts.map +1 -0
  486. package/dist/modules/tool-auth/connection-key-rejection.js +20 -0
  487. package/dist/modules/tool-auth/connection-key-rejection.js.map +1 -0
  488. package/dist/modules/tool-auth/connection-keys-admin.routes.d.ts +14 -0
  489. package/dist/modules/tool-auth/connection-keys-admin.routes.d.ts.map +1 -0
  490. package/dist/modules/tool-auth/connection-keys-admin.routes.js +67 -0
  491. package/dist/modules/tool-auth/connection-keys-admin.routes.js.map +1 -0
  492. package/dist/modules/tool-auth/external-api-key.interface.d.ts +66 -1
  493. package/dist/modules/tool-auth/external-api-key.interface.d.ts.map +1 -1
  494. package/dist/modules/tool-auth/external-api-key.interface.js +2 -1
  495. package/dist/modules/tool-auth/external-api-key.interface.js.map +1 -1
  496. package/dist/modules/tool-auth/external-api-key.service.d.ts +23 -4
  497. package/dist/modules/tool-auth/external-api-key.service.d.ts.map +1 -1
  498. package/dist/modules/tool-auth/external-api-key.service.js +79 -19
  499. package/dist/modules/tool-auth/external-api-key.service.js.map +1 -1
  500. package/dist/modules/tool-auth/internal-token.service.d.ts +5 -2
  501. package/dist/modules/tool-auth/internal-token.service.d.ts.map +1 -1
  502. package/dist/modules/tool-auth/internal-token.service.js +5 -2
  503. package/dist/modules/tool-auth/internal-token.service.js.map +1 -1
  504. package/dist/modules/tool-auth/key-or-session.middleware.d.ts +23 -0
  505. package/dist/modules/tool-auth/key-or-session.middleware.d.ts.map +1 -0
  506. package/dist/modules/tool-auth/key-or-session.middleware.js +39 -0
  507. package/dist/modules/tool-auth/key-or-session.middleware.js.map +1 -0
  508. package/dist/modules/tool-auth/tool-auth.middleware.d.ts +7 -1
  509. package/dist/modules/tool-auth/tool-auth.middleware.d.ts.map +1 -1
  510. package/dist/modules/tool-auth/tool-auth.middleware.js +8 -5
  511. package/dist/modules/tool-auth/tool-auth.middleware.js.map +1 -1
  512. package/dist/modules/tool-helpers/tool-context.d.ts +14 -0
  513. package/dist/modules/tool-helpers/tool-context.d.ts.map +1 -1
  514. package/dist/modules/tool-helpers/tool-context.js +28 -6
  515. package/dist/modules/tool-helpers/tool-context.js.map +1 -1
  516. package/dist/modules/tool-helpers/tool-handler.d.ts.map +1 -1
  517. package/dist/modules/tool-helpers/tool-handler.js +22 -5
  518. package/dist/modules/tool-helpers/tool-handler.js.map +1 -1
  519. package/dist/modules/tool-helpers/tool.contract.d.ts +6 -1
  520. package/dist/modules/tool-helpers/tool.contract.d.ts.map +1 -1
  521. package/dist/modules/tool-helpers/tool.contract.js +7 -1
  522. package/dist/modules/tool-helpers/tool.contract.js.map +1 -1
  523. package/dist/modules/tool-manuals/index.d.ts +2 -1
  524. package/dist/modules/tool-manuals/index.d.ts.map +1 -1
  525. package/dist/modules/tool-manuals/index.js +1 -0
  526. package/dist/modules/tool-manuals/index.js.map +1 -1
  527. package/dist/modules/tool-manuals/mcp-json-discovery.d.ts +36 -0
  528. package/dist/modules/tool-manuals/mcp-json-discovery.d.ts.map +1 -1
  529. package/dist/modules/tool-manuals/mcp-json-discovery.js +136 -96
  530. package/dist/modules/tool-manuals/mcp-json-discovery.js.map +1 -1
  531. package/dist/modules/tool-manuals/mcp-server-edit.service.d.ts +10 -2
  532. package/dist/modules/tool-manuals/mcp-server-edit.service.d.ts.map +1 -1
  533. package/dist/modules/tool-manuals/mcp-server-edit.service.js +12 -15
  534. package/dist/modules/tool-manuals/mcp-server-edit.service.js.map +1 -1
  535. package/dist/modules/tool-manuals/pending-tools.service.d.ts +50 -0
  536. package/dist/modules/tool-manuals/pending-tools.service.d.ts.map +1 -0
  537. package/dist/modules/tool-manuals/pending-tools.service.js +149 -0
  538. package/dist/modules/tool-manuals/pending-tools.service.js.map +1 -0
  539. package/dist/modules/tool-manuals/tool-delete.service.d.ts +135 -0
  540. package/dist/modules/tool-manuals/tool-delete.service.d.ts.map +1 -0
  541. package/dist/modules/tool-manuals/tool-delete.service.js +303 -0
  542. package/dist/modules/tool-manuals/tool-delete.service.js.map +1 -0
  543. package/dist/modules/tool-manuals/tool-manuals.contract.d.ts +161 -0
  544. package/dist/modules/tool-manuals/tool-manuals.contract.d.ts.map +1 -1
  545. package/dist/modules/tool-manuals/tool-manuals.contract.js +9 -0
  546. package/dist/modules/tool-manuals/tool-manuals.contract.js.map +1 -1
  547. package/dist/modules/tool-manuals/tool-manuals.routes.d.ts +19 -2
  548. package/dist/modules/tool-manuals/tool-manuals.routes.d.ts.map +1 -1
  549. package/dist/modules/tool-manuals/tool-manuals.routes.js +127 -57
  550. package/dist/modules/tool-manuals/tool-manuals.routes.js.map +1 -1
  551. package/dist/modules/tool-manuals/tool-manuals.service.d.ts +121 -2
  552. package/dist/modules/tool-manuals/tool-manuals.service.d.ts.map +1 -1
  553. package/dist/modules/tool-manuals/tool-manuals.service.js +415 -92
  554. package/dist/modules/tool-manuals/tool-manuals.service.js.map +1 -1
  555. package/dist/modules/tool-manuals/tool-manuals.tools.d.ts.map +1 -1
  556. package/dist/modules/tool-manuals/tool-manuals.tools.js +78 -6
  557. package/dist/modules/tool-manuals/tool-manuals.tools.js.map +1 -1
  558. package/dist/modules/workflow/agent-tools/workflow.tools.d.ts.map +1 -1
  559. package/dist/modules/workflow/agent-tools/workflow.tools.js +88 -54
  560. package/dist/modules/workflow/agent-tools/workflow.tools.js.map +1 -1
  561. package/dist/modules/workflow/event-bus.d.ts +10 -4
  562. package/dist/modules/workflow/event-bus.d.ts.map +1 -1
  563. package/dist/modules/workflow/event-bus.js +14 -11
  564. package/dist/modules/workflow/event-bus.js.map +1 -1
  565. package/dist/modules/workflow/events.routes.d.ts +17 -2
  566. package/dist/modules/workflow/events.routes.d.ts.map +1 -1
  567. package/dist/modules/workflow/events.routes.js +31 -12
  568. package/dist/modules/workflow/events.routes.js.map +1 -1
  569. package/dist/modules/workflow/file-lock.service.d.ts +22 -4
  570. package/dist/modules/workflow/file-lock.service.d.ts.map +1 -1
  571. package/dist/modules/workflow/file-lock.service.js +27 -4
  572. package/dist/modules/workflow/file-lock.service.js.map +1 -1
  573. package/dist/modules/workflow/git/change-request-link.d.ts +20 -0
  574. package/dist/modules/workflow/git/change-request-link.d.ts.map +1 -0
  575. package/dist/modules/workflow/git/change-request-link.js +34 -0
  576. package/dist/modules/workflow/git/change-request-link.js.map +1 -0
  577. package/dist/modules/workflow/git/git-version.d.ts.map +1 -1
  578. package/dist/modules/workflow/git/git-version.js +3 -1
  579. package/dist/modules/workflow/git/git-version.js.map +1 -1
  580. package/dist/modules/workflow/git/git.service.d.ts +303 -6
  581. package/dist/modules/workflow/git/git.service.d.ts.map +1 -1
  582. package/dist/modules/workflow/git/git.service.js +753 -170
  583. package/dist/modules/workflow/git/git.service.js.map +1 -1
  584. package/dist/modules/workflow/git/node-git-runner.d.ts +36 -0
  585. package/dist/modules/workflow/git/node-git-runner.d.ts.map +1 -0
  586. package/dist/modules/workflow/git/node-git-runner.js +273 -0
  587. package/dist/modules/workflow/git/node-git-runner.js.map +1 -0
  588. package/dist/modules/workflow/git/pull-request.service.d.ts +57 -2
  589. package/dist/modules/workflow/git/pull-request.service.d.ts.map +1 -1
  590. package/dist/modules/workflow/git/pull-request.service.js +165 -25
  591. package/dist/modules/workflow/git/pull-request.service.js.map +1 -1
  592. package/dist/modules/workflow/pending-commits.service.d.ts +11 -0
  593. package/dist/modules/workflow/pending-commits.service.d.ts.map +1 -1
  594. package/dist/modules/workflow/pending-commits.service.js +24 -4
  595. package/dist/modules/workflow/pending-commits.service.js.map +1 -1
  596. package/dist/modules/workflow/pending-commits.worker.d.ts +15 -8
  597. package/dist/modules/workflow/pending-commits.worker.d.ts.map +1 -1
  598. package/dist/modules/workflow/pending-commits.worker.js +107 -58
  599. package/dist/modules/workflow/pending-commits.worker.js.map +1 -1
  600. package/dist/modules/workflow/recovery-bot.d.ts.map +1 -1
  601. package/dist/modules/workflow/recovery-bot.js +3 -1
  602. package/dist/modules/workflow/recovery-bot.js.map +1 -1
  603. package/dist/modules/workflow/review-workflow/approval-lock.d.ts +60 -0
  604. package/dist/modules/workflow/review-workflow/approval-lock.d.ts.map +1 -0
  605. package/dist/modules/workflow/review-workflow/approval-lock.js +116 -0
  606. package/dist/modules/workflow/review-workflow/approval-lock.js.map +1 -0
  607. package/dist/modules/workflow/review-workflow/review-workflow.interface.d.ts +54 -7
  608. package/dist/modules/workflow/review-workflow/review-workflow.interface.d.ts.map +1 -1
  609. package/dist/modules/workflow/review-workflow/review-workflow.service.d.ts +64 -0
  610. package/dist/modules/workflow/review-workflow/review-workflow.service.d.ts.map +1 -1
  611. package/dist/modules/workflow/review-workflow/review-workflow.service.js +269 -90
  612. package/dist/modules/workflow/review-workflow/review-workflow.service.js.map +1 -1
  613. package/dist/modules/workflow/sanitize-error.d.ts +5 -2
  614. package/dist/modules/workflow/sanitize-error.d.ts.map +1 -1
  615. package/dist/modules/workflow/sanitize-error.js +8 -4
  616. package/dist/modules/workflow/sanitize-error.js.map +1 -1
  617. package/dist/modules/workflow/workflow.routes.d.ts +2 -0
  618. package/dist/modules/workflow/workflow.routes.d.ts.map +1 -1
  619. package/dist/modules/workflow/workflow.routes.js +259 -29
  620. package/dist/modules/workflow/workflow.routes.js.map +1 -1
  621. package/dist/modules/workflow/workflow.service.d.ts +217 -14
  622. package/dist/modules/workflow/workflow.service.d.ts.map +1 -1
  623. package/dist/modules/workflow/workflow.service.js +1142 -109
  624. package/dist/modules/workflow/workflow.service.js.map +1 -1
  625. package/dist/modules/workspace/empty-dirs.d.ts +15 -0
  626. package/dist/modules/workspace/empty-dirs.d.ts.map +1 -0
  627. package/dist/modules/workspace/empty-dirs.js +90 -0
  628. package/dist/modules/workspace/empty-dirs.js.map +1 -0
  629. package/dist/modules/workspace/file-readers/content-mode.d.ts +50 -0
  630. package/dist/modules/workspace/file-readers/content-mode.d.ts.map +1 -0
  631. package/dist/modules/workspace/file-readers/content-mode.js +55 -0
  632. package/dist/modules/workspace/file-readers/content-mode.js.map +1 -0
  633. package/dist/modules/workspace/file-readers/doc-extract.service.d.ts +4 -1
  634. package/dist/modules/workspace/file-readers/doc-extract.service.d.ts.map +1 -1
  635. package/dist/modules/workspace/file-readers/doc-extract.service.js +4 -1
  636. package/dist/modules/workspace/file-readers/doc-extract.service.js.map +1 -1
  637. package/dist/modules/workspace/file-readers/doc-extract.types.d.ts +5 -2
  638. package/dist/modules/workspace/file-readers/doc-extract.types.d.ts.map +1 -1
  639. package/dist/modules/workspace/file-readers/doc-extract.types.js +7 -4
  640. package/dist/modules/workspace/file-readers/doc-extract.types.js.map +1 -1
  641. package/dist/modules/workspace/file-readers/document-reader.d.ts +2 -0
  642. package/dist/modules/workspace/file-readers/document-reader.d.ts.map +1 -1
  643. package/dist/modules/workspace/file-readers/document-reader.js +5 -0
  644. package/dist/modules/workspace/file-readers/document-reader.js.map +1 -1
  645. package/dist/modules/workspace/file-readers/extract-docx.d.ts +6 -0
  646. package/dist/modules/workspace/file-readers/extract-docx.d.ts.map +1 -1
  647. package/dist/modules/workspace/file-readers/extract-docx.js +6 -0
  648. package/dist/modules/workspace/file-readers/extract-docx.js.map +1 -1
  649. package/dist/modules/workspace/file-readers/file-reader.d.ts +24 -5
  650. package/dist/modules/workspace/file-readers/file-reader.d.ts.map +1 -1
  651. package/dist/modules/workspace/file-readers/file-reader.js +11 -6
  652. package/dist/modules/workspace/file-readers/file-reader.js.map +1 -1
  653. package/dist/modules/workspace/file-readers/file-reader.registry.d.ts.map +1 -1
  654. package/dist/modules/workspace/file-readers/file-reader.registry.js +6 -1
  655. package/dist/modules/workspace/file-readers/file-reader.registry.js.map +1 -1
  656. package/dist/modules/workspace/file-readers/image-reader.d.ts +7 -5
  657. package/dist/modules/workspace/file-readers/image-reader.d.ts.map +1 -1
  658. package/dist/modules/workspace/file-readers/image-reader.js +9 -5
  659. package/dist/modules/workspace/file-readers/image-reader.js.map +1 -1
  660. package/dist/modules/workspace/file-readers/ooxml-text.d.ts +3 -0
  661. package/dist/modules/workspace/file-readers/ooxml-text.d.ts.map +1 -1
  662. package/dist/modules/workspace/file-readers/ooxml-text.js +39 -2
  663. package/dist/modules/workspace/file-readers/ooxml-text.js.map +1 -1
  664. package/dist/modules/workspace/file-readers/text-reader.d.ts +29 -1
  665. package/dist/modules/workspace/file-readers/text-reader.d.ts.map +1 -1
  666. package/dist/modules/workspace/file-readers/text-reader.js +57 -3
  667. package/dist/modules/workspace/file-readers/text-reader.js.map +1 -1
  668. package/dist/modules/workspace/git-internals.middleware.d.ts +28 -0
  669. package/dist/modules/workspace/git-internals.middleware.d.ts.map +1 -0
  670. package/dist/modules/workspace/git-internals.middleware.js +93 -0
  671. package/dist/modules/workspace/git-internals.middleware.js.map +1 -0
  672. package/dist/modules/workspace/not-found.d.ts +80 -0
  673. package/dist/modules/workspace/not-found.d.ts.map +1 -0
  674. package/dist/modules/workspace/not-found.js +112 -0
  675. package/dist/modules/workspace/not-found.js.map +1 -0
  676. package/dist/modules/workspace/session-ontology.gate.d.ts +1 -1
  677. package/dist/modules/workspace/session-ontology.gate.d.ts.map +1 -1
  678. package/dist/modules/workspace/session-ontology.gate.js +1 -1
  679. package/dist/modules/workspace/session-ontology.gate.js.map +1 -1
  680. package/dist/modules/workspace/startup/beside-checkout.d.ts +42 -0
  681. package/dist/modules/workspace/startup/beside-checkout.d.ts.map +1 -0
  682. package/dist/modules/workspace/startup/beside-checkout.js +110 -0
  683. package/dist/modules/workspace/startup/beside-checkout.js.map +1 -0
  684. package/dist/modules/workspace/startup/kb-git.d.ts +7 -12
  685. package/dist/modules/workspace/startup/kb-git.d.ts.map +1 -1
  686. package/dist/modules/workspace/startup/kb-git.js +34 -35
  687. package/dist/modules/workspace/startup/kb-git.js.map +1 -1
  688. package/dist/modules/workspace/startup/kb-startup-runner.d.ts +95 -0
  689. package/dist/modules/workspace/startup/kb-startup-runner.d.ts.map +1 -1
  690. package/dist/modules/workspace/startup/kb-startup-runner.js +257 -55
  691. package/dist/modules/workspace/startup/kb-startup-runner.js.map +1 -1
  692. package/dist/modules/workspace/startup/steps/groups-to-plugins.step.d.ts +45 -0
  693. package/dist/modules/workspace/startup/steps/groups-to-plugins.step.d.ts.map +1 -1
  694. package/dist/modules/workspace/startup/steps/groups-to-plugins.step.js +417 -385
  695. package/dist/modules/workspace/startup/steps/groups-to-plugins.step.js.map +1 -1
  696. package/dist/modules/workspace/startup/steps/personal-spaces.step.d.ts +48 -0
  697. package/dist/modules/workspace/startup/steps/personal-spaces.step.d.ts.map +1 -0
  698. package/dist/modules/workspace/startup/steps/personal-spaces.step.js +183 -0
  699. package/dist/modules/workspace/startup/steps/personal-spaces.step.js.map +1 -0
  700. package/dist/modules/workspace/startup/steps/plugin-display-names.step.d.ts +51 -0
  701. package/dist/modules/workspace/startup/steps/plugin-display-names.step.d.ts.map +1 -0
  702. package/dist/modules/workspace/startup/steps/plugin-display-names.step.js +158 -0
  703. package/dist/modules/workspace/startup/steps/plugin-display-names.step.js.map +1 -0
  704. package/dist/modules/workspace/startup/steps/plugin-layout.d.ts +64 -0
  705. package/dist/modules/workspace/startup/steps/plugin-layout.d.ts.map +1 -0
  706. package/dist/modules/workspace/startup/steps/plugin-layout.js +97 -0
  707. package/dist/modules/workspace/startup/steps/plugin-layout.js.map +1 -0
  708. package/dist/modules/workspace/startup/steps/plugin-manifests.step.d.ts +41 -0
  709. package/dist/modules/workspace/startup/steps/plugin-manifests.step.d.ts.map +1 -0
  710. package/dist/modules/workspace/startup/steps/plugin-manifests.step.js +85 -0
  711. package/dist/modules/workspace/startup/steps/plugin-manifests.step.js.map +1 -0
  712. package/dist/modules/workspace/startup/steps/roles-yaml.step.d.ts +3 -1
  713. package/dist/modules/workspace/startup/steps/roles-yaml.step.d.ts.map +1 -1
  714. package/dist/modules/workspace/startup/steps/roles-yaml.step.js +4 -12
  715. package/dist/modules/workspace/startup/steps/roles-yaml.step.js.map +1 -1
  716. package/dist/modules/workspace/startup/steps/seed-tree.d.ts +6 -1
  717. package/dist/modules/workspace/startup/steps/seed-tree.d.ts.map +1 -1
  718. package/dist/modules/workspace/startup/steps/seed-tree.js +174 -54
  719. package/dist/modules/workspace/startup/steps/seed-tree.js.map +1 -1
  720. package/dist/modules/workspace/startup/steps/template-files.step.d.ts +96 -24
  721. package/dist/modules/workspace/startup/steps/template-files.step.d.ts.map +1 -1
  722. package/dist/modules/workspace/startup/steps/template-files.step.js +521 -126
  723. package/dist/modules/workspace/startup/steps/template-files.step.js.map +1 -1
  724. package/dist/modules/workspace/startup/steps/template-source.d.ts +94 -0
  725. package/dist/modules/workspace/startup/steps/template-source.d.ts.map +1 -0
  726. package/dist/modules/workspace/startup/steps/template-source.js +160 -0
  727. package/dist/modules/workspace/startup/steps/template-source.js.map +1 -0
  728. package/dist/modules/workspace/workspace.routes.d.ts +14 -2
  729. package/dist/modules/workspace/workspace.routes.d.ts.map +1 -1
  730. package/dist/modules/workspace/workspace.routes.js +657 -246
  731. package/dist/modules/workspace/workspace.routes.js.map +1 -1
  732. package/dist/modules/workspace/workspace.service.d.ts +323 -12
  733. package/dist/modules/workspace/workspace.service.d.ts.map +1 -1
  734. package/dist/modules/workspace/workspace.service.js +1006 -257
  735. package/dist/modules/workspace/workspace.service.js.map +1 -1
  736. package/dist/modules/workspace/workspace.tools.d.ts +42 -1
  737. package/dist/modules/workspace/workspace.tools.d.ts.map +1 -1
  738. package/dist/modules/workspace/workspace.tools.js +1590 -146
  739. package/dist/modules/workspace/workspace.tools.js.map +1 -1
  740. package/dist/modules/workspace/write-denial.d.ts +76 -0
  741. package/dist/modules/workspace/write-denial.d.ts.map +1 -0
  742. package/dist/modules/workspace/write-denial.js +138 -0
  743. package/dist/modules/workspace/write-denial.js.map +1 -0
  744. package/dist/shared/canonical-file-identity.d.ts +64 -0
  745. package/dist/shared/canonical-file-identity.d.ts.map +1 -0
  746. package/dist/shared/canonical-file-identity.js +92 -0
  747. package/dist/shared/canonical-file-identity.js.map +1 -0
  748. package/dist/shared/domain-errors.d.ts +128 -0
  749. package/dist/shared/domain-errors.d.ts.map +1 -1
  750. package/dist/shared/domain-errors.js +166 -0
  751. package/dist/shared/domain-errors.js.map +1 -1
  752. package/dist/shared/email-identity.d.ts +32 -0
  753. package/dist/shared/email-identity.d.ts.map +1 -0
  754. package/dist/shared/email-identity.js +37 -0
  755. package/dist/shared/email-identity.js.map +1 -0
  756. package/dist/shared/fs-errors.d.ts +8 -0
  757. package/dist/shared/fs-errors.d.ts.map +1 -0
  758. package/dist/shared/fs-errors.js +11 -0
  759. package/dist/shared/fs-errors.js.map +1 -0
  760. package/dist/shared/fs-walk.d.ts +20 -6
  761. package/dist/shared/fs-walk.d.ts.map +1 -1
  762. package/dist/shared/fs-walk.js +35 -27
  763. package/dist/shared/fs-walk.js.map +1 -1
  764. package/dist/shared/fs.contract.d.ts +206 -0
  765. package/dist/shared/fs.contract.d.ts.map +1 -0
  766. package/dist/shared/fs.contract.js +79 -0
  767. package/dist/shared/fs.contract.js.map +1 -0
  768. package/dist/shared/git-failure.d.ts +80 -0
  769. package/dist/shared/git-failure.d.ts.map +1 -0
  770. package/dist/shared/git-failure.js +139 -0
  771. package/dist/shared/git-failure.js.map +1 -0
  772. package/dist/shared/git-internals.d.ts +17 -0
  773. package/dist/shared/git-internals.d.ts.map +1 -0
  774. package/dist/shared/git-internals.js +123 -0
  775. package/dist/shared/git-internals.js.map +1 -0
  776. package/dist/shared/git.contract.d.ts +157 -0
  777. package/dist/shared/git.contract.d.ts.map +1 -0
  778. package/dist/shared/git.contract.js +103 -0
  779. package/dist/shared/git.contract.js.map +1 -0
  780. package/dist/shared/http-errors.d.ts +33 -0
  781. package/dist/shared/http-errors.d.ts.map +1 -0
  782. package/dist/shared/http-errors.js +35 -0
  783. package/dist/shared/http-errors.js.map +1 -0
  784. package/dist/shared/kb-walk.d.ts +52 -0
  785. package/dist/shared/kb-walk.d.ts.map +1 -0
  786. package/dist/shared/kb-walk.js +76 -0
  787. package/dist/shared/kb-walk.js.map +1 -0
  788. package/dist/shared/logger.contract.d.ts +63 -0
  789. package/dist/shared/logger.contract.d.ts.map +1 -0
  790. package/dist/shared/logger.contract.js +126 -0
  791. package/dist/shared/logger.contract.js.map +1 -0
  792. package/dist/shared/logging.d.ts +31 -0
  793. package/dist/shared/logging.d.ts.map +1 -0
  794. package/dist/shared/logging.js +92 -0
  795. package/dist/shared/logging.js.map +1 -0
  796. package/dist/shared/path-containment.d.ts +21 -0
  797. package/dist/shared/path-containment.d.ts.map +1 -0
  798. package/dist/shared/path-containment.js +34 -0
  799. package/dist/shared/path-containment.js.map +1 -0
  800. package/dist/shared/path-order.d.ts +18 -0
  801. package/dist/shared/path-order.d.ts.map +1 -0
  802. package/dist/shared/path-order.js +35 -0
  803. package/dist/shared/path-order.js.map +1 -0
  804. package/dist/shared/pending-proposals.d.ts +71 -0
  805. package/dist/shared/pending-proposals.d.ts.map +1 -0
  806. package/dist/shared/pending-proposals.js +98 -0
  807. package/dist/shared/pending-proposals.js.map +1 -0
  808. package/dist/shared/printable.d.ts +22 -0
  809. package/dist/shared/printable.d.ts.map +1 -0
  810. package/dist/shared/printable.js +65 -0
  811. package/dist/shared/printable.js.map +1 -0
  812. package/dist/shared/redact-secret.d.ts +30 -0
  813. package/dist/shared/redact-secret.d.ts.map +1 -0
  814. package/dist/shared/redact-secret.js +114 -0
  815. package/dist/shared/redact-secret.js.map +1 -0
  816. package/dist/shared/rename-no-replace.d.ts +119 -0
  817. package/dist/shared/rename-no-replace.d.ts.map +1 -0
  818. package/dist/shared/rename-no-replace.js +323 -0
  819. package/dist/shared/rename-no-replace.js.map +1 -0
  820. package/dist/shared/ssrf.d.ts.map +1 -1
  821. package/dist/shared/ssrf.js +49 -18
  822. package/dist/shared/ssrf.js.map +1 -1
  823. package/dist/shared/ttl-cache.d.ts +28 -1
  824. package/dist/shared/ttl-cache.d.ts.map +1 -1
  825. package/dist/shared/ttl-cache.js +33 -1
  826. package/dist/shared/ttl-cache.js.map +1 -1
  827. package/dist/version.d.ts +10 -6
  828. package/dist/version.d.ts.map +1 -1
  829. package/dist/version.js +10 -6
  830. package/dist/version.js.map +1 -1
  831. package/kb-template/.bevelignore +4 -3
  832. package/kb-template/AGENTS.md +364 -54
  833. package/kb-template/KnowledgeBase/How to get started.md +1 -1
  834. package/kb-template/Skills/.gitkeep +0 -0
  835. package/kb-template/access.md +5 -3
  836. package/kb-template/mcp-description.md +27 -0
  837. package/migrations/0005_github_facade.sql +25 -0
  838. package/migrations/0006_api_tokens_revoked_by.sql +1 -0
  839. package/migrations/0007_github_facade_registered.sql +1 -0
  840. package/migrations/0008_change_request_apply_failure.sql +4 -0
  841. package/migrations/0009_change_request_apply_failure_kind.sql +13 -0
  842. package/migrations/0010_plugin_join_requests.sql +15 -0
  843. package/migrations/0011_plugin_join_request_claim.sql +11 -0
  844. package/migrations/meta/0005_snapshot.json +1717 -0
  845. package/migrations/meta/0006_snapshot.json +1723 -0
  846. package/migrations/meta/0007_snapshot.json +1729 -0
  847. package/migrations/meta/0008_snapshot.json +1753 -0
  848. package/migrations/meta/0009_snapshot.json +1759 -0
  849. package/migrations/meta/0010_snapshot.json +1872 -0
  850. package/migrations/meta/0011_snapshot.json +1884 -0
  851. package/migrations/meta/_journal.json +49 -0
  852. package/package.json +8 -7
  853. package/src/__tests__/core-config.domain.test.ts +67 -2
  854. package/src/__tests__/kb-layout-config.test.ts +295 -0
  855. package/src/__tests__/open-change-gate.ts +15 -0
  856. package/src/core/__tests__/catalog-cache-invalidation.test.ts +226 -0
  857. package/src/core/__tests__/catalog-revision.test.ts +190 -0
  858. package/src/core/__tests__/lifecycle.test.ts +369 -0
  859. package/src/core/__tests__/public-config.test.ts +30 -0
  860. package/src/core/__tests__/readiness.test.ts +109 -0
  861. package/src/core/catalog-cache-invalidation.ts +111 -0
  862. package/src/core/catalog-revision.ts +110 -0
  863. package/src/core/create-core-server.ts +358 -63
  864. package/src/core/create-core-services.ts +449 -107
  865. package/src/core/lifecycle.ts +312 -0
  866. package/src/core/public-config.ts +86 -0
  867. package/src/core/readiness.ts +123 -0
  868. package/src/core-config.ts +70 -4
  869. package/src/index.ts +15 -0
  870. package/src/modules/access/__tests__/access-control.admin-root-floor.test.ts +362 -0
  871. package/src/modules/access/__tests__/access-control.atref-batch.test.ts +2 -1
  872. package/src/modules/access/__tests__/access-control.atref-cache.test.ts +46 -22
  873. package/src/modules/access/__tests__/access-control.deny-dependents.test.ts +215 -0
  874. package/src/modules/access/__tests__/access-control.download-read.test.ts +268 -0
  875. package/src/modules/access/__tests__/access-control.everyone-read.test.ts +145 -0
  876. package/src/modules/access/__tests__/access-control.group-read.test.ts +163 -0
  877. package/src/modules/access/__tests__/access-control.invalidate-race.test.ts +88 -0
  878. package/src/modules/access/__tests__/access-control.platform-restore.test.ts +152 -0
  879. package/src/modules/access/__tests__/access-control.prospective.test.ts +189 -0
  880. package/src/modules/access/__tests__/access-control.read-batch.test.ts +2 -1
  881. package/src/modules/access/__tests__/access-control.service.test.ts +142 -81
  882. package/src/modules/access/__tests__/access-groups.test.ts +47 -14
  883. package/src/modules/access/__tests__/access-md-format.test.ts +2 -1
  884. package/src/modules/access/__tests__/access-mutation.service.test.ts +52 -4
  885. package/src/modules/access/__tests__/access-own-read-grant.test.ts +2 -0
  886. package/src/modules/access/__tests__/access-personal-plugin.test.ts +153 -0
  887. package/src/modules/access/__tests__/access-plugin-principals.test.ts +385 -0
  888. package/src/modules/access/__tests__/access-restrict-here.test.ts +450 -0
  889. package/src/modules/access/__tests__/access.routes.batch.test.ts +139 -0
  890. package/src/modules/access/__tests__/access.routes.folder-governs.test.ts +394 -0
  891. package/src/modules/access/__tests__/access.routes.group-grant.test.ts +6 -2
  892. package/src/modules/access/__tests__/access.routes.overrides.test.ts +3 -2
  893. package/src/modules/access/__tests__/access.routes.proposal-branch.test.ts +234 -0
  894. package/src/modules/access/__tests__/access.routes.prospective.test.ts +216 -0
  895. package/src/modules/access/__tests__/access.routes.revoke.test.ts +7 -2
  896. package/src/modules/access/__tests__/access.routes.unknown-email.test.ts +360 -0
  897. package/src/modules/access/__tests__/change-read-gate.test.ts +272 -0
  898. package/src/modules/access/__tests__/creator-access.test.ts +81 -83
  899. package/src/modules/access/__tests__/grant-sources.test.ts +3 -2
  900. package/src/modules/access/__tests__/groups-admin.service.test.ts +14 -5
  901. package/src/modules/access/__tests__/roles-admin.security.test.ts +196 -0
  902. package/src/modules/access/__tests__/roles-admin.service.test.ts +127 -2
  903. package/src/modules/access/__tests__/roles-capabilities.test.ts +5 -4
  904. package/src/modules/access/__tests__/roles.routes.test.ts +5 -2
  905. package/src/modules/access/__tests__/user-access-removal.service.test.ts +402 -0
  906. package/src/modules/access/__tests__/users-db-double.ts +63 -0
  907. package/src/modules/access/access-control.interface.ts +269 -18
  908. package/src/modules/access/access-control.service.ts +943 -226
  909. package/src/modules/access/access-mutation.service.ts +182 -13
  910. package/src/modules/access/access-view.ts +316 -0
  911. package/src/modules/access/access.routes.ts +385 -105
  912. package/src/modules/access/admin-locked-commit.ts +12 -14
  913. package/src/modules/access/admin-route-helpers.ts +4 -4
  914. package/src/modules/access/change-read-gate.ts +148 -0
  915. package/src/modules/access/creator-access.ts +89 -124
  916. package/src/modules/access/directory-sync-bot.ts +4 -1
  917. package/src/modules/access/groups-admin.service.ts +3 -3
  918. package/src/modules/access/reference-scan.ts +5 -5
  919. package/src/modules/access/roles-admin.service.ts +94 -15
  920. package/src/modules/access/synced-groups-committer.ts +10 -15
  921. package/src/modules/access/synced-groups-writer.ts +3 -12
  922. package/src/modules/access/user-access-removal.service.ts +711 -0
  923. package/src/modules/access-model/__tests__/access-grammar.test.ts +18 -0
  924. package/src/modules/access-model/__tests__/access-splice.test.ts +63 -1
  925. package/src/modules/access-model/__tests__/frontmatter-fences.test.ts +71 -0
  926. package/src/modules/access-model/__tests__/plugin-token-canonical.test.ts +40 -0
  927. package/src/modules/access-model/__tests__/roles-yaml-guard.test.ts +131 -0
  928. package/src/modules/access-model/access-errors.ts +56 -15
  929. package/src/modules/access-model/access-grammar.ts +198 -49
  930. package/src/modules/access-model/access-splice.ts +18 -18
  931. package/src/modules/access-model/access-template.ts +44 -0
  932. package/src/modules/access-model/change-gate.ts +80 -0
  933. package/src/modules/access-model/creator.ts +18 -21
  934. package/src/modules/access-model/frontmatter-lines.ts +98 -0
  935. package/src/modules/access-model/group-files.ts +4 -0
  936. package/src/modules/access-model/plugin-principals.ts +130 -0
  937. package/src/modules/access-model/roles-yaml-guard.ts +182 -4
  938. package/src/modules/admin/admin-access.service.ts +6 -2
  939. package/src/modules/agent-instructions/__tests__/agent-instructions.route.test.ts +100 -0
  940. package/src/modules/agent-instructions/__tests__/compose.test.ts +256 -0
  941. package/src/modules/agent-instructions/__tests__/read-preamble.test.ts +135 -0
  942. package/src/modules/agent-instructions/agent-instructions.routes.ts +41 -0
  943. package/src/modules/agent-instructions/compose.ts +271 -0
  944. package/src/modules/agent-instructions/index.ts +14 -0
  945. package/src/modules/agent-instructions/read-preamble.ts +88 -0
  946. package/src/modules/auth/__tests__/account-erasure.approval-gate.test.ts +209 -0
  947. package/src/modules/auth/__tests__/account.routes.test.ts +178 -2
  948. package/src/modules/auth/__tests__/auth.middleware.test.ts +78 -0
  949. package/src/modules/auth/__tests__/auth.service.test.ts +338 -5
  950. package/src/modules/auth/__tests__/oidc-auth-provider.test.ts +352 -12
  951. package/src/modules/auth/__tests__/onboarding-done.route.test.ts +3 -1
  952. package/src/modules/auth/account-erasure.service.ts +117 -10
  953. package/src/modules/auth/account.routes.ts +115 -14
  954. package/src/modules/auth/auth.routes.ts +20 -7
  955. package/src/modules/auth/auth.service.ts +187 -28
  956. package/src/modules/auth/oidc-auth-provider.ts +120 -22
  957. package/src/modules/code-mode/__tests__/code-mode.tool.test.ts +109 -1
  958. package/src/modules/code-mode/code-mode.tool.ts +13 -2
  959. package/src/modules/connection-probe/__tests__/connection-probe.service.test.ts +78 -0
  960. package/src/modules/connection-probe/connection-probe.service.ts +59 -7
  961. package/src/modules/database/__tests__/advisory-lease.test.ts +152 -0
  962. package/src/modules/database/__tests__/advisory-lock.test.ts +147 -0
  963. package/src/modules/database/advisory-lock.ts +346 -0
  964. package/src/modules/database/connection.ts +9 -1
  965. package/src/modules/database/core-schema.ts +177 -0
  966. package/src/modules/database/migrate.ts +27 -6
  967. package/src/modules/declared-variables/declared-variables.routes.ts +6 -3
  968. package/src/modules/diff/__tests__/diff.service.seed-atomicity.test.ts +3 -0
  969. package/src/modules/diff/__tests__/diff.service.test.ts +3 -0
  970. package/src/modules/diff/diff.routes.ts +2 -4
  971. package/src/modules/diff/diff.service.ts +75 -79
  972. package/src/modules/kb-fs/__tests__/locking-filesystem.test.ts +472 -9
  973. package/src/modules/kb-fs/__tests__/node-fs.test.ts +409 -0
  974. package/src/modules/kb-fs/__tests__/repo-path.test.ts +210 -1
  975. package/src/modules/{workspace → kb-fs}/bevel-ignore.ts +22 -15
  976. package/src/modules/kb-fs/file-change-notifier.ts +4 -1
  977. package/src/modules/kb-fs/git-guarded-filesystem.ts +123 -0
  978. package/src/modules/kb-fs/locking-filesystem.ts +399 -109
  979. package/src/modules/kb-fs/node-fs.ts +165 -0
  980. package/src/modules/kb-fs/read-only-filesystem.ts +18 -9
  981. package/src/modules/kb-fs/repo-path.ts +213 -3
  982. package/src/modules/kb-sync/__tests__/kb-sync.routes.test.ts +297 -0
  983. package/src/modules/kb-sync/__tests__/kb-sync.service.test.ts +295 -0
  984. package/src/modules/kb-sync/__tests__/sync-auth.test.ts +118 -0
  985. package/src/modules/kb-sync/__tests__/sync-payload.test.ts +148 -0
  986. package/src/modules/kb-sync/index.ts +19 -0
  987. package/src/modules/kb-sync/kb-sync.interface.ts +79 -0
  988. package/src/modules/kb-sync/kb-sync.routes.ts +200 -0
  989. package/src/modules/kb-sync/kb-sync.service.ts +204 -0
  990. package/src/modules/kb-sync/sync-auth.ts +118 -0
  991. package/src/modules/kb-sync/sync-payload.ts +143 -0
  992. package/src/modules/marketplace/__tests__/github-facade.test.ts +575 -0
  993. package/src/modules/marketplace/__tests__/marketplace-git.test.ts +180 -0
  994. package/src/modules/marketplace/__tests__/marketplace-repo.head.test.ts +47 -0
  995. package/src/modules/marketplace/git-http.routes.ts +196 -0
  996. package/src/modules/marketplace/github-facade/github-facade-admin.routes.ts +110 -0
  997. package/src/modules/marketplace/github-facade/github-facade-codes.store.ts +145 -0
  998. package/src/modules/marketplace/github-facade/github-facade-credentials.service.ts +263 -0
  999. package/src/modules/marketplace/github-facade/github-facade.routes.ts +294 -0
  1000. package/src/modules/marketplace/github-facade/github-facade.service.ts +282 -0
  1001. package/src/modules/marketplace/github-facade/index.ts +26 -0
  1002. package/src/modules/marketplace/index.ts +3 -0
  1003. package/src/modules/marketplace/marketplace-repo.service.ts +352 -0
  1004. package/src/modules/mcp/__tests__/downstream-pool.test.ts +278 -0
  1005. package/src/modules/mcp/__tests__/downstream-token-refresh.test.ts +178 -0
  1006. package/src/modules/mcp/__tests__/fake-downstream-mcp-server.ts +156 -0
  1007. package/src/modules/mcp/__tests__/first-call-probe.cli-args.test.ts +178 -0
  1008. package/src/modules/mcp/__tests__/first-call-probe.test.ts +414 -0
  1009. package/src/modules/mcp/__tests__/manual-failure-memo.test.ts +98 -6
  1010. package/src/modules/mcp/__tests__/mcp-auth.middleware.test.ts +8 -5
  1011. package/src/modules/mcp/__tests__/mcp-routes-harness.ts +1 -3
  1012. package/src/modules/mcp/__tests__/mcp.e2e.test.ts +1055 -59
  1013. package/src/modules/mcp/__tests__/mcp.routes.stateless.test.ts +182 -0
  1014. package/src/modules/mcp/__tests__/mcp.service.test.ts +274 -6
  1015. package/src/modules/mcp/__tests__/surface-log-throttle.test.ts +169 -0
  1016. package/src/modules/mcp/downstream-pool.ts +256 -0
  1017. package/src/modules/mcp/downstream-token-refresh.ts +170 -0
  1018. package/src/modules/mcp/first-call-probe.cli-args.ts +159 -0
  1019. package/src/modules/mcp/first-call-probe.cli.ts +60 -0
  1020. package/src/modules/mcp/first-call-probe.ts +418 -0
  1021. package/src/modules/mcp/manual-failure-memo.ts +81 -23
  1022. package/src/modules/mcp/mcp-auth.middleware.ts +25 -16
  1023. package/src/modules/mcp/mcp.routes.ts +376 -482
  1024. package/src/modules/mcp/mcp.service.ts +846 -176
  1025. package/src/modules/mcp/oauth/bevel-oauth-provider.ts +8 -2
  1026. package/src/modules/mcp/oauth/oauth-consent.routes.ts +28 -6
  1027. package/src/modules/mcp/oauth/oauth-state.ts +15 -3
  1028. package/src/modules/mcp/surface-log-throttle.ts +120 -0
  1029. package/src/modules/plugins/__tests__/bundle-dialect.e2e.test.ts +166 -0
  1030. package/src/modules/plugins/__tests__/bundle-dialect.test.ts +165 -0
  1031. package/src/modules/plugins/__tests__/compile-marketplace.test.ts +423 -0
  1032. package/src/modules/plugins/__tests__/fake-join-request-store.ts +189 -0
  1033. package/src/modules/plugins/__tests__/join-request-jobs.service.test.ts +608 -0
  1034. package/src/modules/plugins/__tests__/plugin-creation-display-name.test.ts +241 -0
  1035. package/src/modules/plugins/__tests__/plugin-index.service.test.ts +201 -16
  1036. package/src/modules/plugins/__tests__/plugin-links.service.test.ts +284 -0
  1037. package/src/modules/plugins/__tests__/plugin-names.test.ts +77 -0
  1038. package/src/modules/plugins/__tests__/plugin-provision.service.test.ts +330 -20
  1039. package/src/modules/plugins/__tests__/plugin-rename.service.test.ts +456 -0
  1040. package/src/modules/plugins/__tests__/plugins.routes.test.ts +441 -43
  1041. package/src/modules/plugins/__tests__/plugins.tools.test.ts +131 -0
  1042. package/src/modules/plugins/__tests__/teams.routes.test.ts +248 -0
  1043. package/src/modules/plugins/compile/compile-marketplace.ts +500 -0
  1044. package/src/modules/plugins/compile/marketplace-compiler.service.ts +151 -0
  1045. package/src/modules/plugins/discovery/__tests__/kb-plugin-source.test.ts +365 -0
  1046. package/src/modules/plugins/discovery/bundle-dialect/bundle.source.ts +161 -0
  1047. package/src/modules/plugins/discovery/bundle-dialect/registry.ts +250 -0
  1048. package/src/modules/plugins/discovery/kb-plugin-source.ts +117 -0
  1049. package/src/modules/plugins/discovery/native.source.ts +140 -0
  1050. package/src/modules/plugins/discovery/plugin-source.ts +113 -0
  1051. package/src/modules/plugins/index.ts +25 -2
  1052. package/src/modules/plugins/join-request-jobs.service.ts +675 -0
  1053. package/src/modules/plugins/join-request-records.store.ts +353 -0
  1054. package/src/modules/plugins/join-requests.service.ts +7 -4
  1055. package/src/modules/plugins/plugin-links.service.ts +350 -0
  1056. package/src/modules/plugins/plugin-links.ts +187 -0
  1057. package/src/modules/plugins/plugin-provision.service.ts +356 -78
  1058. package/src/modules/plugins/plugin-rename.service.ts +310 -0
  1059. package/src/modules/plugins/plugins.contract.ts +79 -4
  1060. package/src/modules/plugins/plugins.routes.ts +320 -123
  1061. package/src/modules/plugins/plugins.service.ts +184 -57
  1062. package/src/modules/plugins/plugins.tools.ts +88 -0
  1063. package/src/modules/plugins/teams.routes.ts +129 -0
  1064. package/src/modules/secrets-vault/__tests__/connect-pending.route.test.ts +359 -15
  1065. package/src/modules/secrets-vault/__tests__/db-secrets-vault.oauth.test.ts +248 -0
  1066. package/src/modules/secrets-vault/__tests__/namespace-secrets.test.ts +202 -0
  1067. package/src/modules/secrets-vault/db-secrets-vault.service.ts +217 -35
  1068. package/src/modules/secrets-vault/index.ts +1 -0
  1069. package/src/modules/secrets-vault/mcp-oauth-discovery.service.ts +6 -3
  1070. package/src/modules/secrets-vault/secrets-variable-loader.ts +4 -4
  1071. package/src/modules/secrets-vault/secrets-vault.contract.ts +93 -0
  1072. package/src/modules/secrets-vault/secrets-vault.routes.ts +99 -38
  1073. package/src/modules/settings/__tests__/connection-check.test.ts +233 -0
  1074. package/src/modules/settings/__tests__/deployment-settings.service.test.ts +240 -1
  1075. package/src/modules/settings/__tests__/git-root-folders.test.ts +247 -0
  1076. package/src/modules/settings/__tests__/oidc-check.test.ts +185 -0
  1077. package/src/modules/settings/__tests__/setup.routes.boot-failure.test.ts +119 -0
  1078. package/src/modules/settings/__tests__/setup.routes.layout-phase.test.ts +170 -0
  1079. package/src/modules/settings/__tests__/setup.routes.oidc.test.ts +555 -0
  1080. package/src/modules/settings/__tests__/setup.routes.sync-status.test.ts +77 -0
  1081. package/src/modules/settings/__tests__/setup.routes.test.ts +667 -16
  1082. package/src/modules/settings/connection-check.ts +351 -0
  1083. package/src/modules/settings/deployment-settings.service.ts +478 -39
  1084. package/src/modules/settings/git-root-folders.ts +171 -0
  1085. package/src/modules/settings/oidc-check.ts +229 -0
  1086. package/src/modules/settings/setup.routes.ts +480 -110
  1087. package/src/modules/skills/__tests__/allowed-tools-check.test.ts +224 -0
  1088. package/src/modules/skills/__tests__/allowed-tools-warn.tools.test.ts +210 -0
  1089. package/src/modules/skills/__tests__/pending-skills.service.test.ts +3 -3
  1090. package/src/modules/skills/__tests__/skill-access-requests.routes.test.ts +128 -0
  1091. package/src/modules/skills/__tests__/skills.routes.warnings.test.ts +91 -0
  1092. package/src/modules/skills/__tests__/skills.service.test.ts +308 -2
  1093. package/src/modules/skills/allowed-tools-check.ts +352 -0
  1094. package/src/modules/skills/index.ts +5 -0
  1095. package/src/modules/skills/pending-skills.service.ts +26 -85
  1096. package/src/modules/skills/skill-access-requests.routes.ts +203 -0
  1097. package/src/modules/skills/skills.contract.ts +67 -3
  1098. package/src/modules/skills/skills.routes.ts +75 -4
  1099. package/src/modules/skills/skills.service.ts +258 -66
  1100. package/src/modules/skills/skills.tools.ts +43 -5
  1101. package/src/modules/tool-auth/__tests__/connection-key-rejection.test.ts +192 -0
  1102. package/src/modules/tool-auth/__tests__/connection-keys-admin.routes.test.ts +116 -0
  1103. package/src/modules/tool-auth/__tests__/external-api-key.service.test.ts +124 -0
  1104. package/src/modules/tool-auth/connection-key-rejection.ts +25 -0
  1105. package/src/modules/tool-auth/connection-keys-admin.routes.ts +76 -0
  1106. package/src/modules/tool-auth/external-api-key.interface.ts +73 -1
  1107. package/src/modules/tool-auth/external-api-key.service.ts +95 -29
  1108. package/src/modules/tool-auth/internal-token.service.ts +5 -2
  1109. package/src/modules/tool-auth/key-or-session.middleware.ts +45 -0
  1110. package/src/modules/tool-auth/tool-auth.middleware.ts +16 -7
  1111. package/src/modules/tool-helpers/__tests__/agent-roles-write.test.ts +228 -0
  1112. package/src/modules/tool-helpers/__tests__/phase4-tools.test.ts +33 -4
  1113. package/src/modules/tool-helpers/tool-context.ts +46 -7
  1114. package/src/modules/tool-helpers/tool-handler.ts +23 -5
  1115. package/src/modules/tool-helpers/tool.contract.ts +5 -0
  1116. package/src/modules/tool-manuals/__tests__/mcp-json-discovery.test.ts +24 -1
  1117. package/src/modules/tool-manuals/__tests__/mcp-server-edit.service.test.ts +2 -1
  1118. package/src/modules/tool-manuals/__tests__/pending-tools.service.test.ts +411 -0
  1119. package/src/modules/tool-manuals/__tests__/tool-delete.route.test.ts +133 -0
  1120. package/src/modules/tool-manuals/__tests__/tool-delete.service.test.ts +469 -0
  1121. package/src/modules/tool-manuals/__tests__/tool-manuals.archive.route.test.ts +21 -2
  1122. package/src/modules/tool-manuals/__tests__/tool-manuals.cli.test.ts +11 -4
  1123. package/src/modules/tool-manuals/__tests__/tool-manuals.detail.route.test.ts +6 -1
  1124. package/src/modules/tool-manuals/__tests__/tool-manuals.invalid.routes.test.ts +254 -0
  1125. package/src/modules/tool-manuals/__tests__/tool-manuals.invalid.test.ts +577 -0
  1126. package/src/modules/tool-manuals/__tests__/tool-manuals.mcp-oauth.test.ts +6 -1
  1127. package/src/modules/tool-manuals/__tests__/tool-manuals.pending.route.test.ts +102 -0
  1128. package/src/modules/tool-manuals/__tests__/tool-manuals.restart.test.ts +285 -0
  1129. package/src/modules/tool-manuals/__tests__/tool-manuals.service.test.ts +178 -2
  1130. package/src/modules/tool-manuals/__tests__/tool-manuals.tools.test.ts +114 -2
  1131. package/src/modules/tool-manuals/index.ts +3 -0
  1132. package/src/modules/tool-manuals/mcp-json-discovery.ts +164 -95
  1133. package/src/modules/tool-manuals/mcp-server-edit.service.ts +11 -14
  1134. package/src/modules/tool-manuals/pending-tools.service.ts +179 -0
  1135. package/src/modules/tool-manuals/tool-delete.service.ts +401 -0
  1136. package/src/modules/tool-manuals/tool-manuals.contract.ts +165 -0
  1137. package/src/modules/tool-manuals/tool-manuals.routes.ts +138 -54
  1138. package/src/modules/tool-manuals/tool-manuals.service.ts +440 -104
  1139. package/src/modules/tool-manuals/tool-manuals.tools.ts +81 -6
  1140. package/src/modules/workflow/__tests__/apply-failure.test.ts +1038 -0
  1141. package/src/modules/workflow/__tests__/event-bus.test.ts +61 -9
  1142. package/src/modules/workflow/__tests__/fake-file-lock-db.ts +199 -0
  1143. package/src/modules/workflow/__tests__/file-lock.service.path-identity.test.ts +237 -0
  1144. package/src/modules/workflow/__tests__/format-affected-owners.test.ts +18 -0
  1145. package/src/modules/workflow/__tests__/merge-announces-tree.test.ts +220 -0
  1146. package/src/modules/workflow/__tests__/pending-commits.worker.concurrency.test.ts +187 -0
  1147. package/src/modules/workflow/__tests__/preserve-roles-yaml.test.ts +3 -1
  1148. package/src/modules/workflow/__tests__/sanitize-error.test.ts +10 -0
  1149. package/src/modules/workflow/__tests__/workflow.routes.folder-proposals.test.ts +128 -0
  1150. package/src/modules/workflow/__tests__/workflow.routes.fork-point-file.test.ts +149 -0
  1151. package/src/modules/workflow/__tests__/workflow.routes.lock-path.test.ts +305 -0
  1152. package/src/modules/workflow/__tests__/workflow.service.branch-in-use.test.ts +2 -0
  1153. package/src/modules/workflow/__tests__/workflow.service.commitFileWhileLocked.test.ts +3 -0
  1154. package/src/modules/workflow/__tests__/workflow.service.deleted-branch-sweep.test.ts +2 -0
  1155. package/src/modules/workflow/__tests__/workflow.service.facade.test.ts +296 -27
  1156. package/src/modules/workflow/__tests__/workflow.service.folder-proposals.test.ts +564 -0
  1157. package/src/modules/workflow/__tests__/workflow.service.platform-restore.test.ts +135 -0
  1158. package/src/modules/workflow/__tests__/workflow.service.read-gate.test.ts +172 -0
  1159. package/src/modules/workflow/__tests__/workflow.service.releaseLock.test.ts +133 -2
  1160. package/src/modules/workflow/__tests__/workflow.service.sync.test.ts +442 -0
  1161. package/src/modules/workflow/__tests__/workflow.service.update-from-target.test.ts +281 -0
  1162. package/src/modules/workflow/agent-tools/__tests__/workflow.tools.test.ts +158 -7
  1163. package/src/modules/workflow/agent-tools/workflow.tools.ts +93 -64
  1164. package/src/modules/workflow/event-bus.ts +26 -28
  1165. package/src/modules/workflow/events.routes.ts +56 -21
  1166. package/src/modules/workflow/file-lock.service.ts +27 -4
  1167. package/src/modules/workflow/git/__tests__/change-request-link.test.ts +43 -0
  1168. package/src/modules/workflow/git/__tests__/git.service.accessGating.test.ts +1 -0
  1169. package/src/modules/workflow/git/__tests__/git.service.changedFilesForPr.test.ts +238 -1
  1170. package/src/modules/workflow/git/__tests__/git.service.forkPoint.test.ts +245 -0
  1171. package/src/modules/workflow/git/__tests__/git.service.list-branches.test.ts +35 -0
  1172. package/src/modules/workflow/git/__tests__/git.service.mergeChangeRequest.test.ts +149 -0
  1173. package/src/modules/workflow/git/__tests__/git.service.postMergePull.test.ts +3 -3
  1174. package/src/modules/workflow/git/__tests__/git.service.pull.test.ts +47 -4
  1175. package/src/modules/workflow/git/__tests__/git.service.revertPathsAndPush.test.ts +177 -0
  1176. package/src/modules/workflow/git/__tests__/git.service.syncFromRemote.test.ts +253 -0
  1177. package/src/modules/workflow/git/__tests__/node-git-runner.test.ts +114 -0
  1178. package/src/modules/workflow/git/__tests__/pull-request.service.getPrDetail.test.ts +69 -2
  1179. package/src/modules/workflow/git/__tests__/pull-request.service.list-fetch.test.ts +121 -0
  1180. package/src/modules/workflow/git/__tests__/pull-request.service.placeholder.test.ts +79 -0
  1181. package/src/modules/workflow/git/__tests__/pull-request.service.test.ts +1 -1
  1182. package/src/modules/workflow/git/__tests__/pull-request.service.viewer-can-cancel.test.ts +1 -1
  1183. package/src/modules/workflow/git/__tests__/pull-request.service.viewer-can-update.test.ts +111 -0
  1184. package/src/modules/workflow/git/change-request-link.ts +35 -0
  1185. package/src/modules/workflow/git/git-version.ts +5 -2
  1186. package/src/modules/workflow/git/git.service.ts +922 -199
  1187. package/src/modules/workflow/git/node-git-runner.ts +315 -0
  1188. package/src/modules/workflow/git/pull-request.service.ts +188 -27
  1189. package/src/modules/workflow/pending-commits.service.ts +26 -7
  1190. package/src/modules/workflow/pending-commits.worker.ts +114 -69
  1191. package/src/modules/workflow/recovery-bot.ts +4 -1
  1192. package/src/modules/workflow/review-workflow/__tests__/approval-states.test.ts +180 -1
  1193. package/src/modules/workflow/review-workflow/__tests__/cancel-pr.test.ts +1 -1
  1194. package/src/modules/workflow/review-workflow/__tests__/carry-approvals-forward.test.ts +520 -0
  1195. package/src/modules/workflow/review-workflow/__tests__/erase-approver.test.ts +84 -0
  1196. package/src/modules/workflow/review-workflow/__tests__/merge-gate.test.ts +89 -77
  1197. package/src/modules/workflow/review-workflow/approval-lock.ts +122 -0
  1198. package/src/modules/workflow/review-workflow/review-workflow.interface.ts +59 -7
  1199. package/src/modules/workflow/review-workflow/review-workflow.service.ts +309 -105
  1200. package/src/modules/workflow/sanitize-error.ts +9 -4
  1201. package/src/modules/workflow/workflow.routes.ts +273 -29
  1202. package/src/modules/workflow/workflow.service.ts +1341 -174
  1203. package/src/modules/workspace/__tests__/empty-dirs.test.ts +44 -0
  1204. package/src/modules/workspace/__tests__/file-stat-access.test.ts +301 -0
  1205. package/src/modules/workspace/__tests__/git-internals.security.test.ts +792 -0
  1206. package/src/modules/workspace/__tests__/workspace-paths-inside-the-repo.test.ts +464 -0
  1207. package/src/modules/workspace/__tests__/workspace.routes.branch-errors.test.ts +139 -0
  1208. package/src/modules/workspace/__tests__/workspace.routes.create-grant.test.ts +189 -37
  1209. package/src/modules/workspace/__tests__/workspace.routes.delete.test.ts +51 -11
  1210. package/src/modules/workspace/__tests__/workspace.routes.download-implies-read.test.ts +161 -0
  1211. package/src/modules/workspace/__tests__/workspace.routes.download.test.ts +109 -10
  1212. package/src/modules/workspace/__tests__/workspace.routes.file-writes.test.ts +624 -0
  1213. package/src/modules/workspace/__tests__/workspace.routes.folders.test.ts +409 -0
  1214. package/src/modules/workspace/__tests__/workspace.routes.move-platform-files.test.ts +327 -0
  1215. package/src/modules/workspace/__tests__/workspace.routes.read-gate.test.ts +31 -13
  1216. package/src/modules/workspace/__tests__/workspace.service.ensure-remotes-fetched.test.ts +109 -0
  1217. package/src/modules/workspace/__tests__/workspace.service.list-cloned.test.ts +94 -0
  1218. package/src/modules/workspace/__tests__/workspace.service.missing-branch.test.ts +28 -0
  1219. package/src/modules/workspace/__tests__/workspace.service.move-never-overwrites.test.ts +218 -0
  1220. package/src/modules/workspace/__tests__/workspace.service.read-filter.test.ts +98 -13
  1221. package/src/modules/workspace/__tests__/workspace.service.test.ts +811 -42
  1222. package/src/modules/workspace/__tests__/workspace.service.unknown-branch.test.ts +197 -0
  1223. package/src/modules/workspace/__tests__/workspace.tools.agents-file.test.ts +128 -0
  1224. package/src/modules/workspace/__tests__/workspace.tools.branch-errors.test.ts +212 -0
  1225. package/src/modules/workspace/__tests__/workspace.tools.test.ts +2632 -110
  1226. package/src/modules/workspace/__tests__/write-denial.test.ts +75 -0
  1227. package/src/modules/workspace/empty-dirs.ts +79 -0
  1228. package/src/modules/workspace/file-readers/README.md +32 -0
  1229. package/src/modules/workspace/file-readers/__tests__/doc-extract.test.ts +59 -2
  1230. package/src/modules/workspace/file-readers/__tests__/file-reader.registry.test.ts +133 -4
  1231. package/src/modules/workspace/file-readers/__tests__/fixtures/soft-break.docx +0 -0
  1232. package/src/modules/workspace/file-readers/__tests__/fixtures/tab.docx +0 -0
  1233. package/src/modules/workspace/file-readers/content-mode.ts +87 -0
  1234. package/src/modules/workspace/file-readers/doc-extract.service.ts +4 -1
  1235. package/src/modules/workspace/file-readers/doc-extract.types.ts +8 -4
  1236. package/src/modules/workspace/file-readers/document-reader.ts +6 -0
  1237. package/src/modules/workspace/file-readers/extract-docx.ts +6 -0
  1238. package/src/modules/workspace/file-readers/file-reader.registry.ts +9 -1
  1239. package/src/modules/workspace/file-readers/file-reader.ts +27 -6
  1240. package/src/modules/workspace/file-readers/image-reader.ts +10 -5
  1241. package/src/modules/workspace/file-readers/ooxml-text.ts +38 -2
  1242. package/src/modules/workspace/file-readers/text-reader.ts +61 -4
  1243. package/src/modules/workspace/git-internals.middleware.ts +86 -0
  1244. package/src/modules/workspace/not-found.ts +119 -0
  1245. package/src/modules/workspace/session-ontology.gate.ts +1 -1
  1246. package/src/modules/workspace/startup/__tests__/beside-checkout.test.ts +181 -0
  1247. package/src/modules/workspace/startup/__tests__/kb-startup-runner.degraded.test.ts +361 -0
  1248. package/src/modules/workspace/startup/__tests__/kb-startup-runner.test.ts +53 -16
  1249. package/src/modules/workspace/startup/beside-checkout.ts +112 -0
  1250. package/src/modules/workspace/startup/kb-git.ts +43 -36
  1251. package/src/modules/workspace/startup/kb-startup-runner.ts +303 -63
  1252. package/src/modules/workspace/startup/steps/__tests__/steps.test.ts +1405 -48
  1253. package/src/modules/workspace/startup/steps/groups-to-plugins.step.ts +460 -417
  1254. package/src/modules/workspace/startup/steps/personal-spaces.step.ts +191 -0
  1255. package/src/modules/workspace/startup/steps/plugin-display-names.step.ts +169 -0
  1256. package/src/modules/workspace/startup/steps/plugin-layout.ts +110 -0
  1257. package/src/modules/workspace/startup/steps/plugin-manifests.step.ts +90 -0
  1258. package/src/modules/workspace/startup/steps/roles-yaml.step.ts +6 -12
  1259. package/src/modules/workspace/startup/steps/seed-tree.ts +177 -54
  1260. package/src/modules/workspace/startup/steps/template-files.step.ts +581 -126
  1261. package/src/modules/workspace/startup/steps/template-source.ts +168 -0
  1262. package/src/modules/workspace/workspace.routes.ts +691 -269
  1263. package/src/modules/workspace/workspace.service.ts +1071 -292
  1264. package/src/modules/workspace/workspace.tools.ts +1787 -180
  1265. package/src/modules/workspace/write-denial.ts +189 -0
  1266. package/src/shared/__tests__/canonical-file-identity.test.ts +154 -0
  1267. package/src/shared/__tests__/email-identity.test.ts +35 -0
  1268. package/src/shared/__tests__/filename.test.ts +0 -0
  1269. package/src/shared/__tests__/frontmatter-id.test.ts +5 -0
  1270. package/src/shared/__tests__/git-failure.test.ts +198 -0
  1271. package/src/shared/__tests__/git-internals.test.ts +115 -0
  1272. package/src/shared/__tests__/http-errors.test.ts +42 -0
  1273. package/src/shared/__tests__/logging.test.ts +185 -0
  1274. package/src/shared/__tests__/path-containment.test.ts +60 -0
  1275. package/src/shared/__tests__/path-order.test.ts +24 -0
  1276. package/src/shared/__tests__/pending-proposals.readAt.test.ts +102 -0
  1277. package/src/shared/__tests__/printable.test.ts +64 -0
  1278. package/src/shared/__tests__/redact-secret.test.ts +122 -0
  1279. package/src/shared/__tests__/rename-no-replace.test.ts +466 -0
  1280. package/src/shared/__tests__/ssrf.test.ts +20 -0
  1281. package/src/shared/__tests__/ttl-cache.test.ts +55 -0
  1282. package/src/shared/canonical-file-identity.ts +92 -0
  1283. package/src/shared/domain-errors.ts +178 -0
  1284. package/src/shared/email-identity.ts +38 -0
  1285. package/src/shared/fs.contract.ts +225 -0
  1286. package/src/shared/git-failure.ts +196 -0
  1287. package/src/shared/git-internals.ts +124 -0
  1288. package/src/shared/git.contract.ts +170 -0
  1289. package/src/shared/http-errors.ts +36 -0
  1290. package/src/shared/logger.contract.ts +141 -0
  1291. package/src/shared/logging.ts +96 -0
  1292. package/src/shared/path-containment.ts +34 -0
  1293. package/src/shared/path-order.ts +33 -0
  1294. package/src/shared/pending-proposals.ts +161 -0
  1295. package/src/shared/printable.ts +68 -0
  1296. package/src/shared/redact-secret.ts +118 -0
  1297. package/src/shared/rename-no-replace.ts +386 -0
  1298. package/src/shared/ssrf.ts +44 -16
  1299. package/src/shared/ttl-cache.ts +33 -1
  1300. package/src/version.ts +10 -6
  1301. package/src/modules/diff/diff-paths.ts +0 -9
  1302. package/src/modules/mcp/__tests__/mcp-session-store.test.ts +0 -151
  1303. package/src/modules/mcp/__tests__/mcp.routes.session.test.ts +0 -226
  1304. package/src/modules/mcp/mcp-session-store.ts +0 -162
  1305. package/src/shared/__tests__/fs-walk.test.ts +0 -42
  1306. package/src/shared/fs-walk.ts +0 -30
  1307. package/src/shared/hash-email.ts +0 -14
@@ -1,30 +1,34 @@
1
- import { randomUUID } from 'node:crypto';
1
+ import { createHash } from 'node:crypto';
2
+ import { logger } from '../../shared/logging.js';
3
+ const log = logger('mcp');
2
4
  import { Server } from '@modelcontextprotocol/sdk/server/index.js';
3
- import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
4
- import { CallToolRequestSchema, ListToolsRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, McpError, ErrorCode, } from '@modelcontextprotocol/sdk/types.js';
5
+ import { CallToolRequestSchema, ListToolsRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, McpError, ErrorCode, isInitializeRequest, } from '@modelcontextprotocol/sdk/types.js';
5
6
  import '@utcp/http'; // side effect: registers the 'http' UTCP communication protocol
6
7
  import '@utcp/mcp'; // side effect: registers the 'mcp' protocol (native MCP-server `.tool` sources)
7
- import { UtcpClientConfigSerializer, CallTemplateSerializer, } from '@utcp/sdk';
8
+ import { UtcpClientConfigSerializer, CallTemplateSerializer, UtcpManualSchema, } from '@utcp/sdk';
8
9
  import { CodeModeUtcpClient } from '@utcp/code-mode';
9
- import { CODE_MODE_META_TOOLS, META_TOOL_NAMES, dispatchMetaTool, dispatchToolCall, registerManual, flattenManualTool, toListedTool, toolError, needsAuthorizationResult, skillPromptText, } from '@bevel-software/platform-mcp-core';
10
+ import { CODE_MODE_META_TOOLS, META_TOOL_NAMES, dispatchMetaTool, dispatchToolCall, registerManual, installSessionRecovery, flattenManualTool, toListedTool, toolError, retiredToolMessage, needsAuthorizationResult, skillPromptText, } from '@bevel-software/platform-mcp-core';
10
11
  import { bevelSecretsLoaderConfig } from '../secrets-vault/index.js';
11
- import { scopesCovered } from '../secrets-vault/secrets-vault.contract.js';
12
+ import { scopesCovered, } from '../secrets-vault/secrets-vault.contract.js';
12
13
  import { EXTERNAL_KB_MANUAL_NAME } from '../tool-manuals/tool-manuals.contract.js';
13
14
  import { seedBevelHostedManualVars } from '../../shared/utcp-namespace.js';
14
15
  import { ManualFailureMemo } from './manual-failure-memo.js';
16
+ import { DownstreamPool, POOL_KEY_SEPARATOR } from './downstream-pool.js';
17
+ import { SurfaceLogThrottle } from './surface-log-throttle.js';
18
+ import { DownstreamRefreshGuard, isDownstreamTokenRejection } from './downstream-token-refresh.js';
19
+ import { printable } from '../../shared/printable.js';
20
+ import { composeAgentInstructions, prefixToolDescription, PREFIXED_TOOLS, } from '../agent-instructions/index.js';
15
21
  /**
16
22
  * Upper bound on one `loopbackJson` round-trip (manual list, skill fetch) so a
17
- * hung loopback can't stall `createSession`. Generous: these endpoints answer
18
- * in milliseconds; only a wedged process ever comes near it.
23
+ * hung loopback can't stall a request. Generous: these endpoints answer in
24
+ * milliseconds; only a wedged process ever comes near it.
19
25
  */
20
26
  const LOOPBACK_TIMEOUT_MS = 15_000;
21
27
  /**
22
- * Lifetime of the internal token minted as an OAuth/JWT session's loopback
23
- * bearer. Longer than the session store's 4h idle eviction (see
24
- * `DEFAULT_IDLE_TTL_MS` in mcp-session-store.ts) so the credential is not the
25
- * first thing to die under a session's normal lifecycle. A continuously-active
26
- * session CAN outlive it — its tool calls then fail at the loopback and the
27
- * client recovers by re-initializing, which mints a fresh token.
28
+ * Lifetime of the internal token minted as an OAuth/JWT request's loopback
29
+ * bearer. A request only needs it for as long as it runs, but one `tools/call`
30
+ * can legitimately run for a long time (`ask`, a long `call_tool_chain`), so
31
+ * the lifetime is generous rather than tight.
28
32
  *
29
33
  * Exported because `POST /api/mcp/local-token` (mcp.routes.ts) performs the
30
34
  * same OAuth-access-token → internal-token exchange for the LOCAL MCP server,
@@ -33,133 +37,189 @@ const LOOPBACK_TIMEOUT_MS = 15_000;
33
37
  */
34
38
  export const MCP_LOOPBACK_TOKEN_TTL_MS = 5 * 60 * 60 * 1000;
35
39
  const callTemplateSerializer = new CallTemplateSerializer();
40
+ /** The {@link DownstreamRoute.afterFailure} answer that means "refreshed — retry once". */
41
+ const RETRY_WITH_REFRESHED_TOKEN = Symbol('retry-with-refreshed-token');
36
42
  /**
37
- * The MCP server is a GENERIC proxy over the UTCP tool surface. It owns no tool
38
- * logic: per MCP session it stands up a `UtcpClient` pointed at the backend's
39
- * own `GET /api/agent/utcp` manual (over loopback, authenticated with the
40
- * caller's connection key), discovers every tool, and re-exposes each one to
41
- * the MCP client. A tool call is dispatched straight back through the same REST
42
- * endpoint the tool's UTCP `tool_call_template` names — so the agent logic,
43
+ * The MCP server is a GENERIC, STATELESS proxy over the UTCP tool surface. It
44
+ * owns no tool logic and no session: every HTTP request gets its own MCP
45
+ * `Server`, built from that request's bearer. When the request needs tools it
46
+ * stands up a `UtcpClient` pointed at the backend's own `GET /api/agent/all-tools`
47
+ * catalog (over loopback, authenticated as the caller, so ACL filtering lives
48
+ * ONCE behind the REST surface), discovers every tool, and re-exposes each one
49
+ * to the MCP client. A tool call is dispatched straight back through the same
50
+ * REST endpoint the tool's UTCP `tool_call_template` names — so the agent logic,
43
51
  * thread continuity, and per-key token metering all live ONCE behind that REST
44
52
  * endpoint (`AgentAskService` for `ask`), never duplicated here.
45
53
  *
54
+ * Because nothing is held between requests, a platform restart between two
55
+ * requests of one client conversation is undetectable by the client.
56
+ *
57
+ * There is NO catalog cache at this layer, deliberately: the catalog is
58
+ * re-derived per request, and if that ever proves too slow the fix belongs in
59
+ * the source path (all-tools/ACL), which serves every other caller too.
60
+ *
61
+ * The one exception to "nothing between requests" is proxied third-party MCP
62
+ * servers (`mcp` manuals): those are session-ful by nature, so their
63
+ * connections live in a {@link DownstreamPool} keyed by (user, manual) — lazy,
64
+ * single-flight, idle-evicted, bounded, and healed by session recovery. Losing
65
+ * any of it costs a reconnect, never correctness.
66
+ *
46
67
  * Dispatch always uses `callToolStreaming`, which is uniform across tool kinds:
47
68
  * a plain `http` tool yields exactly one chunk (its final result, emitted as
48
69
  * the tool result with no progress), while a `streamable_http` tool yields many
49
- * (the all-but-last become `notifications/progress`, the last is the result).
50
- * Because of that, adding — or later upgrading a tool to streaming — never
51
- * touches this file.
70
+ * (the all-but-last become `notifications/progress` on the request's own
71
+ * response stream, the last is the result).
52
72
  *
53
73
  * Auth note: `/api/agent/*` accepts connection keys and internal tokens only.
54
- * Connection-key sessions pass the caller's own key through to the loopback;
55
- * OAuth/JWT sessions can't (their bearer would 401 there), so `createSession`
56
- * mints a least-privilege internal token for the resolved user and uses THAT
57
- * as the session's loopback bearer instead.
74
+ * Connection-key requests pass the caller's own key through to the loopback;
75
+ * OAuth/JWT requests can't (their bearer would 401 there), so the proxy mints a
76
+ * least-privilege internal token for the resolved user and uses THAT as the
77
+ * request's loopback bearer instead.
58
78
  */
59
79
  export class McpService {
60
- sessionStore;
61
80
  opts;
62
81
  secretsVault;
63
82
  toolManuals;
64
83
  internalTokens;
65
84
  revokeOAuthAccess;
66
85
  // Circuit breaker for manuals whose credentials just failed — see the memo.
86
+ // Retry policy, not session state: it survives the move to statelessness.
67
87
  manualFailures = new ManualFailureMemo();
88
+ surfaceLog = new SurfaceLogThrottle();
89
+ // One forced token refresh per (user, manual) per minute — see downstream-token-refresh.
90
+ tokenRefreshes;
68
91
  /**
69
- * Invalidate remembered manual failures — wired to the secrets vault's
70
- * mutation listener, so a just-repaired credential is retried on the very
71
- * next session build. `null` = a shared secret changed (affects everyone).
92
+ * The tools each pooled manual last advertised, by manual definition. A
93
+ * downstream can only be asked what its tools are over a connection, and a
94
+ * caller whose sign-in is missing or broken has no connection — so their
95
+ * tools would silently vanish from the surface, and a call would answer
96
+ * "Unknown tool" instead of "sign in again on /connect". These definitions
97
+ * keep the manual on the surface for such a caller; the call-time credential
98
+ * check then answers with the link, and an interactive client is sent back
99
+ * through authorization. Definitions, never credentials or results. Keyed
100
+ * by catalog name — one entry per manual, replaced when the manual is next
101
+ * discovered — and used only while the manual's definition is the one the
102
+ * tools were discovered from, so an edited `mcp.json` never serves the old
103
+ * server's tools.
72
104
  */
73
- clearManualFailures(userId) {
74
- if (userId === null)
75
- this.manualFailures.clearAll();
76
- else
77
- this.manualFailures.clearUser(userId);
78
- }
79
- constructor(sessionStore, opts,
105
+ knownDownstreamTools = new Map();
106
+ // The downstream connection pool for `mcp` manuals — see the class doc.
107
+ downstream;
108
+ constructor(opts,
80
109
  // The vault + manual catalog, used to check a caller's per-user credentials
81
110
  // before dispatching a tool. Optional so existing constructions/tests that
82
111
  // don't exercise the check keep working (the check is skipped when absent).
83
112
  secretsVault, toolManuals,
84
- // Mints the loopback bearer for OAuth/JWT sessions (see class doc).
85
- // Optional for the same test-compat reason; without it those sessions
113
+ // Mints the loopback bearer for OAuth/JWT requests (see class doc).
114
+ // Optional for the same test-compat reason; without it those requests
86
115
  // fall back to the old pass-through (and 401 at the loopback hop).
87
116
  internalTokens,
88
117
  // Revokes an MCP OAuth access token (BevelOAuthProvider.revokeByAccessToken)
89
- // — the reset that sends an interactive session back through the browser
118
+ // — the reset that sends an interactive client back through the browser
90
119
  // authorization when one of its TOOL sign-ins breaks. Optional: without
91
120
  // it, broken sign-ins surface only as the /connect link in the result.
92
121
  revokeOAuthAccess) {
93
- this.sessionStore = sessionStore;
94
122
  this.opts = opts;
95
123
  this.secretsVault = secretsVault;
96
124
  this.toolManuals = toolManuals;
97
125
  this.internalTokens = internalTokens;
98
126
  this.revokeOAuthAccess = revokeOAuthAccess;
127
+ this.downstream = new DownstreamPool({
128
+ ...opts.downstreamPool,
129
+ // Since @utcp/sdk 1.2.0 a client closes only the protocol instances it
130
+ // created, and @utcp/mcp registers as a factory — so this closes exactly
131
+ // this entry's MCP sessions and touches no other client's.
132
+ dispose: (entry) => entry.client.close(),
133
+ });
134
+ // Paced on the pool's clock, so a test that moves one moves both.
135
+ this.tokenRefreshes = new DownstreamRefreshGuard(undefined, opts.downstreamPool?.now);
99
136
  }
100
137
  /**
101
- * Subscribe to store-driven evictions (idle-TTL sweep, size-cap eviction) so
102
- * the route layer can drop its transport mirror. Returns an unsubscribe fn.
138
+ * A secret changed — wired to the secrets vault's mutation listener.
139
+ * `null` = a shared secret changed (affects everyone).
140
+ *
141
+ * Two things were built from the old value: remembered manual failures (so a
142
+ * just-repaired credential is retried on the very next request) and pooled
143
+ * downstream connections (dialed and discovered with the old credential).
144
+ * Both are dropped; the next request rebuilds whatever it needs.
103
145
  */
104
- onSessionEvicted(listener) {
105
- return this.sessionStore.onEvict(listener);
146
+ onSecretsChanged(userId) {
147
+ this.forgetStaleRefreshWindows(userId);
148
+ if (userId === null) {
149
+ this.manualFailures.clearAll();
150
+ this.downstream.closeAll();
151
+ return;
152
+ }
153
+ this.manualFailures.clearUser(userId);
154
+ this.downstream.evictWhere((key) => key.startsWith(`${userId}${POOL_KEY_SEPARATOR}`));
106
155
  }
107
156
  /**
108
- * Build a fresh per-session (transport, server) pair. Async because tool
109
- * discovery (a loopback round-trip authenticated with `bearer`) happens here,
110
- * before the server is returned, so `tools/list` is ready the moment the
111
- * client asks. The route awaits this, then `server.connect(transport)`.
157
+ * A credential changed, so a refresh window that FAILED to produce one no
158
+ * longer describes anything: a token the user has just re-authorized (or an
159
+ * admin has just re-keyed) must be tried on the very next rejection, not sit
160
+ * out the remainder of a minute earned by the credential it replaced.
161
+ *
162
+ * Only settled, non-`refreshed` windows are forgotten. A refresh of our own
163
+ * is itself a secrets mutation, and clearing on that would hand a provider
164
+ * that keeps minting tokens the downstream keeps refusing one refresh per
165
+ * call — precisely the loop the once-a-minute guard exists to bound. An
166
+ * in-flight attempt (no outcome yet) is left alone for the same reason: it
167
+ * may be the very refresh that raised this notification.
112
168
  */
113
- async createSession(userId, tokenId, bearer, onSessionInitialized) {
169
+ forgetStaleRefreshWindows(userId) {
170
+ const mine = (key) => userId === null || key.startsWith(`${userId}${POOL_KEY_SEPARATOR}`);
171
+ this.tokenRefreshes.clearWhere((key, outcome) => mine(key) && outcome !== undefined && outcome !== 'refreshed');
172
+ }
173
+ /**
174
+ * Build the MCP `Server` for ONE request. The route connects it to a fresh
175
+ * stateless transport, lets it answer, and closes both with the response.
176
+ *
177
+ * Cheap by construction: nothing is fetched up front except what the
178
+ * request's own messages need. The agent instructions are read only when the
179
+ * request carries an `initialize` (the only place they ride); the tool
180
+ * catalog is built on the first handler that needs it and shared by every
181
+ * message of the request (a JSON-RPC batch), never beyond it.
182
+ */
183
+ async createRequestServer(caller, messages) {
184
+ const { userId, tokenId, bearer } = caller;
114
185
  // The loopback surface (`/api/agent/*`) accepts connection keys and
115
- // internal tokens only. A connection-key session passes the caller's own
116
- // key through (per-key metering rides on it); an OAuth/JWT session's
186
+ // internal tokens only. A connection-key request passes the caller's own
187
+ // key through (per-key metering rides on it); an OAuth/JWT request's
117
188
  // bearer would 401 there, so mint a least-privilege internal token for
118
189
  // the resolved user instead — flagged `externalProxy` so the tool-auth
119
190
  // verifier resolves it to `source: 'external'`: the caller IS an external
120
191
  // agent and must be treated like one (admitted to `start_session`/`ask`,
121
- // refused from internal-only tools). TTL covers the session store's 4h
122
- // idle eviction — an evicted session re-initializes and re-mints.
192
+ // refused from internal-only tools).
123
193
  const loopbackBearer = tokenId == null && this.internalTokens
124
194
  ? this.internalTokens.mint({ userId, externalProxy: true }, MCP_LOOPBACK_TOKEN_TTL_MS)
125
195
  : bearer;
126
- // The list of manuals this caller gets: the KB manual + each `.tool` they
127
- // can read. Fetched over loopback with the caller's key, so ACL filtering
128
- // lives ONCE behind the REST surface.
129
- const manuals = await this.fetchManualTemplates(loopbackBearer);
130
- const client = await this.buildClient(loopbackBearer, userId, manuals);
131
- const tools = await this.discoverTools(client, manuals, userId);
132
- // Confirms the MCP session was built for a connecting client (vs. an
133
- // in-process agent code-mode client, which never runs createSession) and
134
- // how many tools discovery yielded before listing/filtering.
135
- console.log(`[mcp] createSession: user=${userId} tokenId=${tokenId ?? 'none'} — ` +
136
- `discovered ${tools.length} tool(s) across ${manuals.length} manual(s)`);
137
- const transport = new StreamableHTTPServerTransport({
138
- sessionIdGenerator: () => randomUUID(),
139
- onsessioninitialized: (sessionId) => {
140
- this.sessionStore.create(sessionId, userId, tokenId);
141
- onSessionInitialized(sessionId);
142
- },
143
- onsessionclosed: (sessionId) => {
144
- this.sessionStore.delete(sessionId);
145
- },
196
+ let instructions;
197
+ const agentInstructions = () => (instructions ??= this.composeAgentInstructions());
198
+ let surface;
199
+ const requestSurface = () => (surface ??= this.buildSurface(userId, tokenId, loopbackBearer));
200
+ const initializing = (Array.isArray(messages) ? messages : [messages]).some((m) => isInitializeRequest(m));
201
+ const server = new Server({ name: 'bevel-mcp', version: '0.1.0' }, {
202
+ capabilities: { tools: {}, prompts: {} },
203
+ // `instructions` rides the initialize result; clients that honour it
204
+ // place the text in the model's system prompt without the model acting.
205
+ ...(initializing ? { instructions: (await agentInstructions()).instructions } : {}),
146
206
  });
147
- const server = new Server({ name: 'bevel-mcp', version: '0.1.0' }, { capabilities: { tools: {}, prompts: {} } });
148
207
  server.setRequestHandler(ListToolsRequestSchema, async () => {
208
+ const [{ tools, catalogNames }, { toolPrefix }] = await Promise.all([requestSurface(), agentInstructions()]);
149
209
  // A discovered tool whose name collides with a meta-tool would be
150
210
  // listed but never callable (the dispatcher routes the name to the
151
211
  // meta-tool first), so drop it from the listing entirely.
152
212
  let listed = tools.filter((t) => !META_TOOL_NAMES.has(t.mcpName));
153
- // Connection-key sessions are autonomous pipelines — nobody is present
213
+ // Connection-key callers are autonomous pipelines — nobody is present
154
214
  // to complete a sign-in mid-run, so register ONLY the tools whose
155
215
  // per-user credentials are already satisfied. Interactive (OAuth/JWT)
156
- // sessions keep the full listing: their caller can configure a tool on
216
+ // callers keep the full listing: they can configure a tool on
157
217
  // /connect when the call-time check points them there.
158
218
  if (tokenId != null) {
159
219
  const ready = await Promise.all(
160
220
  // A per-tool check that throws must NOT reject the whole list (which
161
221
  // would blank every tool) — fail that one tool closed and move on.
162
- listed.map((t) => this.missingUserSecrets(userId, t).then((missing) => missing.length === 0, () => false)));
222
+ listed.map((t) => this.missingUserSecrets(userId, catalogNames.get(t.manualName) ?? t.manualName).then((missing) => missing.length === 0, () => false)));
163
223
  listed = listed.filter((_, i) => ready[i]);
164
224
  }
165
225
  // Validate + dedupe each discovered tool so ONE non-conforming or
@@ -180,14 +240,20 @@ export class McpService {
180
240
  continue;
181
241
  }
182
242
  seen.add(entry.name);
183
- direct.push(entry);
243
+ // The four knowledge-base tools carry the purpose prefix: the one
244
+ // pre-call channel every client shows the model, for the clients that
245
+ // drop the handshake's `instructions`. Applied AFTER the credential
246
+ // filter above, so a connection-key caller's listing carries it too.
247
+ // Every other tool, meta-tools included, keeps its description as is.
248
+ direct.push(PREFIXED_TOOLS.has(entry.name)
249
+ ? { ...entry, description: prefixToolDescription(toolPrefix, entry.description) }
250
+ : entry);
184
251
  }
185
252
  // Log only when a tool was dropped (name/schema/duplicate) — that's the
186
253
  // anomaly worth surfacing, since a downstream client would otherwise hide
187
- // it by rejecting the whole response. The steady-state served count is
188
- // already visible once per session in the createSession log above.
254
+ // it by rejecting the whole response.
189
255
  if (dropped.length) {
190
- console.warn(`[mcp] tools/list: serving ${CODE_MODE_META_TOOLS.length + direct.length} tool(s); ` +
256
+ log.warn(`tools/list: serving ${CODE_MODE_META_TOOLS.length + direct.length} tool(s); ` +
191
257
  `dropped ${dropped.length} non-listable: ${dropped.join(', ')}`);
192
258
  }
193
259
  return {
@@ -196,44 +262,66 @@ export class McpService {
196
262
  };
197
263
  });
198
264
  server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
199
- if (META_TOOL_NAMES.has(request.params.name)) {
200
- return this.dispatchMetaTool(client, request.params.name, request.params.arguments ?? {});
265
+ const { client, tools, unavailable, catalogNames } = await requestSurface();
266
+ const toolName = request.params.name;
267
+ if (META_TOOL_NAMES.has(toolName)) {
268
+ return this.dispatchMetaTool(client, toolName, request.params.arguments ?? {});
201
269
  }
202
- const proxied = tools.find((t) => t.mcpName === request.params.name);
203
- if (!proxied) {
204
- return toolError(`Unknown tool "${request.params.name}".`);
205
- }
206
- // Stop before running a tool whose personal (user-scoped) credentials the
207
- // caller hasn't provided — return a setup link instead of a blank-credential
208
- // request that would fail opaquely at the provider.
209
- const needsAuth = await this.checkUserSecrets(userId, proxied);
210
- if (needsAuth) {
270
+ /**
271
+ * The needs-authorization answer, when the caller's sign-in for the
272
+ * manual registered as `utcpName` is missing or broken; `null` to
273
+ * proceed. Stops before running a tool whose personal (user-scoped)
274
+ * credentials the caller hasn't provided — a setup link instead of a
275
+ * blank-credential request that would fail opaquely at the provider.
276
+ * The credential catalog keys manuals by their CATALOG name; a tool
277
+ * carries the registered (rewritten) one, so it is translated back.
278
+ */
279
+ const needsAuthorization = async (utcpName) => {
280
+ const needsAuth = await this.checkUserSecrets(userId, toolName, catalogNames.get(utcpName) ?? utcpName);
281
+ if (!needsAuth)
282
+ return null;
211
283
  // A sign-in that EXISTS but is broken (expired grant, abandoned
212
- // consent, missing scopes) on an interactive OAuth session: revoke the
284
+ // consent, missing scopes) on an interactive OAuth caller: revoke the
213
285
  // agent's own grant too. Its next request then 401s, its refresh
214
286
  // fails, and it re-runs the browser authorization — landing the user
215
287
  // on /connect where the broken sign-in shows as not-connected, to
216
288
  // re-authorize or deselect. Never-configured tools keep the plain
217
289
  // link (revoking for those would loop on every poke at a tool the
218
- // user simply hasn't set up). Connection-key sessions have no grant
290
+ // user simply hasn't set up). Connection-key callers have no grant
219
291
  // to reset; the revoke no-ops on non-OAuth bearers anyway.
220
292
  if (needsAuth.brokenSignIn && tokenId == null && this.revokeOAuthAccess) {
221
293
  try {
222
294
  await this.revokeOAuthAccess(bearer);
223
295
  }
224
296
  catch (err) {
225
- console.warn('[mcp] failed to reset the session grant for re-auth:', err);
297
+ log.warn('failed to reset the caller grant for re-auth:', { err });
226
298
  }
227
299
  }
228
300
  return needsAuth.result;
301
+ };
302
+ const proxied = tools.find((t) => t.mcpName === toolName);
303
+ if (!proxied) {
304
+ // Not on the surface — but if the name belongs to a manual that is off
305
+ // it only because this caller's sign-in is gone (and nothing in this
306
+ // process has seen its tools yet), the honest answer is the sign-in
307
+ // link, exactly as if the tool were listed. Longest matching prefix:
308
+ // manual names may themselves contain underscores.
309
+ const owner = unavailable
310
+ .filter((m) => toolName.startsWith(`${m.utcpName}_`))
311
+ .sort((a, b) => b.utcpName.length - a.utcpName.length)[0];
312
+ const answer = owner ? await needsAuthorization(owner.utcpName) : null;
313
+ return answer ?? toolError(retiredToolMessage(toolName) ?? `Unknown tool "${toolName}".`);
229
314
  }
315
+ const needsAuth = await needsAuthorization(proxied.manualName);
316
+ if (needsAuth)
317
+ return needsAuth;
230
318
  return this.dispatch(client, proxied, request, extra);
231
319
  });
232
320
  // Prompts = skills. Each skill becomes a user-callable prompt (slash command
233
321
  // in MCP clients). Backed by the same skill endpoints the tools use, over
234
322
  // loopback with the caller's key — so the default-branch catalog, access
235
323
  // filtering, and progressive disclosure all live ONCE behind that REST
236
- // surface, never duplicated here.
324
+ // surface, never duplicated here. Neither handler needs the tool catalog.
237
325
  server.setRequestHandler(ListPromptsRequestSchema, async () => {
238
326
  const skills = await this.fetchSkillList(loopbackBearer);
239
327
  const prompts = skills.map((s) => ({
@@ -253,7 +341,57 @@ export class McpService {
253
341
  messages: [{ role: 'user', content: { type: 'text', text: skillPromptText(skill) } }],
254
342
  };
255
343
  });
256
- return { transport, server };
344
+ return server;
345
+ }
346
+ /**
347
+ * The request's tool surface: catalog over loopback, a fresh UTCP client,
348
+ * every manual registered (pooled for `mcp` ones), tools flattened.
349
+ *
350
+ * Logs one line with the time each half took — the per-request overhead
351
+ * the stateless design trades for restart-invisibility, kept visible so it
352
+ * is measured rather than assumed.
353
+ */
354
+ async buildSurface(userId, tokenId, loopbackBearer) {
355
+ const started = performance.now();
356
+ // The list of manuals this caller gets: the KB manual + each `.tool` they
357
+ // can read. Fetched over loopback with the caller's key, so ACL filtering
358
+ // lives ONCE behind the REST surface.
359
+ const manuals = await this.fetchManualTemplates(loopbackBearer);
360
+ const catalogMs = performance.now() - started;
361
+ const client = await this.buildClient(loopbackBearer, userId, manuals);
362
+ const { tools, unavailable, catalogNames } = await this.discoverTools(client, manuals, userId);
363
+ const totalMs = performance.now() - started;
364
+ // Per user: on a shape change or once per interval, never per request —
365
+ // see SurfaceLogThrottle for why both halves matter.
366
+ const decision = this.surfaceLog.decide(userId, { tools: tools.length, manuals: manuals.length });
367
+ if (decision.log) {
368
+ log.info(
369
+ // Both ids come from the request (an identity provider's subject, a
370
+ // connection key's id), so neither is interpolated raw — see printable.
371
+ `request surface: user=${printable(userId)} tokenId=${tokenId ? printable(tokenId) : 'none'} — ` +
372
+ `${tools.length} tool(s) across ${manuals.length} manual(s) in ${totalMs.toFixed(0)}ms ` +
373
+ `(catalog ${catalogMs.toFixed(0)}ms, registration ${(totalMs - catalogMs).toFixed(0)}ms)` +
374
+ (decision.suppressed > 0 ? ` [+${decision.suppressed} identical rebuild(s) since last line]` : ''));
375
+ }
376
+ return { client, tools, unavailable, catalogNames };
377
+ }
378
+ /**
379
+ * The instructions and tool prefix. A reader failure (a disk fault; ENOENT
380
+ * is not one, the reader answers null for that) falls back to the header
381
+ * alone and the fixed prefix line with a logged warning: a request never
382
+ * fails over its preamble.
383
+ */
384
+ async composeAgentInstructions() {
385
+ const read = this.opts.readAgentPreamble;
386
+ if (!read)
387
+ return composeAgentInstructions(null);
388
+ try {
389
+ return composeAgentInstructions(await read());
390
+ }
391
+ catch (err) {
392
+ log.warn('could not read mcp-description.md; this request gets the platform header alone:', { err });
393
+ return composeAgentInstructions(null);
394
+ }
257
395
  }
258
396
  /** Loopback GET of the default-branch skill catalog (via the `list_skills` tool). */
259
397
  async fetchSkillList(bearer) {
@@ -272,10 +410,9 @@ export class McpService {
272
410
  * The ONE loopback round-trip: fetch `path` on our own REST surface with the
273
411
  * caller's bearer, parse JSON. Failures are logged under `label` (never the
274
412
  * bearer) and degrade to null — a loopback hiccup must not throw into the
275
- * MCP session. GET when `json` is absent, POST with a JSON body when present.
276
- * Bounded: a hung loopback (e.g. mid-restart) must not block `createSession`
277
- * or a prompts handler indefinitely; a timeout aborts and degrades to null
278
- * like any other failure.
413
+ * MCP request. GET when `json` is absent, POST with a JSON body when present.
414
+ * Bounded: a hung loopback (e.g. mid-restart) must not block a request
415
+ * indefinitely; a timeout aborts and degrades to null like any other failure.
279
416
  */
280
417
  async loopbackJson(bearer, path, label, json) {
281
418
  try {
@@ -288,13 +425,13 @@ export class McpService {
288
425
  signal: AbortSignal.timeout(LOOPBACK_TIMEOUT_MS),
289
426
  });
290
427
  if (!res.ok) {
291
- console.error(`[mcp] ${label} loopback failed: HTTP ${res.status} ${await res.text().catch(() => '')}`);
428
+ log.error(`${label} loopback failed: HTTP ${res.status} ${await res.text().catch(() => '')}`);
292
429
  return null;
293
430
  }
294
431
  return await res.json();
295
432
  }
296
433
  catch (err) {
297
- console.error(`[mcp] ${label} loopback threw:`, err instanceof Error ? err.message : err);
434
+ log.error(`${label} loopback threw:`, { err });
298
435
  return null;
299
436
  }
300
437
  }
@@ -307,7 +444,7 @@ export class McpService {
307
444
  * validated into `CallTemplate`s at the boundary. The KB manual is guaranteed
308
445
  * present (a fallback covers an unavailable endpoint); a user manual that
309
446
  * fails validation is dropped + logged so one bad `.tool` can't break the
310
- * session. HTTP transport loses the `CallTemplate` type, so we re-validate the
447
+ * request. HTTP transport loses the `CallTemplate` type, so we re-validate the
311
448
  * received JSON even though the producing endpoint already validated it.
312
449
  */
313
450
  async fetchManualTemplates(bearer) {
@@ -328,7 +465,7 @@ export class McpService {
328
465
  const name = String(raw?.name ?? '');
329
466
  if (isKb)
330
467
  throw err; // the KB manual must be valid — the core toolset depends on it
331
- console.warn(`[mcp] skipping manual "${name}": ${err instanceof Error ? err.message : String(err)}`);
468
+ log.warn(`skipping manual "${name}": ${err instanceof Error ? err.message : String(err)}`);
332
469
  }
333
470
  }
334
471
  // Always include the KB manual, even if `all-tools` was unavailable/regressed.
@@ -348,75 +485,360 @@ export class McpService {
348
485
  });
349
486
  }
350
487
  /**
351
- * One `CodeModeUtcpClient` per session. Reserved `API_URL`/`CONNECTION_KEY` are
488
+ * One `CodeModeUtcpClient` per request. Reserved `API_URL`/`CONNECTION_KEY` are
352
489
  * seeded (namespaced) ONLY for Bevel-hosted manuals — the KB manual and inline
353
490
  * `.tool` sub-manuals, whose discovery template targets the loopback (`${API_URL}`).
354
491
  * Third-party http/mcp `.tool`s point at arbitrary user URLs, so we must NOT seed
355
492
  * them the caller's bearer: a malicious `.tool` referencing `${CONNECTION_KEY}`
356
493
  * would otherwise exfiltrate the caller's token to its own endpoint. Tool
357
494
  * `${SECRET}` refs resolve lazily via the per-user `bevel-secrets` loader.
495
+ *
496
+ * Not `close()`d: a request's client holds no connection of its own (its
497
+ * `mcp` manuals route to the pool, so its own `mcp` protocol instance never
498
+ * opens a session), and dropping the reference is the whole teardown.
358
499
  */
359
500
  async buildClient(bearer, userId, manuals) {
360
- // Bevel-hosted manuals (KB + inline `.tool` sub-manuals, discovery url
361
- // `${API_URL}/…`) get the loopback creds; third-party `.tool` URLs are never
362
- // seeded so the bearer can't leak. Same rule the in-process agent factory uses.
363
501
  const variables = seedBevelHostedManualVars(manuals, this.opts.loopbackBaseUrl, bearer);
364
- const config = new UtcpClientConfigSerializer().validateDict({
365
- variables,
366
- load_variables_from: [bevelSecretsLoaderConfig(userId)],
367
- });
368
- return CodeModeUtcpClient.create(process.cwd(), config);
502
+ return CodeModeUtcpClient.create(process.cwd(), utcpClientConfig(userId, variables));
369
503
  }
370
504
  /**
371
- * Register EVERY manual on the client, then flatten each discovered tool into
372
- * the proxy's advertised shape. A failure registering a user `.tool` is
373
- * isolated (logged + skipped) so one broken manual never breaks the session;
374
- * the KB manual failing is fatal (the core toolset is unusable).
505
+ * Register EVERY manual for this request, then flatten each discovered tool
506
+ * into the proxy's advertised shape. Manuals register concurrently — they are
507
+ * independent, and a request pays for the slowest one rather than the sum. A
508
+ * failure registering a user `.tool` is isolated (logged + skipped) so one
509
+ * broken manual never breaks the request; the KB manual failing is fatal (the
510
+ * core toolset is unusable).
375
511
  *
376
- * Failures are memoized per (user, manual) for a few minutes (see
377
- * {@link ManualFailureMemo}): sessions rebuild constantly, and a manual with
378
- * a broken credential (expired OAuth, revoked key) would otherwise re-dial
379
- * its provider on every single build.
512
+ * `mcp` manuals never dial from here: they are attached from the downstream
513
+ * pool (see {@link attachDownstream}).
514
+ *
515
+ * Failures are memoized per (user, manual definition) for a few minutes (see
516
+ * {@link ManualFailureMemo}): the catalog is rebuilt on every request, and a
517
+ * manual with a broken credential (expired OAuth, revoked key) would
518
+ * otherwise re-dial its provider on every single one. The definition's
519
+ * fingerprint is part of the key, so a manual edited after a failure (a
520
+ * corrected `mcp.json` URL) is tried on the very next request.
380
521
  */
381
522
  async discoverTools(client, manuals, userId) {
523
+ const routes = new Map();
524
+ const unavailable = [];
525
+ const catalogNames = new Map();
526
+ for (const m of manuals) {
527
+ if (m.call_template_type === 'mcp')
528
+ catalogNames.set(utcpManualName(m), String(m.name));
529
+ }
530
+ // The shared layer rewrites every manual name (`[^\w]` → `_`) and tools
531
+ // route by the rewritten prefix, so two manuals whose names rewrite to one
532
+ // identifier would silently share it. Sequential registration used to
533
+ // throw "already registered" for the second; concurrent registration
534
+ // (below) would let both pass the shared layer's pre-check, one
535
+ // overwriting the other in the repository while `routes` kept whichever
536
+ // resolved last — tools/list from one server, tools/call to the other.
537
+ // Decided here, over the whole list, before anything is registered: every
538
+ // manual in a colliding group fails with a message naming the others. The
539
+ // KB manual always keeps its name — a `.tool` colliding with it fails,
540
+ // the KB manual does not.
541
+ const byRewrittenName = new Map();
382
542
  for (const m of manuals) {
543
+ const rewritten = utcpManualName(m);
544
+ byRewrittenName.set(rewritten, [...(byRewrittenName.get(rewritten) ?? []), String(m.name)]);
545
+ }
546
+ const outcomes = await Promise.all(manuals.map(async (m) => {
383
547
  const isKb = m.name === EXTERNAL_KB_MANUAL_NAME;
384
548
  const name = String(m.name);
549
+ // Both taken before registration, which renames the template in place.
550
+ const rewritten = utcpManualName(m);
551
+ const siblings = (byRewrittenName.get(rewritten) ?? []).filter((s) => s !== name);
552
+ // A collision is a property of the LIST, not of this manual's
553
+ // definition, so the memo key carries the siblings: the moment one is
554
+ // renamed away, the key changes and the survivor is tried on the very
555
+ // next request instead of sitting out the memo's TTL.
556
+ const memoKey = `${name}${POOL_KEY_SEPARATOR}${templateFingerprint(m)}` +
557
+ (siblings.length > 0 ? `${POOL_KEY_SEPARATOR}collides:${[...siblings].sort().join(',')}` : '');
385
558
  if (!isKb) {
386
- const recent = this.manualFailures.recentFailure(userId, name);
559
+ const recent = this.manualFailures.recentFailure(userId, memoKey);
387
560
  if (recent !== undefined) {
388
- console.warn(`[mcp] skipping manual "${name}" (recent failure, not retried): ${recent}`);
389
- continue;
561
+ log.warn(`skipping manual "${name}" (recent failure, not retried): ${recent}`);
562
+ return { isKb, ok: true };
390
563
  }
391
564
  }
392
- // Captured BEFORE the awaited attempt: if a secrets change clears the
393
- // memo while registration is in flight, the stale failure from the OLD
394
- // credential must not resurrect an entry the clear removed.
395
- const generation = this.manualFailures.currentGeneration;
396
- // `registerManual` never throws: a discovery/network failure and a
397
- // validation failure both come back as `{ ok: false }`, because the retry
398
- // policy — this memo — is ours, not the shared layer's.
399
- const result = await registerManual(client, m);
400
- if (!result.ok) {
401
- if (isKb)
402
- throw new Error(`Bevel tool discovery failed: ${result.error}`);
403
- this.manualFailures.recordFailure(userId, name, result.error, generation);
404
- console.warn(`[mcp] skipping manual "${name}": ${result.error}`);
565
+ // Begun BEFORE the awaited attempt: if a secrets change (or a
566
+ // concurrent success of this same manual) clears the memo while
567
+ // registration is in flight, the stale failure must not resurrect an
568
+ // entry the clear removed.
569
+ const generation = this.manualFailures.beginAttempt();
570
+ try {
571
+ // Neither path throws: a discovery/network failure and a validation
572
+ // failure both come back as `{ ok: false }`, because the retry
573
+ // policy — this memo — is ours, not the shared layer's.
574
+ const result = !isKb && siblings.length > 0
575
+ ? {
576
+ ok: false,
577
+ error: `manual name "${name}" rewrites to "${rewritten}", the same identifier as ` +
578
+ `${siblings.map((s) => `"${s}"`).join(', ')} — rename one; a colliding manual is not registered`,
579
+ }
580
+ : m.call_template_type === 'mcp'
581
+ ? await this.attachDownstream(client, m, userId, routes)
582
+ : await registerManual(client, m);
583
+ if (!result.ok) {
584
+ if (isKb)
585
+ return { isKb, ok: false, error: result.error };
586
+ // A failure the manual may recover from on its own schedule (a
587
+ // token refresh that hasn't settled) is reported but NOT
588
+ // remembered: the memo's five minutes would outlast the refresh
589
+ // policy's one and hold the manual down after the provider is back.
590
+ if (!result.retryable)
591
+ this.manualFailures.recordFailure(userId, memoKey, result.error, generation);
592
+ if (result.signInMissing)
593
+ unavailable.push({ utcpName: rewritten });
594
+ log.warn(`skipping manual "${name}": ${result.error}`);
595
+ }
596
+ else if (!isKb) {
597
+ this.manualFailures.clear(userId, memoKey);
598
+ }
405
599
  }
406
- else if (!isKb) {
407
- this.manualFailures.clear(userId, name);
600
+ finally {
601
+ this.manualFailures.endAttempt(generation);
408
602
  }
409
- }
603
+ return { isKb, ok: true };
604
+ }));
605
+ const kbFailure = outcomes.find((o) => o.isKb && !o.ok);
606
+ if (kbFailure && !kbFailure.ok)
607
+ throw new Error(`Bevel tool discovery failed: ${kbFailure.error}`);
608
+ if (routes.size > 0)
609
+ routeToDownstream(client, routes);
410
610
  const utcpTools = await client.getTools();
411
- return utcpTools.map((tool) => flattenManualTool(tool, EXTERNAL_KB_MANUAL_NAME));
611
+ return {
612
+ tools: utcpTools.map((tool) => flattenManualTool(tool, EXTERNAL_KB_MANUAL_NAME)),
613
+ unavailable,
614
+ catalogNames,
615
+ };
412
616
  }
413
617
  /**
414
- * Run one tool call through `callToolStreaming` with a one-chunk lookahead:
415
- * every chunk except the last becomes a progress notification, the last is
416
- * the result. Continuity is the caller's: a tool that supports it (e.g.
417
- * `ask`) returns its `sessionId` in the result verbatim, and the caller
418
- * echoes it back per the tool's own schema — the proxy never rewrites args.
618
+ * Make one `mcp` manual's tools part of this request's client, backed by the
619
+ * pooled connection for (user, manual).
620
+ *
621
+ * The pooled client's discovered tools are copied into the request client's
622
+ * repository — so `tools/list`, `list_tools`/`tools_info` and the TypeScript
623
+ * interfaces `call_tool_chain` generates all see them exactly as if they had
624
+ * been registered here — and `routes` records that calls to this manual go to
625
+ * the pool. The route re-acquires at CALL time rather than holding the pooled
626
+ * client, so an entry evicted between discovery and the call is transparently
627
+ * re-created instead of used after its connection was closed. Each use holds
628
+ * a pool lease only for its own duration, so the pool never closes a
629
+ * connection an operation is still using.
419
630
  */
631
+ async attachDownstream(client, template, userId, routes) {
632
+ const key = downstreamPoolKey(userId, template);
633
+ // The catalog name, which is what the manual's per-user variables are keyed by.
634
+ const catalogName = String(template.name ?? '');
635
+ const manualName = utcpManualName(template);
636
+ const definition = templateFingerprint(template);
637
+ const acquire = () => this.downstream.acquire(key, () => this.connectDownstream(userId, template));
638
+ const afterFailure = (err) => this.afterDownstreamFailure(userId, catalogName, key, err);
639
+ const attach = async (tools) => {
640
+ await client.config.tool_repository.saveManual({ ...template, name: manualName }, UtcpManualSchema.parse({ tools }));
641
+ routes.set(manualName, { acquire, afterFailure });
642
+ };
643
+ // Set when the handshake failed on a credential the provider may yet
644
+ // renew: the caller must NOT remember that as a dead manual (see below).
645
+ let credentialTransient = false;
646
+ try {
647
+ let lease;
648
+ try {
649
+ lease = await acquire();
650
+ }
651
+ catch (err) {
652
+ // A connection dialed with a token the server refuses fails right here,
653
+ // at the handshake — the same refresh-and-retry applies.
654
+ const verdict = await this.classifyDownstreamFailure(userId, catalogName, key, err);
655
+ if (!verdict.retry) {
656
+ credentialTransient = verdict.credentialTransient;
657
+ throw verdict.error;
658
+ }
659
+ lease = await acquire();
660
+ }
661
+ let tools;
662
+ try {
663
+ tools = (await lease.value.client.getTools()).filter((t) => t.name.startsWith(`${manualName}.`));
664
+ }
665
+ finally {
666
+ lease.release();
667
+ }
668
+ this.knownDownstreamTools.set(catalogName, { definition, tools });
669
+ await attach(tools);
670
+ return { ok: true };
671
+ }
672
+ catch (err) {
673
+ const error = err instanceof Error ? err.message : String(err);
674
+ // No connection because this CALLER has no usable sign-in for the manual
675
+ // (never signed in, or the grant was just found dead and wiped): the
676
+ // manual is not broken, the sign-in is. Keep its tools on the surface
677
+ // from what the downstream last advertised, so a call answers with the
678
+ // sign-in link — and never remember the failure, since re-authorizing is
679
+ // one visit to /connect away and the next attempt costs no network.
680
+ if (await this.signInMissing(userId, catalogName)) {
681
+ const known = this.knownDownstreamTools.get(catalogName);
682
+ if (known && known.definition === definition) {
683
+ await attach(known.tools);
684
+ return { ok: true };
685
+ }
686
+ return { ok: false, error, retryable: true, signInMissing: true };
687
+ }
688
+ // `retryable` keeps a transient credential failure out of the caller's
689
+ // five-minute failure memo: the refresh-and-retry policy for a rejected
690
+ // token is one minute, and a memo entry would silently outlast it.
691
+ return { ok: false, error, retryable: credentialTransient };
692
+ }
693
+ }
694
+ /** Whether the caller's sign-in for the manual named `catalogName` is missing or broken — a check that must never throw here. */
695
+ async signInMissing(userId, catalogName) {
696
+ try {
697
+ return (await this.missingUserSecrets(userId, catalogName)).length > 0;
698
+ }
699
+ catch {
700
+ return false;
701
+ }
702
+ }
703
+ /**
704
+ * Create one pooled downstream connection: a client registering just this
705
+ * manual.
706
+ *
707
+ * `@utcp/mcp` (1.2.0+) registers its protocol as a FACTORY, so this client
708
+ * gets an `mcp` protocol instance of its own: the session it opens lives in
709
+ * that instance, is reachable from no other client, and ends with
710
+ * `client.close()`. That is what makes a pool entry per (user, server) an
711
+ * actual isolation boundary — two users with byte-identical server
712
+ * definitions still never share a connection — with nothing reached into.
713
+ *
714
+ * SESSION RECOVERY is installed on the pooled client: a downstream server
715
+ * that restarts (or expires a session) answers our next call with the spec's
716
+ * 404/`-32001`, and recovery re-registers in place and retries once. It is
717
+ * deliberately clear of {@link ManualFailureMemo}: that memo is a circuit
718
+ * breaker for manuals whose REGISTRATION failed, so a recovery neither
719
+ * consults it nor records into it.
720
+ *
721
+ * A registration that fails closes the client it built (ending whatever the
722
+ * attempt opened) and throws, so the pool caches nothing and the caller's
723
+ * memo records the failure.
724
+ */
725
+ async connectDownstream(userId, template) {
726
+ // Third-party manuals are never seeded loopback credentials (see
727
+ // `buildClient`), so a pooled client carries no request-scoped bearer.
728
+ const client = await CodeModeUtcpClient.create(process.cwd(), utcpClientConfig(userId, {}));
729
+ // Our own copy: registration renames the template in place, and recovery
730
+ // re-registers from exactly what discovery used.
731
+ const own = structuredClone(template);
732
+ const manualName = utcpManualName(own);
733
+ installSessionRecovery(client, { manualTemplate: (name) => (name === manualName ? own : undefined) });
734
+ const result = await registerManual(client, own);
735
+ if (!result.ok) {
736
+ await client.close().catch(() => { });
737
+ throw new Error(result.error);
738
+ }
739
+ return { client };
740
+ }
741
+ /**
742
+ * A pooled manual's operation failed: may it be retried with a refreshed
743
+ * token? Answers {@link RETRY_WITH_REFRESHED_TOKEN} when so, otherwise the
744
+ * error the caller should see.
745
+ *
746
+ * Only a token rejection (401 / `invalid_token`) qualifies. Then the
747
+ * caller's OAuth token for this manual is refreshed once, ignoring its
748
+ * stored expiry, and:
749
+ * - refreshed → the pooled connection (dialed with the dead token) is
750
+ * dropped and the operation retried once, on a fresh one;
751
+ * - rejected → the grant is gone and the vault has wiped it; the caller is
752
+ * told to re-authorize on /connect, where it now shows as not connected;
753
+ * - transient, or no refresh allowed / possible → the original error.
754
+ */
755
+ async afterDownstreamFailure(userId, manualName, poolKey, err) {
756
+ const verdict = await this.classifyDownstreamFailure(userId, manualName, poolKey, err);
757
+ return verdict.retry ? RETRY_WITH_REFRESHED_TOKEN : verdict.error;
758
+ }
759
+ /** {@link afterDownstreamFailure}, keeping the one distinction its symbol-or-error answer drops. */
760
+ async classifyDownstreamFailure(userId, manualName, poolKey, err) {
761
+ if (!isDownstreamTokenRejection(err))
762
+ return { retry: false, error: err, credentialTransient: false };
763
+ const outcome = await this.refreshDownstreamToken(userId, manualName);
764
+ if (outcome === 'refreshed') {
765
+ // The vault's mutation signal evicts this user's connections too; doing it
766
+ // here as well keeps the retry correct whether or not that is wired.
767
+ this.downstream.evictWhere((k) => k === poolKey);
768
+ return { retry: true };
769
+ }
770
+ if (outcome === 'rejected') {
771
+ // The connection was dialed with a grant that no longer exists; the
772
+ // vault's mutation signal drops it too, this keeps the next request
773
+ // honest whether or not that is wired.
774
+ this.downstream.evictWhere((k) => k === poolKey);
775
+ return {
776
+ retry: false,
777
+ credentialTransient: false,
778
+ error: new Error(`Your sign-in for "${manualName}" was rejected and has been disconnected. ` +
779
+ `Re-authorize it on ${this.opts.publicFrontendUrl}/connect, then run the tool again.`),
780
+ };
781
+ }
782
+ // The token stands and so does the call's own error. Whether the NEXT
783
+ // call may try again depends on why: a refresh that failed transiently, or
784
+ // one the window refused, will be worth attempting shortly — while
785
+ // "nothing here to refresh" (no vault, no OAuth variable, no stored token)
786
+ // is a standing condition, and the failure memo should hold the manual
787
+ // down exactly as it does for any other broken credential.
788
+ const mayRecoverSoon = outcome === 'transient' || outcome === 'guarded';
789
+ return { retry: false, error: err, credentialTransient: mayRecoverSoon };
790
+ }
791
+ /**
792
+ * Force-refresh the caller's OAuth token(s) for `manualName`, at most once per
793
+ * (user, manual) per minute. Logs ONE line per attempt — manual, user,
794
+ * outcome, never token material.
795
+ *
796
+ * `'guarded'` when the window refused this one (a refresh just ran, or is
797
+ * running, for this pair); `undefined` when there was nothing to refresh at
798
+ * all: no vault wired, or no OAuth variable on the manual. The two are not
799
+ * the same thing to the caller — see {@link classifyDownstreamFailure}.
800
+ */
801
+ async refreshDownstreamToken(userId, manualName) {
802
+ const vault = this.secretsVault;
803
+ if (!vault || !this.toolManuals || !manualName)
804
+ return undefined;
805
+ let keys;
806
+ try {
807
+ keys = (await this.toolManuals.userScopedKeysForManual(manualName)).filter((v) => v.oauth).map((v) => v.key);
808
+ }
809
+ catch (err) {
810
+ // The error's own message is caller-controlled as well (it quotes the
811
+ // manual, and may quote a provider's reply), and a raw Error handed to
812
+ // the logger renders its message and stack verbatim — so it goes through
813
+ // the same escaper rather than travelling as an object.
814
+ log.warn(`downstream token refresh: could not read the variables of manual=${printable(manualName)}: ` +
815
+ printable(err instanceof Error ? err.message : String(err)));
816
+ return undefined;
817
+ }
818
+ if (keys.length === 0)
819
+ return undefined;
820
+ const attempt = this.tokenRefreshes.run(`${userId}${POOL_KEY_SEPARATOR}${manualName}`, async () => {
821
+ const outcomes = [];
822
+ for (const key of keys) {
823
+ // A vault fault is not a verdict on the grant: keep the token, try later.
824
+ outcomes.push(await vault.forceRefresh(userId, key).catch(() => 'transient'));
825
+ }
826
+ const outcome = outcomes.includes('rejected')
827
+ ? 'rejected'
828
+ : outcomes.includes('transient')
829
+ ? 'transient'
830
+ : outcomes.includes('refreshed')
831
+ ? 'refreshed'
832
+ : 'skipped';
833
+ if (outcome !== 'skipped') {
834
+ // Both values reach the log from outside (a catalog name, an identity
835
+ // provider's id), so both are escaped: one event stays one line.
836
+ log.info(`downstream token refresh: manual=${printable(manualName)} user=${printable(userId)} outcome=${outcome}`);
837
+ }
838
+ return outcome;
839
+ });
840
+ return attempt ? await attempt : 'guarded';
841
+ }
420
842
  /**
421
843
  * If the tool declares per-user credentials the caller hasn't set, return a
422
844
  * needs-authorization result (naming the tool + a setup link); otherwise null
@@ -426,15 +848,15 @@ export class McpService {
426
848
  * services aren't wired, or the tool's manual declares no per-user credential
427
849
  * (e.g. the built-in KB tools).
428
850
  */
429
- async checkUserSecrets(userId, tool) {
430
- const missing = await this.missingUserSecrets(userId, tool);
851
+ async checkUserSecrets(userId, toolName, manualName) {
852
+ const missing = await this.missingUserSecrets(userId, manualName);
431
853
  if (missing.length === 0)
432
854
  return null;
433
855
  return {
434
- result: needsAuthorizationResult(tool.mcpName, missing.map((v) => v.label ?? v.name), `${this.opts.publicFrontendUrl}/connect`),
856
+ result: needsAuthorizationResult(toolName, missing.map((v) => v.label ?? v.name), `${this.opts.publicFrontendUrl}/connect`),
435
857
  // At least one missing item is a sign-in the caller already HAS a row
436
858
  // for (dead grant, abandoned consent, or missing scopes) — the state
437
- // that warrants resetting an interactive session for re-auth, as
859
+ // that warrants resetting an interactive client for re-auth, as
438
860
  // opposed to a tool the caller never set up at all.
439
861
  brokenSignIn: missing.some((v) => v.brokenSignIn),
440
862
  };
@@ -442,14 +864,14 @@ export class McpService {
442
864
  /**
443
865
  * The per-user variables of `tool`'s manual the caller has NOT satisfied.
444
866
  * Shared by the call-time needs-authorization check above and the
445
- * listing-time filter for connection-key sessions (which registers only
867
+ * listing-time filter for connection-key callers (which registers only
446
868
  * ready tools). Empty when the vault/manual services aren't wired or the
447
869
  * manual declares no per-user credential.
448
870
  */
449
- async missingUserSecrets(userId, tool) {
450
- if (!this.secretsVault || !this.toolManuals || !tool.manualName)
871
+ async missingUserSecrets(userId, manualName) {
872
+ if (!this.secretsVault || !this.toolManuals || !manualName)
451
873
  return [];
452
- const userVars = await this.toolManuals.userScopedKeysForManual(tool.manualName);
874
+ const userVars = await this.toolManuals.userScopedKeysForManual(manualName);
453
875
  if (userVars.length === 0)
454
876
  return [];
455
877
  const status = await this.secretsVault.statusFor(userId, userVars.map((v) => v.key));
@@ -464,6 +886,17 @@ export class McpService {
464
886
  missing.push({ name: v.name, label: v.label, brokenSignIn }); // no row at all → needs a value / sign-in
465
887
  continue;
466
888
  }
889
+ // A row of the OTHER kind is not this credential: a `.tool` edited from
890
+ // an OAuth sign-in to a plain key (or back) leaves the old row behind,
891
+ // and serving a token where a key is declared — or a key where a
892
+ // sign-in is — fails opaquely at the provider. Not a broken sign-in
893
+ // either: nothing to reset, the user has to set the credential up as
894
+ // the manual now declares it.
895
+ const declaredKind = v.oauth ? 'oauth' : 'static';
896
+ if (st.userKind && st.userKind !== declaredKind) {
897
+ missing.push({ name: v.name, label: v.label, brokenSignIn: false });
898
+ continue;
899
+ }
467
900
  // An OAuth-backed var whose row exists but has no token yet is NOT ready —
468
901
  // the user has registered but not completed sign-in. Fail closed: anything
469
902
  // other than a confirmed `true` (including a non-oauth row → undefined)
@@ -483,6 +916,14 @@ export class McpService {
483
916
  }
484
917
  return missing;
485
918
  }
919
+ /**
920
+ * Run one tool call through `callToolStreaming` with a one-chunk lookahead:
921
+ * every chunk except the last becomes a progress notification — sent on THIS
922
+ * request's own response stream — and the last is the result. Continuity is
923
+ * the caller's: a tool that supports it (e.g. `ask`) returns its `sessionId`
924
+ * in the result verbatim, and the caller echoes it back per the tool's own
925
+ * schema — the proxy never rewrites args.
926
+ */
486
927
  async dispatch(client, tool, request,
487
928
  // `sendNotification` typed loosely (`any`) so a `notifications/progress`
488
929
  // payload without a `progressToken` is accepted — same approach the prior
@@ -500,8 +941,8 @@ export class McpService {
500
941
  }
501
942
  /**
502
943
  * Handle a code-mode meta-tool. The shared implementation reflects on this
503
- * session's client, so `list_tools`/`tools_info` describe exactly the catalog
504
- * this session discovered and `call_tool_chain` runs in that client's
944
+ * request's client, so `list_tools`/`tools_info` describe exactly the catalog
945
+ * this request discovered and `call_tool_chain` runs in that client's
505
946
  * isolated-vm — resolving over loopback with the caller's key. The workspace
506
947
  * spill store is passed in so an oversized chain result comes back as a
507
948
  * `read_file`-able ref rather than a wall of JSON.
@@ -510,6 +951,119 @@ export class McpService {
510
951
  return dispatchMetaTool(client, name, args, this.opts.spillStore);
511
952
  }
512
953
  }
954
+ /**
955
+ * The UTCP client config for `userId`: the given variables, plus the per-user
956
+ * `bevel-secrets` loader that resolves every `${SECRET}` ref lazily. Shared by
957
+ * request clients and pooled downstream clients, so both resolve a manual's
958
+ * variables through exactly the same tiers.
959
+ */
960
+ function utcpClientConfig(userId, variables) {
961
+ return new UtcpClientConfigSerializer().validateDict({
962
+ variables,
963
+ load_variables_from: [bevelSecretsLoaderConfig(userId)],
964
+ });
965
+ }
966
+ /**
967
+ * The name a manual is registered under. `UtcpClient.registerManual` rewrites
968
+ * every non-word character to `_`, and tool names are prefixed with the result,
969
+ * so routing has to key on the same rewrite.
970
+ */
971
+ function utcpManualName(template) {
972
+ return String(template.name ?? '').replace(/[^\w]/g, '_');
973
+ }
974
+ /**
975
+ * The pool key for (user, manual). The template's fingerprint is part of it, so
976
+ * an edited `mcp.json` (new URL, new headers) gets a new connection rather than
977
+ * the one dialed for the old definition, which simply idles out. Hashed: the
978
+ * template can carry credentials and the key must stay log-safe.
979
+ */
980
+ function downstreamPoolKey(userId, template) {
981
+ return [userId, utcpManualName(template), templateFingerprint(template)].join(POOL_KEY_SEPARATOR);
982
+ }
983
+ /** A short, log-safe hash of a manual's whole definition: changes whenever the definition does. */
984
+ function templateFingerprint(template) {
985
+ return createHash('sha256').update(JSON.stringify(template)).digest('hex').slice(0, 16);
986
+ }
987
+ /**
988
+ * Route tool calls for pooled manuals to their pooled client, in place on the
989
+ * request client. Both entry points are wrapped — `callToolStreaming` is the
990
+ * MCP dispatch path, `callTool` is what `call_tool_chain` bridges every
991
+ * in-isolate tool function to — so the two can never disagree. Every other
992
+ * manual's calls go through the request client unchanged.
993
+ *
994
+ * Each routed call holds its pool lease until the call ends — for a stream,
995
+ * until the consumer finishes or abandons it (`for await` returns the
996
+ * generator, which runs the `finally`).
997
+ *
998
+ * A call the downstream refuses for its token (401 / `invalid_token`) goes to
999
+ * the route's `afterFailure`, which may refresh the token and ask for ONE retry
1000
+ * on a fresh connection. Retrying is safe for the same reason session recovery
1001
+ * is: authentication is decided before the request reaches a tool, so the
1002
+ * refused attempt ran nothing.
1003
+ */
1004
+ function routeToDownstream(client, routes) {
1005
+ const callTool = client.callTool.bind(client);
1006
+ const callToolStreaming = client.callToolStreaming.bind(client);
1007
+ const routeOf = (toolName) => routes.get(toolName.split('.')[0] ?? '');
1008
+ client.callTool = async function routedCallTool(toolName, toolArgs) {
1009
+ const route = routeOf(toolName);
1010
+ if (!route)
1011
+ return callTool(toolName, toolArgs);
1012
+ const once = async () => {
1013
+ const lease = await route.acquire();
1014
+ try {
1015
+ return await lease.value.client.callTool(toolName, toolArgs);
1016
+ }
1017
+ finally {
1018
+ lease.release();
1019
+ }
1020
+ };
1021
+ try {
1022
+ return await once();
1023
+ }
1024
+ catch (err) {
1025
+ const next = await route.afterFailure(err);
1026
+ if (next !== RETRY_WITH_REFRESHED_TOKEN)
1027
+ throw next;
1028
+ // Exactly one retry: whatever it produces is what the caller sees.
1029
+ return await once();
1030
+ }
1031
+ };
1032
+ client.callToolStreaming = async function* routedCallToolStreaming(toolName, toolArgs) {
1033
+ const route = routeOf(toolName);
1034
+ if (!route) {
1035
+ yield* callToolStreaming(toolName, toolArgs);
1036
+ return;
1037
+ }
1038
+ const once = async function* () {
1039
+ const lease = await route.acquire();
1040
+ try {
1041
+ yield* lease.value.client.callToolStreaming(toolName, toolArgs);
1042
+ }
1043
+ finally {
1044
+ lease.release();
1045
+ }
1046
+ };
1047
+ let yielded = false;
1048
+ try {
1049
+ for await (const chunk of once()) {
1050
+ yielded = true;
1051
+ yield chunk;
1052
+ }
1053
+ return;
1054
+ }
1055
+ catch (err) {
1056
+ // A stream that already produced output was accepted — a rejection can
1057
+ // only come before the first chunk, and replaying would duplicate output.
1058
+ if (yielded)
1059
+ throw err;
1060
+ const next = await route.afterFailure(err);
1061
+ if (next !== RETRY_WITH_REFRESHED_TOKEN)
1062
+ throw next;
1063
+ }
1064
+ yield* once();
1065
+ };
1066
+ }
513
1067
  /**
514
1068
  * The pieces of the proxy that are shared with the local MCP server now live in
515
1069
  * `@bevel-software/platform-mcp-core`. Re-exported here because this module is