@cursor/july 0.1.87 → 0.1.89

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 (73) hide show
  1. package/dist/bin/agent-serve.js +8 -1
  2. package/dist/internal/advertise-tools.d.ts.map +1 -1
  3. package/dist/internal/advertise-tools.js +4 -2
  4. package/dist/internal/cli-ax.js +1 -1
  5. package/dist/internal/cli-deploy.d.ts +3 -2
  6. package/dist/internal/cli-deploy.d.ts.map +1 -1
  7. package/dist/internal/cli-deploy.js +84 -9
  8. package/dist/internal/cli-docs.js +11 -0
  9. package/dist/internal/cloud-merge.d.ts +3 -1
  10. package/dist/internal/cloud-merge.d.ts.map +1 -1
  11. package/dist/internal/cloud-merge.js +10 -2
  12. package/dist/internal/cursor/account-mcp.d.ts.map +1 -1
  13. package/dist/internal/cursor/account-mcp.js +8 -4
  14. package/dist/internal/cursor/backend-client.d.ts +12 -0
  15. package/dist/internal/cursor/backend-client.d.ts.map +1 -1
  16. package/dist/internal/cursor/backend-client.js +27 -1
  17. package/dist/internal/deploy-client.d.ts +42 -1
  18. package/dist/internal/deploy-client.d.ts.map +1 -1
  19. package/dist/internal/deploy-client.js +70 -2
  20. package/dist/internal/discovery.d.ts.map +1 -1
  21. package/dist/internal/discovery.js +87 -11
  22. package/dist/internal/docs-site.d.ts +13 -2
  23. package/dist/internal/docs-site.d.ts.map +1 -1
  24. package/dist/internal/docs-site.js +76 -13
  25. package/dist/internal/grokbot/runner.d.ts +61 -0
  26. package/dist/internal/grokbot/runner.d.ts.map +1 -0
  27. package/dist/internal/grokbot/runner.js +278 -0
  28. package/dist/internal/mcp-endpoint.js +6 -3
  29. package/dist/internal/mcp-host.d.ts +14 -1
  30. package/dist/internal/mcp-host.d.ts.map +1 -1
  31. package/dist/internal/mcp-host.js +41 -2
  32. package/dist/internal/runtime-dispatch-runner.d.ts +30 -0
  33. package/dist/internal/runtime-dispatch-runner.d.ts.map +1 -0
  34. package/dist/internal/runtime-dispatch-runner.js +60 -0
  35. package/dist/internal/sdk-runner.d.ts.map +1 -1
  36. package/dist/internal/sdk-runner.js +7 -0
  37. package/dist/internal/server.d.ts.map +1 -1
  38. package/dist/internal/server.js +24 -1
  39. package/dist/internal/session-engine.d.ts +9 -2
  40. package/dist/internal/session-engine.d.ts.map +1 -1
  41. package/dist/internal/session-engine.js +121 -46
  42. package/dist/internal/tool-policy.d.ts +33 -1
  43. package/dist/internal/tool-policy.d.ts.map +1 -1
  44. package/dist/internal/tool-policy.js +53 -0
  45. package/dist/playground/assets/{index-Bqn91tW4.js → index-BmiIjFlM.js} +45 -45
  46. package/dist/playground/assets/index-DQGZnAI0.css +1 -0
  47. package/dist/playground/index.html +2 -2
  48. package/dist/types.d.ts +86 -2
  49. package/dist/types.d.ts.map +1 -1
  50. package/package.json +1 -1
  51. package/skills/debug/SKILL.md +1 -2
  52. package/skills/framework-map/SKILL.md +1 -2
  53. package/src/bin/agent-serve.ts +9 -1
  54. package/src/internal/advertise-tools.ts +7 -0
  55. package/src/internal/cli-ax.ts +1 -1
  56. package/src/internal/cli-deploy.ts +123 -15
  57. package/src/internal/cli-docs.ts +11 -0
  58. package/src/internal/cloud-merge.ts +12 -2
  59. package/src/internal/cursor/account-mcp.ts +15 -1
  60. package/src/internal/cursor/backend-client.ts +37 -0
  61. package/src/internal/deploy-client.ts +122 -2
  62. package/src/internal/discovery.ts +133 -13
  63. package/src/internal/docs-site.ts +83 -13
  64. package/src/internal/grokbot/runner.ts +361 -0
  65. package/src/internal/mcp-endpoint.ts +6 -1
  66. package/src/internal/mcp-host.ts +48 -0
  67. package/src/internal/runtime-dispatch-runner.ts +63 -0
  68. package/src/internal/sdk-runner.ts +9 -0
  69. package/src/internal/server.ts +32 -4
  70. package/src/internal/session-engine.ts +126 -21
  71. package/src/internal/tool-policy.ts +80 -1
  72. package/src/types.ts +84 -2
  73. package/dist/playground/assets/index-C0_5hOsf.css +0 -1
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * Thin client for the Agent Serve deployment management API
3
- * (`/internal/agent-serve/deployments` on the Cursor backend). Pure
3
+ * (`/internal/agent-serve/deployments` on the Cursor backend) and the v2
4
+ * AgentSDK accept path (`/internal/agentkit/deployments`). Pure
4
5
  * request/response + error mapping — no console I/O, no polling loops;
5
6
  * rendering lives in `cli-deploy.ts`.
6
7
  *
@@ -66,6 +67,7 @@ export function deploymentServiceAccountId(deployment) {
66
67
  const id = String(raw).trim();
67
68
  return id === "" ? undefined : id;
68
69
  }
70
+ export const TERMINAL_AGENTKIT_DEPLOY_STATUSES = new Set(["running", "failed", "stopped"]);
69
71
  // All response schemas are `.passthrough()`: the backend keeps growing the
70
72
  // deployment payload (serviceAccountId, egressAllowedDomains, secret
71
73
  // metadata, ...) and unknown fields must flow through untouched — both so
@@ -83,6 +85,33 @@ const deployAcceptedSchema = z
83
85
  aliasToken: z.string().optional(),
84
86
  })
85
87
  .passthrough();
88
+ const agentkitDeployAcceptedSchema = z
89
+ .object({
90
+ applicationId: z.string().min(1),
91
+ releaseId: z.string().min(1),
92
+ status: z.string(),
93
+ })
94
+ .passthrough();
95
+ const agentkitDeployStatusSchema = z
96
+ .object({
97
+ applicationId: z.string().min(1),
98
+ releaseId: z.string().min(1),
99
+ slug: z.string().min(1),
100
+ teamId: z.number(),
101
+ status: z.enum(["pending", "deploying", "running", "failed", "stopped"]),
102
+ progress: z.enum([
103
+ "queued",
104
+ "creating",
105
+ "building",
106
+ "starting",
107
+ "finalizing",
108
+ "running",
109
+ "failed",
110
+ "stopped",
111
+ ]),
112
+ statusMessage: z.string().nullable(),
113
+ })
114
+ .passthrough();
86
115
  const deploymentSchema = z.object({
87
116
  id: z.number(),
88
117
  slug: z.string(),
@@ -263,6 +292,45 @@ export class AgentServeDeployClient {
263
292
  return deployAcceptedSchema.parse(raw);
264
293
  });
265
294
  }
295
+ /**
296
+ * Create or redeploy onto the v2 control plane
297
+ * (`POST /internal/agentkit/deployments`). 202 means accepted; poll
298
+ * {@link getAgentkitDeploy} until a terminal status.
299
+ */
300
+ deployAgentkit(args) {
301
+ return __awaiter(this, void 0, void 0, function* () {
302
+ const slugError = validateDeploymentSlug(args.slug);
303
+ if (slugError !== undefined) {
304
+ throw new DeployApiError(slugError, 400);
305
+ }
306
+ const raw = yield this.request({
307
+ method: "POST",
308
+ path: "/internal/agentkit/deployments",
309
+ body: {
310
+ teamId: args.teamId,
311
+ slug: args.slug,
312
+ gitRepoUrl: args.gitRepoUrl,
313
+ gitRef: args.gitRef,
314
+ agentPath: args.agentPath,
315
+ repositories: args.repositories !== undefined && args.repositories.length > 0
316
+ ? args.repositories
317
+ : undefined,
318
+ },
319
+ context: { verb: "deploy", slug: args.slug },
320
+ });
321
+ return agentkitDeployAcceptedSchema.parse(raw);
322
+ });
323
+ }
324
+ getAgentkitDeploy(args) {
325
+ return __awaiter(this, void 0, void 0, function* () {
326
+ const raw = yield this.request({
327
+ method: "GET",
328
+ path: `/internal/agentkit/deployments/${encodeURIComponent(args.slug)}?teamId=${args.teamId}`,
329
+ context: { verb: "get deployment", slug: args.slug },
330
+ });
331
+ return agentkitDeployStatusSchema.parse(raw);
332
+ });
333
+ }
266
334
  listDeployments(args) {
267
335
  return __awaiter(this, void 0, void 0, function* () {
268
336
  const raw = yield this.request({
@@ -476,7 +544,7 @@ function mapErrorResponse(response, bodyText, context) {
476
544
  // Fastify's route-not-found envelope means we hit the wrong host
477
545
  // (api2 vs api.cursor.com), not a missing deployment / closed gate.
478
546
  if (/Route \S+ not found/i.test(bodyText)) {
479
- return new DeployApiError(`Agent Serve deploy API not found on this host — use the default api.cursor.com (unset CURSOR_API_BASE_URL), or point CURSOR_API_BASE_URL at a backend that mounts /internal/agent-serve/*.`, 404);
547
+ return new DeployApiError(`Agent Serve deploy API not found on this host — use the default api.cursor.com (unset CURSOR_API_BASE_URL), or point CURSOR_API_BASE_URL at a backend that mounts /internal/agent-serve/* and /internal/agentkit/*.`, 404);
480
548
  }
481
549
  return new DeployApiError(context.slug === undefined
482
550
  ? `Not found — the agent_serve_mvp feature gate may not be enabled for your team.`
@@ -1 +1 @@
1
- {"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../src/internal/discovery.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAkBH,OAAO,EAKL,KAAK,YAAY,EACjB,KAAK,gBAAgB,EASrB,KAAK,UAAU,EAwBhB,MAAM,aAAa,CAAC;AAgCrB,MAAM,WAAW,uBAAuB;IACtC,sDAAsD;IACtD,YAAY,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CAC3E;AAmBD;;;;GAIG;AACH,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CASrE;AAED,sEAAsE;AACtE,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;;GAIG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,aAAa,EAAE,CAAC,CA2B1B;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,uBAA4B,GACpC,OAAO,CAAC,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,YAAY,CAAA;CAAE,CAAC,CAAC,CA6BzD;AAED;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,uBAAuB,GAAG;IACjC,IAAI,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC;CACtB,GACL,OAAO,CAAC,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,YAAY,CAAA;CAAE,CAAC,CAAC,CAgBzD;AAWD,iFAAiF;AACjF,eAAO,MAAM,cAAc,EAAE,GAAG,CAAC,MAAM,CAIrC,CAAC;AAEH,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,uBAA4B,GACpC,OAAO,CAAC,YAAY,CAAC,CA0EvB;AAED,qEAAqE;AACrE,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAElE;AAED,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,UAAU,EAAE,GAAG,MAAM,CAOnE;AAozBD;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAiB3E;AAo2BD,wBAAgB,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,gBAAgB,CA4JnE"}
1
+ {"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../src/internal/discovery.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAkBH,OAAO,EAKL,KAAK,YAAY,EACjB,KAAK,gBAAgB,EASrB,KAAK,UAAU,EAwBhB,MAAM,aAAa,CAAC;AAgCrB,MAAM,WAAW,uBAAuB;IACtC,sDAAsD;IACtD,YAAY,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CAC3E;AAmBD;;;;GAIG;AACH,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CASrE;AAED,sEAAsE;AACtE,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;;GAIG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,aAAa,EAAE,CAAC,CA2B1B;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,uBAA4B,GACpC,OAAO,CAAC,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,YAAY,CAAA;CAAE,CAAC,CAAC,CA6BzD;AAED;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,uBAAuB,GAAG;IACjC,IAAI,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC;CACtB,GACL,OAAO,CAAC,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,YAAY,CAAA;CAAE,CAAC,CAAC,CAgBzD;AAWD,iFAAiF;AACjF,eAAO,MAAM,cAAc,EAAE,GAAG,CAAC,MAAM,CAIrC,CAAC;AAEH,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,uBAA4B,GACpC,OAAO,CAAC,YAAY,CAAC,CA0EvB;AAED,qEAAqE;AACrE,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAElE;AAED,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,UAAU,EAAE,GAAG,MAAM,CAOnE;AAk0BD;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAiB3E;AA88BD,wBAAgB,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,gBAAgB,CA4JnE"}
@@ -313,7 +313,7 @@ function loadAgent(ctx, agentDir, options) {
313
313
  const connections = yield loadConnections(ctx, yield resolveMcpConnectionsDir(ctx, agentDir));
314
314
  const seedFiles = yield loadSeedFiles(ctx, agentDir);
315
315
  const subagents = yield loadSubagents(ctx, join(agentDir, "subagents"));
316
- const runtime = (config === null || config === void 0 ? void 0 : config.runtime) === "cloud" ? "cloud" : "local";
316
+ const runtime = resolveRuntime(ctx, agentDir, config === null || config === void 0 ? void 0 : config.runtime);
317
317
  // Keep authored `cloud` even when default runtime is local — per-session
318
318
  // `send({ cloud })` merges it under cloudOverride for handoff sessions.
319
319
  const cloud = config === null || config === void 0 ? void 0 : config.cloud;
@@ -332,25 +332,27 @@ function loadAgent(ctx, agentDir, options) {
332
332
  const allowedTools = authoredAllowlist === undefined || authoredAllowlist.includes("mcp")
333
333
  ? authoredAllowlist
334
334
  : [...authoredAllowlist, "mcp"];
335
- // The allowlist states runtime-agnostic intent, but the SDK cannot
336
- // enforce tool restrictions on cloud agents yet a cloud-runtime agent
337
- // that declares one must fail at serve start, never run unrestricted.
338
- // (Hybrid per-send cloud sessions fail closed in the session engine.)
339
- if (allowedTools !== undefined && runtime === "cloud") {
335
+ // The allowlist states runtime-agnostic intent, but only the local
336
+ // harness can enforce it (the Cursor SDK rejects tool restrictions on
337
+ // cloud agents, and the Grok Bot harness has its own fixed toolset) — a
338
+ // non-local agent that declares one must fail at serve start, never run
339
+ // unrestricted. (Hybrid per-send cloud sessions fail closed in the
340
+ // session engine.)
341
+ if (allowedTools !== undefined && runtime !== "local") {
340
342
  ctx.diagnostics.push({
341
343
  severity: "error",
342
344
  path: displayPath(ctx, join(agentDir, "agent.ts")),
343
- message: 'tools cannot be enforced on runtime: "cloud" yet (the Cursor SDK rejects tool restrictions on cloud agents). Remove `tools` or run the agent on the local runtime.',
345
+ message: `tools cannot be enforced on runtime: "${runtime}". Remove \`tools\` or run the agent on the local runtime.`,
344
346
  });
345
347
  }
346
348
  // Per-session connection features (defineConnection auth/advertiseTools)
347
349
  // only run on local turns: advertised tools are in-process server tools,
348
350
  // and per-session headers cannot reach a cloud VM's MCP config. A
349
- // cloud-runtime agent that declares them must fail at serve start —
350
- // never run without the connection's tools or identity. (Hybrid
351
- // per-send cloud sessions fail closed in the session engine.)
351
+ // non-local agent that declares them must fail at serve start — never
352
+ // run without the connection's tools or identity. (Hybrid per-send
353
+ // cloud sessions fail closed in the session engine.)
352
354
  const perSessionConnection = connections.find((connection) => connection.advertiseTools === true || connection.auth !== undefined);
353
- if (perSessionConnection !== undefined && runtime === "cloud") {
355
+ if (perSessionConnection !== undefined && runtime !== "local") {
354
356
  ctx.diagnostics.push({
355
357
  severity: "error",
356
358
  path: displayPath(ctx, join(agentDir, "agent.ts")),
@@ -395,6 +397,19 @@ function loadAgent(ctx, agentDir, options) {
395
397
  });
396
398
  }
397
399
  appendBuiltinTools(ctx, agentDir, tools, config === null || config === void 0 ? void 0 : config.builtinTools);
400
+ // After appendBuiltinTools so opted-in built-ins (server-executed) count.
401
+ if (runtime === "grokbot") {
402
+ checkGrokBotRuntimeLimitations(ctx, agentDir, {
403
+ serverTools: tools.filter((tool) => tool.execution === "server").length,
404
+ agentTools: tools.filter((tool) => tool.execution === "agent").length,
405
+ skills: skills.length,
406
+ seedFiles: seedFiles.length,
407
+ connections: connections.length,
408
+ subagents: subagents.length,
409
+ hasCloudOptions: cloud !== undefined,
410
+ hasLocalSandbox: localSandbox,
411
+ });
412
+ }
398
413
  return Object.assign(Object.assign(Object.assign(Object.assign({ name, description: config === null || config === void 0 ? void 0 : config.description,
399
414
  // Root agents always get a concrete model: authored value or DEFAULT_MODEL.
400
415
  model: isValidModelSetting(config === null || config === void 0 ? void 0 : config.model) ? config.model : DEFAULT_MODEL, instructions,
@@ -1263,6 +1278,67 @@ function appendBuiltinTools(ctx, agentDir, tools, config) {
1263
1278
  tools.push(tool);
1264
1279
  }
1265
1280
  }
1281
+ /**
1282
+ * Validate the authored runtime. An unrecognized value is an error
1283
+ * diagnostic and falls back to local — a typo must not silently pick a
1284
+ * different harness for every turn.
1285
+ */
1286
+ function resolveRuntime(ctx, agentDir, runtime) {
1287
+ if (runtime === undefined ||
1288
+ runtime === "local" ||
1289
+ runtime === "cloud" ||
1290
+ runtime === "grokbot") {
1291
+ return runtime !== null && runtime !== void 0 ? runtime : "local";
1292
+ }
1293
+ ctx.diagnostics.push({
1294
+ severity: "error",
1295
+ path: displayPath(ctx, join(agentDir, "agent.ts")),
1296
+ message: `runtime must be "local", "cloud", or "grokbot"; got ${JSON.stringify(runtime)}.`,
1297
+ });
1298
+ return "local";
1299
+ }
1300
+ /**
1301
+ * Grok Bot turns run on the Sand harness with its own toolset: authored
1302
+ * server tools, MCP connections, and subagents have no path onto that
1303
+ * toolset yet, so an agent declaring them must fail at serve start rather
1304
+ * than run with capabilities silently missing.
1305
+ */
1306
+ function checkGrokBotRuntimeLimitations(ctx, agentDir, counts) {
1307
+ const agentPath = displayPath(ctx, join(agentDir, "agent.ts"));
1308
+ const error = (path, message) => {
1309
+ ctx.diagnostics.push({ severity: "error", path, message });
1310
+ };
1311
+ const warn = (path, message) => {
1312
+ ctx.diagnostics.push({ severity: "warning", path, message });
1313
+ };
1314
+ if (counts.serverTools > 0) {
1315
+ error(displayPath(ctx, join(agentDir, "tools")), 'Server tools (execution: "server", including opted-in builtinTools) are not reachable from grokbot turns yet. Remove them or run the agent on the local runtime.');
1316
+ }
1317
+ if (counts.connections > 0) {
1318
+ error(displayPath(ctx, join(agentDir, "mcp-connections")), "MCP connections are not wired into grokbot turns yet. Remove them or run the agent on the local runtime.");
1319
+ }
1320
+ if (counts.subagents > 0) {
1321
+ error(displayPath(ctx, join(agentDir, "subagents")), "Authored subagents are not available on grokbot turns (the Grok Bot harness runs its own subagent set). Remove them or run the agent on the local runtime.");
1322
+ }
1323
+ // The remaining declarations mirror the cloud runtime's warnings: the
1324
+ // turn runs on a hosted machine (the account's box), so local-workspace
1325
+ // materialization never reaches it.
1326
+ if (counts.agentTools > 0) {
1327
+ warn(displayPath(ctx, join(agentDir, "tools")), 'Agent tools (execution: "agent") are described in the hosted session\'s instructions (with script bodies); they are not written onto the box filesystem automatically.');
1328
+ }
1329
+ if (counts.skills > 0) {
1330
+ warn(displayPath(ctx, join(agentDir, "skills")), "Authored skills are materialized into the local session workspace only; the hosted Grok Bot box does not see them.");
1331
+ }
1332
+ if (counts.seedFiles > 0) {
1333
+ warn(displayPath(ctx, join(agentDir, "sandbox")), "sandbox/workspace seed files apply to the local session workspace only; grokbot turns run on the account's hosted box.");
1334
+ }
1335
+ if (counts.hasCloudOptions) {
1336
+ warn(agentPath, 'The `cloud` block is unused on runtime: "grokbot", and grokbot sessions refuse per-session cloud attach.');
1337
+ }
1338
+ if (counts.hasLocalSandbox) {
1339
+ warn(agentPath, 'local.sandbox does not apply to runtime: "grokbot"; the box is the account\'s Cursor-hosted computer.');
1340
+ }
1341
+ }
1266
1342
  function warnCloudRuntimeLimitations(ctx, agentDir, counts) {
1267
1343
  const agentPath = displayPath(ctx, join(agentDir, "agent.ts"));
1268
1344
  if (!counts.hasCloudOptions) {
@@ -6,10 +6,21 @@
6
6
  * resolve under the mount). `serve` auto-builds it when the local
7
7
  * vitepress toolchain is present (source checkouts); published installs
8
8
  * ship the prebuilt site inside `dist/**`.
9
+ *
10
+ * Set `AGENT_SERVE_DOCS_DIST` to an overlay directory that contains a built
11
+ * site (`index.html`). When that path exists, `/docs` is served from it so a
12
+ * long-lived host (corp ECS) can pick up the published `@cursor/july` docs
13
+ * without rebuilding the process image. Requests re-read the path, so an
14
+ * atomic symlink swap is visible without a restart.
15
+ */
16
+ /** Absolute path of the VitePress site shipped in this install (ignores overlay). */
17
+ export declare function shippedDocsDistDir(): string;
18
+ /**
19
+ * Directory `/docs` is served from. Prefers `AGENT_SERVE_DOCS_DIST` when that
20
+ * overlay has a built site; otherwise the install's `dist/docs/`.
9
21
  */
10
- /** Absolute path of the built VitePress site shipped in this install. */
11
22
  export declare function docsDistDir(): string;
12
- /** Whether `pnpm run docs:build` has produced the docs site. */
23
+ /** Whether a built docs site is available at `distDir` (overlay or shipped). */
13
24
  export declare function docsSiteExists(distDir?: string): boolean;
14
25
  /**
15
26
  * Resolve a request path under the docs mount to a file inside the built
@@ -1 +1 @@
1
- {"version":3,"file":"docs-site.d.ts","sourceRoot":"","sources":["../../src/internal/docs-site.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAeH,yEAAyE;AACzE,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED,gEAAgE;AAChE,wBAAgB,cAAc,CAAC,OAAO,GAAE,MAAsB,GAAG,OAAO,CAEvE;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE,MAAsB,GAC9B,MAAM,GAAG,SAAS,CAoBpB;AAED,+CAA+C;AAC/C,wBAAgB,cAAc,CAC5B,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE,MAAsB,GAC9B,QAAQ,CAiCV;AAED;;;;;GAKG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAkB,GAC3C,OAAO,CAAC,IAAI,CAAC,CA8Bf"}
1
+ {"version":3,"file":"docs-site.d.ts","sourceRoot":"","sources":["../../src/internal/docs-site.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AA0DH,qFAAqF;AACrF,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAED;;;GAGG;AACH,wBAAgB,WAAW,IAAI,MAAM,CAMpC;AAED,gFAAgF;AAChF,wBAAgB,cAAc,CAAC,OAAO,GAAE,MAAsB,GAAG,OAAO,CAEvE;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE,MAAsB,GAC9B,MAAM,GAAG,SAAS,CAyBpB;AAED,+CAA+C;AAC/C,wBAAgB,cAAc,CAC5B,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE,MAAsB,GAC9B,QAAQ,CAqCV;AAED;;;;;GAKG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAkB,GAC3C,OAAO,CAAC,IAAI,CAAC,CA8Bf"}
@@ -6,6 +6,12 @@
6
6
  * resolve under the mount). `serve` auto-builds it when the local
7
7
  * vitepress toolchain is present (source checkouts); published installs
8
8
  * ship the prebuilt site inside `dist/**`.
9
+ *
10
+ * Set `AGENT_SERVE_DOCS_DIST` to an overlay directory that contains a built
11
+ * site (`index.html`). When that path exists, `/docs` is served from it so a
12
+ * long-lived host (corp ECS) can pick up the published `@cursor/july` docs
13
+ * without rebuilding the process image. Requests re-read the path, so an
14
+ * atomic symlink swap is visible without a restart.
9
15
  */
10
16
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
11
17
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
@@ -17,20 +23,69 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
17
23
  });
18
24
  };
19
25
  import { spawn } from "node:child_process";
20
- import { existsSync, readFileSync, statSync } from "node:fs";
26
+ import { existsSync, readFileSync, realpathSync, statSync } from "node:fs";
21
27
  import { createRequire } from "node:module";
22
28
  import { dirname, extname, join, normalize, sep } from "node:path";
23
29
  import { fileURLToPath } from "node:url";
24
30
  import { STATIC_CONTENT_TYPES } from "./playground/static.js";
25
31
  // src|dist/internal/docs-site.ts → packages/agent-serve/dist/docs/.
26
32
  const DOCS_DIST_DIR = fileURLToPath(new URL("../../dist/docs/", import.meta.url));
27
- /** Absolute path of the built VitePress site shipped in this install. */
33
+ const DOCS_OVERLAY_ENV = "AGENT_SERVE_DOCS_DIST";
34
+ function realDir(dir) {
35
+ try {
36
+ return realpathSync(dir);
37
+ }
38
+ catch (_a) {
39
+ return undefined;
40
+ }
41
+ }
42
+ function isInsideRoot(fileReal, rootReal) {
43
+ const prefix = rootReal.endsWith(sep) ? rootReal : `${rootReal}${sep}`;
44
+ return fileReal === rootReal || fileReal.startsWith(prefix);
45
+ }
46
+ /**
47
+ * Resolve `candidate` to a regular file whose real path stays under
48
+ * `rootReal`. Follows overlay / site-root symlinks, but refuses a planted
49
+ * symlink (or hard-linked path) that escapes the docs tree.
50
+ */
51
+ function containedFile(candidate, rootReal) {
52
+ try {
53
+ const real = realpathSync(candidate);
54
+ if (!isInsideRoot(real, rootReal) || !statSync(real).isFile()) {
55
+ return undefined;
56
+ }
57
+ return real;
58
+ }
59
+ catch (_a) {
60
+ return undefined;
61
+ }
62
+ }
63
+ function hasDocsIndex(distDir) {
64
+ const root = realDir(distDir);
65
+ if (root === undefined) {
66
+ return false;
67
+ }
68
+ return containedFile(join(distDir, "index.html"), root) !== undefined;
69
+ }
70
+ /** Absolute path of the VitePress site shipped in this install (ignores overlay). */
71
+ export function shippedDocsDistDir() {
72
+ return DOCS_DIST_DIR;
73
+ }
74
+ /**
75
+ * Directory `/docs` is served from. Prefers `AGENT_SERVE_DOCS_DIST` when that
76
+ * overlay has a built site; otherwise the install's `dist/docs/`.
77
+ */
28
78
  export function docsDistDir() {
79
+ var _a;
80
+ const overlay = (_a = process.env[DOCS_OVERLAY_ENV]) === null || _a === void 0 ? void 0 : _a.trim();
81
+ if (overlay !== undefined && overlay !== "" && hasDocsIndex(overlay)) {
82
+ return overlay;
83
+ }
29
84
  return DOCS_DIST_DIR;
30
85
  }
31
- /** Whether `pnpm run docs:build` has produced the docs site. */
32
- export function docsSiteExists(distDir = DOCS_DIST_DIR) {
33
- return existsSync(join(distDir, "index.html"));
86
+ /** Whether a built docs site is available at `distDir` (overlay or shipped). */
87
+ export function docsSiteExists(distDir = docsDistDir()) {
88
+ return hasDocsIndex(distDir);
34
89
  }
35
90
  /**
36
91
  * Resolve a request path under the docs mount to a file inside the built
@@ -38,7 +93,7 @@ export function docsSiteExists(distDir = DOCS_DIST_DIR) {
38
93
  * emits one `.html` per page, so clean URLs resolve through the chain:
39
94
  * exact file → directory `index.html` → `<path>.html`.
40
95
  */
41
- export function resolveDocsFile(requestPath, distDir = DOCS_DIST_DIR) {
96
+ export function resolveDocsFile(requestPath, distDir = docsDistDir()) {
42
97
  const decoded = requestPath
43
98
  .split("/")
44
99
  .filter((part) => part !== "")
@@ -47,20 +102,25 @@ export function resolveDocsFile(requestPath, distDir = DOCS_DIST_DIR) {
47
102
  if (normalized.startsWith("..") || normalized.includes(`..${sep}`)) {
48
103
  return undefined;
49
104
  }
105
+ const rootReal = realDir(distDir);
106
+ if (rootReal === undefined) {
107
+ return undefined;
108
+ }
50
109
  const root = distDir.endsWith(sep) ? distDir : `${distDir}${sep}`;
51
110
  const base = join(root, normalized);
52
111
  if (base !== root.slice(0, -1) && !base.startsWith(root)) {
53
112
  return undefined;
54
113
  }
55
114
  for (const candidate of [base, join(base, "index.html"), `${base}.html`]) {
56
- if (existsSync(candidate) && statSync(candidate).isFile()) {
57
- return candidate;
115
+ const file = containedFile(candidate, rootReal);
116
+ if (file !== undefined) {
117
+ return file;
58
118
  }
59
119
  }
60
120
  return undefined;
61
121
  }
62
122
  /** Serve one path from the built docs site. */
63
- export function renderDocsFile(requestPath, distDir = DOCS_DIST_DIR) {
123
+ export function renderDocsFile(requestPath, distDir = docsDistDir()) {
64
124
  var _a;
65
125
  if (!docsSiteExists(distDir)) {
66
126
  return new Response(fallbackHtml(), {
@@ -70,8 +130,11 @@ export function renderDocsFile(requestPath, distDir = DOCS_DIST_DIR) {
70
130
  }
71
131
  const filePath = resolveDocsFile(requestPath, distDir);
72
132
  if (filePath === undefined) {
73
- const notFound = join(distDir, "404.html");
74
- return new Response(existsSync(notFound) ? readFileSync(notFound, "utf8") : "Not found", {
133
+ const root = realDir(distDir);
134
+ const notFound = root === undefined
135
+ ? undefined
136
+ : containedFile(join(distDir, "404.html"), root);
137
+ return new Response(notFound !== undefined ? readFileSync(notFound, "utf8") : "Not found", {
75
138
  status: 404,
76
139
  headers: { "content-type": "text/html; charset=utf-8" },
77
140
  });
@@ -98,7 +161,7 @@ export function renderDocsFile(requestPath, distDir = DOCS_DIST_DIR) {
98
161
  */
99
162
  export function ensureDocsSiteBundle() {
100
163
  return __awaiter(this, arguments, void 0, function* (logger = console.log) {
101
- if (docsSiteExists()) {
164
+ if (docsSiteExists(DOCS_DIST_DIR)) {
102
165
  return;
103
166
  }
104
167
  const toolchain = resolveDocsToolchain();
@@ -115,7 +178,7 @@ export function ensureDocsSiteBundle() {
115
178
  if (code !== 0) {
116
179
  throw new Error(`docs vitepress build failed (exit ${code})`);
117
180
  }
118
- if (!docsSiteExists()) {
181
+ if (!docsSiteExists(DOCS_DIST_DIR)) {
119
182
  throw new Error("docs vitepress build finished but dist/docs/index.html is missing");
120
183
  }
121
184
  logger("[agent-sdk] docs site build complete");
@@ -0,0 +1,61 @@
1
+ /**
2
+ * The grokbot runtime's remote client — a thin client like `"cloud"`.
3
+ * Turns execute on Cursor's hosted Grok Bot (Sand) harness (the Temporal
4
+ * turn workflow and the account's own computer), reached through the
5
+ * public `/v0/grokbot` session API.
6
+ *
7
+ * Sand delivery contract, preserved end to end: only content the agent
8
+ * delivers through SendToUser becomes the user-visible reply. The hosted
9
+ * transcript exposes those deliveries as `send-message` entries; the
10
+ * agent's internal monologue never appears in the transcript, so it can
11
+ * never leak into the session reply.
12
+ */
13
+ import type { RunnerTurnRequest, TurnOutcome } from "../../types.js";
14
+ import type { AgentRunner } from "./../sdk-runner.js";
15
+ export interface GrokBotRunnerOptions {
16
+ /** Cursor API key. Defaults to the `CURSOR_API_KEY` environment variable. */
17
+ apiKey?: string;
18
+ /** Test seam. Defaults to global fetch. */
19
+ fetchImpl?: typeof fetch;
20
+ /** Test seam. Defaults to {@link cursorBackendUrl}. */
21
+ backendUrl?: string;
22
+ /** Test seam. Poll interval while a turn runs. */
23
+ pollIntervalMs?: number;
24
+ /** Test seam. Hard turn deadline. */
25
+ turnTimeoutMs?: number;
26
+ }
27
+ /** One transcript entry as `/v0/grokbot/sessions/:id/entries` exposes it. */
28
+ export interface GrokBotEntry {
29
+ seq: string;
30
+ updatedSeq: string;
31
+ kind: string;
32
+ role?: string;
33
+ text?: string;
34
+ createdAtMs: number;
35
+ }
36
+ export declare class GrokBotRunner implements AgentRunner {
37
+ private readonly options;
38
+ /**
39
+ * One hosted Grok Bot agent per SDK agent name — the backend
40
+ * get-or-creates by name, so every SDK session forwards into the same
41
+ * hosted agent and conversation, and the Grok Bot app shows one agent
42
+ * rather than one per session.
43
+ */
44
+ private readonly agents;
45
+ /**
46
+ * Per-hosted-agent turn chain. Sessions share one hosted conversation
47
+ * and one transcript cursor, so turns run one at a time per agent:
48
+ * deliveries attribute to the turn that sent them, and an abort only
49
+ * interrupts its own turn — mirroring the hosted workflow's own queue.
50
+ */
51
+ private readonly turns;
52
+ private client;
53
+ constructor(options?: GrokBotRunnerOptions);
54
+ runTurn(request: RunnerTurnRequest): Promise<TurnOutcome>;
55
+ private executeTurn;
56
+ dispose(): Promise<void>;
57
+ private ensureClient;
58
+ private getAgent;
59
+ private sleep;
60
+ }
61
+ //# sourceMappingURL=runner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../../src/internal/grokbot/runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAErE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEtD,MAAM,WAAW,oBAAoB;IACnC,6EAA6E;IAC7E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,2CAA2C;IAC3C,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,uDAAuD;IACvD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kDAAkD;IAClD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,qCAAqC;IACrC,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,6EAA6E;AAC7E,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;CACrB;AAoID,qBAAa,aAAc,YAAW,WAAW;IAiBnC,OAAO,CAAC,QAAQ,CAAC,OAAO;IAhBpC;;;;;OAKG;IACH,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkC;IACzD;;;;;OAKG;IACH,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAuC;IAC7D,OAAO,CAAC,MAAM,CAA+B;IAE7C,YAA6B,OAAO,GAAE,oBAAyB,EAAI;IAE7D,OAAO,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,WAAW,CAAC,CAsB9D;YAEa,WAAW;IAiFnB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAI7B;IAED,OAAO,CAAC,YAAY;YAKN,QAAQ;YAyBR,KAAK;CAgBpB"}