@cursor/july 0.1.114 → 0.2.1

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 (206) hide show
  1. package/dist/channels/slack/channel-watch.d.ts +19 -3
  2. package/dist/channels/slack/channel-watch.d.ts.map +1 -1
  3. package/dist/channels/slack/channel-watch.js +48 -9
  4. package/dist/channels/slack/inbound.d.ts +7 -0
  5. package/dist/channels/slack/inbound.d.ts.map +1 -1
  6. package/dist/channels/slack/inbound.js +23 -0
  7. package/dist/channels/slack/slack-channel.d.ts.map +1 -1
  8. package/dist/channels/slack/slack-channel.js +87 -8
  9. package/dist/channels/slack/types.d.ts +11 -12
  10. package/dist/channels/slack/types.d.ts.map +1 -1
  11. package/dist/docs/404.html +2 -2
  12. package/dist/docs/assets/{app.BqkJwOZ-.js → app.D23Y-7Tp.js} +4 -4
  13. package/dist/docs/assets/chunks/@localSearchIndexroot.CzCCM7N8.js +1 -0
  14. package/dist/docs/assets/chunks/{VPLocalSearchBox.BJAi2KiV.js → VPLocalSearchBox.CWBeTFRZ.js} +1 -1
  15. package/dist/docs/assets/chunks/{arc.BZpXTgvV.js → arc.DSF2O3pm.js} +1 -1
  16. package/dist/docs/assets/chunks/{architectureDiagram-Q4EWVU46.WYI-7F-Y.js → architectureDiagram-Q4EWVU46.J52Wzbkg.js} +1 -1
  17. package/dist/docs/assets/chunks/{baseUniq.CZaUPpg0.js → baseUniq.CQS3LPCt.js} +1 -1
  18. package/dist/docs/assets/chunks/{blockDiagram-DXYQGD6D.D6UES2pD.js → blockDiagram-DXYQGD6D.Dw339Gr5.js} +1 -1
  19. package/dist/docs/assets/chunks/{c4Diagram-AHTNJAMY.cwebIe4i.js → c4Diagram-AHTNJAMY.BUdtOaRZ.js} +1 -1
  20. package/dist/docs/assets/chunks/channel.Bfu4df88.js +1 -0
  21. package/dist/docs/assets/chunks/{chunk-4BX2VUAB.fVyFnjxg.js → chunk-4BX2VUAB.CuOrkEqk.js} +1 -1
  22. package/dist/docs/assets/chunks/{chunk-4TB4RGXK.BanufG1c.js → chunk-4TB4RGXK.BJNBcY7U.js} +1 -1
  23. package/dist/docs/assets/chunks/{chunk-55IACEB6.VaSMz5-2.js → chunk-55IACEB6.VJK5LAm_.js} +1 -1
  24. package/dist/docs/assets/chunks/{chunk-EDXVE4YY.CN2diZOM.js → chunk-EDXVE4YY.BYYLihvj.js} +1 -1
  25. package/dist/docs/assets/chunks/{chunk-FMBD7UC4.g4ivypu3.js → chunk-FMBD7UC4.CmoW8BXP.js} +1 -1
  26. package/dist/docs/assets/chunks/{chunk-OYMX7WX6.GZXKn9JJ.js → chunk-OYMX7WX6.DTGY4C-M.js} +1 -1
  27. package/dist/docs/assets/chunks/{chunk-QZHKN3VN.itXxJZCd.js → chunk-QZHKN3VN.Cg5n67vl.js} +1 -1
  28. package/dist/docs/assets/chunks/{chunk-YZCP3GAM.-rw2GfvX.js → chunk-YZCP3GAM.C3GR_ia5.js} +1 -1
  29. package/dist/docs/assets/chunks/classDiagram-6PBFFD2Q.DdfgtaWs.js +1 -0
  30. package/dist/docs/assets/chunks/classDiagram-v2-HSJHXN6E.DdfgtaWs.js +1 -0
  31. package/dist/docs/assets/chunks/clone.rkmfti6d.js +1 -0
  32. package/dist/docs/assets/chunks/{cose-bilkent-S5V4N54A.CmaI5br0.js → cose-bilkent-S5V4N54A.BTRG8N3b.js} +1 -1
  33. package/dist/docs/assets/chunks/{dagre-KV5264BT.4wY9S4Kt.js → dagre-KV5264BT.Bob_bp_p.js} +1 -1
  34. package/dist/docs/assets/chunks/{diagram-5BDNPKRD.Pc3c0u9W.js → diagram-5BDNPKRD.ggPcs9uO.js} +1 -1
  35. package/dist/docs/assets/chunks/{diagram-G4DWMVQ6.CYrWz-nj.js → diagram-G4DWMVQ6.BP0qyJkp.js} +1 -1
  36. package/dist/docs/assets/chunks/{diagram-MMDJMWI5.Bgj5hukb.js → diagram-MMDJMWI5.B0X24UKr.js} +1 -1
  37. package/dist/docs/assets/chunks/{diagram-TYMM5635.DGMEXalS.js → diagram-TYMM5635.B4rXHFVt.js} +1 -1
  38. package/dist/docs/assets/chunks/{erDiagram-SMLLAGMA.GepTV9Im.js → erDiagram-SMLLAGMA._55Rt9oX.js} +1 -1
  39. package/dist/docs/assets/chunks/{flowDiagram-DWJPFMVM.DVKywg3j.js → flowDiagram-DWJPFMVM.DGP4XvR5.js} +1 -1
  40. package/dist/docs/assets/chunks/{ganttDiagram-T4ZO3ILL.C7qt9Mlo.js → ganttDiagram-T4ZO3ILL.BtXtkL4E.js} +1 -1
  41. package/dist/docs/assets/chunks/{gitGraphDiagram-UUTBAWPF.U30_r82P.js → gitGraphDiagram-UUTBAWPF.B9cPWblK.js} +1 -1
  42. package/dist/docs/assets/chunks/{graph.CyyMyAWv.js → graph.D8HzNexS.js} +1 -1
  43. package/dist/docs/assets/chunks/{infoDiagram-42DDH7IO.Dn9ACW3y.js → infoDiagram-42DDH7IO.Bw7CQUpi.js} +1 -1
  44. package/dist/docs/assets/chunks/{ishikawaDiagram-UXIWVN3A.DlIdIGOA.js → ishikawaDiagram-UXIWVN3A.MwkzF6nQ.js} +1 -1
  45. package/dist/docs/assets/chunks/{journeyDiagram-VCZTEJTY.DZj4vy4E.js → journeyDiagram-VCZTEJTY.DIGFF-3C.js} +1 -1
  46. package/dist/docs/assets/chunks/{kanban-definition-6JOO6SKY.Dl63eMUV.js → kanban-definition-6JOO6SKY.DhYef2BN.js} +1 -1
  47. package/dist/docs/assets/chunks/{layout.BLHZLWPH.js → layout.C0XUxuPi.js} +1 -1
  48. package/dist/docs/assets/chunks/{linear.aXKGKaNw.js → linear.BwNPpZex.js} +1 -1
  49. package/dist/docs/assets/chunks/{min.zWnFcpcc.js → min.CwAQdL7z.js} +1 -1
  50. package/dist/docs/assets/chunks/{mindmap-definition-QFDTVHPH.Qs4MQBea.js → mindmap-definition-QFDTVHPH.pWsSVLsP.js} +1 -1
  51. package/dist/docs/assets/chunks/{pieDiagram-DEJITSTG.BmPHgsk7.js → pieDiagram-DEJITSTG.BDJ3FbBy.js} +1 -1
  52. package/dist/docs/assets/chunks/{quadrantDiagram-34T5L4WZ.D5MQ3gwA.js → quadrantDiagram-34T5L4WZ.Co80izyB.js} +1 -1
  53. package/dist/docs/assets/chunks/{requirementDiagram-MS252O5E.CkdUFrO7.js → requirementDiagram-MS252O5E.JveKw4yx.js} +1 -1
  54. package/dist/docs/assets/chunks/{sankeyDiagram-XADWPNL6.KZrljrAV.js → sankeyDiagram-XADWPNL6.B0A7adPi.js} +1 -1
  55. package/dist/docs/assets/chunks/{sequenceDiagram-FGHM5R23.XMoEW-Lx.js → sequenceDiagram-FGHM5R23.d6JZ5Hre.js} +1 -1
  56. package/dist/docs/assets/chunks/{stateDiagram-FHFEXIEX.BmTzePLj.js → stateDiagram-FHFEXIEX.DWnL0NQl.js} +1 -1
  57. package/dist/docs/assets/chunks/stateDiagram-v2-QKLJ7IA2.ZEetPk0E.js +1 -0
  58. package/dist/docs/assets/chunks/{theme.BfQzpxsg.js → theme.MJTLx0hh.js} +2 -2
  59. package/dist/docs/assets/chunks/{timeline-definition-GMOUNBTQ.Dug0oamp.js → timeline-definition-GMOUNBTQ.CFS7Ai4c.js} +1 -1
  60. package/dist/docs/assets/chunks/{vennDiagram-DHZGUBPP.BOTHrEFu.js → vennDiagram-DHZGUBPP.CwSlnjCf.js} +1 -1
  61. package/dist/docs/assets/chunks/wardley-RL74JXVD.3gurI8YA.js +162 -0
  62. package/dist/docs/assets/chunks/{wardleyDiagram-NUSXRM2D.CoXKdfi6.js → wardleyDiagram-NUSXRM2D.B_8mvtjh.js} +1 -1
  63. package/dist/docs/assets/chunks/{xychartDiagram-5P7HB3ND.DXoSCjAW.js → xychartDiagram-5P7HB3ND.DtjU5H85.js} +1 -1
  64. package/dist/docs/assets/{guides_slack.md.Bo96y42E.js → guides_slack.md.Bjw2r2gL.js} +5 -5
  65. package/dist/docs/assets/{guides_slack.md.Bo96y42E.lean.js → guides_slack.md.Bjw2r2gL.lean.js} +1 -1
  66. package/dist/docs/assets/reference_cli.md.BvnQM8wd.js +97 -0
  67. package/dist/docs/assets/reference_cli.md.BvnQM8wd.lean.js +1 -0
  68. package/dist/docs/building-with-agents.html +35 -35
  69. package/dist/docs/deployment.html +35 -35
  70. package/dist/docs/evals.html +35 -35
  71. package/dist/docs/guides/agent-to-agent.html +35 -35
  72. package/dist/docs/guides/bitbucket.html +35 -35
  73. package/dist/docs/guides/cloud-agents.html +35 -35
  74. package/dist/docs/guides/convert-automation.html +35 -35
  75. package/dist/docs/guides/github.html +35 -35
  76. package/dist/docs/guides/gitlab.html +35 -35
  77. package/dist/docs/guides/grokbot-agents.html +35 -35
  78. package/dist/docs/guides/hooks.html +35 -35
  79. package/dist/docs/guides/improve.html +35 -35
  80. package/dist/docs/guides/jev.html +35 -35
  81. package/dist/docs/guides/mcp-oauth.html +35 -35
  82. package/dist/docs/guides/opentelemetry.html +35 -35
  83. package/dist/docs/guides/slack.html +39 -39
  84. package/dist/docs/guides/slack.md +16 -1
  85. package/dist/docs/guides/webhooks.html +35 -35
  86. package/dist/docs/hashmap.json +1 -1
  87. package/dist/docs/hillclimbing.html +35 -35
  88. package/dist/docs/index.html +35 -35
  89. package/dist/docs/llms-full.txt +699 -752
  90. package/dist/docs/llms.txt +1 -1
  91. package/dist/docs/quickstart.html +35 -35
  92. package/dist/docs/reference/agent-config.html +35 -35
  93. package/dist/docs/reference/artifacts.html +35 -35
  94. package/dist/docs/reference/channels.html +35 -35
  95. package/dist/docs/reference/cli.html +127 -125
  96. package/dist/docs/reference/cli.md +685 -753
  97. package/dist/docs/reference/connections.html +35 -35
  98. package/dist/docs/reference/evals.html +35 -35
  99. package/dist/docs/reference/extensions.html +35 -35
  100. package/dist/docs/reference/hooks.html +35 -35
  101. package/dist/docs/reference/http-api.html +35 -35
  102. package/dist/docs/reference/instructions.html +35 -35
  103. package/dist/docs/reference/playground.html +35 -35
  104. package/dist/docs/reference/project-layout.html +35 -35
  105. package/dist/docs/reference/prompt.html +35 -35
  106. package/dist/docs/reference/schedules.html +35 -35
  107. package/dist/docs/reference/sessions.html +35 -35
  108. package/dist/docs/reference/skills.html +35 -35
  109. package/dist/docs/reference/subagents.html +35 -35
  110. package/dist/docs/reference/tools.html +35 -35
  111. package/dist/docs/templates/agentic-owners.html +35 -35
  112. package/dist/docs/templates/pr-autofixer.html +35 -35
  113. package/dist/docs/templates/security-reviewer.html +35 -35
  114. package/dist/docs/templates/thermo-quality-review.html +35 -35
  115. package/dist/docs/templates/thermo-review.html +35 -35
  116. package/dist/docs/templates/triage.html +35 -35
  117. package/dist/docs/troubleshooting.html +35 -35
  118. package/dist/files-backends/cursor-hosted.d.ts +11 -17
  119. package/dist/files-backends/cursor-hosted.d.ts.map +1 -1
  120. package/dist/files-backends/cursor-hosted.js +13 -41
  121. package/dist/index.d.ts +1 -1
  122. package/dist/index.d.ts.map +1 -1
  123. package/dist/internal/artifacts-store.d.ts +11 -0
  124. package/dist/internal/artifacts-store.d.ts.map +1 -1
  125. package/dist/internal/artifacts-store.js +113 -18
  126. package/dist/internal/cli-deploy.d.ts.map +1 -1
  127. package/dist/internal/cli-deploy.js +9 -1
  128. package/dist/internal/cursor/cursor-api-transport.d.ts +37 -0
  129. package/dist/internal/cursor/cursor-api-transport.d.ts.map +1 -0
  130. package/dist/internal/cursor/cursor-api-transport.js +44 -0
  131. package/dist/internal/cursor/hosted-store-secrets.d.ts +21 -0
  132. package/dist/internal/cursor/hosted-store-secrets.d.ts.map +1 -1
  133. package/dist/internal/cursor/hosted-store-secrets.js +26 -0
  134. package/dist/internal/cursor/store-api-client.d.ts +82 -0
  135. package/dist/internal/cursor/store-api-client.d.ts.map +1 -0
  136. package/dist/internal/cursor/store-api-client.js +227 -0
  137. package/dist/internal/deploy-client.d.ts +6 -0
  138. package/dist/internal/deploy-client.d.ts.map +1 -1
  139. package/dist/internal/deploy-client.js +3 -0
  140. package/dist/internal/deploy-manifest.d.ts +8 -0
  141. package/dist/internal/deploy-manifest.d.ts.map +1 -1
  142. package/dist/internal/deploy-manifest.js +7 -1
  143. package/dist/internal/discovery/agent-config.d.ts +3 -1
  144. package/dist/internal/discovery/agent-config.d.ts.map +1 -1
  145. package/dist/internal/discovery/agent-config.js +7 -4
  146. package/dist/internal/framework-storage-selection.d.ts +1 -1
  147. package/dist/internal/framework-storage-selection.d.ts.map +1 -1
  148. package/dist/internal/platform-timers.d.ts.map +1 -1
  149. package/dist/internal/platform-timers.js +20 -2
  150. package/dist/internal/reminder-runner.d.ts +79 -1
  151. package/dist/internal/reminder-runner.d.ts.map +1 -1
  152. package/dist/internal/reminder-runner.js +287 -46
  153. package/dist/internal/server.d.ts.map +1 -1
  154. package/dist/internal/server.js +7 -0
  155. package/dist/internal/session-engine.d.ts.map +1 -1
  156. package/dist/internal/session-engine.js +13 -15
  157. package/dist/internal/store-api-protocol.d.ts +134 -0
  158. package/dist/internal/store-api-protocol.d.ts.map +1 -0
  159. package/dist/internal/store-api-protocol.js +126 -0
  160. package/dist/memory.d.ts +49 -10
  161. package/dist/memory.d.ts.map +1 -1
  162. package/dist/memory.js +193 -50
  163. package/dist/playground/assets/{index-CrMWlgUU.js → index-Cs0MKsv4.js} +30 -30
  164. package/dist/playground/assets/index-DLwnR9ys.css +1 -0
  165. package/dist/playground/index.html +2 -2
  166. package/dist/reminders.d.ts +1 -1
  167. package/dist/reminders.d.ts.map +1 -1
  168. package/dist/types.d.ts +44 -10
  169. package/dist/types.d.ts.map +1 -1
  170. package/docs/guides/slack.md +16 -1
  171. package/docs/reference/cli.md +686 -754
  172. package/package.json +1 -1
  173. package/skills/setup-slack/SKILL.md +1 -1
  174. package/src/channels/slack/channel-watch.ts +57 -8
  175. package/src/channels/slack/inbound.ts +24 -0
  176. package/src/channels/slack/slack-channel.ts +127 -4
  177. package/src/channels/slack/types.ts +11 -12
  178. package/src/files-backends/cursor-hosted.ts +31 -68
  179. package/src/index.ts +1 -0
  180. package/src/internal/artifacts-store.ts +131 -25
  181. package/src/internal/cli-deploy.ts +12 -1
  182. package/src/internal/cursor/cursor-api-transport.ts +73 -0
  183. package/src/internal/cursor/hosted-store-secrets.ts +35 -0
  184. package/src/internal/cursor/store-api-client.ts +360 -0
  185. package/src/internal/deploy-client.ts +9 -0
  186. package/src/internal/deploy-manifest.ts +15 -0
  187. package/src/internal/discovery/agent-config.ts +8 -6
  188. package/src/internal/framework-storage-selection.ts +1 -1
  189. package/src/internal/platform-timers.ts +24 -2
  190. package/src/internal/reminder-runner.ts +454 -66
  191. package/src/internal/server.ts +8 -0
  192. package/src/internal/session-engine.ts +17 -22
  193. package/src/internal/store-api-protocol.ts +222 -0
  194. package/src/memory.ts +240 -59
  195. package/src/reminders.ts +1 -0
  196. package/src/types.ts +47 -10
  197. package/dist/docs/assets/chunks/@localSearchIndexroot.BnSgidYE.js +0 -1
  198. package/dist/docs/assets/chunks/channel.DdM5EfNW.js +0 -1
  199. package/dist/docs/assets/chunks/classDiagram-6PBFFD2Q.CjfGHeg2.js +0 -1
  200. package/dist/docs/assets/chunks/classDiagram-v2-HSJHXN6E.CjfGHeg2.js +0 -1
  201. package/dist/docs/assets/chunks/clone.wSOICb_f.js +0 -1
  202. package/dist/docs/assets/chunks/stateDiagram-v2-QKLJ7IA2.Cu5X28zZ.js +0 -1
  203. package/dist/docs/assets/chunks/wardley-RL74JXVD.DXy2i1LS.js +0 -162
  204. package/dist/docs/assets/reference_cli.md.DLWDz9ij.js +0 -95
  205. package/dist/docs/assets/reference_cli.md.DLWDz9ij.lean.js +0 -1
  206. package/dist/playground/assets/index-C61EWMBK.css +0 -1
@@ -0,0 +1,360 @@
1
+ /**
2
+ * The store API client: July's one gateway to the factory domain-call lane,
3
+ * `POST /internal/agentsdk/store/api/<call>`. This module owns the whole
4
+ * transport — base URL and deployment credential (the same resolution the
5
+ * files sink uses, via `cursor-api-transport.ts`), envelope encoding,
6
+ * response validation, typed error mapping, and the bounded backoff policy.
7
+ * Feature modules (`memory.ts`, later `session-run-log.ts`, …) call typed
8
+ * methods like {@link StoreApiClient.memoryAppend} and never hand-roll
9
+ * fetch; future domain calls (`sessionRun.report`, `startLog.flush`, …) are
10
+ * added here as new methods on this one client.
11
+ *
12
+ * The lane is selected per pod by the task-bound store protocol pin:
13
+ * {@link isStoreApiLaneEnabled} is true only under the exact
14
+ * `factory-api-v1` pin AND with a provisioned deployment store. The
15
+ * availability check is not redundant: the pin file is written by the hosted
16
+ * task bind, but a local-dev env var could name the pin without any store to
17
+ * serve reads — appending into the void. Both resolve lazily per call, so a
18
+ * pin bound after serve start takes effect without a restart.
19
+ */
20
+
21
+ import {
22
+ MEMORY_APPEND_MAX_RECORD_BYTES,
23
+ memoryAppendResponseSchema,
24
+ memoryReadResponseSchema,
25
+ STORE_API_MEMORY_APPEND_CALL,
26
+ STORE_API_MEMORY_READ_CALL,
27
+ STORE_API_PATH,
28
+ STORE_API_PROTOCOL_VERSION,
29
+ serializedRecordBytes,
30
+ } from "../store-api-protocol.js";
31
+ import {
32
+ type CursorApiTransportOptions,
33
+ resolveCursorApiBaseUrl,
34
+ resolveCursorApiFetch,
35
+ resolveCursorApiKey,
36
+ } from "./cursor-api-transport.js";
37
+ import {
38
+ resolveDeploymentStoreSourceIdSync,
39
+ resolveStoreProtocolSync,
40
+ storeProtocolEnablesStoreApi,
41
+ } from "./hosted-store-secrets.js";
42
+
43
+ export interface StoreApiClientOptions extends CursorApiTransportOptions {
44
+ /** Deployment store source id override (lane availability check). */
45
+ storeSourceId?: string;
46
+ /** Lazy store source id, preferred over {@link storeSourceId}. */
47
+ resolveStoreSourceId?: () => string | undefined;
48
+ /** Lazy store protocol pin (default: env, then the task-bound file). */
49
+ resolveStoreProtocol?: () => string | undefined;
50
+ /** Backoff sleep override (tests). */
51
+ sleep?: (ms: number) => Promise<void>;
52
+ /** Jitter source override (tests). Returns [0, 1). */
53
+ random?: () => number;
54
+ }
55
+
56
+ /**
57
+ * How one domain call failed, after the client's bounded retries:
58
+ *
59
+ * - `rejected` — the server (or the client's own pre-check) refused the
60
+ * payload with a typed 4xx. Deterministic; never retried.
61
+ * - `shed` — 429 from the per-deployment limiter or kill switch. Retried
62
+ * only within the small Retry-After bound below; retrying harder against
63
+ * a shed is exactly the stampede the domain lane exists to prevent.
64
+ * - `unavailable` — 5xx or a network failure, retried up to the attempt
65
+ * bound.
66
+ * - `bad_response` — a 2xx whose body failed the response schema; a
67
+ * contract break, not a transient, so never retried.
68
+ */
69
+ export type StoreApiFailureKind =
70
+ | "rejected"
71
+ | "shed"
72
+ | "unavailable"
73
+ | "bad_response";
74
+
75
+ export class StoreApiCallError extends Error {
76
+ constructor(
77
+ readonly kind: StoreApiFailureKind,
78
+ message: string,
79
+ readonly status?: number
80
+ ) {
81
+ super(message);
82
+ this.name = "StoreApiCallError";
83
+ }
84
+ }
85
+
86
+ /**
87
+ * Bounded backoff policy. Domain calls run at turn boundaries (a memory
88
+ * append after `turn.completed`), so the budget is a few short retries, not
89
+ * persistence: 3 attempts total and never more than 2s asleep between them.
90
+ * A 429 whose Retry-After exceeds the cap is a deliberate shed (a kill
91
+ * switch, a hard budget) — give up immediately instead of camping on it.
92
+ */
93
+ const STORE_API_MAX_ATTEMPTS = 3;
94
+ const STORE_API_MAX_BACKOFF_MS = 2_000;
95
+
96
+ /**
97
+ * Hard deadline per fetch (the envelope POSTs and the presigned journal
98
+ * GET). Without one, a stalled — not failed — connection rides undici's
99
+ * ~300 s inactivity timers, and hydration runs at the head of the session
100
+ * dispatch chain where a stall delays every queued handler. 15 s matches
101
+ * the server's own presigned-fetch deadline and is generous for a ≤5 MiB
102
+ * journal.
103
+ */
104
+ const STORE_API_FETCH_TIMEOUT_MS = 15_000;
105
+
106
+ function backoffMs(attempt: number, random: () => number): number {
107
+ return Math.min(
108
+ 200 * 2 ** attempt * (0.5 + random()),
109
+ STORE_API_MAX_BACKOFF_MS
110
+ );
111
+ }
112
+
113
+ /**
114
+ * Is the domain-call lane on for this pod? Exact pin match plus a
115
+ * provisioned deployment store; anything else keeps the client-side
116
+ * patterns, fail-safe in both directions like the flush pin itself.
117
+ */
118
+ export function isStoreApiLaneEnabled(
119
+ options: StoreApiClientOptions = {}
120
+ ): boolean {
121
+ const protocol =
122
+ options.resolveStoreProtocol?.() ?? resolveStoreProtocolSync();
123
+ if (!storeProtocolEnablesStoreApi(protocol)) {
124
+ return false;
125
+ }
126
+ const sourceId = (
127
+ options.resolveStoreSourceId?.() ??
128
+ options.storeSourceId ??
129
+ resolveDeploymentStoreSourceIdSync()
130
+ )?.trim();
131
+ return sourceId !== undefined && sourceId !== "";
132
+ }
133
+
134
+ export type StoreApiClient = {
135
+ /**
136
+ * One `memory.append` domain call: the server appends the record to a
137
+ * server-owned journal shard. Resolves on success; throws
138
+ * {@link StoreApiCallError} after the bounded retries. The caller owns the
139
+ * failure policy (memory drops the record — appending is advisory).
140
+ */
141
+ memoryAppend(payload: {
142
+ agent: string;
143
+ record: Record<string, unknown>;
144
+ }): Promise<void>;
145
+ /**
146
+ * One `memory.read` domain call plus the presigned byte fetch: the server
147
+ * flushes the agent's pending append buffer (best-effort) and presigns
148
+ * the canonical journal; this method then downloads it. Undefined while
149
+ * the agent has no journal. Throws {@link StoreApiCallError} after the
150
+ * bounded retries — the caller owns the failure policy (hydration keeps
151
+ * the existing mirror).
152
+ */
153
+ memoryReadContent(payload: {
154
+ agent: string;
155
+ }): Promise<Uint8Array | undefined>;
156
+ };
157
+
158
+ export function createStoreApiClient(
159
+ options: StoreApiClientOptions = {}
160
+ ): StoreApiClient {
161
+ const sleep =
162
+ options.sleep ??
163
+ ((ms: number) => new Promise<void>(resolve => setTimeout(resolve, ms)));
164
+ const random = options.random ?? Math.random;
165
+
166
+ /** One POST of a versioned envelope; returns the parsed 2xx body. */
167
+ const postOnce = async (
168
+ call: string,
169
+ envelope: Record<string, unknown>
170
+ ): Promise<Response> => {
171
+ const fetchImpl = resolveCursorApiFetch(options);
172
+ return await fetchImpl(
173
+ `${resolveCursorApiBaseUrl(options)}${STORE_API_PATH}/${call}`,
174
+ {
175
+ method: "POST",
176
+ headers: {
177
+ Authorization: `Bearer ${resolveCursorApiKey(options)}`,
178
+ "Content-Type": "application/json",
179
+ },
180
+ body: JSON.stringify(envelope),
181
+ signal: AbortSignal.timeout(STORE_API_FETCH_TIMEOUT_MS),
182
+ }
183
+ );
184
+ };
185
+
186
+ /** The response's `Retry-After` in ms, when present and numeric. */
187
+ const retryAfterDelayMs = (response: Response): number | undefined => {
188
+ const header = response.headers.get("retry-after")?.trim();
189
+ const seconds =
190
+ header === undefined || header === "" ? Number.NaN : Number(header);
191
+ return Number.isFinite(seconds) ? seconds * 1_000 : undefined;
192
+ };
193
+
194
+ const describeErrorBody = async (response: Response): Promise<string> => {
195
+ try {
196
+ const parsed = (await response.json()) as { error?: unknown };
197
+ if (typeof parsed?.error === "string") {
198
+ return parsed.error;
199
+ }
200
+ } catch {
201
+ // Non-JSON error body; the status is the message.
202
+ }
203
+ return `HTTP ${response.status}`;
204
+ };
205
+
206
+ const callApi = async (
207
+ call: string,
208
+ envelope: Record<string, unknown>
209
+ ): Promise<unknown> => {
210
+ let lastFailure: StoreApiCallError | undefined;
211
+ // A shed's Retry-After (when within the cap) overrides the next jittered
212
+ // backoff; cleared before every attempt.
213
+ let nextDelayMs: number | undefined;
214
+ for (let attempt = 0; attempt < STORE_API_MAX_ATTEMPTS; attempt += 1) {
215
+ if (attempt > 0) {
216
+ await sleep(nextDelayMs ?? backoffMs(attempt, random));
217
+ }
218
+ nextDelayMs = undefined;
219
+ let response: Response;
220
+ try {
221
+ response = await postOnce(call, envelope);
222
+ } catch (error) {
223
+ lastFailure = new StoreApiCallError(
224
+ "unavailable",
225
+ `store api ${call} transport failure: ${
226
+ error instanceof Error ? error.message : String(error)
227
+ }`
228
+ );
229
+ continue;
230
+ }
231
+ if (response.ok) {
232
+ try {
233
+ return (await response.json()) as unknown;
234
+ } catch {
235
+ throw new StoreApiCallError(
236
+ "bad_response",
237
+ `store api ${call} answered non-JSON (${response.status})`,
238
+ response.status
239
+ );
240
+ }
241
+ }
242
+ if (response.status === 429) {
243
+ const retryDelayMs = retryAfterDelayMs(response);
244
+ const shed = new StoreApiCallError(
245
+ "shed",
246
+ `store api ${call} shed: ${await describeErrorBody(response)}`,
247
+ response.status
248
+ );
249
+ if (
250
+ retryDelayMs !== undefined &&
251
+ retryDelayMs > STORE_API_MAX_BACKOFF_MS
252
+ ) {
253
+ // A long Retry-After is a kill switch or hard budget: obey it by
254
+ // giving up now, not by camping on the route.
255
+ throw shed;
256
+ }
257
+ nextDelayMs = retryDelayMs;
258
+ lastFailure = shed;
259
+ continue;
260
+ }
261
+ if (response.status >= 500) {
262
+ // A degraded 503 carries `Retry-After` too (the server's buffer-down
263
+ // answer). Honor it clamped to the backoff cap — unlike a shed, a
264
+ // 5xx is transient by definition, so a long hint never means "give
265
+ // up", just "wait the cap".
266
+ const retryDelayMs = retryAfterDelayMs(response);
267
+ if (retryDelayMs !== undefined) {
268
+ nextDelayMs = Math.min(retryDelayMs, STORE_API_MAX_BACKOFF_MS);
269
+ }
270
+ lastFailure = new StoreApiCallError(
271
+ "unavailable",
272
+ `store api ${call} failed: ${await describeErrorBody(response)}`,
273
+ response.status
274
+ );
275
+ continue;
276
+ }
277
+ // Any other 4xx is deterministic; retrying re-sends the same refusal.
278
+ throw new StoreApiCallError(
279
+ "rejected",
280
+ `store api ${call} rejected: ${await describeErrorBody(response)}`,
281
+ response.status
282
+ );
283
+ }
284
+ throw lastFailure ?? new StoreApiCallError("unavailable", "no attempt ran");
285
+ };
286
+
287
+ return {
288
+ async memoryAppend(payload) {
289
+ const recordBytes = serializedRecordBytes(payload.record);
290
+ if (recordBytes > MEMORY_APPEND_MAX_RECORD_BYTES) {
291
+ // The server-side controller enforces the same cap; checking here
292
+ // spares a doomed request and fails with the same typed shape.
293
+ throw new StoreApiCallError(
294
+ "rejected",
295
+ `memory.append record is ${recordBytes} serialized bytes; the cap is ${MEMORY_APPEND_MAX_RECORD_BYTES}`
296
+ );
297
+ }
298
+ const body = await callApi(STORE_API_MEMORY_APPEND_CALL, {
299
+ v: STORE_API_PROTOCOL_VERSION,
300
+ call: STORE_API_MEMORY_APPEND_CALL,
301
+ payload,
302
+ });
303
+ if (!memoryAppendResponseSchema.safeParse(body).success) {
304
+ throw new StoreApiCallError(
305
+ "bad_response",
306
+ "unexpected memory.append response shape"
307
+ );
308
+ }
309
+ },
310
+
311
+ async memoryReadContent(payload) {
312
+ const body = await callApi(STORE_API_MEMORY_READ_CALL, {
313
+ v: STORE_API_PROTOCOL_VERSION,
314
+ call: STORE_API_MEMORY_READ_CALL,
315
+ payload,
316
+ });
317
+ const parsed = memoryReadResponseSchema.safeParse(body);
318
+ if (!parsed.success) {
319
+ throw new StoreApiCallError(
320
+ "bad_response",
321
+ "unexpected memory.read response shape"
322
+ );
323
+ }
324
+ if (parsed.data.journal === null) {
325
+ return undefined;
326
+ }
327
+ // Bulk bytes ride the presigned URL, never the control plane — same
328
+ // split as the verb lane. Unretried: the whole call reruns at the
329
+ // next session start, and hydration keeps the existing mirror.
330
+ const fetchImpl = resolveCursorApiFetch(options);
331
+ let response: Response;
332
+ try {
333
+ response = await fetchImpl(parsed.data.journal.url, {
334
+ method: "GET",
335
+ redirect: "manual",
336
+ signal: AbortSignal.timeout(STORE_API_FETCH_TIMEOUT_MS),
337
+ });
338
+ } catch (error) {
339
+ throw new StoreApiCallError(
340
+ "unavailable",
341
+ `memory.read journal fetch transport failure: ${
342
+ error instanceof Error ? error.message : String(error)
343
+ }`
344
+ );
345
+ }
346
+ if (response.status === 404) {
347
+ // The presign raced a rotation or delete; absent is absent.
348
+ return undefined;
349
+ }
350
+ if (!response.ok) {
351
+ throw new StoreApiCallError(
352
+ "unavailable",
353
+ `memory.read journal fetch failed (HTTP ${response.status})`,
354
+ response.status
355
+ );
356
+ }
357
+ return new Uint8Array(await response.arrayBuffer());
358
+ },
359
+ };
360
+ }
@@ -295,6 +295,12 @@ export interface AgentkitStopAccepted {
295
295
  applicationId: string;
296
296
  releaseId: string;
297
297
  status: string;
298
+ /**
299
+ * `"global"` when the backend escalated the stop to the application-level
300
+ * suspension — the default for a multi-tenant app stopped by its
301
+ * publisher. Resume needs `start <slug> --global`.
302
+ */
303
+ scope?: "global";
298
304
  cancellation?: AgentkitCancelRunsResult;
299
305
  }
300
306
 
@@ -471,6 +477,9 @@ const agentkitStopAcceptedSchema = z
471
477
  applicationId: z.string().min(1),
472
478
  releaseId: z.string().min(1),
473
479
  status: z.string(),
480
+ // Tolerate scope values a newer backend may add: parse only "global",
481
+ // drop anything else rather than failing the stop response.
482
+ scope: z.literal("global").optional().catch(undefined),
474
483
  cancellation: agentkitCancelRunsResultSchema.optional(),
475
484
  })
476
485
  .passthrough();
@@ -128,6 +128,10 @@ const agentDeployManifestV1Schema = z.object({
128
128
  continuation: continuationIdentitySchema,
129
129
  catch: catchDeclarationSchema.optional(),
130
130
  slackReply: slackReplyDeclarationSchema.optional(),
131
+ slackChannelPosts: z
132
+ .array(z.string().min(1).max(80))
133
+ .max(64)
134
+ .optional(),
131
135
  })
132
136
  )
133
137
  .max(64),
@@ -166,6 +170,14 @@ export interface AgentDeployManifestDeclarations {
166
170
  * hosted runtime starts. Present only for `slack` channels in agentic mode.
167
171
  */
168
172
  slackReply?: AgentDeployManifestSlackReplyDeclaration;
173
+ /**
174
+ * The channel-watch allowlist (`engagement.channelPosts.allow`).
175
+ * Present only for `slack` channels that watch channel posts. The
176
+ * control plane materializes channel-scoped subscription edges from
177
+ * the channel-id entries so posts outside the allowlist drop at
178
+ * ingress.
179
+ */
180
+ slackChannelPosts?: string[];
169
181
  /**
170
182
  * Control-plane catch routes: present only for an authored channel
171
183
  * whose auth chain carries a `sharedSecretAuth` / `hmacSignatureAuth`
@@ -242,6 +254,9 @@ export function buildAgentDeployManifest(
242
254
  ...(kind === "slack" && meta?.slackReply !== undefined
243
255
  ? { slackReply: meta.slackReply }
244
256
  : {}),
257
+ ...(kind === "slack" && meta?.slackChannelPosts !== undefined
258
+ ? { slackChannelPosts: [...meta.slackChannelPosts] }
259
+ : {}),
245
260
  };
246
261
  });
247
262
 
@@ -33,16 +33,18 @@ export function runtimeArchitectureCompatibilityError(agent: {
33
33
  : undefined;
34
34
  }
35
35
 
36
+ /** Author-facing default when {@link AgentConfig.architecture} is omitted. */
37
+ export const DEFAULT_AGENT_ARCHITECTURE: AgentArchitecture = "v2";
38
+
36
39
  export function resolveArchitecture(
37
40
  ctx: DiscoveryContext,
38
41
  agentDir: string,
39
42
  architecture: AgentArchitecture | undefined
40
43
  ): AgentArchitecture | undefined {
41
- if (
42
- architecture === undefined ||
43
- architecture === "v1" ||
44
- architecture === "v2"
45
- ) {
44
+ if (architecture === undefined) {
45
+ return DEFAULT_AGENT_ARCHITECTURE;
46
+ }
47
+ if (architecture === "v1" || architecture === "v2") {
46
48
  return architecture;
47
49
  }
48
50
  ctx.diagnostics.push({
@@ -55,7 +57,7 @@ export function resolveArchitecture(
55
57
 
56
58
  /**
57
59
  * `persistent: true` selects the long-lived-pod hosting mode of v2. It has
58
- * no meaning on v1 (resident engine) or when the architecture is unset.
60
+ * no meaning on v1 (resident engine).
59
61
  */
60
62
  export function resolvePersistent(
61
63
  ctx: DiscoveryContext,
@@ -66,7 +66,7 @@ import { resolveAgentV2Hosting } from "./v2-hosting.js";
66
66
  export interface FrameworkStorageSelectionInput {
67
67
  /** `agent/storage.ts`, when the author wrote one (v1 only: discovery rejects it on v2). */
68
68
  readonly authored: StorageDefinition | undefined;
69
- /** {@link AgentConfig.architecture}; omitted means v1. */
69
+ /** {@link AgentConfig.architecture}; discovery fills `"v2"` when omitted. */
70
70
  readonly architecture?: AgentArchitecture | undefined;
71
71
  /** Environment override for tests; defaults to `process.env`. */
72
72
  readonly env?: Record<string, string | undefined>;
@@ -236,6 +236,28 @@ async function timedWorkJsonFetch(
236
236
  });
237
237
  }
238
238
 
239
+ const CP_ERROR_BODY_LIMIT = 512;
240
+
241
+ /**
242
+ * Read failures carry status and a bounded body: the guest logs them once
243
+ * per process, and a 405 body names the route the caller should be on.
244
+ */
245
+ async function reminderCpReadError(
246
+ what: string,
247
+ response: Response
248
+ ): Promise<Error> {
249
+ let body = "";
250
+ try {
251
+ body = (await response.text()).trim();
252
+ } catch {
253
+ // Status-only detail.
254
+ }
255
+ const detail = body === "" ? "" : ` ${body.slice(0, CP_ERROR_BODY_LIMIT)}`;
256
+ return new Error(
257
+ `reminder CP ${what} failed: HTTP ${response.status}${detail}`
258
+ );
259
+ }
260
+
239
261
  /**
240
262
  * Cursor-hosted HTTP ReminderControlPlane for architecture v2.
241
263
  * Speaks factory `/internal/agentsdk/reminders` (ELB → factory ECS).
@@ -275,7 +297,7 @@ export function createCursorHostedReminderControlPlane(
275
297
  return undefined;
276
298
  }
277
299
  if (!response.ok) {
278
- throw new Error(`reminder CP get failed: HTTP ${response.status}`);
300
+ throw await reminderCpReadError("get", response);
279
301
  }
280
302
  const parsed: unknown = await response.json();
281
303
  return isReminderRecord(parsed) ? parsed : undefined;
@@ -287,7 +309,7 @@ export function createCursorHostedReminderControlPlane(
287
309
  `${AGENTSDK_REMINDERS_PREFIX}/reminders`
288
310
  );
289
311
  if (!response.ok) {
290
- throw new Error(`reminder CP list failed: HTTP ${response.status}`);
312
+ throw await reminderCpReadError("list", response);
291
313
  }
292
314
  const parsed: unknown = await response.json();
293
315
  if (