@cursor/july 0.1.16 → 0.1.18

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 (273) hide show
  1. package/README.md +9 -4
  2. package/dist/bin/agent-serve.js +60 -2
  3. package/dist/channels/slack/api.d.ts.map +1 -1
  4. package/dist/channels/slack/api.js +13 -3
  5. package/dist/channels/slack/auth.d.ts +7 -1
  6. package/dist/channels/slack/auth.d.ts.map +1 -1
  7. package/dist/channels/slack/auth.js +14 -0
  8. package/dist/channels/slack/blocks.d.ts +61 -0
  9. package/dist/channels/slack/blocks.d.ts.map +1 -0
  10. package/dist/channels/slack/blocks.js +90 -0
  11. package/dist/channels/slack/cursor-account.d.ts.map +1 -1
  12. package/dist/channels/slack/cursor-account.js +1 -1
  13. package/dist/channels/slack/defaults.d.ts +2 -0
  14. package/dist/channels/slack/defaults.d.ts.map +1 -1
  15. package/dist/channels/slack/defaults.js +29 -3
  16. package/dist/channels/slack/dispatch.d.ts +3 -17
  17. package/dist/channels/slack/dispatch.d.ts.map +1 -1
  18. package/dist/channels/slack/dispatch.js +4 -1
  19. package/dist/channels/slack/inbound.d.ts.map +1 -1
  20. package/dist/channels/slack/inbound.js +6 -1
  21. package/dist/channels/slack/index.d.ts +2 -0
  22. package/dist/channels/slack/index.d.ts.map +1 -1
  23. package/dist/channels/slack/index.js +2 -0
  24. package/dist/channels/slack/init.d.ts.map +1 -1
  25. package/dist/channels/slack/init.js +4 -1
  26. package/dist/channels/slack/interactive.d.ts +39 -3
  27. package/dist/channels/slack/interactive.d.ts.map +1 -1
  28. package/dist/channels/slack/interactive.js +153 -7
  29. package/dist/channels/slack/manifest.d.ts +13 -0
  30. package/dist/channels/slack/manifest.d.ts.map +1 -1
  31. package/dist/channels/slack/manifest.js +36 -14
  32. package/dist/channels/slack/message-body.d.ts +13 -0
  33. package/dist/channels/slack/message-body.d.ts.map +1 -0
  34. package/dist/channels/slack/message-body.js +82 -0
  35. package/dist/channels/slack/setup.d.ts +4 -1
  36. package/dist/channels/slack/setup.d.ts.map +1 -1
  37. package/dist/channels/slack/setup.js +16 -2
  38. package/dist/channels/slack/slack-channel.d.ts.map +1 -1
  39. package/dist/channels/slack/slack-channel.js +24 -3
  40. package/dist/channels/slack/thread-context.d.ts +0 -2
  41. package/dist/channels/slack/thread-context.d.ts.map +1 -1
  42. package/dist/channels/slack/thread-context.js +1 -65
  43. package/dist/channels/slack/types.d.ts +93 -1
  44. package/dist/channels/slack/types.d.ts.map +1 -1
  45. package/dist/connections.d.ts +4 -1
  46. package/dist/connections.d.ts.map +1 -1
  47. package/dist/connections.js +4 -1
  48. package/dist/docs/404.html +2 -2
  49. package/dist/docs/ab.html +3 -3
  50. package/dist/docs/assets/{app.DjHC-Ggf.js → app.BR5EdVSq.js} +1 -1
  51. package/dist/docs/assets/chunks/@localSearchIndexroot.BOzkeUi8.js +1 -0
  52. package/dist/docs/assets/chunks/{VPLocalSearchBox.DwviwmIq.js → VPLocalSearchBox.CNCzfUKC.js} +1 -1
  53. package/dist/docs/assets/chunks/{theme.BIpeYSon.js → theme.CwKvMSWv.js} +2 -2
  54. package/dist/docs/assets/{example-agents_security-reviewer.md.BZSNycMf.js → example-agents_security-reviewer.md.Dhj_m7_B.js} +1 -1
  55. package/dist/docs/assets/{guides_mcp-oauth.md.DqmEOQY1.js → guides_mcp-oauth.md.Dd8EgSem.js} +3 -2
  56. package/dist/docs/assets/{guides_mcp-oauth.md.DqmEOQY1.lean.js → guides_mcp-oauth.md.Dd8EgSem.lean.js} +1 -1
  57. package/dist/docs/assets/{guides_slack.md.FWale6Ip.js → guides_slack.md.D_xFKlnF.js} +1 -1
  58. package/dist/docs/assets/{reference_connections.md.CsSr3rDz.js → reference_connections.md.B9Q3TOve.js} +12 -5
  59. package/dist/docs/assets/{reference_connections.md.CsSr3rDz.lean.js → reference_connections.md.B9Q3TOve.lean.js} +1 -1
  60. package/dist/docs/building-with-agents.html +3 -3
  61. package/dist/docs/concepts.html +3 -3
  62. package/dist/docs/deployment.html +3 -3
  63. package/dist/docs/evals.html +3 -3
  64. package/dist/docs/example-agents/approval-buddy.html +3 -3
  65. package/dist/docs/example-agents/benny.html +3 -3
  66. package/dist/docs/example-agents/bugbot.html +3 -3
  67. package/dist/docs/example-agents/codebase-wiki.html +3 -3
  68. package/dist/docs/example-agents/codeowners-review.html +3 -3
  69. package/dist/docs/example-agents/concierge.html +3 -3
  70. package/dist/docs/example-agents/fsd.html +3 -3
  71. package/dist/docs/example-agents/index.html +3 -3
  72. package/dist/docs/example-agents/knowledge-base.html +3 -3
  73. package/dist/docs/example-agents/oncall.html +3 -3
  74. package/dist/docs/example-agents/security-reviewer.html +5 -5
  75. package/dist/docs/example-agents/slack-agent.html +3 -3
  76. package/dist/docs/example-agents/weather-agent.html +3 -3
  77. package/dist/docs/guides/agent-to-agent.html +3 -3
  78. package/dist/docs/guides/cloud-runtime.html +3 -3
  79. package/dist/docs/guides/github.html +3 -3
  80. package/dist/docs/guides/human-in-the-loop.html +3 -3
  81. package/dist/docs/guides/mcp-oauth.html +6 -5
  82. package/dist/docs/guides/slack.html +5 -5
  83. package/dist/docs/guides/webhooks.html +3 -3
  84. package/dist/docs/hashmap.json +1 -1
  85. package/dist/docs/hillclimbing.html +3 -3
  86. package/dist/docs/index.html +3 -3
  87. package/dist/docs/quickstart.html +3 -3
  88. package/dist/docs/reference/agent-config.html +3 -3
  89. package/dist/docs/reference/channels.html +3 -3
  90. package/dist/docs/reference/cli.html +3 -3
  91. package/dist/docs/reference/connections.html +14 -7
  92. package/dist/docs/reference/hooks.html +3 -3
  93. package/dist/docs/reference/http-api.html +3 -3
  94. package/dist/docs/reference/instructions.html +3 -3
  95. package/dist/docs/reference/playground.html +3 -3
  96. package/dist/docs/reference/project-layout.html +3 -3
  97. package/dist/docs/reference/prompt.html +3 -3
  98. package/dist/docs/reference/schedules.html +3 -3
  99. package/dist/docs/reference/sessions.html +3 -3
  100. package/dist/docs/reference/skills.html +3 -3
  101. package/dist/docs/reference/subagents.html +3 -3
  102. package/dist/docs/reference/tools.html +3 -3
  103. package/dist/docs/scaffolding-agents.html +3 -3
  104. package/dist/docs/storage.html +3 -3
  105. package/dist/docs/troubleshooting.html +3 -3
  106. package/dist/evals/assertions.d.ts +190 -0
  107. package/dist/evals/assertions.d.ts.map +1 -0
  108. package/dist/evals/assertions.js +461 -0
  109. package/dist/evals/expect.d.ts +95 -0
  110. package/dist/evals/expect.d.ts.map +1 -0
  111. package/dist/evals/expect.js +194 -0
  112. package/dist/evals/judge.d.ts +133 -0
  113. package/dist/evals/judge.d.ts.map +1 -0
  114. package/dist/evals/judge.js +228 -0
  115. package/dist/evals/loaders.d.ts +51 -0
  116. package/dist/evals/loaders.d.ts.map +1 -0
  117. package/dist/evals/loaders.js +124 -0
  118. package/dist/evals/matchers.d.ts +95 -0
  119. package/dist/evals/matchers.d.ts.map +1 -0
  120. package/dist/evals/matchers.js +145 -0
  121. package/dist/evals/reporters.d.ts +70 -0
  122. package/dist/evals/reporters.d.ts.map +1 -0
  123. package/dist/evals/reporters.js +221 -0
  124. package/dist/evals/results.d.ts +103 -0
  125. package/dist/evals/results.d.ts.map +1 -0
  126. package/dist/evals/results.js +28 -0
  127. package/dist/evals/run-facts.d.ts +77 -0
  128. package/dist/evals/run-facts.d.ts.map +1 -0
  129. package/dist/evals/run-facts.js +187 -0
  130. package/dist/evals.d.ts +118 -31
  131. package/dist/evals.d.ts.map +1 -1
  132. package/dist/evals.js +46 -12
  133. package/dist/index.d.ts +1 -1
  134. package/dist/index.d.ts.map +1 -1
  135. package/dist/index.js +1 -1
  136. package/dist/internal/builtin-tools/index.d.ts +10 -0
  137. package/dist/internal/builtin-tools/index.d.ts.map +1 -0
  138. package/dist/internal/builtin-tools/index.js +27 -0
  139. package/dist/internal/builtin-tools/reminders.d.ts +9 -0
  140. package/dist/internal/builtin-tools/reminders.d.ts.map +1 -0
  141. package/dist/internal/builtin-tools/reminders.js +138 -0
  142. package/dist/internal/cli-ax.d.ts +27 -0
  143. package/dist/internal/cli-ax.d.ts.map +1 -1
  144. package/dist/internal/cli-ax.js +90 -12
  145. package/dist/internal/cli-mcp.d.ts +8 -0
  146. package/dist/internal/cli-mcp.d.ts.map +1 -1
  147. package/dist/internal/cli-mcp.js +98 -0
  148. package/dist/internal/cli-slack.d.ts +29 -1
  149. package/dist/internal/cli-slack.d.ts.map +1 -1
  150. package/dist/internal/cli-slack.js +799 -13
  151. package/dist/internal/cursor-event-relay.d.ts +30 -0
  152. package/dist/internal/cursor-event-relay.d.ts.map +1 -1
  153. package/dist/internal/cursor-event-relay.js +37 -0
  154. package/dist/internal/deploy-client.d.ts +7 -0
  155. package/dist/internal/deploy-client.d.ts.map +1 -1
  156. package/dist/internal/deploy-client.js +9 -0
  157. package/dist/internal/discovery.d.ts.map +1 -1
  158. package/dist/internal/discovery.js +70 -9
  159. package/dist/internal/distribution.d.ts.map +1 -1
  160. package/dist/internal/distribution.js +2 -0
  161. package/dist/internal/eval-judge-model.d.ts +59 -0
  162. package/dist/internal/eval-judge-model.d.ts.map +1 -0
  163. package/dist/internal/eval-judge-model.js +131 -0
  164. package/dist/internal/eval-run-store.d.ts.map +1 -1
  165. package/dist/internal/eval-run-store.js +12 -20
  166. package/dist/internal/eval-runner.d.ts +31 -25
  167. package/dist/internal/eval-runner.d.ts.map +1 -1
  168. package/dist/internal/eval-runner.js +329 -126
  169. package/dist/internal/evals-client.d.ts.map +1 -1
  170. package/dist/internal/evals-client.js +4 -1
  171. package/dist/internal/local-env.d.ts +8 -0
  172. package/dist/internal/local-env.d.ts.map +1 -0
  173. package/dist/internal/local-env.js +47 -0
  174. package/dist/internal/playground/static.d.ts +3 -0
  175. package/dist/internal/playground/static.d.ts.map +1 -1
  176. package/dist/internal/playground/static.js +3 -0
  177. package/dist/internal/reminder-runner.d.ts +7 -0
  178. package/dist/internal/reminder-runner.d.ts.map +1 -1
  179. package/dist/internal/reminder-runner.js +21 -0
  180. package/dist/internal/run-client.d.ts +15 -0
  181. package/dist/internal/run-client.d.ts.map +1 -1
  182. package/dist/internal/run-client.js +3 -2
  183. package/dist/internal/sdk-runner.d.ts +51 -1
  184. package/dist/internal/sdk-runner.d.ts.map +1 -1
  185. package/dist/internal/sdk-runner.js +176 -36
  186. package/dist/internal/server.d.ts.map +1 -1
  187. package/dist/internal/server.js +11 -1
  188. package/dist/internal/session-engine.d.ts +18 -5
  189. package/dist/internal/session-engine.d.ts.map +1 -1
  190. package/dist/internal/session-engine.js +81 -19
  191. package/dist/internal/slack-provision-client.d.ts +133 -0
  192. package/dist/internal/slack-provision-client.d.ts.map +1 -0
  193. package/dist/internal/slack-provision-client.js +286 -0
  194. package/dist/playground/assets/cursor-icons-16-f_W_ogc-.woff2 +0 -0
  195. package/dist/playground/assets/index-DRjS5klQ.js +85 -0
  196. package/dist/playground/assets/index-TCDs-UhZ.css +1 -0
  197. package/dist/playground/index.html +2 -2
  198. package/dist/types.d.ts +98 -4
  199. package/dist/types.d.ts.map +1 -1
  200. package/dist/types.js +26 -0
  201. package/docs/example-agents/security-reviewer.md +1 -1
  202. package/docs/guides/mcp-oauth.md +10 -5
  203. package/docs/guides/slack.md +3 -2
  204. package/docs/reference/connections.md +28 -18
  205. package/package.json +20 -2
  206. package/skills/create-agent/SKILL.md +15 -7
  207. package/skills/debug/SKILL.md +3 -1
  208. package/skills/mcp-auth/SKILL.md +1 -1
  209. package/skills/setup-slack/SKILL.md +177 -11
  210. package/src/bin/agent-serve.ts +63 -2
  211. package/src/channels/slack/api.ts +16 -3
  212. package/src/channels/slack/auth.ts +16 -1
  213. package/src/channels/slack/blocks.ts +139 -0
  214. package/src/channels/slack/cursor-account.ts +1 -0
  215. package/src/channels/slack/defaults.ts +32 -4
  216. package/src/channels/slack/dispatch.ts +6 -19
  217. package/src/channels/slack/inbound.ts +6 -1
  218. package/src/channels/slack/index.ts +2 -0
  219. package/src/channels/slack/init.ts +3 -0
  220. package/src/channels/slack/interactive.ts +184 -19
  221. package/src/channels/slack/manifest.ts +37 -6
  222. package/src/channels/slack/message-body.ts +90 -0
  223. package/src/channels/slack/setup.ts +16 -2
  224. package/src/channels/slack/slack-channel.ts +37 -6
  225. package/src/channels/slack/thread-context.ts +1 -69
  226. package/src/channels/slack/types.ts +105 -1
  227. package/src/connections.ts +4 -1
  228. package/src/evals/assertions.ts +704 -0
  229. package/src/evals/expect.ts +272 -0
  230. package/src/evals/judge.ts +346 -0
  231. package/src/evals/loaders.ts +113 -0
  232. package/src/evals/matchers.ts +246 -0
  233. package/src/evals/reporters.ts +274 -0
  234. package/src/evals/results.ts +132 -0
  235. package/src/evals/run-facts.ts +274 -0
  236. package/src/evals.ts +205 -42
  237. package/src/index.ts +2 -0
  238. package/src/internal/builtin-tools/index.ts +40 -0
  239. package/src/internal/builtin-tools/reminders.ts +158 -0
  240. package/src/internal/cli-ax.ts +134 -15
  241. package/src/internal/cli-mcp.ts +118 -5
  242. package/src/internal/cli-slack.ts +1017 -15
  243. package/src/internal/cursor-event-relay.ts +67 -0
  244. package/src/internal/deploy-client.ts +10 -0
  245. package/src/internal/discovery.ts +83 -5
  246. package/src/internal/distribution.ts +2 -0
  247. package/src/internal/eval-judge-model.ts +148 -0
  248. package/src/internal/eval-run-store.ts +10 -14
  249. package/src/internal/eval-runner.ts +460 -214
  250. package/src/internal/evals-client.ts +5 -0
  251. package/src/internal/local-env.ts +53 -0
  252. package/src/internal/playground/static.ts +3 -0
  253. package/src/internal/reminder-runner.ts +30 -0
  254. package/src/internal/run-client.ts +17 -1
  255. package/src/internal/sdk-runner.ts +234 -35
  256. package/src/internal/server.ts +12 -0
  257. package/src/internal/session-engine.ts +103 -21
  258. package/src/internal/slack-provision-client.ts +442 -0
  259. package/src/types.ts +125 -4
  260. package/dist/channels/slack/post-update-delivery.d.ts +0 -85
  261. package/dist/channels/slack/post-update-delivery.d.ts.map +0 -1
  262. package/dist/docs/assets/chunks/@localSearchIndexroot.DZtu0ZIc.js +0 -1
  263. package/dist/internal/json-dir-store.d.ts +0 -32
  264. package/dist/internal/json-dir-store.d.ts.map +0 -1
  265. package/dist/internal/persistence-coordinator.d.ts +0 -127
  266. package/dist/internal/persistence-coordinator.d.ts.map +0 -1
  267. package/dist/persistence.d.ts +0 -184
  268. package/dist/persistence.d.ts.map +0 -1
  269. package/dist/playground/assets/cursor-icons-16-CQ50JpfO.woff2 +0 -0
  270. package/dist/playground/assets/index-Bwl4Onx4.js +0 -85
  271. package/dist/playground/assets/index-ByV4nfch.css +0 -1
  272. /package/dist/docs/assets/{example-agents_security-reviewer.md.BZSNycMf.lean.js → example-agents_security-reviewer.md.Dhj_m7_B.lean.js} +0 -0
  273. /package/dist/docs/assets/{guides_slack.md.FWale6Ip.lean.js → guides_slack.md.D_xFKlnF.lean.js} +0 -0
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Loads an agent directory's `.env.local` (and each immediate child's,
3
+ * for multi-agent hosts) into process.env. Real env always wins —
4
+ * `process.loadEnvFile` never overrides. Values a previous call loaded are
5
+ * refreshed, so a reload picks up edits made since.
6
+ */
7
+ import { existsSync, readdirSync } from "node:fs";
8
+ import { join } from "node:path";
9
+ // Not real env, so a reload has to clear them first: loadEnvFile skips
10
+ // anything already in process.env, which would pin the first-boot values.
11
+ let fileLoadedKeys = new Set();
12
+ export function loadAgentLocalEnv(dir) {
13
+ for (const key of fileLoadedKeys) {
14
+ delete process.env[key];
15
+ }
16
+ const realKeys = new Set(Object.keys(process.env));
17
+ const loaded = [];
18
+ const tryLoad = (path) => {
19
+ if (!existsSync(path)) {
20
+ return;
21
+ }
22
+ process.loadEnvFile(path);
23
+ loaded.push(path);
24
+ };
25
+ const trackLoadedKeys = () => {
26
+ fileLoadedKeys = new Set(Object.keys(process.env).filter((key) => !realKeys.has(key)));
27
+ };
28
+ tryLoad(join(dir, ".env.local"));
29
+ let children;
30
+ try {
31
+ children = readdirSync(dir, { withFileTypes: true })
32
+ .filter((entry) => entry.isDirectory() && !entry.name.startsWith("."))
33
+ .map((entry) => entry.name);
34
+ }
35
+ catch (_a) {
36
+ trackLoadedKeys();
37
+ return loaded;
38
+ }
39
+ for (const child of children) {
40
+ if (child === "node_modules") {
41
+ continue;
42
+ }
43
+ tryLoad(join(dir, child, ".env.local"));
44
+ }
45
+ trackLoadedKeys();
46
+ return loaded;
47
+ }
@@ -18,6 +18,9 @@ export declare function playgroundBundleExists(): boolean;
18
18
  * The SPA `index.html` with a `<base href>` injected so its relative asset
19
19
  * URLs resolve under the mount point (`/playground/` or `/<slug>/playground/`).
20
20
  * Falls back to a helpful placeholder page when the bundle is missing.
21
+ * The hosted alias performs the same injection for its central copy
22
+ * (`backend/server/src/agentServe/aliasPlaygroundShell.ts`) — keep them
23
+ * behaviorally aligned.
21
24
  */
22
25
  export declare function renderPlaygroundIndexHtml(baseHref: string): string;
23
26
  /** Serve one built asset from `dist/playground/assets/` by filename. */
@@ -1 +1 @@
1
- {"version":3,"file":"static.d.ts","sourceRoot":"","sources":["../../../src/internal/playground/static.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAcH,iFAAiF;AACjF,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAiBvD,CAAC;AAEF,uEAAuE;AACvE,wBAAgB,sBAAsB,IAAI,OAAO,CAEhD;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAUlE;AAED,wEAAwE;AACxE,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,CAsB5D;AAED,6CAA6C;AAC7C,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,+EAA+E;AAC/E,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,eAAe,EAAE,GAAG,MAAM,CAiBvE"}
1
+ {"version":3,"file":"static.d.ts","sourceRoot":"","sources":["../../../src/internal/playground/static.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAcH,iFAAiF;AACjF,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAiBvD,CAAC;AAEF,uEAAuE;AACvE,wBAAgB,sBAAsB,IAAI,OAAO,CAEhD;AAED;;;;;;;GAOG;AACH,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAUlE;AAED,wEAAwE;AACxE,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,CAsB5D;AAED,6CAA6C;AAC7C,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,+EAA+E;AAC/E,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,eAAe,EAAE,GAAG,MAAM,CAiBvE"}
@@ -45,6 +45,9 @@ export function playgroundBundleExists() {
45
45
  * The SPA `index.html` with a `<base href>` injected so its relative asset
46
46
  * URLs resolve under the mount point (`/playground/` or `/<slug>/playground/`).
47
47
  * Falls back to a helpful placeholder page when the bundle is missing.
48
+ * The hosted alias performs the same injection for its central copy
49
+ * (`backend/server/src/agentServe/aliasPlaygroundShell.ts`) — keep them
50
+ * behaviorally aligned.
48
51
  */
49
52
  export function renderPlaygroundIndexHtml(baseHref) {
50
53
  if (!playgroundBundleExists()) {
@@ -42,6 +42,13 @@ export declare class ReminderRunner {
42
42
  cancel(id: string, reason?: string): Promise<ReminderInfo | undefined>;
43
43
  /** Cancel all armed reminders matching a continuation token (e.g. PR closed). */
44
44
  cancelForContinuation(continuationToken: string, reason: string): Promise<number>;
45
+ /**
46
+ * Re-key armed reminders when a channel rotates a session's continuation
47
+ * token (the built-in HTTP channel rotates after every follow-up). Without
48
+ * this, a reminder armed before the rotation misses its session at fire
49
+ * time and disarms as `session_gone`.
50
+ */
51
+ rekeyContinuation(channelId: string, oldToken: string, newToken: string): Promise<number>;
45
52
  /** Fire one reminder immediately (dev / hillclimb). */
46
53
  dispatch(reminderId: string): Promise<{
47
54
  reminderId: string;
@@ -1 +1 @@
1
- {"version":3,"file":"reminder-runner.d.ts","sourceRoot":"","sources":["../../src/internal/reminder-runner.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAEV,mBAAmB,EAGnB,YAAY,EAEb,MAAM,aAAa,CAAC;AASrB,OAAO,EAEL,KAAK,cAAc,EAEpB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAoB,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAE3E,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAEjE,qBAAa,oBAAqB,SAAQ,KAAK;IAG3C,QAAQ,CAAC,oBAAoB,EAAE,MAAM,EAAE;IAFzC,YACE,UAAU,EAAE,MAAM,EACT,oBAAoB,EAAE,MAAM,EAAE,EAIxC;CACF;AAyDD,qBAAa,cAAc;IAUvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAVzB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgB;IACtC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAmC;IAC5D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqC;IAC5D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqB;IAC5C,uEAAuE;IACvE,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAoC;IAC9D,OAAO,CAAC,OAAO,CAAS;IAExB,YACmB,MAAM,EAAE,aAAa,EACrB,MAAM,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAe,EAG3D;IAED,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED,sEAAsE;IAChE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CA+B3B;IAED;;;OAGG;YACW,kBAAkB;IA6BhC,8EAA8E;YAChE,OAAO;IAKrB,IAAI,IAAI,IAAI,CAOX;IAEK,MAAM,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,YAAY,CAAC,CA8D9D;IAEK,IAAI,CAAC,MAAM,CAAC,EAAE;QAClB,MAAM,CAAC,EAAE,cAAc,CAAC,QAAQ,CAAC,CAAC;QAClC,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,iBAAiB,CAAC,EAAE,MAAM,CAAC;KAC5B,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CA4B1B;IAEK,MAAM,CACV,EAAE,EAAE,MAAM,EACV,MAAM,SAAoB,GACzB,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC,CAkBnC;IAED,iFAAiF;IAC3E,qBAAqB,CACzB,iBAAiB,EAAE,MAAM,EACzB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,CAAC,CAUjB;IAED,uDAAuD;IACjD,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC;QAC1C,UAAU,EAAE,MAAM,CAAC;QACnB,OAAO,EAAE,OAAO,GAAG,MAAM,CAAC;QAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC,CAQD;IAED,OAAO,CAAC,QAAQ;IA4ChB,OAAO,CAAC,UAAU;YAQJ,IAAI;YA6GJ,aAAa;IAY3B,OAAO,CAAC,eAAe;IAsBvB;;;OAGG;YACW,mBAAmB;YAcnB,aAAa;YAcb,YAAY;IA0C1B,OAAO,CAAC,gBAAgB;IAyDxB,OAAO,CAAC,iBAAiB;YAeX,MAAM;YAYN,SAAS;CAoFxB;AAGD,YAAY,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC"}
1
+ {"version":3,"file":"reminder-runner.d.ts","sourceRoot":"","sources":["../../src/internal/reminder-runner.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAEV,mBAAmB,EAGnB,YAAY,EAEb,MAAM,aAAa,CAAC;AASrB,OAAO,EAEL,KAAK,cAAc,EAEpB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAoB,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAE3E,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAEjE,qBAAa,oBAAqB,SAAQ,KAAK;IAG3C,QAAQ,CAAC,oBAAoB,EAAE,MAAM,EAAE;IAFzC,YACE,UAAU,EAAE,MAAM,EACT,oBAAoB,EAAE,MAAM,EAAE,EAIxC;CACF;AAyDD,qBAAa,cAAc;IAUvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAVzB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgB;IACtC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAmC;IAC5D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqC;IAC5D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqB;IAC5C,uEAAuE;IACvE,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAoC;IAC9D,OAAO,CAAC,OAAO,CAAS;IAExB,YACmB,MAAM,EAAE,aAAa,EACrB,MAAM,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAe,EAG3D;IAED,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED,sEAAsE;IAChE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CA+B3B;IAED;;;OAGG;YACW,kBAAkB;IA6BhC,8EAA8E;YAChE,OAAO;IAKrB,IAAI,IAAI,IAAI,CAOX;IAEK,MAAM,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,YAAY,CAAC,CA8D9D;IAEK,IAAI,CAAC,MAAM,CAAC,EAAE;QAClB,MAAM,CAAC,EAAE,cAAc,CAAC,QAAQ,CAAC,CAAC;QAClC,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,iBAAiB,CAAC,EAAE,MAAM,CAAC;KAC5B,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CA4B1B;IAEK,MAAM,CACV,EAAE,EAAE,MAAM,EACV,MAAM,SAAoB,GACzB,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC,CAkBnC;IAED,iFAAiF;IAC3E,qBAAqB,CACzB,iBAAiB,EAAE,MAAM,EACzB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,CAAC,CAUjB;IAED;;;;;OAKG;IACG,iBAAiB,CACrB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,CAAC,CAkBjB;IAED,uDAAuD;IACjD,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC;QAC1C,UAAU,EAAE,MAAM,CAAC;QACnB,OAAO,EAAE,OAAO,GAAG,MAAM,CAAC;QAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC,CAQD;IAED,OAAO,CAAC,QAAQ;IA4ChB,OAAO,CAAC,UAAU;YAQJ,IAAI;YA6GJ,aAAa;IAY3B,OAAO,CAAC,eAAe;IAsBvB;;;OAGG;YACW,mBAAmB;YAcnB,aAAa;YAcb,YAAY;IA0C1B,OAAO,CAAC,gBAAgB;IAyDxB,OAAO,CAAC,iBAAiB;YAeX,MAAM;YAYN,SAAS;CAoFxB;AAGD,YAAY,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC"}
@@ -279,6 +279,27 @@ export class ReminderRunner {
279
279
  return n;
280
280
  });
281
281
  }
282
+ /**
283
+ * Re-key armed reminders when a channel rotates a session's continuation
284
+ * token (the built-in HTTP channel rotates after every follow-up). Without
285
+ * this, a reminder armed before the rotation misses its session at fire
286
+ * time and disarms as `session_gone`.
287
+ */
288
+ rekeyContinuation(channelId, oldToken, newToken) {
289
+ return __awaiter(this, void 0, void 0, function* () {
290
+ const armed = yield this.store.listArmed();
291
+ let n = 0;
292
+ for (const record of armed) {
293
+ if (record.channelId !== channelId ||
294
+ record.continuationToken !== oldToken) {
295
+ continue;
296
+ }
297
+ yield this.persist(Object.assign(Object.assign({}, record), { continuationToken: newToken, updatedAt: new Date().toISOString() }));
298
+ n += 1;
299
+ }
300
+ return n;
301
+ });
302
+ }
282
303
  /** Fire one reminder immediately (dev / hillclimb). */
283
304
  dispatch(reminderId) {
284
305
  return __awaiter(this, void 0, void 0, function* () {
@@ -34,6 +34,11 @@ export interface RunSessionResult {
34
34
  events: SessionEvent[];
35
35
  trajectory: Trajectory;
36
36
  ok: boolean;
37
+ /**
38
+ * Index to pass as `startIndex` on the next call for this session. Undefined
39
+ * when the turn streamed nothing, in which case reuse the previous value.
40
+ */
41
+ nextEventIndex?: number;
37
42
  }
38
43
  /**
39
44
  * Run one or more messages against a live agent-serve base URL
@@ -43,6 +48,16 @@ export declare function runSession(options: RunClientOptions & {
43
48
  messages: string[];
44
49
  sessionId?: string;
45
50
  continuationToken?: string;
51
+ /**
52
+ * First event index to read when resuming an existing session.
53
+ *
54
+ * The stream replays from `startIndex` and this client stops at the first
55
+ * terminal event, so a caller that sends several turns across separate
56
+ * `runSession` calls **must** pass the index after its last consumed event
57
+ * (see {@link RunSessionResult.nextEventIndex}). Omitting it replays the
58
+ * earlier turn and returns those stale events instead of the new turn's.
59
+ */
60
+ startIndex?: number;
46
61
  /** Applied only when creating a new session (first message). */
47
62
  workspaceDir?: string;
48
63
  /** Applied only when creating a new session (first message). */
@@ -1 +1 @@
1
- {"version":3,"file":"run-client.d.ts","sourceRoot":"","sources":["../../src/internal/run-client.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EACV,iBAAiB,EACjB,YAAY,EACZ,cAAc,EACf,MAAM,aAAa,CAAC;AACrB,OAAO,EAAuB,KAAK,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC7E,OAAO,EAAmB,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAEnE,6EAA6E;AAC7E,qBAAa,sBAAuB,SAAQ,KAAK;IAG7C,QAAQ,CAAC,SAAS,EAAE,MAAM;IAF5B,YACE,OAAO,EAAE,MAAM,EACN,SAAS,EAAE,MAAM,EAI3B;CACF;AACD,MAAM,WAAW,gBAAiB,SAAQ,WAAW;IACnD,OAAO,EAAE,MAAM,CAAC;IAChB,yBAAyB;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2EAA2E;IAC3E,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,qEAAqE;IACrE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;IACxC;;;OAGG;IACH,OAAO,CAAC,EAAE,cAAc,CAAC;CAC1B;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,YAAY,EAAE,CAAC;IACvB,UAAU,EAAE,UAAU,CAAC;IACvB,EAAE,EAAE,OAAO,CAAC;CACb;AAQD;;;GAGG;AACH,wBAAsB,UAAU,CAC9B,OAAO,EAAE,gBAAgB,GAAG;IAC1B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,gEAAgE;IAChE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gEAAgE;IAChE,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,gEAAgE;IAChE,KAAK,CAAC,EAAE,iBAAiB,CAAC;CAC3B,GACA,OAAO,CAAC,gBAAgB,CAAC,CAyD3B"}
1
+ {"version":3,"file":"run-client.d.ts","sourceRoot":"","sources":["../../src/internal/run-client.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EACV,iBAAiB,EACjB,YAAY,EACZ,cAAc,EACf,MAAM,aAAa,CAAC;AACrB,OAAO,EAAuB,KAAK,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC7E,OAAO,EAAmB,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAEnE,6EAA6E;AAC7E,qBAAa,sBAAuB,SAAQ,KAAK;IAG7C,QAAQ,CAAC,SAAS,EAAE,MAAM;IAF5B,YACE,OAAO,EAAE,MAAM,EACN,SAAS,EAAE,MAAM,EAI3B;CACF;AACD,MAAM,WAAW,gBAAiB,SAAQ,WAAW;IACnD,OAAO,EAAE,MAAM,CAAC;IAChB,yBAAyB;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2EAA2E;IAC3E,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,qEAAqE;IACrE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;IACxC;;;OAGG;IACH,OAAO,CAAC,EAAE,cAAc,CAAC;CAC1B;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,YAAY,EAAE,CAAC;IACvB,UAAU,EAAE,UAAU,CAAC;IACvB,EAAE,EAAE,OAAO,CAAC;IACZ;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAQD;;;GAGG;AACH,wBAAsB,UAAU,CAC9B,OAAO,EAAE,gBAAgB,GAAG;IAC1B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;;;;;;;;OAQG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gEAAgE;IAChE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gEAAgE;IAChE,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,gEAAgE;IAChE,KAAK,CAAC,EAAE,iBAAiB,CAAC;CAC3B,GACA,OAAO,CAAC,gBAAgB,CAAC,CA0D3B"}
@@ -35,6 +35,7 @@ const TERMINAL_TYPES = new Set([
35
35
  */
36
36
  export function runSession(options) {
37
37
  return __awaiter(this, void 0, void 0, function* () {
38
+ var _a;
38
39
  if (options.messages.length === 0) {
39
40
  throw new Error("runSession requires at least one message");
40
41
  }
@@ -42,7 +43,7 @@ export function runSession(options) {
42
43
  let sessionId = options.sessionId;
43
44
  let continuationToken = options.continuationToken;
44
45
  const allEvents = [];
45
- let nextEventIndex = 0;
46
+ let nextEventIndex = (_a = options.startIndex) !== null && _a !== void 0 ? _a : 0;
46
47
  const auth = {
47
48
  bearerToken: options.bearerToken,
48
49
  headers: options.headers,
@@ -78,7 +79,7 @@ export function runSession(options) {
78
79
  throw new Error("server did not return a session id");
79
80
  }
80
81
  const trajectory = buildTrajectory(allEvents);
81
- return Object.assign(Object.assign({ sessionId }, (continuationToken === undefined ? {} : { continuationToken })), { baseUrl, events: allEvents, trajectory, ok: trajectory.ok });
82
+ return Object.assign(Object.assign({ sessionId }, (continuationToken === undefined ? {} : { continuationToken })), { baseUrl, events: allEvents, trajectory, ok: trajectory.ok, nextEventIndex: allEvents.length === 0 ? undefined : nextEventIndex });
82
83
  });
83
84
  }
84
85
  function runOneTurn(args) {
@@ -5,13 +5,33 @@
5
5
  * settings; cloud agents use Cursor cloud (`bc-…` ids) with optional
6
6
  * `cloud` options from `defineAgent`.
7
7
  */
8
- import { type LocalAgentStore, type ModelSelection } from "@cursor/sdk";
8
+ import { type LocalAgentStore, type ModelSelection, type RunResult } from "@cursor/sdk";
9
9
  import { type ModelSetting, type RunnerTurnRequest, type TurnOutcome } from "../types.js";
10
10
  /** Internal seam between the session engine and the Cursor SDK harness. */
11
11
  export interface AgentRunner {
12
12
  runTurn(request: RunnerTurnRequest): Promise<TurnOutcome>;
13
+ /**
14
+ * Resolve a local workspace before any session needs it, so the first turn
15
+ * is not the one that pays for it. Best effort, hence the reported outcome:
16
+ * a runner that cannot warm must say so rather than let a caller log
17
+ * success over a workspace that was never touched.
18
+ */
19
+ prewarm?(request: RunnerPrewarmRequest): Promise<PrewarmOutcome>;
13
20
  dispose?(): Promise<void>;
14
21
  }
22
+ /**
23
+ * The parts of a turn that decide which local executor it runs on. Must stay
24
+ * a subset of {@link RunnerTurnRequest} — anything that disagrees warms an
25
+ * executor no turn will ask for.
26
+ */
27
+ export type RunnerPrewarmRequest = Pick<RunnerTurnRequest, "workspaceDir" | "runnerStateDir" | "sandbox" | "mcpServers" | "subagents" | "model">;
28
+ /** Whether a workspace was actually resolved, and why not when it wasn't. */
29
+ export type PrewarmOutcome = {
30
+ readonly warmed: true;
31
+ } | {
32
+ readonly warmed: false;
33
+ readonly reason: string;
34
+ };
15
35
  export interface CursorSdkRunnerOptions {
16
36
  /** Cursor API key. Defaults to the `CURSOR_API_KEY` environment variable. */
17
37
  apiKey?: string;
@@ -24,14 +44,43 @@ export interface CursorSdkRunnerOptions {
24
44
  /** Diagnostics for degraded paths (resume-miss fallback). */
25
45
  logger?: (line: string) => void;
26
46
  }
47
+ /**
48
+ * The backend's `NotLoggedIn` copy ("Authentication error" title, "try
49
+ * logging out and back in." detail) as it surfaces through SDK RunResults.
50
+ * Deliberately narrow: this gates a one-shot in-place retry, and matching
51
+ * broader error text would retry turns that a fresh transport cannot fix.
52
+ */
53
+ export declare function isAuthErrorMessage(message: string | undefined): boolean;
27
54
  export declare class CursorSdkRunner implements AgentRunner {
28
55
  private readonly options;
29
56
  private readonly agents;
30
57
  private readonly stores;
58
+ private readonly prewarmReleases;
31
59
  constructor(options?: CursorSdkRunnerOptions);
32
60
  runTurn(request: RunnerTurnRequest): Promise<TurnOutcome>;
61
+ private runTurnAttempt;
62
+ /**
63
+ * Build the local executor for a workspace before any session asks for it.
64
+ * The warmed executor is reference counted, so the lease is held until
65
+ * {@link dispose}; dropping it early would tear the workspace back down.
66
+ */
67
+ prewarm(request: RunnerPrewarmRequest): Promise<PrewarmOutcome>;
33
68
  dispose(): Promise<void>;
34
69
  private getAgent;
70
+ /**
71
+ * Drop a cached handle and close it best-effort to release its transport
72
+ * and executor lease. Identity-checked so a turn that lost a race with a
73
+ * newer open cannot evict the replacement handle.
74
+ */
75
+ private evictAgent;
76
+ private log;
77
+ private requireApiKey;
78
+ private buildSharedOptions;
79
+ /**
80
+ * The options that decide which local executor a turn runs on. Prewarming
81
+ * goes through here too, so a warmed workspace is the one turns land on.
82
+ */
83
+ private buildLocalOptions;
35
84
  private openAgent;
36
85
  private openLocalAgent;
37
86
  private openCloudAgent;
@@ -47,4 +96,5 @@ export declare function isServerMintedCloudAgentId(id: string): boolean;
47
96
  */
48
97
  export declare function isLocalAgentNotFoundError(error: unknown, agentId: string): boolean;
49
98
  export declare function toModelSelection(model: ModelSetting): ModelSelection;
99
+ export declare function runErrorMessage(result: Pick<RunResult, "error">): string;
50
100
  //# sourceMappingURL=sdk-runner.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sdk-runner.d.ts","sourceRoot":"","sources":["../../src/internal/sdk-runner.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAML,KAAK,eAAe,EACpB,KAAK,cAAc,EAGpB,MAAM,aAAa,CAAC;AACrB,OAAO,EAEL,KAAK,YAAY,EAEjB,KAAK,iBAAiB,EACtB,KAAK,WAAW,EAEjB,MAAM,aAAa,CAAC;AAErB,2EAA2E;AAC3E,MAAM,WAAW,WAAW;IAC1B,OAAO,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAC1D,OAAO,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B;AAED,MAAM,WAAW,sBAAsB;IACrC,6EAA6E;IAC7E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB,6DAA6D;IAC7D,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACjC;AAED,qBAAa,eAAgB,YAAW,WAAW;IAIrC,OAAO,CAAC,QAAQ,CAAC,OAAO;IAHpC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAwC;IAC/D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA+C;IAEtE,YAA6B,OAAO,GAAE,sBAA2B,EAAI;IAE/D,OAAO,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,WAAW,CAAC,CA0D9D;IAEK,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAQ7B;IAED,OAAO,CAAC,QAAQ;YAYF,SAAS;YA2BT,cAAc;YAyCd,cAAc;IAqC5B,OAAO,CAAC,QAAQ;CAUjB;AAED,4EAA4E;AAC5E,wBAAgB,0BAA0B,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAE9D;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,OAAO,EACd,OAAO,EAAE,MAAM,GACd,OAAO,CAMT;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,YAAY,GAAG,cAAc,CAQpE"}
1
+ {"version":3,"file":"sdk-runner.d.ts","sourceRoot":"","sources":["../../src/internal/sdk-runner.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAOL,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,SAAS,EAEf,MAAM,aAAa,CAAC;AACrB,OAAO,EAEL,KAAK,YAAY,EAEjB,KAAK,iBAAiB,EACtB,KAAK,WAAW,EAEjB,MAAM,aAAa,CAAC;AAErB,2EAA2E;AAC3E,MAAM,WAAW,WAAW;IAC1B,OAAO,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAC1D;;;;;OAKG;IACH,OAAO,CAAC,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IACjE,OAAO,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B;AAED;;;;GAIG;AACH,MAAM,MAAM,oBAAoB,GAAG,IAAI,CACrC,iBAAiB,EACf,cAAc,GACd,gBAAgB,GAChB,SAAS,GACT,YAAY,GACZ,WAAW,GACX,OAAO,CACV,CAAC;AAEF,6EAA6E;AAC7E,MAAM,MAAM,cAAc,GACtB;IAAE,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAA;CAAE,GACzB;IAAE,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAcxD,MAAM,WAAW,sBAAsB;IACrC,6EAA6E;IAC7E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB,6DAA6D;IAC7D,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACjC;AAwBD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAKvE;AAED,qBAAa,eAAgB,YAAW,WAAW;IAKrC,OAAO,CAAC,QAAQ,CAAC,OAAO;IAJpC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAwC;IAC/D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA+C;IACtE,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAkC;IAElE,YAA6B,OAAO,GAAE,sBAA2B,EAAI;IAE/D,OAAO,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,WAAW,CAAC,CAkC9D;YAEa,cAAc;IAyE5B;;;;OAIG;IACG,OAAO,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,cAAc,CAAC,CAepE;IAEK,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAY7B;IAED,OAAO,CAAC,QAAQ;IA0BhB;;;;OAIG;IACH,OAAO,CAAC,UAAU;IASlB,OAAO,CAAC,GAAG;IAIX,OAAO,CAAC,aAAa;IAUrB,OAAO,CAAC,kBAAkB;IAc1B;;;OAGG;YACW,iBAAiB;YAkBjB,SAAS;YAOT,cAAc;YA6Bd,cAAc;IAqC5B,OAAO,CAAC,QAAQ;CAUjB;AAED,4EAA4E;AAC5E,wBAAgB,0BAA0B,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAE9D;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,OAAO,EACd,OAAO,EAAE,MAAM,GACd,OAAO,CAMT;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,YAAY,GAAG,cAAc,CAQpE;AAmED,wBAAgB,eAAe,CAAC,MAAM,EAAE,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,GAAG,MAAM,CAExE"}
@@ -15,18 +15,80 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
15
15
  });
16
16
  };
17
17
  import { mkdir } from "node:fs/promises";
18
- import { Agent, JsonlLocalAgentStore, } from "@cursor/sdk";
18
+ import { Agent, createAgentPlatform, JsonlLocalAgentStore, } from "@cursor/sdk";
19
19
  import { DEFAULT_MODEL, } from "../types.js";
20
+ /**
21
+ * How long one SDK agent handle (and the Connect transport inside it) may be
22
+ * reused before the runner retires it.
23
+ *
24
+ * The transport exchanges the account API key for a short-lived access token
25
+ * (`SessionType.API_KEY_TOKEN`, 60 minutes) once per handle, and has no
26
+ * reliable refresh: an Unauthenticated rejection on the agent's streaming RPC
27
+ * surfaces while the stream is being read — outside the transport's
28
+ * request-time 401 retry — so an expired token gets replayed on every
29
+ * subsequent turn until the handle is rebuilt. Long-lived sessions (watch
30
+ * wakes, crons) hit this at the ~60 minute mark and then fail forever.
31
+ * Retiring the handle comfortably before the token can expire keeps them
32
+ * healthy: `Agent.resume` rehydrates the same conversation from the runner
33
+ * store on a fresh transport, so recycling costs only transport warmth.
34
+ */
35
+ const MAX_AGENT_HANDLE_AGE_MS = 45 * 60 * 1000;
36
+ /**
37
+ * The backend's `NotLoggedIn` copy ("Authentication error" title, "try
38
+ * logging out and back in." detail) as it surfaces through SDK RunResults.
39
+ * Deliberately narrow: this gates a one-shot in-place retry, and matching
40
+ * broader error text would retry turns that a fresh transport cannot fix.
41
+ */
42
+ export function isAuthErrorMessage(message) {
43
+ if (message === undefined) {
44
+ return false;
45
+ }
46
+ return /authentication error|try logging out and back in/i.test(message);
47
+ }
20
48
  export class CursorSdkRunner {
21
49
  constructor(options = {}) {
22
50
  this.options = options;
23
51
  this.agents = new Map();
24
52
  this.stores = new Map();
53
+ this.prewarmReleases = [];
25
54
  }
26
55
  runTurn(request) {
27
56
  return __awaiter(this, void 0, void 0, function* () {
57
+ var _a;
58
+ let sawUpdate = false;
59
+ const tracked = Object.assign(Object.assign({}, request), { onUpdate: (update) => {
60
+ sawUpdate = true;
61
+ return request.onUpdate(update);
62
+ } });
63
+ const outcome = yield this.runTurnAttempt(tracked);
64
+ if (outcome.status !== "error" ||
65
+ !isAuthErrorMessage(outcome.errorMessage) ||
66
+ sawUpdate ||
67
+ request.isFirstTurn ||
68
+ ((_a = request.signal) === null || _a === void 0 ? void 0 : _a.aborted) === true) {
69
+ return outcome;
70
+ }
71
+ // The turn died on an authentication failure before producing any output
72
+ // — the signature of a handle whose exchanged access token expired (the
73
+ // failed attempt already evicted it). Retrying once on a fresh handle is
74
+ // safe here because nothing streamed and no tool ran. First turns are
75
+ // excluded: their token was exchanged moments ago, so the credential
76
+ // itself is the problem and a retry cannot succeed.
77
+ this.log(`[agentkit] session ${request.sessionId}: retrying the turn on a fresh SDK agent handle after an authentication failure`);
28
78
  try {
29
- const agent = yield this.getAgent(request);
79
+ return yield this.runTurnAttempt(tracked);
80
+ }
81
+ catch (_b) {
82
+ // The retry was best effort; report the original failure.
83
+ return outcome;
84
+ }
85
+ });
86
+ }
87
+ runTurnAttempt(request) {
88
+ return __awaiter(this, void 0, void 0, function* () {
89
+ const agentPromise = this.getAgent(request);
90
+ try {
91
+ const agent = yield agentPromise;
30
92
  const run = yield agent.send(request.prompt, Object.assign({ onDelta: (_a) => __awaiter(this, [_a], void 0, function* ({ update }) {
31
93
  try {
32
94
  yield request.onUpdate(update);
@@ -65,7 +127,17 @@ export class CursorSdkRunner {
65
127
  }
66
128
  try {
67
129
  const result = yield run.wait();
68
- return toTurnOutcome(result);
130
+ const outcome = toTurnOutcome(result);
131
+ if (outcome.status === "error") {
132
+ // An error result usually means the handle's transport is poisoned
133
+ // — most often a cached access token that aged past its 60-minute
134
+ // lifetime and gets replayed on every request (stream failures
135
+ // bypass the transport's 401 retry). Retire the handle so the next
136
+ // attempt resumes the conversation from the store on a fresh
137
+ // transport instead of failing every turn until a restart.
138
+ this.evictAgent(request.sessionId, agentPromise);
139
+ }
140
+ return outcome;
69
141
  }
70
142
  finally {
71
143
  signal === null || signal === void 0 ? void 0 : signal.removeEventListener("abort", onAbort);
@@ -74,14 +146,36 @@ export class CursorSdkRunner {
74
146
  catch (error) {
75
147
  // Drop the cached agent so a dead Connect/HTTP2 session cannot poison
76
148
  // the next turn (terminal/shell overflow often kills the transport).
77
- this.agents.delete(request.sessionId);
149
+ this.evictAgent(request.sessionId, agentPromise);
78
150
  throw error;
79
151
  }
80
152
  });
81
153
  }
154
+ /**
155
+ * Build the local executor for a workspace before any session asks for it.
156
+ * The warmed executor is reference counted, so the lease is held until
157
+ * {@link dispose}; dropping it early would tear the workspace back down.
158
+ */
159
+ prewarm(request) {
160
+ return __awaiter(this, void 0, void 0, function* () {
161
+ const platform = (yield createAgentPlatform());
162
+ if (typeof platform.prewarmLocalWorkspace !== "function") {
163
+ // Older @cursor/sdk. Turns still work; they just pay on the first one.
164
+ return {
165
+ warmed: false,
166
+ reason: "the installed @cursor/sdk has no prewarmLocalWorkspace; upgrade it to warm the workspace before the first turn",
167
+ };
168
+ }
169
+ const release = yield platform.prewarmLocalWorkspace(yield this.buildLocalOptions(request));
170
+ this.prewarmReleases.push(release);
171
+ return { warmed: true };
172
+ });
173
+ }
82
174
  dispose() {
83
175
  return __awaiter(this, void 0, void 0, function* () {
84
- const agents = yield Promise.allSettled([...this.agents.values()]);
176
+ const releases = this.prewarmReleases.splice(0);
177
+ yield Promise.allSettled(releases.map((release) => release()));
178
+ const agents = yield Promise.allSettled([...this.agents.values()].map((handle) => handle.agent));
85
179
  this.agents.clear();
86
180
  for (const settled of agents) {
87
181
  if (settled.status === "fulfilled") {
@@ -91,47 +185,89 @@ export class CursorSdkRunner {
91
185
  });
92
186
  }
93
187
  getAgent(request) {
94
- let agentPromise = this.agents.get(request.sessionId);
95
- if (agentPromise === undefined) {
96
- agentPromise = this.openAgent(request).catch((error) => {
97
- this.agents.delete(request.sessionId);
98
- throw error;
99
- });
100
- this.agents.set(request.sessionId, agentPromise);
188
+ const cached = this.agents.get(request.sessionId);
189
+ if (cached !== undefined) {
190
+ const ageMs = Date.now() - cached.openedAtMs;
191
+ if (ageMs < MAX_AGENT_HANDLE_AGE_MS) {
192
+ return cached.agent;
193
+ }
194
+ // Past this age the handle's exchanged access token could expire
195
+ // mid-turn. Retire it and reopen below on a fresh transport.
196
+ this.log(`[agentkit] session ${request.sessionId}: recycling the SDK agent handle after ${Math.round(ageMs / 60000)} min so the turn runs on a fresh access token`);
197
+ this.evictAgent(request.sessionId, cached.agent);
101
198
  }
199
+ const agentPromise = this.openAgent(request).catch((error) => {
200
+ // Nothing opened, so there is no handle to close — just free the slot.
201
+ this.agents.delete(request.sessionId);
202
+ throw error;
203
+ });
204
+ this.agents.set(request.sessionId, {
205
+ agent: agentPromise,
206
+ openedAtMs: Date.now(),
207
+ });
102
208
  return agentPromise;
103
209
  }
210
+ /**
211
+ * Drop a cached handle and close it best-effort to release its transport
212
+ * and executor lease. Identity-checked so a turn that lost a race with a
213
+ * newer open cannot evict the replacement handle.
214
+ */
215
+ evictAgent(sessionId, agent) {
216
+ const cached = this.agents.get(sessionId);
217
+ if (cached === undefined || cached.agent !== agent) {
218
+ return;
219
+ }
220
+ this.agents.delete(sessionId);
221
+ void cached.agent.then((sdkAgent) => sdkAgent.close()).catch(() => { });
222
+ }
223
+ log(line) {
224
+ var _a;
225
+ ((_a = this.options.logger) !== null && _a !== void 0 ? _a : (() => { }))(line);
226
+ }
227
+ requireApiKey() {
228
+ var _a;
229
+ const apiKey = (_a = this.options.apiKey) !== null && _a !== void 0 ? _a : process.env.CURSOR_API_KEY;
230
+ if (apiKey === undefined || apiKey.trim() === "") {
231
+ throw new Error("The Cursor SDK runner requires a Cursor credential: run `agent-serve login`, set CURSOR_API_KEY, or pass serve({ apiKey }).");
232
+ }
233
+ return apiKey;
234
+ }
235
+ buildSharedOptions(request) {
236
+ var _a;
237
+ const subagents = toAgentDefinitions(request.subagents);
238
+ return Object.assign(Object.assign({ model: toModelSelection((_a = request.model) !== null && _a !== void 0 ? _a : DEFAULT_MODEL), apiKey: this.requireApiKey() }, (Object.keys(request.mcpServers).length > 0
239
+ ? { mcpServers: request.mcpServers }
240
+ : {})), (subagents === undefined ? {} : { agents: subagents }));
241
+ }
242
+ /**
243
+ * The options that decide which local executor a turn runs on. Prewarming
244
+ * goes through here too, so a warmed workspace is the one turns land on.
245
+ */
246
+ buildLocalOptions(request) {
247
+ return __awaiter(this, void 0, void 0, function* () {
248
+ var _a;
249
+ const store = (_a = this.options.store) !== null && _a !== void 0 ? _a : (yield this.getStore(request.runnerStateDir));
250
+ return Object.assign(Object.assign({}, this.buildSharedOptions(request)), { local: Object.assign({ cwd: request.workspaceDir, settingSources: ["project"], store }, (request.sandbox === true
251
+ ? { sandboxOptions: { enabled: true } }
252
+ : {})) });
253
+ });
254
+ }
104
255
  openAgent(request) {
105
256
  return __awaiter(this, void 0, void 0, function* () {
106
- var _a, _b;
107
- const apiKey = (_a = this.options.apiKey) !== null && _a !== void 0 ? _a : process.env.CURSOR_API_KEY;
108
- if (apiKey === undefined || apiKey.trim() === "") {
109
- throw new Error("The Cursor SDK runner requires a Cursor credential: run `agent-serve login`, set CURSOR_API_KEY, or pass serve({ apiKey }).");
110
- }
111
- const model = (_b = request.model) !== null && _b !== void 0 ? _b : DEFAULT_MODEL;
112
- const subagents = toAgentDefinitions(request.subagents);
113
- const shared = Object.assign(Object.assign({ model: toModelSelection(model), apiKey }, (Object.keys(request.mcpServers).length > 0
114
- ? { mcpServers: request.mcpServers }
115
- : {})), (subagents === undefined ? {} : { agents: subagents }));
116
257
  if (request.runtime === "cloud") {
117
- return this.openCloudAgent(request, shared);
258
+ return this.openCloudAgent(request, this.buildSharedOptions(request));
118
259
  }
119
- return this.openLocalAgent(request, shared);
260
+ return this.openLocalAgent(request);
120
261
  });
121
262
  }
122
- openLocalAgent(request, shared) {
263
+ openLocalAgent(request) {
123
264
  return __awaiter(this, void 0, void 0, function* () {
124
- var _a, _b, _c, _d;
125
- const store = (_a = this.options.store) !== null && _a !== void 0 ? _a : (yield this.getStore(request.runnerStateDir));
126
- const options = Object.assign(Object.assign({}, shared), { local: {
127
- cwd: request.workspaceDir,
128
- settingSources: ["project"],
129
- store,
130
- } });
265
+ var _a, _b;
266
+ const options = yield this.buildLocalOptions(request);
131
267
  if (request.isFirstTurn || request.sdkAgentId === undefined) {
132
- return Agent.create(Object.assign(Object.assign({}, options), { agentId: (_b = request.sdkAgentId) !== null && _b !== void 0 ? _b : request.sessionId }));
268
+ return Agent.create(Object.assign(Object.assign({}, options), { agentId: (_a = request.sdkAgentId) !== null && _a !== void 0 ? _a : request.sessionId }));
133
269
  }
134
- const agentId = (_c = request.sdkAgentId) !== null && _c !== void 0 ? _c : request.sessionId;
270
+ const agentId = (_b = request.sdkAgentId) !== null && _b !== void 0 ? _b : request.sessionId;
135
271
  try {
136
272
  return yield Agent.resume(agentId, options);
137
273
  }
@@ -144,7 +280,7 @@ export class CursorSdkRunner {
144
280
  // conversation under the same id beats failing this thread's turns
145
281
  // forever ("Agent … not found" on every follow-up). The channel's
146
282
  // warm-turn prompt context re-hydrates the thread history.
147
- ((_d = this.options.logger) !== null && _d !== void 0 ? _d : (() => { }))(`[agentkit] no stored conversation for ${agentId} on this host; starting a fresh one`);
283
+ this.log(`[agentkit] no stored conversation for ${agentId} on this host; starting a fresh one`);
148
284
  return Agent.create(Object.assign(Object.assign({}, options), { agentId }));
149
285
  }
150
286
  });
@@ -242,6 +378,10 @@ function toTurnOutcome(result) {
242
378
  ? {}
243
379
  : { reasoningTokens: result.usage.reasoningTokens }));
244
380
  return Object.assign(Object.assign(Object.assign({ status: result.status }, (result.result === undefined ? {} : { result: result.result })), (result.status === "error"
245
- ? { errorMessage: "The Cursor agent run failed" }
381
+ ? { errorMessage: runErrorMessage(result) }
246
382
  : {})), (usage === undefined ? {} : { usage }));
247
383
  }
384
+ export function runErrorMessage(result) {
385
+ var _a, _b;
386
+ return ((_b = (_a = result.error) === null || _a === void 0 ? void 0 : _a.message) === null || _b === void 0 ? void 0 : _b.trim()) || "The Cursor agent run failed";
387
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/internal/server.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AA4BH,OAAO,KAAK,EACV,YAAY,EACZ,gBAAgB,EAOhB,YAAY,EACb,MAAM,aAAa,CAAC;AAqFrB,OAAO,EAAE,KAAK,WAAW,EAAmB,MAAM,iBAAiB,CAAC;AAapE,8EAA8E;AAC9E,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,YAAY,CAAC;CACvB;AAYD,6EAA6E;AAC7E,MAAM,WAAW,0BAA0B;IACzC,oEAAoE;IACpE,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED;;;;GAIG;AACH,wBAAsB,WAAW,CAC/B,MAAM,EAAE,UAAU,EAAE,EACpB,OAAO,GAAE,YAAY,GAAG,0BAA+B,GACtD,OAAO,CAAC,gBAAgB,CAAC,CAmpB3B"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/internal/server.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AA4BH,OAAO,KAAK,EACV,YAAY,EACZ,gBAAgB,EAOhB,YAAY,EACb,MAAM,aAAa,CAAC;AAqFrB,OAAO,EAAE,KAAK,WAAW,EAAmB,MAAM,iBAAiB,CAAC;AAapE,8EAA8E;AAC9E,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,YAAY,CAAC;CACvB;AAYD,6EAA6E;AAC7E,MAAM,WAAW,0BAA0B;IACzC,oEAAoE;IACpE,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED;;;;GAIG;AACH,wBAAsB,WAAW,CAC/B,MAAM,EAAE,UAAU,EAAE,EACpB,OAAO,GAAE,YAAY,GAAG,0BAA+B,GACtD,OAAO,CAAC,gBAAgB,CAAC,CA2pB3B"}
@@ -241,6 +241,11 @@ export function startServer(mounts_1) {
241
241
  // Rehydrate sessions from the authored storage sink before any
242
242
  // channel or route can address them (continuation tokens must resolve).
243
243
  yield engine.restoreStoredSessions();
244
+ // Resolve a shared harness workspace in the background: on a large repo
245
+ // that takes seconds, and a deployment coming online should absorb it
246
+ // rather than whoever sends the first message. No-op unless the agent
247
+ // pins `local.workspaceDir`.
248
+ void engine.prewarmSharedWorkspace();
244
249
  if (!githubAuthWarmed) {
245
250
  // Soft ambient GitHub auth check before channel onStart (which may call
246
251
  // host.github). Missing auth is a warning only — serve still starts.
@@ -263,6 +268,7 @@ export function startServer(mounts_1) {
263
268
  list: (filter) => reminderRunner.list(filter),
264
269
  cancel: (id, reason) => reminderRunner.cancel(id, reason),
265
270
  cancelForContinuation: (token, reason) => reminderRunner.cancelForContinuation(token, reason),
271
+ rekeyContinuation: (channelId, oldToken, newToken) => reminderRunner.rekeyContinuation(channelId, oldToken, newToken),
266
272
  dispatch: (id) => reminderRunner.dispatch(id),
267
273
  });
268
274
  engine.setEvals({
@@ -687,7 +693,11 @@ function mountAgentRoutes(router, runtime, args) {
687
693
  method: "GET",
688
694
  pattern: `${base}/v1/meta`,
689
695
  auth: "none",
690
- handler: () => jsonResponse(Object.assign({ name: project.name, dev, basePath: base }, (multi ? { indexPath: "/" } : {}))),
696
+ handler: () => jsonResponse(Object.assign({ name: project.name, dev, basePath: base,
697
+ // Framework version, for SPA/engine skew observability now that the
698
+ // hosted playground shell is served centrally (backend deploys)
699
+ // while engines stay on their install-time version.
700
+ version: packageVersion() }, (multi ? { indexPath: "/" } : {}))),
691
701
  });
692
702
  router.add({
693
703
  method: "GET",
@@ -227,15 +227,28 @@ export declare class SessionEngine {
227
227
  getContinuationLastBotMessageTs(channelId: string, continuationToken: string): Promise<string | undefined>;
228
228
  interruptContinuation(channelId: string, continuationToken: string): Promise<boolean>;
229
229
  /**
230
- * Local harness cwd for a session: per-send override, else
231
- * `<agent.local.cwd>/<sessionId>`, else the durable session workspace.
230
+ * Local harness cwd for a session: per-send override, else the shared
231
+ * `agent.local.workspaceDir`, else `<agent.local.cwd>/<sessionId>`, else
232
+ * the durable session workspace.
232
233
  */
233
234
  harnessCwd(record: SessionRecord): string;
234
235
  /**
235
- * Directory that receives AGENTS.md / skills / agent tools. When the
236
- * harness cwd is a one-off override (e.g. PR worktree), scaffold stays in
237
- * the durable session workspace; otherwise scaffold lands in the harness.
236
+ * True when the harness cwd is a directory the session does not own — a
237
+ * per-send override (e.g. a PR worktree) or a workspace shared by every
238
+ * session. Agent scaffold has to stay out of those, so it lands in the
239
+ * durable session workspace and the instructions travel inline instead.
238
240
  */
241
+ private hasBorrowedWorkspace;
242
+ /**
243
+ * Resolve the shared harness workspace during startup, so the first session
244
+ * is not the one that waits for it. Only possible with
245
+ * `local.workspaceDir`: every other layout gives a session its own cwd,
246
+ * which is unknowable until that session exists.
247
+ *
248
+ * Best effort — warming is an optimization, and a turn rebuilds on its own.
249
+ */
250
+ prewarmSharedWorkspace(): Promise<void>;
251
+ /** Directory that receives AGENTS.md / skills / agent tools. */
239
252
  private scaffoldDir;
240
253
  private executeTurn;
241
254
  private buildTurnRequest;