dtc-mcp 0.2.0 → 1.0.0
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/README.md +169 -402
- package/data/docs.json +4338 -0
- package/dist/docs/loader.d.ts +40 -0
- package/dist/docs/loader.js +110 -0
- package/dist/docs/loader.js.map +1 -0
- package/dist/docs/search.d.ts +47 -0
- package/dist/docs/search.js +101 -0
- package/dist/docs/search.js.map +1 -0
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/sandbox/bridge.d.ts +2 -0
- package/dist/sandbox/bridge.js +101 -0
- package/dist/sandbox/bridge.js.map +1 -0
- package/dist/sandbox/node-discovery.d.ts +7 -0
- package/dist/sandbox/node-discovery.js +228 -0
- package/dist/sandbox/node-discovery.js.map +1 -0
- package/dist/sandbox/protocol.d.ts +76 -0
- package/dist/sandbox/protocol.js +20 -0
- package/dist/sandbox/protocol.js.map +1 -0
- package/dist/sandbox/proxy-template.d.ts +19 -0
- package/dist/sandbox/proxy-template.js +83 -0
- package/dist/sandbox/proxy-template.js.map +1 -0
- package/dist/sandbox/runner.d.ts +20 -0
- package/dist/sandbox/runner.js +99 -0
- package/dist/sandbox/runner.js.map +1 -0
- package/dist/sandbox/sandbox-helpers.d.ts +14 -0
- package/dist/sandbox/sandbox-helpers.js +98 -0
- package/dist/sandbox/sandbox-helpers.js.map +1 -0
- package/dist/sandbox/sidecar/index.d.ts +16 -0
- package/dist/sandbox/sidecar/index.js +346 -0
- package/dist/sandbox/sidecar/index.js.map +1 -0
- package/dist/sandbox/sidecar-runner.d.ts +32 -0
- package/dist/sandbox/sidecar-runner.js +325 -0
- package/dist/sandbox/sidecar-runner.js.map +1 -0
- package/dist/sandbox/timeout.d.ts +16 -0
- package/dist/sandbox/timeout.js +38 -0
- package/dist/sandbox/timeout.js.map +1 -0
- package/dist/sandbox/vm-runner.d.ts +35 -0
- package/dist/sandbox/vm-runner.js +182 -0
- package/dist/sandbox/vm-runner.js.map +1 -0
- package/dist/sdk/klaviyo/host.d.ts +43 -0
- package/dist/sdk/klaviyo/host.js +218 -0
- package/dist/sdk/klaviyo/host.js.map +1 -0
- package/dist/sdk/shopify/host.d.ts +23 -0
- package/dist/sdk/shopify/host.js +175 -0
- package/dist/sdk/shopify/host.js.map +1 -0
- package/dist/server.js +7 -7
- package/dist/server.js.map +1 -1
- package/dist/shared/errors.d.ts +0 -14
- package/dist/shared/errors.js +0 -73
- package/dist/shared/errors.js.map +1 -1
- package/dist/{platforms/klaviyo/tools.d.ts → tools/execute_code.d.ts} +1 -1
- package/dist/tools/execute_code.js +70 -0
- package/dist/tools/execute_code.js.map +1 -0
- package/dist/{platforms/shopify/tools.d.ts → tools/read_doc.d.ts} +1 -1
- package/dist/tools/read_doc.js +70 -0
- package/dist/tools/read_doc.js.map +1 -0
- package/dist/tools/search_docs.d.ts +2 -0
- package/dist/tools/search_docs.js +55 -0
- package/dist/tools/search_docs.js.map +1 -0
- package/package.json +16 -5
- package/dist/cross-platform/correlator.d.ts +0 -10
- package/dist/cross-platform/correlator.js +0 -166
- package/dist/cross-platform/correlator.js.map +0 -1
- package/dist/cross-platform/tools.d.ts +0 -2
- package/dist/cross-platform/tools.js +0 -30
- package/dist/cross-platform/tools.js.map +0 -1
- package/dist/platforms/klaviyo/client.d.ts +0 -91
- package/dist/platforms/klaviyo/client.js +0 -389
- package/dist/platforms/klaviyo/client.js.map +0 -1
- package/dist/platforms/klaviyo/tools.js +0 -363
- package/dist/platforms/klaviyo/tools.js.map +0 -1
- package/dist/platforms/klaviyo/transforms.d.ts +0 -59
- package/dist/platforms/klaviyo/transforms.js +0 -326
- package/dist/platforms/klaviyo/transforms.js.map +0 -1
- package/dist/platforms/shopify/client.d.ts +0 -51
- package/dist/platforms/shopify/client.js +0 -352
- package/dist/platforms/shopify/client.js.map +0 -1
- package/dist/platforms/shopify/tools.js +0 -368
- package/dist/platforms/shopify/tools.js.map +0 -1
- package/dist/platforms/shopify/transforms.d.ts +0 -83
- package/dist/platforms/shopify/transforms.js +0 -308
- package/dist/platforms/shopify/transforms.js.map +0 -1
- package/dist/shared/pagination.d.ts +0 -21
- package/dist/shared/pagination.js +0 -36
- package/dist/shared/pagination.js.map +0 -1
- package/dist/shared/types.d.ts +0 -318
- package/dist/shared/types.js +0 -3
- package/dist/shared/types.js.map +0 -1
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JS source for the output-discipline helpers that get injected into the
|
|
3
|
+
* sandbox global scope. Same code runs in both runners (node:vm and
|
|
4
|
+
* isolated-vm) — keeping this as a single string source-of-truth means the
|
|
5
|
+
* behavior the LLM observes is identical regardless of which runner is
|
|
6
|
+
* actually executing.
|
|
7
|
+
*
|
|
8
|
+
* Why these helpers exist: Stainless's published benchmark caps factuality
|
|
9
|
+
* at 53% across all code-mode MCPs, with the model "tending toward verbose
|
|
10
|
+
* responses beyond what's strictly necessary." These helpers give the LLM
|
|
11
|
+
* a vocabulary to project / aggregate / trim raw API responses before
|
|
12
|
+
* returning, and the docs explicitly point at them.
|
|
13
|
+
*/
|
|
14
|
+
export const SANDBOX_HELPERS_SOURCE = `
|
|
15
|
+
/**
|
|
16
|
+
* pick(value, schema) — projection over deep objects + arrays.
|
|
17
|
+
*
|
|
18
|
+
* schema is a partial mirror of value's shape; truthy leaves are kept.
|
|
19
|
+
* pick({a:1,b:2,c:{x:3,y:4}}, {a:true, c:{x:true}}) → {a:1, c:{x:3}}
|
|
20
|
+
*
|
|
21
|
+
* Arrays inherit the schema for each element:
|
|
22
|
+
* pick([{a:1,b:2}, {a:3,b:4}], {a:true}) → [{a:1}, {a:3}]
|
|
23
|
+
*/
|
|
24
|
+
globalThis.pick = function pick(value, schema) {
|
|
25
|
+
if (value === null || value === undefined) return value;
|
|
26
|
+
if (Array.isArray(value)) return value.map((item) => pick(item, schema));
|
|
27
|
+
if (typeof value !== 'object') return value;
|
|
28
|
+
if (schema === true) return value;
|
|
29
|
+
if (!schema || typeof schema !== 'object') return undefined;
|
|
30
|
+
const out = {};
|
|
31
|
+
for (const key of Object.keys(schema)) {
|
|
32
|
+
if (!(key in value)) continue;
|
|
33
|
+
const subSchema = schema[key];
|
|
34
|
+
if (subSchema === true) {
|
|
35
|
+
out[key] = value[key];
|
|
36
|
+
} else if (subSchema && typeof subSchema === 'object') {
|
|
37
|
+
out[key] = pick(value[key], subSchema);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return out;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* topN(arr, n, by) — top N items by a numeric key (descending).
|
|
45
|
+
* topN([{revenue: 10}, {revenue: 30}, {revenue: 20}], 2, 'revenue')
|
|
46
|
+
* → [{revenue: 30}, {revenue: 20}]
|
|
47
|
+
*
|
|
48
|
+
* by can be a string (property name) or a function (custom comparator value).
|
|
49
|
+
*/
|
|
50
|
+
globalThis.topN = function topN(arr, n, by) {
|
|
51
|
+
if (!Array.isArray(arr)) return [];
|
|
52
|
+
const keyFn = typeof by === 'function' ? by : (item) => (item == null ? 0 : item[by] ?? 0);
|
|
53
|
+
return [...arr]
|
|
54
|
+
.map((item) => ({ item, key: Number(keyFn(item)) || 0 }))
|
|
55
|
+
.sort((a, b) => b.key - a.key)
|
|
56
|
+
.slice(0, n)
|
|
57
|
+
.map((entry) => entry.item);
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* summarize(arr, opts) — auto-summarize an array. Returns:
|
|
62
|
+
* { count, top?, total?, avg?, min?, max? }
|
|
63
|
+
*
|
|
64
|
+
* Options:
|
|
65
|
+
* - by: string | (item) => number — the numeric field to aggregate
|
|
66
|
+
* - topN: number — also return the top N items by 'by' (default: omitted)
|
|
67
|
+
* - total: boolean — include sum (default: true when 'by' is set)
|
|
68
|
+
* - stats: boolean — include avg/min/max (default: true when 'by' is set)
|
|
69
|
+
*/
|
|
70
|
+
globalThis.summarize = function summarize(arr, opts) {
|
|
71
|
+
opts = opts || {};
|
|
72
|
+
if (!Array.isArray(arr)) {
|
|
73
|
+
return { count: 0 };
|
|
74
|
+
}
|
|
75
|
+
const result = { count: arr.length };
|
|
76
|
+
if (opts.by !== undefined) {
|
|
77
|
+
const keyFn = typeof opts.by === 'function' ? opts.by : (item) => (item == null ? 0 : item[opts.by] ?? 0);
|
|
78
|
+
const values = arr.map((item) => Number(keyFn(item)) || 0);
|
|
79
|
+
const wantTotal = opts.total !== false;
|
|
80
|
+
const wantStats = opts.stats !== false;
|
|
81
|
+
if (wantTotal) {
|
|
82
|
+
result.total = values.reduce((s, v) => s + v, 0);
|
|
83
|
+
}
|
|
84
|
+
if (wantStats && values.length > 0) {
|
|
85
|
+
result.min = Math.min(...values);
|
|
86
|
+
result.max = Math.max(...values);
|
|
87
|
+
result.avg = result.total !== undefined
|
|
88
|
+
? result.total / values.length
|
|
89
|
+
: values.reduce((s, v) => s + v, 0) / values.length;
|
|
90
|
+
}
|
|
91
|
+
if (opts.topN && opts.topN > 0) {
|
|
92
|
+
result.top = topN(arr, opts.topN, opts.by);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return result;
|
|
96
|
+
};
|
|
97
|
+
`.trim();
|
|
98
|
+
//# sourceMappingURL=sandbox-helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sandbox-helpers.js","sourceRoot":"","sources":["../../src/sandbox/sandbox-helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,MAAM,CAAC,MAAM,sBAAsB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmFrC,CAAC,IAAI,EAAE,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sidecar entrypoint — spawned by the main MCP server as a child Node process.
|
|
3
|
+
*
|
|
4
|
+
* Why it exists: Claude Desktop is Electron with hardened runtime + Library
|
|
5
|
+
* Validation, which refuses to dlopen native modules whose code signature
|
|
6
|
+
* doesn't share Anthropic's Team ID. `isolated-vm` therefore can't be loaded
|
|
7
|
+
* directly inside the main MCP server. A child process spawned from the
|
|
8
|
+
* user's system `node` binary has no such restriction, so we load
|
|
9
|
+
* isolated-vm here and proxy execute requests to/from main via stdio.
|
|
10
|
+
*
|
|
11
|
+
* Protocol: newline-delimited JSON, see ../protocol.ts.
|
|
12
|
+
* stdin ← MainToSidecar messages
|
|
13
|
+
* stdout → SidecarToMain messages
|
|
14
|
+
* stderr → diagnostic logs only (not protocol)
|
|
15
|
+
*/
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sidecar entrypoint — spawned by the main MCP server as a child Node process.
|
|
3
|
+
*
|
|
4
|
+
* Why it exists: Claude Desktop is Electron with hardened runtime + Library
|
|
5
|
+
* Validation, which refuses to dlopen native modules whose code signature
|
|
6
|
+
* doesn't share Anthropic's Team ID. `isolated-vm` therefore can't be loaded
|
|
7
|
+
* directly inside the main MCP server. A child process spawned from the
|
|
8
|
+
* user's system `node` binary has no such restriction, so we load
|
|
9
|
+
* isolated-vm here and proxy execute requests to/from main via stdio.
|
|
10
|
+
*
|
|
11
|
+
* Protocol: newline-delimited JSON, see ../protocol.ts.
|
|
12
|
+
* stdin ← MainToSidecar messages
|
|
13
|
+
* stdout → SidecarToMain messages
|
|
14
|
+
* stderr → diagnostic logs only (not protocol)
|
|
15
|
+
*/
|
|
16
|
+
import { createInterface } from "node:readline";
|
|
17
|
+
import { SANDBOX_HELPERS_SOURCE } from "../sandbox-helpers.js";
|
|
18
|
+
function send(msg) {
|
|
19
|
+
process.stdout.write(JSON.stringify(msg) + "\n");
|
|
20
|
+
}
|
|
21
|
+
function logErr(line) {
|
|
22
|
+
process.stderr.write(`[sidecar] ${line}\n`);
|
|
23
|
+
}
|
|
24
|
+
// Step 1: try to load isolated-vm. If this throws, we tell main and exit so it
|
|
25
|
+
// can fall back to the in-process node:vm runner.
|
|
26
|
+
let ivmModule;
|
|
27
|
+
try {
|
|
28
|
+
ivmModule = await import("isolated-vm").then((m) => m.default ?? m);
|
|
29
|
+
}
|
|
30
|
+
catch (e) {
|
|
31
|
+
send({
|
|
32
|
+
type: "fatal",
|
|
33
|
+
reason: `isolated-vm load failed: ${e instanceof Error ? e.message : String(e)}`,
|
|
34
|
+
});
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
const ivm = ivmModule;
|
|
38
|
+
const ivmVersion = ivmModule.version ?? "unknown";
|
|
39
|
+
// Step 2: emit ready. Main will follow with an `init` message giving us the
|
|
40
|
+
// method-path registry to mirror into the isolate's globals.
|
|
41
|
+
send({ type: "ready", ivmVersion });
|
|
42
|
+
let methodPaths = [];
|
|
43
|
+
let proxyScript = null;
|
|
44
|
+
// Track host-call resolves per (execId, callId). Each isolate execute can fan
|
|
45
|
+
// out many host calls in parallel (Promise.all in user code), so we need
|
|
46
|
+
// per-call resolution rather than per-execute.
|
|
47
|
+
const pendingHostCalls = new Map();
|
|
48
|
+
// ---- Stateful session ----
|
|
49
|
+
//
|
|
50
|
+
// One isolate per sidecar process = one MCP connection. Bootstrap runs once;
|
|
51
|
+
// each execute reuses the same context so user variables (`globalThis.x =
|
|
52
|
+
// ...`) persist across calls. After 30 min idle the isolate is disposed and
|
|
53
|
+
// the next execute recreates it with `sessionReset: true` in the result.
|
|
54
|
+
const IDLE_TTL_MS = 30 * 60_000;
|
|
55
|
+
const HEAP_LIMIT_MB = 256;
|
|
56
|
+
let session = null;
|
|
57
|
+
let idleTimer = null;
|
|
58
|
+
// Pulls the current execute's id so the host-call bridge can tag outbound
|
|
59
|
+
// messages. Set in handleExecute before user code runs.
|
|
60
|
+
let currentExecId = null;
|
|
61
|
+
const rl = createInterface({ input: process.stdin, crlfDelay: Infinity });
|
|
62
|
+
rl.on("line", (line) => {
|
|
63
|
+
if (!line.trim())
|
|
64
|
+
return;
|
|
65
|
+
let msg;
|
|
66
|
+
try {
|
|
67
|
+
msg = JSON.parse(line);
|
|
68
|
+
}
|
|
69
|
+
catch (e) {
|
|
70
|
+
logErr(`bad JSON from main: ${e instanceof Error ? e.message : String(e)}`);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
switch (msg.type) {
|
|
74
|
+
case "init":
|
|
75
|
+
handleInit(msg);
|
|
76
|
+
break;
|
|
77
|
+
case "execute":
|
|
78
|
+
void handleExecute(msg);
|
|
79
|
+
break;
|
|
80
|
+
case "host-result":
|
|
81
|
+
handleHostResult(msg);
|
|
82
|
+
break;
|
|
83
|
+
case "shutdown":
|
|
84
|
+
process.exit(0);
|
|
85
|
+
break;
|
|
86
|
+
default:
|
|
87
|
+
logErr(`unknown msg type: ${msg.type}`);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
rl.on("close", () => {
|
|
91
|
+
// Stdin closed → main process is gone or shutting us down. Exit cleanly.
|
|
92
|
+
process.exit(0);
|
|
93
|
+
});
|
|
94
|
+
function handleInit(msg) {
|
|
95
|
+
methodPaths = msg.methodPaths;
|
|
96
|
+
proxyScript = buildIsolateProxyScript(methodPaths);
|
|
97
|
+
}
|
|
98
|
+
function handleHostResult(msg) {
|
|
99
|
+
const key = `${msg.execId}:${msg.callId}`;
|
|
100
|
+
const resolver = pendingHostCalls.get(key);
|
|
101
|
+
if (!resolver) {
|
|
102
|
+
logErr(`stale host-result for ${key}`);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
pendingHostCalls.delete(key);
|
|
106
|
+
resolver(msg.resultJson);
|
|
107
|
+
}
|
|
108
|
+
async function ensureSession() {
|
|
109
|
+
if (session && !session.isolate.isDisposed) {
|
|
110
|
+
refreshIdleTimer();
|
|
111
|
+
return { wasReset: false };
|
|
112
|
+
}
|
|
113
|
+
if (!proxyScript) {
|
|
114
|
+
throw new Error("Sidecar not initialized (missing init message)");
|
|
115
|
+
}
|
|
116
|
+
logErr("creating new isolate session");
|
|
117
|
+
const isolate = new ivm.Isolate({ memoryLimit: HEAP_LIMIT_MB });
|
|
118
|
+
const context = await isolate.createContext();
|
|
119
|
+
const jail = context.global;
|
|
120
|
+
await jail.set("global", jail.derefInto());
|
|
121
|
+
// The host-bridge Reference is installed ONCE on the persistent context.
|
|
122
|
+
// It reads currentExecId at call time so calls across executes get tagged
|
|
123
|
+
// with their owning execute's id.
|
|
124
|
+
const invokeRef = new ivm.Reference(async (path, argsJson) => {
|
|
125
|
+
const execId = currentExecId;
|
|
126
|
+
if (!execId) {
|
|
127
|
+
return `__ERROR__host call made outside of an execute context`;
|
|
128
|
+
}
|
|
129
|
+
const s = session;
|
|
130
|
+
if (!s) {
|
|
131
|
+
return `__ERROR__session unavailable`;
|
|
132
|
+
}
|
|
133
|
+
const callId = `c${s.callCounter++}`;
|
|
134
|
+
const key = `${execId}:${callId}`;
|
|
135
|
+
const promise = new Promise((resolveCall) => {
|
|
136
|
+
pendingHostCalls.set(key, resolveCall);
|
|
137
|
+
});
|
|
138
|
+
send({
|
|
139
|
+
type: "host-call",
|
|
140
|
+
execId,
|
|
141
|
+
callId,
|
|
142
|
+
path,
|
|
143
|
+
argsJson,
|
|
144
|
+
});
|
|
145
|
+
return promise;
|
|
146
|
+
});
|
|
147
|
+
await jail.set("__host_invoke", invokeRef);
|
|
148
|
+
// Bootstrap: install proxy + console capture + sandbox helpers. Runs once.
|
|
149
|
+
const bootstrap = await isolate.compileScript(proxyScript);
|
|
150
|
+
await bootstrap.run(context);
|
|
151
|
+
session = { isolate, context, callCounter: 0 };
|
|
152
|
+
refreshIdleTimer();
|
|
153
|
+
return { wasReset: true };
|
|
154
|
+
}
|
|
155
|
+
function refreshIdleTimer() {
|
|
156
|
+
if (idleTimer)
|
|
157
|
+
clearTimeout(idleTimer);
|
|
158
|
+
idleTimer = setTimeout(() => {
|
|
159
|
+
logErr("idle TTL hit; disposing isolate");
|
|
160
|
+
disposeSession();
|
|
161
|
+
}, IDLE_TTL_MS);
|
|
162
|
+
idleTimer.unref?.();
|
|
163
|
+
}
|
|
164
|
+
function disposeSession() {
|
|
165
|
+
if (idleTimer) {
|
|
166
|
+
clearTimeout(idleTimer);
|
|
167
|
+
idleTimer = null;
|
|
168
|
+
}
|
|
169
|
+
if (session) {
|
|
170
|
+
try {
|
|
171
|
+
session.isolate.dispose();
|
|
172
|
+
}
|
|
173
|
+
catch {
|
|
174
|
+
// already disposed
|
|
175
|
+
}
|
|
176
|
+
session = null;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
async function handleExecute(msg) {
|
|
180
|
+
const start = Date.now();
|
|
181
|
+
let wasReset = false;
|
|
182
|
+
try {
|
|
183
|
+
({ wasReset } = await ensureSession());
|
|
184
|
+
}
|
|
185
|
+
catch (e) {
|
|
186
|
+
send({
|
|
187
|
+
type: "execute-result",
|
|
188
|
+
id: msg.id,
|
|
189
|
+
ok: false,
|
|
190
|
+
error: e instanceof Error ? e.message : String(e),
|
|
191
|
+
stdout: [],
|
|
192
|
+
durationMs: Date.now() - start,
|
|
193
|
+
});
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
const s = session;
|
|
197
|
+
if (!s) {
|
|
198
|
+
send({
|
|
199
|
+
type: "execute-result",
|
|
200
|
+
id: msg.id,
|
|
201
|
+
ok: false,
|
|
202
|
+
error: "session disposed before execute could run",
|
|
203
|
+
stdout: [],
|
|
204
|
+
durationMs: Date.now() - start,
|
|
205
|
+
});
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
currentExecId = msg.id;
|
|
209
|
+
try {
|
|
210
|
+
// Reset stdout for this call; user-declared globals on `globalThis`
|
|
211
|
+
// persist across calls (the whole point of stateful sessions).
|
|
212
|
+
// Strip TS in the main process before sending — we don't ship sucrase
|
|
213
|
+
// to the sidecar (see sidecar-runner.ts).
|
|
214
|
+
const wrapped = `
|
|
215
|
+
(async () => {
|
|
216
|
+
__resetStdout();
|
|
217
|
+
const __result = await (async () => {
|
|
218
|
+
${msg.code}
|
|
219
|
+
})();
|
|
220
|
+
return JSON.stringify({
|
|
221
|
+
result: __result === undefined ? null : __result,
|
|
222
|
+
stdout: __getStdout(),
|
|
223
|
+
});
|
|
224
|
+
})();
|
|
225
|
+
`;
|
|
226
|
+
const userScript = await s.isolate.compileScript(wrapped);
|
|
227
|
+
const resultJson = (await userScript.run(s.context, {
|
|
228
|
+
timeout: msg.timeoutMs,
|
|
229
|
+
promise: true,
|
|
230
|
+
}));
|
|
231
|
+
const parsed = JSON.parse(resultJson);
|
|
232
|
+
send({
|
|
233
|
+
type: "execute-result",
|
|
234
|
+
id: msg.id,
|
|
235
|
+
ok: true,
|
|
236
|
+
resultJson: JSON.stringify(parsed.result ?? null),
|
|
237
|
+
stdout: parsed.stdout,
|
|
238
|
+
durationMs: Date.now() - start,
|
|
239
|
+
...(wasReset ? { sessionReset: true } : {}),
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
catch (e) {
|
|
243
|
+
const msgStr = e instanceof Error ? e.message : String(e);
|
|
244
|
+
const isTimeout = msgStr.includes("Script execution timed out");
|
|
245
|
+
const isOOM = msgStr.includes("memory") || msgStr.includes("Array buffer allocation");
|
|
246
|
+
// Memory limit kills the isolate. Drop the session so the next call
|
|
247
|
+
// builds a fresh one (the LLM will see sessionReset on it).
|
|
248
|
+
if (isOOM) {
|
|
249
|
+
disposeSession();
|
|
250
|
+
}
|
|
251
|
+
send({
|
|
252
|
+
type: "execute-result",
|
|
253
|
+
id: msg.id,
|
|
254
|
+
ok: false,
|
|
255
|
+
error: isTimeout
|
|
256
|
+
? `Code timed out after ${msg.timeoutMs}ms. Add \`// @timeout 2m\` (max 5m) at the top of your code to extend.`
|
|
257
|
+
: msgStr,
|
|
258
|
+
stdout: [],
|
|
259
|
+
durationMs: Date.now() - start,
|
|
260
|
+
...(wasReset ? { sessionReset: true } : {}),
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
finally {
|
|
264
|
+
currentExecId = null;
|
|
265
|
+
// Don't dispose the isolate — that's the whole point of stateful sessions.
|
|
266
|
+
// Clean up any orphaned pending host calls for this execute.
|
|
267
|
+
for (const key of pendingHostCalls.keys()) {
|
|
268
|
+
if (key.startsWith(`${msg.id}:`))
|
|
269
|
+
pendingHostCalls.delete(key);
|
|
270
|
+
}
|
|
271
|
+
refreshIdleTimer();
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Build the JS that runs INSIDE the isolated-vm isolate. Different from the
|
|
276
|
+
* node:vm proxy template because isolated-vm requires Reference.apply with
|
|
277
|
+
* explicit `arguments.copy` / `result.promise` options to cross the isolate
|
|
278
|
+
* boundary. Args travel as JSON strings to avoid prototype-chain leaks.
|
|
279
|
+
*/
|
|
280
|
+
function buildIsolateProxyScript(paths) {
|
|
281
|
+
const tree = {};
|
|
282
|
+
for (const path of paths) {
|
|
283
|
+
const segments = path.split(".");
|
|
284
|
+
let cursor = tree;
|
|
285
|
+
for (let i = 0; i < segments.length - 1; i++) {
|
|
286
|
+
const key = segments[i];
|
|
287
|
+
if (typeof cursor[key] !== "object")
|
|
288
|
+
cursor[key] = {};
|
|
289
|
+
cursor = cursor[key];
|
|
290
|
+
}
|
|
291
|
+
cursor[segments[segments.length - 1]] = path;
|
|
292
|
+
}
|
|
293
|
+
function emit(node) {
|
|
294
|
+
const parts = [];
|
|
295
|
+
for (const [key, value] of Object.entries(node)) {
|
|
296
|
+
if (typeof value === "string") {
|
|
297
|
+
parts.push(`${JSON.stringify(key)}: (...args) => __invoke(${JSON.stringify(value)}, args)`);
|
|
298
|
+
}
|
|
299
|
+
else {
|
|
300
|
+
parts.push(`${JSON.stringify(key)}: ${emit(value)}`);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
return `{${parts.join(",")}}`;
|
|
304
|
+
}
|
|
305
|
+
return `
|
|
306
|
+
(function () {
|
|
307
|
+
const __invoke = async function (path, args) {
|
|
308
|
+
const argsJson = JSON.stringify(args);
|
|
309
|
+
const resultJson = await __host_invoke.apply(undefined, [path, argsJson], {
|
|
310
|
+
arguments: { copy: false },
|
|
311
|
+
result: { promise: true }
|
|
312
|
+
});
|
|
313
|
+
if (typeof resultJson === 'string' && resultJson.startsWith('__ERROR__')) {
|
|
314
|
+
throw new Error(resultJson.slice(9));
|
|
315
|
+
}
|
|
316
|
+
return resultJson ? JSON.parse(resultJson) : undefined;
|
|
317
|
+
};
|
|
318
|
+
|
|
319
|
+
const __stdout = [];
|
|
320
|
+
globalThis.console = {
|
|
321
|
+
log: (...args) => {
|
|
322
|
+
__stdout.push(args.map((a) => typeof a === 'string' ? a : JSON.stringify(a)).join(' '));
|
|
323
|
+
},
|
|
324
|
+
error: (...args) => {
|
|
325
|
+
__stdout.push('[err] ' + args.map((a) => typeof a === 'string' ? a : JSON.stringify(a)).join(' '));
|
|
326
|
+
},
|
|
327
|
+
warn: (...args) => {
|
|
328
|
+
__stdout.push('[warn] ' + args.map((a) => typeof a === 'string' ? a : JSON.stringify(a)).join(' '));
|
|
329
|
+
},
|
|
330
|
+
info: (...args) => {
|
|
331
|
+
__stdout.push(args.map((a) => typeof a === 'string' ? a : JSON.stringify(a)).join(' '));
|
|
332
|
+
},
|
|
333
|
+
};
|
|
334
|
+
globalThis.__getStdout = () => __stdout;
|
|
335
|
+
globalThis.__resetStdout = () => { __stdout.length = 0; };
|
|
336
|
+
|
|
337
|
+
const __sdk = ${emit(tree)};
|
|
338
|
+
for (const k of Object.keys(__sdk)) {
|
|
339
|
+
globalThis[k] = __sdk[k];
|
|
340
|
+
}
|
|
341
|
+
})();
|
|
342
|
+
|
|
343
|
+
${SANDBOX_HELPERS_SOURCE}
|
|
344
|
+
`;
|
|
345
|
+
}
|
|
346
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/sandbox/sidecar/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type DiscoveredNode } from "./node-discovery.js";
|
|
2
|
+
import type { RunResult } from "./vm-runner.js";
|
|
3
|
+
/**
|
|
4
|
+
* Sidecar runner: spawns a system-Node child process that hosts `isolated-vm`
|
|
5
|
+
* and proxies execute_code calls to it. The sidecar exists because Claude
|
|
6
|
+
* Desktop's Electron hardened runtime blocks loading native modules into the
|
|
7
|
+
* main MCP server process. See ./sidecar/index.ts for the child side.
|
|
8
|
+
*
|
|
9
|
+
* Lifecycle (lazy):
|
|
10
|
+
* - First call to runSandboxSidecar triggers discovery + spawn.
|
|
11
|
+
* - Sidecar emits `ready` → we send `init` with the method registry.
|
|
12
|
+
* - Subsequent calls reuse the same process for low per-call latency.
|
|
13
|
+
* - On unexpected exit we mark the runner unavailable; runner.ts falls
|
|
14
|
+
* back to the vm-runner for the current and future calls.
|
|
15
|
+
*
|
|
16
|
+
* Why not fork() a worker thread instead: workers run in the SAME process
|
|
17
|
+
* (still bound by Electron's hardened runtime). A separately-spawned `node`
|
|
18
|
+
* binary is the actual escape hatch.
|
|
19
|
+
*/
|
|
20
|
+
export interface SidecarAvailability {
|
|
21
|
+
available: true;
|
|
22
|
+
node: DiscoveredNode;
|
|
23
|
+
}
|
|
24
|
+
export interface SidecarUnavailable {
|
|
25
|
+
available: false;
|
|
26
|
+
reason: string;
|
|
27
|
+
}
|
|
28
|
+
export type SidecarStatus = SidecarAvailability | SidecarUnavailable;
|
|
29
|
+
export declare function getSidecarStatus(): Promise<SidecarStatus>;
|
|
30
|
+
export declare function runSandboxSidecar(code: string, options: {
|
|
31
|
+
timeoutMs: number;
|
|
32
|
+
}): Promise<RunResult>;
|