@cursor/july 0.1.39 → 0.1.41

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 (259) hide show
  1. package/AGENTS.md +4 -3
  2. package/dist/bin/agent-serve.js +28 -9
  3. package/dist/channels/slack/api.d.ts.map +1 -1
  4. package/dist/channels/slack/api.js +18 -8
  5. package/dist/channels/slack/attachments.d.ts +82 -0
  6. package/dist/channels/slack/attachments.d.ts.map +1 -0
  7. package/dist/channels/slack/attachments.js +520 -0
  8. package/dist/channels/slack/cursor-account.d.ts +7 -1
  9. package/dist/channels/slack/cursor-account.d.ts.map +1 -1
  10. package/dist/channels/slack/cursor-account.js +2 -2
  11. package/dist/channels/slack/defaults.d.ts.map +1 -1
  12. package/dist/channels/slack/defaults.js +26 -17
  13. package/dist/channels/slack/dispatch.d.ts +4 -3
  14. package/dist/channels/slack/dispatch.d.ts.map +1 -1
  15. package/dist/channels/slack/dispatch.js +84 -21
  16. package/dist/channels/slack/inbound.d.ts +6 -0
  17. package/dist/channels/slack/inbound.d.ts.map +1 -1
  18. package/dist/channels/slack/inbound.js +48 -2
  19. package/dist/channels/slack/index.d.ts +1 -0
  20. package/dist/channels/slack/index.d.ts.map +1 -1
  21. package/dist/channels/slack/index.js +1 -0
  22. package/dist/channels/slack/live-delivery.d.ts.map +1 -1
  23. package/dist/channels/slack/live-delivery.js +16 -4
  24. package/dist/channels/slack/manifest.d.ts.map +1 -1
  25. package/dist/channels/slack/manifest.js +1 -0
  26. package/dist/channels/slack/slack-channel.d.ts.map +1 -1
  27. package/dist/channels/slack/slack-channel.js +7 -4
  28. package/dist/channels/slack/types.d.ts +49 -1
  29. package/dist/channels/slack/types.d.ts.map +1 -1
  30. package/dist/docs/404.html +2 -2
  31. package/dist/docs/ab.html +6 -6
  32. package/dist/docs/assets/{ab.md.6cLOW7--.js → ab.md.hdxsvX5M.js} +2 -2
  33. package/dist/docs/assets/{app.BQ8Hihdf.js → app.mIw24pb1.js} +1 -1
  34. package/dist/docs/assets/{building-with-agents.md.txrcGU2B.js → building-with-agents.md.PeZaZA1P.js} +1 -1
  35. package/dist/docs/assets/chunks/@localSearchIndexroot.BA7V8dEJ.js +1 -0
  36. package/dist/docs/assets/chunks/{VPLocalSearchBox.BBCr8Yuy.js → VPLocalSearchBox.hOzpPwrG.js} +1 -1
  37. package/dist/docs/assets/chunks/{theme.CK_NiGC-.js → theme.BtFhUYmh.js} +2 -2
  38. package/dist/docs/assets/{deployment.md.CuK5SNjN.js → deployment.md.BHVjVqRa.js} +4 -4
  39. package/dist/docs/assets/{deployment.md.CuK5SNjN.lean.js → deployment.md.BHVjVqRa.lean.js} +1 -1
  40. package/dist/docs/assets/{evals.md.BQXI3rXy.js → evals.md.qeoGgPw0.js} +3 -3
  41. package/dist/docs/assets/example-agents_index.md.xmJ87d_3.js +2 -0
  42. package/dist/docs/assets/{guides_webhooks.md.BERuBSJW.js → guides_webhooks.md.DB-r_er9.js} +47 -4
  43. package/dist/docs/assets/{guides_webhooks.md.BERuBSJW.lean.js → guides_webhooks.md.DB-r_er9.lean.js} +1 -1
  44. package/dist/docs/assets/index.md.BKpbkCa6.js +24 -0
  45. package/dist/docs/assets/{index.md.CmhptOmN.lean.js → index.md.BKpbkCa6.lean.js} +1 -1
  46. package/dist/docs/assets/{quickstart.md.C_b6ESpD.js → quickstart.md.rIbfahJM.js} +4 -4
  47. package/dist/docs/assets/{reference_cli.md.Byvrg8eu.js → reference_cli.md.DqEqQpGn.js} +5 -5
  48. package/dist/docs/assets/{reference_cli.md.Byvrg8eu.lean.js → reference_cli.md.DqEqQpGn.lean.js} +1 -1
  49. package/dist/docs/assets/{reference_hooks.md.BGDw4VLm.js → reference_hooks.md.BHeG-vjK.js} +2 -2
  50. package/dist/docs/assets/{reference_hooks.md.BGDw4VLm.lean.js → reference_hooks.md.BHeG-vjK.lean.js} +1 -1
  51. package/dist/docs/assets/{storage.md.mQDtIULc.js → storage.md.DcGSnIxX.js} +10 -4
  52. package/dist/docs/assets/{storage.md.mQDtIULc.lean.js → storage.md.DcGSnIxX.lean.js} +1 -1
  53. package/dist/docs/assets/troubleshooting.md.CkgwmVI0.js +1 -0
  54. package/dist/docs/assets/{troubleshooting.md.B5RVX_tL.lean.js → troubleshooting.md.CkgwmVI0.lean.js} +1 -1
  55. package/dist/docs/building-with-agents.html +5 -5
  56. package/dist/docs/concepts.html +3 -3
  57. package/dist/docs/deployment.html +6 -6
  58. package/dist/docs/evals.html +7 -7
  59. package/dist/docs/example-agents/approval-buddy.html +3 -3
  60. package/dist/docs/example-agents/benny.html +3 -3
  61. package/dist/docs/example-agents/bugbot.html +3 -3
  62. package/dist/docs/example-agents/codebase-wiki.html +3 -3
  63. package/dist/docs/example-agents/codeowners-review.html +3 -3
  64. package/dist/docs/example-agents/concierge.html +3 -3
  65. package/dist/docs/example-agents/fsd.html +3 -3
  66. package/dist/docs/example-agents/index.html +5 -5
  67. package/dist/docs/example-agents/knowledge-base.html +3 -3
  68. package/dist/docs/example-agents/oncall.html +3 -3
  69. package/dist/docs/example-agents/security-reviewer.html +3 -3
  70. package/dist/docs/example-agents/slack-agent.html +3 -3
  71. package/dist/docs/example-agents/weather-agent.html +3 -3
  72. package/dist/docs/guides/agent-to-agent.html +3 -3
  73. package/dist/docs/guides/cloud-runtime.html +3 -3
  74. package/dist/docs/guides/github.html +3 -3
  75. package/dist/docs/guides/human-in-the-loop.html +3 -3
  76. package/dist/docs/guides/mcp-oauth.html +3 -3
  77. package/dist/docs/guides/slack.html +3 -3
  78. package/dist/docs/guides/webhooks.html +49 -6
  79. package/dist/docs/hashmap.json +1 -1
  80. package/dist/docs/hillclimbing.html +3 -3
  81. package/dist/docs/index.html +7 -7
  82. package/dist/docs/quickstart.html +8 -8
  83. package/dist/docs/reference/agent-config.html +3 -3
  84. package/dist/docs/reference/artifacts.html +3 -3
  85. package/dist/docs/reference/channels.html +3 -3
  86. package/dist/docs/reference/cli.html +8 -8
  87. package/dist/docs/reference/connections.html +3 -3
  88. package/dist/docs/reference/hooks.html +5 -5
  89. package/dist/docs/reference/http-api.html +3 -3
  90. package/dist/docs/reference/instructions.html +3 -3
  91. package/dist/docs/reference/playground.html +3 -3
  92. package/dist/docs/reference/project-layout.html +3 -3
  93. package/dist/docs/reference/prompt.html +3 -3
  94. package/dist/docs/reference/schedules.html +3 -3
  95. package/dist/docs/reference/sessions.html +3 -3
  96. package/dist/docs/reference/skills.html +3 -3
  97. package/dist/docs/reference/subagents.html +3 -3
  98. package/dist/docs/reference/tools.html +3 -3
  99. package/dist/docs/scaffolding-agents.html +3 -3
  100. package/dist/docs/storage.html +14 -8
  101. package/dist/docs/troubleshooting.html +5 -5
  102. package/dist/index.d.ts +4 -2
  103. package/dist/index.d.ts.map +1 -1
  104. package/dist/index.js +3 -1
  105. package/dist/internal/cli-ax.d.ts.map +1 -1
  106. package/dist/internal/cli-ax.js +22 -2
  107. package/dist/internal/cli-deploy.d.ts +6 -0
  108. package/dist/internal/cli-deploy.d.ts.map +1 -1
  109. package/dist/internal/cli-deploy.js +14 -4
  110. package/dist/internal/cli-mcp-oauth.d.ts.map +1 -1
  111. package/dist/internal/cli-mcp-oauth.js +3 -1
  112. package/dist/internal/cli-mcp.js +4 -4
  113. package/dist/internal/cursor-event-relay.d.ts +45 -0
  114. package/dist/internal/cursor-event-relay.d.ts.map +1 -1
  115. package/dist/internal/cursor-event-relay.js +96 -2
  116. package/dist/internal/deploy-client.js +1 -1
  117. package/dist/internal/discovery.d.ts.map +1 -1
  118. package/dist/internal/discovery.js +35 -7
  119. package/dist/internal/distribution.d.ts.map +1 -1
  120. package/dist/internal/distribution.js +3 -1
  121. package/dist/internal/durable-session-store.d.ts +48 -0
  122. package/dist/internal/durable-session-store.d.ts.map +1 -0
  123. package/dist/internal/durable-session-store.js +86 -0
  124. package/dist/internal/hosting.d.ts +1 -1
  125. package/dist/internal/hosting.js +2 -2
  126. package/dist/internal/init-project.d.ts +34 -0
  127. package/dist/internal/init-project.d.ts.map +1 -1
  128. package/dist/internal/init-project.js +121 -2
  129. package/dist/internal/ledger-serving.d.ts +101 -0
  130. package/dist/internal/ledger-serving.d.ts.map +1 -0
  131. package/dist/internal/ledger-serving.js +174 -0
  132. package/dist/internal/listen-port.d.ts +22 -0
  133. package/dist/internal/listen-port.d.ts.map +1 -0
  134. package/dist/internal/listen-port.js +77 -0
  135. package/dist/internal/mcp-oauth.d.ts +12 -1
  136. package/dist/internal/mcp-oauth.d.ts.map +1 -1
  137. package/dist/internal/mcp-oauth.js +25 -3
  138. package/dist/internal/playground/static.d.ts +21 -4
  139. package/dist/internal/playground/static.d.ts.map +1 -1
  140. package/dist/internal/playground/static.js +82 -18
  141. package/dist/internal/sdk-runner.d.ts.map +1 -1
  142. package/dist/internal/sdk-runner.js +10 -1
  143. package/dist/internal/server.d.ts.map +1 -1
  144. package/dist/internal/server.js +67 -49
  145. package/dist/internal/session-engine.d.ts +57 -1
  146. package/dist/internal/session-engine.d.ts.map +1 -1
  147. package/dist/internal/session-engine.js +117 -28
  148. package/dist/internal/slack-provision-client.js +1 -1
  149. package/dist/internal/workspace.d.ts +6 -2
  150. package/dist/internal/workspace.d.ts.map +1 -1
  151. package/dist/internal/workspace.js +10 -2
  152. package/dist/kv/memory-kv.d.ts +23 -0
  153. package/dist/kv/memory-kv.d.ts.map +1 -0
  154. package/dist/kv/memory-kv.js +103 -0
  155. package/dist/kv.d.ts +22 -0
  156. package/dist/kv.d.ts.map +1 -0
  157. package/dist/kv.js +20 -0
  158. package/dist/ledger/session-ledger.d.ts +204 -0
  159. package/dist/ledger/session-ledger.d.ts.map +1 -0
  160. package/dist/ledger/session-ledger.js +382 -0
  161. package/dist/ledger.d.ts +11 -0
  162. package/dist/ledger.d.ts.map +1 -0
  163. package/dist/ledger.js +9 -0
  164. package/dist/playground/assets/index-B3HBneZZ.js +85 -0
  165. package/dist/playground/assets/index-Bqk9nplh.css +1 -0
  166. package/dist/playground/index.html +2 -2
  167. package/dist/storage-backends/cursor-hosted.d.ts +25 -3
  168. package/dist/storage-backends/cursor-hosted.d.ts.map +1 -1
  169. package/dist/storage-backends/cursor-hosted.js +50 -2
  170. package/dist/storage-backends/file-kv.d.ts +5 -2
  171. package/dist/storage-backends/file-kv.d.ts.map +1 -1
  172. package/dist/storage-backends/file-kv.js +107 -7
  173. package/dist/storage.d.ts +60 -5
  174. package/dist/storage.d.ts.map +1 -1
  175. package/dist/storage.js +28 -4
  176. package/dist/types.d.ts +123 -3
  177. package/dist/types.d.ts.map +1 -1
  178. package/dist/types.js +14 -0
  179. package/docs/README.md +10 -7
  180. package/docs/ab.md +2 -2
  181. package/docs/building-with-agents.md +1 -1
  182. package/docs/deployment.md +34 -11
  183. package/docs/evals.md +3 -3
  184. package/docs/example-agents/index.md +1 -1
  185. package/docs/guides/webhooks.md +87 -0
  186. package/docs/quickstart.md +7 -8
  187. package/docs/reference/cli.md +15 -6
  188. package/docs/reference/hooks.md +8 -2
  189. package/docs/storage.md +67 -7
  190. package/docs/troubleshooting.md +10 -2
  191. package/package.json +20 -7
  192. package/skills/create-agent/SKILL.md +1 -1
  193. package/src/bin/agent-serve.ts +27 -11
  194. package/src/channels/slack/api.ts +19 -14
  195. package/src/channels/slack/attachments.ts +635 -0
  196. package/src/channels/slack/cursor-account.ts +8 -0
  197. package/src/channels/slack/defaults.ts +34 -18
  198. package/src/channels/slack/dispatch.ts +121 -6
  199. package/src/channels/slack/inbound.ts +60 -0
  200. package/src/channels/slack/index.ts +1 -0
  201. package/src/channels/slack/live-delivery.ts +17 -3
  202. package/src/channels/slack/manifest.ts +1 -0
  203. package/src/channels/slack/slack-channel.ts +7 -0
  204. package/src/channels/slack/types.ts +47 -1
  205. package/src/index.ts +9 -0
  206. package/src/internal/cli-ax.ts +25 -1
  207. package/src/internal/cli-deploy.ts +22 -4
  208. package/src/internal/cli-mcp-oauth.ts +3 -1
  209. package/src/internal/cli-mcp.ts +4 -4
  210. package/src/internal/cursor-event-relay.ts +168 -0
  211. package/src/internal/deploy-client.ts +1 -1
  212. package/src/internal/discovery.ts +42 -5
  213. package/src/internal/distribution.ts +3 -1
  214. package/src/internal/durable-session-store.ts +95 -0
  215. package/src/internal/hosting.ts +2 -2
  216. package/src/internal/init-project.ts +151 -2
  217. package/src/internal/ledger-serving.ts +240 -0
  218. package/src/internal/listen-port.ts +85 -0
  219. package/src/internal/mcp-oauth.ts +29 -4
  220. package/src/internal/playground/static.ts +111 -20
  221. package/src/internal/sdk-runner.ts +11 -1
  222. package/src/internal/server.ts +76 -62
  223. package/src/internal/session-engine.ts +192 -16
  224. package/src/internal/slack-provision-client.ts +1 -1
  225. package/src/internal/workspace.ts +14 -3
  226. package/src/kv/memory-kv.ts +99 -0
  227. package/src/kv.ts +27 -0
  228. package/src/ledger/session-ledger.ts +535 -0
  229. package/src/ledger.ts +29 -0
  230. package/src/storage-backends/cursor-hosted.ts +108 -3
  231. package/src/storage-backends/file-kv.ts +128 -12
  232. package/src/storage.ts +90 -6
  233. package/src/types.ts +130 -4
  234. package/dist/channels/slack/post-update-delivery.d.ts +0 -85
  235. package/dist/channels/slack/post-update-delivery.d.ts.map +0 -1
  236. package/dist/docs/assets/chunks/@localSearchIndexroot.B-VTH4As.js +0 -1
  237. package/dist/docs/assets/example-agents_index.md.DgGBwckv.js +0 -2
  238. package/dist/docs/assets/index.md.CmhptOmN.js +0 -24
  239. package/dist/docs/assets/troubleshooting.md.B5RVX_tL.js +0 -1
  240. package/dist/internal/json-dir-store.d.ts +0 -32
  241. package/dist/internal/json-dir-store.d.ts.map +0 -1
  242. package/dist/internal/persistence-coordinator.d.ts +0 -127
  243. package/dist/internal/persistence-coordinator.d.ts.map +0 -1
  244. package/dist/multi-tenant.d.ts +0 -80
  245. package/dist/multi-tenant.d.ts.map +0 -1
  246. package/dist/multi-tenant.js +0 -69
  247. package/dist/persistence.d.ts +0 -184
  248. package/dist/persistence.d.ts.map +0 -1
  249. package/dist/playground/assets/index-BRhBbnd4.css +0 -1
  250. package/dist/playground/assets/index-_2WKw9a-.js +0 -85
  251. package/dist/storage-backends/postgres-kv.d.ts +0 -82
  252. package/dist/storage-backends/postgres-kv.d.ts.map +0 -1
  253. package/dist/storage-backends/postgres-kv.js +0 -185
  254. package/src/storage-backends/postgres-kv.ts +0 -253
  255. /package/dist/docs/assets/{ab.md.6cLOW7--.lean.js → ab.md.hdxsvX5M.lean.js} +0 -0
  256. /package/dist/docs/assets/{building-with-agents.md.txrcGU2B.lean.js → building-with-agents.md.PeZaZA1P.lean.js} +0 -0
  257. /package/dist/docs/assets/{evals.md.BQXI3rXy.lean.js → evals.md.qeoGgPw0.lean.js} +0 -0
  258. /package/dist/docs/assets/{example-agents_index.md.DgGBwckv.lean.js → example-agents_index.md.xmJ87d_3.lean.js} +0 -0
  259. /package/dist/docs/assets/{quickstart.md.C_b6ESpD.lean.js → quickstart.md.rIbfahJM.lean.js} +0 -0
@@ -15,17 +15,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
15
15
  step((generator = generator.apply(thisArg, _arguments || [])).next());
16
16
  });
17
17
  };
18
- var __rest = (this && this.__rest) || function (s, e) {
19
- var t = {};
20
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
21
- t[p] = s[p];
22
- if (s != null && typeof Object.getOwnPropertySymbols === "function")
23
- for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
24
- if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
25
- t[p[i]] = s[p[i]];
26
- }
27
- return t;
28
- };
29
18
  import { mkdir, rm, writeFile } from "node:fs/promises";
30
19
  import { dirname, join } from "node:path";
31
20
  import { mergeABInstructions, resolveABMaxPlaygroundSessions, resolveABSplit, } from "../ab.js";
@@ -33,6 +22,8 @@ import { slackThreadPermalink } from "../channels/slack/links.js";
33
22
  import { SlackAskDedupeStore, SlackNudgeStore, } from "../channels/slack/nudge-store.js";
34
23
  import { resolveDedicatedSlackHostBinding } from "../channels/slack/slack-channel.js";
35
24
  import { isCursorHostedFilesAvailable } from "../files-backends/cursor-hosted.js";
25
+ import { SessionLedger, supportsSessionLedgerKv, } from "../ledger/session-ledger.js";
26
+ import { fileKv } from "../storage-backends/file-kv.js";
36
27
  import { DEFAULT_MODEL, DIRECT_TOOL_CALL_CHANNEL_ID, isHostOauthConnectionTransport, isSymbolicConnectionTransport, } from "../types.js";
37
28
  import { ABCollector } from "./ab-collector.js";
38
29
  import { foldABStream } from "./ab-fold.js";
@@ -43,6 +34,7 @@ import { samePrincipal } from "./auth.js";
43
34
  import { mergeCloudOptions, resolveSessionRuntime } from "./cloud-merge.js";
44
35
  import { applyCloudUsageToEvents, cloudSdkAgentIdFromEvents, isUnpricedCompletedTurn, mapSdkTokenUsage, } from "./cloud-turn-cost.js";
45
36
  import { isDevMode } from "./dev-mode.js";
37
+ import { ledgerKeyPrefix, namespacedKv, storageCasKv, } from "./durable-session-store.js";
46
38
  import { EventLogStore } from "./event-log.js";
47
39
  import { TurnEventMapper } from "./event-mapper.js";
48
40
  import { selectFrameworkStorageDefinition } from "./framework-storage-selection.js";
@@ -51,6 +43,7 @@ import { createHostKvApi } from "./host-kv.js";
51
43
  import { createHostPlatforms, createHostSlackClient, } from "./host-platforms.js";
52
44
  import { formatContinuationToken, newContinuationKey, newSessionId, newToolCallId, } from "./ids.js";
53
45
  import { validateToolInput } from "./json-schema.js";
46
+ import { LedgerServing, newLedgerPodId } from "./ledger-serving.js";
54
47
  import { McpHost } from "./mcp-host.js";
55
48
  import { buildSessionContextBlock, SCHEDULE_CHANNEL_PREFIX, } from "./prompt-context.js";
56
49
  import { assertCloudCanHonorAccountServersFilters } from "./resolved-connections.js";
@@ -211,6 +204,67 @@ export class SessionEngine {
211
204
  for (const channel of options.project.channels) {
212
205
  this.channelsById.set(channel.id, channel.definition);
213
206
  }
207
+ this.ledgerServing = this.buildLedgerServing(options);
208
+ }
209
+ /**
210
+ * Ledger-mode wiring (`serving: "ledger"`): resolve a CAS-capable
211
+ * durable-session store and build the delivery seam. Resident agents
212
+ * (the default) return undefined and never touch ledger keys.
213
+ */
214
+ buildLedgerServing(options) {
215
+ if (options.project.agent.serving !== "ledger") {
216
+ return undefined;
217
+ }
218
+ const ledgerKv = this.resolveDurableSessionStore(options);
219
+ return new LedgerServing({
220
+ ledger: new SessionLedger({ kv: ledgerKv, podId: newLedgerPodId() }),
221
+ deliverTurn: (request) => this.send(request.channelId, request.message, Object.assign(Object.assign({}, request.options), { continuationToken: request.continuationToken, ledgerDelivery: true })),
222
+ logger: this.logger,
223
+ });
224
+ }
225
+ /**
226
+ * Pick the KV the ledger coordinates on, in precedence order:
227
+ *
228
+ * 1. `options.durableSessionStore` — an explicit store separate from
229
+ * agent state (advanced deployments, tests).
230
+ * 2. The authored storage backend (`agent/storage.ts`) when it
231
+ * implements the `cas` group — one backend serves both the storage
232
+ * API and the durable session API.
233
+ * 3. No authored storage: a file store under `<stateRoot>/ledger-kv`
234
+ * (same place resident state lives; single-process only).
235
+ *
236
+ * An authored backend without `cas` fails fast: silently falling back
237
+ * to local files would fork coordination away from the deployment's
238
+ * durable store. The check demands exactly the methods the
239
+ * coordination-only ledger uses — `listKeys` is not one of them.
240
+ *
241
+ * Whatever store wins, the returned handle is scoped here — once —
242
+ * under `agentkit/v1/<agent>/durable-session/`. The ledger speaks bare
243
+ * `session/…` / `ledger/…` keys; namespacing is this boundary's job,
244
+ * exactly like `host.kv`'s agent scoping.
245
+ */
246
+ resolveDurableSessionStore(options) {
247
+ const namespace = ledgerKeyPrefix(options.project.name);
248
+ const explicit = options.durableSessionStore;
249
+ if (explicit !== undefined) {
250
+ if (!supportsSessionLedgerKv(explicit)) {
251
+ throw new Error(`Agent "${options.project.name}" declares serving: "ledger", but the configured durableSessionStore is not CAS-capable (getWithVersion / putIfAbsent / putIfVersion). Provide a store implementing those methods (see @cursor/july/kv).`);
252
+ }
253
+ return namespacedKv(explicit, namespace);
254
+ }
255
+ const casArgs = {
256
+ agentName: options.project.name,
257
+ projectRoot: options.project.rootDir,
258
+ };
259
+ const authored = options.project.storage;
260
+ if (authored !== undefined) {
261
+ if (authored.cas === undefined) {
262
+ throw new Error(`Agent "${options.project.name}" declares serving: "ledger", which needs conditional writes, but the storage backend in agent/storage.ts does not implement the cas group. Add cas: {...} to defineStorage (fileKv and cursorHostedStorage already include it), or pass an explicit durableSessionStore.`);
263
+ }
264
+ return namespacedKv(storageCasKv(authored, casArgs), namespace);
265
+ }
266
+ const fallback = fileKv({ dir: join(options.stateRoot, "ledger-kv") });
267
+ return namespacedKv(storageCasKv(fallback, casArgs), namespace);
214
268
  }
215
269
  /**
216
270
  * Attach serve-time resolved connections (peers, Cursor account bridge).
@@ -349,6 +403,12 @@ export class SessionEngine {
349
403
  return __awaiter(this, arguments, void 0, function* (channelId, message, options = {}) {
350
404
  var _a;
351
405
  var _b, _c, _d, _e, _f;
406
+ // Ledger-mode agents acquire the session lease before any turn runs;
407
+ // only the seam's own lease-holding deliveries fall through to the
408
+ // resident path.
409
+ if (this.ledgerServing !== undefined && options.ledgerDelivery !== true) {
410
+ return this.ledgerServing.deliver(channelId, message, options);
411
+ }
352
412
  const auth = (_b = options.auth) !== null && _b !== void 0 ? _b : null;
353
413
  let existing = options.continuationToken === undefined
354
414
  ? undefined
@@ -365,12 +425,14 @@ export class SessionEngine {
365
425
  // Refresh harness cwd when the caller supplies a newer worktree (e.g. PR
366
426
  // synchronize). Leave the durable continuation key unchanged.
367
427
  let record = existing;
368
- if (options.workspaceDir !== undefined &&
369
- options.workspaceDir !== existing.workspaceOverride) {
370
- record = yield this.updateRecord(existing.sessionId, (current) => { var _a; return (Object.assign(Object.assign({}, current), { workspaceOverride: options.workspaceDir, pendingWorkspaceFiles: (_a = options.workspaceFiles) !== null && _a !== void 0 ? _a : current.pendingWorkspaceFiles })); });
371
- }
372
- else if (options.workspaceFiles !== undefined) {
373
- record = yield this.updateRecord(existing.sessionId, (current) => (Object.assign(Object.assign({}, current), { pendingWorkspaceFiles: options.workspaceFiles })));
428
+ const refreshWorkspace = options.workspaceDir !== undefined &&
429
+ options.workspaceDir !== existing.workspaceOverride;
430
+ if (refreshWorkspace ||
431
+ options.workspaceFiles !== undefined ||
432
+ options.images !== undefined) {
433
+ record = yield this.updateRecord(existing.sessionId, (current) => (Object.assign(Object.assign({}, current), { workspaceOverride: refreshWorkspace
434
+ ? options.workspaceDir
435
+ : current.workspaceOverride, pendingWorkspaceFiles: mergePendingWorkspaceFiles(current.pendingWorkspaceFiles, options.workspaceFiles), pendingImages: mergePendingImages(current.pendingImages, options.images) })));
374
436
  }
375
437
  // Refresh the cloud attach the same way: a follow-up send carries the
376
438
  // caller's CURRENT cloud options (e.g. a PR attach re-derived per wake),
@@ -399,6 +461,7 @@ export class SessionEngine {
399
461
  channelState,
400
462
  workspaceOverride: options.workspaceDir,
401
463
  pendingWorkspaceFiles: options.workspaceFiles,
464
+ pendingImages: options.images,
402
465
  cloudOverride: options.cloud,
403
466
  sdkAgentId: options.sdkAgentId,
404
467
  turnCount: 0,
@@ -918,13 +981,19 @@ export class SessionEngine {
918
981
  stateRoot: this.stateRoot,
919
982
  });
920
983
  const pendingFiles = record.pendingWorkspaceFiles;
984
+ const pendingImages = record.pendingImages;
921
985
  if (pendingFiles !== undefined &&
922
986
  Object.keys(pendingFiles).length > 0) {
923
987
  yield writeWorkspaceFiles(harnessCwd, pendingFiles);
924
- yield this.updateRecord(sessionId, (current) => {
925
- const { pendingWorkspaceFiles: _cleared } = current, rest = __rest(current, ["pendingWorkspaceFiles"]);
926
- return rest;
927
- });
988
+ }
989
+ if ((pendingFiles !== undefined &&
990
+ Object.keys(pendingFiles).length > 0) ||
991
+ (pendingImages !== undefined && pendingImages.length > 0)) {
992
+ yield this.updateRecord(sessionId, (current) => (Object.assign(Object.assign({}, current), { pendingWorkspaceFiles: current.pendingWorkspaceFiles === pendingFiles
993
+ ? undefined
994
+ : current.pendingWorkspaceFiles, pendingImages: current.pendingImages === pendingImages
995
+ ? undefined
996
+ : current.pendingImages })));
928
997
  }
929
998
  // The harness only loads the scaffolded AGENTS.md when the session
930
999
  // workspace is its own project root. When the harness cwd is borrowed
@@ -945,7 +1014,7 @@ export class SessionEngine {
945
1014
  update.type === "tool-call-delta") {
946
1015
  yield yieldEventLoop();
947
1016
  }
948
- }), signal);
1017
+ }), signal, pendingImages);
949
1018
  this.activeToolContexts.set(sessionId, { record, turnId, emit });
950
1019
  try {
951
1020
  outcome = yield this.runner.runTurn(request);
@@ -1024,7 +1093,7 @@ export class SessionEngine {
1024
1093
  return Object.assign(Object.assign(Object.assign({}, outcome), (finalResult === undefined ? {} : { result: finalResult })), (finalUsage === undefined ? {} : { usage: finalUsage }));
1025
1094
  });
1026
1095
  }
1027
- buildTurnRequest(record, agent, turnId, prompt, isFirstTurn, instructionsInvisibleToHarness, emit, onUpdate, signal) {
1096
+ buildTurnRequest(record, agent, turnId, prompt, isFirstTurn, instructionsInvisibleToHarness, emit, onUpdate, signal, images) {
1028
1097
  var _a, _b, _c;
1029
1098
  // Per-session cloud attach (channel/tool handoff) forces cloud runtime
1030
1099
  // even when the agent defaults to local for chat server tools.
@@ -1078,9 +1147,9 @@ export class SessionEngine {
1078
1147
  turnPrompt = `${preamble}\n\n${turnPrompt}`;
1079
1148
  }
1080
1149
  }
1081
- return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ sessionId: record.sessionId }, (record.sdkAgentId === undefined
1150
+ return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ sessionId: record.sessionId }, (record.sdkAgentId === undefined
1082
1151
  ? {}
1083
- : { sdkAgentId: record.sdkAgentId })), { workspaceDir: this.harnessCwd(record), sandbox: ((_c = this.project.agent.local) === null || _c === void 0 ? void 0 : _c.sandbox) === true, runnerStateDir: join(this.stateRoot, "runner"), prompt: turnPrompt, isFirstTurn }), (agent.model === undefined ? {} : { model: agent.model })), { runtime }), (mergedCloud === undefined ? {} : { cloud: mergedCloud })), { customTools: runtime === "local" ? this.buildCustomTools(record, turnId, emit) : {}, mcpServers: this.buildMcpServers(runtime, record.sessionId), subagents: buildRunnerSubagents(agent), onUpdate,
1152
+ : { sdkAgentId: record.sdkAgentId })), { workspaceDir: this.harnessCwd(record), sandbox: ((_c = this.project.agent.local) === null || _c === void 0 ? void 0 : _c.sandbox) === true, runnerStateDir: join(this.stateRoot, "runner"), prompt: turnPrompt, isFirstTurn }), (images !== undefined && images.length > 0 ? { images } : {})), (agent.model === undefined ? {} : { model: agent.model })), { runtime }), (mergedCloud === undefined ? {} : { cloud: mergedCloud })), { customTools: runtime === "local" ? this.buildCustomTools(record, turnId, emit) : {}, mcpServers: this.buildMcpServers(runtime, record.sessionId), subagents: buildRunnerSubagents(agent), onUpdate,
1084
1153
  signal,
1085
1154
  // Local follow-ups expire any lingering active run so a preempted turn
1086
1155
  // (or one orphaned by a crashed process) never blocks this send.
@@ -2412,22 +2481,42 @@ export class SessionEngine {
2412
2481
  /** Drain running turns, dispatches, and pending writes, then dispose. */
2413
2482
  close() {
2414
2483
  return __awaiter(this, void 0, void 0, function* () {
2415
- var _a, _b, _c;
2484
+ var _a, _b, _c, _d;
2416
2485
  this.approvals.cancelAll("deny");
2486
+ // Ledger deliveries spawn turns, so settle them before activeTurns.
2487
+ yield (_a = this.ledgerServing) === null || _a === void 0 ? void 0 : _a.close();
2417
2488
  yield Promise.allSettled([...this.activeTurns.values()]);
2418
2489
  yield Promise.allSettled([...this.backgroundWork]);
2419
2490
  yield Promise.allSettled([...this.dispatchChains.values()]);
2420
2491
  yield Promise.allSettled([...this.updateChains.values()]);
2421
2492
  yield this.logs.flushAll();
2422
- yield (_a = this.storage) === null || _a === void 0 ? void 0 : _a.close();
2493
+ yield (_b = this.storage) === null || _b === void 0 ? void 0 : _b.close();
2423
2494
  yield this.mcpHost.close();
2424
- yield (_c = (_b = this.runner).dispose) === null || _c === void 0 ? void 0 : _c.call(_b);
2495
+ yield (_d = (_c = this.runner).dispose) === null || _d === void 0 ? void 0 : _d.call(_c);
2425
2496
  });
2426
2497
  }
2427
2498
  }
2428
2499
  /** Parallel event-stream loads during the startup bulk restore. */
2429
2500
  const RESTORE_FETCH_CONCURRENCY = 8;
2430
2501
  /** NDJSON payload for a restored event stream; undefined when empty. */
2502
+ function mergePendingImages(current, incoming) {
2503
+ if (incoming === undefined) {
2504
+ return current;
2505
+ }
2506
+ if (current === undefined || current.length === 0) {
2507
+ return incoming;
2508
+ }
2509
+ return [...current, ...incoming];
2510
+ }
2511
+ function mergePendingWorkspaceFiles(current, incoming) {
2512
+ if (incoming === undefined) {
2513
+ return current;
2514
+ }
2515
+ if (current === undefined) {
2516
+ return incoming;
2517
+ }
2518
+ return Object.assign(Object.assign({}, current), incoming);
2519
+ }
2431
2520
  function eventsNdjson(events) {
2432
2521
  if (events.length === 0) {
2433
2522
  return undefined;
@@ -250,7 +250,7 @@ function mapErrorResponse(response, bodyText, context) {
250
250
  case 401:
251
251
  return new SlackProvisionApiError("The Cursor API key was rejected. Run `agent-sdk login` again or update CURSOR_API_KEY.", { status: 401 });
252
252
  case 403:
253
- return new SlackProvisionApiError(`${serverError !== null && serverError !== void 0 ? serverError : "Not authorized"} — Slack provisioning needs team-admin permission and the cloud-agent entitlement on that team.`, { status: 403 });
253
+ return new SlackProvisionApiError(`${serverError !== null && serverError !== void 0 ? serverError : "Not authorized"} — Slack provisioning needs team membership and the cloud-agent entitlement on that team.`, { status: 403 });
254
254
  case 404: {
255
255
  // Fastify's route-not-found envelope means we hit the wrong host
256
256
  // (api2 vs api.cursor.com), not a closed gate.
@@ -108,7 +108,11 @@ export declare function materializeWorkspace(options: MaterializeWorkspaceOption
108
108
  export declare function buildSkillMd(skill: DiscoveredSkill): string;
109
109
  /**
110
110
  * Write relative path → contents under `workspaceDir`, refusing paths that
111
- * escape the directory.
111
+ * escape the directory. Values may be utf8 strings or base64 blob envelopes.
112
112
  */
113
- export declare function writeWorkspaceFiles(workspaceDir: string, files: Record<string, string>): Promise<void>;
113
+ export declare function writeWorkspaceFiles(workspaceDir: string, files: Record<string, string | {
114
+ encoding: "base64";
115
+ data: string;
116
+ mimeType?: string;
117
+ }>): Promise<void>;
114
118
  //# sourceMappingURL=workspace.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../../src/internal/workspace.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAgBH,OAAO,KAAK,EACV,eAAe,EACf,cAAc,EACd,aAAa,EACd,MAAM,aAAa,CAAC;AAIrB,MAAM,WAAW,2BAA2B;IAC1C,KAAK,EAAE,aAAa,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,IAAI,EAAE,OAAO,CAAC;IACd;;;;;;;OAOG;IACH,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAOjE;AAED,+EAA+E;AAC/E,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE5D;AAED;;;;;GAKG;AACH,eAAO,MAAM,4BAA4B,mBAAmB,CAAC;AAE7D;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAM1D;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,MAAM,GAAG,SAAS,GAC/B,MAAM,GAAG,SAAS,CAapB;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,cAAc,EAAE,EACvB,OAAO,GAAE;IAAE,cAAc,EAAE,OAAO,CAAA;CAA8B,GAC/D,MAAM,CA8CR;AAED;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,cAAc,EAAE,EACvB,OAAO,EAAE;IAAE,aAAa,EAAE,MAAM,CAAA;CAAE,GACjC,MAAM,CA6BR;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,aAAa,EACpB,OAAO,EAAE;IAAE,cAAc,EAAE,OAAO,CAAC;IAAC,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAAE,GAChE,MAAM,CAeR;AAED;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAcrE;AAED,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,2BAA2B,GACnC,OAAO,CAAC,IAAI,CAAC,CAkCf;AAqGD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,CAO3D;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC5B,OAAO,CAAC,IAAI,CAAC,CAMf"}
1
+ {"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../../src/internal/workspace.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAgBH,OAAO,KAAK,EACV,eAAe,EACf,cAAc,EACd,aAAa,EACd,MAAM,aAAa,CAAC;AAIrB,MAAM,WAAW,2BAA2B;IAC1C,KAAK,EAAE,aAAa,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,IAAI,EAAE,OAAO,CAAC;IACd;;;;;;;OAOG;IACH,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAOjE;AAED,+EAA+E;AAC/E,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE5D;AAED;;;;;GAKG;AACH,eAAO,MAAM,4BAA4B,mBAAmB,CAAC;AAE7D;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAM1D;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,MAAM,GAAG,SAAS,GAC/B,MAAM,GAAG,SAAS,CAapB;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,cAAc,EAAE,EACvB,OAAO,GAAE;IAAE,cAAc,EAAE,OAAO,CAAA;CAA8B,GAC/D,MAAM,CA8CR;AAED;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,cAAc,EAAE,EACvB,OAAO,EAAE;IAAE,aAAa,EAAE,MAAM,CAAA;CAAE,GACjC,MAAM,CA6BR;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,aAAa,EACpB,OAAO,EAAE;IAAE,cAAc,EAAE,OAAO,CAAC;IAAC,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAAE,GAChE,MAAM,CAeR;AAED;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAcrE;AAED,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,2BAA2B,GACnC,OAAO,CAAC,IAAI,CAAC,CAkCf;AAqGD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,CAO3D;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,MAAM,CACX,MAAM,EACN,MAAM,GAAG;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,CACjE,GACA,OAAO,CAAC,IAAI,CAAC,CAcf"}
@@ -352,14 +352,22 @@ export function buildSkillMd(skill) {
352
352
  }
353
353
  /**
354
354
  * Write relative path → contents under `workspaceDir`, refusing paths that
355
- * escape the directory.
355
+ * escape the directory. Values may be utf8 strings or base64 blob envelopes.
356
356
  */
357
357
  export function writeWorkspaceFiles(workspaceDir, files) {
358
358
  return __awaiter(this, void 0, void 0, function* () {
359
359
  for (const [relativePath, contents] of Object.entries(files)) {
360
360
  const target = resolveWorkspaceWritePath(workspaceDir, relativePath);
361
361
  yield mkdir(dirname(target), { recursive: true });
362
- yield writeFile(target, contents, "utf8");
362
+ if (typeof contents === "string") {
363
+ yield writeFile(target, contents, "utf8");
364
+ }
365
+ else if (contents.encoding === "base64") {
366
+ yield writeFile(target, Buffer.from(contents.data, "base64"));
367
+ }
368
+ else {
369
+ throw new Error(`Unsupported workspace file encoding for ${relativePath}`);
370
+ }
363
371
  }
364
372
  });
365
373
  }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * In-memory {@link HostKvCasApi} — the test/dev implementation of the
3
+ * interface module (`@cursor/july/kv`), exported at
4
+ * `@cursor/july/kv/memory`.
5
+ *
6
+ * The memory KV *is* the dev shim: tests and local runs exercise the
7
+ * same CAS coordination paths that hosted serving uses, not a mock of an
8
+ * RPC. Values are deep-copied on both write and
9
+ * read so callers can never observe (or cause) shared-reference mutation.
10
+ */
11
+ import type { StorageCasTable } from "../storage.js";
12
+ import type { HostKvCasApi } from "../types.js";
13
+ /** Create an empty in-memory CAS-capable KV. */
14
+ export declare function createMemoryKv(): HostKvCasApi;
15
+ /**
16
+ * In-memory `cas` group for `defineStorage` — a complete conditional-write
17
+ * group for sinks whose plain methods are inert or live elsewhere (test
18
+ * fixtures, an off-hosting no-op sink). Non-durable and process-local by
19
+ * construction; a real deployment backend should implement CAS against
20
+ * its own store instead.
21
+ */
22
+ export declare function memoryCasTable(): StorageCasTable;
23
+ //# sourceMappingURL=memory-kv.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory-kv.d.ts","sourceRoot":"","sources":["../../src/kv/memory-kv.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,KAAK,EACV,YAAY,EAIb,MAAM,aAAa,CAAC;AAErB,gDAAgD;AAChD,wBAAgB,cAAc,IAAI,YAAY,CA4D7C;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,IAAI,eAAe,CAShD"}
@@ -0,0 +1,103 @@
1
+ /**
2
+ * In-memory {@link HostKvCasApi} — the test/dev implementation of the
3
+ * interface module (`@cursor/july/kv`), exported at
4
+ * `@cursor/july/kv/memory`.
5
+ *
6
+ * The memory KV *is* the dev shim: tests and local runs exercise the
7
+ * same CAS coordination paths that hosted serving uses, not a mock of an
8
+ * RPC. Values are deep-copied on both write and
9
+ * read so callers can never observe (or cause) shared-reference mutation.
10
+ */
11
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
12
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
13
+ return new (P || (P = Promise))(function (resolve, reject) {
14
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
15
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
16
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
17
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
18
+ });
19
+ };
20
+ /** Create an empty in-memory CAS-capable KV. */
21
+ export function createMemoryKv() {
22
+ const entries = new Map();
23
+ let versionCounter = 0;
24
+ const nextVersion = () => {
25
+ versionCounter += 1;
26
+ return `v${versionCounter}`;
27
+ };
28
+ const snapshot = (key) => {
29
+ const entry = entries.get(key);
30
+ if (entry === undefined) {
31
+ return undefined;
32
+ }
33
+ return { value: structuredClone(entry.value), version: entry.version };
34
+ };
35
+ return {
36
+ get(key) {
37
+ return __awaiter(this, void 0, void 0, function* () {
38
+ var _a;
39
+ return (_a = snapshot(key)) === null || _a === void 0 ? void 0 : _a.value;
40
+ });
41
+ },
42
+ put(key, value) {
43
+ return __awaiter(this, void 0, void 0, function* () {
44
+ entries.set(key, {
45
+ value: structuredClone(value),
46
+ version: nextVersion(),
47
+ });
48
+ });
49
+ },
50
+ delete(key) {
51
+ return __awaiter(this, void 0, void 0, function* () {
52
+ entries.delete(key);
53
+ });
54
+ },
55
+ getWithVersion(key) {
56
+ return __awaiter(this, void 0, void 0, function* () {
57
+ return snapshot(key);
58
+ });
59
+ },
60
+ putIfAbsent(key, value) {
61
+ return __awaiter(this, void 0, void 0, function* () {
62
+ if (entries.has(key)) {
63
+ return { ok: false, current: snapshot(key) };
64
+ }
65
+ const version = nextVersion();
66
+ entries.set(key, { value: structuredClone(value), version });
67
+ return { ok: true, version };
68
+ });
69
+ },
70
+ putIfVersion(key, value, expectedVersion) {
71
+ return __awaiter(this, void 0, void 0, function* () {
72
+ const entry = entries.get(key);
73
+ if (entry === undefined || entry.version !== expectedVersion) {
74
+ return { ok: false, current: snapshot(key) };
75
+ }
76
+ const version = nextVersion();
77
+ entries.set(key, { value: structuredClone(value), version });
78
+ return { ok: true, version };
79
+ });
80
+ },
81
+ listKeys(prefix) {
82
+ return __awaiter(this, void 0, void 0, function* () {
83
+ return [...entries.keys()].filter((key) => key.startsWith(prefix)).sort();
84
+ });
85
+ },
86
+ };
87
+ }
88
+ /**
89
+ * In-memory `cas` group for `defineStorage` — a complete conditional-write
90
+ * group for sinks whose plain methods are inert or live elsewhere (test
91
+ * fixtures, an off-hosting no-op sink). Non-durable and process-local by
92
+ * construction; a real deployment backend should implement CAS against
93
+ * its own store instead.
94
+ */
95
+ export function memoryCasTable() {
96
+ const kv = createMemoryKv();
97
+ return {
98
+ getWithVersion: (key) => kv.getWithVersion(key),
99
+ putIfAbsent: (key, value) => kv.putIfAbsent(key, value),
100
+ putIfVersion: (key, value, expectedVersion) => kv.putIfVersion(key, value, expectedVersion),
101
+ listKeys: (prefix) => kv.listKeys(prefix),
102
+ };
103
+ }
package/dist/kv.d.ts ADDED
@@ -0,0 +1,22 @@
1
+ /**
2
+ * The CAS-capable KV **interface** — `@cursor/july/kv`.
3
+ *
4
+ * This module is implementation-free on purpose: it is the contract a
5
+ * bring-your-own KV implements so coordination protocols (conditional
6
+ * writes are the substrate for the upcoming session ledger) can run on
7
+ * it. {@link HostKvCasApi} is the conditional-write superset of the plain
8
+ * {@link HostKvApi}; {@link supportsKvCas} is the runtime probe for
9
+ * stores of unknown provenance — a `defineStorage` backend declares CAS
10
+ * through its `cas` group instead, so it never needs probing.
11
+ *
12
+ * Implementations live elsewhere:
13
+ *
14
+ * - `@cursor/july/kv/memory` — `createMemoryKv`, the test/dev shim.
15
+ * - The storage backends implement the same operations as the `cas`
16
+ * group on `defineStorage` (see `StorageCasTable` in
17
+ * `@cursor/july/storage`): `fileKv` (single-process) and
18
+ * `cursorHostedStorage` (control-plane proxy). See `docs/storage.md`.
19
+ */
20
+ export type { HostKvApi, HostKvCasApi, KvCasResult, KvVersionedEntry, } from "./types.js";
21
+ export { supportsKvCas } from "./types.js";
22
+ //# sourceMappingURL=kv.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kv.d.ts","sourceRoot":"","sources":["../src/kv.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,YAAY,EACV,SAAS,EACT,YAAY,EACZ,WAAW,EACX,gBAAgB,GACjB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC"}
package/dist/kv.js ADDED
@@ -0,0 +1,20 @@
1
+ /**
2
+ * The CAS-capable KV **interface** — `@cursor/july/kv`.
3
+ *
4
+ * This module is implementation-free on purpose: it is the contract a
5
+ * bring-your-own KV implements so coordination protocols (conditional
6
+ * writes are the substrate for the upcoming session ledger) can run on
7
+ * it. {@link HostKvCasApi} is the conditional-write superset of the plain
8
+ * {@link HostKvApi}; {@link supportsKvCas} is the runtime probe for
9
+ * stores of unknown provenance — a `defineStorage` backend declares CAS
10
+ * through its `cas` group instead, so it never needs probing.
11
+ *
12
+ * Implementations live elsewhere:
13
+ *
14
+ * - `@cursor/july/kv/memory` — `createMemoryKv`, the test/dev shim.
15
+ * - The storage backends implement the same operations as the `cas`
16
+ * group on `defineStorage` (see `StorageCasTable` in
17
+ * `@cursor/july/storage`): `fileKv` (single-process) and
18
+ * `cursorHostedStorage` (control-plane proxy). See `docs/storage.md`.
19
+ */
20
+ export { supportsKvCas } from "./types.js";