@cursor/july 0.1.96 → 0.1.99

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 (381) hide show
  1. package/AGENTS.md +1 -1
  2. package/README.md +3 -2
  3. package/dist/bin/agent-serve.js +13 -3
  4. package/dist/channels/github/github-channel.d.ts.map +1 -1
  5. package/dist/channels/github/github-channel.js +16 -0
  6. package/dist/channels/origin/api.d.ts +15 -4
  7. package/dist/channels/origin/api.d.ts.map +1 -1
  8. package/dist/channels/origin/api.js +19 -3
  9. package/dist/channels/origin/binding.d.ts +11 -0
  10. package/dist/channels/origin/binding.d.ts.map +1 -1
  11. package/dist/channels/origin/binding.js +41 -25
  12. package/dist/channels/origin/index.d.ts +1 -0
  13. package/dist/channels/origin/index.d.ts.map +1 -1
  14. package/dist/channels/origin/index.js +1 -0
  15. package/dist/channels/origin/origin-channel.d.ts +2 -0
  16. package/dist/channels/origin/origin-channel.d.ts.map +1 -1
  17. package/dist/channels/origin/origin-channel.js +40 -4
  18. package/dist/channels/origin/reactions.d.ts +56 -0
  19. package/dist/channels/origin/reactions.d.ts.map +1 -0
  20. package/dist/channels/origin/reactions.js +67 -0
  21. package/dist/channels/origin/types.d.ts +11 -0
  22. package/dist/channels/origin/types.d.ts.map +1 -1
  23. package/dist/channels/slack/approvals.d.ts +16 -0
  24. package/dist/channels/slack/approvals.d.ts.map +1 -1
  25. package/dist/channels/slack/approvals.js +86 -0
  26. package/dist/channels/slack/cli-project.d.ts +19 -0
  27. package/dist/channels/slack/cli-project.d.ts.map +1 -0
  28. package/dist/channels/slack/cli-project.js +234 -0
  29. package/dist/channels/slack/defaults.d.ts.map +1 -1
  30. package/dist/channels/slack/defaults.js +142 -63
  31. package/dist/channels/slack/dispatch.d.ts.map +1 -1
  32. package/dist/channels/slack/dispatch.js +1 -1
  33. package/dist/channels/slack/init.d.ts +3 -2
  34. package/dist/channels/slack/init.d.ts.map +1 -1
  35. package/dist/channels/slack/init.js +5 -5
  36. package/dist/channels/slack/interactive.d.ts +2 -1
  37. package/dist/channels/slack/interactive.d.ts.map +1 -1
  38. package/dist/channels/slack/interactive.js +15 -4
  39. package/dist/channels/slack/live-delivery.d.ts +1 -1
  40. package/dist/channels/slack/live-delivery.d.ts.map +1 -1
  41. package/dist/channels/slack/live-delivery.js +4 -2
  42. package/dist/channels/slack/manifest.d.ts +1 -1
  43. package/dist/channels/slack/manifest.js +1 -1
  44. package/dist/channels/slack/progress-delivery.d.ts +28 -0
  45. package/dist/channels/slack/progress-delivery.d.ts.map +1 -0
  46. package/dist/channels/slack/progress-delivery.js +115 -0
  47. package/dist/channels/slack/setup.d.ts +1 -1
  48. package/dist/channels/slack/setup.d.ts.map +1 -1
  49. package/dist/channels/slack/setup.js +10 -6
  50. package/dist/channels/slack/slack-channel.d.ts.map +1 -1
  51. package/dist/channels/slack/slack-channel.js +1 -0
  52. package/dist/channels/slack/tool-approval-events.d.ts.map +1 -1
  53. package/dist/channels/slack/tool-approval-events.js +91 -1
  54. package/dist/channels/slack/types.d.ts +9 -1
  55. package/dist/channels/slack/types.d.ts.map +1 -1
  56. package/dist/docs/404.html +2 -2
  57. package/dist/docs/ab.html +4 -4
  58. package/dist/docs/assets/{app.jXleCmOc.js → app.BplEAZ3S.js} +1 -1
  59. package/dist/docs/assets/chunks/@localSearchIndexroot.DpuI4i7Z.js +1 -0
  60. package/dist/docs/assets/chunks/{VPLocalSearchBox.8LhyglIT.js → VPLocalSearchBox.CHXyv4wP.js} +1 -1
  61. package/dist/docs/assets/chunks/{theme.9ged-pr2.js → theme.BTcsZmjQ.js} +2 -2
  62. package/dist/docs/assets/{deployment.md.D9msOFOW.js → deployment.md.MFPKqsqI.js} +2 -2
  63. package/dist/docs/assets/{guides_mcp-oauth.md.DPYmBCbV.js → guides_mcp-oauth.md.CN-6YmTJ.js} +4 -4
  64. package/dist/docs/assets/{guides_mcp-oauth.md.DPYmBCbV.lean.js → guides_mcp-oauth.md.CN-6YmTJ.lean.js} +1 -1
  65. package/dist/docs/assets/guides_slack.md.VDXQV3ja.js +22 -0
  66. package/dist/docs/assets/guides_slack.md.VDXQV3ja.lean.js +1 -0
  67. package/dist/docs/assets/index.md.CVeRUOeZ.js +5 -0
  68. package/dist/docs/assets/{reference_agent-config.md.Cp_x38Nl.js → reference_agent-config.md.BHeYMgme.js} +1 -1
  69. package/dist/docs/assets/{reference_cli.md.CCnG-nJx.js → reference_cli.md.DfoeyvL0.js} +9 -6
  70. package/dist/docs/assets/{reference_cli.md.CCnG-nJx.lean.js → reference_cli.md.DfoeyvL0.lean.js} +1 -1
  71. package/dist/docs/assets/{reference_connections.md.BH8Oc0D0.js → reference_connections.md.DxldvyIB.js} +4 -3
  72. package/dist/docs/assets/{reference_http-api.md.D89k1mdm.js → reference_http-api.md.BEJx9XVj.js} +2 -2
  73. package/dist/docs/assets/reference_sessions.md.NxFP_CAC.js +1 -0
  74. package/dist/docs/assets/{reference_tools.md.BHeXn2id.js → reference_tools.md.CvAHsdSp.js} +10 -2
  75. package/dist/docs/assets/{reference_tools.md.BHeXn2id.lean.js → reference_tools.md.CvAHsdSp.lean.js} +1 -1
  76. package/dist/docs/assets/templates_agents-md.md.CXSMZljE.js +2 -0
  77. package/dist/docs/assets/templates_agents-md.md.CXSMZljE.lean.js +1 -0
  78. package/dist/docs/assets/troubleshooting.md.DCiPBhYs.js +1 -0
  79. package/dist/docs/building-with-agents.html +4 -4
  80. package/dist/docs/concepts.html +4 -4
  81. package/dist/docs/deployment.html +7 -7
  82. package/dist/docs/deployment.md +5 -4
  83. package/dist/docs/design/runtime-abstraction.md +1757 -0
  84. package/dist/docs/evals.html +4 -4
  85. package/dist/docs/guides/agent-to-agent.html +4 -4
  86. package/dist/docs/guides/cloud-runtime.html +4 -4
  87. package/dist/docs/guides/convert-automation.html +4 -4
  88. package/dist/docs/guides/github.html +4 -4
  89. package/dist/docs/guides/human-in-the-loop.html +4 -4
  90. package/dist/docs/guides/mcp-oauth.html +8 -8
  91. package/dist/docs/guides/mcp-oauth.md +26 -8
  92. package/dist/docs/guides/opentelemetry.html +4 -4
  93. package/dist/docs/guides/slack.html +17 -33
  94. package/dist/docs/guides/slack.md +92 -201
  95. package/dist/docs/guides/webhooks.html +4 -4
  96. package/dist/docs/hashmap.json +1 -1
  97. package/dist/docs/hillclimbing.html +4 -4
  98. package/dist/docs/index.html +6 -6
  99. package/dist/docs/index.md +5 -3
  100. package/dist/docs/llms-full.txt +2065 -637
  101. package/dist/docs/llms.txt +3 -2
  102. package/dist/docs/quickstart.html +4 -4
  103. package/dist/docs/reference/agent-config.html +6 -6
  104. package/dist/docs/reference/agent-config.md +2 -2
  105. package/dist/docs/reference/artifacts.html +4 -4
  106. package/dist/docs/reference/channels.html +4 -4
  107. package/dist/docs/reference/cli.html +13 -10
  108. package/dist/docs/reference/cli.md +32 -16
  109. package/dist/docs/reference/connections.html +9 -8
  110. package/dist/docs/reference/connections.md +6 -3
  111. package/dist/docs/reference/hooks.html +4 -4
  112. package/dist/docs/reference/http-api.html +7 -7
  113. package/dist/docs/reference/http-api.md +3 -1
  114. package/dist/docs/reference/instructions.html +4 -4
  115. package/dist/docs/reference/playground.html +4 -4
  116. package/dist/docs/reference/project-layout.html +4 -4
  117. package/dist/docs/reference/prompt.html +4 -4
  118. package/dist/docs/reference/schedules.html +4 -4
  119. package/dist/docs/reference/sessions.html +5 -5
  120. package/dist/docs/reference/sessions.md +4 -2
  121. package/dist/docs/reference/skills.html +4 -4
  122. package/dist/docs/reference/subagents.html +4 -4
  123. package/dist/docs/reference/tools.html +15 -7
  124. package/dist/docs/reference/tools.md +34 -2
  125. package/dist/docs/scaffolding-agents.html +4 -4
  126. package/dist/docs/storage.html +4 -4
  127. package/dist/docs/templates/agentic-owners.html +4 -4
  128. package/dist/docs/templates/agents-md.html +28 -0
  129. package/dist/docs/templates/agents-md.md +105 -0
  130. package/dist/docs/templates/code-wiki.html +5 -5
  131. package/dist/docs/templates/demo.html +4 -4
  132. package/dist/docs/templates/pr-autofixer.html +4 -4
  133. package/dist/docs/templates/security-help.html +4 -4
  134. package/dist/docs/templates/security-reviewer.html +5 -5
  135. package/dist/docs/templates/triage.html +4 -4
  136. package/dist/docs/troubleshooting.html +5 -5
  137. package/dist/docs/troubleshooting.md +2 -2
  138. package/dist/evals/run-facts.d.ts.map +1 -1
  139. package/dist/evals/run-facts.js +27 -0
  140. package/dist/files-backends/cursor-hosted.d.ts +3 -2
  141. package/dist/files-backends/cursor-hosted.d.ts.map +1 -1
  142. package/dist/files-backends/cursor-hosted.js +3 -2
  143. package/dist/index.d.ts +1 -0
  144. package/dist/index.d.ts.map +1 -1
  145. package/dist/index.js +1 -0
  146. package/dist/internal/advertise-tools.d.ts.map +1 -1
  147. package/dist/internal/advertise-tools.js +15 -9
  148. package/dist/internal/approval-gate.d.ts +12 -13
  149. package/dist/internal/approval-gate.d.ts.map +1 -1
  150. package/dist/internal/approval-gate.js +16 -21
  151. package/dist/internal/as-of.d.ts +19 -0
  152. package/dist/internal/as-of.d.ts.map +1 -0
  153. package/dist/internal/as-of.js +82 -0
  154. package/dist/internal/chat-client.js +10 -0
  155. package/dist/internal/cli-deploy.d.ts +6 -0
  156. package/dist/internal/cli-deploy.d.ts.map +1 -1
  157. package/dist/internal/cli-deploy.js +149 -21
  158. package/dist/internal/cli-mcp-oauth.js +8 -18
  159. package/dist/internal/cli-slack-manual.d.ts +24 -2
  160. package/dist/internal/cli-slack-manual.d.ts.map +1 -1
  161. package/dist/internal/cli-slack-manual.js +251 -20
  162. package/dist/internal/cli-slack.d.ts +9 -2
  163. package/dist/internal/cli-slack.d.ts.map +1 -1
  164. package/dist/internal/cli-slack.js +29 -82
  165. package/dist/internal/cursor/account-mcp.d.ts +1 -0
  166. package/dist/internal/cursor/account-mcp.d.ts.map +1 -1
  167. package/dist/internal/cursor/account-mcp.js +17 -0
  168. package/dist/internal/cursor-agent-template.d.ts +1 -1
  169. package/dist/internal/cursor-agent-template.d.ts.map +1 -1
  170. package/dist/internal/cursor-agent-template.js +1 -0
  171. package/dist/internal/cursor-event-relay.d.ts.map +1 -1
  172. package/dist/internal/cursor-event-relay.js +5 -6
  173. package/dist/internal/deploy-client.d.ts +17 -0
  174. package/dist/internal/deploy-client.d.ts.map +1 -1
  175. package/dist/internal/deploy-client.js +31 -10
  176. package/dist/internal/env-file.d.ts +19 -0
  177. package/dist/internal/env-file.d.ts.map +1 -0
  178. package/dist/internal/env-file.js +90 -0
  179. package/dist/internal/framework-file-storage.d.ts +11 -17
  180. package/dist/internal/framework-file-storage.d.ts.map +1 -1
  181. package/dist/internal/framework-file-storage.js +17 -40
  182. package/dist/internal/framework-storage-selection.d.ts +13 -11
  183. package/dist/internal/framework-storage-selection.d.ts.map +1 -1
  184. package/dist/internal/framework-storage-selection.js +37 -26
  185. package/dist/internal/hosted-admission-adapter.d.ts +28 -0
  186. package/dist/internal/hosted-admission-adapter.d.ts.map +1 -0
  187. package/dist/internal/hosted-admission-adapter.js +7 -0
  188. package/dist/internal/hosted-delivery-protocol.d.ts +13 -1
  189. package/dist/internal/hosted-delivery-protocol.d.ts.map +1 -1
  190. package/dist/internal/hosted-delivery-protocol.js +8 -1
  191. package/dist/internal/hosted-delivery.d.ts +21 -1
  192. package/dist/internal/hosted-delivery.d.ts.map +1 -1
  193. package/dist/internal/hosted-delivery.js +101 -34
  194. package/dist/internal/hosted-execution-diag.d.ts +59 -0
  195. package/dist/internal/hosted-execution-diag.d.ts.map +1 -0
  196. package/dist/internal/hosted-execution-diag.js +187 -0
  197. package/dist/internal/http-channel.d.ts.map +1 -1
  198. package/dist/internal/http-channel.js +85 -2
  199. package/dist/internal/init-project.d.ts.map +1 -1
  200. package/dist/internal/init-project.js +2 -0
  201. package/dist/internal/logs-client.d.ts +5 -0
  202. package/dist/internal/logs-client.d.ts.map +1 -1
  203. package/dist/internal/logs-client.js +5 -0
  204. package/dist/internal/mcp-endpoint.js +2 -3
  205. package/dist/internal/mcp-host.d.ts +10 -0
  206. package/dist/internal/mcp-host.d.ts.map +1 -1
  207. package/dist/internal/mcp-host.js +57 -8
  208. package/dist/internal/mcp-oauth-on-demand.d.ts +68 -0
  209. package/dist/internal/mcp-oauth-on-demand.d.ts.map +1 -0
  210. package/dist/internal/mcp-oauth-on-demand.js +287 -0
  211. package/dist/internal/mcp-oauth-persist.d.ts +42 -0
  212. package/dist/internal/mcp-oauth-persist.d.ts.map +1 -0
  213. package/dist/internal/mcp-oauth-persist.js +92 -0
  214. package/dist/internal/mcp-oauth.d.ts +1 -0
  215. package/dist/internal/mcp-oauth.d.ts.map +1 -1
  216. package/dist/internal/mcp-oauth.js +10 -2
  217. package/dist/internal/null-kv-storage.d.ts +48 -0
  218. package/dist/internal/null-kv-storage.d.ts.map +1 -0
  219. package/dist/internal/null-kv-storage.js +58 -0
  220. package/dist/internal/otel/collector.d.ts.map +1 -1
  221. package/dist/internal/otel/collector.js +22 -9
  222. package/dist/internal/server.d.ts +6 -0
  223. package/dist/internal/server.d.ts.map +1 -1
  224. package/dist/internal/server.js +123 -33
  225. package/dist/internal/session-engine.d.ts +88 -3
  226. package/dist/internal/session-engine.d.ts.map +1 -1
  227. package/dist/internal/session-engine.js +538 -46
  228. package/dist/internal/session-run-log.d.ts +120 -0
  229. package/dist/internal/session-run-log.d.ts.map +1 -0
  230. package/dist/internal/session-run-log.js +359 -0
  231. package/dist/internal/sessions-client.d.ts +9 -7
  232. package/dist/internal/sessions-client.d.ts.map +1 -1
  233. package/dist/internal/sessions-client.js +3 -1
  234. package/dist/internal/storage-coordinator.d.ts +13 -0
  235. package/dist/internal/storage-coordinator.d.ts.map +1 -1
  236. package/dist/internal/storage-coordinator.js +37 -6
  237. package/dist/internal/storage-roles.d.ts +5 -0
  238. package/dist/internal/storage-roles.d.ts.map +1 -1
  239. package/dist/internal/stream-progress.d.ts.map +1 -1
  240. package/dist/internal/stream-progress.js +10 -0
  241. package/dist/internal/tool-policy.d.ts +29 -9
  242. package/dist/internal/tool-policy.d.ts.map +1 -1
  243. package/dist/internal/tool-policy.js +24 -0
  244. package/dist/internal/trajectory.d.ts.map +1 -1
  245. package/dist/internal/trajectory.js +10 -0
  246. package/dist/internal/turn-outbox.d.ts +24 -0
  247. package/dist/internal/turn-outbox.d.ts.map +1 -0
  248. package/dist/internal/turn-outbox.js +80 -0
  249. package/dist/playground/assets/index-D7rGZNjy.css +1 -0
  250. package/dist/playground/assets/index-jzNbJENa.js +69 -0
  251. package/dist/playground/index.html +2 -2
  252. package/dist/storage-backends/cursor-hosted.d.ts +1 -1
  253. package/dist/storage-backends/cursor-hosted.d.ts.map +1 -1
  254. package/dist/storage-backends/cursor-hosted.js +12 -0
  255. package/dist/storage-protocol.d.ts +8 -0
  256. package/dist/storage-protocol.d.ts.map +1 -1
  257. package/dist/storage-protocol.js +8 -0
  258. package/dist/storage.d.ts +8 -0
  259. package/dist/storage.d.ts.map +1 -1
  260. package/dist/tools.d.ts +12 -2
  261. package/dist/tools.d.ts.map +1 -1
  262. package/dist/types.d.ts +88 -7
  263. package/dist/types.d.ts.map +1 -1
  264. package/docs/README.md +5 -3
  265. package/docs/deployment.md +5 -4
  266. package/docs/design/runtime-abstraction.md +1757 -0
  267. package/docs/guides/mcp-oauth.md +26 -8
  268. package/docs/guides/slack.md +93 -202
  269. package/docs/reference/agent-config.md +2 -2
  270. package/docs/reference/cli.md +32 -16
  271. package/docs/reference/connections.md +6 -3
  272. package/docs/reference/http-api.md +3 -1
  273. package/docs/reference/sessions.md +4 -2
  274. package/docs/reference/tools.md +34 -2
  275. package/docs/templates/agents-md.md +110 -0
  276. package/docs/troubleshooting.md +2 -2
  277. package/package.json +1 -1
  278. package/skills/create-agent/SKILL.md +2 -1
  279. package/skills/mcp-auth/SKILL.md +6 -3
  280. package/skills/setup-slack/SKILL.md +23 -13
  281. package/src/bin/agent-serve.ts +12 -1
  282. package/src/channels/github/github-channel.ts +17 -0
  283. package/src/channels/origin/api.ts +24 -5
  284. package/src/channels/origin/binding.ts +55 -26
  285. package/src/channels/origin/index.ts +1 -0
  286. package/src/channels/origin/origin-channel.ts +78 -10
  287. package/src/channels/origin/reactions.ts +82 -0
  288. package/src/channels/origin/types.ts +11 -0
  289. package/src/channels/slack/approvals.ts +105 -0
  290. package/src/channels/slack/cli-project.ts +267 -0
  291. package/src/channels/slack/defaults.ts +165 -74
  292. package/src/channels/slack/dispatch.ts +2 -0
  293. package/src/channels/slack/init.ts +10 -5
  294. package/src/channels/slack/interactive.ts +35 -9
  295. package/src/channels/slack/live-delivery.ts +5 -3
  296. package/src/channels/slack/manifest.ts +1 -1
  297. package/src/channels/slack/progress-delivery.ts +133 -0
  298. package/src/channels/slack/setup.ts +10 -6
  299. package/src/channels/slack/slack-channel.ts +1 -0
  300. package/src/channels/slack/tool-approval-events.ts +93 -0
  301. package/src/channels/slack/types.ts +9 -1
  302. package/src/evals/run-facts.ts +32 -0
  303. package/src/files-backends/cursor-hosted.ts +3 -2
  304. package/src/index.ts +4 -0
  305. package/src/internal/advertise-tools.ts +31 -10
  306. package/src/internal/approval-gate.ts +20 -29
  307. package/src/internal/as-of.ts +107 -0
  308. package/src/internal/chat-client.ts +19 -0
  309. package/src/internal/cli-deploy.ts +203 -13
  310. package/src/internal/cli-mcp-oauth.ts +7 -21
  311. package/src/internal/cli-slack-manual.ts +350 -18
  312. package/src/internal/cli-slack.ts +40 -84
  313. package/src/internal/cursor/account-mcp.ts +21 -0
  314. package/src/internal/cursor-agent-template.ts +1 -0
  315. package/src/internal/cursor-event-relay.ts +5 -6
  316. package/src/internal/deploy-client.ts +43 -0
  317. package/src/internal/env-file.ts +84 -0
  318. package/src/internal/framework-file-storage.ts +18 -46
  319. package/src/internal/framework-storage-selection.ts +41 -25
  320. package/src/internal/hosted-admission-adapter.ts +42 -0
  321. package/src/internal/hosted-delivery-protocol.ts +14 -2
  322. package/src/internal/hosted-delivery.ts +169 -44
  323. package/src/internal/hosted-execution-diag.ts +252 -0
  324. package/src/internal/http-channel.ts +107 -0
  325. package/src/internal/init-project.ts +2 -0
  326. package/src/internal/logs-client.ts +5 -0
  327. package/src/internal/mcp-endpoint.ts +13 -4
  328. package/src/internal/mcp-host.ts +77 -11
  329. package/src/internal/mcp-oauth-on-demand.ts +352 -0
  330. package/src/internal/mcp-oauth-persist.ts +127 -0
  331. package/src/internal/mcp-oauth.ts +17 -1
  332. package/src/internal/null-kv-storage.ts +74 -0
  333. package/src/internal/otel/collector.ts +30 -0
  334. package/src/internal/server.ts +159 -11
  335. package/src/internal/session-engine.ts +691 -57
  336. package/src/internal/session-run-log.ts +584 -0
  337. package/src/internal/sessions-client.ts +17 -8
  338. package/src/internal/storage-coordinator.ts +49 -9
  339. package/src/internal/storage-roles.ts +7 -0
  340. package/src/internal/stream-progress.ts +19 -0
  341. package/src/internal/tool-policy.ts +49 -9
  342. package/src/internal/trajectory.ts +10 -0
  343. package/src/internal/turn-outbox.ts +85 -0
  344. package/src/storage-backends/cursor-hosted.ts +13 -1
  345. package/src/storage-protocol.ts +10 -0
  346. package/src/storage.ts +12 -0
  347. package/src/tools.ts +12 -2
  348. package/src/types.ts +93 -8
  349. package/templates/agents-md/README.md +39 -0
  350. package/templates/agents-md/agent/agent.ts +8 -0
  351. package/templates/agents-md/agent/channels/github.ts +10 -0
  352. package/templates/agents-md/agent/channels/queue.ts +28 -0
  353. package/templates/agents-md/agent/channels/slack.ts +9 -0
  354. package/templates/agents-md/agent/instructions.md +39 -0
  355. package/templates/agents-md/agent/lib/collect.ts +439 -0
  356. package/templates/agents-md/agent/lib/config.ts +8 -0
  357. package/templates/agents-md/agent/lib/paths.ts +51 -0
  358. package/templates/agents-md/agent/schedules/weekly.ts +17 -0
  359. package/templates/agents-md/agent/tools/apply_agents.ts +226 -0
  360. package/templates/agents-md/evals/agents.eval.ts +135 -0
  361. package/templates/agents-md/evals/evals.config.ts +5 -0
  362. package/templates/agents-md/init.json +38 -0
  363. package/templates/agents-md/package.json +18 -0
  364. package/templates/agents-md/tsconfig.json +12 -0
  365. package/dist/docs/assets/chunks/@localSearchIndexroot.DFoGuETX.js +0 -1
  366. package/dist/docs/assets/guides_slack.md.C32HsdKk.js +0 -38
  367. package/dist/docs/assets/guides_slack.md.C32HsdKk.lean.js +0 -1
  368. package/dist/docs/assets/index.md.CI93Ltlb.js +0 -5
  369. package/dist/docs/assets/reference_sessions.md.D0mIh4KK.js +0 -1
  370. package/dist/docs/assets/troubleshooting.md.Ctv3T8C2.js +0 -1
  371. package/dist/docs/design/agsh.md +0 -406
  372. package/dist/playground/assets/index-B1DDvBeC.css +0 -1
  373. package/dist/playground/assets/index-Cx9CclK_.js +0 -88
  374. package/docs/design/agsh.md +0 -406
  375. /package/dist/docs/assets/{deployment.md.D9msOFOW.lean.js → deployment.md.MFPKqsqI.lean.js} +0 -0
  376. /package/dist/docs/assets/{index.md.CI93Ltlb.lean.js → index.md.CVeRUOeZ.lean.js} +0 -0
  377. /package/dist/docs/assets/{reference_agent-config.md.Cp_x38Nl.lean.js → reference_agent-config.md.BHeYMgme.lean.js} +0 -0
  378. /package/dist/docs/assets/{reference_connections.md.BH8Oc0D0.lean.js → reference_connections.md.DxldvyIB.lean.js} +0 -0
  379. /package/dist/docs/assets/{reference_http-api.md.D89k1mdm.lean.js → reference_http-api.md.BEJx9XVj.lean.js} +0 -0
  380. /package/dist/docs/assets/{reference_sessions.md.D0mIh4KK.lean.js → reference_sessions.md.NxFP_CAC.lean.js} +0 -0
  381. /package/dist/docs/assets/{troubleshooting.md.Ctv3T8C2.lean.js → troubleshooting.md.DCiPBhYs.lean.js} +0 -0
@@ -15,6 +15,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
15
15
  step((generator = generator.apply(thisArg, _arguments || [])).next());
16
16
  });
17
17
  };
18
+ import { AsyncLocalStorage } from "node:async_hooks";
18
19
  import { mkdir, rm, writeFile } from "node:fs/promises";
19
20
  import { dirname, join } from "node:path";
20
21
  import { mergeABInstructions, resolveABMaxPlaygroundSessions, resolveABSplit, } from "../ab.js";
@@ -24,13 +25,14 @@ import { SlackAskDedupeStore, SlackNudgeStore, } from "../channels/slack/nudge-s
24
25
  import { resolveDedicatedSlackHostBinding } from "../channels/slack/slack-channel.js";
25
26
  import { AGENT_SERVE_USER_STORE_FILES_SOURCE_ID, agentStoreKeys, } from "../files.js";
26
27
  import { cursorHostedFiles, isCursorHostedFilesAvailable, isCursorUserStoreFilesAvailable, } from "../files-backends/cursor-hosted.js";
27
- import { DEFAULT_MODEL, DIRECT_TOOL_CALL_CHANNEL_ID, isHostOauthConnectionTransport, isSymbolicConnectionTransport, } from "../types.js";
28
+ import { DEFAULT_MODEL, DIRECT_TOOL_CALL_CHANNEL_ID, isCursorAccountTransport, isHostOauthConnectionTransport, isSymbolicConnectionTransport, } from "../types.js";
28
29
  import { ABCollector } from "./ab-collector.js";
29
30
  import { foldABStream } from "./ab-fold.js";
30
31
  import { buildABSnapshot } from "./ab-snapshot.js";
31
- import { resolveAdvertisedTools } from "./advertise-tools.js";
32
+ import { resolveAdvertisedTools, } from "./advertise-tools.js";
32
33
  import { ApprovalGate } from "./approval-gate.js";
33
34
  import { ArtifactsStore } from "./artifacts-store.js";
35
+ import { assertTimeArgs, normalizeAsOf, sessionClock } from "./as-of.js";
34
36
  import { SessionAuthError, samePrincipal } from "./auth.js";
35
37
  import { mergeCloudOptions, resolveSessionRuntime } from "./cloud-merge.js";
36
38
  import { applyCloudUsageToEvents, cloudSdkAgentIdFromEvents, isUnpricedCompletedTurn, mapSdkTokenUsage, } from "./cloud-turn-cost.js";
@@ -47,7 +49,8 @@ import { createHostPlatforms, createHostSlackClient, } from "./host-platforms.js
47
49
  import { HostedAdmissionLocalSendError, isDuringHostedAdmission, } from "./hosted-admission-context.js";
48
50
  import { formatContinuationToken, newContinuationKey, newSessionId, newToolCallId, parseContinuationToken, } from "./ids.js";
49
51
  import { validateToolInput } from "./json-schema.js";
50
- import { McpHost } from "./mcp-host.js";
52
+ import { isMcpNeedsAuthError, McpHost } from "./mcp-host.js";
53
+ import { McpOauthOnDemandHub } from "./mcp-oauth-on-demand.js";
51
54
  import { shouldStartProcessMemoryTelemetry, startProcessMemoryTelemetry, } from "./process-memory-telemetry.js";
52
55
  import { buildSessionContextBlock, SCHEDULE_CHANNEL_PREFIX, } from "./prompt-context.js";
53
56
  import { assertCloudCanHonorAccountServersFilters } from "./resolved-connections.js";
@@ -56,11 +59,12 @@ import { SessionStore } from "./session-store.js";
56
59
  import { syncSkillsToStore } from "./skills-sync.js";
57
60
  import { steeringEnabled } from "./steering.js";
58
61
  import { StorageCoordinator } from "./storage-coordinator.js";
59
- import { decideToolCall, resolveEffect } from "./tool-policy.js";
62
+ import { decideToolCall, directCallEffect } from "./tool-policy.js";
60
63
  import { normalizeToolResult, toolCallErrorMessage } from "./tool-result.js";
61
64
  import { estimateTurnCostFromApi, roundCostUsd, } from "./turn-cost.js";
62
65
  import { TurnGovernor } from "./turn-governor.js";
63
66
  import { TurnLeaseStore } from "./turn-lease-store.js";
67
+ import { TurnOutbox } from "./turn-outbox.js";
64
68
  import { buildAgentsMdContent, buildCloudMemorySection, ensureOwnGitRoot, isNestedInGitRepo, materializeWorkspace, SERVER_TOOLS_MCP_SERVER_NAME, writeWorkspaceFiles, } from "./workspace.js";
65
69
  export const HTTP_CHANNEL_ID = "http";
66
70
  export { SCHEDULE_CHANNEL_PREFIX } from "./prompt-context.js";
@@ -134,6 +138,19 @@ export class ApprovalInterruptedError extends Error {
134
138
  this.name = "ApprovalInterruptedError";
135
139
  }
136
140
  }
141
+ export class AuthNotFoundError extends Error {
142
+ constructor(sessionId, callId) {
143
+ super(`No pending MCP auth for session ${sessionId} call ${callId}`);
144
+ this.name = "AuthNotFoundError";
145
+ }
146
+ }
147
+ export class AuthInterruptedError extends Error {
148
+ constructor(sessionId, callId) {
149
+ super(`MCP auth for session ${sessionId} call ${callId} is no longer live (host may have restarted while the tool was parked)`);
150
+ this.name = "AuthInterruptedError";
151
+ }
152
+ }
153
+ const mcpAuthAls = new AsyncLocalStorage();
137
154
  export class SessionEngine {
138
155
  constructor(options) {
139
156
  var _a, _b, _c, _d, _e;
@@ -143,6 +160,13 @@ export class SessionEngine {
143
160
  /** Sessions with a turn being admitted (before the run promise exists). */
144
161
  this.pendingTurns = new Set();
145
162
  this.activeTurns = new Map();
163
+ /**
164
+ * Sessions whose workspace a turn in this process has materialized. A
165
+ * session is busy from admit — before the governor slot and the turn's
166
+ * own materialize — so a read running alongside a turn consults this,
167
+ * not busy, to know whether the workspace is ready to be left alone.
168
+ */
169
+ this.materializedWorkspaces = new Set();
146
170
  /** Context used by the cloud turn's HTTP MCP callbacks. */
147
171
  this.activeToolContexts = new Map();
148
172
  /**
@@ -179,6 +203,8 @@ export class SessionEngine {
179
203
  this.dispatchChains = new Map();
180
204
  this.backgroundWork = new Set();
181
205
  this.approvals = new ApprovalGate();
206
+ this.auths = new ApprovalGate();
207
+ this.oauthHub = new McpOauthOnDemandHub();
182
208
  /** Serve-time resolved connections (see {@link setResolvedConnections}). */
183
209
  this.resolvedConnections = [];
184
210
  /** Sessions whose completed turns are fully priced (no further backfill). */
@@ -203,6 +229,7 @@ export class SessionEngine {
203
229
  this.nudgeStore = new SlackNudgeStore(join(options.stateRoot, "slack-nudges"));
204
230
  this.askDedupe = new SlackAskDedupeStore(join(options.stateRoot, "slack-asks"));
205
231
  this.turnLeases = new TurnLeaseStore(join(options.stateRoot, "turn-leases"));
232
+ this.outbox = new TurnOutbox(join(options.stateRoot, "outbox"));
206
233
  this.logs = new EventLogStore((sessionId) => this.sessions.eventFilePath(sessionId), (sessionId, error) => this.logger(`[agent-sdk] failed to persist events for ${sessionId}: ${describeError(error)}`));
207
234
  // Framework session state (records, event chunks, continuations) is
208
235
  // mirrored to whatever this selects; see framework-storage-selection.ts
@@ -284,10 +311,20 @@ export class SessionEngine {
284
311
  setCloudServerToolsConnection(connection) {
285
312
  this.cloudServerToolsConnection = connection;
286
313
  }
314
+ setMcpOauthCallbackUrl(url) {
315
+ this.oauthHub.callbackUrl = url;
316
+ this.mcpHost.setOAuthRedirectUrl(url);
317
+ }
318
+ setCursorAccountAuthProbe(probe) {
319
+ this.probeCursorAccount = probe;
320
+ }
321
+ get oauthCallbackHub() {
322
+ return this.oauthHub;
323
+ }
287
324
  /** Shared host services (MCP / GitHub / Slack / reminders / evals / kv / files / otel / Slack nudges). */
288
325
  get host() {
289
326
  return {
290
- mcp: this.mcpHost,
327
+ mcp: this.wrapMcp(this.mcpHost),
291
328
  github: this.platforms.github,
292
329
  slack: this.platforms.slack,
293
330
  reminders: this.reminderApi,
@@ -584,12 +621,36 @@ export class SessionEngine {
584
621
  const now = new Date().toISOString();
585
622
  const channelState = this.initialChannelState(channelId, sendOptions.state);
586
623
  const purpose = sendOptions.purpose === "eval" ? "eval" : "live";
587
- let record = Object.assign(Object.assign({ sessionId: (_d = sendOptions.hostedSessionId) !== null && _d !== void 0 ? _d : newSessionId(), channelId, mode: (_e = sendOptions.mode) !== null && _e !== void 0 ? _e : "chat", purpose }, (sendOptions.dryRun === true ? { dryRun: true } : {})), { continuationKey: (_f = sendOptions.continuationToken) !== null && _f !== void 0 ? _f : newContinuationKey(), auth, title: sendOptions.title, channelState, workspaceOverride: sendOptions.workspaceDir, pendingWorkspaceFiles: sendOptions.workspaceFiles, pendingImages: sendOptions.images, cloudOverride: sendOptions.cloud, sdkAgentId: sendOptions.sdkAgentId, turnCount: 0, createdAt: now, updatedAt: now });
624
+ const frozenAsOf = normalizeAsOf(sendOptions.asOf);
625
+ assertTimeArgs(this.project.agent.tools, frozenAsOf);
626
+ let record = {
627
+ sessionId: (_d = sendOptions.hostedSessionId) !== null && _d !== void 0 ? _d : newSessionId(),
628
+ channelId,
629
+ mode: (_e = sendOptions.mode) !== null && _e !== void 0 ? _e : "chat",
630
+ purpose,
631
+ dryRun: sendOptions.dryRun === true ? true : undefined,
632
+ asOf: frozenAsOf,
633
+ continuationKey: (_f = sendOptions.continuationToken) !== null && _f !== void 0 ? _f : newContinuationKey(),
634
+ auth,
635
+ title: sendOptions.title,
636
+ channelState,
637
+ workspaceOverride: sendOptions.workspaceDir,
638
+ pendingWorkspaceFiles: sendOptions.workspaceFiles,
639
+ pendingImages: sendOptions.images,
640
+ cloudOverride: sendOptions.cloud,
641
+ sdkAgentId: sendOptions.sdkAgentId,
642
+ turnCount: 0,
643
+ createdAt: now,
644
+ updatedAt: now,
645
+ };
588
646
  yield this.sessions.save(record);
589
647
  (_a = this.storage) === null || _a === void 0 ? void 0 : _a.sessionRecord(record);
590
648
  yield this.appendEvent(record.sessionId, {
591
649
  type: "session.started",
592
- data: { channelId },
650
+ data: {
651
+ channelId,
652
+ dryRun: record.dryRun === true ? true : undefined,
653
+ },
593
654
  });
594
655
  record = yield this.enrollABs(record);
595
656
  const since = (yield this.logs.get(record.sessionId)).count;
@@ -791,10 +852,28 @@ export class SessionEngine {
791
852
  const prior = (_a = this.admissionChains.get(sessionId)) !== null && _a !== void 0 ? _a : Promise.resolve();
792
853
  const admitted = prior
793
854
  .catch(() => { })
794
- .then(() => this.admitTurn(sessionId, message, options));
855
+ .then(() => __awaiter(this, void 0, void 0, function* () {
856
+ // Another server holds the turn: hand the message to it and coalesce.
857
+ if (yield this.turnLeases.runningElsewhere(sessionId)) {
858
+ yield this.outbox.post(sessionId, { message, options });
859
+ return true;
860
+ }
861
+ return this.admitTurn(sessionId, message, options);
862
+ }));
795
863
  this.admissionChains.set(sessionId, admitted.catch(() => { }));
796
864
  return admitted;
797
865
  }
866
+ /** Admit what other servers handed to this turn's holder. Never awaited by the lifecycle. */
867
+ drainOutbox(sessionId) {
868
+ void this.outbox
869
+ .takeAll(sessionId)
870
+ .then((items) => {
871
+ for (const item of items) {
872
+ void this.startTurn(sessionId, item.message, item.options).catch(() => { });
873
+ }
874
+ })
875
+ .catch(() => { });
876
+ }
798
877
  enqueueCoalesced(sessionId, item) {
799
878
  var _a;
800
879
  const queue = (_a = this.coalesceQueues.get(sessionId)) !== null && _a !== void 0 ? _a : [];
@@ -1004,6 +1083,8 @@ export class SessionEngine {
1004
1083
  let lifecycle;
1005
1084
  lifecycle = (() => __awaiter(this, void 0, void 0, function* () {
1006
1085
  let outcome;
1086
+ const poll = setInterval(() => this.drainOutbox(sessionId), 1000);
1087
+ poll.unref();
1007
1088
  try {
1008
1089
  outcome = yield this.executeTurn(record, turnId, message, isFirstTurn, abort.signal);
1009
1090
  }
@@ -1013,6 +1094,9 @@ export class SessionEngine {
1013
1094
  errorMessage: describeError(error),
1014
1095
  };
1015
1096
  }
1097
+ finally {
1098
+ clearInterval(poll);
1099
+ }
1016
1100
  this.lastOutcomes.set(sessionId, outcome);
1017
1101
  const wasCurrent = this.activeTurns.get(sessionId) === lifecycle;
1018
1102
  if (wasCurrent) {
@@ -1038,6 +1122,10 @@ export class SessionEngine {
1038
1122
  // The drain may have nested a successor turn, which took its own
1039
1123
  // reference; the lease outlives this release until that one ends too.
1040
1124
  yield lease.release();
1125
+ // Handed off between the last poll and the release: nobody else will.
1126
+ if (!abort.signal.aborted) {
1127
+ this.drainOutbox(sessionId);
1128
+ }
1041
1129
  return outcome;
1042
1130
  }))();
1043
1131
  this.activeTurns.set(sessionId, lifecycle);
@@ -1087,6 +1175,7 @@ export class SessionEngine {
1087
1175
  this.coalesceDrains.has(sessionId) ||
1088
1176
  ((_b = (_a = this.coalesceQueues.get(sessionId)) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0) > 0;
1089
1177
  this.clearCoalesced(sessionId);
1178
+ yield this.outbox.clear(sessionId);
1090
1179
  const record = yield this.sessions.get(sessionId);
1091
1180
  const continuationKey = record === null || record === void 0 ? void 0 : record.continuationKey;
1092
1181
  if (continuationKey !== undefined && continuationKey !== null) {
@@ -1275,6 +1364,7 @@ export class SessionEngine {
1275
1364
  seed: isFirstTurn,
1276
1365
  stateRoot: this.stateRoot,
1277
1366
  });
1367
+ this.materializedWorkspaces.add(sessionId);
1278
1368
  // Must precede the carrier: the harness resolves rules, skills,
1279
1369
  // `mcp.json` and hooks from its git root, so a workspace nested in an
1280
1370
  // outer repo would load that repo's hooks instead of the ones written
@@ -1337,12 +1427,15 @@ export class SessionEngine {
1337
1427
  }
1338
1428
  catch (error) {
1339
1429
  this.approvals.cancelSession(sessionId, "deny");
1430
+ this.auths.cancelSession(sessionId, "deny");
1340
1431
  outcome = { status: "error", errorMessage: describeError(error) };
1341
1432
  }
1342
1433
  finally {
1343
1434
  permit.release();
1344
1435
  this.approvals.cancelSession(sessionId, "deny");
1436
+ this.auths.cancelSession(sessionId, "deny");
1345
1437
  yield this.clearPendingApprovals(sessionId);
1438
+ yield this.clearPendingAuths(sessionId);
1346
1439
  // Anything still queued belongs to the next turn's boundary drain, not
1347
1440
  // to this turn's edge detection.
1348
1441
  this.deliveredNudges.delete(sessionId);
@@ -1517,6 +1610,7 @@ export class SessionEngine {
1517
1610
  channelId: record.channelId,
1518
1611
  channelKind: (_b = (_a = this.channelsById.get(record.channelId)) === null || _a === void 0 ? void 0 : _a.meta) === null || _b === void 0 ? void 0 : _b.kind,
1519
1612
  environment: isDevMode() ? "local dev server" : "hosted deployment",
1613
+ now: record.asOf === undefined ? undefined : sessionClock(record.asOf)(),
1520
1614
  });
1521
1615
  turnPrompt = `${contextBlock}\n\n${prompt}`;
1522
1616
  }
@@ -1833,11 +1927,17 @@ export class SessionEngine {
1833
1927
  // named passthroughs resolved fresh on every turn — reminder fires and
1834
1928
  // post-restart follow-ups included — and a listing failure throws,
1835
1929
  // failing the turn closed.
1836
- for (const tool of yield resolveAdvertisedTools({
1930
+ for (const tool of yield mcpAuthAls.run({
1931
+ sessionId: record.sessionId,
1932
+ turnId,
1933
+ callId: newToolCallId("mcp"),
1934
+ toolName: "mcp",
1935
+ emit,
1936
+ }, () => resolveAdvertisedTools({
1837
1937
  agent,
1838
1938
  session: this.sessionInfo(record),
1839
- hostMcp: this.mcpHost,
1840
- })) {
1939
+ hostMcp: this.advertiseMcp(),
1940
+ }))) {
1841
1941
  register(tool);
1842
1942
  }
1843
1943
  return tools;
@@ -1903,6 +2003,7 @@ export class SessionEngine {
1903
2003
  send: (channelId, message, sendOptions = {}) => { var _a; return this.send(channelId, message, Object.assign(Object.assign({}, sendOptions), { auth: (_a = sendOptions.auth) !== null && _a !== void 0 ? _a : args.record.auth })); },
1904
2004
  getSession: (channelId, sessionId) => this.getChannelSession(channelId, sessionId),
1905
2005
  emit: args.emit,
2006
+ now: sessionClock(args.record.asOf),
1906
2007
  };
1907
2008
  try {
1908
2009
  // Before the approval gate: a dry run is unattended, so parking a write
@@ -1914,12 +2015,16 @@ export class SessionEngine {
1914
2015
  annotations: args.tool.annotations,
1915
2016
  },
1916
2017
  }
1917
- : {})), { dryRunResult: args.tool.definition.dryRunResult, input: validation.value }));
2018
+ : {})), { dryRunResult: args.tool.definition.dryRunResult, input: validation.value, asOf: args.record.asOf, timeArgs: args.tool.definition.timeArgs }));
1918
2019
  if (decision.kind === "answer") {
1919
2020
  (_a = this.stubbedCallIds.get(args.record.sessionId)) === null || _a === void 0 ? void 0 : _a.add(toolCallId);
1920
2021
  this.logger(`[session] tool ${args.tool.name} answered by host (${toolCallId})`);
1921
2022
  return normalizeToolResult(decision.result);
1922
2023
  }
2024
+ if (decision.kind === "unbounded") {
2025
+ this.logger(`[session] tool ${args.tool.name} refused, unbounded_time (${toolCallId})`);
2026
+ return toolErrorResult(decision.message);
2027
+ }
1923
2028
  if (decision.kind === "refuse") {
1924
2029
  this.logger(`[session] tool ${args.tool.name} refused, effect unclassified (${toolCallId})`);
1925
2030
  // The coverage signal: a run reports how much of itself was runnable.
@@ -1945,7 +2050,13 @@ export class SessionEngine {
1945
2050
  }
1946
2051
  const started = Date.now();
1947
2052
  this.logger(`[session] tool ${args.tool.name} start`);
1948
- const result = yield execute(validation.value, toolCtx);
2053
+ const result = yield mcpAuthAls.run({
2054
+ sessionId: args.record.sessionId,
2055
+ turnId: args.turnId,
2056
+ callId: toolCallId,
2057
+ toolName: args.tool.name,
2058
+ emit: args.emit,
2059
+ }, () => execute(validation.value, toolCtx));
1949
2060
  this.logger(`[session] tool ${args.tool.name} done (${Date.now() - started}ms)`);
1950
2061
  return normalizeToolResult(result);
1951
2062
  }
@@ -1970,7 +2081,7 @@ export class SessionEngine {
1970
2081
  args: args.args,
1971
2082
  requestedAt,
1972
2083
  };
1973
- const resolutionPromise = this.approvals.wait(Object.assign({ sessionId: args.sessionId }, pendingRecord));
2084
+ const resolutionPromise = this.approvals.wait(args.sessionId, pendingRecord);
1974
2085
  yield this.updateRecord(args.sessionId, (current) => { var _a; return (Object.assign(Object.assign({}, current), { pendingApprovals: [
1975
2086
  ...((_a = current.pendingApprovals) !== null && _a !== void 0 ? _a : []).filter((item) => item.callId !== args.callId),
1976
2087
  pendingRecord,
@@ -2056,6 +2167,245 @@ export class SessionEngine {
2056
2167
  yield this.updateRecord(sessionId, (current) => { var _a; return (Object.assign(Object.assign({}, current), { pendingApprovals: ((_a = current.pendingApprovals) !== null && _a !== void 0 ? _a : []).filter((item) => item.callId !== callId) })); });
2057
2168
  });
2058
2169
  }
2170
+ wrapMcp(inner) {
2171
+ return {
2172
+ names: () => inner.names(),
2173
+ listTools: (name) => this.withMcpAuth(name, () => inner.listTools(name)),
2174
+ callTool: (name, tool, args) => this.withMcpAuth(name, () => inner.callTool(name, tool, args)),
2175
+ };
2176
+ }
2177
+ advertiseMcp() {
2178
+ return {
2179
+ listTools: (name) => this.withMcpListAuth(name, () => this.mcpHost.listTools(name)),
2180
+ callTool: (name, tool, args) => this.withMcpAuth(name, () => this.mcpHost.callTool(name, tool, args)),
2181
+ oneOff: (connection) => {
2182
+ const inner = this.mcpHost.oneOff(connection);
2183
+ return {
2184
+ listTools: () => this.withMcpListAuth(connection.name, () => inner.listTools()),
2185
+ callTool: (tool, args) => this.withMcpAuth(connection.name, () => inner.callTool(tool, args)),
2186
+ };
2187
+ },
2188
+ };
2189
+ }
2190
+ withMcpListAuth(connection, run) {
2191
+ const ctx = mcpAuthAls.getStore();
2192
+ if (ctx === undefined) {
2193
+ return this.withMcpAuth(connection, run);
2194
+ }
2195
+ const toolName = `mcp:${connection}`;
2196
+ return mcpAuthAls.run(Object.assign(Object.assign({}, ctx), { callId: newToolCallId(toolName), toolName }), () => this.withMcpAuth(connection, run));
2197
+ }
2198
+ withMcpAuth(connection, run) {
2199
+ return __awaiter(this, void 0, void 0, function* () {
2200
+ try {
2201
+ return yield run();
2202
+ }
2203
+ catch (error) {
2204
+ if (!isMcpNeedsAuthError(error)) {
2205
+ throw error;
2206
+ }
2207
+ return yield this.parkAndRetryMcp(connection, run, error);
2208
+ }
2209
+ });
2210
+ }
2211
+ parkAndRetryMcp(connection, run, error) {
2212
+ return __awaiter(this, void 0, void 0, function* () {
2213
+ const ctx = mcpAuthAls.getStore();
2214
+ if (ctx === undefined) {
2215
+ throw error;
2216
+ }
2217
+ const minted = yield this.mintAuthUrl(connection, ctx.sessionId);
2218
+ if (minted === undefined) {
2219
+ throw error;
2220
+ }
2221
+ if ("authorized" in minted) {
2222
+ yield this.persistHostedMcpOauth(connection);
2223
+ yield this.mcpHost.dropClient(connection);
2224
+ return yield this.withMcpAuth(connection, run);
2225
+ }
2226
+ if (minted.state !== "") {
2227
+ const bind = this.oauthHub.bind(minted.state, ctx.sessionId, ctx.callId);
2228
+ if (bind === "already_done") {
2229
+ yield this.persistHostedMcpOauth(connection);
2230
+ yield this.mcpHost.dropClient(connection);
2231
+ return yield this.withMcpAuth(connection, run);
2232
+ }
2233
+ }
2234
+ const decision = yield this.parkForAuth({
2235
+ sessionId: ctx.sessionId,
2236
+ turnId: ctx.turnId,
2237
+ callId: ctx.callId,
2238
+ toolName: ctx.toolName,
2239
+ connection,
2240
+ authUrl: minted.authUrl,
2241
+ emit: ctx.emit,
2242
+ });
2243
+ if (decision === "deny") {
2244
+ throw new Error(`MCP connection "${connection}" authorization was denied.`);
2245
+ }
2246
+ yield this.persistHostedMcpOauth(connection);
2247
+ yield this.mcpHost.dropClient(connection);
2248
+ return yield this.withMcpAuth(connection, run);
2249
+ });
2250
+ }
2251
+ persistHostedMcpOauth(connection) {
2252
+ return __awaiter(this, void 0, void 0, function* () {
2253
+ const authored = this.authoredConnection(connection);
2254
+ if (authored === undefined ||
2255
+ !isHostOauthConnectionTransport(authored.transport)) {
2256
+ return;
2257
+ }
2258
+ yield this.oauthHub.persistFor(connection, authored.transport.url);
2259
+ });
2260
+ }
2261
+ authoredConnection(name) {
2262
+ var _a;
2263
+ var _b;
2264
+ return ((_b = this.project.agent.connections.find((entry) => entry.name === name)) !== null && _b !== void 0 ? _b : (_a = this.project.agent.hostConnections) === null || _a === void 0 ? void 0 : _a.find((entry) => entry.name === name));
2265
+ }
2266
+ mintAuthUrl(connection, sessionId) {
2267
+ return __awaiter(this, void 0, void 0, function* () {
2268
+ const authored = this.authoredConnection(connection);
2269
+ if (authored === undefined) {
2270
+ return undefined;
2271
+ }
2272
+ if (isCursorAccountTransport(authored.transport)) {
2273
+ const probe = this.probeCursorAccount;
2274
+ if (probe === undefined) {
2275
+ return undefined;
2276
+ }
2277
+ const authUrl = yield probe(connection);
2278
+ if (authUrl === undefined || authUrl === "") {
2279
+ return undefined;
2280
+ }
2281
+ return { authUrl, state: "" };
2282
+ }
2283
+ if (!isHostOauthConnectionTransport(authored.transport)) {
2284
+ return undefined;
2285
+ }
2286
+ return yield this.oauthHub.mint({
2287
+ connection,
2288
+ url: authored.transport.url,
2289
+ type: authored.transport.type === "sse" ? "sse" : "http",
2290
+ headers: authored.transport.headers,
2291
+ sessionId,
2292
+ });
2293
+ });
2294
+ }
2295
+ parkForAuth(args) {
2296
+ return __awaiter(this, void 0, void 0, function* () {
2297
+ const requestedAt = new Date().toISOString();
2298
+ const pendingRecord = {
2299
+ callId: args.callId,
2300
+ turnId: args.turnId,
2301
+ toolName: args.toolName,
2302
+ connection: args.connection,
2303
+ authUrl: args.authUrl,
2304
+ requestedAt,
2305
+ };
2306
+ const resolutionPromise = this.auths.wait(args.sessionId, pendingRecord);
2307
+ yield this.updateRecord(args.sessionId, (current) => { var _a; return (Object.assign(Object.assign({}, current), { pendingAuths: [
2308
+ ...((_a = current.pendingAuths) !== null && _a !== void 0 ? _a : []).filter((item) => item.callId !== args.callId),
2309
+ pendingRecord,
2310
+ ] })); });
2311
+ args.emit({
2312
+ type: "action.auth_requested",
2313
+ data: {
2314
+ callId: args.callId,
2315
+ toolName: args.toolName,
2316
+ connection: args.connection,
2317
+ authUrl: args.authUrl,
2318
+ },
2319
+ });
2320
+ this.logger(`[session] tool ${args.toolName} awaiting MCP auth ${args.connection} (${args.callId})`);
2321
+ const { decision, by } = yield resolutionPromise;
2322
+ yield this.updateRecord(args.sessionId, (current) => { var _a; return (Object.assign(Object.assign({}, current), { pendingAuths: ((_a = current.pendingAuths) !== null && _a !== void 0 ? _a : []).filter((item) => item.callId !== args.callId) })); });
2323
+ args.emit({
2324
+ type: "action.auth_resolved",
2325
+ data: {
2326
+ callId: args.callId,
2327
+ toolName: args.toolName,
2328
+ connection: args.connection,
2329
+ decision,
2330
+ by,
2331
+ },
2332
+ });
2333
+ this.logger(`[session] tool ${args.toolName} MCP auth ${decision} (${args.callId})`);
2334
+ return decision;
2335
+ });
2336
+ }
2337
+ clearPendingAuths(sessionId) {
2338
+ return __awaiter(this, void 0, void 0, function* () {
2339
+ yield this.oauthHub.abortSession(sessionId);
2340
+ const current = yield this.sessions.get(sessionId);
2341
+ if (current === undefined ||
2342
+ current.pendingAuths === undefined ||
2343
+ current.pendingAuths.length === 0) {
2344
+ return;
2345
+ }
2346
+ yield this.updateRecord(sessionId, (record) => (Object.assign(Object.assign({}, record), { pendingAuths: [] })));
2347
+ });
2348
+ }
2349
+ listPendingAuths(sessionId) {
2350
+ return __awaiter(this, void 0, void 0, function* () {
2351
+ var _a;
2352
+ const record = yield this.sessions.get(sessionId);
2353
+ if (record === undefined) {
2354
+ return [];
2355
+ }
2356
+ const live = this.auths.list(sessionId);
2357
+ if (live.length > 0) {
2358
+ return live;
2359
+ }
2360
+ return (_a = record.pendingAuths) !== null && _a !== void 0 ? _a : [];
2361
+ });
2362
+ }
2363
+ resolveAuth(sessionId, callId, decision, auth, options) {
2364
+ return __awaiter(this, void 0, void 0, function* () {
2365
+ var _a, _b;
2366
+ const record = yield this.sessions.get(sessionId);
2367
+ if (record === undefined) {
2368
+ throw new AuthNotFoundError(sessionId, callId);
2369
+ }
2370
+ const ownershipAuth = (options === null || options === void 0 ? void 0 : options.asSessionOwner) === true ? record.auth : auth;
2371
+ if (!samePrincipal(record.auth, ownershipAuth)) {
2372
+ throw new SessionAuthError(sessionId);
2373
+ }
2374
+ const pending = (_b = ((_a = record.pendingAuths) !== null && _a !== void 0 ? _a : []).find((item) => item.callId === callId)) !== null && _b !== void 0 ? _b : this.auths.list(sessionId).find((item) => item.callId === callId);
2375
+ if (pending === undefined) {
2376
+ throw new AuthNotFoundError(sessionId, callId);
2377
+ }
2378
+ const resolvedBy = approvalResolverLabel(auth);
2379
+ if (decision === "deny") {
2380
+ yield this.oauthHub.abortCall(sessionId, callId);
2381
+ }
2382
+ if (!this.auths.resolve(sessionId, callId, decision, resolvedBy)) {
2383
+ yield this.removePendingAuth(sessionId, callId);
2384
+ throw new AuthInterruptedError(sessionId, callId);
2385
+ }
2386
+ return pending;
2387
+ });
2388
+ }
2389
+ removePendingAuth(sessionId, callId) {
2390
+ return __awaiter(this, void 0, void 0, function* () {
2391
+ yield this.updateRecord(sessionId, (current) => { var _a; return (Object.assign(Object.assign({}, current), { pendingAuths: ((_a = current.pendingAuths) !== null && _a !== void 0 ? _a : []).filter((item) => item.callId !== callId) })); });
2392
+ });
2393
+ }
2394
+ runWithMcpPark(sessionId, toolName, fn) {
2395
+ return __awaiter(this, void 0, void 0, function* () {
2396
+ const active = this.activeToolContexts.get(sessionId);
2397
+ if (active === undefined) {
2398
+ return fn();
2399
+ }
2400
+ return mcpAuthAls.run({
2401
+ sessionId,
2402
+ turnId: active.turnId,
2403
+ callId: newToolCallId(toolName),
2404
+ toolName,
2405
+ emit: active.emit,
2406
+ }, fn);
2407
+ });
2408
+ }
2059
2409
  // ==========================================================================
2060
2410
  // Direct tool calls (deterministic invocation, no model turn)
2061
2411
  // ==========================================================================
@@ -2070,8 +2420,10 @@ export class SessionEngine {
2070
2420
  * and materialized workspace) and the call is recorded on the session's
2071
2421
  * event stream as `actions.requested` / `action.result` under a
2072
2422
  * per-call `turnId` (the call id), so it shows up in trajectories.
2073
- * Rejected with {@link SessionBusyError} while a model turn is running.
2074
- * Without a session, the tool runs against an **ephemeral** scratch
2423
+ * While a model turn is running, a read-effect call runs alongside it
2424
+ * (the turn's workspace is read as-is) and a write-effect call is
2425
+ * rejected with {@link SessionBusyError}. Without a session, the tool
2426
+ * runs against an **ephemeral** scratch
2075
2427
  * workspace under `<stateRoot>/tool-calls/<callId>` (materialized with
2076
2428
  * seed files, removed after the call returns).
2077
2429
  *
@@ -2111,26 +2463,22 @@ export class SessionEngine {
2111
2463
  throw new InvalidContinuationTokenError(`expected "<channelId>:<key>" (as /v1/sessions lists it), got "${options.continuationToken}"`);
2112
2464
  }
2113
2465
  // A token that maps to a live (or restorable) session takes the
2114
- // session path: same owner check, same turn serialization, same
2115
- // event recording as an explicit sessionId. Skipping those just
2116
- // because the caller addressed the session by token would fail open.
2466
+ // session path: same owner check, same busy semantics, same event
2467
+ // recording as an explicit sessionId. Skipping those just because
2468
+ // the caller addressed the session by token would fail open.
2117
2469
  record = (_b = (yield this.sessions.findByContinuation(continuation.channelId, continuation.key))) !== null && _b !== void 0 ? _b : (yield this.restoreSessionByContinuation(continuation.channelId, continuation.key));
2118
2470
  if (record !== undefined && !samePrincipal(record.auth, auth)) {
2119
2471
  throw new SessionAuthError(record.sessionId);
2120
2472
  }
2121
2473
  }
2122
2474
  if (record !== undefined) {
2123
- // Direct calls respect the same serialization as follow-up sends: a
2124
- // running model turn owns the session workspace and event stream.
2125
- if (this.activeTurns.has(record.sessionId) ||
2126
- this.pendingTurns.has(record.sessionId)) {
2127
- throw new SessionBusyError(record.sessionId);
2128
- }
2129
2475
  return {
2130
2476
  record,
2131
2477
  session: this.sessionInfo(record),
2132
2478
  workspaceDir: this.harnessCwd(record),
2133
2479
  scratchDir: undefined,
2480
+ busy: this.activeTurns.has(record.sessionId) ||
2481
+ this.pendingTurns.has(record.sessionId),
2134
2482
  };
2135
2483
  }
2136
2484
  // No session behind the token (or no token at all): a synthetic
@@ -2150,6 +2498,7 @@ export class SessionEngine {
2150
2498
  },
2151
2499
  workspaceDir: scratchDir,
2152
2500
  scratchDir,
2501
+ busy: false,
2153
2502
  };
2154
2503
  });
2155
2504
  }
@@ -2182,8 +2531,32 @@ export class SessionEngine {
2182
2531
  };
2183
2532
  });
2184
2533
  }
2534
+ /**
2535
+ * One catalog tool by name. Authored tools are local — their schema does
2536
+ * not depend on session identity or connection listings — so a detail
2537
+ * fetch for `ls` must not wait on every advertised MCP server.
2538
+ */
2539
+ describeCatalogTool(toolName_1) {
2540
+ return __awaiter(this, arguments, void 0, function* (toolName, options = {}) {
2541
+ const authored = this.project.agent.tools.find((tool) => tool.name === toolName);
2542
+ if (authored !== undefined) {
2543
+ return { tool: authored };
2544
+ }
2545
+ const catalog = yield this.listCatalogTools(options);
2546
+ const tool = catalog.tools.find((entry) => entry.name === toolName);
2547
+ if (tool === undefined) {
2548
+ return {
2549
+ tool: undefined,
2550
+ availableTools: catalog.tools.map((entry) => entry.name),
2551
+ connectionErrors: catalog.connectionErrors,
2552
+ };
2553
+ }
2554
+ return { tool };
2555
+ });
2556
+ }
2185
2557
  callTool(toolName_1) {
2186
2558
  return __awaiter(this, arguments, void 0, function* (toolName, input = {}, options = {}) {
2559
+ var _a;
2187
2560
  const callId = newToolCallId(toolName);
2188
2561
  // Identity resolves before the tool lookup: advertised connection tools
2189
2562
  // only exist relative to a session (per-session auth), so finding them
@@ -2203,7 +2576,7 @@ export class SessionEngine {
2203
2576
  const advertised = yield resolveAdvertisedTools({
2204
2577
  agent: this.project.agent,
2205
2578
  session,
2206
- hostMcp: this.mcpHost,
2579
+ hostMcp: this.advertiseMcp(),
2207
2580
  });
2208
2581
  tool = advertised.find((t) => t.name === toolName);
2209
2582
  }
@@ -2220,6 +2593,17 @@ export class SessionEngine {
2220
2593
  if (!validation.ok) {
2221
2594
  throw new ToolInputError({ toolName, detail: validation.message });
2222
2595
  }
2596
+ // A running model turn owns the session workspace: a direct write would
2597
+ // race the harness's own edits, so it waits (409). A read runs alongside
2598
+ // the turn — the operator inspecting a live session is the point — and
2599
+ // its events stay separable by their per-call turnId. The effect can
2600
+ // depend on the input, hence deciding after validation; an MCP tool
2601
+ // nothing classifies is a write here, fail-closed.
2602
+ if (identity.busy &&
2603
+ record !== undefined &&
2604
+ directCallEffect(tool, validation.value) !== "read") {
2605
+ throw new SessionBusyError(record.sessionId);
2606
+ }
2223
2607
  let workspaceUnavailable = false;
2224
2608
  try {
2225
2609
  yield mkdir(workspaceDir, { recursive: true });
@@ -2239,28 +2623,50 @@ export class SessionEngine {
2239
2623
  // to write) authored tool may rely on ctx.workspaceDir being the
2240
2624
  // real session workspace, so silently relocating it is not safe —
2241
2625
  // fail typed instead.
2626
+ //
2627
+ // A shared `local.workspaceDir` (change-monitor's phantom /repo) is
2628
+ // that path by design. Relocating it to scratch would flag a false
2629
+ // session-state warning; keep the borrowed cwd and skip the flag.
2242
2630
  const relocatable = tool.advertised === true ||
2243
- resolveEffect(tool.definition.effect, validation.value) === "read";
2631
+ directCallEffect(tool, validation.value) === "read";
2244
2632
  if (!relocatable) {
2245
2633
  throw new WorkspaceUnavailableError(toolName, error);
2246
2634
  }
2247
- this.logger(`[session] tool ${toolName} workspace unavailable (direct ${callId}); using scratch: ${error instanceof Error ? error.message : String(error)}`);
2248
- scratchDir = join(this.stateRoot, "tool-calls", callId);
2249
- workspaceDir = scratchDir;
2250
- workspaceUnavailable = true;
2251
- yield mkdir(workspaceDir, { recursive: true });
2635
+ if (((_a = this.project.agent.local) === null || _a === void 0 ? void 0 : _a.workspaceDir) !== undefined) {
2636
+ this.logger(`[session] tool ${toolName} harness cwd unavailable (direct ${callId}); keeping borrowed workspace`);
2637
+ }
2638
+ else {
2639
+ this.logger(`[session] tool ${toolName} workspace unavailable (direct ${callId}); using scratch: ${error instanceof Error ? error.message : String(error)}`);
2640
+ scratchDir = join(this.stateRoot, "tool-calls", callId);
2641
+ workspaceDir = scratchDir;
2642
+ workspaceUnavailable = true;
2643
+ yield mkdir(workspaceDir, { recursive: true });
2644
+ }
2252
2645
  }
2253
2646
  // Match what a model turn would see: session workspaces get the same
2254
2647
  // scaffold as executeTurn (seeds only before the first turn); scratch
2255
- // workspaces are materialized fresh.
2256
- yield materializeWorkspace({
2257
- agent: this.project.agent,
2258
- workspaceDir: record === undefined || workspaceUnavailable
2259
- ? workspaceDir
2260
- : this.scaffoldDir(record),
2261
- seed: record === undefined || workspaceUnavailable || record.turnCount === 0,
2262
- stateRoot: this.stateRoot,
2263
- });
2648
+ // workspaces are materialized fresh. A read running alongside a turn
2649
+ // that has materialized its workspace leaves it alone — re-seeding
2650
+ // would restore files the agent deleted mid-turn. A session is busy
2651
+ // from admit, though, so a read that lands while the first turn is
2652
+ // still queued or scaffolding materializes the workspace itself, seeds
2653
+ // included (turnCount is already 1 for that pending first turn).
2654
+ const turnMaterialized = record !== undefined &&
2655
+ identity.busy &&
2656
+ this.materializedWorkspaces.has(record.sessionId);
2657
+ if (record === undefined || workspaceUnavailable || !turnMaterialized) {
2658
+ yield materializeWorkspace({
2659
+ agent: this.project.agent,
2660
+ workspaceDir: record === undefined || workspaceUnavailable
2661
+ ? workspaceDir
2662
+ : this.scaffoldDir(record),
2663
+ seed: record === undefined ||
2664
+ workspaceUnavailable ||
2665
+ record.turnCount === 0 ||
2666
+ (identity.busy && record.turnCount === 1),
2667
+ stateRoot: this.stateRoot,
2668
+ });
2669
+ }
2264
2670
  // A per-call turnId keeps these events visible in trajectories (which
2265
2671
  // drop turn-less action events) without attributing them to a model turn.
2266
2672
  if (record !== undefined) {
@@ -2275,7 +2681,7 @@ export class SessionEngine {
2275
2681
  // `handle.callTool` performs a write just as readily.
2276
2682
  const decision = decideToolCall(Object.assign(Object.assign({ dryRun: (record === null || record === void 0 ? void 0 : record.dryRun) === true, effect: tool.definition.effect }, (tool.advertised === true
2277
2683
  ? { mcpTool: { name: tool.name, annotations: tool.annotations } }
2278
- : {})), { dryRunResult: tool.definition.dryRunResult, input: validation.value }));
2684
+ : {})), { dryRunResult: tool.definition.dryRunResult, input: validation.value, asOf: record === null || record === void 0 ? void 0 : record.asOf, timeArgs: tool.definition.timeArgs }));
2279
2685
  const started = Date.now();
2280
2686
  this.logger(`[session] tool ${toolName} start (direct ${callId})`);
2281
2687
  let result;
@@ -2288,7 +2694,12 @@ export class SessionEngine {
2288
2694
  void this.appendEvent(live.sessionId, Object.assign(Object.assign({}, payload), { turnId: callId })).catch(() => { });
2289
2695
  };
2290
2696
  try {
2291
- if (decision.kind === "refuse") {
2697
+ if (decision.kind === "unbounded") {
2698
+ this.logger(`[session] tool ${toolName} refused, unbounded_time (direct ${callId})`);
2699
+ result = normalizeToolResult(toolErrorResult(decision.message));
2700
+ isError = true;
2701
+ }
2702
+ else if (decision.kind === "refuse") {
2292
2703
  this.logger(`[session] tool ${toolName} refused, effect unclassified (direct ${callId})`);
2293
2704
  emit === null || emit === void 0 ? void 0 : emit({
2294
2705
  type: "action.effect_unclassified",
@@ -2303,7 +2714,7 @@ export class SessionEngine {
2303
2714
  isError = false;
2304
2715
  }
2305
2716
  else {
2306
- result = normalizeToolResult(yield execute(validation.value, {
2717
+ const run = () => execute(validation.value, {
2307
2718
  toolCallId: callId,
2308
2719
  session,
2309
2720
  workspaceDir,
@@ -2321,7 +2732,17 @@ export class SessionEngine {
2321
2732
  : session.auth })),
2322
2733
  getSession: (channelId, sessionId) => this.getChannelSession(channelId, sessionId),
2323
2734
  emit,
2324
- }));
2735
+ now: sessionClock(record === null || record === void 0 ? void 0 : record.asOf),
2736
+ });
2737
+ result = normalizeToolResult(record !== undefined && emit !== undefined
2738
+ ? yield mcpAuthAls.run({
2739
+ sessionId: record.sessionId,
2740
+ turnId: callId,
2741
+ callId,
2742
+ toolName,
2743
+ emit,
2744
+ }, run)
2745
+ : yield run());
2325
2746
  isError = isErrorEnvelope(result);
2326
2747
  }
2327
2748
  }
@@ -2401,6 +2822,10 @@ export class SessionEngine {
2401
2822
  if (decision.kind === "run") {
2402
2823
  return { answered: false };
2403
2824
  }
2825
+ if (decision.kind === "unbounded") {
2826
+ this.logger(`[session] bridged tool ${args.toolName} refused, unbounded_time (${args.sessionId})`);
2827
+ return { answered: true, result: toolErrorResult(decision.message) };
2828
+ }
2404
2829
  if (decision.kind === "refuse") {
2405
2830
  this.logger(`[session] bridged tool ${args.toolName} refused, effect unclassified (${args.sessionId})`);
2406
2831
  context.emit({
@@ -2688,6 +3113,64 @@ export class SessionEngine {
2688
3113
  };
2689
3114
  });
2690
3115
  }
3116
+ /**
3117
+ * The single newest session visible to `caller` (`GET /v1/sessions?latest=1`).
3118
+ *
3119
+ * Short-circuits the full listing: the local store already holds every
3120
+ * session this host created plus the startup bulk restore, so the common
3121
+ * case answers from memory without a sink round trip. Only when the local
3122
+ * store has nothing for the caller (fresh host, `restore: "off"`) does it
3123
+ * ask the sink — for a bounded newest-written window when the backend
3124
+ * can order by write time, else the full list. A session written by
3125
+ * another replica moments ago can lose to a local one; callers that need
3126
+ * the exact newest row should use the full listing.
3127
+ */
3128
+ latestSessionWithSource(caller, options) {
3129
+ return __awaiter(this, void 0, void 0, function* () {
3130
+ var _a;
3131
+ var _b;
3132
+ const includeAll = (_b = options === null || options === void 0 ? void 0 : options.includeAll) !== null && _b !== void 0 ? _b : false;
3133
+ const newestVisible = (records) => {
3134
+ let newest;
3135
+ for (const record of records) {
3136
+ if (!(includeAll || samePrincipal(record.auth, caller))) {
3137
+ continue;
3138
+ }
3139
+ if (newest === undefined ||
3140
+ record.updatedAt.localeCompare(newest.updatedAt) > 0) {
3141
+ newest = record;
3142
+ }
3143
+ }
3144
+ return newest;
3145
+ };
3146
+ const local = newestVisible(yield this.sessions.list());
3147
+ if (local !== undefined) {
3148
+ return {
3149
+ sessions: this.summarizeSessionRecords([local], caller, includeAll),
3150
+ source: "local",
3151
+ };
3152
+ }
3153
+ if (((_a = this.storage) === null || _a === void 0 ? void 0 : _a.isCursorHosted) === true) {
3154
+ try {
3155
+ const window = yield this.storage.listNewestSessionsFromSink(LATEST_SESSION_SINK_WINDOW);
3156
+ if (window !== undefined) {
3157
+ const stored = newestVisible(window);
3158
+ if (stored !== undefined) {
3159
+ return {
3160
+ sessions: this.summarizeSessionRecords([stored], caller, includeAll),
3161
+ source: "cursor-hosted",
3162
+ };
3163
+ }
3164
+ }
3165
+ }
3166
+ catch (error) {
3167
+ this.logger(`[agent-sdk] cursor-hosted newest-session lookup failed; falling back to the full list: ${describeError(error)}`);
3168
+ }
3169
+ }
3170
+ const listed = yield this.listSessionsWithSource(caller, options);
3171
+ return { sessions: listed.sessions.slice(0, 1), source: listed.source };
3172
+ });
3173
+ }
2691
3174
  /**
2692
3175
  * Durable sink rows plus local records (local wins on the same id when
2693
3176
  * newer — covers debounce windows that have not flushed yet). Newest
@@ -2734,6 +3217,7 @@ export class SessionEngine {
2734
3217
  : undefined,
2735
3218
  createdAt: record.createdAt,
2736
3219
  updatedAt: record.updatedAt,
3220
+ dryRun: record.dryRun === true ? true : undefined,
2737
3221
  continuationToken: record.httpContinuationKey !== undefined
2738
3222
  ? formatContinuationToken(HTTP_CHANNEL_ID, record.httpContinuationKey)
2739
3223
  : record.continuationKey === null
@@ -3006,7 +3490,7 @@ export class SessionEngine {
3006
3490
  this.coalesceDrains.has(sessionId));
3007
3491
  }
3008
3492
  sessionInfo(record) {
3009
- return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ id: record.sessionId, channelId: record.channelId, mode: record.mode, purpose: record.purpose === "eval" ? "eval" : "live" }, (record.dryRun === true ? { dryRun: true } : {})), { auth: record.auth, continuationKey: record.continuationKey }), (record.abs === undefined ? {} : { abs: record.abs })), (record.title === undefined ? {} : { title: record.title })), (record.sdkAgentId === undefined
3493
+ return Object.assign(Object.assign(Object.assign({ id: record.sessionId, channelId: record.channelId, mode: record.mode, purpose: record.purpose === "eval" ? "eval" : "live", dryRun: record.dryRun === true ? true : undefined, asOf: record.asOf, auth: record.auth, continuationKey: record.continuationKey }, (record.abs === undefined ? {} : { abs: record.abs })), (record.title === undefined ? {} : { title: record.title })), (record.sdkAgentId === undefined
3010
3494
  ? {}
3011
3495
  : { sdkAgentId: record.sdkAgentId }));
3012
3496
  }
@@ -3291,6 +3775,8 @@ export class SessionEngine {
3291
3775
  var _a, _b, _c, _d, _e;
3292
3776
  (_a = this.stopMemoryTelemetry) === null || _a === void 0 ? void 0 : _a.call(this);
3293
3777
  this.approvals.cancelAll("deny");
3778
+ this.auths.cancelAll("deny");
3779
+ yield this.oauthHub.close();
3294
3780
  yield Promise.allSettled([...this.activeTurns.values()]);
3295
3781
  yield Promise.allSettled([...this.backgroundWork]);
3296
3782
  yield Promise.allSettled([...this.dispatchChains.values()]);
@@ -3307,6 +3793,12 @@ export class SessionEngine {
3307
3793
  }
3308
3794
  /** Parallel event-stream loads during the startup bulk restore. */
3309
3795
  const RESTORE_FETCH_CONCURRENCY = 8;
3796
+ /**
3797
+ * Newest-written sink rows fetched for `GET /v1/sessions?latest=1` when the
3798
+ * local store has nothing for the caller. Wide enough that the caller's own
3799
+ * session is normally inside it even when other principals are busier.
3800
+ */
3801
+ const LATEST_SESSION_SINK_WINDOW = 50;
3310
3802
  /** NDJSON payload for a restored event stream; undefined when empty. */
3311
3803
  function mergePendingImages(current, incoming) {
3312
3804
  if (incoming === undefined) {