@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.
- package/dist/bin/agent-serve.js +8 -1
- package/dist/internal/advertise-tools.d.ts.map +1 -1
- package/dist/internal/advertise-tools.js +4 -2
- package/dist/internal/cli-ax.js +1 -1
- package/dist/internal/cli-deploy.d.ts +3 -2
- package/dist/internal/cli-deploy.d.ts.map +1 -1
- package/dist/internal/cli-deploy.js +84 -9
- package/dist/internal/cli-docs.js +11 -0
- package/dist/internal/cloud-merge.d.ts +3 -1
- package/dist/internal/cloud-merge.d.ts.map +1 -1
- package/dist/internal/cloud-merge.js +10 -2
- package/dist/internal/cursor/account-mcp.d.ts.map +1 -1
- package/dist/internal/cursor/account-mcp.js +8 -4
- package/dist/internal/cursor/backend-client.d.ts +12 -0
- package/dist/internal/cursor/backend-client.d.ts.map +1 -1
- package/dist/internal/cursor/backend-client.js +27 -1
- package/dist/internal/deploy-client.d.ts +42 -1
- package/dist/internal/deploy-client.d.ts.map +1 -1
- package/dist/internal/deploy-client.js +70 -2
- package/dist/internal/discovery.d.ts.map +1 -1
- package/dist/internal/discovery.js +87 -11
- package/dist/internal/docs-site.d.ts +13 -2
- package/dist/internal/docs-site.d.ts.map +1 -1
- package/dist/internal/docs-site.js +76 -13
- package/dist/internal/grokbot/runner.d.ts +61 -0
- package/dist/internal/grokbot/runner.d.ts.map +1 -0
- package/dist/internal/grokbot/runner.js +278 -0
- package/dist/internal/mcp-endpoint.js +6 -3
- package/dist/internal/mcp-host.d.ts +14 -1
- package/dist/internal/mcp-host.d.ts.map +1 -1
- package/dist/internal/mcp-host.js +41 -2
- package/dist/internal/runtime-dispatch-runner.d.ts +30 -0
- package/dist/internal/runtime-dispatch-runner.d.ts.map +1 -0
- package/dist/internal/runtime-dispatch-runner.js +60 -0
- package/dist/internal/sdk-runner.d.ts.map +1 -1
- package/dist/internal/sdk-runner.js +7 -0
- package/dist/internal/server.d.ts.map +1 -1
- package/dist/internal/server.js +24 -1
- package/dist/internal/session-engine.d.ts +9 -2
- package/dist/internal/session-engine.d.ts.map +1 -1
- package/dist/internal/session-engine.js +121 -46
- package/dist/internal/tool-policy.d.ts +33 -1
- package/dist/internal/tool-policy.d.ts.map +1 -1
- package/dist/internal/tool-policy.js +53 -0
- package/dist/playground/assets/{index-Bqn91tW4.js → index-BmiIjFlM.js} +45 -45
- package/dist/playground/assets/index-DQGZnAI0.css +1 -0
- package/dist/playground/index.html +2 -2
- package/dist/types.d.ts +86 -2
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/skills/debug/SKILL.md +1 -2
- package/skills/framework-map/SKILL.md +1 -2
- package/src/bin/agent-serve.ts +9 -1
- package/src/internal/advertise-tools.ts +7 -0
- package/src/internal/cli-ax.ts +1 -1
- package/src/internal/cli-deploy.ts +123 -15
- package/src/internal/cli-docs.ts +11 -0
- package/src/internal/cloud-merge.ts +12 -2
- package/src/internal/cursor/account-mcp.ts +15 -1
- package/src/internal/cursor/backend-client.ts +37 -0
- package/src/internal/deploy-client.ts +122 -2
- package/src/internal/discovery.ts +133 -13
- package/src/internal/docs-site.ts +83 -13
- package/src/internal/grokbot/runner.ts +361 -0
- package/src/internal/mcp-endpoint.ts +6 -1
- package/src/internal/mcp-host.ts +48 -0
- package/src/internal/runtime-dispatch-runner.ts +63 -0
- package/src/internal/sdk-runner.ts +9 -0
- package/src/internal/server.ts +32 -4
- package/src/internal/session-engine.ts +126 -21
- package/src/internal/tool-policy.ts +80 -1
- package/src/types.ts +84 -2
- 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)
|
|
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;
|
|
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)
|
|
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
|
|
336
|
-
//
|
|
337
|
-
//
|
|
338
|
-
//
|
|
339
|
-
|
|
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:
|
|
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
|
-
//
|
|
350
|
-
//
|
|
351
|
-
//
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
32
|
-
export function docsSiteExists(distDir =
|
|
33
|
-
return
|
|
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 =
|
|
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
|
-
|
|
57
|
-
|
|
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 =
|
|
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
|
|
74
|
-
|
|
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"}
|