@cursor/july 0.1.103 → 0.1.105

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 (264) hide show
  1. package/dist/channels/change-monitors/change-monitors-channel.d.ts +5 -0
  2. package/dist/channels/change-monitors/change-monitors-channel.d.ts.map +1 -0
  3. package/dist/channels/change-monitors/change-monitors-channel.js +41 -0
  4. package/dist/channels/change-monitors/index.d.ts +4 -0
  5. package/dist/channels/change-monitors/index.d.ts.map +1 -0
  6. package/dist/channels/change-monitors/index.js +2 -0
  7. package/dist/channels/change-monitors/types.d.ts +39 -0
  8. package/dist/channels/change-monitors/types.d.ts.map +1 -0
  9. package/dist/channels/change-monitors/types.js +1 -0
  10. package/dist/channels/deployments/deployments-channel.d.ts.map +1 -1
  11. package/dist/channels/deployments/deployments-channel.js +1 -0
  12. package/dist/channels/deployments/types.d.ts +2 -0
  13. package/dist/channels/deployments/types.d.ts.map +1 -1
  14. package/dist/channels/github/defaults.d.ts.map +1 -1
  15. package/dist/channels/github/defaults.js +4 -0
  16. package/dist/channels/github/progress.d.ts +22 -0
  17. package/dist/channels/github/progress.d.ts.map +1 -1
  18. package/dist/channels/github/progress.js +32 -5
  19. package/dist/channels/issues/index.d.ts +4 -0
  20. package/dist/channels/issues/index.d.ts.map +1 -0
  21. package/dist/channels/issues/index.js +2 -0
  22. package/dist/channels/issues/issues-channel.d.ts +5 -0
  23. package/dist/channels/issues/issues-channel.d.ts.map +1 -0
  24. package/dist/channels/issues/issues-channel.js +37 -0
  25. package/dist/channels/issues/types.d.ts +33 -0
  26. package/dist/channels/issues/types.d.ts.map +1 -0
  27. package/dist/channels/issues/types.js +1 -0
  28. package/dist/docs/404.html +2 -2
  29. package/dist/docs/ab.html +4 -4
  30. package/dist/docs/assets/{app.DW9pXkpL.js → app.BVwaffdK.js} +1 -1
  31. package/dist/docs/assets/chunks/@localSearchIndexroot.CJxMklAy.js +1 -0
  32. package/dist/docs/assets/chunks/{VPLocalSearchBox.CdEIUwDg.js → VPLocalSearchBox.WuWTZ1x8.js} +1 -1
  33. package/dist/docs/assets/chunks/{theme.YZMHgPgg.js → theme.BYdI_6sF.js} +2 -2
  34. package/dist/docs/assets/{guides_github.md.DKYiT9do.js → guides_github.md.c0gdGJ-D.js} +1 -1
  35. package/dist/docs/assets/{guides_github.md.DKYiT9do.lean.js → guides_github.md.c0gdGJ-D.lean.js} +1 -1
  36. package/dist/docs/assets/guides_grokbot-agents.md.DVqdhBKb.js +9 -0
  37. package/dist/docs/assets/guides_grokbot-agents.md.DVqdhBKb.lean.js +1 -0
  38. package/dist/docs/assets/index.md.BW_6tOgR.js +5 -0
  39. package/dist/docs/assets/index.md.BW_6tOgR.lean.js +1 -0
  40. package/dist/docs/assets/{reference_channels.md.Dz8Cnudp.js → reference_channels.md.DBGcaB7m.js} +2 -2
  41. package/dist/docs/assets/{reference_channels.md.Dz8Cnudp.lean.js → reference_channels.md.DBGcaB7m.lean.js} +1 -1
  42. package/dist/docs/assets/{reference_cli.md.CJNc_xYK.js → reference_cli.md.C6Lo8SEd.js} +2 -1
  43. package/dist/docs/assets/{reference_extensions.md.DykHW3qL.js → reference_extensions.md.CGmMLblt.js} +1 -1
  44. package/dist/docs/assets/templates_grokbot-agents.md.c1s6Flp9.js +3 -0
  45. package/dist/docs/assets/templates_grokbot-agents.md.c1s6Flp9.lean.js +1 -0
  46. package/dist/docs/building-with-agents.html +4 -4
  47. package/dist/docs/concepts.html +4 -4
  48. package/dist/docs/deployment.html +4 -4
  49. package/dist/docs/design/filesystem.md +376 -0
  50. package/dist/docs/evals.html +4 -4
  51. package/dist/docs/guides/agent-to-agent.html +4 -4
  52. package/dist/docs/guides/cloud-agents.html +5 -5
  53. package/dist/docs/guides/convert-automation.html +4 -4
  54. package/dist/docs/guides/github.html +6 -6
  55. package/dist/docs/guides/github.md +5 -0
  56. package/dist/docs/guides/grokbot-agents.html +35 -0
  57. package/dist/docs/guides/grokbot-agents.md +88 -0
  58. package/dist/docs/guides/human-in-the-loop.html +4 -4
  59. package/dist/docs/guides/mcp-oauth.html +4 -4
  60. package/dist/docs/guides/opentelemetry.html +5 -5
  61. package/dist/docs/guides/slack.html +4 -4
  62. package/dist/docs/guides/webhooks.html +4 -4
  63. package/dist/docs/hashmap.json +1 -1
  64. package/dist/docs/hillclimbing.html +4 -4
  65. package/dist/docs/index.html +6 -6
  66. package/dist/docs/index.md +6 -1
  67. package/dist/docs/llms-full.txt +562 -2
  68. package/dist/docs/llms.txt +3 -0
  69. package/dist/docs/quickstart.html +4 -4
  70. package/dist/docs/reference/agent-config.html +4 -4
  71. package/dist/docs/reference/artifacts.html +4 -4
  72. package/dist/docs/reference/channels.html +6 -6
  73. package/dist/docs/reference/channels.md +20 -0
  74. package/dist/docs/reference/cli.html +7 -6
  75. package/dist/docs/reference/cli.md +2 -1
  76. package/dist/docs/reference/connections.html +4 -4
  77. package/dist/docs/reference/extensions.html +6 -6
  78. package/dist/docs/reference/extensions.md +2 -0
  79. package/dist/docs/reference/hooks.html +4 -4
  80. package/dist/docs/reference/http-api.html +4 -4
  81. package/dist/docs/reference/instructions.html +4 -4
  82. package/dist/docs/reference/playground.html +4 -4
  83. package/dist/docs/reference/project-layout.html +4 -4
  84. package/dist/docs/reference/prompt.html +4 -4
  85. package/dist/docs/reference/result.html +4 -4
  86. package/dist/docs/reference/schedules.html +4 -4
  87. package/dist/docs/reference/sessions.html +4 -4
  88. package/dist/docs/reference/skills.html +4 -4
  89. package/dist/docs/reference/subagents.html +4 -4
  90. package/dist/docs/reference/tools.html +4 -4
  91. package/dist/docs/scaffolding-agents.html +4 -4
  92. package/dist/docs/skills/ab.html +4 -4
  93. package/dist/docs/skills/create-agent.html +4 -4
  94. package/dist/docs/skills/debug.html +4 -4
  95. package/dist/docs/skills/evals.html +4 -4
  96. package/dist/docs/skills/framework-map.html +4 -4
  97. package/dist/docs/skills/github.html +4 -4
  98. package/dist/docs/skills/hillclimb.html +4 -4
  99. package/dist/docs/skills/index.html +4 -4
  100. package/dist/docs/skills/mcp-auth.html +4 -4
  101. package/dist/docs/skills/otel.html +4 -4
  102. package/dist/docs/skills/setup-slack.html +4 -4
  103. package/dist/docs/storage.html +4 -4
  104. package/dist/docs/templates/agentic-owners.html +4 -4
  105. package/dist/docs/templates/agents-md.html +4 -4
  106. package/dist/docs/templates/code-wiki.html +5 -5
  107. package/dist/docs/templates/demo.html +5 -5
  108. package/dist/docs/templates/grokbot-agents.html +29 -0
  109. package/dist/docs/templates/grokbot-agents.md +48 -0
  110. package/dist/docs/templates/pr-autofixer.html +4 -4
  111. package/dist/docs/templates/security-help.html +4 -4
  112. package/dist/docs/templates/security-reviewer.html +4 -4
  113. package/dist/docs/templates/triage.html +4 -4
  114. package/dist/docs/troubleshooting.html +4 -4
  115. package/dist/files.d.ts +7 -2
  116. package/dist/files.d.ts.map +1 -1
  117. package/dist/files.js +7 -2
  118. package/dist/filesystem.d.ts +440 -0
  119. package/dist/filesystem.d.ts.map +1 -0
  120. package/dist/filesystem.js +1694 -0
  121. package/dist/index.d.ts +2 -0
  122. package/dist/index.d.ts.map +1 -1
  123. package/dist/index.js +1 -0
  124. package/dist/internal/continuation-channel.d.ts +4 -2
  125. package/dist/internal/continuation-channel.d.ts.map +1 -1
  126. package/dist/internal/continuation-channel.js +21 -12
  127. package/dist/internal/continuation-identity.d.ts +13 -5
  128. package/dist/internal/continuation-identity.d.ts.map +1 -1
  129. package/dist/internal/continuation-identity.js +74 -35
  130. package/dist/internal/cursor-agent-template.d.ts +1 -1
  131. package/dist/internal/cursor-agent-template.d.ts.map +1 -1
  132. package/dist/internal/cursor-agent-template.js +1 -0
  133. package/dist/internal/discovery/agent.d.ts.map +1 -1
  134. package/dist/internal/discovery/agent.js +80 -8
  135. package/dist/internal/discovery/info.d.ts.map +1 -1
  136. package/dist/internal/discovery/info.js +3 -0
  137. package/dist/internal/factory-resource-channel.d.ts +33 -0
  138. package/dist/internal/factory-resource-channel.d.ts.map +1 -0
  139. package/dist/internal/factory-resource-channel.js +77 -0
  140. package/dist/internal/filesystem/errors.d.ts +64 -0
  141. package/dist/internal/filesystem/errors.d.ts.map +1 -0
  142. package/dist/internal/filesystem/errors.js +175 -0
  143. package/dist/internal/filesystem/format.d.ts +28 -0
  144. package/dist/internal/filesystem/format.d.ts.map +1 -0
  145. package/dist/internal/filesystem/format.js +213 -0
  146. package/dist/internal/filesystem/merge.d.ts +34 -0
  147. package/dist/internal/filesystem/merge.d.ts.map +1 -0
  148. package/dist/internal/filesystem/merge.js +196 -0
  149. package/dist/internal/filesystem/scratch.d.ts +59 -0
  150. package/dist/internal/filesystem/scratch.d.ts.map +1 -0
  151. package/dist/internal/filesystem/scratch.js +212 -0
  152. package/dist/internal/filesystem/sdk-schemas.d.ts +29 -0
  153. package/dist/internal/filesystem/sdk-schemas.d.ts.map +1 -0
  154. package/dist/internal/filesystem/sdk-schemas.js +153 -0
  155. package/dist/internal/filesystem/tools.d.ts +42 -0
  156. package/dist/internal/filesystem/tools.d.ts.map +1 -0
  157. package/dist/internal/filesystem/tools.js +618 -0
  158. package/dist/internal/filesystem/walk.d.ts +74 -0
  159. package/dist/internal/filesystem/walk.d.ts.map +1 -0
  160. package/dist/internal/filesystem/walk.js +339 -0
  161. package/dist/internal/framework-file-storage.d.ts +3 -1
  162. package/dist/internal/framework-file-storage.d.ts.map +1 -1
  163. package/dist/internal/framework-file-storage.js +3 -1
  164. package/dist/internal/guest-network.d.ts +5 -2
  165. package/dist/internal/guest-network.d.ts.map +1 -1
  166. package/dist/internal/guest-network.js +7 -2
  167. package/dist/internal/hosted-delivery.d.ts +7 -0
  168. package/dist/internal/hosted-delivery.d.ts.map +1 -1
  169. package/dist/internal/hosted-delivery.js +41 -3
  170. package/dist/internal/hosted-managed-automation.d.ts.map +1 -1
  171. package/dist/internal/hosted-managed-automation.js +27 -2
  172. package/dist/internal/init-project.d.ts.map +1 -1
  173. package/dist/internal/init-project.js +4 -1
  174. package/dist/internal/sdk-runner.d.ts +13 -1
  175. package/dist/internal/sdk-runner.d.ts.map +1 -1
  176. package/dist/internal/sdk-runner.js +21 -1
  177. package/dist/internal/server.d.ts.map +1 -1
  178. package/dist/internal/server.js +11 -3
  179. package/dist/internal/session-engine.d.ts +30 -0
  180. package/dist/internal/session-engine.d.ts.map +1 -1
  181. package/dist/internal/session-engine.js +484 -82
  182. package/dist/internal/store-mirror.d.ts +2 -2
  183. package/dist/internal/store-mirror.js +2 -2
  184. package/dist/internal/tenant-slack/relay.d.ts +2 -0
  185. package/dist/internal/tenant-slack/relay.d.ts.map +1 -1
  186. package/dist/internal/tenant-slack/relay.js +18 -8
  187. package/dist/internal/testing/factory-resource-fixtures.d.ts +48 -0
  188. package/dist/internal/testing/factory-resource-fixtures.d.ts.map +1 -0
  189. package/dist/internal/testing/factory-resource-fixtures.js +41 -0
  190. package/dist/internal/workspace-sync.d.ts +31 -6
  191. package/dist/internal/workspace-sync.d.ts.map +1 -1
  192. package/dist/internal/workspace-sync.js +67 -12
  193. package/dist/internal/workspace.d.ts +9 -0
  194. package/dist/internal/workspace.d.ts.map +1 -1
  195. package/dist/internal/workspace.js +16 -0
  196. package/dist/playground/assets/{index-59KvgREd.js → index-BaQzjaNK.js} +40 -40
  197. package/dist/playground/assets/index-CceqnLTX.css +1 -0
  198. package/dist/playground/index.html +2 -2
  199. package/dist/types.d.ts +60 -11
  200. package/dist/types.d.ts.map +1 -1
  201. package/docs/README.md +6 -1
  202. package/docs/design/filesystem.md +376 -0
  203. package/docs/guides/github.md +5 -0
  204. package/docs/guides/grokbot-agents.md +93 -0
  205. package/docs/reference/channels.md +20 -0
  206. package/docs/reference/cli.md +2 -1
  207. package/docs/reference/extensions.md +2 -0
  208. package/docs/templates/grokbot-agents.md +53 -0
  209. package/package.json +25 -2
  210. package/src/channels/change-monitors/change-monitors-channel.ts +62 -0
  211. package/src/channels/change-monitors/index.ts +8 -0
  212. package/src/channels/change-monitors/types.ts +44 -0
  213. package/src/channels/deployments/deployments-channel.ts +1 -0
  214. package/src/channels/deployments/types.ts +2 -0
  215. package/src/channels/github/defaults.ts +4 -0
  216. package/src/channels/github/progress.ts +76 -10
  217. package/src/channels/issues/index.ts +9 -0
  218. package/src/channels/issues/issues-channel.ts +51 -0
  219. package/src/channels/issues/types.ts +41 -0
  220. package/src/files.ts +9 -2
  221. package/src/filesystem.ts +2074 -0
  222. package/src/index.ts +28 -0
  223. package/src/internal/continuation-channel.ts +29 -12
  224. package/src/internal/continuation-identity.ts +122 -37
  225. package/src/internal/cursor-agent-template.ts +1 -0
  226. package/src/internal/discovery/agent.ts +87 -1
  227. package/src/internal/discovery/info.ts +3 -0
  228. package/src/internal/factory-resource-channel.ts +122 -0
  229. package/src/internal/filesystem/errors.ts +220 -0
  230. package/src/internal/filesystem/format.ts +276 -0
  231. package/src/internal/filesystem/merge.ts +195 -0
  232. package/src/internal/filesystem/scratch.ts +255 -0
  233. package/src/internal/filesystem/sdk-schemas.ts +204 -0
  234. package/src/internal/filesystem/tools.ts +821 -0
  235. package/src/internal/filesystem/walk.ts +369 -0
  236. package/src/internal/framework-file-storage.ts +3 -1
  237. package/src/internal/guest-network.ts +8 -2
  238. package/src/internal/hosted-delivery.ts +71 -2
  239. package/src/internal/hosted-managed-automation.ts +49 -5
  240. package/src/internal/init-project.ts +4 -1
  241. package/src/internal/sdk-runner.ts +23 -0
  242. package/src/internal/server.ts +16 -0
  243. package/src/internal/session-engine.ts +595 -73
  244. package/src/internal/store-mirror.ts +2 -2
  245. package/src/internal/tenant-slack/relay.ts +28 -4
  246. package/src/internal/testing/factory-resource-fixtures.ts +85 -0
  247. package/src/internal/workspace-sync.ts +84 -12
  248. package/src/internal/workspace.ts +20 -0
  249. package/src/types.ts +58 -11
  250. package/templates/grokbot-agents/README.md +26 -0
  251. package/templates/grokbot-agents/agent/agent.ts +6 -0
  252. package/templates/grokbot-agents/agent/extensions/grokbot.ts +5 -0
  253. package/templates/grokbot-agents/agent/instructions.md +7 -0
  254. package/templates/grokbot-agents/evals/evals.config.ts +5 -0
  255. package/templates/grokbot-agents/evals/grokbot-agents.eval.ts +18 -0
  256. package/templates/grokbot-agents/init.json +18 -0
  257. package/templates/grokbot-agents/package.json +17 -0
  258. package/templates/grokbot-agents/tsconfig.json +12 -0
  259. package/dist/docs/assets/chunks/@localSearchIndexroot.nrl1ifBq.js +0 -1
  260. package/dist/docs/assets/index.md.D75GWhPl.js +0 -5
  261. package/dist/docs/assets/index.md.D75GWhPl.lean.js +0 -1
  262. package/dist/playground/assets/index-MbMxXg-y.css +0 -1
  263. /package/dist/docs/assets/{reference_cli.md.CJNc_xYK.lean.js → reference_cli.md.C6Lo8SEd.lean.js} +0 -0
  264. /package/dist/docs/assets/{reference_extensions.md.DykHW3qL.lean.js → reference_extensions.md.CGmMLblt.lean.js} +0 -0
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Mirror an authored file tree onto an Agent Store prefix. Shared by the
3
- * skills and workspace seed syncs so both keep the same write-then-sweep
4
- * discipline and the same path refusals.
3
+ * skills, workspace seed, and session workspaceFile syncs so they keep the
4
+ * same write-then-sweep discipline and the same path refusals.
5
5
  */
6
6
 
7
7
  import { posix } from "node:path";
@@ -109,13 +109,22 @@ export async function postRelaySlackMessage(args: {
109
109
  resolve?: () => RelaySlackPostTarget | undefined;
110
110
  fetchImpl?: typeof fetch;
111
111
  timeoutMs?: number;
112
+ /** Diagnostic sink; defaults to `console.info`. */
113
+ log?: (line: string) => void;
112
114
  }): Promise<RelaySlackPostResult> {
113
115
  const channel = args.channel.trim();
116
+ const log = args.log ?? ((line: string) => console.info(line));
114
117
  if (channel === "") {
118
+ log(
119
+ `[agent-sdk-slack-relay-client] refusing post automationUuid=${args.automationUuid}: empty channel`
120
+ );
115
121
  return { ok: false, channel, status: 0, error: "empty channel" };
116
122
  }
117
123
  const target = (args.resolve ?? resolveRelaySlackTarget)();
118
124
  if (target === undefined) {
125
+ log(
126
+ `[agent-sdk-slack-relay-client] refusing post automationUuid=${args.automationUuid} channel=${channel}: no Cursor credential resolved (CURSOR_API_KEY / pod credential absent)`
127
+ );
119
128
  return {
120
129
  ok: false,
121
130
  channel,
@@ -128,6 +137,11 @@ export async function postRelaySlackMessage(args: {
128
137
  baseUrl: target.relayBaseUrl,
129
138
  automationUuid: args.automationUuid,
130
139
  });
140
+ const messageChars = args.message.length;
141
+ log(
142
+ `[agent-sdk-slack-relay-client] POST ${url} channel=${channel} messageChars=${String(messageChars)} truncated=${String(messageChars > AGENT_SDK_SLACK_RELAY_MAX_MESSAGE_CHARS)} threaded=${String(args.threadTs !== undefined)} timeoutMs=${String(args.timeoutMs ?? DEFAULT_TIMEOUT_MS)}`
143
+ );
144
+ const startedAt = Date.now();
131
145
  let response: Response;
132
146
  try {
133
147
  response = await fetchImpl(url, {
@@ -145,6 +159,9 @@ export async function postRelaySlackMessage(args: {
145
159
  signal: AbortSignal.timeout(args.timeoutMs ?? DEFAULT_TIMEOUT_MS),
146
160
  });
147
161
  } catch (error) {
162
+ log(
163
+ `[agent-sdk-slack-relay-client] request failed before a response channel=${channel} automationUuid=${args.automationUuid} elapsedMs=${String(Date.now() - startedAt)}: ${describeError(error)}`
164
+ );
148
165
  return { ok: false, channel, status: 0, error: describeError(error) };
149
166
  }
150
167
  let body: unknown;
@@ -158,16 +175,23 @@ export async function postRelaySlackMessage(args: {
158
175
  ? (body as Record<string, unknown>)
159
176
  : {};
160
177
  if (!response.ok || record.ok !== true) {
178
+ const error =
179
+ typeof record.error === "string" && record.error !== ""
180
+ ? record.error
181
+ : `relay responded ${response.status}`;
182
+ log(
183
+ `[agent-sdk-slack-relay-client] relay denied channel=${channel} automationUuid=${args.automationUuid} status=${String(response.status)} bodyOk=${String(record.ok)} elapsedMs=${String(Date.now() - startedAt)}: ${error}`
184
+ );
161
185
  return {
162
186
  ok: false,
163
187
  channel,
164
188
  status: response.status,
165
- error:
166
- typeof record.error === "string" && record.error !== ""
167
- ? record.error
168
- : `relay responded ${response.status}`,
189
+ error,
169
190
  };
170
191
  }
192
+ log(
193
+ `[agent-sdk-slack-relay-client] relay posted channel=${typeof record.channel === "string" ? record.channel : channel} automationUuid=${args.automationUuid} status=${String(response.status)} ts=${typeof record.ts === "string" ? record.ts : "<none>"} elapsedMs=${String(Date.now() - startedAt)}`
194
+ );
171
195
  return {
172
196
  ok: true,
173
197
  channel: typeof record.channel === "string" ? record.channel : channel,
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Factory resource continuation fixtures shared by July and the control
3
+ * plane identity suite. Pure data: no imports, so server-shared can load
4
+ * this file by relative path without pulling `@cursor/july`.
5
+ */
6
+
7
+ export const FACTORY_CHECKPOINT_NAME: string =
8
+ "changeMonitors/cm-1/checkpoints/cp-1";
9
+ export const FACTORY_ISSUE_NAME: string = "issues/iss-1";
10
+
11
+ export interface FactoryCheckpointResourceFixture {
12
+ name: string;
13
+ deployment: string;
14
+ runKey: string;
15
+ issues: { title: string };
16
+ evidenceSummary: string;
17
+ planRevision: string;
18
+ createTime: string;
19
+ description: string;
20
+ }
21
+
22
+ export interface FactoryIssueResourceFixture {
23
+ name: string;
24
+ title: string;
25
+ body: string;
26
+ state: "STATE_OPEN";
27
+ createTime: string;
28
+ updateTime: string;
29
+ path: string;
30
+ etag: string;
31
+ }
32
+
33
+ export interface CheckpointCreatedPayloadFixture {
34
+ eventId: string;
35
+ eventType: "checkpoint.created";
36
+ teamId: string;
37
+ occurredAtMs: number;
38
+ checkpoint: FactoryCheckpointResourceFixture;
39
+ }
40
+
41
+ export interface IssueCreatedPayloadFixture {
42
+ eventId: string;
43
+ eventType: "issue.created";
44
+ teamId: string;
45
+ occurredAtMs: number;
46
+ issue: FactoryIssueResourceFixture;
47
+ }
48
+
49
+ export const FACTORY_CHECKPOINT_RESOURCE: FactoryCheckpointResourceFixture = {
50
+ name: FACTORY_CHECKPOINT_NAME,
51
+ deployment: "deployments/11111111-1111-4111-8111-111111111111",
52
+ runKey: "t+1h",
53
+ issues: { title: "POST /checkout 500 rate elevated" },
54
+ evidenceSummary: "5xx rate rose after the deploy.",
55
+ planRevision: "changeMonitors/cm-1/planRevisions/3",
56
+ createTime: "2026-09-08T21:00:00Z",
57
+ description: "Checkout 500s are elevated.",
58
+ };
59
+
60
+ export const FACTORY_ISSUE_RESOURCE: FactoryIssueResourceFixture = {
61
+ name: FACTORY_ISSUE_NAME,
62
+ title: "Checkout 500s",
63
+ body: "5xx rate rose after the deploy.",
64
+ state: "STATE_OPEN",
65
+ createTime: "2026-09-08T21:00:00Z",
66
+ updateTime: "2026-09-08T21:00:00Z",
67
+ path: "checkout/500s",
68
+ etag: 'W/"1"',
69
+ };
70
+
71
+ export const CHECKPOINT_CREATED_PAYLOAD: CheckpointCreatedPayloadFixture = {
72
+ eventId: "evt-cp-1",
73
+ eventType: "checkpoint.created",
74
+ teamId: "team-1",
75
+ occurredAtMs: 1,
76
+ checkpoint: FACTORY_CHECKPOINT_RESOURCE,
77
+ };
78
+
79
+ export const ISSUE_CREATED_PAYLOAD: IssueCreatedPayloadFixture = {
80
+ eventId: "evt-iss-1",
81
+ eventType: "issue.created",
82
+ teamId: "team-1",
83
+ occurredAtMs: 1,
84
+ issue: FACTORY_ISSUE_RESOURCE,
85
+ };
@@ -1,10 +1,10 @@
1
1
  /**
2
- * Sync `agent/sandbox/workspace/**` seed files onto an Agent Store so
3
- * cloud-runtime turns read them from the store mount (the first cloud prompt
4
- * names the directory; see `buildCloudWorkspaceSection`). Hosted deployments
5
- * write store-root `workspace/<path>`. Local `serve`/`run` with
6
- * `runtime: "cloud"` writes `agent-serve/<agent>/workspace/<path>` on the
7
- * USER store.
2
+ * Sync workspace trees onto an Agent Store so cloud-runtime turns read
3
+ * them from the store mount. Authored `agent/sandbox/workspace/**` seeds
4
+ * land at store-root `workspace/<path>` (see `buildCloudWorkspaceSection`).
5
+ * Per-turn `workspaceFiles` land at `sessions/<sessionId>/workspace/<path>`
6
+ * (see `buildCloudSessionWorkspaceSection`). Personal-key local+cloud
7
+ * nests both under `agent-serve/<agent>/`.
8
8
  */
9
9
 
10
10
  import { readFile } from "node:fs/promises";
@@ -13,6 +13,15 @@ import { MEMORY_DIR_NAME } from "../memory.js";
13
13
  import type { SeedFile } from "../types.js";
14
14
  import { mirrorToStore, storeRelPath } from "./store-mirror.js";
15
15
 
16
+ export type WorkspaceFileBody =
17
+ | string
18
+ | { encoding: "base64"; data: string; mimeType?: string };
19
+
20
+ /** Path or encoding that can never land. Distinct from a store outage. */
21
+ export class WorkspaceFileRefusal extends Error {
22
+ override readonly name = "WorkspaceFileRefusal";
23
+ }
24
+
16
25
  /**
17
26
  * Mirror the seed tree onto the store at its authored relative paths and
18
27
  * delete keys no seed claims so redeploys drop removed files. Every seed
@@ -30,7 +39,7 @@ export async function syncWorkspaceToStore(args: {
30
39
  for (const seed of args.seedFiles) {
31
40
  desired.set(
32
41
  agentStoreKeys.workspaceFile(
33
- seedRelPath(seed.relativePath),
42
+ workspaceRelPath(seed.relativePath),
34
43
  workspacePrefix
35
44
  ),
36
45
  await readFile(seed.sourcePath)
@@ -39,17 +48,80 @@ export async function syncWorkspaceToStore(args: {
39
48
  await mirrorToStore({ sink: args.sink, prefix: workspacePrefix, desired });
40
49
  }
41
50
 
51
+ /**
52
+ * Replace the session workspace prefix with this turn's `workspaceFiles`.
53
+ * Keys the map does not claim are deleted so a later send cannot leave a
54
+ * stale `pr.json`. Every path validates before the store is touched.
55
+ * Returns the relative paths that landed, in send order.
56
+ */
57
+ export async function syncSessionWorkspaceFiles(args: {
58
+ sink: FileSink;
59
+ files: Record<string, WorkspaceFileBody>;
60
+ workspacePrefix: string;
61
+ }): Promise<string[]> {
62
+ const desired = new Map<string, Uint8Array>();
63
+ const relPaths: string[] = [];
64
+ for (const [relativePath, contents] of Object.entries(args.files)) {
65
+ const rel = workspaceRelPath(relativePath);
66
+ desired.set(
67
+ agentStoreKeys.workspaceFile(rel, args.workspacePrefix),
68
+ workspaceFileBytes(relativePath, contents)
69
+ );
70
+ relPaths.push(rel);
71
+ }
72
+ await mirrorToStore({
73
+ sink: args.sink,
74
+ prefix: args.workspacePrefix,
75
+ desired,
76
+ });
77
+ return relPaths;
78
+ }
79
+
80
+ /** Delete every key under the session workspace prefix. */
81
+ export async function wipeSessionWorkspace(args: {
82
+ sink: FileSink;
83
+ workspacePrefix: string;
84
+ }): Promise<void> {
85
+ await mirrorToStore({
86
+ sink: args.sink,
87
+ prefix: args.workspacePrefix,
88
+ desired: new Map(),
89
+ });
90
+ }
91
+
42
92
  /**
43
93
  * Same reservation as local materialization's `resolveWorkspaceWritePath`:
44
- * `memory/` is the shared cross-session journal, so a seed under it fails
45
- * the sync exactly as it fails a local first turn.
94
+ * `memory/` is the shared cross-session journal, so a seed or send under it
95
+ * fails the sync exactly as it fails a local first turn.
46
96
  */
47
- function seedRelPath(relPath: string): string {
48
- const rel = storeRelPath(relPath, "workspace file");
97
+ function workspaceRelPath(relPath: string): string {
98
+ let rel: string;
99
+ try {
100
+ rel = storeRelPath(relPath, "workspace file");
101
+ } catch (error) {
102
+ throw new WorkspaceFileRefusal(
103
+ error instanceof Error ? error.message : String(error)
104
+ );
105
+ }
49
106
  if (rel.split("/", 1)[0] === MEMORY_DIR_NAME) {
50
- throw new Error(
107
+ throw new WorkspaceFileRefusal(
51
108
  `"${MEMORY_DIR_NAME}" is reserved for shared session memory; refusing to sync ${relPath}`
52
109
  );
53
110
  }
54
111
  return rel;
55
112
  }
113
+
114
+ function workspaceFileBytes(
115
+ relativePath: string,
116
+ contents: WorkspaceFileBody
117
+ ): Uint8Array {
118
+ if (typeof contents === "string") {
119
+ return new TextEncoder().encode(contents);
120
+ }
121
+ if (contents.encoding === "base64") {
122
+ return new Uint8Array(Buffer.from(contents.data, "base64"));
123
+ }
124
+ throw new WorkspaceFileRefusal(
125
+ `Unsupported workspace file encoding for ${relativePath}`
126
+ );
127
+ }
@@ -80,6 +80,26 @@ export function buildCloudWorkspaceSection(dir: string): string {
80
80
  ].join("\n");
81
81
  }
82
82
 
83
+ /**
84
+ * Per-turn preamble for cloud `workspaceFiles` after they land on the
85
+ * session store prefix (see `syncSessionWorkspaceFiles`). Omitted when
86
+ * the sync did not land.
87
+ *
88
+ * Same shared Agent Store mount as authored seeds — the session path is
89
+ * replace-per-send / task-end wipe lifetime, not a separate mount ACL.
90
+ */
91
+ export function buildCloudSessionWorkspaceSection(
92
+ dir: string,
93
+ relPaths: readonly string[]
94
+ ): string {
95
+ const listed = relPaths.map((path) => `\`${path}\``).join(", ");
96
+ return [
97
+ "## Session workspace files",
98
+ "",
99
+ `This turn's workspace files live at \`${dir}\` on this machine (${listed}). Read them with your normal file tools. They sit on the same shared Agent Store mount as authored workspace seeds; the session directory is replaced on the next send for this session, and task sessions remove it when they finish.`,
100
+ ].join("\n");
101
+ }
102
+
83
103
  /** Relative path of an agent-side tool script inside the session workspace. */
84
104
  export function agentToolScriptPath(toolName: string): string {
85
105
  return `.agent-serve/tools/${toolName}.sh`;
package/src/types.ts CHANGED
@@ -11,6 +11,7 @@
11
11
  import type { InteractionUpdate, SDKCustomTool, ToolName } from "@cursor/sdk";
12
12
  import type { z } from "zod";
13
13
  import type { ABConfigFile } from "./ab.js";
14
+ import type { FileSystem } from "./filesystem.js";
14
15
  import type {
15
16
  ContinuationClaim,
16
17
  ContinuationIdentity,
@@ -169,6 +170,18 @@ export function toPublicCloudInfo(
169
170
  };
170
171
  }
171
172
 
173
+ /**
174
+ * Session-scoped facts a `root` factory needs and does not otherwise
175
+ * have at `defineAgent` time. The factory returns a handle: each
176
+ * method must observe the current binding. Do not snapshot the tree.
177
+ */
178
+ export interface RootContext {
179
+ sessionId: string;
180
+ agentName?: string;
181
+ continuationKey?: string;
182
+ host?: { files: HostFilesApi; reminders?: ReminderHostApi };
183
+ }
184
+
172
185
  /** Input to `defineAgent` (authored at `agent/agent.ts`). */
173
186
  export interface AgentConfig {
174
187
  /**
@@ -190,10 +203,21 @@ export interface AgentConfig {
190
203
  */
191
204
  instructions?: string;
192
205
  /**
193
- * Execution runtime. Defaults to `"local"`. Use `"cloud"` to run turns
194
- * on Cursor cloud agents (see {@link cloud}).
206
+ * Execution runtime. Defaults to `"local"`. Compatibility strings
207
+ * `"cloud"` and `"grokbot"` remain for agents that already ship; they
208
+ * are not a product surface. New agents omit this field.
195
209
  */
196
210
  runtime?: AgentRuntime;
211
+ /**
212
+ * The FileSystem the model can see. Omit it and the root is the host
213
+ * disk. A static handle (`tempFs`, `unionFs`, ...) is that object on
214
+ * every session — writes are shared. Pass `(ctx) => …` and return a
215
+ * new handle per session when you want isolation. A factory that
216
+ * returns the same object still shares. Incompatible with
217
+ * {@link local} `cwd` / `workspaceDir` / `sandbox` and with
218
+ * {@link runtime} `"cloud"`.
219
+ */
220
+ root?: FileSystem | ((ctx: RootContext) => FileSystem | Promise<FileSystem>);
197
221
  /**
198
222
  * Cloud agent defaults. Used when {@link runtime} is `"cloud"`, and as
199
223
  * the base merged under per-session {@link SendMessageOptions.cloud}
@@ -262,7 +286,8 @@ export interface AgentConfig {
262
286
  * deploys onto the v2 control plane (v2 APIs and schemas). Omitted
263
287
  * channel `continuation` then inherits from declared events (`github.pr/v2`,
264
288
  * `github.issue/v2`, `github.none/v2`, `slack.thread/v2`, `origin.pr/v2`,
265
- * `deployments.deployment/v2`, `none/v2`). An explicit per-channel selector
289
+ * `deployments.deployment/v2`, `change_monitors.checkpoint/v2`,
290
+ * `issues.issue/v2`, `none/v2`). An explicit per-channel selector
266
291
  * still overrides.
267
292
  *
268
293
  * ```ts
@@ -1901,8 +1926,9 @@ export interface SessionRecord {
1901
1926
  */
1902
1927
  workspaceOverride?: string;
1903
1928
  /**
1904
- * One-shot files to write into the harness cwd before the next turn
1905
- * (see {@link SendMessageOptions.workspaceFiles}). Cleared after apply.
1929
+ * One-shot files for the next turn (see {@link SendMessageOptions.workspaceFiles}).
1930
+ * Local turns write them into the harness cwd. Cloud turns sync them onto
1931
+ * the session Agent Store prefix. Cleared after apply.
1906
1932
  */
1907
1933
  pendingWorkspaceFiles?: Record<
1908
1934
  string,
@@ -2087,12 +2113,12 @@ export interface SendMessageOptions {
2087
2113
  */
2088
2114
  workspaceDir?: string;
2089
2115
  /**
2090
- * Relative path → contents written into the session harness cwd after
2091
- * scaffold materialize and before the next turn. On create, queued for
2092
- * the first turn; on resume, replaces any pending files. Prefer this
2093
- * over {@link workspaceDir} when you only need to inject a few
2094
- * host-prepared files (skills/AGENTS.md still land in the normal
2095
- * session workspace). Values may be utf8 strings or
2116
+ * Relative path → contents for the next turn. Local turns write them into
2117
+ * the harness cwd after scaffold materialize. Cloud turns sync them onto
2118
+ * the session Agent Store prefix instead of the VM working directory. On
2119
+ * create, queued for the first turn; on resume, merged into any pending
2120
+ * files. Prefer this over {@link workspaceDir} when you only need to
2121
+ * inject a few host-prepared files. Values may be utf8 strings or
2096
2122
  * `{ encoding: "base64", data }` blobs (Slack attachments, binary docs).
2097
2123
  */
2098
2124
  workspaceFiles?: Record<
@@ -2520,6 +2546,13 @@ export interface ChannelMeta {
2520
2546
  * to dispatch on. Extracted into the deploy manifest as `eventTypes`.
2521
2547
  */
2522
2548
  deploymentEventTypes?: readonly string[];
2549
+ /**
2550
+ * For Change Monitor checkpoint and Factory issue packs: the factory
2551
+ * event types this channel is wired to dispatch on. Extracted into the
2552
+ * deploy manifest as `eventTypes`. Kept separate from
2553
+ * `deploymentEventTypes`.
2554
+ */
2555
+ factoryEventTypes?: readonly string[];
2523
2556
  /**
2524
2557
  * For Slack packs with the opt-in channel watch: the allowlisted channels
2525
2558
  * (ids or `#names`) this channel dispatches on without a mention. Surfaced
@@ -3122,6 +3155,11 @@ export interface ResolvedAgent {
3122
3155
  instructions?: string;
3123
3156
  /** Execution runtime. Root agents default to `"local"`. */
3124
3157
  runtime: AgentRuntime;
3158
+ /**
3159
+ * Authored {@link AgentConfig.root}. The factory is persisted, not a
3160
+ * serialized tree. A resumed session calls it again (or reuses the handle).
3161
+ */
3162
+ root?: FileSystem | ((ctx: RootContext) => FileSystem | Promise<FileSystem>);
3125
3163
  /** Cloud options when {@link runtime} is `"cloud"`. */
3126
3164
  cloud?: AgentCloudOptions;
3127
3165
  /**
@@ -3274,6 +3312,8 @@ export interface AgentProjectInfo {
3274
3312
  bitbucketWebhookEvents?: readonly string[];
3275
3313
  /** Factory deployment event types the channel dispatches on, when declared. */
3276
3314
  deploymentEventTypes?: readonly string[];
3315
+ /** Change Monitor checkpoint or Factory issue event types the channel dispatches on, when declared. */
3316
+ factoryEventTypes?: readonly string[];
3277
3317
  /** Slack channels watched for posts (opt-in channel watch), when declared. */
3278
3318
  slackChannelPosts?: readonly string[];
3279
3319
  }>;
@@ -3324,10 +3364,17 @@ export interface RunnerTurnRequest {
3324
3364
  sdkAgentId?: string;
3325
3365
  /** Absolute path of the session's materialized workspace. */
3326
3366
  workspaceDir: string;
3367
+ /** Resolved FileSystem handle when {@link AgentConfig.root} is set. */
3368
+ root?: FileSystem;
3327
3369
  /** Run the local harness sandboxed ({@link AgentLocalOptions.sandbox}). */
3328
3370
  sandbox?: boolean;
3329
3371
  /** Built-in tool allowlist ({@link AgentConfig.tools}, resolved). */
3330
3372
  tools?: ToolName[];
3373
+ /**
3374
+ * Native tools hidden on the Cursor SDK agent because synthesized
3375
+ * FileSystem tools own those names. Host-default omitted `tools` only.
3376
+ */
3377
+ disallowedTools?: ToolName[];
3331
3378
  /** Absolute path for runner-owned durable state (conversation store). */
3332
3379
  runnerStateDir: string;
3333
3380
  prompt: string;
@@ -0,0 +1,26 @@
1
+ # Grok Bot agents
2
+
3
+ Consults the Grok Bot agents you name. This agent stays in its own
4
+ conversation and reports the reply.
5
+
6
+ ```bash
7
+ npx @cursor/july init ./grokbot --template grokbot-agents
8
+ ```
9
+
10
+ `init` asks for the names shown in the Grok Bot app. Skip the prompt
11
+ with `--var agents="Plan Keeper, Chief of Staff"`.
12
+
13
+ ## Run
14
+
15
+ ```bash
16
+ agent-sdk login
17
+ agent-sdk dev
18
+ ```
19
+
20
+ In the playground, ask it to talk to one of the names you entered. A
21
+ name outside the list is refused.
22
+
23
+ ## Edit
24
+
25
+ - `agent/extensions/grokbot.ts`: who it may talk to
26
+ - `agent/instructions.md`: when to consult them
@@ -0,0 +1,6 @@
1
+ import { defineAgent } from "@cursor/july";
2
+
3
+ export default defineAgent({
4
+ // Empty allowlist: only the mounted Grok Bot tools.
5
+ tools: [],
6
+ });
@@ -0,0 +1,5 @@
1
+ import cursorGrokBotAgents from "@cursor/july/extensions/cursor-grokbot-agents";
2
+
3
+ export default cursorGrokBotAgents({
4
+ agents: ["Plan Keeper"],
5
+ });
@@ -0,0 +1,7 @@
1
+ # Grok Bot agents
2
+
3
+ Consult the Grok Bot agents named in `agent/extensions/grokbot.ts`. Stay in this conversation and report the reply.
4
+
5
+ When someone asks who you can talk to, call `grokbot__list`. Do not send a message.
6
+
7
+ When the question belongs to one of those agents, use the consult skill. A name outside the list is refused.
@@ -0,0 +1,5 @@
1
+ import { defineEvalConfig } from "@cursor/july/evals";
2
+
3
+ export default defineEvalConfig({
4
+ maxConcurrency: 10,
5
+ });
@@ -0,0 +1,18 @@
1
+ import { defineEval } from "@cursor/july/evals";
2
+
3
+ export default defineEval({
4
+ tags: ["smoke"],
5
+ cases: [
6
+ {
7
+ id: "list",
8
+ description: "Asked who it can talk to, it lists and does not send.",
9
+ async test(t) {
10
+ await t.send("Who can you talk to? List them. Do not message anyone.");
11
+ t.succeeded();
12
+ t.calledTool("grokbot__list");
13
+ t.notCalledTool("grokbot__ask");
14
+ t.notCalledTool("grokbot__interrupt");
15
+ },
16
+ },
17
+ ],
18
+ });
@@ -0,0 +1,18 @@
1
+ {
2
+ "questions": [
3
+ {
4
+ "id": "agents",
5
+ "prompt": "Which Grok Bot agents may this agent talk to?",
6
+ "hint": "Comma-separated names, as shown in the Grok Bot app.",
7
+ "placeholder": "Plan Keeper, Chief of Staff"
8
+ }
9
+ ],
10
+ "replace": [
11
+ {
12
+ "file": "agent/extensions/grokbot.ts",
13
+ "find": "[\"Plan Keeper\"]",
14
+ "answer": "agents",
15
+ "as": "json-array"
16
+ }
17
+ ]
18
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "grokbot-agents",
3
+ "private": true,
4
+ "type": "module",
5
+ "description": "Consults the Grok Bot agents you name.",
6
+ "scripts": {
7
+ "check": "tsc --noEmit",
8
+ "dev": "agent-sdk dev"
9
+ },
10
+ "dependencies": {
11
+ "@cursor/july": "latest"
12
+ },
13
+ "devDependencies": {
14
+ "@types/node": "^22.14.0",
15
+ "typescript": "^5.8.0"
16
+ }
17
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "strict": true,
7
+ "noEmit": true,
8
+ "skipLibCheck": true,
9
+ "types": ["node"]
10
+ },
11
+ "include": ["agent/**/*", "evals/**/*"]
12
+ }