@cursor/july 0.1.93 → 0.1.94

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 (318) hide show
  1. package/AGENTS.md +8 -20
  2. package/README.md +4 -26
  3. package/dist/channels/slack/attachments.js +2 -2
  4. package/dist/channels/slack/dispatch.d.ts +0 -7
  5. package/dist/channels/slack/dispatch.d.ts.map +1 -1
  6. package/dist/channels/slack/dispatch.js +4 -7
  7. package/dist/channels/slack/eval-directive.d.ts +5 -12
  8. package/dist/channels/slack/eval-directive.d.ts.map +1 -1
  9. package/dist/channels/slack/eval-directive.js +8 -19
  10. package/dist/channels/slack/index.d.ts +0 -6
  11. package/dist/channels/slack/index.d.ts.map +1 -1
  12. package/dist/channels/slack/index.js +0 -6
  13. package/dist/channels/slack/setup.d.ts +4 -4
  14. package/dist/channels/slack/setup.d.ts.map +1 -1
  15. package/dist/channels/slack/setup.js +8 -15
  16. package/dist/channels/slack/slack-channel.d.ts +6 -13
  17. package/dist/channels/slack/slack-channel.d.ts.map +1 -1
  18. package/dist/channels/slack/slack-channel.js +15 -101
  19. package/dist/channels/slack/types.d.ts +12 -79
  20. package/dist/channels/slack/types.d.ts.map +1 -1
  21. package/dist/channels/slack/types.js +1 -15
  22. package/dist/client.d.ts +14 -0
  23. package/dist/client.d.ts.map +1 -0
  24. package/dist/client.js +12 -0
  25. package/dist/connections.d.ts +18 -9
  26. package/dist/connections.d.ts.map +1 -1
  27. package/dist/connections.js +17 -8
  28. package/dist/docs/404.html +2 -2
  29. package/dist/docs/ab.html +4 -4
  30. package/dist/docs/assets/{app.CjWU-x0z.js → app.CFDEas4I.js} +1 -1
  31. package/dist/docs/assets/chunks/@localSearchIndexroot.DU3U2Ij2.js +1 -0
  32. package/dist/docs/assets/chunks/{VPLocalSearchBox.Cxy8ySFQ.js → VPLocalSearchBox.B1IIYpYS.js} +1 -1
  33. package/dist/docs/assets/chunks/{theme.Dvq1Bktu.js → theme.Ct4NSiLm.js} +2 -2
  34. package/dist/docs/assets/concepts.md.lwAgBIMI.js +1 -0
  35. package/dist/docs/assets/{deployment.md.DoLFAzfm.js → deployment.md.D9msOFOW.js} +3 -8
  36. package/dist/docs/assets/{deployment.md.DoLFAzfm.lean.js → deployment.md.D9msOFOW.lean.js} +1 -1
  37. package/dist/docs/assets/{guides_agent-to-agent.md.B3JIaAqz.js → guides_agent-to-agent.md.BDb0t1QV.js} +1 -1
  38. package/dist/docs/assets/guides_cloud-runtime.md.CkYbjnAX.js +9 -0
  39. package/dist/docs/assets/guides_cloud-runtime.md.CkYbjnAX.lean.js +1 -0
  40. package/dist/docs/assets/{guides_convert-automation.md.Bboisykk.js → guides_convert-automation.md.B4sjlodG.js} +1 -1
  41. package/dist/docs/assets/{guides_github.md.DqJhuaN1.js → guides_github.md.Cnh2mL4a.js} +1 -1
  42. package/dist/docs/assets/{guides_mcp-oauth.md.CJvrXtkN.js → guides_mcp-oauth.md.DPYmBCbV.js} +7 -9
  43. package/dist/docs/assets/{guides_mcp-oauth.md.CJvrXtkN.lean.js → guides_mcp-oauth.md.DPYmBCbV.lean.js} +1 -1
  44. package/dist/docs/assets/{guides_slack.md.mqeNKs84.js → guides_slack.md.C32HsdKk.js} +5 -11
  45. package/dist/docs/assets/guides_slack.md.C32HsdKk.lean.js +1 -0
  46. package/dist/docs/assets/index.md.DRakGHFe.js +5 -0
  47. package/dist/docs/assets/{index.md.B-lVR4wT.lean.js → index.md.DRakGHFe.lean.js} +1 -1
  48. package/dist/docs/assets/{quickstart.md.BrmfrrIr.js → quickstart.md.Nj_LjW_a.js} +1 -1
  49. package/dist/docs/assets/{reference_cli.md.D9KESDsD.js → reference_cli.md.Cw6_ICYG.js} +1 -1
  50. package/dist/docs/assets/{reference_connections.md.DB6SsN6U.js → reference_connections.md.BH8Oc0D0.js} +5 -5
  51. package/dist/docs/assets/{reference_connections.md.DB6SsN6U.lean.js → reference_connections.md.BH8Oc0D0.lean.js} +1 -1
  52. package/dist/docs/assets/{reference_hooks.md.BxN87gCw.js → reference_hooks.md.a8BJxMR5.js} +1 -1
  53. package/dist/docs/assets/reference_http-api.md.D89k1mdm.js +11 -0
  54. package/dist/docs/assets/reference_http-api.md.D89k1mdm.lean.js +1 -0
  55. package/dist/docs/assets/reference_project-layout.md.Bv4KOtlB.js +19 -0
  56. package/dist/docs/assets/{reference_skills.md.BFW9retM.js → reference_skills.md.8son6Hjm.js} +3 -3
  57. package/dist/docs/assets/{reference_subagents.md.Xoav0AII.js → reference_subagents.md.CfsIloPm.js} +1 -1
  58. package/dist/docs/assets/{reference_tools.md.DuKvkYWG.js → reference_tools.md.BHeXn2id.js} +3 -3
  59. package/dist/docs/assets/{reference_tools.md.DuKvkYWG.lean.js → reference_tools.md.BHeXn2id.lean.js} +1 -1
  60. package/dist/docs/assets/{templates_pr-autofixer.md.R4K_qytS.js → templates_pr-autofixer.md.DU7dQpor.js} +2 -2
  61. package/dist/docs/assets/{templates_pr-autofixer.md.R4K_qytS.lean.js → templates_pr-autofixer.md.DU7dQpor.lean.js} +1 -1
  62. package/dist/docs/assets/{templates_security-reviewer.md.ByFyRta2.js → templates_security-reviewer.md.CTa7u_l1.js} +2 -2
  63. package/dist/docs/assets/{templates_security-reviewer.md.ByFyRta2.lean.js → templates_security-reviewer.md.CTa7u_l1.lean.js} +1 -1
  64. package/dist/docs/assets/troubleshooting.md.Ctv3T8C2.js +1 -0
  65. package/dist/docs/building-with-agents.html +4 -4
  66. package/dist/docs/concepts.html +5 -5
  67. package/dist/docs/concepts.md +1 -0
  68. package/dist/docs/deployment.html +7 -12
  69. package/dist/docs/deployment.md +1 -20
  70. package/dist/docs/design/agsh.md +406 -0
  71. package/dist/docs/evals.html +4 -4
  72. package/dist/docs/guides/agent-to-agent.html +6 -6
  73. package/dist/docs/guides/agent-to-agent.md +2 -2
  74. package/dist/docs/guides/cloud-runtime.html +6 -6
  75. package/dist/docs/guides/cloud-runtime.md +1 -0
  76. package/dist/docs/guides/convert-automation.html +6 -6
  77. package/dist/docs/guides/convert-automation.md +1 -1
  78. package/dist/docs/guides/github.html +6 -6
  79. package/dist/docs/guides/github.md +4 -4
  80. package/dist/docs/guides/human-in-the-loop.html +4 -4
  81. package/dist/docs/guides/mcp-oauth.html +11 -13
  82. package/dist/docs/guides/mcp-oauth.md +10 -18
  83. package/dist/docs/guides/opentelemetry.html +5 -5
  84. package/dist/docs/guides/slack.html +9 -15
  85. package/dist/docs/guides/slack.md +9 -46
  86. package/dist/docs/guides/webhooks.html +4 -4
  87. package/dist/docs/hashmap.json +1 -1
  88. package/dist/docs/hillclimbing.html +4 -4
  89. package/dist/docs/index.html +6 -6
  90. package/dist/docs/index.md +0 -28
  91. package/dist/docs/llms-full.txt +712 -2830
  92. package/dist/docs/llms.txt +2 -16
  93. package/dist/docs/quickstart.html +6 -6
  94. package/dist/docs/quickstart.md +2 -3
  95. package/dist/docs/reference/agent-config.html +4 -4
  96. package/dist/docs/reference/artifacts.html +4 -4
  97. package/dist/docs/reference/channels.html +4 -4
  98. package/dist/docs/reference/cli.html +6 -6
  99. package/dist/docs/reference/cli.md +2 -1
  100. package/dist/docs/reference/connections.html +9 -9
  101. package/dist/docs/reference/connections.md +15 -11
  102. package/dist/docs/reference/hooks.html +6 -6
  103. package/dist/docs/reference/hooks.md +2 -3
  104. package/dist/docs/reference/http-api.html +6 -6
  105. package/dist/docs/reference/http-api.md +8 -0
  106. package/dist/docs/reference/instructions.html +4 -4
  107. package/dist/docs/reference/playground.html +4 -4
  108. package/dist/docs/reference/project-layout.html +8 -6
  109. package/dist/docs/reference/project-layout.md +5 -1
  110. package/dist/docs/reference/prompt.html +4 -4
  111. package/dist/docs/reference/schedules.html +4 -4
  112. package/dist/docs/reference/sessions.html +4 -4
  113. package/dist/docs/reference/skills.html +7 -7
  114. package/dist/docs/reference/subagents.html +6 -6
  115. package/dist/docs/reference/subagents.md +2 -2
  116. package/dist/docs/reference/tools.html +7 -7
  117. package/dist/docs/reference/tools.md +19 -3
  118. package/dist/docs/scaffolding-agents.html +4 -4
  119. package/dist/docs/storage.html +4 -4
  120. package/dist/docs/templates/agentic-owners.html +4 -4
  121. package/dist/docs/templates/demo.html +4 -4
  122. package/dist/docs/templates/pr-autofixer.html +6 -6
  123. package/dist/docs/templates/pr-autofixer.md +4 -3
  124. package/dist/docs/templates/security-reviewer.html +5 -5
  125. package/dist/docs/templates/security-reviewer.md +2 -3
  126. package/dist/docs/templates/triage.html +4 -4
  127. package/dist/docs/troubleshooting.html +5 -5
  128. package/dist/docs/troubleshooting.md +2 -2
  129. package/dist/index.d.ts +1 -1
  130. package/dist/index.d.ts.map +1 -1
  131. package/dist/index.js +1 -1
  132. package/dist/internal/advertise-tools.d.ts +11 -0
  133. package/dist/internal/advertise-tools.d.ts.map +1 -1
  134. package/dist/internal/advertise-tools.js +47 -9
  135. package/dist/internal/cli-mcp-oauth.d.ts.map +1 -1
  136. package/dist/internal/cli-mcp-oauth.js +7 -4
  137. package/dist/internal/convert-automation/convert-workflow.d.ts.map +1 -1
  138. package/dist/internal/convert-automation/convert-workflow.js +26 -15
  139. package/dist/internal/convert-automation/slug.d.ts +0 -2
  140. package/dist/internal/convert-automation/slug.d.ts.map +1 -1
  141. package/dist/internal/convert-automation/slug.js +0 -8
  142. package/dist/internal/cursor/account-mcp.d.ts.map +1 -1
  143. package/dist/internal/cursor/account-mcp.js +5 -1
  144. package/dist/internal/discovery.d.ts.map +1 -1
  145. package/dist/internal/discovery.js +88 -13
  146. package/dist/internal/hosted-delivery.d.ts.map +1 -1
  147. package/dist/internal/hosted-delivery.js +22 -9
  148. package/dist/internal/mcp-endpoint.js +3 -3
  149. package/dist/internal/mcp-host.d.ts +8 -7
  150. package/dist/internal/mcp-host.d.ts.map +1 -1
  151. package/dist/internal/mcp-host.js +8 -7
  152. package/dist/internal/peer-connections.d.ts.map +1 -1
  153. package/dist/internal/peer-connections.js +5 -1
  154. package/dist/internal/playground/static.d.ts +0 -3
  155. package/dist/internal/playground/static.d.ts.map +1 -1
  156. package/dist/internal/resolved-connections.d.ts.map +1 -1
  157. package/dist/internal/resolved-connections.js +5 -7
  158. package/dist/internal/server.d.ts.map +1 -1
  159. package/dist/internal/server.js +113 -172
  160. package/dist/internal/session-engine.d.ts +45 -10
  161. package/dist/internal/session-engine.d.ts.map +1 -1
  162. package/dist/internal/session-engine.js +208 -65
  163. package/dist/internal/tool-catalog.d.ts +31 -0
  164. package/dist/internal/tool-catalog.d.ts.map +1 -0
  165. package/dist/internal/tool-catalog.js +67 -0
  166. package/dist/playground/assets/{index-D9MFzhNE.js → index-B3JCyigB.js} +1 -1
  167. package/dist/playground/index.html +1 -1
  168. package/dist/types.d.ts +72 -23
  169. package/dist/types.d.ts.map +1 -1
  170. package/dist/types.js +19 -0
  171. package/docs/README.md +0 -28
  172. package/docs/concepts.md +1 -0
  173. package/docs/deployment.md +1 -20
  174. package/docs/design/agsh.md +406 -0
  175. package/docs/guides/agent-to-agent.md +2 -2
  176. package/docs/guides/cloud-runtime.md +1 -0
  177. package/docs/guides/convert-automation.md +1 -1
  178. package/docs/guides/github.md +4 -4
  179. package/docs/guides/mcp-oauth.md +10 -18
  180. package/docs/guides/slack.md +10 -47
  181. package/docs/quickstart.md +2 -3
  182. package/docs/reference/cli.md +2 -1
  183. package/docs/reference/connections.md +15 -11
  184. package/docs/reference/hooks.md +2 -3
  185. package/docs/reference/http-api.md +8 -0
  186. package/docs/reference/project-layout.md +5 -1
  187. package/docs/reference/subagents.md +2 -2
  188. package/docs/reference/tools.md +19 -3
  189. package/docs/templates/pr-autofixer.md +4 -3
  190. package/docs/templates/security-reviewer.md +2 -3
  191. package/docs/troubleshooting.md +2 -2
  192. package/package.json +9 -2
  193. package/skills/create-agent/SKILL.md +6 -13
  194. package/skills/debug/SKILL.md +2 -4
  195. package/skills/evals/SKILL.md +1 -1
  196. package/skills/framework-map/SKILL.md +3 -2
  197. package/skills/mcp-auth/SKILL.md +10 -13
  198. package/skills/setup-slack/SKILL.md +21 -137
  199. package/src/channels/slack/attachments.ts +2 -2
  200. package/src/channels/slack/dispatch.ts +2 -16
  201. package/src/channels/slack/eval-directive.ts +8 -27
  202. package/src/channels/slack/index.ts +0 -6
  203. package/src/channels/slack/setup.ts +8 -15
  204. package/src/channels/slack/slack-channel.ts +14 -125
  205. package/src/channels/slack/types.ts +12 -96
  206. package/src/client.ts +23 -0
  207. package/src/connections.ts +20 -7
  208. package/src/index.ts +2 -0
  209. package/src/internal/advertise-tools.ts +45 -7
  210. package/src/internal/cli-mcp-oauth.ts +6 -4
  211. package/src/internal/convert-automation/convert-workflow.ts +29 -17
  212. package/src/internal/convert-automation/slug.ts +0 -9
  213. package/src/internal/cursor/account-mcp.ts +4 -1
  214. package/src/internal/discovery.ts +104 -13
  215. package/src/internal/fixtures/units-server.ts +52 -0
  216. package/src/internal/hosted-delivery.ts +60 -28
  217. package/src/internal/mcp-endpoint.ts +3 -3
  218. package/src/internal/mcp-host.ts +8 -7
  219. package/src/internal/peer-connections.ts +4 -1
  220. package/src/internal/playground/static.ts +1 -3
  221. package/src/internal/resolved-connections.ts +8 -10
  222. package/src/internal/server.ts +151 -251
  223. package/src/internal/session-engine.ts +254 -69
  224. package/src/internal/tool-catalog.ts +106 -0
  225. package/src/types.ts +90 -23
  226. package/templates/pr-autofixer/agent/channels/slack.ts +8 -2
  227. package/templates/triage/README.md +2 -1
  228. package/templates/triage/overlays/jira/agent/mcp-connections/tracker.ts +0 -1
  229. package/templates/triage/overlays/linear/agent/mcp-connections/tracker.ts +0 -1
  230. package/dist/channels/slack/cursor-account.d.ts +0 -87
  231. package/dist/channels/slack/cursor-account.d.ts.map +0 -1
  232. package/dist/channels/slack/cursor-account.js +0 -100
  233. package/dist/docs/assets/chunks/@localSearchIndexroot.ChpIC3Zy.js +0 -1
  234. package/dist/docs/assets/concepts.md.F6AiPorA.js +0 -1
  235. package/dist/docs/assets/example-agents_approval-buddy.md.DmezILPg.js +0 -10
  236. package/dist/docs/assets/example-agents_approval-buddy.md.DmezILPg.lean.js +0 -1
  237. package/dist/docs/assets/example-agents_benny.md.B0kwY7D_.js +0 -5
  238. package/dist/docs/assets/example-agents_benny.md.B0kwY7D_.lean.js +0 -1
  239. package/dist/docs/assets/example-agents_bugbot.md.BRGMi9O2.js +0 -11
  240. package/dist/docs/assets/example-agents_bugbot.md.BRGMi9O2.lean.js +0 -1
  241. package/dist/docs/assets/example-agents_codebase-wiki.md.BBNw9Ekr.js +0 -8
  242. package/dist/docs/assets/example-agents_codebase-wiki.md.BBNw9Ekr.lean.js +0 -1
  243. package/dist/docs/assets/example-agents_codeowners-review.md.Bfta-lBU.js +0 -8
  244. package/dist/docs/assets/example-agents_codeowners-review.md.Bfta-lBU.lean.js +0 -1
  245. package/dist/docs/assets/example-agents_concierge.md.BzB2b20R.js +0 -22
  246. package/dist/docs/assets/example-agents_concierge.md.BzB2b20R.lean.js +0 -1
  247. package/dist/docs/assets/example-agents_index.md.ChBp0AX6.js +0 -2
  248. package/dist/docs/assets/example-agents_index.md.ChBp0AX6.lean.js +0 -1
  249. package/dist/docs/assets/example-agents_knowledge-base.md.CrA85ig-.js +0 -11
  250. package/dist/docs/assets/example-agents_knowledge-base.md.CrA85ig-.lean.js +0 -1
  251. package/dist/docs/assets/example-agents_oncall.md.DK4XkYTd.js +0 -10
  252. package/dist/docs/assets/example-agents_oncall.md.DK4XkYTd.lean.js +0 -1
  253. package/dist/docs/assets/example-agents_security-reviewer.md.74pPpWYj.js +0 -19
  254. package/dist/docs/assets/example-agents_security-reviewer.md.74pPpWYj.lean.js +0 -1
  255. package/dist/docs/assets/example-agents_slack-agent.md.D7Kdj5BV.js +0 -5
  256. package/dist/docs/assets/example-agents_slack-agent.md.D7Kdj5BV.lean.js +0 -1
  257. package/dist/docs/assets/example-agents_weather-agent.md.CaGpmw3Y.js +0 -25
  258. package/dist/docs/assets/example-agents_weather-agent.md.CaGpmw3Y.lean.js +0 -1
  259. package/dist/docs/assets/guides_cloud-runtime.md.BnvjPiia.js +0 -9
  260. package/dist/docs/assets/guides_cloud-runtime.md.BnvjPiia.lean.js +0 -1
  261. package/dist/docs/assets/guides_slack.md.mqeNKs84.lean.js +0 -1
  262. package/dist/docs/assets/index.md.B-lVR4wT.js +0 -5
  263. package/dist/docs/assets/reference_http-api.md.C68BERYr.js +0 -11
  264. package/dist/docs/assets/reference_http-api.md.C68BERYr.lean.js +0 -1
  265. package/dist/docs/assets/reference_project-layout.md.WN9nwJht.js +0 -17
  266. package/dist/docs/assets/troubleshooting.md.vCWwvqcJ.js +0 -1
  267. package/dist/docs/example-agents/approval-buddy.html +0 -36
  268. package/dist/docs/example-agents/approval-buddy.md +0 -266
  269. package/dist/docs/example-agents/benny.html +0 -31
  270. package/dist/docs/example-agents/benny.md +0 -173
  271. package/dist/docs/example-agents/bugbot.html +0 -37
  272. package/dist/docs/example-agents/bugbot.md +0 -229
  273. package/dist/docs/example-agents/codebase-wiki.html +0 -34
  274. package/dist/docs/example-agents/codebase-wiki.md +0 -167
  275. package/dist/docs/example-agents/codeowners-review.html +0 -34
  276. package/dist/docs/example-agents/codeowners-review.md +0 -192
  277. package/dist/docs/example-agents/concierge.html +0 -48
  278. package/dist/docs/example-agents/concierge.md +0 -200
  279. package/dist/docs/example-agents/index.html +0 -28
  280. package/dist/docs/example-agents/index.md +0 -99
  281. package/dist/docs/example-agents/knowledge-base.html +0 -37
  282. package/dist/docs/example-agents/knowledge-base.md +0 -168
  283. package/dist/docs/example-agents/oncall.html +0 -36
  284. package/dist/docs/example-agents/oncall.md +0 -212
  285. package/dist/docs/example-agents/security-reviewer.html +0 -45
  286. package/dist/docs/example-agents/security-reviewer.md +0 -265
  287. package/dist/docs/example-agents/slack-agent.html +0 -31
  288. package/dist/docs/example-agents/slack-agent.md +0 -142
  289. package/dist/docs/example-agents/weather-agent.html +0 -51
  290. package/dist/docs/example-agents/weather-agent.md +0 -297
  291. package/dist/internal/cursor-slack-relay.d.ts +0 -96
  292. package/dist/internal/cursor-slack-relay.d.ts.map +0 -1
  293. package/dist/internal/cursor-slack-relay.js +0 -176
  294. package/docs/example-agents/approval-buddy.md +0 -271
  295. package/docs/example-agents/benny.md +0 -178
  296. package/docs/example-agents/bugbot.md +0 -234
  297. package/docs/example-agents/codebase-wiki.md +0 -172
  298. package/docs/example-agents/codeowners-review.md +0 -197
  299. package/docs/example-agents/concierge.md +0 -205
  300. package/docs/example-agents/index.md +0 -104
  301. package/docs/example-agents/knowledge-base.md +0 -173
  302. package/docs/example-agents/oncall.md +0 -217
  303. package/docs/example-agents/security-reviewer.md +0 -270
  304. package/docs/example-agents/slack-agent.md +0 -147
  305. package/docs/example-agents/weather-agent.md +0 -302
  306. package/src/channels/slack/cursor-account.ts +0 -202
  307. package/src/internal/cursor-slack-relay.ts +0 -249
  308. /package/dist/docs/assets/{concepts.md.F6AiPorA.lean.js → concepts.md.lwAgBIMI.lean.js} +0 -0
  309. /package/dist/docs/assets/{guides_agent-to-agent.md.B3JIaAqz.lean.js → guides_agent-to-agent.md.BDb0t1QV.lean.js} +0 -0
  310. /package/dist/docs/assets/{guides_convert-automation.md.Bboisykk.lean.js → guides_convert-automation.md.B4sjlodG.lean.js} +0 -0
  311. /package/dist/docs/assets/{guides_github.md.DqJhuaN1.lean.js → guides_github.md.Cnh2mL4a.lean.js} +0 -0
  312. /package/dist/docs/assets/{quickstart.md.BrmfrrIr.lean.js → quickstart.md.Nj_LjW_a.lean.js} +0 -0
  313. /package/dist/docs/assets/{reference_cli.md.D9KESDsD.lean.js → reference_cli.md.Cw6_ICYG.lean.js} +0 -0
  314. /package/dist/docs/assets/{reference_hooks.md.BxN87gCw.lean.js → reference_hooks.md.a8BJxMR5.lean.js} +0 -0
  315. /package/dist/docs/assets/{reference_project-layout.md.WN9nwJht.lean.js → reference_project-layout.md.Bv4KOtlB.lean.js} +0 -0
  316. /package/dist/docs/assets/{reference_skills.md.BFW9retM.lean.js → reference_skills.md.8son6Hjm.lean.js} +0 -0
  317. /package/dist/docs/assets/{reference_subagents.md.Xoav0AII.lean.js → reference_subagents.md.CfsIloPm.lean.js} +0 -0
  318. /package/dist/docs/assets/{troubleshooting.md.vCWwvqcJ.lean.js → troubleshooting.md.Ctv3T8C2.lean.js} +0 -0
@@ -49,6 +49,7 @@ import {
49
49
  type ConnectionTransport,
50
50
  DEFAULT_MODEL,
51
51
  DIRECT_TOOL_CALL_CHANNEL_ID,
52
+ type DiscoveredTool,
52
53
  type HookHandler,
53
54
  type HostContext,
54
55
  type HttpChannelDefinition,
@@ -117,6 +118,7 @@ import {
117
118
  newContinuationKey,
118
119
  newSessionId,
119
120
  newToolCallId,
121
+ parseContinuationToken,
120
122
  } from "./ids.js";
121
123
  import { validateToolInput } from "./json-schema.js";
122
124
  import { McpHost } from "./mcp-host.js";
@@ -136,7 +138,7 @@ import { SessionStore } from "./session-store.js";
136
138
  import { syncSkillsToStore } from "./skills-sync.js";
137
139
  import { StorageCoordinator } from "./storage-coordinator.js";
138
140
  import type { FrameworkSessionStore } from "./storage-roles.js";
139
- import { decideToolCall } from "./tool-policy.js";
141
+ import { decideToolCall, resolveEffect } from "./tool-policy.js";
140
142
  import { normalizeToolResult, toolCallErrorMessage } from "./tool-result.js";
141
143
  import {
142
144
  type EstimateTurnCostFn,
@@ -197,6 +199,30 @@ export class ToolNotDirectlyCallableError extends Error {
197
199
  }
198
200
  }
199
201
 
202
+ export class InvalidContinuationTokenError extends Error {
203
+ constructor(detail: string) {
204
+ super(`Invalid continuation token: ${detail}`);
205
+ this.name = "InvalidContinuationTokenError";
206
+ }
207
+ }
208
+
209
+ /**
210
+ * A session-bound direct call whose harness cwd cannot be materialized and
211
+ * whose effect is not read: a write tool may rely on ctx.workspaceDir being
212
+ * the real session workspace, so it fails typed instead of silently running
213
+ * in a scratch directory.
214
+ */
215
+ export class WorkspaceUnavailableError extends Error {
216
+ constructor(toolName: string, cause: unknown) {
217
+ super(
218
+ `Session workspace unavailable for tool "${toolName}": ${
219
+ cause instanceof Error ? cause.message : String(cause)
220
+ }`
221
+ );
222
+ this.name = "WorkspaceUnavailableError";
223
+ }
224
+ }
225
+
200
226
  export class ToolInputError extends Error {
201
227
  constructor(args: { toolName: string; detail: string }) {
202
228
  super(`Invalid input for tool "${args.toolName}": ${args.detail}`);
@@ -474,7 +500,10 @@ export class SessionEngine {
474
500
  // resolves them; the host-side MCP registry starts with the concrete
475
501
  // connections and gains the rest via setResolvedConnections.
476
502
  this.mcpHost = new McpHost(
477
- options.project.agent.connections.filter(
503
+ [
504
+ ...options.project.agent.connections,
505
+ ...(options.project.agent.hostConnections ?? []),
506
+ ].filter(
478
507
  (connection) => !isSymbolicConnectionTransport(connection.transport)
479
508
  )
480
509
  );
@@ -2148,27 +2177,17 @@ export class SessionEngine {
2148
2177
  * Connection names a cloud turn can only reach through the host connection
2149
2178
  * bridge on the tool MCP endpoint: filtered account connections without a
2150
2179
  * public bridge URL, and host-OAuth connections whose tokens live on this
2151
- * host. `hostOnly` names are never bridged — that flag means the model
2152
- * must not see the connection at all, on any runtime.
2180
+ * host.
2153
2181
  */
2154
2182
  cloudBridgeableConnectionNames(): string[] {
2155
- const hostOnlyNames = new Set(
2156
- this.project.agent.connections
2157
- .filter((connection) => connection.hostOnly === true)
2158
- .map((connection) => connection.name)
2159
- );
2160
2183
  const names: string[] = [];
2161
2184
  for (const connection of this.project.agent.connections) {
2162
- if (
2163
- !hostOnlyNames.has(connection.name) &&
2164
- isHostOauthConnectionTransport(connection.transport)
2165
- ) {
2185
+ if (isHostOauthConnectionTransport(connection.transport)) {
2166
2186
  names.push(connection.name);
2167
2187
  }
2168
2188
  }
2169
2189
  for (const resolved of this.resolvedConnections) {
2170
2190
  if (
2171
- !hostOnlyNames.has(resolved.name) &&
2172
2191
  resolved.accountServersFilter !== undefined &&
2173
2192
  resolved.cloudUrl === undefined
2174
2193
  ) {
@@ -2181,8 +2200,7 @@ export class SessionEngine {
2181
2200
  /**
2182
2201
  * True when cloud turns reach `name` through the host connection bridge —
2183
2202
  * the gate the tool MCP endpoint applies before forwarding a bridge
2184
- * request to `host.mcp`, so `hostOnly` connections (and arbitrary names)
2185
- * stay unreachable from a VM.
2203
+ * request to `host.mcp`, so arbitrary names stay unreachable from a VM.
2186
2204
  */
2187
2205
  isCloudBridgedConnection(name: string): boolean {
2188
2206
  if (this.cloudServerToolsConnection === undefined) {
@@ -2212,10 +2230,11 @@ export class SessionEngine {
2212
2230
  }
2213
2231
 
2214
2232
  /**
2215
- * Authored + resolved MCP servers for a turn. Skips `hostOnly`. On cloud
2216
- * turns, connections whose credential lives on this host filtered
2217
- * account connections without a public bridge URL, host-OAuth servers
2218
- * mount as host connection bridges over the tool MCP endpoint instead of
2233
+ * Authored + resolved MCP servers for a turn. Skips advertised
2234
+ * connections (those surface as named server tools). On cloud turns,
2235
+ * connections whose credential lives on this host filtered account
2236
+ * connections without a public bridge URL, host-OAuth servers mount
2237
+ * as host connection bridges over the tool MCP endpoint instead of
2219
2238
  * being omitted or failing the turn closed.
2220
2239
  */
2221
2240
  private buildMcpServers(
@@ -2229,16 +2248,17 @@ export class SessionEngine {
2229
2248
  return {};
2230
2249
  }
2231
2250
  // Advertised connections surface as named server tools instead of an
2232
- // attached MCP server (each tool appears exactly once), so they are
2233
- // excluded here alongside hostOnly.
2234
- const hostOnlyNames = new Set(
2251
+ // attached MCP server (each tool appears exactly once).
2252
+ const advertisedNames = new Set(
2235
2253
  this.project.agent.connections
2236
- .filter(
2237
- (connection) =>
2238
- connection.hostOnly === true || connection.advertiseTools === true
2239
- )
2254
+ .filter((connection) => connection.advertiseTools === true)
2240
2255
  .map((connection) => connection.name)
2241
2256
  );
2257
+ const hostConnectionNames = new Set(
2258
+ (this.project.agent.hostConnections ?? []).map(
2259
+ (connection) => connection.name
2260
+ )
2261
+ );
2242
2262
  const bridgedNames = new Set(
2243
2263
  runtime === "cloud" &&
2244
2264
  sessionId !== undefined &&
@@ -2250,7 +2270,9 @@ export class SessionEngine {
2250
2270
  assertCloudCanHonorAccountServersFilters({
2251
2271
  runtime,
2252
2272
  resolvedConnections: this.resolvedConnections.filter(
2253
- (resolved) => !hostOnlyNames.has(resolved.name)
2273
+ (resolved) =>
2274
+ !advertisedNames.has(resolved.name) &&
2275
+ !hostConnectionNames.has(resolved.name)
2254
2276
  ),
2255
2277
  bridgedNames,
2256
2278
  });
@@ -2260,7 +2282,10 @@ export class SessionEngine {
2260
2282
  : this.cloudBridgeTransport(sessionId, name);
2261
2283
  const servers: Record<string, ConnectionTransport> = {};
2262
2284
  for (const connection of this.project.agent.connections) {
2263
- if (hostOnlyNames.has(connection.name)) {
2285
+ if (
2286
+ advertisedNames.has(connection.name) ||
2287
+ hostConnectionNames.has(connection.name)
2288
+ ) {
2264
2289
  continue;
2265
2290
  }
2266
2291
  if (isSymbolicConnectionTransport(connection.transport)) {
@@ -2301,7 +2326,10 @@ export class SessionEngine {
2301
2326
  servers[connection.name] = connection.transport;
2302
2327
  }
2303
2328
  for (const resolved of this.resolvedConnections) {
2304
- if (hostOnlyNames.has(resolved.name)) {
2329
+ if (
2330
+ advertisedNames.has(resolved.name) ||
2331
+ hostConnectionNames.has(resolved.name)
2332
+ ) {
2305
2333
  continue;
2306
2334
  }
2307
2335
  const url = runtime === "cloud" ? resolved.cloudUrl : resolved.localUrl;
@@ -2346,16 +2374,14 @@ export class SessionEngine {
2346
2374
 
2347
2375
  /**
2348
2376
  * True when a connection with per-session `auth` attaches to the model
2349
- * (not `hostOnly`, not advertised). These turns set
2377
+ * (not advertised). These turns set
2350
2378
  * {@link RunnerTurnRequest.perSendMcpServers} so the evaluated headers
2351
2379
  * ride every send instead of being pinned on the cached agent handle.
2352
2380
  */
2353
2381
  private hasAttachedAuthedConnections(): boolean {
2354
2382
  return this.project.agent.connections.some(
2355
2383
  (connection) =>
2356
- connection.auth !== undefined &&
2357
- connection.hostOnly !== true &&
2358
- connection.advertiseTools !== true
2384
+ connection.auth !== undefined && connection.advertiseTools !== true
2359
2385
  );
2360
2386
  }
2361
2387
 
@@ -2371,9 +2397,7 @@ export class SessionEngine {
2371
2397
  ): Promise<ReadonlyMap<string, Record<string, string>> | undefined> {
2372
2398
  const authed = this.project.agent.connections.filter(
2373
2399
  (connection) =>
2374
- connection.auth !== undefined &&
2375
- connection.hostOnly !== true &&
2376
- connection.advertiseTools !== true
2400
+ connection.auth !== undefined && connection.advertiseTools !== true
2377
2401
  );
2378
2402
  if (authed.length === 0) {
2379
2403
  return undefined;
@@ -2783,12 +2807,168 @@ export class SessionEngine {
2783
2807
  * with the same `{ content, isError }` envelope the model would see, not
2784
2808
  * an exception.
2785
2809
  */
2810
+ /**
2811
+ * The session identity a direct call (or catalog listing) runs under:
2812
+ * an explicit sessionId, a continuation token resolved to a live (or
2813
+ * restorable) session with the same owner/busy checks a sessionId call
2814
+ * gets, or — when neither maps to a session — a synthetic identity
2815
+ * carrying the token's channel id and continuation key so binding
2816
+ * resolvers (e.g. VFS mounts) can still serve the call.
2817
+ */
2818
+ private async resolveDirectCallIdentity(
2819
+ callId: string,
2820
+ options: Pick<CallToolOptions, "auth" | "sessionId" | "continuationToken">
2821
+ ): Promise<{
2822
+ record: SessionRecord | undefined;
2823
+ session: SessionInfo;
2824
+ workspaceDir: string;
2825
+ scratchDir: string | undefined;
2826
+ }> {
2827
+ if (
2828
+ options.sessionId !== undefined &&
2829
+ options.continuationToken !== undefined
2830
+ ) {
2831
+ throw new InvalidContinuationTokenError(
2832
+ "mutually exclusive with sessionId — a real session already carries its own continuation key"
2833
+ );
2834
+ }
2835
+ const auth = options.auth ?? null;
2836
+ let record: SessionRecord | undefined;
2837
+ let continuation: { channelId: string; key: string } | null = null;
2838
+ if (options.sessionId !== undefined) {
2839
+ record = await this.sessions.get(options.sessionId);
2840
+ if (record === undefined) {
2841
+ throw new UnknownSessionError(options.sessionId);
2842
+ }
2843
+ } else if (options.continuationToken !== undefined) {
2844
+ continuation = parseContinuationToken(options.continuationToken);
2845
+ if (continuation === null) {
2846
+ throw new InvalidContinuationTokenError(
2847
+ `expected "<channelId>:<key>" (as /v1/sessions lists it), got "${options.continuationToken}"`
2848
+ );
2849
+ }
2850
+ // A token that maps to a live (or restorable) session takes the
2851
+ // session path: same owner check, same turn serialization, same
2852
+ // event recording as an explicit sessionId. Skipping those just
2853
+ // because the caller addressed the session by token would fail open.
2854
+ record =
2855
+ (await this.sessions.findByContinuation(
2856
+ continuation.channelId,
2857
+ continuation.key
2858
+ )) ??
2859
+ (await this.restoreSessionByContinuation(
2860
+ continuation.channelId,
2861
+ continuation.key
2862
+ ));
2863
+ if (record !== undefined && !samePrincipal(record.auth, auth)) {
2864
+ throw new SessionAuthError(record.sessionId);
2865
+ }
2866
+ }
2867
+ if (record !== undefined) {
2868
+ // Direct calls respect the same serialization as follow-up sends: a
2869
+ // running model turn owns the session workspace and event stream.
2870
+ if (
2871
+ this.activeTurns.has(record.sessionId) ||
2872
+ this.pendingTurns.has(record.sessionId)
2873
+ ) {
2874
+ throw new SessionBusyError(record.sessionId);
2875
+ }
2876
+ return {
2877
+ record,
2878
+ session: this.sessionInfo(record),
2879
+ workspaceDir: this.harnessCwd(record),
2880
+ scratchDir: undefined,
2881
+ };
2882
+ }
2883
+ // No session behind the token (or no token at all): a synthetic
2884
+ // session carries the token's channel id and key, so binding resolvers
2885
+ // keyed on the continuation key (e.g. VFS mounts) can serve the call
2886
+ // with no live session. The workspace stays scratch and nothing is
2887
+ // recorded on a session event stream.
2888
+ const scratchDir = join(this.stateRoot, "tool-calls", callId);
2889
+ return {
2890
+ record: undefined,
2891
+ session: {
2892
+ id: callId,
2893
+ channelId: continuation?.channelId ?? DIRECT_TOOL_CALL_CHANNEL_ID,
2894
+ mode: "task",
2895
+ continuationKey: continuation?.key,
2896
+ auth,
2897
+ },
2898
+ workspaceDir: scratchDir,
2899
+ scratchDir,
2900
+ };
2901
+ }
2902
+
2903
+ /**
2904
+ * The live tool catalog for one session identity: authored server tools
2905
+ * plus the advertised passthroughs a turn under the same identity would
2906
+ * see, under their model-facing names. A connection whose listing fails
2907
+ * is skipped and reported in `connectionErrors` — the inspection surface
2908
+ * degrades legibly instead of hiding every other tool behind one broken
2909
+ * connector.
2910
+ */
2911
+ async listCatalogTools(
2912
+ options: Pick<
2913
+ CallToolOptions,
2914
+ "auth" | "sessionId" | "continuationToken"
2915
+ > = {}
2916
+ ): Promise<{
2917
+ tools: DiscoveredTool[];
2918
+ connectionErrors: Array<{ connection: string; message: string }>;
2919
+ }> {
2920
+ const { session } = await this.resolveDirectCallIdentity(
2921
+ newToolCallId("catalog"),
2922
+ options
2923
+ );
2924
+ const connectionErrors: Array<{ connection: string; message: string }> = [];
2925
+ const advertised = await resolveAdvertisedTools({
2926
+ agent: this.project.agent,
2927
+ session,
2928
+ hostMcp: this.mcpHost,
2929
+ onConnectionError: (connection, error) => {
2930
+ connectionErrors.push({
2931
+ connection,
2932
+ message: error instanceof Error ? error.message : String(error),
2933
+ });
2934
+ },
2935
+ });
2936
+ return {
2937
+ tools: [...this.project.agent.tools, ...advertised],
2938
+ connectionErrors,
2939
+ };
2940
+ }
2941
+
2786
2942
  async callTool(
2787
2943
  toolName: string,
2788
2944
  input: unknown = {},
2789
2945
  options: CallToolOptions = {}
2790
2946
  ): Promise<ToolCallOutcome> {
2791
- const tool = this.project.agent.tools.find((t) => t.name === toolName);
2947
+ const callId = newToolCallId(toolName);
2948
+ // Identity resolves before the tool lookup: advertised connection tools
2949
+ // only exist relative to a session (per-session auth), so finding them
2950
+ // needs the same identity the call runs under.
2951
+ const identity = await this.resolveDirectCallIdentity(callId, options);
2952
+ const record = identity.record;
2953
+ const session = identity.session;
2954
+ let workspaceDir = identity.workspaceDir;
2955
+ let scratchDir = identity.scratchDir;
2956
+ let tool = this.project.agent.tools.find((t) => t.name === toolName);
2957
+ if (
2958
+ tool === undefined &&
2959
+ this.project.agent.connections.some((c) => c.advertiseTools === true)
2960
+ ) {
2961
+ // Advertised passthroughs are ordinary server tools in the session's
2962
+ // namespace; resolve the live listing so direct calls address them by
2963
+ // the same model-facing name a turn would. A listing failure fails
2964
+ // the call closed, like it fails a turn.
2965
+ const advertised = await resolveAdvertisedTools({
2966
+ agent: this.project.agent,
2967
+ session,
2968
+ hostMcp: this.mcpHost,
2969
+ });
2970
+ tool = advertised.find((t) => t.name === toolName);
2971
+ }
2792
2972
  if (tool === undefined) {
2793
2973
  throw new UnknownToolError(
2794
2974
  toolName,
@@ -2805,47 +2985,51 @@ export class SessionEngine {
2805
2985
  if (!validation.ok) {
2806
2986
  throw new ToolInputError({ toolName, detail: validation.message });
2807
2987
  }
2808
-
2809
- const callId = newToolCallId(toolName);
2810
- const auth = options.auth ?? null;
2811
- let record: SessionRecord | undefined;
2812
- let session: SessionInfo;
2813
- let workspaceDir: string;
2814
- let scratchDir: string | undefined;
2815
- if (options.sessionId !== undefined) {
2816
- record = await this.sessions.get(options.sessionId);
2988
+ let workspaceUnavailable = false;
2989
+ try {
2990
+ await mkdir(workspaceDir, { recursive: true });
2991
+ } catch (error) {
2817
2992
  if (record === undefined) {
2818
- throw new UnknownSessionError(options.sessionId);
2993
+ throw error;
2819
2994
  }
2820
- // Direct calls respect the same serialization as follow-up sends: a
2821
- // running model turn owns the session workspace and event stream.
2822
- if (
2823
- this.activeTurns.has(record.sessionId) ||
2824
- this.pendingTurns.has(record.sessionId)
2825
- ) {
2826
- throw new SessionBusyError(record.sessionId);
2995
+ // A session's harness cwd can be a path the serving process cannot
2996
+ // create (e.g. an absolute `local.cwd` like /repo on a hosted pod
2997
+ // where the sandboxed harness would have made it). Read-effect calls
2998
+ // fall back to a scratch workspace instead of failing: tools that
2999
+ // resolve their state from the session identity (VFS mounts) never
3000
+ // touch ctx.workspaceDir. Advertised passthroughs are relocatable by
3001
+ // construction: their execute body forwards to the connection and
3002
+ // never reads the workspace. A write (or undeclared, which resolves
3003
+ // to write) authored tool may rely on ctx.workspaceDir being the
3004
+ // real session workspace, so silently relocating it is not safe —
3005
+ // fail typed instead.
3006
+ const relocatable =
3007
+ tool.advertised === true ||
3008
+ resolveEffect(tool.definition.effect, validation.value) === "read";
3009
+ if (!relocatable) {
3010
+ throw new WorkspaceUnavailableError(toolName, error);
2827
3011
  }
2828
- session = this.sessionInfo(record);
2829
- workspaceDir = this.harnessCwd(record);
2830
- } else {
2831
- session = {
2832
- id: callId,
2833
- channelId: DIRECT_TOOL_CALL_CHANNEL_ID,
2834
- mode: "task",
2835
- auth,
2836
- };
3012
+ this.logger(
3013
+ `[session] tool ${toolName} workspace unavailable (direct ${callId}); using scratch: ${
3014
+ error instanceof Error ? error.message : String(error)
3015
+ }`
3016
+ );
2837
3017
  scratchDir = join(this.stateRoot, "tool-calls", callId);
2838
3018
  workspaceDir = scratchDir;
3019
+ workspaceUnavailable = true;
3020
+ await mkdir(workspaceDir, { recursive: true });
2839
3021
  }
2840
- await mkdir(workspaceDir, { recursive: true });
2841
3022
  // Match what a model turn would see: session workspaces get the same
2842
3023
  // scaffold as executeTurn (seeds only before the first turn); scratch
2843
3024
  // workspaces are materialized fresh.
2844
3025
  await materializeWorkspace({
2845
3026
  agent: this.project.agent,
2846
3027
  workspaceDir:
2847
- record === undefined ? workspaceDir : this.scaffoldDir(record),
2848
- seed: record === undefined || record.turnCount === 0,
3028
+ record === undefined || workspaceUnavailable
3029
+ ? workspaceDir
3030
+ : this.scaffoldDir(record),
3031
+ seed:
3032
+ record === undefined || workspaceUnavailable || record.turnCount === 0,
2849
3033
  stateRoot: this.stateRoot,
2850
3034
  });
2851
3035
 
@@ -2981,8 +3165,9 @@ export class SessionEngine {
2981
3165
  isError,
2982
3166
  result,
2983
3167
  durationMs,
2984
- ...(errorMessage === undefined ? {} : { errorMessage }),
2985
- ...(record === undefined ? {} : { sessionId: record.sessionId }),
3168
+ errorMessage,
3169
+ sessionId: record?.sessionId,
3170
+ scratchWorkspace: workspaceUnavailable ? true : undefined,
2986
3171
  };
2987
3172
  }
2988
3173
 
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Projections for the live tool catalog (`GET /v1/tools` and
3
+ * `GET /v1/tools/:name`): the session's tool namespace exactly as a turn
4
+ * would assemble it — authored server tools plus advertised MCP
5
+ * passthroughs — under model-facing names.
6
+ *
7
+ * Titles are curated data, never derived from descriptions: advertised
8
+ * tools inherit the upstream server's MCP `annotations.title` (bounded at
9
+ * listing time), and the well-known non-MCP tool names carry a hardcoded
10
+ * title here so every deployment shows the same display names.
11
+ */
12
+
13
+ import type {
14
+ DiscoveredTool,
15
+ JsonSchemaObject,
16
+ ToolEffect,
17
+ ToolExecution,
18
+ } from "../types.js";
19
+
20
+ /**
21
+ * Display names for the well-known tool names that do not come from MCP
22
+ * (authored tools have no title field; adding one to `defineTool` for a
23
+ * presentation concern is not worth the authoring surface).
24
+ */
25
+ const WELL_KNOWN_TOOL_TITLES: Readonly<Record<string, string>> = {
26
+ diff: "Show change diffs",
27
+ glob: "Find files by pattern",
28
+ grep: "Search file contents",
29
+ ls: "List a directory",
30
+ read: "Read a file",
31
+ search: "Search with a typed query",
32
+ write: "Write a file",
33
+ };
34
+
35
+ function catalogTitle(tool: DiscoveredTool): string | undefined {
36
+ if (tool.advertised === true) {
37
+ return tool.annotations?.title;
38
+ }
39
+ return WELL_KNOWN_TOOL_TITLES[tool.name];
40
+ }
41
+
42
+ /**
43
+ * Sand connector identifiers scope the connector name by owner
44
+ * (`dashboard-team-<id>-Buildkite`, `dashboard-<Name>`, `user-<Name>`);
45
+ * the suffix is the human-meaningful name.
46
+ */
47
+ const CONNECTOR_SCOPE_PREFIX = /^(?:dashboard-team-\d+-|dashboard-|user-)/;
48
+
49
+ /**
50
+ * Where a tool comes from, for humans: the upstream connector/plugin name
51
+ * when the tool declares one (the reserved `__conn__` selector's values
52
+ * name it), the connection name otherwise. One aggregating connection
53
+ * (e.g. a tenant `plugins` endpoint) hosts tools from several connectors,
54
+ * and "plugins" tells an operator nothing — "Buildkite" does.
55
+ */
56
+ function catalogSource(tool: DiscoveredTool): string | undefined {
57
+ if (tool.advertised !== true) {
58
+ return undefined;
59
+ }
60
+ const properties = tool.inputSchema.properties as
61
+ | Record<string, { enum?: unknown[] } | undefined>
62
+ | undefined;
63
+ const first = properties?.__conn__?.enum?.[0];
64
+ if (typeof first === "string" && first !== "") {
65
+ return first.replace(CONNECTOR_SCOPE_PREFIX, "");
66
+ }
67
+ return tool.connection;
68
+ }
69
+
70
+ /** Light listing entry: identifiers and curated display data only. */
71
+ export interface CatalogListEntry {
72
+ name: string;
73
+ title?: string;
74
+ /** Connection name for advertised MCP tools; absent for authored tools. */
75
+ source?: string;
76
+ }
77
+
78
+ /** Full description behind `GET /v1/tools/:name`. */
79
+ export interface CatalogDetailEntry extends CatalogListEntry {
80
+ description: string;
81
+ execution: ToolExecution;
82
+ needsApproval: boolean;
83
+ effect?: ToolEffect | "dynamic";
84
+ inputSchema: JsonSchemaObject;
85
+ outputSchema?: JsonSchemaObject;
86
+ }
87
+
88
+ export function catalogListEntry(tool: DiscoveredTool): CatalogListEntry {
89
+ return {
90
+ name: tool.name,
91
+ title: catalogTitle(tool),
92
+ source: catalogSource(tool),
93
+ };
94
+ }
95
+
96
+ export function catalogDetailEntry(tool: DiscoveredTool): CatalogDetailEntry {
97
+ return {
98
+ ...catalogListEntry(tool),
99
+ description: tool.description,
100
+ execution: tool.execution,
101
+ needsApproval: tool.needsApproval,
102
+ effect: tool.effect,
103
+ inputSchema: tool.inputSchema,
104
+ outputSchema: tool.outputSchema,
105
+ };
106
+ }