@cursor/july 0.1.105 → 0.1.107

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 (217) hide show
  1. package/dist/bin/agent-serve.js +1 -8
  2. package/dist/channels/bitbucket/types.d.ts +2 -4
  3. package/dist/channels/bitbucket/types.d.ts.map +1 -1
  4. package/dist/channels/deployments/types.d.ts +5 -8
  5. package/dist/channels/deployments/types.d.ts.map +1 -1
  6. package/dist/channels/github/types.d.ts +2 -4
  7. package/dist/channels/github/types.d.ts.map +1 -1
  8. package/dist/channels/gitlab/types.d.ts +2 -5
  9. package/dist/channels/gitlab/types.d.ts.map +1 -1
  10. package/dist/channels/origin/types.d.ts +2 -3
  11. package/dist/channels/origin/types.d.ts.map +1 -1
  12. package/dist/channels/slack/defaults.d.ts.map +1 -1
  13. package/dist/channels/slack/defaults.js +3 -0
  14. package/dist/channels/slack/dispatch.d.ts.map +1 -1
  15. package/dist/channels/slack/dispatch.js +1 -1
  16. package/dist/channels/slack/live-delivery.d.ts.map +1 -1
  17. package/dist/channels/slack/live-delivery.js +48 -11
  18. package/dist/channels/slack/types.d.ts +4 -3
  19. package/dist/channels/slack/types.d.ts.map +1 -1
  20. package/dist/docs/404.html +3 -3
  21. package/dist/docs/ab.html +6 -6
  22. package/dist/docs/assets/{app.BVwaffdK.js → app.CtuckIiL.js} +1 -1
  23. package/dist/docs/assets/chunks/@localSearchIndexroot.DXXZxiMv.js +1 -0
  24. package/dist/docs/assets/chunks/{VPLocalSearchBox.WuWTZ1x8.js → VPLocalSearchBox.Bkkhnu8K.js} +2 -2
  25. package/dist/docs/assets/chunks/{theme.BYdI_6sF.js → theme.DhpIe0Pa.js} +2 -2
  26. package/dist/docs/assets/{guides_opentelemetry.md.COh9jFVg.js → guides_opentelemetry.md.SCRMskno.js} +3 -3
  27. package/dist/docs/assets/{guides_opentelemetry.md.COh9jFVg.lean.js → guides_opentelemetry.md.SCRMskno.lean.js} +1 -1
  28. package/dist/docs/assets/{reference_channels.md.DBGcaB7m.js → reference_channels.md.D-qTqwcq.js} +2 -2
  29. package/dist/docs/assets/{reference_channels.md.DBGcaB7m.lean.js → reference_channels.md.D-qTqwcq.lean.js} +1 -1
  30. package/dist/docs/assets/{reference_cli.md.C6Lo8SEd.js → reference_cli.md.Dm67hd2D.js} +1 -1
  31. package/dist/docs/assets/{skills_otel.md.CqhobH3B.js → skills_otel.md.B5Ddv1xH.js} +1 -1
  32. package/dist/docs/assets/{style.BRuM8477.css → style.DCD_zyg3.css} +1 -1
  33. package/dist/docs/building-with-agents.html +6 -6
  34. package/dist/docs/concepts.html +5 -5
  35. package/dist/docs/deployment.html +6 -6
  36. package/dist/docs/evals.html +6 -6
  37. package/dist/docs/guides/agent-to-agent.html +6 -6
  38. package/dist/docs/guides/cloud-agents.html +6 -6
  39. package/dist/docs/guides/convert-automation.html +6 -6
  40. package/dist/docs/guides/github.html +6 -6
  41. package/dist/docs/guides/grokbot-agents.html +6 -6
  42. package/dist/docs/guides/human-in-the-loop.html +6 -6
  43. package/dist/docs/guides/mcp-oauth.html +6 -6
  44. package/dist/docs/guides/opentelemetry.html +8 -8
  45. package/dist/docs/guides/opentelemetry.md +3 -4
  46. package/dist/docs/guides/slack.html +6 -6
  47. package/dist/docs/guides/webhooks.html +6 -6
  48. package/dist/docs/hashmap.json +1 -1
  49. package/dist/docs/hillclimbing.html +6 -6
  50. package/dist/docs/index.html +6 -6
  51. package/dist/docs/llms-full.txt +22 -28
  52. package/dist/docs/quickstart.html +6 -6
  53. package/dist/docs/reference/agent-config.html +6 -6
  54. package/dist/docs/reference/artifacts.html +6 -6
  55. package/dist/docs/reference/channels.html +7 -7
  56. package/dist/docs/reference/channels.md +11 -19
  57. package/dist/docs/reference/cli.html +8 -8
  58. package/dist/docs/reference/cli.md +5 -2
  59. package/dist/docs/reference/connections.html +6 -6
  60. package/dist/docs/reference/extensions.html +6 -6
  61. package/dist/docs/reference/hooks.html +6 -6
  62. package/dist/docs/reference/http-api.html +6 -6
  63. package/dist/docs/reference/instructions.html +6 -6
  64. package/dist/docs/reference/playground.html +5 -5
  65. package/dist/docs/reference/project-layout.html +6 -6
  66. package/dist/docs/reference/prompt.html +6 -6
  67. package/dist/docs/reference/result.html +6 -6
  68. package/dist/docs/reference/schedules.html +6 -6
  69. package/dist/docs/reference/sessions.html +5 -5
  70. package/dist/docs/reference/skills.html +6 -6
  71. package/dist/docs/reference/subagents.html +6 -6
  72. package/dist/docs/reference/tools.html +6 -6
  73. package/dist/docs/scaffolding-agents.html +5 -5
  74. package/dist/docs/skills/ab.html +6 -6
  75. package/dist/docs/skills/create-agent.html +6 -6
  76. package/dist/docs/skills/debug.html +5 -5
  77. package/dist/docs/skills/evals.html +6 -6
  78. package/dist/docs/skills/framework-map.html +5 -5
  79. package/dist/docs/skills/github.html +6 -6
  80. package/dist/docs/skills/hillclimb.html +6 -6
  81. package/dist/docs/skills/index.html +5 -5
  82. package/dist/docs/skills/mcp-auth.html +6 -6
  83. package/dist/docs/skills/otel.html +8 -8
  84. package/dist/docs/skills/otel.md +3 -3
  85. package/dist/docs/skills/setup-slack.html +6 -6
  86. package/dist/docs/storage.html +6 -6
  87. package/dist/docs/templates/agentic-owners.html +6 -6
  88. package/dist/docs/templates/agents-md.html +6 -6
  89. package/dist/docs/templates/code-wiki.html +6 -6
  90. package/dist/docs/templates/demo.html +6 -6
  91. package/dist/docs/templates/grokbot-agents.html +6 -6
  92. package/dist/docs/templates/pr-autofixer.html +6 -6
  93. package/dist/docs/templates/security-help.html +6 -6
  94. package/dist/docs/templates/security-reviewer.html +6 -6
  95. package/dist/docs/templates/triage.html +6 -6
  96. package/dist/docs/troubleshooting.html +5 -5
  97. package/dist/index.d.ts +4 -5
  98. package/dist/index.d.ts.map +1 -1
  99. package/dist/index.js +3 -4
  100. package/dist/internal/cli-deploy.d.ts.map +1 -1
  101. package/dist/internal/cli-deploy.js +23 -11
  102. package/dist/internal/cursor/backend-client.d.ts +25 -0
  103. package/dist/internal/cursor/backend-client.d.ts.map +1 -1
  104. package/dist/internal/cursor/backend-client.js +57 -2
  105. package/dist/internal/deploy-client.d.ts +8 -0
  106. package/dist/internal/deploy-client.d.ts.map +1 -1
  107. package/dist/internal/deploy-client.js +14 -0
  108. package/dist/internal/deploy-manifest.d.ts +3 -0
  109. package/dist/internal/deploy-manifest.d.ts.map +1 -1
  110. package/dist/internal/deploy-manifest.js +15 -12
  111. package/dist/internal/discovery/agent.d.ts.map +1 -1
  112. package/dist/internal/discovery/agent.js +1 -0
  113. package/dist/internal/discovery/info.d.ts.map +1 -1
  114. package/dist/internal/discovery/info.js +7 -3
  115. package/dist/internal/discovery/modules.d.ts +1 -1
  116. package/dist/internal/discovery/modules.d.ts.map +1 -1
  117. package/dist/internal/discovery/modules.js +1 -0
  118. package/dist/internal/discovery/project.d.ts.map +1 -1
  119. package/dist/internal/discovery/project.js +3 -0
  120. package/dist/internal/discovery/reminders.d.ts +7 -0
  121. package/dist/internal/discovery/reminders.d.ts.map +1 -0
  122. package/dist/internal/discovery/reminders.js +65 -0
  123. package/dist/internal/discovery/subagent.js +1 -0
  124. package/dist/internal/distribution.d.ts +5 -0
  125. package/dist/internal/distribution.d.ts.map +1 -1
  126. package/dist/internal/distribution.js +17 -0
  127. package/dist/internal/framework-storage-selection.d.ts +14 -3
  128. package/dist/internal/framework-storage-selection.d.ts.map +1 -1
  129. package/dist/internal/framework-storage-selection.js +36 -6
  130. package/dist/internal/guest-network.d.ts.map +1 -1
  131. package/dist/internal/guest-network.js +2 -0
  132. package/dist/internal/hosted-delivery-protocol.d.ts +48 -0
  133. package/dist/internal/hosted-delivery-protocol.d.ts.map +1 -1
  134. package/dist/internal/hosted-delivery-protocol.js +60 -0
  135. package/dist/internal/hosted-delivery.d.ts +10 -0
  136. package/dist/internal/hosted-delivery.d.ts.map +1 -1
  137. package/dist/internal/hosted-delivery.js +83 -18
  138. package/dist/internal/local-control-plane.d.ts +18 -2
  139. package/dist/internal/local-control-plane.d.ts.map +1 -1
  140. package/dist/internal/local-control-plane.js +199 -17
  141. package/dist/internal/reminder-control-plane-protocol.d.ts +187 -0
  142. package/dist/internal/reminder-control-plane-protocol.d.ts.map +1 -0
  143. package/dist/internal/reminder-control-plane-protocol.js +244 -0
  144. package/dist/internal/reminder-runner.d.ts +48 -6
  145. package/dist/internal/reminder-runner.d.ts.map +1 -1
  146. package/dist/internal/reminder-runner.js +336 -48
  147. package/dist/internal/reminder-schedule.d.ts +5 -2
  148. package/dist/internal/reminder-schedule.d.ts.map +1 -1
  149. package/dist/internal/reminder-schedule.js +8 -6
  150. package/dist/internal/reminder-store.d.ts +24 -7
  151. package/dist/internal/reminder-store.d.ts.map +1 -1
  152. package/dist/internal/reminder-store.js +6 -5
  153. package/dist/internal/request-error-status.d.ts +2 -0
  154. package/dist/internal/request-error-status.d.ts.map +1 -1
  155. package/dist/internal/request-error-status.js +22 -3
  156. package/dist/internal/scm/pr-url.d.ts +40 -0
  157. package/dist/internal/scm/pr-url.d.ts.map +1 -1
  158. package/dist/internal/scm/pr-url.js +93 -14
  159. package/dist/internal/server.d.ts.map +1 -1
  160. package/dist/internal/server.js +67 -27
  161. package/dist/internal/session-engine.d.ts +4 -0
  162. package/dist/internal/session-engine.d.ts.map +1 -1
  163. package/dist/internal/session-engine.js +5 -0
  164. package/dist/playground/assets/{index-BaQzjaNK.js → index-Bq2HpEQB.js} +23 -23
  165. package/dist/playground/assets/index-CZKKNlmb.css +1 -0
  166. package/dist/playground/index.html +2 -2
  167. package/dist/reminders.d.ts +24 -5
  168. package/dist/reminders.d.ts.map +1 -1
  169. package/dist/reminders.js +28 -5
  170. package/dist/types.d.ts +89 -20
  171. package/dist/types.d.ts.map +1 -1
  172. package/docs/guides/opentelemetry.md +3 -4
  173. package/docs/reference/channels.md +11 -19
  174. package/docs/reference/cli.md +5 -2
  175. package/package.json +3 -3
  176. package/skills/otel/SKILL.md +3 -3
  177. package/src/bin/agent-serve.ts +1 -9
  178. package/src/channels/bitbucket/types.ts +2 -4
  179. package/src/channels/deployments/types.ts +5 -8
  180. package/src/channels/github/types.ts +2 -4
  181. package/src/channels/gitlab/types.ts +2 -5
  182. package/src/channels/origin/types.ts +2 -3
  183. package/src/channels/slack/defaults.ts +3 -0
  184. package/src/channels/slack/dispatch.ts +1 -0
  185. package/src/channels/slack/live-delivery.ts +53 -12
  186. package/src/channels/slack/types.ts +4 -3
  187. package/src/index.ts +6 -3
  188. package/src/internal/cli-deploy.ts +30 -12
  189. package/src/internal/cursor/backend-client.ts +90 -2
  190. package/src/internal/deploy-client.ts +16 -0
  191. package/src/internal/deploy-manifest.ts +16 -11
  192. package/src/internal/discovery/agent.ts +1 -0
  193. package/src/internal/discovery/info.ts +6 -0
  194. package/src/internal/discovery/modules.ts +2 -4
  195. package/src/internal/discovery/project.ts +3 -0
  196. package/src/internal/discovery/reminders.ts +65 -0
  197. package/src/internal/discovery/subagent.ts +1 -0
  198. package/src/internal/distribution.ts +20 -0
  199. package/src/internal/framework-storage-selection.ts +43 -6
  200. package/src/internal/guest-network.ts +3 -0
  201. package/src/internal/hosted-delivery-protocol.ts +96 -0
  202. package/src/internal/hosted-delivery.ts +154 -27
  203. package/src/internal/local-control-plane.ts +281 -22
  204. package/src/internal/reminder-control-plane-protocol.ts +499 -0
  205. package/src/internal/reminder-runner.ts +421 -48
  206. package/src/internal/reminder-schedule.ts +11 -6
  207. package/src/internal/reminder-store.ts +27 -7
  208. package/src/internal/request-error-status.ts +27 -3
  209. package/src/internal/scm/pr-url.ts +167 -20
  210. package/src/internal/server.ts +69 -16
  211. package/src/internal/session-engine.ts +5 -0
  212. package/src/reminders.ts +35 -4
  213. package/src/types.ts +95 -20
  214. package/dist/docs/assets/chunks/@localSearchIndexroot.CJxMklAy.js +0 -1
  215. package/dist/playground/assets/index-CceqnLTX.css +0 -1
  216. /package/dist/docs/assets/{reference_cli.md.C6Lo8SEd.lean.js → reference_cli.md.Dm67hd2D.lean.js} +0 -0
  217. /package/dist/docs/assets/{skills_otel.md.CqhobH3B.lean.js → skills_otel.md.B5Ddv1xH.lean.js} +0 -0
@@ -674,14 +674,17 @@ The command polls for up to ten minutes until the status reaches
674
674
 
675
675
  ## delete
676
676
 
677
- `delete` removes a deployment.
677
+ `delete` removes a hosted deployment. You can delete a deployment that
678
+ still runs. The command frees the slug. A later deploy can use the same
679
+ name. Spend stays on the archived service account.
678
680
 
679
681
  ```bash
680
682
  agent-sdk delete <slug> [--team <id>] [--no-wait] [--json]
681
683
  ```
682
684
 
683
685
  The command waits until the deployment is gone. `--no-wait` returns after
684
- the delete request is accepted.
686
+ the delete request is accepted. Architecture v2 slugs use the Agent SDK
687
+ control plane. Architecture v1 slugs use the Agent Serve control plane.
685
688
 
686
689
  ## rotate-token
687
690
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cursor/july",
3
- "version": "0.1.105",
3
+ "version": "0.1.107",
4
4
  "description": "(early alpha) Filesystem-first framework for defining Cursor agents as markdown and TypeScript and serving them over channels with the Cursor SDK.",
5
5
  "license": "SEE LICENSE IN LICENSE.md",
6
6
  "repository": {
@@ -24,7 +24,7 @@
24
24
  "!dist/internal/tenant-mcp/**",
25
25
  "!dist/internal/grokbot/**",
26
26
  "!dist/extensions/cursor-grokbot-agents/**",
27
- "!dist/internal/review-comments.*",
27
+ "!dist/internal/review-comments*",
28
28
  "!dist/internal/shallow-clone.*",
29
29
  "!dist/internal/managed-delivery.*",
30
30
  "src/**/*",
@@ -32,7 +32,7 @@
32
32
  "!src/internal/tenant-mcp/**",
33
33
  "!src/internal/grokbot/**",
34
34
  "!src/extensions/cursor-grokbot-agents/**",
35
- "!src/internal/review-comments.ts",
35
+ "!src/internal/review-comments*",
36
36
  "!src/internal/shallow-clone.ts",
37
37
  "!src/internal/managed-delivery.ts",
38
38
  "skills/**/*",
@@ -33,9 +33,9 @@ export default defineOtel({
33
33
  3. `serve(dir, { otel: { … } })`. `otel: false` disables env and
34
34
  authored config.
35
35
 
36
- Hosted v2 secrets arrive after bake. Use `defineOtel(() => …)` so flush
37
- re-resolves exporters. Authored `agent/otel.ts` records from process
38
- start even when the factory returns no exporters yet.
36
+ Hosted secrets can arrive after startup. Use `defineOtel(() => …)` so
37
+ flush re-resolves exporters. Authored `agent/otel.ts` records from
38
+ process start even when the factory returns no exporters yet.
39
39
 
40
40
  | Signal | Default |
41
41
  | --- | --- |
@@ -341,9 +341,6 @@ Options:
341
341
  the Cursor backend's per-forge forwarder instead of
342
342
  minting raw tokens into this process
343
343
  (AGENT_SERVE_<FORGE>_PROXY_URL overrides a base URL).
344
- --cursor-github-proxy
345
- serve: deprecated alias for --cursor-scm-proxy; removed
346
- one release after --cursor-scm-proxy ships.
347
344
  --public-url serve: base URL where this host is reachable from outside
348
345
  (e.g. https://agent-serve.example.com). Required for peer
349
346
  connections (defineConnection({ agent })) on cloud-runtime
@@ -519,7 +516,6 @@ async function main(argv: string[]): Promise<number> {
519
516
  "allow-anonymous-cursor-account-mcp": { type: "boolean", default: false },
520
517
  "allow-anonymous-grokbot": { type: "boolean", default: false },
521
518
  "cursor-scm-proxy": { type: "boolean", default: false },
522
- "cursor-github-proxy": { type: "boolean", default: false },
523
519
  "no-schedules": { type: "boolean", default: false },
524
520
  "no-control-plane": { type: "boolean", default: false },
525
521
  "no-playground": { type: "boolean", default: false },
@@ -1353,11 +1349,7 @@ async function main(argv: string[]): Promise<number> {
1353
1349
  : undefined,
1354
1350
  allowAnonymousGrokbot:
1355
1351
  values["allow-anonymous-grokbot"] === true ? true : undefined,
1356
- cursorScmProxy:
1357
- values["cursor-scm-proxy"] === true ||
1358
- values["cursor-github-proxy"] === true
1359
- ? true
1360
- : undefined,
1352
+ cursorScmProxy: values["cursor-scm-proxy"] === true ? true : undefined,
1361
1353
  schedules: values["no-schedules"] === true ? false : undefined,
1362
1354
  noControlPlane: values["no-control-plane"] === true ? true : undefined,
1363
1355
  playground: values["no-playground"] === true ? false : undefined,
@@ -229,10 +229,8 @@ export interface BitbucketChannelOptions {
229
229
  */
230
230
  webhookEvents?: readonly string[];
231
231
  /**
232
- * Continuation selector. Omitted inherits {@link AgentConfig.architecture}:
233
- * engine-minted per-PR continuation unless the agent set
234
- * `architecture: "v2"` (then `bitbucket.pr/v2`, or `bitbucket.none/v2`
235
- * when a non-PR event is declared).
232
+ * Continuation selector. Omit this to inherit the agent architecture's
233
+ * default. Set it explicitly only when migrating persisted identities.
236
234
  */
237
235
  continuation?: ContinuationIdentity;
238
236
  /**
@@ -56,10 +56,9 @@ export interface DeploymentsChannelOptions {
56
56
  * and then receives nothing. A bare string takes the default environment and
57
57
  * event filters.
58
58
  *
59
- * Omit on hosted v2. The control plane then binds `deploy_source` edges
60
- * from the deploy's watched `repositories` and the channel admits what it
61
- * is sent. That is the multi-tenant shape: an agent cannot enumerate
62
- * sources for a tenant it has never seen.
59
+ * Omit on Cursor-managed hosting. The control plane binds sources from the
60
+ * deployment's watched repositories, and the channel admits only what it
61
+ * receives. An agent cannot enumerate sources for an unseen tenant.
63
62
  *
64
63
  * Name sources to narrow below that scope, or to drive the self-hosted
65
64
  * relay, which has no deploy scope to inherit. On that wire `[]` means
@@ -89,10 +88,8 @@ export interface DeploymentsChannelOptions {
89
88
  onStart?: ChannelDefinition["onStart"];
90
89
  onStop?: ChannelDefinition["onStop"];
91
90
  /**
92
- * Continuation selector. Omitted inherits {@link AgentConfig.architecture}:
93
- * `"deployments.none/v1"` unless the agent set `architecture: "v2"` (then
94
- * `"deployments.deployment/v2"`). Override with `"deployments.none/v2"`
95
- * for one-shot events.
91
+ * Continuation selector. Omit this to inherit the agent architecture's
92
+ * default. Set it explicitly only when migrating persisted identities.
96
93
  */
97
94
  continuation?: ContinuationIdentity;
98
95
  }
@@ -480,10 +480,8 @@ export interface GitHubChannelOptions {
480
480
  */
481
481
  botName?: string;
482
482
  /**
483
- * Continuation selector. Omitted inherits {@link AgentConfig.architecture}:
484
- * `"github.pr/v1"` unless the agent set `architecture: "v2"` (then
485
- * `"github.pr/v2"`). Override type with `"github.issue/v2"` or
486
- * `"github.none/v2"` for events outside PR membership.
483
+ * Continuation selector. Omit this to inherit the agent architecture's
484
+ * default. Set it explicitly only when migrating persisted identities.
487
485
  */
488
486
  continuation?: ContinuationIdentity;
489
487
  /**
@@ -219,11 +219,8 @@ export interface GitLabChannelOptions {
219
219
  */
220
220
  webhookEvents?: readonly string[];
221
221
  /**
222
- * Continuation selector. Omitted inherits {@link AgentConfig.architecture}:
223
- * engine-minted per-MR continuation unless the agent set
224
- * `architecture: "v2"` (then `gitlab.mr/v2`, or `gitlab.none/v2` when a
225
- * non-MR event is declared). Override with `"gitlab.none/v2"` for one-shot
226
- * events.
222
+ * Continuation selector. Omit this to inherit the agent architecture's
223
+ * default. Set it explicitly only when migrating persisted identities.
227
224
  */
228
225
  continuation?: ContinuationIdentity;
229
226
  /**
@@ -246,9 +246,8 @@ export interface OriginChannelOptions {
246
246
  */
247
247
  webhookEvents?: readonly string[];
248
248
  /**
249
- * Continuation selector. Omitted inherits {@link AgentConfig.architecture}:
250
- * `"origin.pr/v1"` unless the agent set `architecture: "v2"` (then
251
- * `"origin.pr/v2"`). Override with `"origin.none/v2"` for one-shot events.
249
+ * Continuation selector. Omit this to inherit the agent architecture's
250
+ * default. Set it explicitly only when migrating persisted identities.
252
251
  */
253
252
  continuation?: ContinuationIdentity;
254
253
  /**
@@ -362,6 +362,9 @@ export function buildDefaultEvents(
362
362
  channel.state.streamTs = null;
363
363
  channel.state.streamChannelId = null;
364
364
  channel.state.streamFull = false;
365
+ // A stream failure downgrades the rest of its own turn, not the thread.
366
+ channel.state.streamingUnavailable = false;
367
+ channel.state.streamAppendedChunks = 0;
365
368
  channel.state.lastPostedText = null;
366
369
  channel.state.streamBlockText = null;
367
370
  channel.state.reasoningCard = undefined;
@@ -132,6 +132,7 @@ export function emptySlackChannelState(
132
132
  lastBotMessageTs: null,
133
133
  streamingUnavailable: false,
134
134
  streamFull: false,
135
+ streamAppendedChunks: 0,
135
136
  progressTs: null,
136
137
  approvalMessageByCallId: {},
137
138
  reasoningCard: undefined,
@@ -147,6 +147,7 @@ export function createStreamDeliveryStrategy(
147
147
  channel.state.streamTs = started.ts;
148
148
  channel.state.streamChannelId = started.channel;
149
149
  channel.state.streamFull = false;
150
+ channel.state.streamAppendedChunks = 0;
150
151
  channel.state.lastPostedText = openingText;
151
152
  channel.state.streamBlockText = openingText;
152
153
  log.info("chat.startStream ok", {
@@ -193,6 +194,21 @@ export function createStreamDeliveryStrategy(
193
194
  highlightCodeFences(text)
194
195
  );
195
196
 
197
+ /**
198
+ * The reply does not extend what the stream already holds, so there is no
199
+ * delta to append and the text on Slack is not the reply.
200
+ */
201
+ const rewound = (channel: SlackChannel, text: string): boolean =>
202
+ streamDelta(channel, text) === "" &&
203
+ !highlightCodeFences(text).startsWith(
204
+ highlightCodeFences(channel.state.streamBlockText ?? "")
205
+ );
206
+
207
+ const countAppended = (channel: SlackChannel, chunks: number): void => {
208
+ channel.state.streamAppendedChunks =
209
+ (channel.state.streamAppendedChunks ?? 0) + chunks;
210
+ };
211
+
196
212
  const stopWithSuffix = async (args: {
197
213
  channel: SlackChannel;
198
214
  channelId: string;
@@ -246,25 +262,25 @@ export function createStreamDeliveryStrategy(
246
262
  };
247
263
 
248
264
  /**
249
- * The streamed message is full. Close it as it stands so it stops spinning
250
- * and post the rest as a new thread message. Most of the answer is on Slack
251
- * either way, so the reply counts as delivered even if that post fails: a
252
- * duplicate would be worse than a lost tail.
265
+ * The open stream cannot carry the rest of the reply it is full, or the
266
+ * reply no longer extends what it holds. Close it as it stands so it stops
267
+ * spinning and post the remainder as a new thread message.
253
268
  */
254
- const continueOverflow = async (args: {
269
+ const continueInNewMessage = async (args: {
255
270
  channel: SlackChannel;
256
271
  channelId: string;
257
272
  ts: string;
258
273
  remainder: string;
274
+ reason: string;
259
275
  sessionId: string;
260
- }): Promise<void> => {
261
- const { channel, channelId, ts, remainder, sessionId } = args;
276
+ }): Promise<boolean> => {
277
+ const { channel, channelId, ts, remainder, reason, sessionId } = args;
262
278
  const log = getLog();
263
279
  await stopChatStream({ botToken, channel: channelId, ts });
264
280
  channel.state.streamTs = null;
265
281
  const threadTs = channel.state.threadTs;
266
282
  if (remainder === "" || threadTs === null || threadTs === "") {
267
- return;
283
+ return true;
268
284
  }
269
285
  try {
270
286
  const posted = await postMessage({
@@ -275,19 +291,23 @@ export function createStreamDeliveryStrategy(
275
291
  plainText: remainder.length >= SLACK_MARKDOWN_TEXT_MAX_LEN,
276
292
  });
277
293
  channel.state.lastBotMessageTs = posted.ts;
278
- log.info("reply overflowed the stream; continued in a new message", {
294
+ log.info("reply continued in a new message", {
295
+ reason,
279
296
  channel: channelId,
280
297
  stream_ts: ts,
281
298
  session: sessionId,
282
299
  continued_chars: remainder.length,
283
300
  });
301
+ return true;
284
302
  } catch (error) {
285
- log.warn("stream overflow continuation failed", {
303
+ log.warn("stream continuation failed", {
304
+ reason,
286
305
  error: error instanceof Error ? error.message : String(error),
287
306
  channel: channelId,
288
307
  stream_ts: ts,
289
308
  session: sessionId,
290
309
  });
310
+ return false;
291
311
  }
292
312
  };
293
313
 
@@ -328,6 +348,7 @@ export function createStreamDeliveryStrategy(
328
348
  noteAppendFailure(channel, result);
329
349
  return;
330
350
  }
351
+ countAppended(channel, 1);
331
352
  channel.state.lastPostedText = text;
332
353
  channel.state.streamBlockText = text;
333
354
  },
@@ -364,8 +385,10 @@ export function createStreamDeliveryStrategy(
364
385
  chunks: chunks.length,
365
386
  });
366
387
  noteAppendFailure(channel, result);
388
+ return false;
367
389
  }
368
- return result.ok;
390
+ countAppended(channel, chunks.length);
391
+ return true;
369
392
  },
370
393
 
371
394
  async finalize({ channel, channelId, text, sessionId }) {
@@ -381,6 +404,22 @@ export function createStreamDeliveryStrategy(
381
404
  }
382
405
  // Measured before the stop attempt mutates stream state.
383
406
  const remainder = streamDelta(channel, text);
407
+ // Nothing to append and the stream does not hold the reply: closing it
408
+ // here would leave the answer nowhere and report it as delivered.
409
+ if (rewound(channel, text)) {
410
+ const posted = await continueInNewMessage({
411
+ channel,
412
+ channelId,
413
+ ts,
414
+ remainder: text,
415
+ reason: "rewound",
416
+ sessionId,
417
+ });
418
+ if (posted) {
419
+ channel.state.lastPostedText = text;
420
+ }
421
+ return { delivered: posted };
422
+ }
384
423
  const stopped =
385
424
  channel.state.streamFull === true
386
425
  ? { ok: false, error: "msg_too_long" }
@@ -391,15 +430,17 @@ export function createStreamDeliveryStrategy(
391
430
  stream_ts: ts,
392
431
  session: sessionId,
393
432
  chars: text.length,
433
+ appends: channel.state.streamAppendedChunks ?? 0,
394
434
  });
395
435
  return { delivered: true };
396
436
  }
397
437
  if (stopped.error === "msg_too_long") {
398
- await continueOverflow({
438
+ await continueInNewMessage({
399
439
  channel,
400
440
  channelId,
401
441
  ts,
402
442
  remainder,
443
+ reason: "msg_too_long",
403
444
  sessionId,
404
445
  });
405
446
  channel.state.lastPostedText = text;
@@ -81,6 +81,8 @@ export interface SlackChannelState {
81
81
  streamingUnavailable?: boolean;
82
82
  /** The open stream hit Slack's size cap; appends stop until it closes. */
83
83
  streamFull?: boolean;
84
+ /** Chunks Slack accepted on the open stream, reported when it closes. */
85
+ streamAppendedChunks?: number;
84
86
  /** Editable progress message ts when `chat.startStream` is unavailable. */
85
87
  progressTs: string | null;
86
88
  /**
@@ -597,9 +599,8 @@ export interface SlackAccessPolicy {
597
599
  export interface SlackChannelOptions {
598
600
  credentials?: SlackCredentials;
599
601
  /**
600
- * Continuation selector. Omitted inherits {@link AgentConfig.architecture}:
601
- * `"slack.thread/v1"` unless the agent set `architecture: "v2"` (then
602
- * `"slack.thread/v2"`). Override with `"slack.none/v2"` for one-shot events.
602
+ * Continuation selector. Omit this to inherit the agent architecture's
603
+ * default. Set it explicitly only when migrating persisted identities.
603
604
  */
604
605
  continuation?: ContinuationIdentity;
605
606
  /** Defaults to `{ respondTo: "thread", blockExternals: true }`. */
package/src/index.ts CHANGED
@@ -139,7 +139,9 @@ export {
139
139
  TOOL_MCP_ENDPOINT_PATH,
140
140
  } from "./internal/mcp-endpoint.js";
141
141
  export {
142
+ REMINDER_ARGS_MAX_BYTES,
142
143
  ReminderValidationError,
144
+ rejectAnonymousReminderHandlers,
143
145
  UnknownReminderError,
144
146
  } from "./internal/reminder-runner.js";
145
147
  export type { AgentMount } from "./internal/server.js";
@@ -169,8 +171,10 @@ export { prompt } from "./prompt.js";
169
171
  export type {
170
172
  ReminderBusyPolicy,
171
173
  ReminderCreateInput,
174
+ ReminderDefinition,
172
175
  ReminderFireContext,
173
176
  ReminderFireResult,
177
+ ReminderHandlerConfig,
174
178
  ReminderHostApi,
175
179
  ReminderInfo,
176
180
  ReminderReschedule,
@@ -179,6 +183,7 @@ export type {
179
183
  ReminderTarget,
180
184
  ReminderUntilContext,
181
185
  } from "./reminders.js";
186
+ export { defineReminder } from "./reminders.js";
182
187
  export { defineResult } from "./result.js";
183
188
  export { defineSchedule } from "./schedules.js";
184
189
  export { defineSkill } from "./skills.js";
@@ -226,9 +231,7 @@ export {
226
231
 
227
232
  /**
228
233
  * Runtime config for an agent — authored at `agent/agent.ts` (the root
229
- * agent) or `agent/subagents/<id>/agent.ts` (a subagent). Set
230
- * `architecture: "v2"` to deploy onto the v2 control plane; omitted
231
- * channel continuation then inherits kind `/v2` defaults.
234
+ * agent) or `agent/subagents/<id>/agent.ts` (a subagent).
232
235
  */
233
236
  export function defineAgent(config: AgentConfig): AgentConfigDefinition {
234
237
  return brandDefinition("agent", config);
@@ -1570,14 +1570,26 @@ export async function cmdDelete(
1570
1570
  if (typeof ctx === "number") {
1571
1571
  return ctx;
1572
1572
  }
1573
- let accepted: DeleteAccepted;
1573
+ // Same dispatch as `stop`: v1 409s architecture-v2 slugs, so the v2
1574
+ // DELETE goes first. A v2 404 (missing slug, or an older backend)
1575
+ // falls through to the v1 agent-serve delete.
1576
+ let architecture: "v1" | "v2" = "v2";
1577
+ let accepted: DeleteAccepted | AgentkitStopAccepted;
1574
1578
  try {
1575
- accepted = await ctx.client.deleteDeployment({
1576
- teamId: ctx.teamId,
1577
- slug,
1578
- });
1579
+ accepted = await ctx.client.deleteAgentkit({ teamId: ctx.teamId, slug });
1579
1580
  } catch (error) {
1580
- return renderApiError(error, ctx.err);
1581
+ if (!(error instanceof DeployApiError) || error.status !== 404) {
1582
+ return renderApiError(error, ctx.err);
1583
+ }
1584
+ try {
1585
+ accepted = await ctx.client.deleteDeployment({
1586
+ teamId: ctx.teamId,
1587
+ slug,
1588
+ });
1589
+ architecture = "v1";
1590
+ } catch (v1Error) {
1591
+ return renderApiError(v1Error, ctx.err);
1592
+ }
1581
1593
  }
1582
1594
  if (ctx.noWait) {
1583
1595
  if (ctx.json) {
@@ -1588,7 +1600,11 @@ export async function cmdDelete(
1588
1600
  return 0;
1589
1601
  }
1590
1602
  try {
1591
- await pollUntilGone(ctx, slug);
1603
+ await pollUntilGone(ctx, slug, () =>
1604
+ architecture === "v2"
1605
+ ? ctx.client.getAgentkitDeploy({ teamId: ctx.teamId, slug })
1606
+ : ctx.client.getDeployment({ teamId: ctx.teamId, slug })
1607
+ );
1592
1608
  } catch (error) {
1593
1609
  return renderApiError(error, ctx.err);
1594
1610
  }
@@ -2103,7 +2119,12 @@ function transientDeployStatusWaitMs(
2103
2119
  */
2104
2120
  async function pollUntilGone(
2105
2121
  ctx: DeployCliContext,
2106
- slug: string
2122
+ slug: string,
2123
+ getDetail: () => Promise<{
2124
+ status: string;
2125
+ progress?: DeploymentProgress;
2126
+ statusMessage?: string | null;
2127
+ }>
2107
2128
  ): Promise<void> {
2108
2129
  const startedAt = Date.now();
2109
2130
  const tty = process.stderr.isTTY === true;
@@ -2126,10 +2147,7 @@ async function pollUntilGone(
2126
2147
 
2127
2148
  for (;;) {
2128
2149
  try {
2129
- const detail = await ctx.client.getDeployment({
2130
- teamId: ctx.teamId,
2131
- slug,
2132
- });
2150
+ const detail = await getDetail();
2133
2151
  report(deployProgressLabel(detail));
2134
2152
  } catch (error: unknown) {
2135
2153
  if (error instanceof DeployApiError && error.status === 404) {
@@ -82,6 +82,37 @@ const githubTokenResponseSchema: z.ZodType<CursorGithubToken> = z.object({
82
82
  expiresAt: z.string().datetime(),
83
83
  });
84
84
 
85
+ /** SCMs whose git fetches ride the backend's `/v0/scm-events/<provider>-git-proxy` routes. */
86
+ export type CursorScmCloneProvider = "gitlab" | "bitbucket";
87
+
88
+ /**
89
+ * Proxied clone target for a GitLab / Bitbucket repository. The backend
90
+ * never hands out the provider credential: git fetches go to `remoteUrl`
91
+ * on the backend with the caller's own Cursor API key as a bearer token,
92
+ * and the backend adds the tenant credential per request.
93
+ */
94
+ export interface CursorScmCloneTarget {
95
+ /** Absolute `<backend>/v0/scm-events/<provider>-git-proxy/<repo>.git`. */
96
+ remoteUrl: string;
97
+ /** Bearer credential git presents to the backend (the caller's API key). */
98
+ token: string;
99
+ /** ISO timestamp after which the caller re-resolves the target. */
100
+ expiresAt: string;
101
+ username: string;
102
+ authMode: "bearer";
103
+ }
104
+
105
+ const scmCloneTargetResponseSchema = z.object({
106
+ expiresAt: z.string().datetime(),
107
+ clone: z.object({
108
+ remotePath: z
109
+ .string()
110
+ .regex(/^\/v0\/scm-events\/[a-z]+-git-proxy\/.+\.git$/),
111
+ username: z.string().min(1),
112
+ authMode: z.literal("bearer"),
113
+ }),
114
+ });
115
+
85
116
  const mcpToolSchema = z.object({
86
117
  name: z.string(),
87
118
  providerIdentifier: z.string().optional(),
@@ -490,6 +521,62 @@ export class CursorBackendClient {
490
521
  return githubTokenResponseSchema.parse(parsed);
491
522
  }
492
523
 
524
+ /**
525
+ * Resolve the proxied clone target for a GitLab / Bitbucket repository
526
+ * (`owner/name`; GitLab `path_with_namespace`). Same authorization as the
527
+ * provider proxy this host already calls; the returned remote lives on
528
+ * the backend and takes this client's API key, never a provider token.
529
+ */
530
+ async getScmCloneTarget(
531
+ provider: CursorScmCloneProvider,
532
+ repo: string
533
+ ): Promise<CursorScmCloneTarget> {
534
+ const label = provider === "gitlab" ? "GitLab" : "Bitbucket";
535
+ let response: Response;
536
+ try {
537
+ response = await this.fetchImpl(
538
+ `${this.backendUrl}/v0/scm-events/${provider}-clone-target`,
539
+ {
540
+ method: "POST",
541
+ headers: {
542
+ "content-type": "application/json",
543
+ authorization: `Bearer ${this.currentApiKey()}`,
544
+ },
545
+ body: JSON.stringify({ repo }),
546
+ signal: AbortSignal.timeout(30_000),
547
+ }
548
+ );
549
+ } catch (error) {
550
+ throw new CursorBackendError(
551
+ `Cursor ${label} clone target request failed: ${describeError(error)}`
552
+ );
553
+ }
554
+ const text = await response.text();
555
+ if (!response.ok) {
556
+ throw new CursorBackendError(
557
+ describeGithubTokenHttpFailure(response.status, text, label),
558
+ response.status,
559
+ retryAfterMsFromResponse(response)
560
+ );
561
+ }
562
+ let parsed: unknown;
563
+ try {
564
+ parsed = JSON.parse(text) as unknown;
565
+ } catch {
566
+ throw new CursorBackendError(
567
+ `Cursor backend returned a non-JSON ${label} clone target response.`
568
+ );
569
+ }
570
+ const body = scmCloneTargetResponseSchema.parse(parsed);
571
+ return {
572
+ remoteUrl: `${this.backendUrl}${body.clone.remotePath}`,
573
+ token: this.currentApiKey(),
574
+ expiresAt: body.expiresAt,
575
+ username: body.clone.username,
576
+ authMode: body.clone.authMode,
577
+ };
578
+ }
579
+
493
580
  /**
494
581
  * One unary Connect-JSON call on `aiserver.v1.<service>` with the same
495
582
  * token exchange and 401 retry as the dashboard RPCs. Callers parse the
@@ -864,7 +951,8 @@ const MAX_GITHUB_TOKEN_RETRY_AFTER_MS = 60 * 60_000;
864
951
  */
865
952
  function describeGithubTokenHttpFailure(
866
953
  status: number,
867
- bodyText: string
954
+ bodyText: string,
955
+ label = "GitHub"
868
956
  ): string {
869
957
  const detail = githubTokenErrorFromBody(bodyText);
870
958
  if (status === 401) {
@@ -875,7 +963,7 @@ function describeGithubTokenHttpFailure(
875
963
  if (detail !== undefined) {
876
964
  return detail;
877
965
  }
878
- return `Cursor GitHub credential request failed (${status}).`;
966
+ return `Cursor ${label} credential request failed (${status}).`;
879
967
  }
880
968
 
881
969
  function githubTokenErrorFromBody(bodyText: string): string | undefined {
@@ -675,6 +675,22 @@ export class AgentServeDeployClient {
675
675
  return agentkitStopAcceptedSchema.parse(raw);
676
676
  }
677
677
 
678
+ /**
679
+ * Delete a v2 deployment (`DELETE /internal/agentsdk/deployments/:slug`).
680
+ * 202 means accepted; poll {@link getAgentkitDeploy} until 404.
681
+ */
682
+ async deleteAgentkit(args: {
683
+ teamId: number;
684
+ slug: string;
685
+ }): Promise<AgentkitStopAccepted> {
686
+ const raw = await this.request({
687
+ method: "DELETE",
688
+ path: `/internal/agentsdk/deployments/${encodeURIComponent(args.slug)}?teamId=${args.teamId}`,
689
+ context: { verb: "delete", slug: args.slug },
690
+ });
691
+ return agentkitStopAcceptedSchema.parse(raw);
692
+ }
693
+
678
694
  async listDeployments(args: { teamId: number }): Promise<Deployment[]> {
679
695
  const raw = await this.request({
680
696
  method: "GET",