@cursor/july 0.1.104 → 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 (286) 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/deployments-channel.d.ts.map +1 -1
  5. package/dist/channels/deployments/deployments-channel.js +1 -0
  6. package/dist/channels/deployments/types.d.ts +7 -8
  7. package/dist/channels/deployments/types.d.ts.map +1 -1
  8. package/dist/channels/github/types.d.ts +2 -4
  9. package/dist/channels/github/types.d.ts.map +1 -1
  10. package/dist/channels/gitlab/types.d.ts +2 -5
  11. package/dist/channels/gitlab/types.d.ts.map +1 -1
  12. package/dist/channels/origin/types.d.ts +2 -3
  13. package/dist/channels/origin/types.d.ts.map +1 -1
  14. package/dist/channels/slack/defaults.d.ts.map +1 -1
  15. package/dist/channels/slack/defaults.js +3 -0
  16. package/dist/channels/slack/dispatch.d.ts.map +1 -1
  17. package/dist/channels/slack/dispatch.js +1 -1
  18. package/dist/channels/slack/live-delivery.d.ts.map +1 -1
  19. package/dist/channels/slack/live-delivery.js +48 -11
  20. package/dist/channels/slack/types.d.ts +4 -3
  21. package/dist/channels/slack/types.d.ts.map +1 -1
  22. package/dist/docs/404.html +3 -3
  23. package/dist/docs/ab.html +6 -6
  24. package/dist/docs/assets/{app.DbMWUyGb.js → app.CtuckIiL.js} +1 -1
  25. package/dist/docs/assets/chunks/@localSearchIndexroot.DXXZxiMv.js +1 -0
  26. package/dist/docs/assets/chunks/{VPLocalSearchBox.DcNeTh9o.js → VPLocalSearchBox.Bkkhnu8K.js} +2 -2
  27. package/dist/docs/assets/chunks/{theme.DMjhY3gl.js → theme.DhpIe0Pa.js} +2 -2
  28. package/dist/docs/assets/guides_grokbot-agents.md.DVqdhBKb.js +9 -0
  29. package/dist/docs/assets/guides_grokbot-agents.md.DVqdhBKb.lean.js +1 -0
  30. package/dist/docs/assets/{guides_opentelemetry.md.COh9jFVg.js → guides_opentelemetry.md.SCRMskno.js} +3 -3
  31. package/dist/docs/assets/{guides_opentelemetry.md.COh9jFVg.lean.js → guides_opentelemetry.md.SCRMskno.lean.js} +1 -1
  32. package/dist/docs/assets/index.md.BW_6tOgR.js +5 -0
  33. package/dist/docs/assets/index.md.BW_6tOgR.lean.js +1 -0
  34. package/dist/docs/assets/{reference_channels.md.DBGcaB7m.js → reference_channels.md.D-qTqwcq.js} +2 -2
  35. package/dist/docs/assets/{reference_channels.md.DBGcaB7m.lean.js → reference_channels.md.D-qTqwcq.lean.js} +1 -1
  36. package/dist/docs/assets/{reference_cli.md.CJNc_xYK.js → reference_cli.md.Dm67hd2D.js} +3 -2
  37. package/dist/docs/assets/{reference_extensions.md.DykHW3qL.js → reference_extensions.md.CGmMLblt.js} +1 -1
  38. package/dist/docs/assets/{skills_otel.md.CqhobH3B.js → skills_otel.md.B5Ddv1xH.js} +1 -1
  39. package/dist/docs/assets/{style.BRuM8477.css → style.DCD_zyg3.css} +1 -1
  40. package/dist/docs/assets/templates_grokbot-agents.md.c1s6Flp9.js +3 -0
  41. package/dist/docs/assets/templates_grokbot-agents.md.c1s6Flp9.lean.js +1 -0
  42. package/dist/docs/building-with-agents.html +6 -6
  43. package/dist/docs/concepts.html +5 -5
  44. package/dist/docs/deployment.html +6 -6
  45. package/dist/docs/evals.html +6 -6
  46. package/dist/docs/guides/agent-to-agent.html +6 -6
  47. package/dist/docs/guides/cloud-agents.html +6 -6
  48. package/dist/docs/guides/convert-automation.html +6 -6
  49. package/dist/docs/guides/github.html +6 -6
  50. package/dist/docs/guides/grokbot-agents.html +35 -0
  51. package/dist/docs/guides/grokbot-agents.md +88 -0
  52. package/dist/docs/guides/human-in-the-loop.html +6 -6
  53. package/dist/docs/guides/mcp-oauth.html +6 -6
  54. package/dist/docs/guides/opentelemetry.html +8 -8
  55. package/dist/docs/guides/opentelemetry.md +3 -4
  56. package/dist/docs/guides/slack.html +6 -6
  57. package/dist/docs/guides/webhooks.html +6 -6
  58. package/dist/docs/hashmap.json +1 -1
  59. package/dist/docs/hillclimbing.html +6 -6
  60. package/dist/docs/index.html +8 -8
  61. package/dist/docs/index.md +6 -1
  62. package/dist/docs/llms-full.txt +178 -30
  63. package/dist/docs/llms.txt +2 -0
  64. package/dist/docs/quickstart.html +6 -6
  65. package/dist/docs/reference/agent-config.html +6 -6
  66. package/dist/docs/reference/artifacts.html +6 -6
  67. package/dist/docs/reference/channels.html +7 -7
  68. package/dist/docs/reference/channels.md +11 -19
  69. package/dist/docs/reference/cli.html +10 -9
  70. package/dist/docs/reference/cli.md +7 -3
  71. package/dist/docs/reference/connections.html +6 -6
  72. package/dist/docs/reference/extensions.html +7 -7
  73. package/dist/docs/reference/extensions.md +2 -0
  74. package/dist/docs/reference/hooks.html +6 -6
  75. package/dist/docs/reference/http-api.html +6 -6
  76. package/dist/docs/reference/instructions.html +6 -6
  77. package/dist/docs/reference/playground.html +5 -5
  78. package/dist/docs/reference/project-layout.html +6 -6
  79. package/dist/docs/reference/prompt.html +6 -6
  80. package/dist/docs/reference/result.html +6 -6
  81. package/dist/docs/reference/schedules.html +6 -6
  82. package/dist/docs/reference/sessions.html +5 -5
  83. package/dist/docs/reference/skills.html +6 -6
  84. package/dist/docs/reference/subagents.html +6 -6
  85. package/dist/docs/reference/tools.html +6 -6
  86. package/dist/docs/scaffolding-agents.html +5 -5
  87. package/dist/docs/skills/ab.html +6 -6
  88. package/dist/docs/skills/create-agent.html +6 -6
  89. package/dist/docs/skills/debug.html +5 -5
  90. package/dist/docs/skills/evals.html +6 -6
  91. package/dist/docs/skills/framework-map.html +5 -5
  92. package/dist/docs/skills/github.html +6 -6
  93. package/dist/docs/skills/hillclimb.html +6 -6
  94. package/dist/docs/skills/index.html +5 -5
  95. package/dist/docs/skills/mcp-auth.html +6 -6
  96. package/dist/docs/skills/otel.html +8 -8
  97. package/dist/docs/skills/otel.md +3 -3
  98. package/dist/docs/skills/setup-slack.html +6 -6
  99. package/dist/docs/storage.html +6 -6
  100. package/dist/docs/templates/agentic-owners.html +6 -6
  101. package/dist/docs/templates/agents-md.html +6 -6
  102. package/dist/docs/templates/code-wiki.html +6 -6
  103. package/dist/docs/templates/demo.html +6 -6
  104. package/dist/docs/templates/grokbot-agents.html +29 -0
  105. package/dist/docs/templates/grokbot-agents.md +48 -0
  106. package/dist/docs/templates/pr-autofixer.html +6 -6
  107. package/dist/docs/templates/security-help.html +6 -6
  108. package/dist/docs/templates/security-reviewer.html +6 -6
  109. package/dist/docs/templates/triage.html +6 -6
  110. package/dist/docs/troubleshooting.html +5 -5
  111. package/dist/files.d.ts +7 -2
  112. package/dist/files.d.ts.map +1 -1
  113. package/dist/files.js +7 -2
  114. package/dist/index.d.ts +4 -5
  115. package/dist/index.d.ts.map +1 -1
  116. package/dist/index.js +3 -4
  117. package/dist/internal/cli-deploy.d.ts.map +1 -1
  118. package/dist/internal/cli-deploy.js +23 -11
  119. package/dist/internal/cursor/backend-client.d.ts +25 -0
  120. package/dist/internal/cursor/backend-client.d.ts.map +1 -1
  121. package/dist/internal/cursor/backend-client.js +57 -2
  122. package/dist/internal/cursor-agent-template.d.ts +1 -1
  123. package/dist/internal/cursor-agent-template.d.ts.map +1 -1
  124. package/dist/internal/cursor-agent-template.js +1 -0
  125. package/dist/internal/deploy-client.d.ts +8 -0
  126. package/dist/internal/deploy-client.d.ts.map +1 -1
  127. package/dist/internal/deploy-client.js +14 -0
  128. package/dist/internal/deploy-manifest.d.ts +3 -0
  129. package/dist/internal/deploy-manifest.d.ts.map +1 -1
  130. package/dist/internal/deploy-manifest.js +15 -12
  131. package/dist/internal/discovery/agent.d.ts.map +1 -1
  132. package/dist/internal/discovery/agent.js +1 -0
  133. package/dist/internal/discovery/info.d.ts.map +1 -1
  134. package/dist/internal/discovery/info.js +7 -3
  135. package/dist/internal/discovery/modules.d.ts +1 -1
  136. package/dist/internal/discovery/modules.d.ts.map +1 -1
  137. package/dist/internal/discovery/modules.js +1 -0
  138. package/dist/internal/discovery/project.d.ts.map +1 -1
  139. package/dist/internal/discovery/project.js +3 -0
  140. package/dist/internal/discovery/reminders.d.ts +7 -0
  141. package/dist/internal/discovery/reminders.d.ts.map +1 -0
  142. package/dist/internal/discovery/reminders.js +65 -0
  143. package/dist/internal/discovery/subagent.js +1 -0
  144. package/dist/internal/distribution.d.ts +5 -0
  145. package/dist/internal/distribution.d.ts.map +1 -1
  146. package/dist/internal/distribution.js +17 -0
  147. package/dist/internal/framework-file-storage.d.ts +3 -1
  148. package/dist/internal/framework-file-storage.d.ts.map +1 -1
  149. package/dist/internal/framework-file-storage.js +3 -1
  150. package/dist/internal/framework-storage-selection.d.ts +14 -3
  151. package/dist/internal/framework-storage-selection.d.ts.map +1 -1
  152. package/dist/internal/framework-storage-selection.js +36 -6
  153. package/dist/internal/guest-network.d.ts.map +1 -1
  154. package/dist/internal/guest-network.js +2 -0
  155. package/dist/internal/hosted-delivery-protocol.d.ts +48 -0
  156. package/dist/internal/hosted-delivery-protocol.d.ts.map +1 -1
  157. package/dist/internal/hosted-delivery-protocol.js +60 -0
  158. package/dist/internal/hosted-delivery.d.ts +17 -0
  159. package/dist/internal/hosted-delivery.d.ts.map +1 -1
  160. package/dist/internal/hosted-delivery.js +112 -19
  161. package/dist/internal/hosted-managed-automation.d.ts.map +1 -1
  162. package/dist/internal/hosted-managed-automation.js +27 -2
  163. package/dist/internal/init-project.d.ts.map +1 -1
  164. package/dist/internal/init-project.js +4 -1
  165. package/dist/internal/local-control-plane.d.ts +18 -2
  166. package/dist/internal/local-control-plane.d.ts.map +1 -1
  167. package/dist/internal/local-control-plane.js +199 -17
  168. package/dist/internal/reminder-control-plane-protocol.d.ts +187 -0
  169. package/dist/internal/reminder-control-plane-protocol.d.ts.map +1 -0
  170. package/dist/internal/reminder-control-plane-protocol.js +244 -0
  171. package/dist/internal/reminder-runner.d.ts +48 -6
  172. package/dist/internal/reminder-runner.d.ts.map +1 -1
  173. package/dist/internal/reminder-runner.js +336 -48
  174. package/dist/internal/reminder-schedule.d.ts +5 -2
  175. package/dist/internal/reminder-schedule.d.ts.map +1 -1
  176. package/dist/internal/reminder-schedule.js +8 -6
  177. package/dist/internal/reminder-store.d.ts +24 -7
  178. package/dist/internal/reminder-store.d.ts.map +1 -1
  179. package/dist/internal/reminder-store.js +6 -5
  180. package/dist/internal/request-error-status.d.ts +2 -0
  181. package/dist/internal/request-error-status.d.ts.map +1 -1
  182. package/dist/internal/request-error-status.js +22 -3
  183. package/dist/internal/scm/pr-url.d.ts +40 -0
  184. package/dist/internal/scm/pr-url.d.ts.map +1 -1
  185. package/dist/internal/scm/pr-url.js +93 -14
  186. package/dist/internal/sdk-runner.d.ts +12 -0
  187. package/dist/internal/sdk-runner.d.ts.map +1 -1
  188. package/dist/internal/sdk-runner.js +18 -0
  189. package/dist/internal/server.d.ts.map +1 -1
  190. package/dist/internal/server.js +78 -30
  191. package/dist/internal/session-engine.d.ts +12 -0
  192. package/dist/internal/session-engine.d.ts.map +1 -1
  193. package/dist/internal/session-engine.js +137 -52
  194. package/dist/internal/store-mirror.d.ts +2 -2
  195. package/dist/internal/store-mirror.js +2 -2
  196. package/dist/internal/tenant-slack/relay.d.ts +2 -0
  197. package/dist/internal/tenant-slack/relay.d.ts.map +1 -1
  198. package/dist/internal/tenant-slack/relay.js +18 -8
  199. package/dist/internal/workspace-sync.d.ts +31 -6
  200. package/dist/internal/workspace-sync.d.ts.map +1 -1
  201. package/dist/internal/workspace-sync.js +67 -12
  202. package/dist/internal/workspace.d.ts +9 -0
  203. package/dist/internal/workspace.d.ts.map +1 -1
  204. package/dist/internal/workspace.js +16 -0
  205. package/dist/playground/assets/index-Bq2HpEQB.js +67 -0
  206. package/dist/playground/assets/index-CZKKNlmb.css +1 -0
  207. package/dist/playground/index.html +2 -2
  208. package/dist/reminders.d.ts +24 -5
  209. package/dist/reminders.d.ts.map +1 -1
  210. package/dist/reminders.js +28 -5
  211. package/dist/types.d.ts +98 -28
  212. package/dist/types.d.ts.map +1 -1
  213. package/docs/README.md +6 -1
  214. package/docs/guides/grokbot-agents.md +93 -0
  215. package/docs/guides/opentelemetry.md +3 -4
  216. package/docs/reference/channels.md +11 -19
  217. package/docs/reference/cli.md +7 -3
  218. package/docs/reference/extensions.md +2 -0
  219. package/docs/templates/grokbot-agents.md +53 -0
  220. package/package.json +12 -3
  221. package/skills/otel/SKILL.md +3 -3
  222. package/src/bin/agent-serve.ts +1 -9
  223. package/src/channels/bitbucket/types.ts +2 -4
  224. package/src/channels/deployments/deployments-channel.ts +1 -0
  225. package/src/channels/deployments/types.ts +7 -8
  226. package/src/channels/github/types.ts +2 -4
  227. package/src/channels/gitlab/types.ts +2 -5
  228. package/src/channels/origin/types.ts +2 -3
  229. package/src/channels/slack/defaults.ts +3 -0
  230. package/src/channels/slack/dispatch.ts +1 -0
  231. package/src/channels/slack/live-delivery.ts +53 -12
  232. package/src/channels/slack/types.ts +4 -3
  233. package/src/files.ts +9 -2
  234. package/src/index.ts +6 -3
  235. package/src/internal/cli-deploy.ts +30 -12
  236. package/src/internal/cursor/backend-client.ts +90 -2
  237. package/src/internal/cursor-agent-template.ts +1 -0
  238. package/src/internal/deploy-client.ts +16 -0
  239. package/src/internal/deploy-manifest.ts +16 -11
  240. package/src/internal/discovery/agent.ts +1 -0
  241. package/src/internal/discovery/info.ts +6 -0
  242. package/src/internal/discovery/modules.ts +2 -4
  243. package/src/internal/discovery/project.ts +3 -0
  244. package/src/internal/discovery/reminders.ts +65 -0
  245. package/src/internal/discovery/subagent.ts +1 -0
  246. package/src/internal/distribution.ts +20 -0
  247. package/src/internal/framework-file-storage.ts +3 -1
  248. package/src/internal/framework-storage-selection.ts +43 -6
  249. package/src/internal/guest-network.ts +3 -0
  250. package/src/internal/hosted-delivery-protocol.ts +96 -0
  251. package/src/internal/hosted-delivery.ts +207 -28
  252. package/src/internal/hosted-managed-automation.ts +49 -5
  253. package/src/internal/init-project.ts +4 -1
  254. package/src/internal/local-control-plane.ts +281 -22
  255. package/src/internal/reminder-control-plane-protocol.ts +499 -0
  256. package/src/internal/reminder-runner.ts +421 -48
  257. package/src/internal/reminder-schedule.ts +11 -6
  258. package/src/internal/reminder-store.ts +27 -7
  259. package/src/internal/request-error-status.ts +27 -3
  260. package/src/internal/scm/pr-url.ts +167 -20
  261. package/src/internal/sdk-runner.ts +19 -0
  262. package/src/internal/server.ts +85 -16
  263. package/src/internal/session-engine.ts +173 -56
  264. package/src/internal/store-mirror.ts +2 -2
  265. package/src/internal/tenant-slack/relay.ts +28 -4
  266. package/src/internal/workspace-sync.ts +84 -12
  267. package/src/internal/workspace.ts +20 -0
  268. package/src/reminders.ts +35 -4
  269. package/src/types.ts +104 -28
  270. package/templates/grokbot-agents/README.md +26 -0
  271. package/templates/grokbot-agents/agent/agent.ts +6 -0
  272. package/templates/grokbot-agents/agent/extensions/grokbot.ts +5 -0
  273. package/templates/grokbot-agents/agent/instructions.md +7 -0
  274. package/templates/grokbot-agents/evals/evals.config.ts +5 -0
  275. package/templates/grokbot-agents/evals/grokbot-agents.eval.ts +18 -0
  276. package/templates/grokbot-agents/init.json +18 -0
  277. package/templates/grokbot-agents/package.json +17 -0
  278. package/templates/grokbot-agents/tsconfig.json +12 -0
  279. package/dist/docs/assets/chunks/@localSearchIndexroot.Bqsulb9K.js +0 -1
  280. package/dist/docs/assets/index.md.D75GWhPl.js +0 -5
  281. package/dist/docs/assets/index.md.D75GWhPl.lean.js +0 -1
  282. package/dist/playground/assets/index-8YiozU89.js +0 -67
  283. package/dist/playground/assets/index-MbMxXg-y.css +0 -1
  284. /package/dist/docs/assets/{reference_cli.md.CJNc_xYK.lean.js → reference_cli.md.Dm67hd2D.lean.js} +0 -0
  285. /package/dist/docs/assets/{reference_extensions.md.DykHW3qL.lean.js → reference_extensions.md.CGmMLblt.lean.js} +0 -0
  286. /package/dist/docs/assets/{skills_otel.md.CqhobH3B.lean.js → skills_otel.md.B5Ddv1xH.lean.js} +0 -0
@@ -23,8 +23,14 @@ export interface ResolvedSchedule {
23
23
  nextFireAtMs: number;
24
24
  }
25
25
 
26
- /** Resolve create-input schedule fields into a concrete next-fire plan. */
27
- export function resolveSchedule(input: ReminderCreateInput): ResolvedSchedule {
26
+ /**
27
+ * Resolve create-input schedule fields into a concrete next-fire plan.
28
+ * Pass `nowMs` for deterministic CP / test resolution; CP owns this call.
29
+ */
30
+ export function resolveSchedule(
31
+ input: Pick<ReminderCreateInput, "every" | "cron" | "delay" | "at">,
32
+ nowMs: number = Date.now()
33
+ ): ResolvedSchedule {
28
34
  const shapes = [
29
35
  input.every !== undefined,
30
36
  input.cron !== undefined,
@@ -37,7 +43,6 @@ export function resolveSchedule(input: ReminderCreateInput): ResolvedSchedule {
37
43
  );
38
44
  }
39
45
 
40
- const now = Date.now();
41
46
  if (input.every !== undefined) {
42
47
  const intervalMs = parseDuration(input.every);
43
48
  if (intervalMs <= 0) {
@@ -49,7 +54,7 @@ export function resolveSchedule(input: ReminderCreateInput): ResolvedSchedule {
49
54
  kind: "every",
50
55
  value: String(input.every),
51
56
  intervalMs,
52
- nextFireAtMs: now + intervalMs,
57
+ nextFireAtMs: nowMs + intervalMs,
53
58
  };
54
59
  }
55
60
  if (input.cron !== undefined) {
@@ -57,7 +62,7 @@ export function resolveSchedule(input: ReminderCreateInput): ResolvedSchedule {
57
62
  return {
58
63
  kind: "cron",
59
64
  value: input.cron,
60
- nextFireAtMs: nextCronFireMs(input.cron, now),
65
+ nextFireAtMs: nextCronFireMs(input.cron, nowMs),
61
66
  };
62
67
  }
63
68
  if (input.delay !== undefined) {
@@ -65,7 +70,7 @@ export function resolveSchedule(input: ReminderCreateInput): ResolvedSchedule {
65
70
  return {
66
71
  kind: "delay",
67
72
  value: String(input.delay),
68
- nextFireAtMs: now + delayMs,
73
+ nextFireAtMs: nowMs + delayMs,
69
74
  };
70
75
  }
71
76
  const atMs =
@@ -2,10 +2,10 @@
2
2
  * Reminder document store used by the local control plane
3
3
  * (`<stateRoot>/control-plane/reminders/`).
4
4
  *
5
- * Handlers (`run` / function `until`) are not serializable — they live only
6
- * in the in-memory {@link ReminderRunner} registry. The control plane holds
7
- * schedule, prompt, target, and status so prompt-form reminders survive
8
- * restart.
5
+ * Anonymous `run` / function `until` handlers are not serializable — they live
6
+ * only in the in-memory {@link ReminderRunner} registry. Named `handler` +
7
+ * `args` and prompt-form reminders survive restart (handlers resolve from
8
+ * `agent/reminders/` on every fire).
9
9
  */
10
10
 
11
11
  import {
@@ -18,6 +18,7 @@ import {
18
18
  } from "node:fs/promises";
19
19
  import { join } from "node:path";
20
20
  import type {
21
+ JsonObject,
21
22
  ReminderBusyPolicy,
22
23
  ReminderScheduleKind,
23
24
  ReminderStatus,
@@ -31,6 +32,12 @@ export type {
31
32
  ReminderStatus,
32
33
  } from "../types.js";
33
34
 
35
+ /**
36
+ * Internal record status. `firing` is CP claim state and must not appear on
37
+ * public {@link ReminderStatus} / {@link ReminderInfo}.
38
+ */
39
+ export type ReminderRecordStatus = ReminderStatus | "firing";
40
+
34
41
  /** Serializable reminder record (no function bodies). */
35
42
  export interface ReminderRecord {
36
43
  version: typeof REMINDER_SNAPSHOT_VERSION;
@@ -46,8 +53,15 @@ export interface ReminderRecord {
46
53
  /** Raw schedule value: every/delay string, cron expression, or ISO `at`. */
47
54
  scheduleValue: string;
48
55
  intervalMs?: number;
49
- /** Prompt form — mutually exclusive with in-memory `run`. */
56
+ /** Prompt form — mutually exclusive with `handler` and in-memory `run`. */
50
57
  prompt?: string;
58
+ /**
59
+ * Named handler stem (`agent/reminders/<name>.ts`). Mutually exclusive with
60
+ * `prompt` and in-memory `run`.
61
+ */
62
+ handler?: string;
63
+ /** Serializable args for {@link handler}. */
64
+ args?: JsonObject;
51
65
  /**
52
66
  * True when create() registered a `run` handler. Handlers are not
53
67
  * serializable; after restart, armed records with this flag and no live
@@ -59,9 +73,14 @@ export interface ReminderRecord {
59
73
  /** Natural-language until (agent-facing); function until is in-memory only. */
60
74
  untilPrompt?: string;
61
75
  busyPolicy: ReminderBusyPolicy;
62
- status: ReminderStatus;
76
+ status: ReminderRecordStatus;
63
77
  disarmReason?: string;
64
78
  fireCount: number;
79
+ /**
80
+ * CAS generation. Cancel/rekey and successful outcome apply bump this so
81
+ * in-flight outcomes cannot resurrect a superseded reminder.
82
+ */
83
+ generation?: number;
65
84
  nextFireAtMs: number;
66
85
  createdAt: string;
67
86
  updatedAt: string;
@@ -120,7 +139,8 @@ export class ReminderStore {
120
139
 
121
140
  async listArmed(): Promise<ReminderRecord[]> {
122
141
  const all = await this.list();
123
- return all.filter((r) => r.status === "armed");
142
+ // Treat in-flight claims as still armed for restart / listing purposes.
143
+ return all.filter((r) => r.status === "armed" || r.status === "firing");
124
144
  }
125
145
 
126
146
  async get(id: string): Promise<ReminderRecord | undefined> {
@@ -7,12 +7,18 @@ import {
7
7
  hasGuestNetworkErrno,
8
8
  isQuietGuestConnectStall,
9
9
  } from "./guest-network.js";
10
+ import {
11
+ HOSTED_GUEST_RETRY_TERMINAL,
12
+ HOSTED_GUEST_RETRY_TRANSIENT,
13
+ type HostedGuestRetryDisposition,
14
+ } from "./hosted-delivery-protocol.js";
10
15
  import { SessionAuthError, SessionBusyError } from "./session-engine.js";
11
16
 
12
17
  export interface MappedRequestError {
13
18
  status: 400 | 403 | 409 | 503;
14
19
  code: string;
15
20
  message: string;
21
+ retry: HostedGuestRetryDisposition;
16
22
  }
17
23
 
18
24
  /**
@@ -23,23 +29,39 @@ export function mapThrownRequestError(
23
29
  error: unknown
24
30
  ): MappedRequestError | undefined {
25
31
  if (error instanceof SessionBusyError) {
26
- return { status: 409, code: "session_busy", message: error.message };
32
+ return {
33
+ status: 409,
34
+ code: "session_busy",
35
+ message: error.message,
36
+ retry: HOSTED_GUEST_RETRY_TRANSIENT,
37
+ };
27
38
  }
28
39
  if (error instanceof V2EngineError) {
29
40
  return {
30
41
  status: 409,
31
42
  code: "v2_identity_conflict",
32
43
  message: "Control-plane session identity conflicts with existing state.",
44
+ retry: HOSTED_GUEST_RETRY_TERMINAL,
33
45
  };
34
46
  }
35
47
  if (error instanceof SessionAuthError) {
36
- return { status: 403, code: "forbidden", message: error.message };
48
+ return {
49
+ status: 403,
50
+ code: "forbidden",
51
+ message: error.message,
52
+ retry: HOSTED_GUEST_RETRY_TERMINAL,
53
+ };
37
54
  }
38
55
  if (
39
56
  error instanceof InvalidAsOfError ||
40
57
  error instanceof VacuousTimeArgsError
41
58
  ) {
42
- return { status: 400, code: "invalid_request", message: error.message };
59
+ return {
60
+ status: 400,
61
+ code: "invalid_request",
62
+ message: error.message,
63
+ retry: HOSTED_GUEST_RETRY_TERMINAL,
64
+ };
43
65
  }
44
66
  if (
45
67
  error instanceof GuestNetworkUnavailableError ||
@@ -52,6 +74,7 @@ export function mapThrownRequestError(
52
74
  error instanceof Error
53
75
  ? error.message
54
76
  : "Guest network is not ready for outbound requests.",
77
+ retry: HOSTED_GUEST_RETRY_TRANSIENT,
55
78
  };
56
79
  }
57
80
  if (isQuietGuestConnectStall(error)) {
@@ -62,6 +85,7 @@ export function mapThrownRequestError(
62
85
  error instanceof Error
63
86
  ? error.message
64
87
  : "Guest Connect stalled without a network errno.",
88
+ retry: HOSTED_GUEST_RETRY_TRANSIENT,
65
89
  };
66
90
  }
67
91
  return undefined;
@@ -1,10 +1,21 @@
1
1
  /**
2
2
  * Provider-neutral PR URL parse. GitHub.com plus the Origin page shapes
3
3
  * humans paste: cursor.com/codebase, review.cursor.com/pr, origin.cursor.com.
4
+ *
5
+ * {@link parseScmPrUrl} is the wider parse the review seams use: it also
6
+ * recognizes GitLab merge requests (`/-/merge_requests/<iid>` on any host),
7
+ * Bitbucket Cloud / Data Center pull requests, and GitHub Enterprise Server
8
+ * (`/<owner>/<repo>/pull/<n>` on a host that is none of the above). The
9
+ * narrow {@link parsePrUrl} keeps its github.com + Origin contract for the
10
+ * free-text callers (Slack `pr-ref`) where "any host with /pull/N" would be
11
+ * too eager.
4
12
  */
5
13
 
6
14
  export type PrProvider = "github" | "origin";
7
15
 
16
+ /** Every SCM the review seams can address. */
17
+ export type ScmPrProvider = PrProvider | "gitlab" | "bitbucket";
18
+
8
19
  export type ParsedPrUrl = {
9
20
  provider: PrProvider;
10
21
  owner: string;
@@ -13,6 +24,27 @@ export type ParsedPrUrl = {
13
24
  url: string;
14
25
  };
15
26
 
27
+ export type ParsedScmPrUrl = {
28
+ provider: ScmPrProvider;
29
+ /**
30
+ * Namespace half of the repo: GitHub owner, GitLab group path (nested
31
+ * groups joined with `/`), Bitbucket workspace / project key (`~user`
32
+ * for Data Center personal repos).
33
+ */
34
+ owner: string;
35
+ repo: string;
36
+ number: number;
37
+ /** Canonical PR page URL. */
38
+ url: string;
39
+ /**
40
+ * Hostname the PR lives on (lowercase). `github.com` for dotcom, the
41
+ * GHES hostname for GitHub Enterprise, `gitlab.com` or the self-managed
42
+ * host for GitLab, `bitbucket.org` or the Data Center host for Bitbucket.
43
+ * Origin PRs report the Origin page host.
44
+ */
45
+ host: string;
46
+ };
47
+
16
48
  const ORIGIN_PAGE = /^origin(-[a-z0-9]+)?\.cursor\.com$/i;
17
49
 
18
50
  function positiveInt(raw: string | undefined): number | undefined {
@@ -27,19 +59,28 @@ function positiveInt(raw: string | undefined): number | undefined {
27
59
  }
28
60
 
29
61
  function parsed(
30
- provider: PrProvider,
62
+ provider: ScmPrProvider,
63
+ host: string,
31
64
  owner: string | undefined,
32
65
  repo: string | undefined,
33
- number: number | undefined
34
- ): ParsedPrUrl | undefined {
35
- if (owner === undefined || repo === undefined || number === undefined) {
66
+ number: number | undefined,
67
+ url?: string
68
+ ): ParsedScmPrUrl | undefined {
69
+ if (
70
+ owner === undefined ||
71
+ owner === "" ||
72
+ repo === undefined ||
73
+ repo === "" ||
74
+ number === undefined
75
+ ) {
36
76
  return undefined;
37
77
  }
38
- const url =
39
- provider === "origin"
78
+ const canonical =
79
+ url ??
80
+ (provider === "origin"
40
81
  ? `https://cursor.com/codebase/${owner}/${repo}/pull/${number}`
41
- : `https://github.com/${owner}/${repo}/pull/${number}`;
42
- return { provider, owner, repo, number, url };
82
+ : `https://${host}/${owner}/${repo}/pull/${number}`);
83
+ return { provider, owner, repo, number, url: canonical, host };
43
84
  }
44
85
 
45
86
  /** Strip Slack mrkdwn wrappers and trailing punctuation before `URL`. */
@@ -50,27 +91,49 @@ function normalizeRaw(raw: string): string {
50
91
  .replace(/[>\].,;]+$/, "");
51
92
  }
52
93
 
94
+ function isGithubDotCom(host: string): boolean {
95
+ return host === "github.com" || host === "www.github.com";
96
+ }
97
+
98
+ /** github.com and Origin only — the contract free-text PR references use. */
53
99
  export function parsePrUrl(raw: string): ParsedPrUrl | undefined {
100
+ const wide = parseScmPrUrl(raw);
101
+ if (wide === undefined) {
102
+ return undefined;
103
+ }
104
+ if (wide.provider === "origin") {
105
+ return { ...wide, provider: "origin" };
106
+ }
107
+ if (wide.provider === "github" && isGithubDotCom(wide.host)) {
108
+ return { ...wide, provider: "github" };
109
+ }
110
+ return undefined;
111
+ }
112
+
113
+ /**
114
+ * Every provider shape, including GitHub Enterprise Server. The GitLab and
115
+ * Bitbucket path shapes are unambiguous on any host; a plain
116
+ * `/<owner>/<repo>/pull/<n>` on a host that is not github.com, Origin,
117
+ * GitLab, or Bitbucket is taken as GHES (the only remaining forge with that
118
+ * route). Callers that must not accept arbitrary hosts use
119
+ * {@link parsePrUrl}.
120
+ */
121
+ export function parseScmPrUrl(raw: string): ParsedScmPrUrl | undefined {
54
122
  let url: URL;
55
123
  try {
56
124
  url = new URL(normalizeRaw(raw));
57
125
  } catch {
58
126
  return undefined;
59
127
  }
128
+ if (url.protocol !== "https:" && url.protocol !== "http:") {
129
+ return undefined;
130
+ }
60
131
 
61
132
  const parts = url.pathname.split("/").filter(Boolean);
62
133
  const host = url.hostname.toLowerCase();
63
134
 
64
- if (
65
- (host === "github.com" || host === "www.github.com") &&
66
- parts.length >= 4 &&
67
- parts[2] === "pull"
68
- ) {
69
- return parsed("github", parts[0], parts[1], positiveInt(parts[3]));
70
- }
71
-
72
135
  if (ORIGIN_PAGE.test(host) && parts.length >= 4 && parts[2] === "github") {
73
- return parsed("origin", parts[0], parts[1], positiveInt(parts[3]));
136
+ return parsed("origin", host, parts[0], parts[1], positiveInt(parts[3]));
74
137
  }
75
138
 
76
139
  if (
@@ -79,17 +142,101 @@ export function parsePrUrl(raw: string): ParsedPrUrl | undefined {
79
142
  parts.length >= 5 &&
80
143
  parts[3] === "pull"
81
144
  ) {
82
- return parsed("origin", parts[1], parts[2], positiveInt(parts[4]));
145
+ return parsed("origin", host, parts[1], parts[2], positiveInt(parts[4]));
83
146
  }
84
147
 
85
148
  if (host === "review.cursor.com" && parts[0] === "pr") {
86
149
  if (parts.length >= 5 && parts[3] === "github") {
87
- return parsed("origin", parts[1], parts[2], positiveInt(parts[4]));
150
+ return parsed("origin", host, parts[1], parts[2], positiveInt(parts[4]));
88
151
  }
89
152
  if (parts.length >= 4) {
90
- return parsed("origin", parts[1], parts[2], positiveInt(parts[3]));
153
+ return parsed("origin", host, parts[1], parts[2], positiveInt(parts[3]));
91
154
  }
92
155
  }
93
156
 
157
+ // GitLab MR page: /<group>/[<subgroup>/…]<project>/-/merge_requests/<iid>
158
+ const separator = parts.indexOf("-");
159
+ if (
160
+ separator >= 2 &&
161
+ parts[separator + 1] === "merge_requests" &&
162
+ parts.length >= separator + 3
163
+ ) {
164
+ const owner = parts.slice(0, separator - 1).join("/");
165
+ const repo = parts[separator - 1];
166
+ const number = positiveInt(parts[separator + 2]);
167
+ return parsed(
168
+ "gitlab",
169
+ host,
170
+ owner,
171
+ repo,
172
+ number,
173
+ number === undefined
174
+ ? undefined
175
+ : `https://${host}/${owner}/${repo}/-/merge_requests/${number}`
176
+ );
177
+ }
178
+
179
+ // Bitbucket Cloud: bitbucket.org/<workspace>/<slug>/pull-requests/<id>
180
+ if (
181
+ (host === "bitbucket.org" || host === "www.bitbucket.org") &&
182
+ parts.length >= 4 &&
183
+ parts[2] === "pull-requests"
184
+ ) {
185
+ const number = positiveInt(parts[3]);
186
+ return parsed(
187
+ "bitbucket",
188
+ "bitbucket.org",
189
+ parts[0],
190
+ parts[1],
191
+ number,
192
+ number === undefined
193
+ ? undefined
194
+ : `https://bitbucket.org/${parts[0]}/${parts[1]}/pull-requests/${number}`
195
+ );
196
+ }
197
+
198
+ // Bitbucket Data Center: [/<context>]/projects/<KEY>/repos/<slug>/pull-requests/<id>
199
+ // (personal repos: /users/<name>/repos/<slug>/…, full name `~name/slug`).
200
+ const dc = parts.findIndex(
201
+ (part, index) =>
202
+ (part === "projects" || part === "users") &&
203
+ parts[index + 2] === "repos" &&
204
+ parts[index + 4] === "pull-requests"
205
+ );
206
+ if (dc !== -1 && parts.length >= dc + 6) {
207
+ const number = positiveInt(parts[dc + 5]);
208
+ const owner = parts[dc] === "users" ? `~${parts[dc + 1]}` : parts[dc + 1];
209
+ const slug = parts[dc + 3];
210
+ const context = parts.slice(0, dc).join("/");
211
+ return parsed(
212
+ "bitbucket",
213
+ host,
214
+ owner,
215
+ slug,
216
+ number,
217
+ number === undefined
218
+ ? undefined
219
+ : `${url.origin}/${context === "" ? "" : `${context}/`}${parts.slice(dc, dc + 4).join("/")}/pull-requests/${number}`
220
+ );
221
+ }
222
+
223
+ // GitHub (dotcom or Enterprise Server): /<owner>/<repo>/pull/<n>. Checked
224
+ // last so the forge-specific shapes above win on shared hosts.
225
+ if (
226
+ parts.length >= 4 &&
227
+ parts[2] === "pull" &&
228
+ !ORIGIN_PAGE.test(host) &&
229
+ !/(^|\.)cursor\.com$/.test(host)
230
+ ) {
231
+ const githubHost = isGithubDotCom(host) ? "github.com" : host;
232
+ return parsed(
233
+ "github",
234
+ githubHost,
235
+ parts[0],
236
+ parts[1],
237
+ positiveInt(parts[3])
238
+ );
239
+ }
240
+
94
241
  return undefined;
95
242
  }
@@ -432,6 +432,25 @@ export class CursorSdkRunner implements AgentRunner {
432
432
  return { warmed: true };
433
433
  }
434
434
 
435
+ /**
436
+ * Drop the cached SDK agent for this session, if one is open.
437
+ *
438
+ * Hosted v2 parks and hibernates this process as soon as the execution
439
+ * reply lands on non-interactive channels. A leftover handle still holds
440
+ * the pre-freeze Connect/HTTP2 session; the next wake then reuses it and
441
+ * `AgentService/Run` never starts. Call after `waitForCompletion` so the
442
+ * hibernate snapshot has an empty cache. Slack's interactive hot-window
443
+ * still reuses handles because that path does not go through hosted
444
+ * delivery.
445
+ */
446
+ evictSession(sessionId: string): void {
447
+ const cached = this.agents.get(sessionId);
448
+ if (cached === undefined) {
449
+ return;
450
+ }
451
+ this.evictAgent(sessionId, cached.agent);
452
+ }
453
+
435
454
  async dispose(): Promise<void> {
436
455
  const releases = this.prewarmReleases.splice(0);
437
456
  await Promise.allSettled(releases.map((release) => release()));
@@ -129,6 +129,11 @@ import {
129
129
  } from "./handleAgentServeTrigger.js";
130
130
  import { createHostPlatforms, warmupHostGitHubAuth } from "./host-platforms.js";
131
131
  import { registerHostedDeliveryRoute } from "./hosted-delivery.js";
132
+ import {
133
+ HOSTED_DELIVERY_HEADER,
134
+ HOSTED_GUEST_RETRY_TERMINAL,
135
+ hostedGuestErrorResponse,
136
+ } from "./hosted-delivery-protocol.js";
132
137
  import { hostedErrorStackSnippet } from "./hosted-execution-diag.js";
133
138
  import { flushHostedExecutionProcessDeath } from "./hosted-execution-flush.js";
134
139
  import {
@@ -191,6 +196,7 @@ import {
191
196
  import {
192
197
  ReminderRunner,
193
198
  ReminderValidationError,
199
+ rejectAnonymousReminderHandlers,
194
200
  UnknownReminderError,
195
201
  } from "./reminder-runner.js";
196
202
  import { mapThrownRequestError } from "./request-error-status.js";
@@ -319,12 +325,9 @@ export async function startServer(
319
325
  noControlPlane?: boolean;
320
326
  /** `--cursor-scm-proxy`: every cursorAccount SCM pack routes via the backend forwarder. */
321
327
  cursorScmProxy?: boolean;
322
- /** Deprecated alias (`--cursor-github-proxy`); same effect as cursorScmProxy. */
323
- cursorGithubProxy?: boolean;
324
328
  };
325
329
  const noControlPlane = hosted.noControlPlane === true;
326
- const scmProxyRequested =
327
- hosted.cursorScmProxy === true || hosted.cursorGithubProxy === true;
330
+ const scmProxyRequested = hosted.cursorScmProxy === true;
328
331
  const runSchedules = options.schedules ?? !dev;
329
332
  const runReminders = options.reminders ?? !dev;
330
333
 
@@ -846,12 +849,23 @@ export async function startServer(
846
849
  }
847
850
  const scheduleRunner = new ScheduleRunner(engine, project, logger);
848
851
  let reminderRunner!: ReminderRunner;
852
+ const architecture = project.agent.architecture;
853
+ const useReminderCpProtocol = !noControlPlane && architecture === "v2";
849
854
  const localControlPlane = noControlPlane
850
855
  ? undefined
851
856
  : await createLocalControlPlane({
852
857
  fireSchedule: (name) => scheduleRunner.dispatch(name),
853
- fireReminder: (id, fireCount) =>
854
- reminderRunner.dispatch(id, { expectedFireCount: fireCount }),
858
+ ...(useReminderCpProtocol
859
+ ? {
860
+ executeReminder: (descriptor) =>
861
+ reminderRunner.executeFire(descriptor),
862
+ }
863
+ : {
864
+ fireReminder: (id, fireCount) =>
865
+ reminderRunner.dispatch(id, {
866
+ expectedFireCount: fireCount,
867
+ }),
868
+ }),
855
869
  stateDir: join(stateRoot, "control-plane"),
856
870
  armReminderClocks: runReminders,
857
871
  logger,
@@ -859,7 +873,16 @@ export async function startServer(
859
873
  const timerClient = noControlPlane
860
874
  ? createCursorHostedPlatformTimers()
861
875
  : localControlPlane;
862
- reminderRunner = new ReminderRunner(engine, logger, timerClient);
876
+ reminderRunner = new ReminderRunner(engine, logger, timerClient, {
877
+ namedHandlers: project.reminders ?? [],
878
+ // Architecture v2 rejects anonymous run/until everywhere (local + hosted).
879
+ rejectAnonymousHandlers: rejectAnonymousReminderHandlers({
880
+ noControlPlane,
881
+ architecture,
882
+ }),
883
+ architecture,
884
+ controlPlane: useReminderCpProtocol ? localControlPlane : undefined,
885
+ });
863
886
  const evalRuns = new EvalRunStore(
864
887
  project.rootDir,
865
888
  logger,
@@ -918,6 +941,13 @@ export async function startServer(
918
941
  ...(accountRefs !== undefined && accountBridge !== undefined
919
942
  ? { accountBridge, accountRefs }
920
943
  : {}),
944
+ ...(sdkRunner instanceof CursorSdkRunner
945
+ ? {
946
+ evictSdkSession: (sessionId: string) => {
947
+ sdkRunner.evictSession(sessionId);
948
+ },
949
+ }
950
+ : {}),
921
951
  });
922
952
  for (const channel of project.channels) {
923
953
  const definition = channel.definition;
@@ -928,6 +958,7 @@ export async function startServer(
928
958
  const startArgs: ChannelStartArgs = {
929
959
  send: (message, sendOptions) =>
930
960
  engine.send(channel.id, message, sendOptions),
961
+ architecture: project.agent.architecture,
931
962
  getSession: (sessionId) =>
932
963
  engine.getChannelSession(channel.id, sessionId),
933
964
  receive: (target, input) => engine.receive(target, input),
@@ -1440,6 +1471,12 @@ function mountAgentRoutes(
1440
1471
  * here so the Temporal host can read a stable path after the POST.
1441
1472
  */
1442
1473
  diagStateRoot?: string;
1474
+ /**
1475
+ * Drop the cached SDK agent handle after a hosted turn so hibernate
1476
+ * cannot snapshot a frozen Connect/HTTP2 session. Injected test
1477
+ * runners may omit this.
1478
+ */
1479
+ evictSdkSession?: (sessionId: string) => void;
1443
1480
  }
1444
1481
  ): void {
1445
1482
  const { slug, project, engine, scheduleRunner, reminderRunner } = runtime;
@@ -1508,6 +1545,8 @@ function mountAgentRoutes(
1508
1545
  channelId,
1509
1546
  hostedSessionId,
1510
1547
  }),
1548
+ fireReminder: (reminderId, fireCount) =>
1549
+ reminderRunner.dispatch(reminderId, { expectedFireCount: fireCount }),
1511
1550
  drainSessionDurability: (sessionId) =>
1512
1551
  engine.drainSessionDurability(sessionId),
1513
1552
  flushOtel: args.flushOtel,
@@ -1523,6 +1562,9 @@ function mountAgentRoutes(
1523
1562
  flushStartLog,
1524
1563
  }),
1525
1564
  snapshotLogs: () => logRing.since(),
1565
+ ...(args.evictSdkSession === undefined
1566
+ ? {}
1567
+ : { evictSdkSession: args.evictSdkSession }),
1526
1568
  });
1527
1569
  }
1528
1570
  // Playground lists/opens Slack (and other channel) sessions across
@@ -2969,19 +3011,34 @@ async function handleRequest(
2969
3011
  logger: (line: string) => void
2970
3012
  ): Promise<void> {
2971
3013
  let response: Response;
3014
+ let hostedDeliveryRequest = false;
2972
3015
  const method = req.method ?? "GET";
2973
3016
  try {
2974
3017
  const request = await toFetchRequest(req);
3018
+ hostedDeliveryRequest = request.headers.get(HOSTED_DELIVERY_HEADER) === "1";
3019
+ const requestErrorResponse = (
3020
+ status: number,
3021
+ error: string,
3022
+ message: string
3023
+ ) =>
3024
+ hostedDeliveryRequest
3025
+ ? hostedGuestErrorResponse({
3026
+ status,
3027
+ error,
3028
+ retry: HOSTED_GUEST_RETRY_TERMINAL,
3029
+ message,
3030
+ })
3031
+ : errorResponse(status, error, message);
2975
3032
  const url = new URL(request.url);
2976
3033
  const match = router.match(request.method, url.pathname);
2977
3034
  if (match === undefined) {
2978
3035
  response = router.hasPath(url.pathname)
2979
- ? errorResponse(
3036
+ ? requestErrorResponse(
2980
3037
  405,
2981
3038
  "method_not_allowed",
2982
3039
  `${request.method} is not supported on ${url.pathname}.`
2983
3040
  )
2984
- : errorResponse(
3041
+ : requestErrorResponse(
2985
3042
  404,
2986
3043
  "not_found",
2987
3044
  `No route for ${request.method} ${url.pathname}.`
@@ -2995,7 +3052,7 @@ async function handleRequest(
2995
3052
  unauthorized = auth === null;
2996
3053
  }
2997
3054
  response = unauthorized
2998
- ? errorResponse(
3055
+ ? requestErrorResponse(
2999
3056
  401,
3000
3057
  "unauthorized",
3001
3058
  "No auth policy admitted this request. In production, configure channel auth (e.g. bearerAuth) — the default localDevStrict() policy only admits loopback callers with a loopback Host."
@@ -3009,7 +3066,14 @@ async function handleRequest(
3009
3066
  } catch (error) {
3010
3067
  const mapped = mapThrownRequestError(error);
3011
3068
  if (mapped !== undefined) {
3012
- response = errorResponse(mapped.status, mapped.code, mapped.message);
3069
+ response = hostedDeliveryRequest
3070
+ ? hostedGuestErrorResponse({
3071
+ status: mapped.status,
3072
+ error: mapped.code,
3073
+ retry: mapped.retry,
3074
+ message: mapped.message,
3075
+ })
3076
+ : errorResponse(mapped.status, mapped.code, mapped.message);
3013
3077
  } else {
3014
3078
  logger(
3015
3079
  `[agent-sdk] request failed: ${
@@ -3019,13 +3083,18 @@ async function handleRequest(
3019
3083
  }`
3020
3084
  );
3021
3085
  const snippet = hostedErrorStackSnippet(error);
3022
- response = errorResponse(
3023
- 500,
3024
- "internal_error",
3086
+ const message =
3025
3087
  snippet.length > 0
3026
3088
  ? `Internal server error: ${snippet}`
3027
- : "Internal server error."
3028
- );
3089
+ : "Internal server error.";
3090
+ response = hostedDeliveryRequest
3091
+ ? hostedGuestErrorResponse({
3092
+ status: 500,
3093
+ error: "internal_error",
3094
+ retry: HOSTED_GUEST_RETRY_TERMINAL,
3095
+ message,
3096
+ })
3097
+ : errorResponse(500, "internal_error", message);
3029
3098
  }
3030
3099
  }
3031
3100