@bevel-software/platform-core-backend 0.25.0 → 0.26.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 (254) hide show
  1. package/agent-guide/access-control.md +234 -0
  2. package/agent-guide/conventions.md +27 -0
  3. package/agent-guide/directory-structure.md +145 -0
  4. package/agent-guide/finding-things.md +7 -0
  5. package/agent-guide/introduction.md +27 -0
  6. package/agent-guide/skills.md +47 -0
  7. package/agent-guide/tool-manuals.md +217 -0
  8. package/agent-guide/where-a-new-file-goes.md +36 -0
  9. package/dist/assets.d.ts +7 -0
  10. package/dist/assets.d.ts.map +1 -1
  11. package/dist/assets.js +9 -0
  12. package/dist/assets.js.map +1 -1
  13. package/dist/core/core-ports.d.ts +11 -0
  14. package/dist/core/core-ports.d.ts.map +1 -1
  15. package/dist/core/core-ports.js.map +1 -1
  16. package/dist/core/create-core-server.d.ts.map +1 -1
  17. package/dist/core/create-core-server.js +13 -2
  18. package/dist/core/create-core-server.js.map +1 -1
  19. package/dist/core/create-core-services.d.ts +9 -0
  20. package/dist/core/create-core-services.d.ts.map +1 -1
  21. package/dist/core/create-core-services.js +14 -4
  22. package/dist/core/create-core-services.js.map +1 -1
  23. package/dist/index.d.ts +1 -1
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +2 -2
  26. package/dist/index.js.map +1 -1
  27. package/dist/modules/access/access-control.interface.d.ts +9 -0
  28. package/dist/modules/access/access-control.interface.d.ts.map +1 -1
  29. package/dist/modules/access/access-control.service.d.ts +1 -0
  30. package/dist/modules/access/access-control.service.d.ts.map +1 -1
  31. package/dist/modules/access/access-control.service.js +16 -0
  32. package/dist/modules/access/access-control.service.js.map +1 -1
  33. package/dist/modules/agent-guide/agent-guide.d.ts +139 -0
  34. package/dist/modules/agent-guide/agent-guide.d.ts.map +1 -0
  35. package/dist/modules/agent-guide/agent-guide.js +191 -0
  36. package/dist/modules/agent-guide/agent-guide.js.map +1 -0
  37. package/dist/modules/agent-guide/agent-guide.tools.d.ts +24 -0
  38. package/dist/modules/agent-guide/agent-guide.tools.d.ts.map +1 -0
  39. package/dist/modules/agent-guide/agent-guide.tools.js +100 -0
  40. package/dist/modules/agent-guide/agent-guide.tools.js.map +1 -0
  41. package/dist/modules/agent-guide/index.d.ts +4 -0
  42. package/dist/modules/agent-guide/index.d.ts.map +1 -0
  43. package/dist/modules/agent-guide/index.js +4 -0
  44. package/dist/modules/agent-guide/index.js.map +1 -0
  45. package/dist/modules/agent-instructions/agent-instructions.routes.d.ts +3 -2
  46. package/dist/modules/agent-instructions/agent-instructions.routes.d.ts.map +1 -1
  47. package/dist/modules/agent-instructions/agent-instructions.routes.js +3 -2
  48. package/dist/modules/agent-instructions/agent-instructions.routes.js.map +1 -1
  49. package/dist/modules/agent-instructions/compose.d.ts +9 -6
  50. package/dist/modules/agent-instructions/compose.d.ts.map +1 -1
  51. package/dist/modules/agent-instructions/compose.js +9 -6
  52. package/dist/modules/agent-instructions/compose.js.map +1 -1
  53. package/dist/modules/agent-instructions/index.d.ts +1 -1
  54. package/dist/modules/agent-instructions/index.d.ts.map +1 -1
  55. package/dist/modules/agent-instructions/index.js +1 -1
  56. package/dist/modules/agent-instructions/index.js.map +1 -1
  57. package/dist/modules/agent-instructions/shared-file-rules.d.ts +10 -50
  58. package/dist/modules/agent-instructions/shared-file-rules.d.ts.map +1 -1
  59. package/dist/modules/agent-instructions/shared-file-rules.js +32 -85
  60. package/dist/modules/agent-instructions/shared-file-rules.js.map +1 -1
  61. package/dist/modules/mcp/mcp.service.d.ts +29 -2
  62. package/dist/modules/mcp/mcp.service.d.ts.map +1 -1
  63. package/dist/modules/mcp/mcp.service.js +113 -16
  64. package/dist/modules/mcp/mcp.service.js.map +1 -1
  65. package/dist/modules/mcp/tool-schema-guard.d.ts +105 -0
  66. package/dist/modules/mcp/tool-schema-guard.d.ts.map +1 -0
  67. package/dist/modules/mcp/tool-schema-guard.js +171 -0
  68. package/dist/modules/mcp/tool-schema-guard.js.map +1 -0
  69. package/dist/modules/plugins/plugins.tools.d.ts +36 -2
  70. package/dist/modules/plugins/plugins.tools.d.ts.map +1 -1
  71. package/dist/modules/plugins/plugins.tools.js +71 -14
  72. package/dist/modules/plugins/plugins.tools.js.map +1 -1
  73. package/dist/modules/settings/deployment-settings.service.d.ts +0 -7
  74. package/dist/modules/settings/deployment-settings.service.d.ts.map +1 -1
  75. package/dist/modules/settings/deployment-settings.service.js +14 -53
  76. package/dist/modules/settings/deployment-settings.service.js.map +1 -1
  77. package/dist/modules/settings/setup.routes.d.ts.map +1 -1
  78. package/dist/modules/settings/setup.routes.js +3 -6
  79. package/dist/modules/settings/setup.routes.js.map +1 -1
  80. package/dist/modules/skills/skills.tools.d.ts.map +1 -1
  81. package/dist/modules/skills/skills.tools.js +58 -16
  82. package/dist/modules/skills/skills.tools.js.map +1 -1
  83. package/dist/modules/tool-manuals/tool-manuals.contract.d.ts +23 -4
  84. package/dist/modules/tool-manuals/tool-manuals.contract.d.ts.map +1 -1
  85. package/dist/modules/tool-manuals/tool-manuals.contract.js.map +1 -1
  86. package/dist/modules/tool-manuals/tool-manuals.service.d.ts +4 -0
  87. package/dist/modules/tool-manuals/tool-manuals.service.d.ts.map +1 -1
  88. package/dist/modules/tool-manuals/tool-manuals.service.js +14 -0
  89. package/dist/modules/tool-manuals/tool-manuals.service.js.map +1 -1
  90. package/dist/modules/tool-manuals/tool-manuals.tools.d.ts +7 -0
  91. package/dist/modules/tool-manuals/tool-manuals.tools.d.ts.map +1 -1
  92. package/dist/modules/tool-manuals/tool-manuals.tools.js +66 -36
  93. package/dist/modules/tool-manuals/tool-manuals.tools.js.map +1 -1
  94. package/dist/modules/tool-registry/description-length.d.ts +14 -14
  95. package/dist/modules/tool-registry/description-length.d.ts.map +1 -1
  96. package/dist/modules/tool-registry/description-length.js +24 -26
  97. package/dist/modules/tool-registry/description-length.js.map +1 -1
  98. package/dist/modules/tool-registry/guide-first.d.ts +23 -0
  99. package/dist/modules/tool-registry/guide-first.d.ts.map +1 -0
  100. package/dist/modules/tool-registry/guide-first.js +32 -0
  101. package/dist/modules/tool-registry/guide-first.js.map +1 -0
  102. package/dist/modules/tool-registry/tool-registry.d.ts +6 -0
  103. package/dist/modules/tool-registry/tool-registry.d.ts.map +1 -1
  104. package/dist/modules/tool-registry/tool-registry.js +9 -2
  105. package/dist/modules/tool-registry/tool-registry.js.map +1 -1
  106. package/dist/modules/workflow/agent-tools/change-request-read-shape.d.ts +449 -0
  107. package/dist/modules/workflow/agent-tools/change-request-read-shape.d.ts.map +1 -0
  108. package/dist/modules/workflow/agent-tools/change-request-read-shape.js +481 -0
  109. package/dist/modules/workflow/agent-tools/change-request-read-shape.js.map +1 -0
  110. package/dist/modules/workflow/agent-tools/change-request-read.tools.d.ts +73 -0
  111. package/dist/modules/workflow/agent-tools/change-request-read.tools.d.ts.map +1 -0
  112. package/dist/modules/workflow/agent-tools/change-request-read.tools.js +582 -0
  113. package/dist/modules/workflow/agent-tools/change-request-read.tools.js.map +1 -0
  114. package/dist/modules/workflow/agent-tools/change-request-summary.d.ts +12 -1
  115. package/dist/modules/workflow/agent-tools/change-request-summary.d.ts.map +1 -1
  116. package/dist/modules/workflow/agent-tools/change-request-summary.js +5 -1
  117. package/dist/modules/workflow/agent-tools/change-request-summary.js.map +1 -1
  118. package/dist/modules/workflow/agent-tools/workflow.tools.d.ts.map +1 -1
  119. package/dist/modules/workflow/agent-tools/workflow.tools.js +9 -0
  120. package/dist/modules/workflow/agent-tools/workflow.tools.js.map +1 -1
  121. package/dist/modules/workflow/git/git.service.d.ts +210 -13
  122. package/dist/modules/workflow/git/git.service.d.ts.map +1 -1
  123. package/dist/modules/workflow/git/git.service.js +456 -91
  124. package/dist/modules/workflow/git/git.service.js.map +1 -1
  125. package/dist/modules/workflow/git/merge-commit.d.ts +73 -0
  126. package/dist/modules/workflow/git/merge-commit.d.ts.map +1 -0
  127. package/dist/modules/workflow/git/merge-commit.js +89 -0
  128. package/dist/modules/workflow/git/merge-commit.js.map +1 -0
  129. package/dist/modules/workflow/git/pull-request.service.d.ts +94 -1
  130. package/dist/modules/workflow/git/pull-request.service.d.ts.map +1 -1
  131. package/dist/modules/workflow/git/pull-request.service.js +332 -37
  132. package/dist/modules/workflow/git/pull-request.service.js.map +1 -1
  133. package/dist/modules/workflow/review-workflow/review-workflow.service.d.ts +35 -0
  134. package/dist/modules/workflow/review-workflow/review-workflow.service.d.ts.map +1 -1
  135. package/dist/modules/workflow/review-workflow/review-workflow.service.js +178 -12
  136. package/dist/modules/workflow/review-workflow/review-workflow.service.js.map +1 -1
  137. package/dist/modules/workflow/workflow.routes.d.ts +6 -2
  138. package/dist/modules/workflow/workflow.routes.d.ts.map +1 -1
  139. package/dist/modules/workflow/workflow.routes.js +7 -2
  140. package/dist/modules/workflow/workflow.routes.js.map +1 -1
  141. package/dist/modules/workflow/workflow.service.d.ts +4 -0
  142. package/dist/modules/workflow/workflow.service.d.ts.map +1 -1
  143. package/dist/modules/workflow/workflow.service.js +3 -0
  144. package/dist/modules/workflow/workflow.service.js.map +1 -1
  145. package/dist/modules/workspace/startup/kb-startup-runner.d.ts +70 -0
  146. package/dist/modules/workspace/startup/kb-startup-runner.d.ts.map +1 -1
  147. package/dist/modules/workspace/startup/kb-startup-runner.js +213 -20
  148. package/dist/modules/workspace/startup/kb-startup-runner.js.map +1 -1
  149. package/dist/modules/workspace/startup/steps/seed-tree.d.ts.map +1 -1
  150. package/dist/modules/workspace/startup/steps/seed-tree.js +22 -27
  151. package/dist/modules/workspace/startup/steps/seed-tree.js.map +1 -1
  152. package/dist/modules/workspace/startup/steps/template-files.step.d.ts +58 -52
  153. package/dist/modules/workspace/startup/steps/template-files.step.d.ts.map +1 -1
  154. package/dist/modules/workspace/startup/steps/template-files.step.js +209 -223
  155. package/dist/modules/workspace/startup/steps/template-files.step.js.map +1 -1
  156. package/dist/modules/workspace/startup/steps/template-source.d.ts +5 -3
  157. package/dist/modules/workspace/startup/steps/template-source.d.ts.map +1 -1
  158. package/dist/modules/workspace/startup/steps/template-source.js +5 -3
  159. package/dist/modules/workspace/startup/steps/template-source.js.map +1 -1
  160. package/dist/modules/workspace/workspace.tools.d.ts +10 -1
  161. package/dist/modules/workspace/workspace.tools.d.ts.map +1 -1
  162. package/dist/modules/workspace/workspace.tools.js +211 -18
  163. package/dist/modules/workspace/workspace.tools.js.map +1 -1
  164. package/dist/shared/domain-errors.d.ts +11 -0
  165. package/dist/shared/domain-errors.d.ts.map +1 -1
  166. package/dist/shared/domain-errors.js +14 -0
  167. package/dist/shared/domain-errors.js.map +1 -1
  168. package/dist/shared/hidden-tools.d.ts +44 -0
  169. package/dist/shared/hidden-tools.d.ts.map +1 -0
  170. package/dist/shared/hidden-tools.js +13 -0
  171. package/dist/shared/hidden-tools.js.map +1 -0
  172. package/kb-template/.bevelignore +0 -5
  173. package/package.json +4 -3
  174. package/src/__tests__/kb-layout-config.test.ts +10 -100
  175. package/src/__tests__/packaged-assets-ship.test.ts +54 -0
  176. package/src/assets.ts +10 -0
  177. package/src/core/core-ports.ts +11 -0
  178. package/src/core/create-core-server.ts +13 -2
  179. package/src/core/create-core-services.ts +28 -4
  180. package/src/index.ts +2 -2
  181. package/src/modules/access/__tests__/access-control.atref-batch.test.ts +58 -0
  182. package/src/modules/access/__tests__/access-control.platform-restore.test.ts +8 -7
  183. package/src/modules/access/__tests__/access-personal-plugin.test.ts +1 -18
  184. package/src/modules/access/access-control.interface.ts +15 -0
  185. package/src/modules/access/access-control.service.ts +21 -0
  186. package/src/modules/agent-guide/__tests__/agent-guide.test.ts +328 -0
  187. package/src/modules/agent-guide/__tests__/agent-guide.tools.test.ts +189 -0
  188. package/src/modules/agent-guide/agent-guide.tools.ts +122 -0
  189. package/src/modules/agent-guide/agent-guide.ts +291 -0
  190. package/src/modules/agent-guide/index.ts +21 -0
  191. package/src/modules/agent-instructions/__tests__/shared-file-rules.test.ts +28 -121
  192. package/src/modules/agent-instructions/agent-instructions.routes.ts +3 -2
  193. package/src/modules/agent-instructions/compose.ts +9 -6
  194. package/src/modules/agent-instructions/index.ts +0 -3
  195. package/src/modules/agent-instructions/shared-file-rules.ts +31 -93
  196. package/src/modules/mcp/__tests__/fake-downstream-mcp-server.ts +14 -3
  197. package/src/modules/mcp/__tests__/mcp.e2e.test.ts +250 -0
  198. package/src/modules/mcp/__tests__/mcp.service.test.ts +31 -23
  199. package/src/modules/mcp/__tests__/tool-schema-guard.test.ts +266 -0
  200. package/src/modules/mcp/mcp.service.ts +137 -19
  201. package/src/modules/mcp/tool-schema-guard.ts +196 -0
  202. package/src/modules/plugins/__tests__/plugins.tools.test.ts +154 -4
  203. package/src/modules/plugins/plugins.tools.ts +75 -15
  204. package/src/modules/settings/__tests__/deployment-settings.service.test.ts +26 -55
  205. package/src/modules/settings/deployment-settings.service.ts +13 -54
  206. package/src/modules/settings/setup.routes.ts +3 -6
  207. package/src/modules/skills/__tests__/skills.tools.description.test.ts +91 -0
  208. package/src/modules/skills/skills.tools.ts +62 -16
  209. package/src/modules/tool-manuals/__tests__/tool-manuals.detail.route.test.ts +57 -0
  210. package/src/modules/tool-manuals/__tests__/tool-manuals.tools.test.ts +73 -4
  211. package/src/modules/tool-manuals/tool-manuals.contract.ts +24 -4
  212. package/src/modules/tool-manuals/tool-manuals.service.ts +17 -0
  213. package/src/modules/tool-manuals/tool-manuals.tools.ts +74 -36
  214. package/src/modules/tool-registry/__tests__/own-tool-schemas.test.ts +160 -0
  215. package/src/modules/tool-registry/__tests__/tool-description-length.test.ts +61 -59
  216. package/src/modules/tool-registry/description-length.ts +24 -26
  217. package/src/modules/tool-registry/guide-first.ts +34 -0
  218. package/src/modules/tool-registry/tool-registry.ts +9 -2
  219. package/src/modules/workflow/__tests__/apply-failure.test.ts +6 -1
  220. package/src/modules/workflow/agent-tools/__tests__/change-request-read-shape.test.ts +705 -0
  221. package/src/modules/workflow/agent-tools/__tests__/change-request-read.tools.test.ts +1518 -0
  222. package/src/modules/workflow/agent-tools/__tests__/workflow.tools.test.ts +23 -2
  223. package/src/modules/workflow/agent-tools/change-request-read-shape.ts +712 -0
  224. package/src/modules/workflow/agent-tools/change-request-read.tools.ts +724 -0
  225. package/src/modules/workflow/agent-tools/change-request-summary.ts +5 -1
  226. package/src/modules/workflow/agent-tools/workflow.tools.ts +8 -0
  227. package/src/modules/workflow/git/__tests__/git.service.appliedChange.test.ts +285 -0
  228. package/src/modules/workflow/git/__tests__/git.service.changedFilesForPr.test.ts +124 -0
  229. package/src/modules/workflow/git/__tests__/git.service.mergeChangeRequest.test.ts +334 -0
  230. package/src/modules/workflow/git/__tests__/pull-request.service.list-fetch.test.ts +72 -2
  231. package/src/modules/workflow/git/__tests__/pull-request.service.placeholder.test.ts +24 -2
  232. package/src/modules/workflow/git/__tests__/pull-request.service.test.ts +620 -1
  233. package/src/modules/workflow/git/git.service.ts +537 -94
  234. package/src/modules/workflow/git/merge-commit.ts +88 -0
  235. package/src/modules/workflow/git/pull-request.service.ts +380 -54
  236. package/src/modules/workflow/review-workflow/__tests__/approval-states.test.ts +7 -1
  237. package/src/modules/workflow/review-workflow/__tests__/merge-records-own-commit.test.ts +407 -0
  238. package/src/modules/workflow/review-workflow/review-workflow.service.ts +189 -11
  239. package/src/modules/workflow/workflow.routes.ts +7 -2
  240. package/src/modules/workflow/workflow.service.ts +7 -0
  241. package/src/modules/workspace/__tests__/escape-sequences.routes.test.ts +4 -3
  242. package/src/modules/workspace/__tests__/workspace.routes.move-platform-files.test.ts +21 -10
  243. package/src/modules/workspace/__tests__/workspace.tools.agents-file.test.ts +33 -55
  244. package/src/modules/workspace/__tests__/workspace.tools.test.ts +255 -22
  245. package/src/modules/workspace/startup/__tests__/kb-startup-runner.test.ts +231 -1
  246. package/src/modules/workspace/startup/kb-startup-runner.ts +216 -19
  247. package/src/modules/workspace/startup/steps/__tests__/steps.test.ts +191 -489
  248. package/src/modules/workspace/startup/steps/seed-tree.ts +21 -27
  249. package/src/modules/workspace/startup/steps/template-files.step.ts +217 -249
  250. package/src/modules/workspace/startup/steps/template-source.ts +5 -3
  251. package/src/modules/workspace/workspace.tools.ts +226 -16
  252. package/src/shared/domain-errors.ts +15 -0
  253. package/src/shared/hidden-tools.ts +45 -0
  254. package/kb-template/AGENTS.md +0 -730
@@ -1 +1 @@
1
- {"version":3,"file":"shared-file-rules.d.ts","sourceRoot":"","sources":["../../../src/modules/agent-instructions/shared-file-rules.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,EAKL,KAAK,QAAQ,EACd,MAAM,iCAAiC,CAAC;AAGzC,oFAAoF;AACpF,eAAO,MAAM,oBAAoB,uBAAuB,CAAC;AAUzD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,qBAAqB,OAAQ,CAAC;AAE3C,oEAAoE;AACpE,MAAM,WAAW,cAAc;IAC7B,gEAAgE;IAChE,EAAE,EAAE,MAAM,CAAC;IACX,iDAAiD;IACjD,OAAO,EAAE,MAAM,CAAC;IAChB,oFAAoF;IACpF,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,QAAQ,GAAG,SAAS,cAAc,EAAE,CAqH3E;AAgDD;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,QAAQ,GAAG,MAAM,CAK/D;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,yBAAyB,KAAK,CAAC;AAE5C;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,GAAE,QAA4B,GAAG,MAAM,CAK/E;AAED;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,QAGpC,CAAC"}
1
+ {"version":3,"file":"shared-file-rules.d.ts","sourceRoot":"","sources":["../../../src/modules/agent-instructions/shared-file-rules.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,EAGL,KAAK,QAAQ,EACd,MAAM,iCAAiC,CAAC;AAGzC,oFAAoF;AACpF,eAAO,MAAM,oBAAoB,uBAAuB,CAAC;AAUzD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,qBAAqB,OAAQ,CAAC;AAE3C,oEAAoE;AACpE,MAAM,WAAW,cAAc;IAC7B,gEAAgE;IAChE,EAAE,EAAE,MAAM,CAAC;IACX,iDAAiD;IACjD,OAAO,EAAE,MAAM,CAAC;IAChB,oFAAoF;IACpF,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,QAAQ,GAAG,SAAS,cAAc,EAAE,CAoH3E;AAsCD;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,QAAQ,GAAG,MAAM,CAK/D"}
@@ -14,29 +14,31 @@
14
14
  *
15
15
  * - the MCP `instructions` of the initialize handshake (see `compose.ts`),
16
16
  * which Claude Code, Claude Desktop and Cursor put in the system prompt;
17
- * - the platform-managed agent guide at the repository root (`AGENTS.md` by
18
- * default), rendered from `{{sharedFileRules}}` in the template — claude.ai
19
- * on the web, the Agent SDK and Cline drop `instructions`, and a guide the
20
- * agent is told to read before its first action is always available.
17
+ * - the platform's agent guide, which `get_agent_guide` returns and a
18
+ * `read_file` of the guide's name serves (see `modules/agent-guide`) —
19
+ * claude.ai on the web, the Agent SDK and Cline drop `instructions`, and a
20
+ * guide the agent is told to read before its first action is always
21
+ * available.
21
22
  *
22
23
  * Both places get the SAME string, from {@link sharedFileRulesSection} — not
23
24
  * two hand-mirrored copies. A rule written twice is a rule that drifts, and a
24
25
  * drifted rule is worse than a repeated one, because the agent cannot tell
25
- * which copy is current. Each description ends instead with
26
- * {@link sharedRulesPointer}, one sentence naming the section and the file.
26
+ * which copy is current. Each description opens instead with the one
27
+ * sentence sending the agent to the guide (`tool-registry/guide-first.ts`).
27
28
  *
28
- * Pure text, a function of the layout only: the guide's file name is a
29
- * deployment setting, so nothing here may snapshot `AGENTS.md`.
29
+ * Pure text, a function of the layout only: the guide's name is a deployment
30
+ * setting (an alias a deployment chose before the guide left the disk), so
31
+ * nothing here may snapshot `AGENTS.md`.
30
32
  */
31
- import { DEFAULT_KB_LAYOUT, agentsFileOf, LEGACY_AGENTS_FILE, platformFilesByDepth, } from '@bevel-software/platform-shared';
33
+ import { LEGACY_AGENTS_FILE, platformFilesByDepth, } from '@bevel-software/platform-shared';
32
34
  import { CHAIN_FAILURES_RULE, CHAIN_LARGE_RESULTS_RULE } from '@bevel-software/platform-mcp-core';
33
35
  /** The heading the rules live under, in both places and in the pointer sentence. */
34
36
  export const SHARED_RULES_SECTION = 'Working with files';
35
37
  /**
36
38
  * The guide's name on a knowledge base seeded before it was renamed to
37
- * {@link LEGACY_AGENTS_FILE}. Named in the conventions rule because the seeder
38
- * never deletes a file it did not expect, so such a knowledge base still
39
- * carries one.
39
+ * {@link LEGACY_AGENTS_FILE}, back when the guide was a file. The platform's
40
+ * own copy is taken out at startup now (see template-files.step.ts); one that
41
+ * stays is a file the organisation edited, so it is theirs and still named.
40
42
  */
41
43
  const PRE_RENAME_AGENTS_FILE = 'CLAUDE.md';
42
44
  /**
@@ -63,12 +65,11 @@ export const SHARED_FILE_RULES_CAP = 7_000;
63
65
  * ones that said "this tool" or "this call" name the tools instead.
64
66
  */
65
67
  export function sharedFileRules(layout) {
66
- const agentsFile = agentsFileOf(layout);
67
68
  return [
68
69
  {
69
70
  id: 'agent-guide',
70
71
  heading: "This knowledge base's own conventions",
71
- body: conventionsRule(agentsFile),
72
+ body: conventionsRule(),
72
73
  },
73
74
  {
74
75
  id: 'content-kinds',
@@ -174,15 +175,14 @@ export function sharedFileRules(layout) {
174
175
  }
175
176
  /**
176
177
  * The platform files as the rules list them — from the one function that knows
177
- * which they are, so the list cannot drift from what actually refuses a move,
178
- * and the guide appears under this deployment's name for it.
178
+ * which they are, so the list cannot drift from what actually refuses a move.
179
179
  *
180
180
  * WITH THE DEPTH each name counts at, because the name alone is half the rule:
181
181
  * `access.md` governs the folder it sits in and `.bevelignore` layers, so both
182
- * are platform files wherever they are; `roles.yaml` and the guide are read
183
- * from the repository root only, so a nested copy of either is ordinary
184
- * content that moves and deletes like any page. An agent told only the names
185
- * refuses a rename it may make, and trusts a nested `access.md` it may not.
182
+ * are platform files wherever they are; `roles.yaml` is read from the
183
+ * repository root only, so a nested copy is ordinary content that moves and
184
+ * deletes like any page. An agent told only the names refuses a rename it may
185
+ * make, and trusts a nested `access.md` it may not.
186
186
  */
187
187
  function platformFileList(layout) {
188
188
  const { anyDepth, rootOnly } = platformFilesByDepth(layout);
@@ -190,27 +190,20 @@ function platformFileList(layout) {
190
190
  return `${quoted(anyDepth)} in any folder, ${quoted(rootOnly)} at the repository root`;
191
191
  }
192
192
  /**
193
- * The conventions reminder — which file holds the author's own rules for this
194
- * knowledge base, and to read it first.
193
+ * The conventions reminder — where the platform's guide is, that the
194
+ * organisation's own conventions file comes with it, and to read both first.
195
195
  *
196
- * `CLAUDE.md` is named as a fallback because knowledge bases seeded before the
197
- * rename still carry one. WHEN THE GUIDE HAS BEEN RENAMED the sentence names
198
- * two files, ours first: the second is the organisation's OWN `AGENTS.md`,
199
- * which on such a deployment is ordinary content the platform never touches —
200
- * and which no harness reads for a remote agent, because a remote agent has no
201
- * checkout. Under the default name the wording collapses to the one file it
202
- * has always named.
196
+ * The guide is read by name at the repository root, where coding agents look
197
+ * for an `AGENTS.md` by convention, and `get_agent_guide` returns it alone.
198
+ * One name on every deployment, so the rule takes no layout. `CLAUDE.md` is
199
+ * named as a fallback because a knowledge base seeded before the rename may
200
+ * still carry one its people edited.
203
201
  */
204
- function conventionsRule(agentsFile) {
205
- if (agentsFile === LEGACY_AGENTS_FILE) {
206
- return (`Before your first read or change in a workspace, read \`${LEGACY_AGENTS_FILE}\` at the KB root — or ` +
207
- `\`${PRE_RENAME_AGENTS_FILE}\` on a knowledge base seeded before it was renamed — if either exists: it holds ` +
208
- "the author's conventions for this knowledge base, and you should follow them.");
209
- }
210
- return (`Before your first read or change in a workspace, read \`${agentsFile}\` at the KB root, then ` +
211
- `\`${LEGACY_AGENTS_FILE}\` if it also exists (the organisation's own conventions) — or ` +
212
- `\`${PRE_RENAME_AGENTS_FILE}\` on a knowledge base seeded before it was renamed: together they hold the ` +
213
- 'conventions for this knowledge base, and you should follow them.');
202
+ function conventionsRule() {
203
+ return ("Before your first read or change in a workspace, call `get_agent_guide` and read the platform's guide " +
204
+ `(whole, or one section). read_file on \`${LEGACY_AGENTS_FILE}\` at the KB root answers with the same ` +
205
+ "guide, after the organisation's own conventions file of that name when it has one: follow both. A " +
206
+ `\`${PRE_RENAME_AGENTS_FILE}\` at the KB root is the organisation's own too; read it if it exists.`);
214
207
  }
215
208
  /**
216
209
  * The shared rules as ONE markdown section — the string both channels carry,
@@ -223,50 +216,4 @@ export function sharedFileRulesSection(layout) {
223
216
  .join('\n\n');
224
217
  return `## ${SHARED_RULES_SECTION}\n\n${body}`;
225
218
  }
226
- /**
227
- * The longest guide file name the pointer sentence spells out. Beyond this it
228
- * names the guide by its ROLE instead (see {@link sharedRulesPointer}).
229
- *
230
- * There has to be a bound somewhere, because the pointer rides on every file
231
- * tool and a file name is not a fixed cost: `validateFilename` allows a name
232
- * of up to 255 bytes, so an unbounded pointer could reach 318 characters and
233
- * push `file_stat` to 1,428 — over the description cap, recreating on a
234
- * renamed deployment exactly the truncation this module exists to prevent, and
235
- * invisibly, because every measurement is taken under the default layout.
236
- *
237
- * 40 is well past any name a deployment plausibly picks
238
- * (`ENGINEERING-AGENT-CONVENTIONS.md` is 32) and the fallback below is only
239
- * reachable past it.
240
- */
241
- export const POINTER_GUIDE_NAME_BUDGET = 40;
242
- /**
243
- * The one sentence a tool description ends with, in place of the paragraphs it
244
- * used to carry. Short on purpose: it costs every description the same ~100
245
- * characters at worst, and its whole job is to name the section and the file
246
- * to read.
247
- *
248
- * BOUNDED BY CONSTRUCTION, which is what lets the description cap mean
249
- * something on a deployment that renamed its guide: a name within
250
- * {@link POINTER_GUIDE_NAME_BUDGET} is spelled out, and a longer one gets the
251
- * generic wording. Naming the file is the better sentence and wins whenever it
252
- * fits; a name past the budget is pathological, and there the choice is between
253
- * a sentence that says where to look and a catalog entry the client cuts. The
254
- * guide's own name is still in the section's first rule either way.
255
- *
256
- * An absent layout means the default one, as it does in
257
- * `composeAgentInstructions`: a caller reading the layout from configuration
258
- * gets `undefined` when none is set, and the pointer must still name a file.
259
- */
260
- export function sharedRulesPointer(layout = DEFAULT_KB_LAYOUT) {
261
- const agentsFile = agentsFileOf(layout);
262
- const where = agentsFile.length <= POINTER_GUIDE_NAME_BUDGET ? agentsFile : 'the agent guide at the KB root';
263
- return ` Shared rules for all file tools: see "${SHARED_RULES_SECTION}" in ${where}.`;
264
- }
265
- /**
266
- * The most the pointer can ever cost a description, over every layout. What the
267
- * description cap is measured against, the way the tool prefix is measured at
268
- * ITS cap rather than at whatever the current admin wrote: a description that
269
- * only fits beside the short default guide name does not really fit.
270
- */
271
- export const SHARED_RULES_POINTER_MAX = Math.max(sharedRulesPointer({ ...DEFAULT_KB_LAYOUT, agentsFile: `${'x'.repeat(POINTER_GUIDE_NAME_BUDGET - 3)}.md` }).length, sharedRulesPointer({ ...DEFAULT_KB_LAYOUT, agentsFile: `${'x'.repeat(POINTER_GUIDE_NAME_BUDGET + 10)}.md` }).length);
272
219
  //# sourceMappingURL=shared-file-rules.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"shared-file-rules.js","sourceRoot":"","sources":["../../../src/modules/agent-instructions/shared-file-rules.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,EACL,iBAAiB,EACjB,YAAY,EACZ,kBAAkB,EAClB,oBAAoB,GAErB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,mBAAmB,EAAE,wBAAwB,EAAE,MAAM,mCAAmC,CAAC;AAElG,oFAAoF;AACpF,MAAM,CAAC,MAAM,oBAAoB,GAAG,oBAAoB,CAAC;AAEzD;;;;;GAKG;AACH,MAAM,sBAAsB,GAAG,WAAW,CAAC;AAE3C;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,KAAK,CAAC;AAY3C;;;;;;;;GAQG;AACH,MAAM,UAAU,eAAe,CAAC,MAAgB;IAC9C,MAAM,UAAU,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;IACxC,OAAO;QACL;YACE,EAAE,EAAE,aAAa;YACjB,OAAO,EAAE,uCAAuC;YAChD,IAAI,EAAE,eAAe,CAAC,UAAU,CAAC;SAClC;QACD;YACE,EAAE,EAAE,eAAe;YACnB,OAAO,EAAE,4CAA4C;YACrD,IAAI,EACF,yEAAyE;gBACzE,+GAA+G;gBAC/G,4GAA4G;gBAC5G,kHAAkH;gBAClH,4GAA4G;gBAC5G,+CAA+C;gBAC/C,uEAAuE;gBACvE,6GAA6G;gBAC7G,8GAA8G;gBAC9G,6GAA6G;gBAC7G,gHAAgH;gBAChH,8GAA8G;gBAC9G,+GAA+G;gBAC/G,4GAA4G;gBAC5G,6GAA6G;gBAC7G,+GAA+G;gBAC/G,uGAAuG;gBACvG,kHAAkH;gBAClH,oEAAoE;SACvE;QACD;YACE,EAAE,EAAE,YAAY;YAChB,OAAO,EAAE,+BAA+B;YACxC,IAAI,EACF,6GAA6G;gBAC7G,gHAAgH;gBAChH,0GAA0G;gBAC1G,6GAA6G;SAChH;QACD;YACE,EAAE,EAAE,iBAAiB;YACrB,OAAO,EAAE,iCAAiC;YAC1C,IAAI,EACF,4GAA4G;gBAC5G,mFAAmF;SACtF;QACD;YACE,EAAE,EAAE,kBAAkB;YACtB,OAAO,EAAE,sCAAsC;YAC/C,IAAI,EACF,4GAA4G;gBAC5G,8GAA8G;gBAC9G,8GAA8G;gBAC9G,+GAA+G;gBAC/G,iGAAiG;SACpG;QACD;YACE,yEAAyE;YACzE,wEAAwE;YACxE,4DAA4D;YAC5D,EAAE,EAAE,cAAc;YAClB,OAAO,EAAE,uDAAuD;YAChE,IAAI,EACF,8GAA8G;gBAC9G,6GAA6G;gBAC7G,gHAAgH;gBAChH,iFAAiF;gBACjF,+GAA+G;gBAC/G,6GAA6G;gBAC7G,+CAA+C;SAClD;QACD;YACE,EAAE,EAAE,iBAAiB;YACrB,OAAO,EAAE,kDAAkD;YAC3D,IAAI,EACF,0GAA0G;gBAC1G,+GAA+G;gBAC/G,yGAAyG;gBACzG,6GAA6G;gBAC7G,4GAA4G;gBAC5G,gEAAgE;SACnE;QACD;YACE,EAAE,EAAE,eAAe;YACnB,OAAO,EAAE,uCAAuC;YAChD,IAAI,EACF,oBAAoB,gBAAgB,CAAC,MAAM,CAAC,oBAAoB;gBAChE,6EAA6E;gBAC7E,gHAAgH;gBAChH,+GAA+G;gBAC/G,uCAAuC,MAAM,CAAC,gBAAgB,0DAA0D;gBACxH,gHAAgH;gBAChH,8GAA8G;gBAC9G,8GAA8G;gBAC9G,yFAAyF;SAC5F;QACD;YACE,EAAE,EAAE,yBAAyB;YAC7B,OAAO,EAAE,yCAAyC;YAClD,IAAI,EACF,8GAA8G;gBAC9G,6GAA6G;gBAC7G,gCAAgC;SACnC;QACD;YACE,qEAAqE;YACrE,uEAAuE;YACvE,uEAAuE;YACvE,wEAAwE;YACxE,8DAA8D;YAC9D,EAAE,EAAE,YAAY;YAChB,OAAO,EAAE,qCAAqC;YAC9C,IAAI,EAAE,uBAAuB,mBAAmB,OAAO,wBAAwB,EAAE;SAClF;KACF,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;GAWG;AACH,SAAS,gBAAgB,CAAC,MAAgB;IACxC,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAC5D,MAAM,MAAM,GAAG,CAAC,KAAwB,EAAU,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACrG,OAAO,GAAG,MAAM,CAAC,QAAQ,CAAC,mBAAmB,MAAM,CAAC,QAAQ,CAAC,yBAAyB,CAAC;AACzF,CAAC;AAED;;;;;;;;;;;GAWG;AACH,SAAS,eAAe,CAAC,UAAkB;IACzC,IAAI,UAAU,KAAK,kBAAkB,EAAE,CAAC;QACtC,OAAO,CACL,2DAA2D,kBAAkB,yBAAyB;YACtG,KAAK,sBAAsB,mFAAmF;YAC9G,+EAA+E,CAChF,CAAC;IACJ,CAAC;IACD,OAAO,CACL,2DAA2D,UAAU,0BAA0B;QAC/F,KAAK,kBAAkB,iEAAiE;QACxF,KAAK,sBAAsB,8EAA8E;QACzG,kEAAkE,CACnE,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,sBAAsB,CAAC,MAAgB;IACrD,MAAM,IAAI,GAAG,eAAe,CAAC,MAAM,CAAC;SACjC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,IAAI,CAAC,OAAO,OAAO,IAAI,CAAC,IAAI,EAAE,CAAC;SACpD,IAAI,CAAC,MAAM,CAAC,CAAC;IAChB,OAAO,MAAM,oBAAoB,OAAO,IAAI,EAAE,CAAC;AACjD,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,EAAE,CAAC;AAE5C;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,kBAAkB,CAAC,SAAmB,iBAAiB;IACrE,MAAM,UAAU,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;IACxC,MAAM,KAAK,GACT,UAAU,CAAC,MAAM,IAAI,yBAAyB,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,gCAAgC,CAAC;IACjG,OAAO,0CAA0C,oBAAoB,QAAQ,KAAK,GAAG,CAAC;AACxF,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,IAAI,CAAC,GAAG,CAC9C,kBAAkB,CAAC,EAAE,GAAG,iBAAiB,EAAE,UAAU,EAAE,GAAG,GAAG,CAAC,MAAM,CAAC,yBAAyB,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,MAAM,EAClH,kBAAkB,CAAC,EAAE,GAAG,iBAAiB,EAAE,UAAU,EAAE,GAAG,GAAG,CAAC,MAAM,CAAC,yBAAyB,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC,CAAC,MAAM,CACpH,CAAC"}
1
+ {"version":3,"file":"shared-file-rules.js","sourceRoot":"","sources":["../../../src/modules/agent-instructions/shared-file-rules.ts"],"names":[],"mappings":"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"}
@@ -5,6 +5,7 @@ import type { KbLayout } from '@bevel-software/platform-shared';
5
5
  import { type ISecretsVaultService } from '../secrets-vault/secrets-vault.contract.js';
6
6
  import type { IToolManualService } from '../tool-manuals/tool-manuals.contract.js';
7
7
  import type { SpillStore } from '../workspace/spill-store.js';
8
+ import type { HiddenToolSource } from '../../shared/hidden-tools.js';
8
9
  import type { InternalTokenService } from '../tool-auth/internal-token.service.js';
9
10
  import type { IAgentEventRecorder } from '../audit/audit.contract.js';
10
11
  import { type DownstreamPoolOptions } from './downstream-pool.js';
@@ -33,8 +34,8 @@ export interface McpProxyOptions {
33
34
  readAgentPreamble?: AgentPreambleReader;
34
35
  /**
35
36
  * The layout in effect, read per request: the shared file rules name the
36
- * managed guide, and a deployment may rename it after boot (the setup save
37
- * applies a name without a restart). A GETTER, so nothing snapshots the
37
+ * guide by the name a deployment saved for it, and the setup save applies
38
+ * a layout without a restart. A GETTER, so nothing snapshots the
38
39
  * pre-setup default. Absent, the rules name `AGENTS.md`.
39
40
  */
40
41
  kbLayout?: () => KbLayout;
@@ -136,6 +137,14 @@ export declare class McpService {
136
137
  * server's tools.
137
138
  */
138
139
  private readonly knownDownstreamTools;
140
+ /**
141
+ * The JSON Schema check on connected tools, and the memory of what it found.
142
+ * Process-wide rather than per request, because a schema's validity is a
143
+ * property of the server and not of the caller — and because the point of
144
+ * remembering is that the check runs when a server's tools are loaded, not
145
+ * once per request and never on a tool call. See {@link ToolSchemaGuard}.
146
+ */
147
+ private readonly toolSchemas;
139
148
  private readonly downstream;
140
149
  constructor(opts: McpProxyOptions, secretsVault?: ISecretsVaultService | undefined, toolManuals?: IToolManualService | undefined, internalTokens?: InternalTokenService | undefined, revokeOAuthAccess?: ((bearer: string) => Promise<void>) | undefined, auditRecorder?: IAgentEventRecorder | undefined);
141
150
  /**
@@ -248,6 +257,24 @@ export declare class McpService {
248
257
  * corrected `mcp.json` URL) is tried on the very next request.
249
258
  */
250
259
  private discoverTools;
260
+ /**
261
+ * Check the input schema of every tool the servers just advertised, and take
262
+ * the invalid ones OFF the client's tool repository.
263
+ *
264
+ * The repository is the single place `tools/list`, `list_tools`/`tools_info`
265
+ * and the TypeScript interfaces `call_tool_chain` generates are all built
266
+ * from, so removing a tool here removes it from all three — which is what
267
+ * "not offered to agents" has to mean. Its siblings are untouched: the check
268
+ * is per tool, so one bad schema costs that tool and nothing else of the
269
+ * server.
270
+ *
271
+ * A client would otherwise drop such a tool itself, silently, and the agent
272
+ * would be left without it and without a reason. Hidden here, the reason
273
+ * reaches the people who manage the server (see {@link ToolSchemaGuard}).
274
+ */
275
+ private hideInvalidSchemas;
276
+ /** The schema findings the owner-facing surfaces report — see {@link ToolSchemaGuard}. */
277
+ get hiddenTools(): HiddenToolSource;
251
278
  /**
252
279
  * Make one `mcp` manual's tools part of this request's client, backed by the
253
280
  * pooled connection for (user, manual).
@@ -1 +1 @@
1
- {"version":3,"file":"mcp.service.d.ts","sourceRoot":"","sources":["../../../src/modules/mcp/mcp.service.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAcnE,OAAO,YAAY,CAAC;AACpB,OAAO,WAAW,CAAC;AA0BnB,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iCAAiC,CAAC;AAEhE,OAAO,EAGL,KAAK,oBAAoB,EAC1B,MAAM,4CAA4C,CAAC;AAEpD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0CAA0C,CAAC;AACnF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAE9D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wCAAwC,CAAC;AACnF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAGtE,OAAO,EAAsC,KAAK,qBAAqB,EAAc,MAAM,sBAAsB,CAAC;AAIlH,OAAO,EAKL,KAAK,mBAAmB,EAEzB,MAAM,gCAAgC,CAAC;AAExC;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,qGAAqG;IACrG,UAAU,EAAE,UAAU,CAAC;IACvB,kFAAkF;IAClF,iBAAiB,EAAE,MAAM,CAAC;IAC1B;;;;;;;OAOG;IACH,iBAAiB,CAAC,EAAE,mBAAmB,CAAC;IACxC;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,QAAQ,CAAC;IAC1B,kGAAkG;IAClG,cAAc,CAAC,EAAE,IAAI,CAAC,qBAAqB,CAAC,OAAO,CAAC,EAAE,WAAW,GAAG,YAAY,GAAG,KAAK,CAAC,CAAC;IAC1F;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,mGAAmG;AACnG,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,6FAA6F;IAC7F,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,0CAA0C;IAC1C,MAAM,EAAE,MAAM,CAAC;CAChB;AASD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,yBAAyB,QAAqB,CAAC;AAqE5D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,qBAAa,UAAU;IA2BnB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAIrB,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC;IAC9B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC;IAI7B,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC;IAKhC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAC;IAInC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC;IA1CjC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAA2B;IAC1D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA4B;IAEvD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAA+C;IAC9E;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAgE;IAGrG,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAmC;gBAG3C,IAAI,EAAE,eAAe,EAIrB,YAAY,CAAC,EAAE,oBAAoB,YAAA,EACnC,WAAW,CAAC,EAAE,kBAAkB,YAAA,EAIhC,cAAc,CAAC,EAAE,oBAAoB,YAAA,EAKrC,iBAAiB,CAAC,GAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,aAAA,EAIrD,aAAa,CAAC,EAAE,mBAAmB,YAAA;IAatD;;;;;;;;OAQG;IACH,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAW7C;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,yBAAyB;IAOjC;;;;;;;;;OASG;IACG,mBAAmB,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC;IA4PhF;;;;;;;OAOG;YACW,YAAY;IA0B1B;;;;;OAKG;YACW,wBAAwB;IAYtC,qFAAqF;YACvE,cAAc;IAM5B,wFAAwF;YAC1E,UAAU;IAQxB;;;;;;;OAOG;YACW,YAAY;IAqB1B,8FAA8F;YAChF,YAAY;IAI1B;;;;;;;OAOG;YACW,oBAAoB;IA0BlC,uFAAuF;IACvF,OAAO,CAAC,gBAAgB;IAWxB;;;;;;;;;;;;OAYG;YACW,WAAW;IAKzB;;;;;;;;;;;;;;;;;OAiBG;YACW,aAAa;IAiG3B;;;;;;;;;;;;;OAaG;YACW,gBAAgB;IAkE9B,iIAAiI;YACnH,aAAa;IAQ3B;;;;;;;;;;;;;;;;;;;;;OAqBG;YACW,iBAAiB;IAiB/B;;;;;;;;;;;;;OAaG;YACW,sBAAsB;IAUpC,oGAAoG;YACtF,yBAAyB;IAsCvC;;;;;;;;;OASG;YACW,sBAAsB;IA8CpC;;;;;;;;OAQG;YACW,gBAAgB;IAqB9B;;;;;;OAMG;YACW,kBAAkB;IAqDhC;;;;;;;OAOG;YACW,QAAQ;IAsBtB;;;;;;;OAOG;YACW,gBAAgB;CAO/B;AAyHD;;;;;GAKG;AACH,OAAO,EACL,KAAK,WAAW,EAChB,YAAY,EACZ,mBAAmB,EACnB,iBAAiB,EACjB,qBAAqB,EACrB,mBAAmB,EACnB,gBAAgB,EAChB,wBAAwB,GACzB,MAAM,mCAAmC,CAAC"}
1
+ {"version":3,"file":"mcp.service.d.ts","sourceRoot":"","sources":["../../../src/modules/mcp/mcp.service.ts"],"names":[],"mappings":"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"}
@@ -16,9 +16,11 @@ import { RequestAudit } from '../audit/request-audit.js';
16
16
  import { ManualFailureMemo } from './manual-failure-memo.js';
17
17
  import { DownstreamPool, POOL_KEY_SEPARATOR } from './downstream-pool.js';
18
18
  import { SurfaceLogThrottle } from './surface-log-throttle.js';
19
+ import { ToolSchemaGuard } from './tool-schema-guard.js';
19
20
  import { DownstreamRefreshGuard, isDownstreamTokenRejection } from './downstream-token-refresh.js';
20
21
  import { printable } from '../../shared/printable.js';
21
- import { composeAgentInstructions, prefixToolDescription, PREFIXED_TOOLS, sharedRulesPointer, } from '../agent-instructions/index.js';
22
+ import { composeAgentInstructions, prefixToolDescription, PREFIXED_TOOLS, } from '../agent-instructions/index.js';
23
+ import { guideFirstDescription } from '../tool-registry/guide-first.js';
22
24
  /**
23
25
  * Upper bound on one `loopbackJson` round-trip (manual list, skill fetch) so a
24
26
  * hung loopback can't stall a request. Generous: these endpoints answer in
@@ -105,6 +107,14 @@ export class McpService {
105
107
  * server's tools.
106
108
  */
107
109
  knownDownstreamTools = new Map();
110
+ /**
111
+ * The JSON Schema check on connected tools, and the memory of what it found.
112
+ * Process-wide rather than per request, because a schema's validity is a
113
+ * property of the server and not of the caller — and because the point of
114
+ * remembering is that the check runs when a server's tools are loaded, not
115
+ * once per request and never on a tool call. See {@link ToolSchemaGuard}.
116
+ */
117
+ toolSchemas = new ToolSchemaGuard();
108
118
  // The downstream connection pool for `mcp` manuals — see the class doc.
109
119
  downstream;
110
120
  constructor(opts,
@@ -295,14 +305,17 @@ export class McpService {
295
305
  // different name, and one fixed example is necessarily wrong on one of the
296
306
  // two surfaces.
297
307
  //
298
- // The chain's description ends with the same pointer every file tool ends
299
- // with: what a chain does with a failure, a large result or an image is
300
- // stated once, in the shared rules, and the clients that drop
301
- // `instructions` have the description and the guide to go on. Composed
302
- // here because the guide's name is this deployment's setting.
308
+ // What a chain does with a failure, a large result or an image is
309
+ // stated once, in the shared rules — in the guide and in the handshake
310
+ // instructions — and not on the chain itself (an EMPTY pointer is how
311
+ // `mcp-core` is told the rules are served elsewhere). Like every tool of
312
+ // the platform's own, each meta-tool opens with the one sentence saying
313
+ // what to do before any of them, which is where those rules are. The
314
+ // registry puts the sentence on the tools it lists; the meta-tools are
315
+ // built here, so here it is.
303
316
  const metaTools = codeModeMetaTools(EXTERNAL_KB_MANUAL_NAME, examplePool, {
304
- sharedRulesPointer: sharedRulesPointer(this.opts.kbLayout?.()),
305
- });
317
+ sharedRulesPointer: '',
318
+ }).map((tool) => ({ ...tool, description: guideFirstDescription(tool.description) }));
306
319
  // Log only when a tool was dropped (name/schema/duplicate) — that's the
307
320
  // anomaly worth surfacing, since a downstream client would otherwise hide
308
321
  // it by rejecting the whole response.
@@ -316,7 +329,7 @@ export class McpService {
316
329
  };
317
330
  });
318
331
  server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
319
- const { client, tools, unavailable, catalogNames } = await requestSurface();
332
+ const { client, tools, unavailable, catalogNames, hidden: hiddenTools } = await requestSurface();
320
333
  const toolName = request.params.name;
321
334
  const args = request.params.arguments ?? {};
322
335
  if (META_TOOL_NAMES.has(toolName)) {
@@ -359,6 +372,23 @@ export class McpService {
359
372
  };
360
373
  const proxied = tools.find((t) => t.mcpName === toolName);
361
374
  if (!proxied) {
375
+ // A tool this process hid for an invalid schema: say that, rather than
376
+ // "Unknown tool" about a tool the agent has every reason to think
377
+ // exists. The place and the reason are deliberately NOT here — they are
378
+ // for the people who manage the server, who are the only ones who can
379
+ // act on them.
380
+ const hidden = hiddenTools.get(toolName);
381
+ if (hidden) {
382
+ // The UTCP name, as every other audit path records a tool: the
383
+ // flattened agent name loses the server segment of a multi-segment
384
+ // `<manual>.<server>.<tool>`, and an audit trail that names a
385
+ // different tool than the rest of the trail is worse than none.
386
+ if (audit)
387
+ await audit.denied(hidden.utcpName, args);
388
+ return toolError(`The "${toolName}" tool is hidden from agents because its schema is invalid, so it cannot be ` +
389
+ `called. The people who manage its server can see the place in the schema and the reason, on ` +
390
+ `the tool's page in Hexis and through \`list_tool_setup\`.`);
391
+ }
362
392
  // Not on the surface — but if the name belongs to a manual that is off
363
393
  // it only because this caller's sign-in is gone (and nothing in this
364
394
  // process has seen its tools yet), the honest answer is the sign-in
@@ -427,7 +457,7 @@ export class McpService {
427
457
  const manuals = await this.fetchManualTemplates(loopbackBearer);
428
458
  const catalogMs = performance.now() - started;
429
459
  const client = await this.buildClient(loopbackBearer, userId, manuals);
430
- const { tools, unavailable, catalogNames } = await this.discoverTools(client, manuals, userId);
460
+ const { tools, unavailable, catalogNames, hidden } = await this.discoverTools(client, manuals, userId);
431
461
  const totalMs = performance.now() - started;
432
462
  // Per user: on a shape change or once per interval, never per request —
433
463
  // see SurfaceLogThrottle for why both halves matter.
@@ -441,7 +471,7 @@ export class McpService {
441
471
  `(catalog ${catalogMs.toFixed(0)}ms, registration ${(totalMs - catalogMs).toFixed(0)}ms)` +
442
472
  (decision.suppressed > 0 ? ` [+${decision.suppressed} identical rebuild(s) since last line]` : ''));
443
473
  }
444
- return { client, tools, unavailable, catalogNames };
474
+ return { client, tools, unavailable, catalogNames, hidden };
445
475
  }
446
476
  /**
447
477
  * The instructions and tool prefix. A reader failure (a disk fault; ENOENT
@@ -591,11 +621,31 @@ export class McpService {
591
621
  async discoverTools(client, manuals, userId) {
592
622
  const routes = new Map();
593
623
  const unavailable = [];
624
+ // Taken BEFORE a single manual is registered, so it ranks this load by the
625
+ // freshness of what it is about to read — see ToolSchemaGuard.beginLoad.
626
+ const loadId = this.toolSchemas.beginLoad();
594
627
  const catalogNames = new Map();
595
628
  for (const m of manuals) {
596
629
  if (m.call_template_type === 'mcp')
597
630
  catalogNames.set(utcpManualName(m), String(m.name));
598
631
  }
632
+ // Every manual's catalog name, which is how the owner-facing surfaces know
633
+ // it. `catalogNames` above is the credential catalog's map and covers `mcp`
634
+ // manuals only; the schema check is about the tools of every connected
635
+ // server, so it needs the whole list. Taken HERE, before registration:
636
+ // registering a manual renames the template in place, so `m.name` read
637
+ // afterwards is the rewritten identifier and `my-server` would be recorded
638
+ // as `my_server` — a name no tool page ever looks up.
639
+ // Keyed by the rewritten name, which two manuals can share (the collision
640
+ // handled below): the KB manual's entry is the one that stays, since it is
641
+ // the one that is registered when a `.tool` collides with it.
642
+ const manualCatalogNames = new Map();
643
+ for (const m of manuals) {
644
+ const rewritten = utcpManualName(m);
645
+ if (manualCatalogNames.get(rewritten) === EXTERNAL_KB_MANUAL_NAME)
646
+ continue;
647
+ manualCatalogNames.set(rewritten, String(m.name));
648
+ }
599
649
  // The shared layer rewrites every manual name (`[^\w]` → `_`) and tools
600
650
  // route by the rewritten prefix, so two manuals whose names rewrite to one
601
651
  // identifier would silently share it. Sequential registration used to
@@ -677,11 +727,58 @@ export class McpService {
677
727
  if (routes.size > 0)
678
728
  routeToDownstream(client, routes);
679
729
  const utcpTools = await client.getTools();
680
- return {
681
- tools: utcpTools.map((tool) => flattenManualTool(tool, EXTERNAL_KB_MANUAL_NAME)),
682
- unavailable,
683
- catalogNames,
684
- };
730
+ const flattened = utcpTools.map((tool) => flattenManualTool(tool, EXTERNAL_KB_MANUAL_NAME));
731
+ const { tools, hidden } = await this.hideInvalidSchemas(client, flattened, manualCatalogNames, userId, loadId);
732
+ return { tools, unavailable, catalogNames, hidden };
733
+ }
734
+ /**
735
+ * Check the input schema of every tool the servers just advertised, and take
736
+ * the invalid ones OFF the client's tool repository.
737
+ *
738
+ * The repository is the single place `tools/list`, `list_tools`/`tools_info`
739
+ * and the TypeScript interfaces `call_tool_chain` generates are all built
740
+ * from, so removing a tool here removes it from all three — which is what
741
+ * "not offered to agents" has to mean. Its siblings are untouched: the check
742
+ * is per tool, so one bad schema costs that tool and nothing else of the
743
+ * server.
744
+ *
745
+ * A client would otherwise drop such a tool itself, silently, and the agent
746
+ * would be left without it and without a reason. Hidden here, the reason
747
+ * reaches the people who manage the server (see {@link ToolSchemaGuard}).
748
+ */
749
+ async hideInvalidSchemas(client, tools, catalogNames, userId, loadId) {
750
+ const byManual = new Map();
751
+ // EVERY manual of this surface is screened, including the ones that
752
+ // advertised nothing. A server that removed its last invalid tool, and one
753
+ // whose tools never loaded at all (a sign-in that has gone), both come
754
+ // through here with an empty group — and an empty group is what clears the
755
+ // marker. Screening only the groups that have tools would leave the tool
756
+ // page, `list_tool_setup` and the hidden-tool answer on a call all
757
+ // reporting a defect this process can no longer see.
758
+ for (const manual of catalogNames.values())
759
+ byManual.set(manual, []);
760
+ for (const tool of tools) {
761
+ const manual = catalogNames.get(tool.manualName) ?? tool.manualName;
762
+ byManual.set(manual, [...(byManual.get(manual) ?? []), tool]);
763
+ }
764
+ const found = this.toolSchemas.screen(userId, loadId, byManual);
765
+ const hidden = new Map();
766
+ for (const tool of found.values())
767
+ hidden.set(tool.name, tool);
768
+ if (found.size === 0)
769
+ return { tools, hidden };
770
+ for (const utcpName of found.keys()) {
771
+ await client.config.tool_repository.removeTool(utcpName);
772
+ }
773
+ // Logged every time rather than throttled: a hidden tool is the one thing
774
+ // about this surface that a person has to act on, and it is rare.
775
+ log.warn(`hiding ${found.size} connected tool(s) whose input schema is not valid JSON Schema: ` +
776
+ `${[...found.values()].map((t) => `${t.name} (${t.path}: ${t.reason})`).join(', ')}`);
777
+ return { tools: tools.filter((tool) => !found.has(tool.utcpName)), hidden };
778
+ }
779
+ /** The schema findings the owner-facing surfaces report — see {@link ToolSchemaGuard}. */
780
+ get hiddenTools() {
781
+ return this.toolSchemas;
685
782
  }
686
783
  /**
687
784
  * Make one `mcp` manual's tools part of this request's client, backed by the