@cursor/july 0.1.104 → 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 (161) hide show
  1. package/dist/channels/deployments/deployments-channel.d.ts.map +1 -1
  2. package/dist/channels/deployments/deployments-channel.js +1 -0
  3. package/dist/channels/deployments/types.d.ts +2 -0
  4. package/dist/channels/deployments/types.d.ts.map +1 -1
  5. package/dist/docs/404.html +2 -2
  6. package/dist/docs/ab.html +4 -4
  7. package/dist/docs/assets/{app.DbMWUyGb.js → app.BVwaffdK.js} +1 -1
  8. package/dist/docs/assets/chunks/@localSearchIndexroot.CJxMklAy.js +1 -0
  9. package/dist/docs/assets/chunks/{VPLocalSearchBox.DcNeTh9o.js → VPLocalSearchBox.WuWTZ1x8.js} +1 -1
  10. package/dist/docs/assets/chunks/{theme.DMjhY3gl.js → theme.BYdI_6sF.js} +2 -2
  11. package/dist/docs/assets/guides_grokbot-agents.md.DVqdhBKb.js +9 -0
  12. package/dist/docs/assets/guides_grokbot-agents.md.DVqdhBKb.lean.js +1 -0
  13. package/dist/docs/assets/index.md.BW_6tOgR.js +5 -0
  14. package/dist/docs/assets/index.md.BW_6tOgR.lean.js +1 -0
  15. package/dist/docs/assets/{reference_cli.md.CJNc_xYK.js → reference_cli.md.C6Lo8SEd.js} +2 -1
  16. package/dist/docs/assets/{reference_extensions.md.DykHW3qL.js → reference_extensions.md.CGmMLblt.js} +1 -1
  17. package/dist/docs/assets/templates_grokbot-agents.md.c1s6Flp9.js +3 -0
  18. package/dist/docs/assets/templates_grokbot-agents.md.c1s6Flp9.lean.js +1 -0
  19. package/dist/docs/building-with-agents.html +4 -4
  20. package/dist/docs/concepts.html +4 -4
  21. package/dist/docs/deployment.html +4 -4
  22. package/dist/docs/evals.html +4 -4
  23. package/dist/docs/guides/agent-to-agent.html +4 -4
  24. package/dist/docs/guides/cloud-agents.html +5 -5
  25. package/dist/docs/guides/convert-automation.html +4 -4
  26. package/dist/docs/guides/github.html +4 -4
  27. package/dist/docs/guides/grokbot-agents.html +35 -0
  28. package/dist/docs/guides/grokbot-agents.md +88 -0
  29. package/dist/docs/guides/human-in-the-loop.html +4 -4
  30. package/dist/docs/guides/mcp-oauth.html +4 -4
  31. package/dist/docs/guides/opentelemetry.html +5 -5
  32. package/dist/docs/guides/slack.html +4 -4
  33. package/dist/docs/guides/webhooks.html +4 -4
  34. package/dist/docs/hashmap.json +1 -1
  35. package/dist/docs/hillclimbing.html +4 -4
  36. package/dist/docs/index.html +6 -6
  37. package/dist/docs/index.md +6 -1
  38. package/dist/docs/llms-full.txt +156 -2
  39. package/dist/docs/llms.txt +2 -0
  40. package/dist/docs/quickstart.html +4 -4
  41. package/dist/docs/reference/agent-config.html +4 -4
  42. package/dist/docs/reference/artifacts.html +4 -4
  43. package/dist/docs/reference/channels.html +4 -4
  44. package/dist/docs/reference/cli.html +7 -6
  45. package/dist/docs/reference/cli.md +2 -1
  46. package/dist/docs/reference/connections.html +4 -4
  47. package/dist/docs/reference/extensions.html +6 -6
  48. package/dist/docs/reference/extensions.md +2 -0
  49. package/dist/docs/reference/hooks.html +4 -4
  50. package/dist/docs/reference/http-api.html +4 -4
  51. package/dist/docs/reference/instructions.html +4 -4
  52. package/dist/docs/reference/playground.html +4 -4
  53. package/dist/docs/reference/project-layout.html +4 -4
  54. package/dist/docs/reference/prompt.html +4 -4
  55. package/dist/docs/reference/result.html +4 -4
  56. package/dist/docs/reference/schedules.html +4 -4
  57. package/dist/docs/reference/sessions.html +4 -4
  58. package/dist/docs/reference/skills.html +4 -4
  59. package/dist/docs/reference/subagents.html +4 -4
  60. package/dist/docs/reference/tools.html +4 -4
  61. package/dist/docs/scaffolding-agents.html +4 -4
  62. package/dist/docs/skills/ab.html +4 -4
  63. package/dist/docs/skills/create-agent.html +4 -4
  64. package/dist/docs/skills/debug.html +4 -4
  65. package/dist/docs/skills/evals.html +4 -4
  66. package/dist/docs/skills/framework-map.html +4 -4
  67. package/dist/docs/skills/github.html +4 -4
  68. package/dist/docs/skills/hillclimb.html +4 -4
  69. package/dist/docs/skills/index.html +4 -4
  70. package/dist/docs/skills/mcp-auth.html +4 -4
  71. package/dist/docs/skills/otel.html +4 -4
  72. package/dist/docs/skills/setup-slack.html +4 -4
  73. package/dist/docs/storage.html +4 -4
  74. package/dist/docs/templates/agentic-owners.html +4 -4
  75. package/dist/docs/templates/agents-md.html +4 -4
  76. package/dist/docs/templates/code-wiki.html +5 -5
  77. package/dist/docs/templates/demo.html +5 -5
  78. package/dist/docs/templates/grokbot-agents.html +29 -0
  79. package/dist/docs/templates/grokbot-agents.md +48 -0
  80. package/dist/docs/templates/pr-autofixer.html +4 -4
  81. package/dist/docs/templates/security-help.html +4 -4
  82. package/dist/docs/templates/security-reviewer.html +4 -4
  83. package/dist/docs/templates/triage.html +4 -4
  84. package/dist/docs/troubleshooting.html +4 -4
  85. package/dist/files.d.ts +7 -2
  86. package/dist/files.d.ts.map +1 -1
  87. package/dist/files.js +7 -2
  88. package/dist/internal/cursor-agent-template.d.ts +1 -1
  89. package/dist/internal/cursor-agent-template.d.ts.map +1 -1
  90. package/dist/internal/cursor-agent-template.js +1 -0
  91. package/dist/internal/framework-file-storage.d.ts +3 -1
  92. package/dist/internal/framework-file-storage.d.ts.map +1 -1
  93. package/dist/internal/framework-file-storage.js +3 -1
  94. package/dist/internal/hosted-delivery.d.ts +7 -0
  95. package/dist/internal/hosted-delivery.d.ts.map +1 -1
  96. package/dist/internal/hosted-delivery.js +29 -1
  97. package/dist/internal/hosted-managed-automation.d.ts.map +1 -1
  98. package/dist/internal/hosted-managed-automation.js +27 -2
  99. package/dist/internal/init-project.d.ts.map +1 -1
  100. package/dist/internal/init-project.js +4 -1
  101. package/dist/internal/sdk-runner.d.ts +12 -0
  102. package/dist/internal/sdk-runner.d.ts.map +1 -1
  103. package/dist/internal/sdk-runner.js +18 -0
  104. package/dist/internal/server.d.ts.map +1 -1
  105. package/dist/internal/server.js +11 -3
  106. package/dist/internal/session-engine.d.ts +8 -0
  107. package/dist/internal/session-engine.d.ts.map +1 -1
  108. package/dist/internal/session-engine.js +132 -52
  109. package/dist/internal/store-mirror.d.ts +2 -2
  110. package/dist/internal/store-mirror.js +2 -2
  111. package/dist/internal/tenant-slack/relay.d.ts +2 -0
  112. package/dist/internal/tenant-slack/relay.d.ts.map +1 -1
  113. package/dist/internal/tenant-slack/relay.js +18 -8
  114. package/dist/internal/workspace-sync.d.ts +31 -6
  115. package/dist/internal/workspace-sync.d.ts.map +1 -1
  116. package/dist/internal/workspace-sync.js +67 -12
  117. package/dist/internal/workspace.d.ts +9 -0
  118. package/dist/internal/workspace.d.ts.map +1 -1
  119. package/dist/internal/workspace.js +16 -0
  120. package/dist/playground/assets/{index-8YiozU89.js → index-BaQzjaNK.js} +36 -36
  121. package/dist/playground/assets/index-CceqnLTX.css +1 -0
  122. package/dist/playground/index.html +2 -2
  123. package/dist/types.d.ts +9 -8
  124. package/dist/types.d.ts.map +1 -1
  125. package/docs/README.md +6 -1
  126. package/docs/guides/grokbot-agents.md +93 -0
  127. package/docs/reference/cli.md +2 -1
  128. package/docs/reference/extensions.md +2 -0
  129. package/docs/templates/grokbot-agents.md +53 -0
  130. package/package.json +10 -1
  131. package/src/channels/deployments/deployments-channel.ts +1 -0
  132. package/src/channels/deployments/types.ts +2 -0
  133. package/src/files.ts +9 -2
  134. package/src/internal/cursor-agent-template.ts +1 -0
  135. package/src/internal/framework-file-storage.ts +3 -1
  136. package/src/internal/hosted-delivery.ts +53 -1
  137. package/src/internal/hosted-managed-automation.ts +49 -5
  138. package/src/internal/init-project.ts +4 -1
  139. package/src/internal/sdk-runner.ts +19 -0
  140. package/src/internal/server.ts +16 -0
  141. package/src/internal/session-engine.ts +168 -56
  142. package/src/internal/store-mirror.ts +2 -2
  143. package/src/internal/tenant-slack/relay.ts +28 -4
  144. package/src/internal/workspace-sync.ts +84 -12
  145. package/src/internal/workspace.ts +20 -0
  146. package/src/types.ts +9 -8
  147. package/templates/grokbot-agents/README.md +26 -0
  148. package/templates/grokbot-agents/agent/agent.ts +6 -0
  149. package/templates/grokbot-agents/agent/extensions/grokbot.ts +5 -0
  150. package/templates/grokbot-agents/agent/instructions.md +7 -0
  151. package/templates/grokbot-agents/evals/evals.config.ts +5 -0
  152. package/templates/grokbot-agents/evals/grokbot-agents.eval.ts +18 -0
  153. package/templates/grokbot-agents/init.json +18 -0
  154. package/templates/grokbot-agents/package.json +17 -0
  155. package/templates/grokbot-agents/tsconfig.json +12 -0
  156. package/dist/docs/assets/chunks/@localSearchIndexroot.Bqsulb9K.js +0 -1
  157. package/dist/docs/assets/index.md.D75GWhPl.js +0 -5
  158. package/dist/docs/assets/index.md.D75GWhPl.lean.js +0 -1
  159. package/dist/playground/assets/index-MbMxXg-y.css +0 -1
  160. /package/dist/docs/assets/{reference_cli.md.CJNc_xYK.lean.js → reference_cli.md.C6Lo8SEd.lean.js} +0 -0
  161. /package/dist/docs/assets/{reference_extensions.md.DykHW3qL.lean.js → reference_extensions.md.CGmMLblt.lean.js} +0 -0
@@ -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,
@@ -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
@@ -1926,8 +1926,9 @@ export interface SessionRecord {
1926
1926
  */
1927
1927
  workspaceOverride?: string;
1928
1928
  /**
1929
- * One-shot files to write into the harness cwd before the next turn
1930
- * (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.
1931
1932
  */
1932
1933
  pendingWorkspaceFiles?: Record<
1933
1934
  string,
@@ -2112,12 +2113,12 @@ export interface SendMessageOptions {
2112
2113
  */
2113
2114
  workspaceDir?: string;
2114
2115
  /**
2115
- * Relative path → contents written into the session harness cwd after
2116
- * scaffold materialize and before the next turn. On create, queued for
2117
- * the first turn; on resume, replaces any pending files. Prefer this
2118
- * over {@link workspaceDir} when you only need to inject a few
2119
- * host-prepared files (skills/AGENTS.md still land in the normal
2120
- * 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
2121
2122
  * `{ encoding: "base64", data }` blobs (Slack attachments, binary docs).
2122
2123
  */
2123
2124
  workspaceFiles?: Record<
@@ -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
+ }