@cursor/july 0.1.99 → 0.1.101

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 (420) hide show
  1. package/AGENTS.md +4 -2
  2. package/dist/bin/agent-serve.js +3 -2
  3. package/dist/channels/deployments/deployments-channel.d.ts +41 -5
  4. package/dist/channels/deployments/deployments-channel.d.ts.map +1 -1
  5. package/dist/channels/deployments/deployments-channel.js +88 -8
  6. package/dist/channels/deployments/types.d.ts +4 -3
  7. package/dist/channels/deployments/types.d.ts.map +1 -1
  8. package/dist/channels/github/defaults.d.ts.map +1 -1
  9. package/dist/channels/github/defaults.js +28 -3
  10. package/dist/channels/github/progress.d.ts +7 -0
  11. package/dist/channels/github/progress.d.ts.map +1 -1
  12. package/dist/channels/origin/defaults.d.ts +43 -0
  13. package/dist/channels/origin/defaults.d.ts.map +1 -0
  14. package/dist/channels/origin/defaults.js +111 -0
  15. package/dist/channels/origin/index.d.ts +2 -0
  16. package/dist/channels/origin/index.d.ts.map +1 -1
  17. package/dist/channels/origin/index.js +2 -0
  18. package/dist/channels/origin/origin-channel.d.ts +2 -1
  19. package/dist/channels/origin/origin-channel.d.ts.map +1 -1
  20. package/dist/channels/origin/origin-channel.js +24 -3
  21. package/dist/channels/origin/state.d.ts +32 -0
  22. package/dist/channels/origin/state.d.ts.map +1 -0
  23. package/dist/channels/origin/state.js +23 -0
  24. package/dist/channels/origin/types.d.ts +23 -1
  25. package/dist/channels/origin/types.d.ts.map +1 -1
  26. package/dist/channels/slack/api.d.ts +16 -7
  27. package/dist/channels/slack/api.d.ts.map +1 -1
  28. package/dist/channels/slack/api.js +31 -14
  29. package/dist/channels/slack/code-fences.d.ts +17 -0
  30. package/dist/channels/slack/code-fences.d.ts.map +1 -0
  31. package/dist/channels/slack/code-fences.js +168 -0
  32. package/dist/channels/slack/constants.d.ts +6 -0
  33. package/dist/channels/slack/constants.d.ts.map +1 -1
  34. package/dist/channels/slack/constants.js +6 -0
  35. package/dist/channels/slack/defaults.d.ts +9 -4
  36. package/dist/channels/slack/defaults.d.ts.map +1 -1
  37. package/dist/channels/slack/defaults.js +154 -76
  38. package/dist/channels/slack/dispatch.d.ts.map +1 -1
  39. package/dist/channels/slack/dispatch.js +3 -3
  40. package/dist/channels/slack/inbound.d.ts +9 -0
  41. package/dist/channels/slack/inbound.d.ts.map +1 -1
  42. package/dist/channels/slack/inbound.js +14 -0
  43. package/dist/channels/slack/index.d.ts +2 -0
  44. package/dist/channels/slack/index.d.ts.map +1 -1
  45. package/dist/channels/slack/index.js +2 -0
  46. package/dist/channels/slack/live-delivery.d.ts +5 -0
  47. package/dist/channels/slack/live-delivery.d.ts.map +1 -1
  48. package/dist/channels/slack/live-delivery.js +116 -21
  49. package/dist/channels/slack/reasoning-card.d.ts +38 -0
  50. package/dist/channels/slack/reasoning-card.d.ts.map +1 -0
  51. package/dist/channels/slack/reasoning-card.js +104 -0
  52. package/dist/channels/slack/redact.d.ts +2 -0
  53. package/dist/channels/slack/redact.d.ts.map +1 -0
  54. package/dist/channels/slack/redact.js +5 -0
  55. package/dist/channels/slack/reply-options.d.ts +40 -0
  56. package/dist/channels/slack/reply-options.d.ts.map +1 -0
  57. package/dist/channels/slack/reply-options.js +150 -0
  58. package/dist/channels/slack/slack-channel.d.ts.map +1 -1
  59. package/dist/channels/slack/slack-channel.js +8 -4
  60. package/dist/channels/slack/stream.d.ts +22 -10
  61. package/dist/channels/slack/stream.d.ts.map +1 -1
  62. package/dist/channels/slack/stream.js +9 -16
  63. package/dist/channels/slack/tool-cards.d.ts +22 -0
  64. package/dist/channels/slack/tool-cards.d.ts.map +1 -0
  65. package/dist/channels/slack/tool-cards.js +178 -0
  66. package/dist/channels/slack/types.d.ts +145 -6
  67. package/dist/channels/slack/types.d.ts.map +1 -1
  68. package/dist/connections.d.ts +18 -2
  69. package/dist/connections.d.ts.map +1 -1
  70. package/dist/connections.js +18 -2
  71. package/dist/docs/404.html +2 -2
  72. package/dist/docs/ab.html +6 -6
  73. package/dist/docs/ab.md +1 -1
  74. package/dist/docs/assets/{ab.md.DJo5r4R-.js → ab.md.mlVgqvSk.js} +1 -1
  75. package/dist/docs/assets/{app.BplEAZ3S.js → app.BASO9Kih.js} +1 -1
  76. package/dist/docs/assets/{building-with-agents.md.DI4mEzlt.js → building-with-agents.md.CUSWxlP_.js} +2 -2
  77. package/dist/docs/assets/chunks/@localSearchIndexroot.DbFXINq2.js +1 -0
  78. package/dist/docs/assets/chunks/{VPLocalSearchBox.CHXyv4wP.js → VPLocalSearchBox.DwkqxoE0.js} +1 -1
  79. package/dist/docs/assets/chunks/{theme.BTcsZmjQ.js → theme.CCil_13e.js} +2 -2
  80. package/dist/docs/assets/{evals.md.lfJoEVc8.js → evals.md.CPzDAwoH.js} +1 -1
  81. package/dist/docs/assets/{guides_github.md.Cnh2mL4a.js → guides_github.md.BtPr9GaP.js} +1 -1
  82. package/dist/docs/assets/{guides_mcp-oauth.md.CN-6YmTJ.js → guides_mcp-oauth.md.Dp6cDP7f.js} +1 -1
  83. package/dist/docs/assets/{guides_opentelemetry.md.bmPmkvJu.js → guides_opentelemetry.md.BVTXDCRg.js} +2 -2
  84. package/dist/docs/assets/{guides_slack.md.VDXQV3ja.js → guides_slack.md.9oHPye9o.js} +19 -3
  85. package/dist/docs/assets/{guides_slack.md.VDXQV3ja.lean.js → guides_slack.md.9oHPye9o.lean.js} +1 -1
  86. package/dist/docs/assets/hillclimbing.md.CpTGTCle.js +4 -0
  87. package/dist/docs/assets/{index.md.CVeRUOeZ.js → index.md.Bb4k8kUm.js} +1 -1
  88. package/dist/docs/assets/{quickstart.md.Nj_LjW_a.js → quickstart.md.DdQOF7Y8.js} +1 -1
  89. package/dist/docs/assets/{reference_connections.md.DxldvyIB.js → reference_connections.md.Di6jJAXF.js} +13 -3
  90. package/dist/docs/assets/{reference_connections.md.DxldvyIB.lean.js → reference_connections.md.Di6jJAXF.lean.js} +1 -1
  91. package/dist/docs/assets/{reference_http-api.md.BEJx9XVj.js → reference_http-api.md.oySXBO8o.js} +1 -1
  92. package/dist/docs/assets/scaffolding-agents.md.em43xlY1.js +1 -0
  93. package/dist/docs/assets/skills_ab.md.CsFNatVx.js +26 -0
  94. package/dist/docs/assets/skills_ab.md.CsFNatVx.lean.js +1 -0
  95. package/dist/docs/assets/skills_create-agent.md.BVoWPcan.js +8 -0
  96. package/dist/docs/assets/skills_create-agent.md.BVoWPcan.lean.js +1 -0
  97. package/dist/docs/assets/skills_debug.md.CDbPhHfg.js +1 -0
  98. package/dist/docs/assets/skills_debug.md.CDbPhHfg.lean.js +1 -0
  99. package/dist/docs/assets/skills_evals.md.723kpUmA.js +25 -0
  100. package/dist/docs/assets/skills_evals.md.723kpUmA.lean.js +1 -0
  101. package/dist/docs/assets/skills_framework-map.md.BTi817yv.js +1 -0
  102. package/dist/docs/assets/skills_framework-map.md.BTi817yv.lean.js +1 -0
  103. package/dist/docs/assets/skills_github.md.D0JahM8c.js +16 -0
  104. package/dist/docs/assets/skills_github.md.D0JahM8c.lean.js +1 -0
  105. package/dist/docs/assets/skills_hillclimb.md.B_zJerxA.js +7 -0
  106. package/dist/docs/assets/skills_hillclimb.md.B_zJerxA.lean.js +1 -0
  107. package/dist/docs/assets/skills_index.md.DKwIxzGg.js +1 -0
  108. package/dist/docs/assets/skills_index.md.DKwIxzGg.lean.js +1 -0
  109. package/dist/docs/assets/skills_mcp-auth.md.DGvFP3HE.js +18 -0
  110. package/dist/docs/assets/skills_mcp-auth.md.DGvFP3HE.lean.js +1 -0
  111. package/dist/docs/assets/skills_otel.md.CgiZryR3.js +8 -0
  112. package/dist/docs/assets/skills_otel.md.CgiZryR3.lean.js +1 -0
  113. package/dist/docs/assets/skills_setup-slack.md.BBgx8lUz.js +20 -0
  114. package/dist/docs/assets/skills_setup-slack.md.BBgx8lUz.lean.js +1 -0
  115. package/dist/docs/assets/{troubleshooting.md.DCiPBhYs.js → troubleshooting.md.Cus_YZga.js} +1 -1
  116. package/dist/docs/building-with-agents.html +6 -6
  117. package/dist/docs/building-with-agents.md +14 -11
  118. package/dist/docs/concepts.html +4 -4
  119. package/dist/docs/deployment.html +4 -4
  120. package/dist/docs/evals.html +6 -6
  121. package/dist/docs/evals.md +1 -1
  122. package/dist/docs/guides/agent-to-agent.html +4 -4
  123. package/dist/docs/guides/cloud-runtime.html +4 -4
  124. package/dist/docs/guides/convert-automation.html +4 -4
  125. package/dist/docs/guides/github.html +5 -5
  126. package/dist/docs/guides/github.md +1 -1
  127. package/dist/docs/guides/human-in-the-loop.html +4 -4
  128. package/dist/docs/guides/mcp-oauth.html +5 -5
  129. package/dist/docs/guides/mcp-oauth.md +1 -1
  130. package/dist/docs/guides/opentelemetry.html +7 -7
  131. package/dist/docs/guides/opentelemetry.md +2 -2
  132. package/dist/docs/guides/slack.html +22 -6
  133. package/dist/docs/guides/slack.md +80 -1
  134. package/dist/docs/guides/webhooks.html +5 -5
  135. package/dist/docs/hashmap.json +1 -1
  136. package/dist/docs/hillclimbing.html +6 -6
  137. package/dist/docs/hillclimbing.md +5 -5
  138. package/dist/docs/index.html +6 -6
  139. package/dist/docs/index.md +1 -1
  140. package/dist/docs/llms-full.txt +1073 -31
  141. package/dist/docs/llms.txt +14 -0
  142. package/dist/docs/quickstart.html +5 -5
  143. package/dist/docs/quickstart.md +1 -1
  144. package/dist/docs/reference/agent-config.html +4 -4
  145. package/dist/docs/reference/artifacts.html +4 -4
  146. package/dist/docs/reference/channels.html +4 -4
  147. package/dist/docs/reference/cli.html +4 -4
  148. package/dist/docs/reference/connections.html +17 -7
  149. package/dist/docs/reference/connections.md +32 -1
  150. package/dist/docs/reference/hooks.html +4 -4
  151. package/dist/docs/reference/http-api.html +6 -6
  152. package/dist/docs/reference/http-api.md +1 -1
  153. package/dist/docs/reference/instructions.html +4 -4
  154. package/dist/docs/reference/playground.html +4 -4
  155. package/dist/docs/reference/project-layout.html +4 -4
  156. package/dist/docs/reference/prompt.html +4 -4
  157. package/dist/docs/reference/schedules.html +4 -4
  158. package/dist/docs/reference/sessions.html +4 -4
  159. package/dist/docs/reference/skills.html +4 -4
  160. package/dist/docs/reference/subagents.html +4 -4
  161. package/dist/docs/reference/tools.html +4 -4
  162. package/dist/docs/scaffolding-agents.html +5 -5
  163. package/dist/docs/scaffolding-agents.md +3 -3
  164. package/dist/docs/skills/ab.html +52 -0
  165. package/dist/docs/skills/ab.md +50 -0
  166. package/dist/docs/skills/create-agent.html +34 -0
  167. package/dist/docs/skills/create-agent.md +160 -0
  168. package/dist/docs/skills/debug.html +27 -0
  169. package/dist/docs/skills/debug.md +36 -0
  170. package/dist/docs/skills/evals.html +51 -0
  171. package/dist/docs/skills/evals.md +99 -0
  172. package/dist/docs/skills/framework-map.html +27 -0
  173. package/dist/docs/skills/framework-map.md +95 -0
  174. package/dist/docs/skills/github.html +42 -0
  175. package/dist/docs/skills/github.md +93 -0
  176. package/dist/docs/skills/hillclimb.html +33 -0
  177. package/dist/docs/skills/hillclimb.md +55 -0
  178. package/dist/docs/skills/index.html +27 -0
  179. package/dist/docs/skills/index.md +21 -0
  180. package/dist/docs/skills/mcp-auth.html +44 -0
  181. package/dist/docs/skills/mcp-auth.md +76 -0
  182. package/dist/docs/skills/otel.html +34 -0
  183. package/dist/docs/skills/otel.md +48 -0
  184. package/dist/docs/skills/setup-slack.html +46 -0
  185. package/dist/docs/skills/setup-slack.md +141 -0
  186. package/dist/docs/storage.html +4 -4
  187. package/dist/docs/templates/agentic-owners.html +4 -4
  188. package/dist/docs/templates/agents-md.html +4 -4
  189. package/dist/docs/templates/code-wiki.html +4 -4
  190. package/dist/docs/templates/demo.html +4 -4
  191. package/dist/docs/templates/pr-autofixer.html +4 -4
  192. package/dist/docs/templates/security-help.html +4 -4
  193. package/dist/docs/templates/security-reviewer.html +4 -4
  194. package/dist/docs/templates/triage.html +4 -4
  195. package/dist/docs/troubleshooting.html +5 -5
  196. package/dist/docs/troubleshooting.md +1 -1
  197. package/dist/extensions/cursor-cloud-agents/extension.d.ts +55 -0
  198. package/dist/extensions/cursor-cloud-agents/extension.d.ts.map +1 -0
  199. package/dist/extensions/cursor-cloud-agents/extension.js +64 -0
  200. package/dist/extensions/cursor-cloud-agents/lib/cloud.d.ts +30 -0
  201. package/dist/extensions/cursor-cloud-agents/lib/cloud.d.ts.map +1 -0
  202. package/dist/extensions/cursor-cloud-agents/lib/cloud.js +45 -0
  203. package/dist/extensions/cursor-cloud-agents/lib/fleet.d.ts +25 -0
  204. package/dist/extensions/cursor-cloud-agents/lib/fleet.d.ts.map +1 -0
  205. package/dist/extensions/cursor-cloud-agents/lib/fleet.js +85 -0
  206. package/dist/extensions/cursor-cloud-agents/lib/repos.d.ts +15 -0
  207. package/dist/extensions/cursor-cloud-agents/lib/repos.d.ts.map +1 -0
  208. package/dist/extensions/cursor-cloud-agents/lib/repos.js +55 -0
  209. package/dist/extensions/cursor-cloud-agents/skills/handoff.md +27 -0
  210. package/dist/extensions/cursor-cloud-agents/tools/follow_up.d.ts +4 -0
  211. package/dist/extensions/cursor-cloud-agents/tools/follow_up.d.ts.map +1 -0
  212. package/dist/extensions/cursor-cloud-agents/tools/follow_up.js +37 -0
  213. package/dist/extensions/cursor-cloud-agents/tools/launch.d.ts +4 -0
  214. package/dist/extensions/cursor-cloud-agents/tools/launch.d.ts.map +1 -0
  215. package/dist/extensions/cursor-cloud-agents/tools/launch.js +83 -0
  216. package/dist/extensions/cursor-cloud-agents/tools/list.d.ts +4 -0
  217. package/dist/extensions/cursor-cloud-agents/tools/list.d.ts.map +1 -0
  218. package/dist/extensions/cursor-cloud-agents/tools/list.js +36 -0
  219. package/dist/extensions/cursor-cloud-agents/tools/status.d.ts +4 -0
  220. package/dist/extensions/cursor-cloud-agents/tools/status.d.ts.map +1 -0
  221. package/dist/extensions/cursor-cloud-agents/tools/status.js +41 -0
  222. package/dist/extensions.d.ts +49 -0
  223. package/dist/extensions.d.ts.map +1 -0
  224. package/dist/extensions.js +75 -0
  225. package/dist/files-backends/cursor-hosted.d.ts +6 -0
  226. package/dist/files-backends/cursor-hosted.d.ts.map +1 -1
  227. package/dist/files-backends/cursor-hosted.js +6 -9
  228. package/dist/index.d.ts +2 -1
  229. package/dist/index.d.ts.map +1 -1
  230. package/dist/index.js +2 -1
  231. package/dist/internal/advertise-tools.d.ts +4 -1
  232. package/dist/internal/advertise-tools.d.ts.map +1 -1
  233. package/dist/internal/advertise-tools.js +20 -1
  234. package/dist/internal/as-of.d.ts +18 -0
  235. package/dist/internal/as-of.d.ts.map +1 -1
  236. package/dist/internal/as-of.js +131 -0
  237. package/dist/internal/cli-deploy.d.ts.map +1 -1
  238. package/dist/internal/cli-deploy.js +66 -21
  239. package/dist/internal/continuation-identity.d.ts.map +1 -1
  240. package/dist/internal/continuation-identity.js +3 -1
  241. package/dist/internal/conversation-mirror.d.ts.map +1 -1
  242. package/dist/internal/conversation-mirror.js +3 -4
  243. package/dist/internal/cursor/hosted-deployment-secrets.d.ts +16 -0
  244. package/dist/internal/cursor/hosted-deployment-secrets.d.ts.map +1 -0
  245. package/dist/internal/cursor/hosted-deployment-secrets.js +61 -0
  246. package/dist/internal/cursor/hosted-store-secrets.d.ts +15 -0
  247. package/dist/internal/cursor/hosted-store-secrets.d.ts.map +1 -0
  248. package/dist/internal/cursor/hosted-store-secrets.js +48 -0
  249. package/dist/internal/cursor-deployment-relay.d.ts +15 -1
  250. package/dist/internal/cursor-deployment-relay.d.ts.map +1 -1
  251. package/dist/internal/cursor-deployment-relay.js +46 -7
  252. package/dist/internal/deploy-client.d.ts +29 -6
  253. package/dist/internal/deploy-client.d.ts.map +1 -1
  254. package/dist/internal/deploy-client.js +61 -19
  255. package/dist/internal/discovery.d.ts.map +1 -1
  256. package/dist/internal/discovery.js +426 -121
  257. package/dist/internal/distribution.d.ts.map +1 -1
  258. package/dist/internal/distribution.js +5 -0
  259. package/dist/internal/framework-file-storage.d.ts +15 -8
  260. package/dist/internal/framework-file-storage.d.ts.map +1 -1
  261. package/dist/internal/framework-file-storage.js +70 -10
  262. package/dist/internal/framework-storage-selection.d.ts +12 -12
  263. package/dist/internal/framework-storage-selection.d.ts.map +1 -1
  264. package/dist/internal/framework-storage-selection.js +33 -39
  265. package/dist/internal/hosted-delivery.d.ts +3 -1
  266. package/dist/internal/hosted-delivery.d.ts.map +1 -1
  267. package/dist/internal/hosted-delivery.js +19 -32
  268. package/dist/internal/hosted-execution-diag.d.ts +5 -0
  269. package/dist/internal/hosted-execution-diag.d.ts.map +1 -1
  270. package/dist/internal/hosted-execution-diag.js +5 -0
  271. package/dist/internal/hosted-execution-flush.d.ts +46 -0
  272. package/dist/internal/hosted-execution-flush.d.ts.map +1 -0
  273. package/dist/internal/hosted-execution-flush.js +81 -0
  274. package/dist/internal/mcp-endpoint.js +1 -0
  275. package/dist/internal/mcp-host.d.ts +2 -1
  276. package/dist/internal/mcp-host.d.ts.map +1 -1
  277. package/dist/internal/mcp-host.js +35 -15
  278. package/dist/internal/review-comments.d.ts +1 -1
  279. package/dist/internal/review-comments.d.ts.map +1 -1
  280. package/dist/internal/review-comments.js +4 -4
  281. package/dist/internal/server.d.ts +3 -0
  282. package/dist/internal/server.d.ts.map +1 -1
  283. package/dist/internal/server.js +79 -104
  284. package/dist/internal/session-engine.d.ts +9 -7
  285. package/dist/internal/session-engine.d.ts.map +1 -1
  286. package/dist/internal/session-engine.js +45 -34
  287. package/dist/internal/session-run-log.d.ts +5 -4
  288. package/dist/internal/session-run-log.d.ts.map +1 -1
  289. package/dist/internal/session-run-log.js +8 -8
  290. package/dist/internal/start-log-store.d.ts +60 -0
  291. package/dist/internal/start-log-store.d.ts.map +1 -0
  292. package/dist/internal/start-log-store.js +151 -0
  293. package/dist/internal/storage-coordinator.d.ts +0 -6
  294. package/dist/internal/storage-coordinator.d.ts.map +1 -1
  295. package/dist/internal/storage-coordinator.js +1 -9
  296. package/dist/internal/tool-policy.d.ts +8 -0
  297. package/dist/internal/tool-policy.d.ts.map +1 -1
  298. package/dist/internal/tool-policy.js +19 -7
  299. package/dist/playground/assets/{index-jzNbJENa.js → index-BnNN1-EK.js} +45 -45
  300. package/dist/playground/assets/index-DBQCwFp0.css +1 -0
  301. package/dist/playground/index.html +2 -2
  302. package/dist/storage-backends/cursor-hosted-v2.d.ts +83 -0
  303. package/dist/storage-backends/cursor-hosted-v2.d.ts.map +1 -0
  304. package/dist/storage-backends/cursor-hosted-v2.js +164 -0
  305. package/dist/storage-backends/cursor-hosted.d.ts +6 -0
  306. package/dist/storage-backends/cursor-hosted.d.ts.map +1 -1
  307. package/dist/storage-backends/cursor-hosted.js +6 -1
  308. package/dist/storage-protocol.d.ts +24 -0
  309. package/dist/storage-protocol.d.ts.map +1 -1
  310. package/dist/storage-protocol.js +33 -0
  311. package/dist/storage.d.ts +1 -1
  312. package/dist/storage.d.ts.map +1 -1
  313. package/dist/storage.js +1 -1
  314. package/dist/types.d.ts +123 -6
  315. package/dist/types.d.ts.map +1 -1
  316. package/dist/types.js +29 -1
  317. package/docs/README.md +1 -1
  318. package/docs/ab.md +1 -1
  319. package/docs/building-with-agents.md +14 -11
  320. package/docs/evals.md +1 -1
  321. package/docs/guides/github.md +1 -1
  322. package/docs/guides/mcp-oauth.md +1 -1
  323. package/docs/guides/opentelemetry.md +2 -2
  324. package/docs/guides/slack.md +80 -1
  325. package/docs/hillclimbing.md +5 -5
  326. package/docs/quickstart.md +1 -1
  327. package/docs/reference/connections.md +32 -1
  328. package/docs/reference/http-api.md +1 -1
  329. package/docs/scaffolding-agents.md +3 -3
  330. package/docs/skills/index.md +26 -0
  331. package/docs/troubleshooting.md +1 -1
  332. package/package.json +18 -4
  333. package/src/bin/agent-serve.ts +11 -2
  334. package/src/channels/deployments/deployments-channel.ts +117 -8
  335. package/src/channels/deployments/types.ts +4 -3
  336. package/src/channels/github/defaults.ts +36 -3
  337. package/src/channels/github/progress.ts +7 -0
  338. package/src/channels/origin/defaults.ts +143 -0
  339. package/src/channels/origin/index.ts +2 -0
  340. package/src/channels/origin/origin-channel.ts +37 -1
  341. package/src/channels/origin/state.ts +54 -0
  342. package/src/channels/origin/types.ts +24 -0
  343. package/src/channels/slack/api.ts +37 -18
  344. package/src/channels/slack/code-fences.ts +183 -0
  345. package/src/channels/slack/constants.ts +6 -0
  346. package/src/channels/slack/defaults.ts +173 -92
  347. package/src/channels/slack/dispatch.ts +8 -1
  348. package/src/channels/slack/inbound.ts +17 -0
  349. package/src/channels/slack/index.ts +2 -0
  350. package/src/channels/slack/live-delivery.ts +142 -28
  351. package/src/channels/slack/reasoning-card.ts +140 -0
  352. package/src/channels/slack/redact.ts +6 -0
  353. package/src/channels/slack/reply-options.ts +229 -0
  354. package/src/channels/slack/slack-channel.ts +7 -2
  355. package/src/channels/slack/stream.ts +31 -24
  356. package/src/channels/slack/tool-cards.ts +221 -0
  357. package/src/channels/slack/types.ts +159 -6
  358. package/src/connections.ts +18 -1
  359. package/src/extensions/cursor-cloud-agents/extension.ts +118 -0
  360. package/src/extensions/cursor-cloud-agents/lib/cloud.ts +79 -0
  361. package/src/extensions/cursor-cloud-agents/lib/fleet.ts +109 -0
  362. package/src/extensions/cursor-cloud-agents/lib/repos.ts +81 -0
  363. package/src/extensions/cursor-cloud-agents/skills/handoff.md +27 -0
  364. package/src/extensions/cursor-cloud-agents/tools/follow_up.ts +29 -0
  365. package/src/extensions/cursor-cloud-agents/tools/launch.ts +84 -0
  366. package/src/extensions/cursor-cloud-agents/tools/list.ts +31 -0
  367. package/src/extensions/cursor-cloud-agents/tools/status.ts +39 -0
  368. package/src/extensions.ts +98 -0
  369. package/src/files-backends/cursor-hosted.ts +15 -5
  370. package/src/index.ts +2 -0
  371. package/src/internal/advertise-tools.ts +37 -12
  372. package/src/internal/as-of.ts +163 -0
  373. package/src/internal/cli-deploy.ts +88 -25
  374. package/src/internal/continuation-identity.ts +3 -1
  375. package/src/internal/conversation-mirror.ts +3 -8
  376. package/src/internal/cursor/hosted-deployment-secrets.ts +72 -0
  377. package/src/internal/cursor/hosted-store-secrets.ts +72 -0
  378. package/src/internal/cursor-deployment-relay.ts +65 -8
  379. package/src/internal/deploy-client.ts +83 -28
  380. package/src/internal/discovery.ts +479 -114
  381. package/src/internal/distribution.ts +5 -0
  382. package/src/internal/framework-file-storage.ts +80 -10
  383. package/src/internal/framework-storage-selection.ts +31 -44
  384. package/src/internal/hosted-delivery.ts +38 -63
  385. package/src/internal/hosted-execution-diag.ts +6 -0
  386. package/src/internal/hosted-execution-flush.ts +142 -0
  387. package/src/internal/mcp-endpoint.ts +1 -0
  388. package/src/internal/mcp-host.ts +40 -14
  389. package/src/internal/review-comments.ts +5 -2
  390. package/src/internal/server.ts +81 -100
  391. package/src/internal/session-engine.ts +56 -28
  392. package/src/internal/session-run-log.ts +8 -12
  393. package/src/internal/start-log-store.ts +177 -0
  394. package/src/internal/storage-coordinator.ts +1 -11
  395. package/src/internal/tool-policy.ts +39 -9
  396. package/src/storage-backends/cursor-hosted-v2.ts +219 -0
  397. package/src/storage-backends/cursor-hosted.ts +6 -1
  398. package/src/storage-protocol.ts +37 -0
  399. package/src/storage.ts +1 -0
  400. package/src/types.ts +177 -14
  401. package/dist/docs/assets/chunks/@localSearchIndexroot.DpuI4i7Z.js +0 -1
  402. package/dist/docs/assets/hillclimbing.md.DhESf3OO.js +0 -4
  403. package/dist/docs/assets/scaffolding-agents.md.D7UUkWw0.js +0 -1
  404. package/dist/internal/null-kv-storage.d.ts +0 -48
  405. package/dist/internal/null-kv-storage.d.ts.map +0 -1
  406. package/dist/internal/null-kv-storage.js +0 -58
  407. package/dist/playground/assets/index-D7rGZNjy.css +0 -1
  408. package/src/internal/null-kv-storage.ts +0 -74
  409. /package/dist/docs/assets/{ab.md.DJo5r4R-.lean.js → ab.md.mlVgqvSk.lean.js} +0 -0
  410. /package/dist/docs/assets/{building-with-agents.md.DI4mEzlt.lean.js → building-with-agents.md.CUSWxlP_.lean.js} +0 -0
  411. /package/dist/docs/assets/{evals.md.lfJoEVc8.lean.js → evals.md.CPzDAwoH.lean.js} +0 -0
  412. /package/dist/docs/assets/{guides_github.md.Cnh2mL4a.lean.js → guides_github.md.BtPr9GaP.lean.js} +0 -0
  413. /package/dist/docs/assets/{guides_mcp-oauth.md.CN-6YmTJ.lean.js → guides_mcp-oauth.md.Dp6cDP7f.lean.js} +0 -0
  414. /package/dist/docs/assets/{guides_opentelemetry.md.bmPmkvJu.lean.js → guides_opentelemetry.md.BVTXDCRg.lean.js} +0 -0
  415. /package/dist/docs/assets/{hillclimbing.md.DhESf3OO.lean.js → hillclimbing.md.CpTGTCle.lean.js} +0 -0
  416. /package/dist/docs/assets/{index.md.CVeRUOeZ.lean.js → index.md.Bb4k8kUm.lean.js} +0 -0
  417. /package/dist/docs/assets/{quickstart.md.Nj_LjW_a.lean.js → quickstart.md.DdQOF7Y8.lean.js} +0 -0
  418. /package/dist/docs/assets/{reference_http-api.md.BEJx9XVj.lean.js → reference_http-api.md.oySXBO8o.lean.js} +0 -0
  419. /package/dist/docs/assets/{scaffolding-agents.md.D7UUkWw0.lean.js → scaffolding-agents.md.em43xlY1.lean.js} +0 -0
  420. /package/dist/docs/assets/{troubleshooting.md.DCiPBhYs.lean.js → troubleshooting.md.Cus_YZga.lean.js} +0 -0
@@ -8,12 +8,29 @@
8
8
  * Assistant-pane threads only render stream APIs. Start lazily with the
9
9
  * first real markdown/chunks plus recipient ids — empty startStream is
10
10
  * rejected or never attaches.
11
+ *
12
+ * Every call speaks `chunks`. Slack pins a stream's mode at start: text
13
+ * opened as bare `markdown_text` rejects later `task_update` appends with
14
+ * `streaming_mode_mismatch`, so assistant text goes out as `markdown_text`
15
+ * chunks and tool steps can land in the same message.
11
16
  */
12
17
 
13
18
  import type { ChannelEventContext } from "../../types.js";
14
- import { appendChatStream, startChatStream, stopChatStream } from "./api.js";
19
+ import {
20
+ appendChatStream,
21
+ postMessage,
22
+ startChatStream,
23
+ stopChatStream,
24
+ } from "./api.js";
25
+ import { highlightCodeFences } from "./code-fences.js";
26
+ import { SLACK_MARKDOWN_TEXT_MAX_LEN } from "./constants.js";
15
27
  import type { SlackLog } from "./log.js";
16
- import { computeStreamAppend, type StreamTaskChunk } from "./stream.js";
28
+ import {
29
+ computeStreamAppend,
30
+ markdownChunk,
31
+ type StreamChunk,
32
+ type StreamTaskChunk,
33
+ } from "./stream.js";
17
34
  import type { SlackBotToken, SlackChannelState } from "./types.js";
18
35
 
19
36
  type SlackChannel = ChannelEventContext<SlackChannelState>;
@@ -98,9 +115,13 @@ export function createStreamDeliveryStrategy(
98
115
  if (activeStreamTs(channel) !== null) {
99
116
  return true;
100
117
  }
101
- const hasMarkdown = markdown_text !== undefined && markdown_text !== "";
102
- const hasChunks = chunks !== undefined && chunks.length > 0;
103
- if (!hasMarkdown && !hasChunks) {
118
+ const openingText = markdown_text ?? "";
119
+ const opening: StreamChunk[] = [];
120
+ if (openingText !== "") {
121
+ opening.push(markdownChunk(highlightCodeFences(openingText)));
122
+ }
123
+ opening.push(...(chunks ?? []));
124
+ if (opening.length === 0) {
104
125
  return false;
105
126
  }
106
127
  const log = getLog();
@@ -108,8 +129,7 @@ export function createStreamDeliveryStrategy(
108
129
  botToken,
109
130
  channel: channelId,
110
131
  thread_ts: threadTs,
111
- markdown_text: hasMarkdown ? markdown_text : undefined,
112
- chunks: hasChunks ? chunks : undefined,
132
+ chunks: opening,
113
133
  ...streamRecipients(channel),
114
134
  });
115
135
  if (!started.ok) {
@@ -126,8 +146,9 @@ export function createStreamDeliveryStrategy(
126
146
  }
127
147
  channel.state.streamTs = started.ts;
128
148
  channel.state.streamChannelId = started.channel;
129
- channel.state.lastPostedText = hasMarkdown ? (markdown_text ?? "") : "";
130
- channel.state.streamBlockText = channel.state.lastPostedText;
149
+ channel.state.streamFull = false;
150
+ channel.state.lastPostedText = openingText;
151
+ channel.state.streamBlockText = openingText;
131
152
  log.info("chat.startStream ok", {
132
153
  channel: started.channel,
133
154
  stream_ts: started.ts,
@@ -161,21 +182,29 @@ export function createStreamDeliveryStrategy(
161
182
  return opened ? activeStreamTs(args.channel) : null;
162
183
  };
163
184
 
185
+ /**
186
+ * What to append for the new cumulative text, as Slack should see it: the
187
+ * block text on both sides goes through the same fence rewrite, so the
188
+ * delta lines up with what the stream already holds.
189
+ */
190
+ const streamDelta = (channel: SlackChannel, text: string): string =>
191
+ computeStreamAppend(
192
+ highlightCodeFences(channel.state.streamBlockText ?? ""),
193
+ highlightCodeFences(text)
194
+ );
195
+
164
196
  const stopWithSuffix = async (args: {
165
197
  channel: SlackChannel;
166
198
  channelId: string;
167
199
  ts: string;
168
200
  text: string;
169
201
  }): Promise<{ ok: boolean; error?: string }> => {
170
- const appendText = computeStreamAppend(
171
- args.channel.state.streamBlockText,
172
- args.text
173
- );
202
+ const appendText = streamDelta(args.channel, args.text);
174
203
  const stopped = await stopChatStream({
175
204
  botToken,
176
205
  channel: args.channelId,
177
206
  ts: args.ts,
178
- markdown_text: appendText === "" ? undefined : appendText,
207
+ chunks: appendText === "" ? undefined : [markdownChunk(appendText)],
179
208
  });
180
209
  args.channel.state.streamTs = null;
181
210
  if (stopped.ok) {
@@ -199,11 +228,77 @@ export function createStreamDeliveryStrategy(
199
228
  channel.state.streamTs = null;
200
229
  };
201
230
 
231
+ /**
232
+ * `msg_too_long` means the message is full: every further append would
233
+ * fail the same way, so appends stop until `finalize` continues the reply
234
+ * in a new message.
235
+ */
236
+ const noteAppendFailure = (
237
+ channel: SlackChannel,
238
+ result: { error?: string; unsupported?: boolean }
239
+ ): void => {
240
+ if (result.unsupported === true) {
241
+ channel.state.streamingUnavailable = true;
242
+ }
243
+ if (result.error === "msg_too_long") {
244
+ channel.state.streamFull = true;
245
+ }
246
+ };
247
+
248
+ /**
249
+ * The streamed message is full. Close it as it stands so it stops spinning
250
+ * and post the rest as a new thread message. Most of the answer is on Slack
251
+ * either way, so the reply counts as delivered even if that post fails: a
252
+ * duplicate would be worse than a lost tail.
253
+ */
254
+ const continueOverflow = async (args: {
255
+ channel: SlackChannel;
256
+ channelId: string;
257
+ ts: string;
258
+ remainder: string;
259
+ sessionId: string;
260
+ }): Promise<void> => {
261
+ const { channel, channelId, ts, remainder, sessionId } = args;
262
+ const log = getLog();
263
+ await stopChatStream({ botToken, channel: channelId, ts });
264
+ channel.state.streamTs = null;
265
+ const threadTs = channel.state.threadTs;
266
+ if (remainder === "" || threadTs === null || threadTs === "") {
267
+ return;
268
+ }
269
+ try {
270
+ const posted = await postMessage({
271
+ botToken,
272
+ channel: channelId,
273
+ text: remainder,
274
+ threadTs,
275
+ plainText: remainder.length >= SLACK_MARKDOWN_TEXT_MAX_LEN,
276
+ });
277
+ channel.state.lastBotMessageTs = posted.ts;
278
+ log.info("reply overflowed the stream; continued in a new message", {
279
+ channel: channelId,
280
+ stream_ts: ts,
281
+ session: sessionId,
282
+ continued_chars: remainder.length,
283
+ });
284
+ } catch (error) {
285
+ log.warn("stream overflow continuation failed", {
286
+ error: error instanceof Error ? error.message : String(error),
287
+ channel: channelId,
288
+ stream_ts: ts,
289
+ session: sessionId,
290
+ });
291
+ }
292
+ };
293
+
202
294
  return {
203
295
  inlineToolSteps: true,
204
296
  open,
205
297
 
206
298
  async append({ channel, channelId, text, sessionId }) {
299
+ if (channel.state.streamFull === true) {
300
+ return;
301
+ }
207
302
  const ts = await ensureOpen({
208
303
  channel,
209
304
  channelId,
@@ -213,10 +308,7 @@ export function createStreamDeliveryStrategy(
213
308
  if (ts === null) {
214
309
  return;
215
310
  }
216
- const appendText = computeStreamAppend(
217
- channel.state.streamBlockText,
218
- text
219
- );
311
+ const appendText = streamDelta(channel, text);
220
312
  if (appendText === "") {
221
313
  return;
222
314
  }
@@ -224,7 +316,7 @@ export function createStreamDeliveryStrategy(
224
316
  botToken,
225
317
  channel: channelId,
226
318
  ts,
227
- markdown_text: appendText,
319
+ chunks: [markdownChunk(appendText)],
228
320
  });
229
321
  if (!result.ok) {
230
322
  getLog().warn("appendStream failed", {
@@ -233,9 +325,7 @@ export function createStreamDeliveryStrategy(
233
325
  stream_ts: ts,
234
326
  session: sessionId,
235
327
  });
236
- if (result.unsupported === true) {
237
- channel.state.streamingUnavailable = true;
238
- }
328
+ noteAppendFailure(channel, result);
239
329
  return;
240
330
  }
241
331
  channel.state.lastPostedText = text;
@@ -243,6 +333,9 @@ export function createStreamDeliveryStrategy(
243
333
  },
244
334
 
245
335
  async appendChunks({ channel, channelId, chunks, sessionId }) {
336
+ if (channel.state.streamFull === true) {
337
+ return false;
338
+ }
246
339
  const hadStream = activeStreamTs(channel) !== null;
247
340
  const ts = await ensureOpen({
248
341
  channel,
@@ -262,6 +355,16 @@ export function createStreamDeliveryStrategy(
262
355
  ts,
263
356
  chunks,
264
357
  });
358
+ if (!result.ok) {
359
+ getLog().warn("appendStream chunks failed", {
360
+ error: result.error,
361
+ channel: channelId,
362
+ stream_ts: ts,
363
+ session: sessionId,
364
+ chunks: chunks.length,
365
+ });
366
+ noteAppendFailure(channel, result);
367
+ }
265
368
  return result.ok;
266
369
  },
267
370
 
@@ -276,12 +379,12 @@ export function createStreamDeliveryStrategy(
276
379
  if (ts === null) {
277
380
  return { delivered: false };
278
381
  }
279
- const stopped = await stopWithSuffix({
280
- channel,
281
- channelId,
282
- ts,
283
- text,
284
- });
382
+ // Measured before the stop attempt mutates stream state.
383
+ const remainder = streamDelta(channel, text);
384
+ const stopped =
385
+ channel.state.streamFull === true
386
+ ? { ok: false, error: "msg_too_long" }
387
+ : await stopWithSuffix({ channel, channelId, ts, text });
285
388
  if (stopped.ok) {
286
389
  log.info("reply delivered via stream", {
287
390
  channel: channelId,
@@ -291,6 +394,17 @@ export function createStreamDeliveryStrategy(
291
394
  });
292
395
  return { delivered: true };
293
396
  }
397
+ if (stopped.error === "msg_too_long") {
398
+ await continueOverflow({
399
+ channel,
400
+ channelId,
401
+ ts,
402
+ remainder,
403
+ sessionId,
404
+ });
405
+ channel.state.lastPostedText = text;
406
+ return { delivered: true };
407
+ }
294
408
  log.warn("chat.stopStream failed; falling back to postMessage", {
295
409
  error: stopped.error,
296
410
  channel: channelId,
@@ -0,0 +1,140 @@
1
+ /**
2
+ * The "Thinking" task card that receives the model's reasoning as it streams.
3
+ * Slack appends a card's `details` across updates, so the card is fed
4
+ * deltas: the part of the current reasoning block already on Slack, plus a
5
+ * buffer of what has not gone out yet.
6
+ */
7
+
8
+ import type { ChannelEventContext } from "../../types.js";
9
+ import type { ResolvedSlackReasoningCard } from "./reply-options.js";
10
+ import { type StreamTaskChunk, truncateCardText } from "./stream.js";
11
+ import type { ReasoningCardState, SlackChannelState } from "./types.js";
12
+
13
+ const FLUSH_MS = 1_000;
14
+ const FLUSH_CHARS = 160;
15
+ const CARD_ID = "reasoning";
16
+ const BLOCK_SEPARATOR = "\n\n";
17
+
18
+ type Channel = ChannelEventContext<SlackChannelState>;
19
+ type CardStatus = "in_progress" | "complete";
20
+
21
+ export interface ReasoningCard {
22
+ /** Buffer the current reasoning block's cumulative text; flushes when due. */
23
+ append(args: {
24
+ channel: Channel;
25
+ sessionId: string;
26
+ text: string;
27
+ }): Promise<void>;
28
+ /** Send buffered text and set the card status. */
29
+ flush(args: {
30
+ channel: Channel;
31
+ sessionId: string;
32
+ status: CardStatus;
33
+ }): Promise<void>;
34
+ /** The next reasoning block appends after a blank line. */
35
+ endBlock(channel: Channel): void;
36
+ inProgress(channel: Channel): boolean;
37
+ }
38
+
39
+ /** Delivers one chunk into the reply stream; `false` when nothing went out. */
40
+ export type SendCardChunk = (args: {
41
+ channel: Channel;
42
+ sessionId: string;
43
+ chunk: StreamTaskChunk;
44
+ }) => Promise<boolean>;
45
+
46
+ function cardState(state: SlackChannelState): ReasoningCardState {
47
+ if (state.reasoningCard === undefined) {
48
+ state.reasoningCard = {
49
+ status: null,
50
+ blockSent: null,
51
+ pending: "",
52
+ lastFlushMs: null,
53
+ chars: 0,
54
+ };
55
+ }
56
+ return state.reasoningCard;
57
+ }
58
+
59
+ export function createReasoningCard(
60
+ card: ResolvedSlackReasoningCard,
61
+ send: SendCardChunk
62
+ ): ReasoningCard {
63
+ const flush: ReasoningCard["flush"] = async ({
64
+ channel,
65
+ sessionId,
66
+ status,
67
+ }) => {
68
+ const state = cardState(channel.state);
69
+ if (
70
+ state.pending === "" &&
71
+ (state.status === status || state.status === null)
72
+ ) {
73
+ return;
74
+ }
75
+ const chunk: StreamTaskChunk = {
76
+ type: "task_update",
77
+ id: CARD_ID,
78
+ title: card.title,
79
+ status,
80
+ };
81
+ if (state.pending !== "") {
82
+ chunk.details = state.pending;
83
+ }
84
+ // Stamped on the attempt, so a failing stream is retried at most once
85
+ // per flush window instead of once per token.
86
+ state.lastFlushMs = Date.now();
87
+ if (!(await send({ channel, sessionId, chunk }))) {
88
+ return;
89
+ }
90
+ state.chars += state.pending.length;
91
+ state.pending = "";
92
+ state.status = status;
93
+ };
94
+
95
+ return {
96
+ flush,
97
+
98
+ async append({ channel, sessionId, text }) {
99
+ const state = cardState(channel.state);
100
+ if (state.chars >= card.maxChars) {
101
+ return;
102
+ }
103
+ const sent = state.blockSent ?? 0;
104
+ let delta: string;
105
+ if (sent > 0 && text.length >= sent) {
106
+ delta = text.slice(sent);
107
+ } else {
108
+ const hasText = state.chars + state.pending.length > 0;
109
+ delta = `${hasText ? BLOCK_SEPARATOR : ""}${text}`;
110
+ }
111
+ state.blockSent = text.length;
112
+ if (delta === "") {
113
+ return;
114
+ }
115
+ let pending = `${state.pending}${delta}`;
116
+ const room = card.maxChars - state.chars;
117
+ if (pending.length > room) {
118
+ pending = truncateCardText(pending, room);
119
+ state.chars = card.maxChars - pending.length;
120
+ }
121
+ state.pending = pending;
122
+
123
+ const due =
124
+ state.lastFlushMs === null ||
125
+ Date.now() - state.lastFlushMs >= FLUSH_MS ||
126
+ pending.length >= FLUSH_CHARS;
127
+ if (due) {
128
+ await flush({ channel, sessionId, status: "in_progress" });
129
+ }
130
+ },
131
+
132
+ endBlock(channel) {
133
+ cardState(channel.state).blockSent = null;
134
+ },
135
+
136
+ inProgress(channel) {
137
+ return channel.state.reasoningCard?.status === "in_progress";
138
+ },
139
+ };
140
+ }
@@ -0,0 +1,6 @@
1
+ /** Credential shapes that must never reach a Slack thread verbatim. */
2
+ const SECRET_TOKEN = /\b(crsr_|xox[baprs]-|sk-|Bearer\s+)\S+/gi;
3
+
4
+ export function redactSecretTokens(text: string): string {
5
+ return text.replace(SECRET_TOKEN, "[redacted]");
6
+ }
@@ -0,0 +1,229 @@
1
+ /**
2
+ * Resolve `slackChannel({ reply, toolLabels })` — and the deprecated
3
+ * `streaming` / `thinkingSteps` / `loadingMessages` flags — into one config
4
+ * the default event handlers read.
5
+ */
6
+
7
+ import { SLACK_DEFAULT_LOADING_MESSAGES } from "./constants.js";
8
+ import { defaultToolCardDetails } from "./tool-cards.js";
9
+ import type {
10
+ SlackChannelOptions,
11
+ SlackReasoningCardOptions,
12
+ SlackReplyOptions,
13
+ SlackToolCall,
14
+ SlackToolCardGroup,
15
+ SlackToolLabels,
16
+ SlackToolResult,
17
+ } from "./types.js";
18
+
19
+ export type SlackReplyMode = "post" | "stream";
20
+
21
+ export interface ResolvedSlackStatus {
22
+ reasoning: boolean;
23
+ /** `false`, or the line to show when tool calls start. */
24
+ tools: false | ((calls: readonly SlackToolCall[]) => string);
25
+ idle: string[];
26
+ }
27
+
28
+ export interface ResolvedSlackToolCards {
29
+ group: SlackToolCardGroup;
30
+ details?: (call: SlackToolCall) => string | undefined;
31
+ output?: (result: SlackToolResult) => string | undefined;
32
+ }
33
+
34
+ export interface ResolvedSlackReasoningCard {
35
+ title: string;
36
+ maxChars: number;
37
+ }
38
+
39
+ export interface ResolvedSlackReply {
40
+ mode: SlackReplyMode;
41
+ status: ResolvedSlackStatus;
42
+ toolCards: false | ResolvedSlackToolCards;
43
+ reasoningCard: false | ResolvedSlackReasoningCard;
44
+ toolLabel: (toolName: string) => string;
45
+ /** Author-facing notices about deprecated options that were honored. */
46
+ deprecations: string[];
47
+ }
48
+
49
+ export const DEFAULT_REASONING_CARD_TITLE = "Thinking";
50
+ /** A modest share of `SLACK_MARKDOWN_TEXT_MAX_LEN`, which the whole streamed message shares. */
51
+ export const DEFAULT_REASONING_CARD_MAX_CHARS = 1500;
52
+
53
+ type ReplyInputs = Pick<
54
+ SlackChannelOptions,
55
+ "reply" | "toolLabels" | "streaming" | "thinkingSteps"
56
+ > & { loadingMessages?: readonly string[] };
57
+
58
+ function resolveToolLabel(
59
+ labels: SlackToolLabels | undefined
60
+ ): (toolName: string) => string {
61
+ if (labels === undefined) {
62
+ return (toolName) => toolName;
63
+ }
64
+ const lookup =
65
+ typeof labels === "function" ? labels : (name: string) => labels[name];
66
+ return (toolName) => {
67
+ const label = lookup(toolName);
68
+ return label === undefined || label === "" ? toolName : label;
69
+ };
70
+ }
71
+
72
+ function defaultToolStatusLine(
73
+ toolLabel: (toolName: string) => string
74
+ ): (calls: readonly SlackToolCall[]) => string {
75
+ return (calls) => {
76
+ const names = [...new Set(calls.map((call) => toolLabel(call.toolName)))];
77
+ return `Running ${names.join(", ")}…`;
78
+ };
79
+ }
80
+
81
+ function resolveIdle(idle: readonly string[] | undefined): string[] {
82
+ const cleaned = (idle ?? []).filter((line) => line.trim() !== "");
83
+ return cleaned.length > 0 ? cleaned : [...SLACK_DEFAULT_LOADING_MESSAGES];
84
+ }
85
+
86
+ function resolveReasoningCard(
87
+ option: boolean | SlackReasoningCardOptions | undefined
88
+ ): false | ResolvedSlackReasoningCard {
89
+ if (option === undefined || option === false) {
90
+ return false;
91
+ }
92
+ const options = option === true ? {} : option;
93
+ const title = options.title?.trim();
94
+ return {
95
+ title:
96
+ title === undefined || title === ""
97
+ ? DEFAULT_REASONING_CARD_TITLE
98
+ : title,
99
+ maxChars:
100
+ options.maxChars !== undefined && options.maxChars > 0
101
+ ? options.maxChars
102
+ : DEFAULT_REASONING_CARD_MAX_CHARS,
103
+ };
104
+ }
105
+
106
+ function resolveToolCards(
107
+ option: SlackReplyOptions & { mode: "stream" }
108
+ ): false | ResolvedSlackToolCards {
109
+ const cards = option.toolCards;
110
+ if (cards === undefined || cards === false) {
111
+ return false;
112
+ }
113
+ if (cards === true) {
114
+ return { group: "per-tool", details: defaultToolCardDetails };
115
+ }
116
+ const group = cards.group ?? "per-tool";
117
+ if (cards.collapsible === false) {
118
+ return { group };
119
+ }
120
+ return {
121
+ group,
122
+ details: cards.details ?? defaultToolCardDetails,
123
+ output: cards.output,
124
+ };
125
+ }
126
+
127
+ /**
128
+ * Map the deprecated flags onto a `reply` shape with their old defaults
129
+ * (streaming on, per-call cards on), so a config that only sets these keeps
130
+ * behaving as it did. `null` when none of them is set.
131
+ */
132
+ function legacyReplyOptions(
133
+ options: ReplyInputs
134
+ ): { reply: SlackReplyOptions; deprecations: string[] } | null {
135
+ const idle = options.loadingMessages;
136
+ if (
137
+ options.streaming === undefined &&
138
+ options.thinkingSteps === undefined &&
139
+ idle === undefined
140
+ ) {
141
+ return null;
142
+ }
143
+ const deprecations: string[] = [];
144
+ const mode: SlackReplyMode = options.streaming === false ? "post" : "stream";
145
+ // What legacy streaming showed: one title-only card per call.
146
+ const cards = options.thinkingSteps === false ? false : LEGACY_CARDS;
147
+ const replacement =
148
+ mode === "post"
149
+ ? 'reply: { mode: "post" }'
150
+ : cards === false
151
+ ? 'reply: { mode: "stream" }'
152
+ : 'reply: { mode: "stream", toolCards: { group: "per-call", collapsible: false } }';
153
+ if (idle !== undefined) {
154
+ deprecations.push(
155
+ `slackChannel({ loadingMessages }) is deprecated; use reply: { mode: "${mode}", status: { idle: [...] } }.`
156
+ );
157
+ }
158
+ if (options.streaming !== undefined) {
159
+ deprecations.push(
160
+ `slackChannel({ streaming: ${String(options.streaming)} }) is deprecated; use ${replacement}.`
161
+ );
162
+ }
163
+ if (options.thinkingSteps !== undefined) {
164
+ deprecations.push(
165
+ mode === "post"
166
+ ? "slackChannel({ thinkingSteps }) has no effect in post mode; remove it."
167
+ : `slackChannel({ thinkingSteps: ${String(options.thinkingSteps)} }) is deprecated; use ${replacement}.`
168
+ );
169
+ }
170
+ const status = { idle };
171
+ if (mode === "post") {
172
+ return { reply: { mode, status }, deprecations };
173
+ }
174
+ return { reply: { mode, status, toolCards: cards }, deprecations };
175
+ }
176
+
177
+ const LEGACY_CARDS = { group: "per-call", collapsible: false } as const;
178
+
179
+ export function resolveSlackReply(options: ReplyInputs): ResolvedSlackReply {
180
+ const deprecations: string[] = [];
181
+ let reply: SlackReplyOptions = { mode: "post" };
182
+ const legacy = legacyReplyOptions(options);
183
+ if (options.reply !== undefined) {
184
+ reply = options.reply;
185
+ if (legacy !== null) {
186
+ const ignored = (
187
+ ["streaming", "thinkingSteps", "loadingMessages"] as const
188
+ ).filter((key) => options[key] !== undefined);
189
+ deprecations.push(
190
+ `slackChannel({ ${ignored.join(", ")} }) is ignored because reply is set; remove the deprecated option${ignored.length === 1 ? "" : "s"}.`
191
+ );
192
+ }
193
+ } else if (legacy !== null) {
194
+ reply = legacy.reply;
195
+ deprecations.push(...legacy.deprecations);
196
+ }
197
+
198
+ const toolLabel = resolveToolLabel(options.toolLabels);
199
+ const statusInput = reply.status ?? {};
200
+ const status: ResolvedSlackStatus = {
201
+ reasoning: statusInput.reasoning !== false,
202
+ tools:
203
+ statusInput.tools === false
204
+ ? false
205
+ : typeof statusInput.tools === "function"
206
+ ? statusInput.tools
207
+ : defaultToolStatusLine(toolLabel),
208
+ idle: resolveIdle(statusInput.idle),
209
+ };
210
+
211
+ if (reply.mode === "post") {
212
+ return {
213
+ mode: "post",
214
+ status,
215
+ toolCards: false,
216
+ reasoningCard: false,
217
+ toolLabel,
218
+ deprecations,
219
+ };
220
+ }
221
+ return {
222
+ mode: "stream",
223
+ status,
224
+ toolCards: resolveToolCards(reply),
225
+ reasoningCard: resolveReasoningCard(reply.reasoningCard),
226
+ toolLabel,
227
+ deprecations,
228
+ };
229
+ }
@@ -57,6 +57,7 @@ import {
57
57
  dispatchInteractiveFromPayload,
58
58
  } from "./interactive.js";
59
59
  import { createSlackLogger, type SlackLog } from "./log.js";
60
+ import { resolveSlackReply } from "./reply-options.js";
60
61
  import {
61
62
  type SlackSocketModeHandle,
62
63
  type SlackSocketModeOptions,
@@ -128,7 +129,8 @@ export function slackChannel(
128
129
  const credentials =
129
130
  options.credentials ?? credentialsFromEnv(options.envPrefix);
130
131
  const envKeys = slackEnvKeys(options.envPrefix);
131
- const loadingMessages = options.loadingMessages;
132
+ const reply = resolveSlackReply(options);
133
+ const loadingMessages = reply.status.idle;
132
134
  const policy = options.policy;
133
135
  const blockExternals = resolveSlackBlockExternals(policy);
134
136
  const defaultInbound = createDefaultOnInbound(loadingMessages, policy);
@@ -174,11 +176,13 @@ export function slackChannel(
174
176
  events,
175
177
  buildDefaultEvents({
176
178
  credentials,
179
+ reply: options.reply,
180
+ toolLabels: options.toolLabels,
177
181
  streaming: options.streaming,
178
182
  thinkingSteps: options.thinkingSteps,
183
+ loadingMessages: options.loadingMessages,
179
184
  suggestedPrompts: options.suggestedPrompts,
180
185
  suggestedPromptsTitle: options.suggestedPromptsTitle,
181
- loadingMessages,
182
186
  getLog,
183
187
  })
184
188
  );
@@ -252,6 +256,7 @@ export function slackChannel(
252
256
  ...(channelPosts === undefined
253
257
  ? {}
254
258
  : { slackChannelPosts: [...channelPosts.allow] }),
259
+ deprecations: reply.deprecations,
255
260
  },
256
261
  async receive(input: ReceiveInput, { send }) {
257
262
  const target = input.target ?? {};