@cursor/july 0.1.97 → 0.1.100

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 (337) hide show
  1. package/AGENTS.md +5 -3
  2. package/dist/bin/agent-serve.js +6 -7
  3. package/dist/channels/github/defaults.d.ts.map +1 -1
  4. package/dist/channels/github/defaults.js +28 -3
  5. package/dist/channels/github/github-channel.d.ts.map +1 -1
  6. package/dist/channels/github/github-channel.js +16 -0
  7. package/dist/channels/github/progress.d.ts +7 -0
  8. package/dist/channels/github/progress.d.ts.map +1 -1
  9. package/dist/channels/origin/origin-channel.d.ts +2 -0
  10. package/dist/channels/origin/origin-channel.d.ts.map +1 -1
  11. package/dist/channels/origin/origin-channel.js +37 -4
  12. package/dist/channels/slack/api.d.ts +16 -7
  13. package/dist/channels/slack/api.d.ts.map +1 -1
  14. package/dist/channels/slack/api.js +29 -13
  15. package/dist/channels/slack/constants.d.ts +6 -0
  16. package/dist/channels/slack/constants.d.ts.map +1 -1
  17. package/dist/channels/slack/constants.js +6 -0
  18. package/dist/channels/slack/defaults.d.ts +9 -4
  19. package/dist/channels/slack/defaults.d.ts.map +1 -1
  20. package/dist/channels/slack/defaults.js +221 -122
  21. package/dist/channels/slack/dispatch.d.ts.map +1 -1
  22. package/dist/channels/slack/dispatch.js +3 -3
  23. package/dist/channels/slack/inbound.d.ts +9 -0
  24. package/dist/channels/slack/inbound.d.ts.map +1 -1
  25. package/dist/channels/slack/inbound.js +14 -0
  26. package/dist/channels/slack/index.d.ts +1 -0
  27. package/dist/channels/slack/index.d.ts.map +1 -1
  28. package/dist/channels/slack/index.js +1 -0
  29. package/dist/channels/slack/live-delivery.d.ts +6 -1
  30. package/dist/channels/slack/live-delivery.d.ts.map +1 -1
  31. package/dist/channels/slack/live-delivery.js +110 -20
  32. package/dist/channels/slack/progress-delivery.d.ts +28 -0
  33. package/dist/channels/slack/progress-delivery.d.ts.map +1 -0
  34. package/dist/channels/slack/progress-delivery.js +115 -0
  35. package/dist/channels/slack/reasoning-card.d.ts +38 -0
  36. package/dist/channels/slack/reasoning-card.d.ts.map +1 -0
  37. package/dist/channels/slack/reasoning-card.js +104 -0
  38. package/dist/channels/slack/redact.d.ts +2 -0
  39. package/dist/channels/slack/redact.d.ts.map +1 -0
  40. package/dist/channels/slack/redact.js +5 -0
  41. package/dist/channels/slack/reply-options.d.ts +40 -0
  42. package/dist/channels/slack/reply-options.d.ts.map +1 -0
  43. package/dist/channels/slack/reply-options.js +150 -0
  44. package/dist/channels/slack/slack-channel.d.ts.map +1 -1
  45. package/dist/channels/slack/slack-channel.js +8 -4
  46. package/dist/channels/slack/stream.d.ts +22 -10
  47. package/dist/channels/slack/stream.d.ts.map +1 -1
  48. package/dist/channels/slack/stream.js +9 -16
  49. package/dist/channels/slack/tool-cards.d.ts +22 -0
  50. package/dist/channels/slack/tool-cards.d.ts.map +1 -0
  51. package/dist/channels/slack/tool-cards.js +178 -0
  52. package/dist/channels/slack/types.d.ts +154 -7
  53. package/dist/channels/slack/types.d.ts.map +1 -1
  54. package/dist/docs/404.html +2 -2
  55. package/dist/docs/ab.html +6 -6
  56. package/dist/docs/ab.md +1 -1
  57. package/dist/docs/assets/{ab.md.DJo5r4R-.js → ab.md.mlVgqvSk.js} +1 -1
  58. package/dist/docs/assets/{app.B3rWNYE1.js → app.DZ1e0Ycq.js} +1 -1
  59. package/dist/docs/assets/{building-with-agents.md.DI4mEzlt.js → building-with-agents.md.CUSWxlP_.js} +2 -2
  60. package/dist/docs/assets/chunks/@localSearchIndexroot.j70vvPL4.js +1 -0
  61. package/dist/docs/assets/chunks/{VPLocalSearchBox.C1lhqJJR.js → VPLocalSearchBox.l8omwc6D.js} +1 -1
  62. package/dist/docs/assets/chunks/{theme.B40_SXuv.js → theme.JVcD6gel.js} +2 -2
  63. package/dist/docs/assets/{evals.md.lfJoEVc8.js → evals.md.CPzDAwoH.js} +1 -1
  64. package/dist/docs/assets/{guides_github.md.Cnh2mL4a.js → guides_github.md.BtPr9GaP.js} +1 -1
  65. package/dist/docs/assets/{guides_mcp-oauth.md.CN-6YmTJ.js → guides_mcp-oauth.md.Dp6cDP7f.js} +1 -1
  66. package/dist/docs/assets/{guides_opentelemetry.md.bmPmkvJu.js → guides_opentelemetry.md.BVTXDCRg.js} +2 -2
  67. package/dist/docs/assets/{guides_slack.md.VDXQV3ja.js → guides_slack.md.9oHPye9o.js} +19 -3
  68. package/dist/docs/assets/{guides_slack.md.VDXQV3ja.lean.js → guides_slack.md.9oHPye9o.lean.js} +1 -1
  69. package/dist/docs/assets/hillclimbing.md.CpTGTCle.js +4 -0
  70. package/dist/docs/assets/{index.md.CVeRUOeZ.js → index.md.Bb4k8kUm.js} +1 -1
  71. package/dist/docs/assets/{quickstart.md.Nj_LjW_a.js → quickstart.md.DdQOF7Y8.js} +1 -1
  72. package/dist/docs/assets/{reference_cli.md.RyZf5OTE.js → reference_cli.md.DfoeyvL0.js} +4 -4
  73. package/dist/docs/assets/{reference_cli.md.RyZf5OTE.lean.js → reference_cli.md.DfoeyvL0.lean.js} +1 -1
  74. package/dist/docs/assets/{reference_connections.md.DxldvyIB.js → reference_connections.md.BiGoBAk2.js} +1 -1
  75. package/dist/docs/assets/{reference_http-api.md.5zOAbV86.js → reference_http-api.md.BEJx9XVj.js} +1 -1
  76. package/dist/docs/assets/{reference_tools.md.B84gw9Ii.js → reference_tools.md.CvAHsdSp.js} +10 -2
  77. package/dist/docs/assets/{reference_tools.md.B84gw9Ii.lean.js → reference_tools.md.CvAHsdSp.lean.js} +1 -1
  78. package/dist/docs/assets/scaffolding-agents.md.em43xlY1.js +1 -0
  79. package/dist/docs/assets/skills_ab.md.CsFNatVx.js +26 -0
  80. package/dist/docs/assets/skills_ab.md.CsFNatVx.lean.js +1 -0
  81. package/dist/docs/assets/skills_create-agent.md.BVoWPcan.js +8 -0
  82. package/dist/docs/assets/skills_create-agent.md.BVoWPcan.lean.js +1 -0
  83. package/dist/docs/assets/skills_debug.md.CDbPhHfg.js +1 -0
  84. package/dist/docs/assets/skills_debug.md.CDbPhHfg.lean.js +1 -0
  85. package/dist/docs/assets/skills_evals.md.723kpUmA.js +25 -0
  86. package/dist/docs/assets/skills_evals.md.723kpUmA.lean.js +1 -0
  87. package/dist/docs/assets/skills_framework-map.md.BTi817yv.js +1 -0
  88. package/dist/docs/assets/skills_framework-map.md.BTi817yv.lean.js +1 -0
  89. package/dist/docs/assets/skills_github.md.D0JahM8c.js +16 -0
  90. package/dist/docs/assets/skills_github.md.D0JahM8c.lean.js +1 -0
  91. package/dist/docs/assets/skills_hillclimb.md.B_zJerxA.js +7 -0
  92. package/dist/docs/assets/skills_hillclimb.md.B_zJerxA.lean.js +1 -0
  93. package/dist/docs/assets/skills_index.md.DKwIxzGg.js +1 -0
  94. package/dist/docs/assets/skills_index.md.DKwIxzGg.lean.js +1 -0
  95. package/dist/docs/assets/skills_mcp-auth.md.DGvFP3HE.js +18 -0
  96. package/dist/docs/assets/skills_mcp-auth.md.DGvFP3HE.lean.js +1 -0
  97. package/dist/docs/assets/skills_otel.md.CgiZryR3.js +8 -0
  98. package/dist/docs/assets/skills_otel.md.CgiZryR3.lean.js +1 -0
  99. package/dist/docs/assets/skills_setup-slack.md.BBgx8lUz.js +20 -0
  100. package/dist/docs/assets/skills_setup-slack.md.BBgx8lUz.lean.js +1 -0
  101. package/dist/docs/assets/{troubleshooting.md.DCiPBhYs.js → troubleshooting.md.Cus_YZga.js} +1 -1
  102. package/dist/docs/building-with-agents.html +6 -6
  103. package/dist/docs/building-with-agents.md +14 -11
  104. package/dist/docs/concepts.html +4 -4
  105. package/dist/docs/deployment.html +4 -4
  106. package/dist/docs/design/runtime-abstraction.md +1757 -0
  107. package/dist/docs/evals.html +6 -6
  108. package/dist/docs/evals.md +1 -1
  109. package/dist/docs/guides/agent-to-agent.html +4 -4
  110. package/dist/docs/guides/cloud-runtime.html +4 -4
  111. package/dist/docs/guides/convert-automation.html +4 -4
  112. package/dist/docs/guides/github.html +5 -5
  113. package/dist/docs/guides/github.md +1 -1
  114. package/dist/docs/guides/human-in-the-loop.html +4 -4
  115. package/dist/docs/guides/mcp-oauth.html +5 -5
  116. package/dist/docs/guides/mcp-oauth.md +1 -1
  117. package/dist/docs/guides/opentelemetry.html +7 -7
  118. package/dist/docs/guides/opentelemetry.md +2 -2
  119. package/dist/docs/guides/slack.html +22 -6
  120. package/dist/docs/guides/slack.md +80 -1
  121. package/dist/docs/guides/webhooks.html +5 -5
  122. package/dist/docs/hashmap.json +1 -1
  123. package/dist/docs/hillclimbing.html +6 -6
  124. package/dist/docs/hillclimbing.md +5 -5
  125. package/dist/docs/index.html +6 -6
  126. package/dist/docs/index.md +1 -1
  127. package/dist/docs/llms-full.txt +2830 -37
  128. package/dist/docs/llms.txt +15 -0
  129. package/dist/docs/quickstart.html +5 -5
  130. package/dist/docs/quickstart.md +1 -1
  131. package/dist/docs/reference/agent-config.html +4 -4
  132. package/dist/docs/reference/artifacts.html +4 -4
  133. package/dist/docs/reference/channels.html +4 -4
  134. package/dist/docs/reference/cli.html +7 -7
  135. package/dist/docs/reference/cli.md +1 -7
  136. package/dist/docs/reference/connections.html +6 -6
  137. package/dist/docs/reference/connections.md +1 -1
  138. package/dist/docs/reference/hooks.html +4 -4
  139. package/dist/docs/reference/http-api.html +6 -6
  140. package/dist/docs/reference/http-api.md +1 -0
  141. package/dist/docs/reference/instructions.html +4 -4
  142. package/dist/docs/reference/playground.html +4 -4
  143. package/dist/docs/reference/project-layout.html +4 -4
  144. package/dist/docs/reference/prompt.html +4 -4
  145. package/dist/docs/reference/schedules.html +4 -4
  146. package/dist/docs/reference/sessions.html +4 -4
  147. package/dist/docs/reference/skills.html +4 -4
  148. package/dist/docs/reference/subagents.html +4 -4
  149. package/dist/docs/reference/tools.html +14 -6
  150. package/dist/docs/reference/tools.md +25 -0
  151. package/dist/docs/scaffolding-agents.html +5 -5
  152. package/dist/docs/scaffolding-agents.md +3 -3
  153. package/dist/docs/skills/ab.html +52 -0
  154. package/dist/docs/skills/ab.md +50 -0
  155. package/dist/docs/skills/create-agent.html +34 -0
  156. package/dist/docs/skills/create-agent.md +160 -0
  157. package/dist/docs/skills/debug.html +27 -0
  158. package/dist/docs/skills/debug.md +36 -0
  159. package/dist/docs/skills/evals.html +51 -0
  160. package/dist/docs/skills/evals.md +99 -0
  161. package/dist/docs/skills/framework-map.html +27 -0
  162. package/dist/docs/skills/framework-map.md +95 -0
  163. package/dist/docs/skills/github.html +42 -0
  164. package/dist/docs/skills/github.md +93 -0
  165. package/dist/docs/skills/hillclimb.html +33 -0
  166. package/dist/docs/skills/hillclimb.md +55 -0
  167. package/dist/docs/skills/index.html +27 -0
  168. package/dist/docs/skills/index.md +21 -0
  169. package/dist/docs/skills/mcp-auth.html +44 -0
  170. package/dist/docs/skills/mcp-auth.md +76 -0
  171. package/dist/docs/skills/otel.html +34 -0
  172. package/dist/docs/skills/otel.md +48 -0
  173. package/dist/docs/skills/setup-slack.html +46 -0
  174. package/dist/docs/skills/setup-slack.md +141 -0
  175. package/dist/docs/storage.html +4 -4
  176. package/dist/docs/templates/agentic-owners.html +4 -4
  177. package/dist/docs/templates/agents-md.html +4 -4
  178. package/dist/docs/templates/code-wiki.html +4 -4
  179. package/dist/docs/templates/demo.html +4 -4
  180. package/dist/docs/templates/pr-autofixer.html +4 -4
  181. package/dist/docs/templates/security-help.html +4 -4
  182. package/dist/docs/templates/security-reviewer.html +4 -4
  183. package/dist/docs/templates/triage.html +4 -4
  184. package/dist/docs/troubleshooting.html +5 -5
  185. package/dist/docs/troubleshooting.md +1 -1
  186. package/dist/files-backends/cursor-hosted.d.ts +9 -2
  187. package/dist/files-backends/cursor-hosted.d.ts.map +1 -1
  188. package/dist/files-backends/cursor-hosted.js +9 -11
  189. package/dist/index.d.ts +1 -0
  190. package/dist/index.d.ts.map +1 -1
  191. package/dist/index.js +1 -0
  192. package/dist/internal/as-of.d.ts +19 -0
  193. package/dist/internal/as-of.d.ts.map +1 -0
  194. package/dist/internal/as-of.js +82 -0
  195. package/dist/internal/cli-deploy.d.ts +2 -1
  196. package/dist/internal/cli-deploy.d.ts.map +1 -1
  197. package/dist/internal/cli-deploy.js +102 -7
  198. package/dist/internal/conversation-mirror.d.ts.map +1 -1
  199. package/dist/internal/conversation-mirror.js +3 -4
  200. package/dist/internal/cursor/hosted-store-secrets.d.ts +15 -0
  201. package/dist/internal/cursor/hosted-store-secrets.d.ts.map +1 -0
  202. package/dist/internal/cursor/hosted-store-secrets.js +48 -0
  203. package/dist/internal/cursor-event-relay.d.ts.map +1 -1
  204. package/dist/internal/cursor-event-relay.js +5 -6
  205. package/dist/internal/deploy-client.d.ts +6 -6
  206. package/dist/internal/deploy-client.js +7 -7
  207. package/dist/internal/discovery.d.ts.map +1 -1
  208. package/dist/internal/discovery.js +11 -1
  209. package/dist/internal/framework-file-storage.d.ts +5 -4
  210. package/dist/internal/framework-file-storage.d.ts.map +1 -1
  211. package/dist/internal/framework-file-storage.js +6 -4
  212. package/dist/internal/framework-storage-selection.d.ts +13 -11
  213. package/dist/internal/framework-storage-selection.d.ts.map +1 -1
  214. package/dist/internal/framework-storage-selection.js +28 -23
  215. package/dist/internal/hosted-admission-adapter.d.ts +28 -0
  216. package/dist/internal/hosted-admission-adapter.d.ts.map +1 -0
  217. package/dist/internal/hosted-admission-adapter.js +7 -0
  218. package/dist/internal/hosted-delivery-protocol.d.ts +6 -1
  219. package/dist/internal/hosted-delivery-protocol.d.ts.map +1 -1
  220. package/dist/internal/hosted-delivery-protocol.js +1 -1
  221. package/dist/internal/hosted-delivery.d.ts +15 -1
  222. package/dist/internal/hosted-delivery.d.ts.map +1 -1
  223. package/dist/internal/hosted-delivery.js +47 -21
  224. package/dist/internal/hosted-execution-diag.d.ts +11 -0
  225. package/dist/internal/hosted-execution-diag.d.ts.map +1 -1
  226. package/dist/internal/hosted-execution-diag.js +39 -2
  227. package/dist/internal/http-channel.d.ts.map +1 -1
  228. package/dist/internal/http-channel.js +4 -1
  229. package/dist/internal/server.d.ts +3 -0
  230. package/dist/internal/server.d.ts.map +1 -1
  231. package/dist/internal/server.js +82 -19
  232. package/dist/internal/session-engine.d.ts.map +1 -1
  233. package/dist/internal/session-engine.js +24 -4
  234. package/dist/internal/session-run-log.d.ts +120 -0
  235. package/dist/internal/session-run-log.d.ts.map +1 -0
  236. package/dist/internal/session-run-log.js +358 -0
  237. package/dist/internal/tool-policy.d.ts +20 -8
  238. package/dist/internal/tool-policy.d.ts.map +1 -1
  239. package/dist/internal/tool-policy.js +11 -0
  240. package/dist/playground/assets/index-BszoQDc6.css +1 -0
  241. package/dist/playground/assets/index-DVs98vPL.js +69 -0
  242. package/dist/playground/index.html +2 -2
  243. package/dist/storage-backends/cursor-hosted-v2.d.ts +83 -0
  244. package/dist/storage-backends/cursor-hosted-v2.d.ts.map +1 -0
  245. package/dist/storage-backends/cursor-hosted-v2.js +164 -0
  246. package/dist/storage-backends/cursor-hosted.d.ts +6 -0
  247. package/dist/storage-backends/cursor-hosted.d.ts.map +1 -1
  248. package/dist/storage-backends/cursor-hosted.js +6 -1
  249. package/dist/storage-protocol.d.ts +8 -0
  250. package/dist/storage-protocol.d.ts.map +1 -1
  251. package/dist/storage-protocol.js +8 -0
  252. package/dist/tools.d.ts +12 -2
  253. package/dist/tools.d.ts.map +1 -1
  254. package/dist/types.d.ts +30 -0
  255. package/dist/types.d.ts.map +1 -1
  256. package/docs/README.md +1 -1
  257. package/docs/ab.md +1 -1
  258. package/docs/building-with-agents.md +14 -11
  259. package/docs/design/runtime-abstraction.md +1757 -0
  260. package/docs/evals.md +1 -1
  261. package/docs/guides/github.md +1 -1
  262. package/docs/guides/mcp-oauth.md +1 -1
  263. package/docs/guides/opentelemetry.md +2 -2
  264. package/docs/guides/slack.md +80 -1
  265. package/docs/hillclimbing.md +5 -5
  266. package/docs/quickstart.md +1 -1
  267. package/docs/reference/cli.md +1 -7
  268. package/docs/reference/connections.md +1 -1
  269. package/docs/reference/http-api.md +1 -0
  270. package/docs/reference/tools.md +25 -0
  271. package/docs/scaffolding-agents.md +3 -3
  272. package/docs/skills/index.md +26 -0
  273. package/docs/troubleshooting.md +1 -1
  274. package/package.json +1 -1
  275. package/src/bin/agent-serve.ts +6 -7
  276. package/src/channels/github/defaults.ts +36 -3
  277. package/src/channels/github/github-channel.ts +17 -0
  278. package/src/channels/github/progress.ts +7 -0
  279. package/src/channels/origin/origin-channel.ts +74 -10
  280. package/src/channels/slack/api.ts +35 -17
  281. package/src/channels/slack/constants.ts +6 -0
  282. package/src/channels/slack/defaults.ts +253 -144
  283. package/src/channels/slack/dispatch.ts +10 -1
  284. package/src/channels/slack/inbound.ts +17 -0
  285. package/src/channels/slack/index.ts +1 -0
  286. package/src/channels/slack/live-delivery.ts +135 -22
  287. package/src/channels/slack/progress-delivery.ts +133 -0
  288. package/src/channels/slack/reasoning-card.ts +140 -0
  289. package/src/channels/slack/redact.ts +6 -0
  290. package/src/channels/slack/reply-options.ts +229 -0
  291. package/src/channels/slack/slack-channel.ts +7 -2
  292. package/src/channels/slack/stream.ts +31 -24
  293. package/src/channels/slack/tool-cards.ts +221 -0
  294. package/src/channels/slack/types.ts +168 -7
  295. package/src/files-backends/cursor-hosted.ts +18 -7
  296. package/src/index.ts +4 -0
  297. package/src/internal/as-of.ts +107 -0
  298. package/src/internal/cli-deploy.ts +130 -10
  299. package/src/internal/conversation-mirror.ts +3 -8
  300. package/src/internal/cursor/hosted-store-secrets.ts +72 -0
  301. package/src/internal/cursor-event-relay.ts +5 -6
  302. package/src/internal/deploy-client.ts +10 -10
  303. package/src/internal/discovery.ts +9 -1
  304. package/src/internal/framework-file-storage.ts +6 -4
  305. package/src/internal/framework-storage-selection.ts +28 -25
  306. package/src/internal/hosted-admission-adapter.ts +42 -0
  307. package/src/internal/hosted-delivery-protocol.ts +7 -2
  308. package/src/internal/hosted-delivery.ts +88 -36
  309. package/src/internal/hosted-execution-diag.ts +45 -0
  310. package/src/internal/http-channel.ts +8 -0
  311. package/src/internal/server.ts +100 -2
  312. package/src/internal/session-engine.ts +32 -1
  313. package/src/internal/session-run-log.ts +579 -0
  314. package/src/internal/tool-policy.ts +31 -9
  315. package/src/storage-backends/cursor-hosted-v2.ts +219 -0
  316. package/src/storage-backends/cursor-hosted.ts +6 -1
  317. package/src/storage-protocol.ts +10 -0
  318. package/src/tools.ts +12 -2
  319. package/src/types.ts +30 -0
  320. package/dist/docs/assets/chunks/@localSearchIndexroot.BU9nHdnQ.js +0 -1
  321. package/dist/docs/assets/hillclimbing.md.DhESf3OO.js +0 -4
  322. package/dist/docs/assets/scaffolding-agents.md.D7UUkWw0.js +0 -1
  323. package/dist/playground/assets/index-DrkI6y5O.js +0 -88
  324. package/dist/playground/assets/index-DzNGwm7q.css +0 -1
  325. /package/dist/docs/assets/{ab.md.DJo5r4R-.lean.js → ab.md.mlVgqvSk.lean.js} +0 -0
  326. /package/dist/docs/assets/{building-with-agents.md.DI4mEzlt.lean.js → building-with-agents.md.CUSWxlP_.lean.js} +0 -0
  327. /package/dist/docs/assets/{evals.md.lfJoEVc8.lean.js → evals.md.CPzDAwoH.lean.js} +0 -0
  328. /package/dist/docs/assets/{guides_github.md.Cnh2mL4a.lean.js → guides_github.md.BtPr9GaP.lean.js} +0 -0
  329. /package/dist/docs/assets/{guides_mcp-oauth.md.CN-6YmTJ.lean.js → guides_mcp-oauth.md.Dp6cDP7f.lean.js} +0 -0
  330. /package/dist/docs/assets/{guides_opentelemetry.md.bmPmkvJu.lean.js → guides_opentelemetry.md.BVTXDCRg.lean.js} +0 -0
  331. /package/dist/docs/assets/{hillclimbing.md.DhESf3OO.lean.js → hillclimbing.md.CpTGTCle.lean.js} +0 -0
  332. /package/dist/docs/assets/{index.md.CVeRUOeZ.lean.js → index.md.Bb4k8kUm.lean.js} +0 -0
  333. /package/dist/docs/assets/{quickstart.md.Nj_LjW_a.lean.js → quickstart.md.DdQOF7Y8.lean.js} +0 -0
  334. /package/dist/docs/assets/{reference_connections.md.DxldvyIB.lean.js → reference_connections.md.BiGoBAk2.lean.js} +0 -0
  335. /package/dist/docs/assets/{reference_http-api.md.5zOAbV86.lean.js → reference_http-api.md.BEJx9XVj.lean.js} +0 -0
  336. /package/dist/docs/assets/{scaffolding-agents.md.D7UUkWw0.lean.js → scaffolding-agents.md.em43xlY1.lean.js} +0 -0
  337. /package/dist/docs/assets/{troubleshooting.md.DCiPBhYs.lean.js → troubleshooting.md.Cus_YZga.lean.js} +0 -0
@@ -3,12 +3,7 @@
3
3
  */
4
4
 
5
5
  import type { ChannelEventContext, ChannelEventHandlers } from "../../types.js";
6
- import {
7
- appendChatStream,
8
- postMessage,
9
- setThreadStatus,
10
- truncateTypingStatus,
11
- } from "./api.js";
6
+ import { postMessage, setThreadStatus, truncateTypingStatus } from "./api.js";
12
7
  import { firstNonEmptyLine, maybeSetSuggestedPrompts } from "./assistant.js";
13
8
  import { defaultSlackAuth } from "./auth.js";
14
9
  import {
@@ -18,14 +13,21 @@ import {
18
13
  } from "./constants.js";
19
14
  import { createStreamDeliveryStrategy } from "./live-delivery.js";
20
15
  import { defaultSlackLog, type SlackLog } from "./log.js";
21
- import { buildTaskChunkForResult, buildTaskChunksForCalls } from "./stream.js";
16
+ import { createProgressDelivery } from "./progress-delivery.js";
17
+ import { createReasoningCard, type ReasoningCard } from "./reasoning-card.js";
18
+ import { redactSecretTokens } from "./redact.js";
19
+ import { resolveSlackReply } from "./reply-options.js";
20
+ import type { StreamTaskChunk } from "./stream.js";
21
+ import { createToolCards, type ToolCards } from "./tool-cards.js";
22
22
  import type {
23
23
  SlackAccessPolicy,
24
24
  SlackChannelState,
25
25
  SlackCredentials,
26
26
  SlackMessageHandler,
27
+ SlackReplyOptions,
27
28
  SlackRespondTo,
28
29
  SlackSuggestedPrompt,
30
+ SlackToolLabels,
29
31
  } from "./types.js";
30
32
 
31
33
  const SLACK_TURN_FAILURE_FALLBACK =
@@ -58,9 +60,8 @@ export function formatSlackTurnFailureMessage(raw: string | undefined): string {
58
60
  }
59
61
 
60
62
  function scrubSlackErrorDetail(message: string): string {
61
- const scrubbed = message
63
+ const scrubbed = redactSecretTokens(message)
62
64
  .replace(/https?:\/\/\S+/gi, "[url]")
63
- .replace(/\b(crsr_|xox[baprs]-|sk-|Bearer\s+)\S+/gi, "[redacted]")
64
65
  .replace(/\/(?:home|Users|var\/folders)\/\S+/g, "[path]")
65
66
  .replace(/\b[A-Za-z]:(?:\\|\/)[^\s]+/g, "[path]")
66
67
  .replace(/\\\\[^\s]+/g, "[path]")
@@ -125,19 +126,24 @@ export const defaultOnChannelPost: SlackMessageHandler =
125
126
 
126
127
  export interface BuildDefaultEventsOptions {
127
128
  credentials?: SlackCredentials;
129
+ /** Same shape as `slackChannel({ reply })`; see {@link SlackReplyOptions}. */
130
+ reply?: SlackReplyOptions;
131
+ /** Same as `slackChannel({ toolLabels })`. */
132
+ toolLabels?: SlackToolLabels;
133
+ /** @deprecated Use `reply`. */
128
134
  streaming?: boolean;
135
+ /** @deprecated Use `reply`. */
129
136
  thinkingSteps?: boolean;
137
+ /** @deprecated Use `reply.status.idle`. */
138
+ loadingMessages?: readonly string[];
130
139
  suggestedPrompts?: SlackSuggestedPrompt[];
131
140
  suggestedPromptsTitle?: string;
132
- /** Rotating assistant status lines; defaults to pack constants. */
133
- loadingMessages?: readonly string[];
134
141
  /** Resolved per-call so channel onStart can rebind the server logger. */
135
142
  getLog?: () => SlackLog;
136
143
  }
137
144
 
138
145
  /**
139
146
  * Build default stream-event handlers (typing, streaming, replies).
140
- * Streaming / thinking default to ON.
141
147
  *
142
148
  * Tool-approval cards are a separate primitive — compose with
143
149
  * `buildToolApprovalEvents` or set `toolApprovals: true` on `slackChannel`.
@@ -146,14 +152,77 @@ export function buildDefaultEvents(
146
152
  options: BuildDefaultEventsOptions = {}
147
153
  ): ChannelEventHandlers<SlackChannelState> {
148
154
  const credentials = options.credentials;
149
- const streaming = options.streaming !== false;
150
- const thinkingSteps = options.thinkingSteps !== false;
155
+ const reply = resolveSlackReply({
156
+ reply: options.reply,
157
+ toolLabels: options.toolLabels,
158
+ streaming: options.streaming,
159
+ thinkingSteps: options.thinkingSteps,
160
+ loadingMessages: options.loadingMessages,
161
+ });
162
+ const streaming = reply.mode === "stream";
151
163
  const suggestedPrompts = options.suggestedPrompts ?? [];
152
164
  const suggestedPromptsTitle = options.suggestedPromptsTitle;
153
- const loadingMessages = resolveLoadingMessages(options.loadingMessages);
165
+ const loadingMessages = reply.status.idle;
154
166
  const botToken = credentials?.botToken;
155
167
  const getLog = options.getLog ?? (() => defaultSlackLog);
156
168
  const strategy = createStreamDeliveryStrategy({ botToken, getLog });
169
+ const progress = createProgressDelivery({ botToken, getLog });
170
+
171
+ const streamLive = (state: SlackChannelState): boolean =>
172
+ streaming && !state.streamingUnavailable;
173
+
174
+ const streamTarget = (
175
+ channel: ChannelEventContext<SlackChannelState>
176
+ ): string | null => {
177
+ const channelId = channel.state.streamChannelId ?? channel.state.channelId;
178
+ if (
179
+ channelId === null ||
180
+ channelId === "" ||
181
+ channel.state.threadTs === null
182
+ ) {
183
+ return null;
184
+ }
185
+ return channelId;
186
+ };
187
+
188
+ const sendCards = async (args: {
189
+ channel: ChannelEventContext<SlackChannelState>;
190
+ sessionId: string;
191
+ chunks: StreamTaskChunk[];
192
+ }): Promise<boolean> => {
193
+ if (!streamLive(args.channel.state)) {
194
+ return false;
195
+ }
196
+ const channelId = streamTarget(args.channel);
197
+ if (channelId === null) {
198
+ return false;
199
+ }
200
+ return strategy.appendChunks({ ...args, channelId });
201
+ };
202
+
203
+ const reasoning: ReasoningCard | null =
204
+ reply.reasoningCard === false
205
+ ? null
206
+ : createReasoningCard(reply.reasoningCard, ({ chunk, ...rest }) =>
207
+ sendCards({ ...rest, chunks: [chunk] })
208
+ );
209
+ const toolCards: ToolCards | null =
210
+ reply.toolCards === false
211
+ ? null
212
+ : createToolCards(reply.toolCards, reply.toolLabel);
213
+
214
+ const completeReasoning = async (
215
+ channel: ChannelEventContext<SlackChannelState>,
216
+ sessionId: string
217
+ ): Promise<void> => {
218
+ if (reasoning?.inProgress(channel)) {
219
+ await reasoning.flush({ channel, sessionId, status: "complete" });
220
+ }
221
+ };
222
+
223
+ /** Subagent events carry `parentCallId`; cards and the reply are the parent's. */
224
+ const nested = (event: { data: { parentCallId?: string } }): boolean =>
225
+ event.data.parentCallId !== undefined;
157
226
 
158
227
  const clearWorkingStatus = async (
159
228
  channelId: string,
@@ -174,6 +243,62 @@ export function buildDefaultEvents(
174
243
  }
175
244
  };
176
245
 
246
+ const finishProgress = async (args: {
247
+ channel: ChannelEventContext<SlackChannelState>;
248
+ text: string;
249
+ sessionId: string;
250
+ }): Promise<boolean> => {
251
+ const log = getLog();
252
+ const state = args.channel.state;
253
+ if (
254
+ state.channelId === null ||
255
+ state.threadTs === null ||
256
+ args.text === ""
257
+ ) {
258
+ return false;
259
+ }
260
+ if (await progress.replace({ channel: args.channel, text: args.text })) {
261
+ log.info("reply delivered via progress update", {
262
+ channel: state.channelId,
263
+ thread_ts: state.threadTs,
264
+ session: args.sessionId,
265
+ chars: args.text.length,
266
+ });
267
+ return true;
268
+ }
269
+ await progress.clear({ channel: args.channel });
270
+ try {
271
+ const posted = await postMessage({
272
+ botToken,
273
+ channel: state.channelId,
274
+ text: args.text,
275
+ threadTs: state.threadTs,
276
+ });
277
+ state.lastPostedText = args.text;
278
+ state.lastBotMessageTs = posted.ts;
279
+ log.info("reply delivered via postMessage", {
280
+ channel: state.channelId,
281
+ thread_ts: state.threadTs,
282
+ message_ts: posted.ts,
283
+ session: args.sessionId,
284
+ chars: args.text.length,
285
+ });
286
+ return true;
287
+ } catch (error) {
288
+ log.error(
289
+ `postMessage failed: ${
290
+ error instanceof Error ? error.message : String(error)
291
+ }`,
292
+ {
293
+ channel: state.channelId,
294
+ thread_ts: state.threadTs,
295
+ session: args.sessionId,
296
+ }
297
+ );
298
+ return false;
299
+ }
300
+ };
301
+
177
302
  /**
178
303
  * Deliver assistant text to the bound Slack thread. Used by a stop-reason
179
304
  * `message.completed` and by `turn.completed` when the last assistant
@@ -185,7 +310,6 @@ export function buildDefaultEvents(
185
310
  text: string;
186
311
  sessionId: string;
187
312
  }): Promise<boolean> => {
188
- const log = getLog();
189
313
  const state = args.channel.state;
190
314
  if (
191
315
  state.channelId === null ||
@@ -199,8 +323,7 @@ export function buildDefaultEvents(
199
323
  // pending. Treat a match as "already on Slack", not "already finalized".
200
324
  const streamTs = state.streamTs;
201
325
  if (streamTs !== null && streamTs !== "") {
202
- const canStream = streaming && state.streamingUnavailable !== true;
203
- if (canStream) {
326
+ if (streamLive(state)) {
204
327
  await strategy.finalize({
205
328
  channel: args.channel,
206
329
  channelId: state.streamChannelId ?? state.channelId,
@@ -214,8 +337,7 @@ export function buildDefaultEvents(
214
337
  return true;
215
338
  }
216
339
 
217
- const canStream = streaming && state.streamingUnavailable !== true;
218
- if (canStream) {
340
+ if (streamLive(state)) {
219
341
  const { delivered } = await strategy.finalize({
220
342
  channel: args.channel,
221
343
  channelId: state.streamChannelId ?? state.channelId,
@@ -227,47 +349,23 @@ export function buildDefaultEvents(
227
349
  }
228
350
  }
229
351
 
230
- try {
231
- const posted = await postMessage({
232
- botToken,
233
- channel: state.channelId,
234
- text: args.text,
235
- threadTs: state.threadTs,
236
- });
237
- state.lastPostedText = args.text;
238
- state.lastBotMessageTs = posted.ts;
239
- log.info("reply delivered via postMessage", {
240
- channel: state.channelId,
241
- thread_ts: state.threadTs,
242
- message_ts: posted.ts,
243
- session: args.sessionId,
244
- chars: args.text.length,
245
- });
246
- return true;
247
- } catch (error) {
248
- log.error(
249
- `postMessage failed: ${
250
- error instanceof Error ? error.message : String(error)
251
- }`,
252
- {
253
- channel: state.channelId,
254
- thread_ts: state.threadTs,
255
- session: args.sessionId,
256
- }
257
- );
258
- return false;
259
- }
352
+ return finishProgress(args);
260
353
  };
261
354
 
262
355
  return {
263
356
  async "turn.started"(event, channel) {
264
357
  const log = getLog();
358
+ await progress.clear({ channel });
265
359
  channel.state.pendingToolCallMessage = null;
266
360
  channel.state.lastReasoningTypingAtMs = null;
267
361
  channel.state.lastReasoningTypingStatus = null;
268
362
  channel.state.streamTs = null;
269
363
  channel.state.streamChannelId = null;
364
+ channel.state.streamFull = false;
270
365
  channel.state.lastPostedText = null;
366
+ channel.state.streamBlockText = null;
367
+ channel.state.reasoningCard = undefined;
368
+ channel.state.toolCardCounts = {};
271
369
  // Keep lastBotMessageTs across turns — warm delta watermark.
272
370
  channel.state.approvalMessageByCallId = {};
273
371
 
@@ -293,16 +391,16 @@ export function buildDefaultEvents(
293
391
  },
294
392
 
295
393
  async "message.appended"(event, channel) {
296
- if (!streaming || channel.state.streamingUnavailable === true) {
394
+ // Nested (subagent) text is not the reply.
395
+ if (nested(event) || !streamLive(channel.state)) {
297
396
  return;
298
397
  }
299
- const channelId =
300
- channel.state.streamChannelId ?? channel.state.channelId;
301
- const threadTs = channel.state.threadTs;
302
- if (channelId === null || channelId === "" || threadTs === null) {
398
+ const channelId = streamTarget(channel);
399
+ if (channelId === null) {
303
400
  return;
304
401
  }
305
402
 
403
+ await completeReasoning(channel, event.sessionId);
306
404
  await strategy.append({
307
405
  channel,
308
406
  channelId,
@@ -312,6 +410,18 @@ export function buildDefaultEvents(
312
410
  },
313
411
 
314
412
  async "reasoning.appended"(event, channel) {
413
+ if (!nested(event)) {
414
+ await reasoning?.append({
415
+ channel,
416
+ sessionId: event.sessionId,
417
+ text: event.data.text,
418
+ });
419
+ }
420
+
421
+ // The chip is hidden while a stream is open.
422
+ if (!reply.status.reasoning || channel.state.streamTs !== null) {
423
+ return;
424
+ }
315
425
  const line = firstNonEmptyLine(event.data.text);
316
426
  if (line === undefined) {
317
427
  return;
@@ -335,110 +445,117 @@ export function buildDefaultEvents(
335
445
  if (channel.state.channelId === null || channel.state.threadTs === null) {
336
446
  return;
337
447
  }
448
+ // One entry: Slack cycles `loading_messages` every couple of seconds,
449
+ // so padding an informative line with the rotation makes the chip
450
+ // flip between the reasoning and filler until the next update.
338
451
  await setThreadStatus({
339
452
  botToken,
340
453
  channelId: channel.state.channelId,
341
454
  threadTs: channel.state.threadTs,
342
455
  status,
343
- loadingMessages: [
344
- status,
345
- ...loadingMessages.filter((message) => message !== status),
346
- ],
456
+ loadingMessages: [status],
347
457
  });
348
458
  channel.state.lastReasoningTypingAtMs = now;
349
459
  channel.state.lastReasoningTypingStatus = status;
350
460
  },
351
461
 
462
+ async "reasoning.completed"(event, channel) {
463
+ if (reasoning === null || nested(event)) {
464
+ return;
465
+ }
466
+ reasoning.endBlock(channel);
467
+ await reasoning.flush({
468
+ channel,
469
+ sessionId: event.sessionId,
470
+ status: "in_progress",
471
+ });
472
+ },
473
+
352
474
  async "actions.requested"(event, channel) {
353
475
  const pending = channel.state.pendingToolCallMessage;
354
476
  channel.state.pendingToolCallMessage = null;
355
- const names = event.data.calls.map((call) => call.toolName);
477
+ const calls = event.data.calls;
478
+
479
+ if (toolCards !== null && strategy.inlineToolSteps && !nested(event)) {
480
+ // Card order: the thinking that led to these tools goes first.
481
+ await reasoning?.flush({
482
+ channel,
483
+ sessionId: event.sessionId,
484
+ status: "in_progress",
485
+ });
486
+ const streamed = await sendCards({
487
+ channel,
488
+ sessionId: event.sessionId,
489
+ chunks: toolCards.forCalls(channel.state, calls),
490
+ });
491
+ // An open stream hides the chip; skip the status write.
492
+ if (streamed) {
493
+ return;
494
+ }
495
+ }
356
496
 
497
+ if (reply.status.tools === false) {
498
+ return;
499
+ }
357
500
  const statusText =
358
501
  pending !== null
359
502
  ? truncateTypingStatus(pending)
360
- : truncateTypingStatus(`Running ${names.join(", ")}…`);
361
-
503
+ : truncateTypingStatus(reply.status.tools(calls));
504
+ if (channel.state.channelId === null || channel.state.threadTs === null) {
505
+ return;
506
+ }
507
+ // Hold the tool line steady; see reasoning.appended.
508
+ await setThreadStatus({
509
+ botToken,
510
+ channelId: channel.state.channelId,
511
+ threadTs: channel.state.threadTs,
512
+ status: statusText,
513
+ loadingMessages: [statusText],
514
+ });
362
515
  if (
363
- strategy.inlineToolSteps &&
364
- thinkingSteps &&
365
- streaming &&
366
- channel.state.streamingUnavailable !== true
516
+ toolCards !== null &&
517
+ channel.state.streamingUnavailable === true &&
518
+ (channel.state.streamTs === null || channel.state.streamTs === "")
367
519
  ) {
368
- const channelId =
369
- channel.state.streamChannelId ?? channel.state.channelId;
370
- const threadTs = channel.state.threadTs;
371
- if (channelId !== null && channelId !== "" && threadTs !== null) {
372
- const chunks = buildTaskChunksForCalls(
373
- event.data.calls,
374
- "in_progress"
375
- );
376
- const streamed = await strategy.appendChunks({
377
- channel,
378
- channelId,
379
- chunks,
380
- sessionId: event.sessionId,
381
- });
382
- if (streamed) {
383
- if (
384
- channel.state.channelId !== null &&
385
- channel.state.threadTs !== null
386
- ) {
387
- await setThreadStatus({
388
- botToken,
389
- channelId: channel.state.channelId,
390
- threadTs: channel.state.threadTs,
391
- status: statusText,
392
- });
393
- }
394
- return;
395
- }
396
- }
397
- }
398
-
399
- if (channel.state.channelId !== null && channel.state.threadTs !== null) {
400
- await setThreadStatus({
401
- botToken,
402
- channelId: channel.state.channelId,
403
- threadTs: channel.state.threadTs,
404
- status: statusText,
405
- });
520
+ await progress.upsert({ channel, text: statusText });
406
521
  }
407
522
  },
408
523
 
409
524
  async "action.result"(event, channel) {
525
+ const streamTs = channel.state.streamTs;
410
526
  if (
527
+ toolCards === null ||
411
528
  !strategy.inlineToolSteps ||
412
- !thinkingSteps ||
413
- !streaming ||
414
- channel.state.streamingUnavailable === true ||
415
- channel.state.streamTs === null ||
416
- channel.state.streamTs === ""
529
+ nested(event) ||
530
+ streamTs === null ||
531
+ streamTs === ""
417
532
  ) {
418
533
  return;
419
534
  }
420
- const channelId =
421
- channel.state.streamChannelId ?? channel.state.channelId;
422
- if (channelId === null || channelId === "") {
423
- return;
424
- }
425
- const chunk = buildTaskChunkForResult({
426
- callId: event.data.callId,
427
- toolName: event.data.toolName,
428
- isError: event.data.isError,
429
- });
430
- await appendChatStream({
431
- botToken,
432
- channel: channelId,
433
- ts: channel.state.streamTs,
434
- chunks: [chunk],
535
+ await sendCards({
536
+ channel,
537
+ sessionId: event.sessionId,
538
+ chunks: [
539
+ toolCards.forResult(channel.state, {
540
+ callId: event.data.callId,
541
+ toolName: event.data.toolName,
542
+ output: event.data.output,
543
+ isError: event.data.isError,
544
+ }),
545
+ ],
435
546
  });
436
547
  },
437
548
 
438
549
  async "message.completed"(event, channel) {
550
+ if (nested(event)) {
551
+ return;
552
+ }
439
553
  if (event.data.finishReason === "tool_call") {
440
554
  channel.state.pendingToolCallMessage =
441
555
  firstNonEmptyLine(event.data.text) ?? null;
556
+ // The harness restarts its cumulative text after a tool call, so the
557
+ // next block appends in full instead of diffing against this one.
558
+ channel.state.streamBlockText = null;
442
559
  return;
443
560
  }
444
561
  channel.state.pendingToolCallMessage = null;
@@ -448,10 +565,13 @@ export function buildDefaultEvents(
448
565
  return;
449
566
  }
450
567
 
568
+ await completeReasoning(channel, event.sessionId);
569
+
451
570
  // Empty final text: still close any open stream / clear the skeleton
452
571
  // and clear typing.
453
572
  if (event.data.text === "") {
454
573
  await strategy.finalizeEmpty({ channel });
574
+ await progress.clear({ channel });
455
575
  await clearWorkingStatus(state.channelId, state.threadTs);
456
576
  return;
457
577
  }
@@ -482,6 +602,7 @@ export function buildDefaultEvents(
482
602
  typeof result === "string" &&
483
603
  result !== "" &&
484
604
  result !== channel.state.lastPostedText;
605
+ await completeReasoning(channel, event.sessionId);
485
606
  if (unpublished) {
486
607
  await deliverReplyText({
487
608
  channel,
@@ -492,6 +613,7 @@ export function buildDefaultEvents(
492
613
  // Always close leftovers. deliverReplyText may fall through to
493
614
  // postMessage when streaming is unavailable and leave streamTs open.
494
615
  await strategy.cleanupOrphan({ channel });
616
+ await progress.clear({ channel });
495
617
 
496
618
  // Always drop the assistant chip. message.completed already clears
497
619
  // after a normal reply, but a tool-call-only finish (or a missed
@@ -539,7 +661,8 @@ export function buildDefaultEvents(
539
661
  const errorText = formatSlackTurnFailureMessage(event.data.message);
540
662
 
541
663
  let delivered = false;
542
- if (streaming && state.streamingUnavailable !== true) {
664
+ if (streamLive(state)) {
665
+ await completeReasoning(channel, event.sessionId);
543
666
  ({ delivered } = await strategy.fail({
544
667
  channel,
545
668
  channelId: state.streamChannelId ?? state.channelId,
@@ -548,25 +671,11 @@ export function buildDefaultEvents(
548
671
  }));
549
672
  }
550
673
  if (!delivered) {
551
- try {
552
- await postMessage({
553
- botToken,
554
- channel: state.channelId,
555
- text: errorText,
556
- threadTs: state.threadTs,
557
- });
558
- } catch (error) {
559
- log.error(
560
- `turn.failed postMessage failed: ${
561
- error instanceof Error ? error.message : String(error)
562
- }`,
563
- {
564
- channel: state.channelId,
565
- thread_ts: state.threadTs,
566
- session: event.sessionId,
567
- }
568
- );
569
- }
674
+ await finishProgress({
675
+ channel,
676
+ text: errorText,
677
+ sessionId: event.sessionId,
678
+ });
570
679
  }
571
680
  await clearWorkingStatus(state.channelId, state.threadTs);
572
681
  },
@@ -36,6 +36,7 @@ import {
36
36
  import type { EventIdDedupe } from "./event-id-dedupe.js";
37
37
  import { isExternalSlackSender } from "./external-policy.js";
38
38
  import {
39
+ describeSlackEventShape,
39
40
  formatSlackContextBlock,
40
41
  parseAppMentionEvent,
41
42
  parseAssistantThreadStarted,
@@ -126,9 +127,14 @@ export function emptySlackChannelState(
126
127
  streamTs: null,
127
128
  streamChannelId: null,
128
129
  lastPostedText: null,
130
+ streamBlockText: null,
129
131
  lastBotMessageTs: null,
130
132
  streamingUnavailable: false,
133
+ streamFull: false,
134
+ progressTs: null,
131
135
  approvalMessageByCallId: {},
136
+ reasoningCard: undefined,
137
+ toolCardCounts: {},
132
138
  ...patch,
133
139
  };
134
140
  }
@@ -795,6 +801,9 @@ export function dispatchInboundFromEventBody(
795
801
  }
796
802
  }
797
803
 
798
- log.debug("inbound ignored (unhandled event shape)", { event_id: eventId });
804
+ log.debug("inbound ignored (unhandled event shape)", {
805
+ ...describeSlackEventShape(body),
806
+ event_id: eventId,
807
+ });
799
808
  return false;
800
809
  }
@@ -20,6 +20,23 @@ function asString(value: unknown): string | undefined {
20
20
  return typeof value === "string" ? value : undefined;
21
21
  }
22
22
 
23
+ /**
24
+ * `type` / `subtype` of an Events API body's inner event, for log lines about
25
+ * payloads no parser claimed (own-bot echoes, `message_changed`, pane
26
+ * context changes). Never throws on odd shapes.
27
+ */
28
+ export function describeSlackEventShape(body: unknown): {
29
+ event_type: string;
30
+ event_subtype?: string;
31
+ } {
32
+ const root = asRecord(body);
33
+ const event = asRecord(root?.event);
34
+ return {
35
+ event_type: asString(event?.type) ?? asString(root?.type) ?? "unknown",
36
+ event_subtype: asString(event?.subtype),
37
+ };
38
+ }
39
+
23
40
  /** Strip common Slack mention tokens for a cleaner model prompt. */
24
41
  export function slackTextToMarkdown(text: string): string {
25
42
  return text
@@ -46,4 +46,5 @@ export * from "./stop.js";
46
46
  export * from "./stream.js";
47
47
  export * from "./thread-context.js";
48
48
  export * from "./tool-approval-events.js";
49
+ export { defaultToolCardDetails } from "./tool-cards.js";
49
50
  export * from "./types.js";