cyrus-cursor-runner 0.2.49 → 0.2.50
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/CursorRunner.d.ts +25 -26
- package/dist/CursorRunner.d.ts.map +1 -1
- package/dist/CursorRunner.js +615 -1147
- package/dist/CursorRunner.js.map +1 -1
- package/dist/formatter.d.ts.map +1 -1
- package/dist/formatter.js +5 -0
- package/dist/formatter.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/permission-check.mjs +178 -0
- package/dist/permissions.d.ts +45 -0
- package/dist/permissions.d.ts.map +1 -0
- package/dist/permissions.js +278 -0
- package/dist/permissions.js.map +1 -0
- package/dist/sandbox.d.ts +64 -0
- package/dist/sandbox.d.ts.map +1 -0
- package/dist/sandbox.js +143 -0
- package/dist/sandbox.js.map +1 -0
- package/dist/types.d.ts +19 -11
- package/dist/types.d.ts.map +1 -1
- package/package.json +5 -4
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
// Translates Cyrus / Claude-style tool patterns into the simpler pattern
|
|
2
|
+
// vocabulary that the .cursor/cyrus-permission-check.mjs hook understands.
|
|
3
|
+
//
|
|
4
|
+
// Cyrus tool patterns look like (Claude SDK conventions):
|
|
5
|
+
// Read(<glob>) Bash(<cmd>:<args>)
|
|
6
|
+
// Write(<glob>) mcp__<server>__<tool>
|
|
7
|
+
// Edit(<glob>) Read | Bash | Edit | Write (bare tool name)
|
|
8
|
+
//
|
|
9
|
+
// Cursor hook patterns look like:
|
|
10
|
+
// Read(<glob>)
|
|
11
|
+
// Write(<glob>)
|
|
12
|
+
// Shell(<cmd>) / Shell(<cmd>:<args-glob>)
|
|
13
|
+
// Mcp(<server>:<tool>)
|
|
14
|
+
// Tool(<Name>)
|
|
15
|
+
import { readdirSync } from "node:fs";
|
|
16
|
+
import { join, parse as pathParse, resolve } from "node:path";
|
|
17
|
+
function parseToolPattern(pattern) {
|
|
18
|
+
const trimmed = pattern.trim();
|
|
19
|
+
if (!trimmed)
|
|
20
|
+
return null;
|
|
21
|
+
const match = trimmed.match(/^([A-Za-z][A-Za-z0-9_]*)(?:\((.*)\))?$/);
|
|
22
|
+
if (!match)
|
|
23
|
+
return null;
|
|
24
|
+
return {
|
|
25
|
+
name: match[1] || "",
|
|
26
|
+
argument: match[2]?.trim() ?? null,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function normalizeShellCommandBase(argument) {
|
|
30
|
+
if (!argument)
|
|
31
|
+
return null;
|
|
32
|
+
const firstRule = argument.split(",")[0]?.trim();
|
|
33
|
+
if (!firstRule)
|
|
34
|
+
return null;
|
|
35
|
+
if (firstRule === "*" || firstRule === "**")
|
|
36
|
+
return "*";
|
|
37
|
+
const beforeColon = firstRule.split(":")[0]?.trim();
|
|
38
|
+
return beforeColon || null;
|
|
39
|
+
}
|
|
40
|
+
function normalizeShellArgsGlob(argument) {
|
|
41
|
+
if (!argument)
|
|
42
|
+
return null;
|
|
43
|
+
const firstRule = argument.split(",")[0]?.trim();
|
|
44
|
+
if (!firstRule)
|
|
45
|
+
return null;
|
|
46
|
+
const colonIdx = firstRule.indexOf(":");
|
|
47
|
+
if (colonIdx < 0)
|
|
48
|
+
return null;
|
|
49
|
+
const args = firstRule.slice(colonIdx + 1).trim();
|
|
50
|
+
return args || null;
|
|
51
|
+
}
|
|
52
|
+
function mapMcpPattern(pattern) {
|
|
53
|
+
const trimmed = pattern.trim();
|
|
54
|
+
if (!trimmed.toLowerCase().startsWith("mcp__"))
|
|
55
|
+
return null;
|
|
56
|
+
const parts = trimmed.split("__");
|
|
57
|
+
if (parts.length < 2)
|
|
58
|
+
return null;
|
|
59
|
+
const server = parts[1]?.trim() || "*";
|
|
60
|
+
const tool = parts.length >= 3 ? parts.slice(2).join("__").trim() || "*" : "*";
|
|
61
|
+
return `Mcp(${server}:${tool})`;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Map a single Cyrus/Claude tool pattern into zero or more Cursor hook
|
|
65
|
+
* patterns. Returns an empty array for unrecognized patterns.
|
|
66
|
+
*/
|
|
67
|
+
function mapToolPatternToHookPatterns(pattern) {
|
|
68
|
+
const mcp = mapMcpPattern(pattern);
|
|
69
|
+
if (mcp)
|
|
70
|
+
return [mcp];
|
|
71
|
+
const parsed = parseToolPattern(pattern);
|
|
72
|
+
if (!parsed)
|
|
73
|
+
return [];
|
|
74
|
+
const name = parsed.name.toLowerCase();
|
|
75
|
+
const arg = parsed.argument;
|
|
76
|
+
// Bare tool names (no parentheses) mean "allow this tool unrestricted" in
|
|
77
|
+
// Claude SDK semantics. We must emit BOTH the preToolUse gate (`Tool(...)`)
|
|
78
|
+
// AND the path/command-level gate (`Read(**)`, `Write(**)`, `Shell(*)`),
|
|
79
|
+
// otherwise the SDK passes preToolUse but stops the actual file/shell
|
|
80
|
+
// hook because nothing in the allow list matches the path/command.
|
|
81
|
+
if (!arg) {
|
|
82
|
+
if (name === "bash" || name === "shell") {
|
|
83
|
+
return ["Tool(Shell)", "Shell(*)"];
|
|
84
|
+
}
|
|
85
|
+
if (name === "read" || name === "glob" || name === "grep") {
|
|
86
|
+
return ["Tool(Read)", "Read(**)"];
|
|
87
|
+
}
|
|
88
|
+
if (name === "edit" ||
|
|
89
|
+
name === "write" ||
|
|
90
|
+
name === "multiedit" ||
|
|
91
|
+
name === "notebookedit" ||
|
|
92
|
+
name === "todowrite") {
|
|
93
|
+
return ["Tool(Write)", "Write(**)"];
|
|
94
|
+
}
|
|
95
|
+
// Pass-through for unrecognized bare names — only the preToolUse gate
|
|
96
|
+
// applies; SDK does not have a path-level hook for these.
|
|
97
|
+
const cap = parsed.name.charAt(0).toUpperCase() + parsed.name.slice(1);
|
|
98
|
+
return [`Tool(${cap})`];
|
|
99
|
+
}
|
|
100
|
+
if (name === "bash" || name === "shell") {
|
|
101
|
+
const base = normalizeShellCommandBase(arg);
|
|
102
|
+
const argsGlob = normalizeShellArgsGlob(arg);
|
|
103
|
+
const out = [];
|
|
104
|
+
if (base) {
|
|
105
|
+
out.push(`Shell(${base})`);
|
|
106
|
+
if (argsGlob)
|
|
107
|
+
out.push(`Shell(${base}:${argsGlob})`);
|
|
108
|
+
}
|
|
109
|
+
return out;
|
|
110
|
+
}
|
|
111
|
+
if (name === "read" || name === "glob" || name === "grep") {
|
|
112
|
+
return [`Read(${arg})`];
|
|
113
|
+
}
|
|
114
|
+
if (name === "edit" ||
|
|
115
|
+
name === "write" ||
|
|
116
|
+
name === "multiedit" ||
|
|
117
|
+
name === "notebookedit" ||
|
|
118
|
+
name === "todowrite") {
|
|
119
|
+
return [`Write(${arg})`];
|
|
120
|
+
}
|
|
121
|
+
// Unknown — drop silently. Caller can log if needed.
|
|
122
|
+
return [];
|
|
123
|
+
}
|
|
124
|
+
function isWildcardArg(argument) {
|
|
125
|
+
if (!argument)
|
|
126
|
+
return true;
|
|
127
|
+
const trimmed = argument.trim();
|
|
128
|
+
return trimmed.length === 0 || trimmed === "**";
|
|
129
|
+
}
|
|
130
|
+
function isBroadReadPattern(pattern) {
|
|
131
|
+
const parsed = parseToolPattern(pattern);
|
|
132
|
+
if (!parsed)
|
|
133
|
+
return false;
|
|
134
|
+
const n = parsed.name.toLowerCase();
|
|
135
|
+
if (!(n === "read" || n === "glob" || n === "grep"))
|
|
136
|
+
return false;
|
|
137
|
+
return isWildcardArg(parsed.argument);
|
|
138
|
+
}
|
|
139
|
+
function isBroadWritePattern(pattern) {
|
|
140
|
+
const parsed = parseToolPattern(pattern);
|
|
141
|
+
if (!parsed)
|
|
142
|
+
return false;
|
|
143
|
+
const n = parsed.name.toLowerCase();
|
|
144
|
+
if (!(n === "edit" ||
|
|
145
|
+
n === "write" ||
|
|
146
|
+
n === "multiedit" ||
|
|
147
|
+
n === "notebookedit" ||
|
|
148
|
+
n === "todowrite")) {
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
return isWildcardArg(parsed.argument);
|
|
152
|
+
}
|
|
153
|
+
function toCursorPath(path) {
|
|
154
|
+
return path.replace(/\\/g, "/");
|
|
155
|
+
}
|
|
156
|
+
function buildWorkspaceSiblingDenyPatterns(workspacePath, permission) {
|
|
157
|
+
const resolvedWorkspacePath = resolve(workspacePath);
|
|
158
|
+
const parsed = pathParse(resolvedWorkspacePath);
|
|
159
|
+
if (!parsed.root)
|
|
160
|
+
return [];
|
|
161
|
+
const segments = resolvedWorkspacePath
|
|
162
|
+
.slice(parsed.root.length)
|
|
163
|
+
.split(/[\\/]+/)
|
|
164
|
+
.filter(Boolean);
|
|
165
|
+
if (segments.length === 0)
|
|
166
|
+
return [];
|
|
167
|
+
const denies = new Set();
|
|
168
|
+
let parentPath = parsed.root;
|
|
169
|
+
for (const segment of segments) {
|
|
170
|
+
let entries;
|
|
171
|
+
try {
|
|
172
|
+
entries = readdirSync(parentPath, { withFileTypes: true });
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
for (const sibling of entries) {
|
|
178
|
+
if (!sibling.isDirectory() || sibling.name === segment)
|
|
179
|
+
continue;
|
|
180
|
+
const siblingPath = join(parentPath, sibling.name);
|
|
181
|
+
denies.add(`${permission}(${toCursorPath(siblingPath)}/**)`);
|
|
182
|
+
}
|
|
183
|
+
parentPath = join(parentPath, segment);
|
|
184
|
+
}
|
|
185
|
+
return [...denies];
|
|
186
|
+
}
|
|
187
|
+
function buildSystemRootDenyPatterns(workspacePath, permission) {
|
|
188
|
+
const workspace = toCursorPath(resolve(workspacePath));
|
|
189
|
+
const rootCandidates = [
|
|
190
|
+
"/etc",
|
|
191
|
+
"/bin",
|
|
192
|
+
"/sbin",
|
|
193
|
+
"/usr",
|
|
194
|
+
"/opt",
|
|
195
|
+
"/System",
|
|
196
|
+
"/Library",
|
|
197
|
+
"/Applications",
|
|
198
|
+
"/dev",
|
|
199
|
+
"/proc",
|
|
200
|
+
"/sys",
|
|
201
|
+
"/Volumes",
|
|
202
|
+
"/home",
|
|
203
|
+
];
|
|
204
|
+
const denies = [];
|
|
205
|
+
for (const rootPath of rootCandidates) {
|
|
206
|
+
if (workspace === rootPath || workspace.startsWith(`${rootPath}/`))
|
|
207
|
+
continue;
|
|
208
|
+
denies.push(`${permission}(${rootPath}/**)`);
|
|
209
|
+
}
|
|
210
|
+
return denies;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Auto-deny patterns that protect the host system and worktree siblings
|
|
214
|
+
* whenever a session has broad Read/Write permissions. Mirrors the same
|
|
215
|
+
* scoping the old CLI-based runner applied via .cursor/cli.json.
|
|
216
|
+
*/
|
|
217
|
+
export function buildAutoDenyPatterns(args) {
|
|
218
|
+
const { workspace, allowedTools = [] } = args;
|
|
219
|
+
if (!workspace)
|
|
220
|
+
return [];
|
|
221
|
+
const denies = new Set();
|
|
222
|
+
if (allowedTools.some(isBroadReadPattern)) {
|
|
223
|
+
for (const p of buildWorkspaceSiblingDenyPatterns(workspace, "Read"))
|
|
224
|
+
denies.add(p);
|
|
225
|
+
for (const p of buildSystemRootDenyPatterns(workspace, "Read"))
|
|
226
|
+
denies.add(p);
|
|
227
|
+
}
|
|
228
|
+
if (allowedTools.some(isBroadWritePattern)) {
|
|
229
|
+
for (const p of buildWorkspaceSiblingDenyPatterns(workspace, "Write"))
|
|
230
|
+
denies.add(p);
|
|
231
|
+
for (const p of buildSystemRootDenyPatterns(workspace, "Write"))
|
|
232
|
+
denies.add(p);
|
|
233
|
+
}
|
|
234
|
+
return [...denies];
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Build the final permissions config that ships into the worktree
|
|
238
|
+
* alongside the permission-check helper. Returns deduplicated
|
|
239
|
+
* allow/deny pattern lists in Cursor hook syntax.
|
|
240
|
+
*/
|
|
241
|
+
export function buildCyrusPermissionsConfig(args) {
|
|
242
|
+
const { workspace, allowedTools = [], disallowedTools = [], mcpServers: mcpServersIn = {}, } = args;
|
|
243
|
+
const allow = new Set();
|
|
244
|
+
for (const pattern of allowedTools) {
|
|
245
|
+
for (const mapped of mapToolPatternToHookPatterns(pattern)) {
|
|
246
|
+
allow.add(mapped);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
const deny = new Set();
|
|
250
|
+
for (const pattern of disallowedTools) {
|
|
251
|
+
for (const mapped of mapToolPatternToHookPatterns(pattern)) {
|
|
252
|
+
deny.add(mapped);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
for (const pattern of buildAutoDenyPatterns({ workspace, allowedTools })) {
|
|
256
|
+
deny.add(pattern);
|
|
257
|
+
}
|
|
258
|
+
const mcpServers = [];
|
|
259
|
+
for (const [name, server] of Object.entries(mcpServersIn)) {
|
|
260
|
+
if (!server || typeof server !== "object")
|
|
261
|
+
continue;
|
|
262
|
+
if (typeof server.url === "string" && server.url) {
|
|
263
|
+
mcpServers.push({ name, url: server.url });
|
|
264
|
+
}
|
|
265
|
+
else if (typeof server.command === "string" && server.command) {
|
|
266
|
+
const argv = Array.isArray(server.args) ? server.args : [];
|
|
267
|
+
const commandLine = [server.command, ...argv].join(" ").trim();
|
|
268
|
+
mcpServers.push({ name, commandLine });
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
return {
|
|
272
|
+
workspace: resolve(workspace),
|
|
273
|
+
allow: [...allow],
|
|
274
|
+
deny: [...deny],
|
|
275
|
+
mcpServers,
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
//# sourceMappingURL=permissions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permissions.js","sourceRoot":"","sources":["../src/permissions.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Subset of `@anthropic-ai/claude-agent-sdk`'s `SandboxSettings` we know how
|
|
3
|
+
* to translate. Defined locally (not imported) to avoid a hard dep on
|
|
4
|
+
* cyrus-claude-runner — the EdgeWorker is the only consumer that originates
|
|
5
|
+
* a SandboxSettings, and a structural type is enough.
|
|
6
|
+
*/
|
|
7
|
+
export interface CursorSandboxInput {
|
|
8
|
+
enabled?: boolean;
|
|
9
|
+
failIfUnavailable?: boolean;
|
|
10
|
+
allowUnsandboxedCommands?: boolean;
|
|
11
|
+
network?: {
|
|
12
|
+
allowedDomains?: string[];
|
|
13
|
+
deniedDomains?: string[];
|
|
14
|
+
allowManagedDomainsOnly?: boolean;
|
|
15
|
+
httpProxyPort?: number;
|
|
16
|
+
socksProxyPort?: number;
|
|
17
|
+
};
|
|
18
|
+
filesystem?: {
|
|
19
|
+
allowWrite?: string[];
|
|
20
|
+
denyWrite?: string[];
|
|
21
|
+
denyRead?: string[];
|
|
22
|
+
allowRead?: string[];
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
export interface CursorSandboxJson {
|
|
26
|
+
type: "workspace_readwrite" | "workspace_readonly" | "insecure_none";
|
|
27
|
+
additionalReadwritePaths: string[];
|
|
28
|
+
additionalReadonlyPaths: string[];
|
|
29
|
+
disableTmpWrite: boolean;
|
|
30
|
+
enableSharedBuildCache: boolean;
|
|
31
|
+
networkPolicy: {
|
|
32
|
+
default: "allow" | "deny";
|
|
33
|
+
allow: string[];
|
|
34
|
+
deny: string[];
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
export interface BuildSandboxArgs {
|
|
38
|
+
workspace: string;
|
|
39
|
+
sandboxSettings?: CursorSandboxInput;
|
|
40
|
+
/** Path to a CA cert bundle for MITM TLS interception by the egress proxy. */
|
|
41
|
+
egressCaCertPath?: string;
|
|
42
|
+
/**
|
|
43
|
+
* Extra paths Cursor's sandbox should treat as read+write (e.g. attachments
|
|
44
|
+
* dir, additional repository paths in multi-repo issues). Workspace itself
|
|
45
|
+
* is implicit in `workspace_readwrite`; pass only the *extras*.
|
|
46
|
+
*/
|
|
47
|
+
additionalReadwritePaths?: string[];
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Returns the JSON document to write to `<workspace>/.cursor/sandbox.json`
|
|
51
|
+
* when sandbox is enabled. Returns `null` when sandbox is disabled.
|
|
52
|
+
*/
|
|
53
|
+
export declare function buildCursorSandboxJson(args: BuildSandboxArgs): CursorSandboxJson | null;
|
|
54
|
+
/**
|
|
55
|
+
* Returns the env vars to set on `process.env` (so child shell tools inherit
|
|
56
|
+
* them) before invoking `agent.send`. These cover:
|
|
57
|
+
* - cert-trust env vars when an egress CA bundle is configured
|
|
58
|
+
* - HTTP_PROXY / HTTPS_PROXY / ALL_PROXY when the egress proxy is configured
|
|
59
|
+
*/
|
|
60
|
+
export declare function buildSandboxEnv(args: {
|
|
61
|
+
sandboxSettings?: CursorSandboxInput;
|
|
62
|
+
egressCaCertPath?: string;
|
|
63
|
+
}): Record<string, string>;
|
|
64
|
+
//# sourceMappingURL=sandbox.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sandbox.d.ts","sourceRoot":"","sources":["../src/sandbox.ts"],"names":[],"mappings":"AAkCA;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IAClC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC,OAAO,CAAC,EAAE;QACT,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;QAC1B,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;QACzB,uBAAuB,CAAC,EAAE,OAAO,CAAC;QAClC,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,cAAc,CAAC,EAAE,MAAM,CAAC;KACxB,CAAC;IACF,UAAU,CAAC,EAAE;QACZ,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;QACtB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;QACrB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;QACpB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;KACrB,CAAC;CACF;AAED,MAAM,WAAW,iBAAiB;IACjC,IAAI,EAAE,qBAAqB,GAAG,oBAAoB,GAAG,eAAe,CAAC;IACrE,wBAAwB,EAAE,MAAM,EAAE,CAAC;IACnC,uBAAuB,EAAE,MAAM,EAAE,CAAC;IAClC,eAAe,EAAE,OAAO,CAAC;IACzB,sBAAsB,EAAE,OAAO,CAAC;IAChC,aAAa,EAAE;QACd,OAAO,EAAE,OAAO,GAAG,MAAM,CAAC;QAC1B,KAAK,EAAE,MAAM,EAAE,CAAC;QAChB,IAAI,EAAE,MAAM,EAAE,CAAC;KACf,CAAC;CACF;AAED,MAAM,WAAW,gBAAgB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,kBAAkB,CAAC;IACrC,8EAA8E;IAC9E,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;;OAIG;IACH,wBAAwB,CAAC,EAAE,MAAM,EAAE,CAAC;CACpC;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CACrC,IAAI,EAAE,gBAAgB,GACpB,iBAAiB,GAAG,IAAI,CAqE1B;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE;IACrC,eAAe,CAAC,EAAE,kBAAkB,CAAC;IACrC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC1B,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAgCzB"}
|
package/dist/sandbox.js
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
// Translates the Cyrus / Claude `SandboxSettings` shape into the Cursor SDK's
|
|
2
|
+
// `.cursor/sandbox.json` schema (plus the env vars that need to be set on
|
|
3
|
+
// `process.env` so child shell tools inherit cert-trust + proxy hints).
|
|
4
|
+
//
|
|
5
|
+
// Cursor sandbox model summary (validated via learning tests on
|
|
6
|
+
// `@cursor/sdk@1.0.11`):
|
|
7
|
+
// - `local.sandboxOptions: { enabled: true }` engages Apple Seatbelt on
|
|
8
|
+
// macOS / Landlock+Bubblewrap on Linux via the bundled `cursorsandbox`
|
|
9
|
+
// helper (auto-discovered from `@cursor/sdk-<platform>-<arch>`).
|
|
10
|
+
// - Default policy `workspace_readwrite`: workspace + /tmp are writable,
|
|
11
|
+
// filesystem-wide read is allowed, off-workspace writes blocked, network
|
|
12
|
+
// blocked unless `.cursor/sandbox.json` allows hosts.
|
|
13
|
+
// - `.cursor/sandbox.json` lets us extend the policy with extra
|
|
14
|
+
// read/write paths and a deny-default network allowlist.
|
|
15
|
+
//
|
|
16
|
+
// Mapping from Claude `SandboxSettings`:
|
|
17
|
+
// filesystem.allowWrite[] -> additionalReadwritePaths
|
|
18
|
+
// filesystem.allowRead[] -> additionalReadonlyPaths
|
|
19
|
+
// network.allowedDomains[] -> networkPolicy.allow
|
|
20
|
+
// network.deniedDomains[] -> networkPolicy.deny
|
|
21
|
+
// network.httpProxyPort -> add 127.0.0.1 to allow + HTTP_PROXY env
|
|
22
|
+
// network.socksProxyPort -> add 127.0.0.1 to allow + ALL_PROXY env
|
|
23
|
+
// egressCaCertPath -> NODE_EXTRA_CA_CERTS / SSL_CERT_FILE / ... env
|
|
24
|
+
//
|
|
25
|
+
// Limitations (Cursor SDK lacks per-path deny under workspace_readwrite,
|
|
26
|
+
// per-call filesystem hooks, etc.):
|
|
27
|
+
// - filesystem.denyRead / denyWrite are accepted but not enforced.
|
|
28
|
+
// Document via comments; rely on workspace_readwrite default + hook
|
|
29
|
+
// helper for read-blocking sensitive paths.
|
|
30
|
+
// - network.allowAllUnixSockets / allowMachLookup / allowLocalBinding:
|
|
31
|
+
// not exposed by Cursor sandbox.json; default sandbox behavior applies.
|
|
32
|
+
import { resolve } from "node:path";
|
|
33
|
+
/**
|
|
34
|
+
* Returns the JSON document to write to `<workspace>/.cursor/sandbox.json`
|
|
35
|
+
* when sandbox is enabled. Returns `null` when sandbox is disabled.
|
|
36
|
+
*/
|
|
37
|
+
export function buildCursorSandboxJson(args) {
|
|
38
|
+
const { workspace, sandboxSettings, egressCaCertPath } = args;
|
|
39
|
+
if (!sandboxSettings?.enabled)
|
|
40
|
+
return null;
|
|
41
|
+
const extraWrite = new Set();
|
|
42
|
+
const extraRead = new Set();
|
|
43
|
+
const allow = new Set();
|
|
44
|
+
const deny = new Set();
|
|
45
|
+
for (const p of args.additionalReadwritePaths ?? []) {
|
|
46
|
+
if (p && resolve(p) !== resolve(workspace))
|
|
47
|
+
extraWrite.add(resolve(p));
|
|
48
|
+
}
|
|
49
|
+
const fs = sandboxSettings.filesystem;
|
|
50
|
+
if (fs?.allowWrite) {
|
|
51
|
+
for (const p of fs.allowWrite) {
|
|
52
|
+
if (!p)
|
|
53
|
+
continue;
|
|
54
|
+
const abs = resolve(p);
|
|
55
|
+
if (abs !== resolve(workspace))
|
|
56
|
+
extraWrite.add(abs);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if (fs?.allowRead) {
|
|
60
|
+
for (const p of fs.allowRead) {
|
|
61
|
+
if (!p)
|
|
62
|
+
continue;
|
|
63
|
+
// "." is the workspace shorthand; ignore it because Cursor's
|
|
64
|
+
// `workspace_readwrite` already grants workspace reads.
|
|
65
|
+
if (p === ".")
|
|
66
|
+
continue;
|
|
67
|
+
extraRead.add(resolve(p));
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
// Cursor's sandbox.json doesn't support denyRead/denyWrite under
|
|
71
|
+
// workspace_readwrite. Documented limitation. (Hook-based per-path
|
|
72
|
+
// reads can compensate when needed via `.cursor/hooks.json`.)
|
|
73
|
+
const network = sandboxSettings.network;
|
|
74
|
+
if (network?.allowedDomains)
|
|
75
|
+
for (const d of network.allowedDomains)
|
|
76
|
+
allow.add(d);
|
|
77
|
+
if (network?.deniedDomains)
|
|
78
|
+
for (const d of network.deniedDomains)
|
|
79
|
+
deny.add(d);
|
|
80
|
+
// When the Cyrus egress proxy is in use, child shell processes need to be
|
|
81
|
+
// able to reach the loopback proxy port. Add 127.0.0.1 / ::1 to the
|
|
82
|
+
// network allow-list so curl / npm / git can connect to it.
|
|
83
|
+
if (typeof network?.httpProxyPort === "number" ||
|
|
84
|
+
typeof network?.socksProxyPort === "number") {
|
|
85
|
+
allow.add("127.0.0.1");
|
|
86
|
+
allow.add("::1");
|
|
87
|
+
allow.add("localhost");
|
|
88
|
+
}
|
|
89
|
+
// Read access to the CA cert bundle path so child processes can read
|
|
90
|
+
// it via NODE_EXTRA_CA_CERTS / SSL_CERT_FILE etc.
|
|
91
|
+
if (egressCaCertPath)
|
|
92
|
+
extraRead.add(resolve(egressCaCertPath));
|
|
93
|
+
return {
|
|
94
|
+
type: "workspace_readwrite",
|
|
95
|
+
additionalReadwritePaths: [...extraWrite].sort(),
|
|
96
|
+
additionalReadonlyPaths: [...extraRead].sort(),
|
|
97
|
+
disableTmpWrite: false,
|
|
98
|
+
enableSharedBuildCache: false,
|
|
99
|
+
networkPolicy: {
|
|
100
|
+
default: "deny",
|
|
101
|
+
allow: [...allow].sort(),
|
|
102
|
+
deny: [...deny].sort(),
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Returns the env vars to set on `process.env` (so child shell tools inherit
|
|
108
|
+
* them) before invoking `agent.send`. These cover:
|
|
109
|
+
* - cert-trust env vars when an egress CA bundle is configured
|
|
110
|
+
* - HTTP_PROXY / HTTPS_PROXY / ALL_PROXY when the egress proxy is configured
|
|
111
|
+
*/
|
|
112
|
+
export function buildSandboxEnv(args) {
|
|
113
|
+
const { sandboxSettings, egressCaCertPath } = args;
|
|
114
|
+
const env = {};
|
|
115
|
+
if (!sandboxSettings?.enabled)
|
|
116
|
+
return env;
|
|
117
|
+
if (egressCaCertPath) {
|
|
118
|
+
env.NODE_EXTRA_CA_CERTS = egressCaCertPath; // Node.js (SDK, npm, etc.)
|
|
119
|
+
env.SSL_CERT_FILE = egressCaCertPath; // OpenSSL (general fallback)
|
|
120
|
+
env.GIT_SSL_CAINFO = egressCaCertPath; // Git HTTPS
|
|
121
|
+
env.REQUESTS_CA_BUNDLE = egressCaCertPath; // Python requests
|
|
122
|
+
env.PIP_CERT = egressCaCertPath; // pip
|
|
123
|
+
env.CURL_CA_BUNDLE = egressCaCertPath; // curl (OpenSSL builds)
|
|
124
|
+
env.CARGO_HTTP_CAINFO = egressCaCertPath; // Rust / cargo
|
|
125
|
+
env.AWS_CA_BUNDLE = egressCaCertPath; // AWS CLI / boto3
|
|
126
|
+
env.DENO_CERT = egressCaCertPath; // Deno
|
|
127
|
+
}
|
|
128
|
+
const network = sandboxSettings.network;
|
|
129
|
+
if (typeof network?.httpProxyPort === "number") {
|
|
130
|
+
const url = `http://127.0.0.1:${network.httpProxyPort}`;
|
|
131
|
+
env.HTTP_PROXY = url;
|
|
132
|
+
env.HTTPS_PROXY = url;
|
|
133
|
+
env.http_proxy = url;
|
|
134
|
+
env.https_proxy = url;
|
|
135
|
+
}
|
|
136
|
+
if (typeof network?.socksProxyPort === "number") {
|
|
137
|
+
const url = `socks5://127.0.0.1:${network.socksProxyPort}`;
|
|
138
|
+
env.ALL_PROXY = url;
|
|
139
|
+
env.all_proxy = url;
|
|
140
|
+
}
|
|
141
|
+
return env;
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=sandbox.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sandbox.js","sourceRoot":"","sources":["../src/sandbox.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,24 +1,32 @@
|
|
|
1
1
|
import type { AgentRunnerConfig, AgentSessionInfo, SDKMessage } from "cyrus-core";
|
|
2
|
-
|
|
2
|
+
import type { CursorSandboxInput } from "./sandbox.js";
|
|
3
3
|
export interface CursorRunnerConfig extends AgentRunnerConfig {
|
|
4
|
-
/**
|
|
5
|
-
cursorPath?: string;
|
|
6
|
-
/** API key override for Cursor CLI authentication */
|
|
4
|
+
/** API key for Cursor SDK authentication (falls back to CURSOR_API_KEY env). */
|
|
7
5
|
cursorApiKey?: string;
|
|
8
|
-
/**
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
6
|
+
/**
|
|
7
|
+
* Sandbox settings, structurally compatible with Cyrus / Claude SDK
|
|
8
|
+
* `SandboxSettings`. When `enabled: true`, the runner engages Cursor's
|
|
9
|
+
* `local.sandboxOptions` and writes a `.cursor/sandbox.json` policy
|
|
10
|
+
* mirroring `filesystem.allowRead/Write` and `network.allowed/deniedDomains`.
|
|
11
|
+
* If the Cyrus egress proxy is active (`network.httpProxyPort` set), the
|
|
12
|
+
* runner also adds `127.0.0.1` to the network allow-list and sets the
|
|
13
|
+
* proxy env vars on `process.env` so child shell tools route through it.
|
|
14
|
+
*/
|
|
15
|
+
sandboxSettings?: CursorSandboxInput;
|
|
16
|
+
/**
|
|
17
|
+
* Path to the egress proxy CA cert bundle. When set, the runner exports
|
|
18
|
+
* `NODE_EXTRA_CA_CERTS`, `SSL_CERT_FILE`, etc. into `process.env` so
|
|
19
|
+
* sandboxed child processes trust the MITM-intercepting proxy.
|
|
20
|
+
*/
|
|
21
|
+
egressCaCertPath?: string;
|
|
14
22
|
}
|
|
15
23
|
export interface CursorSessionInfo extends AgentSessionInfo {
|
|
24
|
+
/** The SDK agentId (local-prefix `agent-<uuid>`). */
|
|
16
25
|
sessionId: string | null;
|
|
17
26
|
}
|
|
18
27
|
export interface CursorRunnerEvents {
|
|
19
28
|
message: (message: SDKMessage) => void;
|
|
20
29
|
error: (error: Error) => void;
|
|
21
30
|
complete: (messages: SDKMessage[]) => void;
|
|
22
|
-
streamEvent: (event: CursorJsonEvent) => void;
|
|
23
31
|
}
|
|
24
32
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,iBAAiB,EACjB,gBAAgB,EAChB,UAAU,EACV,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,iBAAiB,EACjB,gBAAgB,EAChB,UAAU,EACV,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAEvD,MAAM,WAAW,kBAAmB,SAAQ,iBAAiB;IAC5D,gFAAgF;IAChF,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;;;;;;OAQG;IACH,eAAe,CAAC,EAAE,kBAAkB,CAAC;IAErC;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,iBAAkB,SAAQ,gBAAgB;IAC1D,qDAAqD;IACrD,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED,MAAM,WAAW,kBAAkB;IAClC,OAAO,EAAE,CAAC,OAAO,EAAE,UAAU,KAAK,IAAI,CAAC;IACvC,KAAK,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAC9B,QAAQ,EAAE,CAAC,QAAQ,EAAE,UAAU,EAAE,KAAK,IAAI,CAAC;CAC3C"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cyrus-cursor-runner",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.50",
|
|
4
4
|
"description": "Cursor Agent CLI process wrapper for Cyrus",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -9,8 +9,9 @@
|
|
|
9
9
|
"dist"
|
|
10
10
|
],
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"
|
|
13
|
-
"cyrus-
|
|
12
|
+
"@cursor/sdk": "^1.0.11",
|
|
13
|
+
"cyrus-core": "0.2.50",
|
|
14
|
+
"cyrus-simple-agent-runner": "0.2.50"
|
|
14
15
|
},
|
|
15
16
|
"devDependencies": {
|
|
16
17
|
"@types/node": "^20.0.0",
|
|
@@ -21,7 +22,7 @@
|
|
|
21
22
|
"access": "public"
|
|
22
23
|
},
|
|
23
24
|
"scripts": {
|
|
24
|
-
"build": "tsc",
|
|
25
|
+
"build": "tsc && node -e \"require('node:fs').copyFileSync('src/permission-check.mjs', 'dist/permission-check.mjs')\"",
|
|
25
26
|
"dev": "tsc --watch",
|
|
26
27
|
"test": "node ../../node_modules/.pnpm/node_modules/vitest/vitest.mjs",
|
|
27
28
|
"test:run": "node ../../node_modules/.pnpm/node_modules/vitest/vitest.mjs run --passWithNoTests",
|