@frontmcp/plugin-codecall 1.8.3 → 1.8.5

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.
@@ -62,6 +62,9 @@ export interface CodeCallVmEnvironment {
62
62
  * @param options - Optional behavior configuration
63
63
  * @param options.throwOnError - When true (default), throws on error.
64
64
  * When false, returns { success, data, error }.
65
+ * The sandbox calls it without options: it applies a script's
66
+ * `{ throwOnError: false }` itself, for `callTool()` and
67
+ * namespace methods alike, so it needs the throw.
65
68
  *
66
69
  * SECURITY NOTES:
67
70
  * - Cannot call 'codecall:*' tools (self-reference blocked)
@@ -83,12 +86,11 @@ export interface CodeCallVmEnvironment {
83
86
  /**
84
87
  * Optional dotted-tool-name namespaces, as data: `{ acme: { getUser: 'acme.getUser' } }`.
85
88
  *
86
- * The enclave service writes them into the script as AgentScript objects whose methods
87
- * call `callTool('acme.getUser', input)` inside the sandbox, so AgentScript can call
88
- * `await acme.getUser({...})` and every such call still passes the sandbox's tool-call
89
- * cap, rate limit and suspicious-sequence checks (they are never host functions). Tools
90
- * whose names cannot be expressed as `{validIdent}.{validIdent}` remain reachable only
91
- * via `callTool`.
89
+ * The enclave service hands them to the sandbox as its `toolNamespaces`, which builds the
90
+ * objects itself, so AgentScript can call `await acme.getUser({...})` and every such call is a
91
+ * `callTool('acme.getUser', …)` inside the sandbox: it passes the tool-call cap, rate limit
92
+ * and suspicious-sequence checks (they are never host functions). Tools whose names the
93
+ * sandbox can't bind remain reachable only via `callTool`.
92
94
  */
93
95
  toolNamespaces?: Record<string, Record<string, string>>;
94
96
  }
@@ -1 +1 @@
1
- {"version":3,"file":"codecall.symbol.d.ts","sourceRoot":"","sources":["../src/codecall.symbol.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"codecall.symbol.d.ts","sourceRoot":"","sources":["../src/codecall.symbol.ts"],"names":[],"mappings":"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"}
package/esm/index.mjs CHANGED
@@ -1733,7 +1733,9 @@ var ToolSearchService = class _ToolSearchService {
1733
1733
  };
1734
1734
 
1735
1735
  // plugins/plugin-codecall/src/services/enclave.service.ts
1736
- import { Enclave } from "@enclave-vm/core";
1736
+ import {
1737
+ Enclave
1738
+ } from "@enclave-vm/core";
1737
1739
  import { Provider as Provider3, ProviderScope as ProviderScope3 } from "@frontmcp/sdk";
1738
1740
 
1739
1741
  // plugins/plugin-codecall/src/utils/build-tool-namespaces.ts
@@ -1784,9 +1786,29 @@ var UNBINDABLE_NAMESPACES = new Set(
1784
1786
  "localStorage sessionStorage indexedDB crypto performance structuredClone AbortController AbortSignal",
1785
1787
  "MessageChannel MessagePort BroadcastChannel TextEncoder TextDecoder Intl setTimeout setInterval",
1786
1788
  "setImmediate clearTimeout clearInterval clearImmediate queueMicrotask WebAssembly Worker SharedWorker",
1787
- "ServiceWorker WeakRef FinalizationRegistry BigInt Atomics SharedArrayBuffer ArrayBuffer DataView"
1789
+ "ServiceWorker WeakRef FinalizationRegistry BigInt Atomics SharedArrayBuffer ArrayBuffer DataView",
1790
+ "importScripts ShadowRealm Iterator AsyncIterator"
1791
+ ].join(" ").split(" ")
1792
+ );
1793
+ var UNCALLABLE_METHODS = new Set(
1794
+ [
1795
+ "process require module exports Buffer eval Function AsyncFunction GeneratorFunction arguments RegExp",
1796
+ "Promise Symbol Proxy Reflect Error TypeError ReferenceError SyntaxError RangeError URIError EvalError",
1797
+ "AggregateError fetch XMLHttpRequest WebSocket localStorage sessionStorage indexedDB crypto performance",
1798
+ "structuredClone AbortController AbortSignal MessageChannel MessagePort BroadcastChannel TextEncoder",
1799
+ "TextDecoder Intl setTimeout setInterval setImmediate clearTimeout clearInterval clearImmediate",
1800
+ "queueMicrotask WebAssembly Worker SharedWorker ServiceWorker WeakMap WeakSet WeakRef FinalizationRegistry",
1801
+ "Map Set Atomics SharedArrayBuffer importScripts ShadowRealm Iterator AsyncIterator"
1788
1802
  ].join(" ").split(" ")
1789
1803
  );
1804
+ var SANDBOX_TOOL_NAME_RE = /^[a-zA-Z][a-zA-Z0-9:._-]*$/;
1805
+ var MAX_SANDBOX_TOOL_NAME_LENGTH = 256;
1806
+ function isBindableNamespace(ns, reservedGlobals) {
1807
+ return IDENT_RE.test(ns) && !PROTOTYPE_KEYS.has(ns) && !ns.startsWith("__") && !RESERVED_NAMESPACES.has(ns) && !UNBINDABLE_NAMESPACES.has(ns) && !reservedGlobals.has(ns);
1808
+ }
1809
+ function isBindableMethod(ns, method, toolName) {
1810
+ return IDENT_RE.test(method) && !PROTOTYPE_KEYS.has(method) && !method.startsWith("__") && !UNCALLABLE_METHODS.has(method) && toolName === `${ns}.${method}` && toolName.length <= MAX_SANDBOX_TOOL_NAME_LENGTH && SANDBOX_TOOL_NAME_RE.test(toolName);
1811
+ }
1790
1812
  function buildToolNamespaces(tools) {
1791
1813
  const namespaces = /* @__PURE__ */ Object.create(null);
1792
1814
  const skipped = [];
@@ -1812,6 +1834,10 @@ function buildToolNamespaces(tools) {
1812
1834
  skipped.push({ name, reason: "reserved-namespace" });
1813
1835
  continue;
1814
1836
  }
1837
+ if (!isBindableMethod(ns, method, name)) {
1838
+ skipped.push({ name, reason: "unsupported-name" });
1839
+ continue;
1840
+ }
1815
1841
  const bucket = namespaces[ns] ?? (namespaces[ns] = /* @__PURE__ */ Object.create(null));
1816
1842
  if (Object.prototype.hasOwnProperty.call(bucket, method)) {
1817
1843
  skipped.push({ name, reason: "duplicate-method" });
@@ -1821,49 +1847,164 @@ function buildToolNamespaces(tools) {
1821
1847
  }
1822
1848
  return { namespaces, skipped };
1823
1849
  }
1824
- var NAMESPACE_CALL_HELPER = "__codecallNamespaceCall";
1825
- var NAMESPACE_CALL_HELPER_SOURCE = `const ${NAMESPACE_CALL_HELPER} = async (toolName, run, options) => { if (options && options.throwOnError === false) { try { return { success: true, data: await run() }; } catch (error) { return { success: false, error: { message: error && error.message, toolName: toolName } }; } } return await run(); };`;
1826
- function mentionsIdentifier(script, identifier) {
1827
- let from = 0;
1828
- for (; ; ) {
1829
- const at = script.indexOf(identifier, from);
1830
- if (at === -1) return false;
1831
- from = at + 1;
1832
- const before = at > 0 ? script[at - 1] : "";
1833
- const after = script[at + identifier.length] ?? "";
1834
- if (/[A-Za-z0-9_$'"`]/.test(before) || /[A-Za-z0-9_$]/.test(after)) continue;
1835
- if (before === "." && script.slice(Math.max(0, at - 3), at) !== "...") continue;
1836
- return true;
1837
- }
1838
- }
1839
- function wrapScriptWithToolNamespaces(script, namespaces) {
1840
- if (!namespaces) return script;
1841
- const declarations = [];
1850
+ function toSandboxToolNamespaces(namespaces, reservedGlobals = []) {
1851
+ if (!namespaces) return void 0;
1852
+ const reserved = new Set(reservedGlobals);
1853
+ const bindable = /* @__PURE__ */ Object.create(null);
1854
+ let count = 0;
1842
1855
  for (const ns of Object.keys(namespaces)) {
1843
- if (!IDENT_RE.test(ns) || RESERVED_NAMESPACES.has(ns) || UNBINDABLE_NAMESPACES.has(ns) || ns.startsWith("__")) {
1844
- continue;
1845
- }
1846
- if (PROTOTYPE_KEYS.has(ns) || !mentionsIdentifier(script, ns)) continue;
1856
+ if (!isBindableNamespace(ns, reserved)) continue;
1847
1857
  const methods = namespaces[ns];
1848
- const entries = [];
1858
+ const bucket = /* @__PURE__ */ Object.create(null);
1859
+ let methodCount = 0;
1849
1860
  for (const method of Object.keys(methods)) {
1850
1861
  const toolName = methods[method];
1851
- if (!IDENT_RE.test(method) || PROTOTYPE_KEYS.has(method) || toolName !== `${ns}.${method}`) continue;
1852
- const literal = JSON.stringify(toolName);
1853
- entries.push(
1854
- `${JSON.stringify(method)}: (input, options) => ${NAMESPACE_CALL_HELPER}(${literal}, () => callTool(${literal}, input === undefined ? {} : input), options)`
1855
- );
1862
+ if (typeof toolName !== "string" || !isBindableMethod(ns, method, toolName)) continue;
1863
+ bucket[method] = toolName;
1864
+ methodCount += 1;
1865
+ }
1866
+ if (methodCount > 0) {
1867
+ bindable[ns] = bucket;
1868
+ count += 1;
1869
+ }
1870
+ }
1871
+ return count > 0 ? bindable : void 0;
1872
+ }
1873
+
1874
+ // plugins/plugin-codecall/src/utils/script-lines.ts
1875
+ import { isWrappedInMain, transformAgentScript } from "@enclave-vm/ast";
1876
+ import * as acorn from "acorn";
1877
+ var PARSE_OPTIONS = { ecmaVersion: "latest", locations: true };
1878
+ var NON_CHILD_KEYS = /* @__PURE__ */ new Set(["type", "loc", "start", "end", "range"]);
1879
+ function isNode(value) {
1880
+ return typeof value === "object" && value !== null && typeof value.type === "string";
1881
+ }
1882
+ function isAddedByTransform(node) {
1883
+ if (node.type === "VariableDeclaration") {
1884
+ const [declaration] = node["declarations"] ?? [];
1885
+ const id = declaration?.["id"];
1886
+ return typeof id?.["name"] === "string" && id["name"].startsWith("__iter_");
1887
+ }
1888
+ if (node.type === "IfStatement") {
1889
+ const right = node["test"]?.["right"];
1890
+ return right?.type === "Identifier" && right["name"] === "__maxIterations";
1891
+ }
1892
+ return false;
1893
+ }
1894
+ function parseScript(script) {
1895
+ try {
1896
+ return { body: parseBody(script, "script"), offset: 0 };
1897
+ } catch {
1898
+ try {
1899
+ return { body: parseBody(script, "module"), offset: 0 };
1900
+ } catch {
1901
+ const wrapped = parseBody(`async function __temp__() {
1902
+ ${script}
1903
+ }`, "script");
1904
+ const fn = wrapped[0];
1905
+ const block = fn?.["body"];
1906
+ return { body: block?.["body"] ?? [], offset: 1 };
1856
1907
  }
1857
- if (entries.length > 0) {
1858
- declarations.push(`const ${ns} = { ${entries.join(", ")} };`);
1908
+ }
1909
+ }
1910
+ function parseBody(code, sourceType) {
1911
+ const program = acorn.parse(code, { ...PARSE_OPTIONS, sourceType });
1912
+ return program["body"] ?? [];
1913
+ }
1914
+ function treesOf(script) {
1915
+ try {
1916
+ const wrap = !isWrappedInMain(script);
1917
+ const printed = parseBody(transformAgentScript(script, { wrapInMain: wrap }), "script");
1918
+ const { body, offset } = parseScript(script);
1919
+ if (!wrap) return { printed, script: body, offset };
1920
+ const main = printed[0]?.["body"];
1921
+ return { printed: main?.["body"] ?? [], script: body, offset };
1922
+ } catch {
1923
+ return void 0;
1924
+ }
1925
+ }
1926
+ function pairLists(printed, script, depth, out, offset) {
1927
+ const kept = printed.filter((node) => !(isNode(node) && isAddedByTransform(node)));
1928
+ if (kept.length !== script.length) return;
1929
+ kept.forEach((node, index) => {
1930
+ const own = script[index];
1931
+ if (isNode(node) && isNode(own)) pairNodes(node, own, depth, out, offset);
1932
+ });
1933
+ }
1934
+ function pairNodes(printed, script, depth, out, offset) {
1935
+ if (printed.type === "ReturnStatement" && script.type === "ExpressionStatement") {
1936
+ record(printed, script, depth, out, offset);
1937
+ const argument = printed["argument"];
1938
+ const expression = script["expression"];
1939
+ if (isNode(argument) && isNode(expression)) pairNodes(argument, expression, depth + 1, out, offset);
1940
+ return;
1941
+ }
1942
+ if (printed.type !== script.type) return;
1943
+ record(printed, script, depth, out, offset);
1944
+ for (const key of Object.keys(printed)) {
1945
+ if (NON_CHILD_KEYS.has(key)) continue;
1946
+ const printedChild = printed[key];
1947
+ const scriptChild = script[key];
1948
+ if (Array.isArray(printedChild) && Array.isArray(scriptChild)) {
1949
+ pairLists(printedChild, scriptChild, depth + 1, out, offset);
1950
+ } else if (isNode(printedChild) && isNode(scriptChild)) {
1951
+ pairNodes(printedChild, scriptChild, depth + 1, out, offset);
1859
1952
  }
1860
1953
  }
1861
- if (declarations.length === 0) return script;
1862
- return `${NAMESPACE_CALL_HELPER_SOURCE} ${declarations.join(" ")} return await (async () => {${script}
1863
- })();`;
1954
+ }
1955
+ function record(printed, script, depth, out, offset) {
1956
+ if (!printed.loc || !script.loc) return;
1957
+ out.push({
1958
+ printedStart: printed.loc.start.line,
1959
+ printedEnd: printed.loc.end.line,
1960
+ scriptLine: script.loc.start.line - offset,
1961
+ depth
1962
+ });
1963
+ }
1964
+ function validatedLineMapper(script) {
1965
+ const trees = treesOf(script);
1966
+ if (!trees) return () => void 0;
1967
+ const pairs = [];
1968
+ pairLists(trees.printed, trees.script, 0, pairs, trees.offset);
1969
+ return (printedLine) => {
1970
+ const starting = pairs.filter((pair) => pair.printedStart === printedLine);
1971
+ const candidates = starting.length > 0 ? starting : pairs.filter((pair) => pair.printedStart <= printedLine && printedLine <= pair.printedEnd);
1972
+ const best = candidates.reduce(
1973
+ (deepest, pair) => !deepest || pair.depth > deepest.depth ? pair : deepest,
1974
+ void 0
1975
+ );
1976
+ return best && best.scriptLine >= 1 ? best.scriptLine : void 0;
1977
+ };
1978
+ }
1979
+ var ISSUE_LINE_RE = / \(line (\d+)\)/g;
1980
+ function withScriptLines(message, script) {
1981
+ if (!message.includes("(line ")) return message;
1982
+ const lineOf = validatedLineMapper(script);
1983
+ return message.replace(ISSUE_LINE_RE, (_match, printed) => {
1984
+ const line = lineOf(Number(printed));
1985
+ return line === void 0 ? "" : ` (line ${line})`;
1986
+ });
1864
1987
  }
1865
1988
 
1866
1989
  // plugins/plugin-codecall/src/services/enclave.service.ts
1990
+ function toolFailureMessage(error, toolName) {
1991
+ if (typeof error === "string" && error) return error;
1992
+ const message = error?.message;
1993
+ return typeof message === "string" && message ? message : `Tool call failed: ${toolName}`;
1994
+ }
1995
+ function toolFailureName(error) {
1996
+ const name = error && typeof error === "object" ? error.name : void 0;
1997
+ return typeof name === "string" && name ? name.slice(0, 128) : "ToolError";
1998
+ }
1999
+ var PARSE_FAILURE_PREFIX = "Failed to parse AgentScript code: ";
2000
+ var PARSE_POSITION_RE = /\((\d+):(\d+)\)$/;
2001
+ function parseFailureOf(message) {
2002
+ const match = PARSE_POSITION_RE.exec(message);
2003
+ const line = match ? Number(match[1]) - 1 : 0;
2004
+ if (!match || line < 1) return { message };
2005
+ const column = Number(match[2]);
2006
+ return { message: `${message.slice(0, match.index)}(${line}:${column})`, location: { line, column } };
2007
+ }
1867
2008
  var ScriptTooLargeError = class extends Error {
1868
2009
  code = "SCRIPT_TOO_LARGE";
1869
2010
  scriptLength;
@@ -1901,8 +2042,20 @@ var EnclaveService = class {
1901
2042
  throw new ScriptTooLargeError(code.length, maxLength);
1902
2043
  }
1903
2044
  }
2045
+ const toolFailures = [];
1904
2046
  const toolHandler = async (toolName, args) => {
1905
- return environment.callTool(toolName, args);
2047
+ try {
2048
+ return await environment.callTool(toolName, args);
2049
+ } catch (error) {
2050
+ const code2 = error?.code;
2051
+ toolFailures.push({
2052
+ toolName,
2053
+ name: toolFailureName(error),
2054
+ message: toolFailureMessage(error, toolName),
2055
+ ...typeof code2 === "string" ? { code: code2 } : {}
2056
+ });
2057
+ throw error;
2058
+ }
1906
2059
  };
1907
2060
  const sidecar = this.sidecarOptions.enabled ? {
1908
2061
  enabled: true,
@@ -1912,8 +2065,29 @@ var EnclaveService = class {
1912
2065
  maxResolvedSize: this.sidecarOptions.maxResolvedSize,
1913
2066
  allowComposites: this.sidecarOptions.allowComposites
1914
2067
  } : void 0;
1915
- const source = wrapScriptWithToolNamespaces(code, environment.toolNamespaces);
1916
- const enclave = new Enclave({
2068
+ const { mcpLog, mcpNotify } = environment;
2069
+ const globals = {
2070
+ // Provide getTool as a custom global
2071
+ getTool: environment.getTool,
2072
+ // Provide logging functions if available
2073
+ ...mcpLog ? {
2074
+ mcpLog: (level, message, metadata) => {
2075
+ mcpLog(level, message, metadata);
2076
+ logs.push(`[mcp:${level}] ${message}`);
2077
+ }
2078
+ } : {},
2079
+ ...mcpNotify ? {
2080
+ mcpNotify: (event, payload) => {
2081
+ mcpNotify(event, payload);
2082
+ logs.push(`[notify] ${event}`);
2083
+ }
2084
+ } : {}
2085
+ // Note: enclave-vm v2.0.0+ provides its own __safe_console internally with rate limiting
2086
+ // and output size limits. Passing console in globals causes "Cannot redefine property"
2087
+ // errors due to Double VM architecture. Console output from user scripts goes to stdout
2088
+ // via enclave's internal console, not to this logs array. Only mcpLog/mcpNotify are captured.
2089
+ };
2090
+ const options = {
1917
2091
  timeout: this.vmOptions.timeoutMs,
1918
2092
  maxToolCalls: this.vmOptions.maxSteps || 100,
1919
2093
  maxIterations: 1e4,
@@ -1923,33 +2097,20 @@ var EnclaveService = class {
1923
2097
  validate: true,
1924
2098
  transform: true,
1925
2099
  sidecar,
2100
+ // Error stacks name no host file, whatever stage raised them.
2101
+ sanitizeStackTraces: true,
1926
2102
  // Allow functions in globals since we intentionally provide getTool, mcpLog, mcpNotify, and console
1927
2103
  allowFunctionsInGlobals: true,
1928
- globals: {
1929
- // Provide getTool as a custom global
1930
- getTool: environment.getTool,
1931
- // Provide logging functions if available
1932
- ...environment.mcpLog ? {
1933
- mcpLog: (level, message, metadata) => {
1934
- environment.mcpLog(level, message, metadata);
1935
- logs.push(`[mcp:${level}] ${message}`);
1936
- }
1937
- } : {},
1938
- ...environment.mcpNotify ? {
1939
- mcpNotify: (event, payload) => {
1940
- environment.mcpNotify(event, payload);
1941
- logs.push(`[notify] ${event}`);
1942
- }
1943
- } : {}
1944
- // Note: enclave-vm v2.0.0+ provides its own __safe_console internally with rate limiting
1945
- // and output size limits. Passing console in globals causes "Cannot redefine property"
1946
- // errors due to Double VM architecture. Console output from user scripts goes to stdout
1947
- // via enclave's internal console, not to this logs array. Only mcpLog/mcpNotify are captured.
1948
- }
1949
- });
2104
+ globals,
2105
+ // Tool namespaces (`acme.getUser()` for a tool named `acme.getUser`) are built by the sandbox
2106
+ // itself: a method call is exactly `callTool('acme.getUser', args, options)`, with the
2107
+ // sandbox's tool-call cap, rate limit, suspicious-sequence checks and `throwOnError`.
2108
+ toolNamespaces: toSandboxToolNamespaces(environment.toolNamespaces, Object.keys(globals))
2109
+ };
2110
+ const enclave = createEnclave(options);
1950
2111
  try {
1951
- const result = await enclave.run(source);
1952
- return this.mapEnclaveResult(result, logs);
2112
+ const result = await enclave.run(code);
2113
+ return this.mapEnclaveResult(result, logs, toolFailures, code);
1953
2114
  } finally {
1954
2115
  enclave.dispose();
1955
2116
  }
@@ -1957,58 +2118,58 @@ var EnclaveService = class {
1957
2118
  /**
1958
2119
  * Map Enclave ExecutionResult to EnclaveExecutionResult
1959
2120
  */
1960
- mapEnclaveResult(result, logs) {
2121
+ mapEnclaveResult(result, logs, toolFailures = [], script = "") {
2122
+ const stats = {
2123
+ duration: result.stats.duration,
2124
+ toolCallCount: result.stats.toolCallCount,
2125
+ iterationCount: result.stats.iterationCount
2126
+ };
1961
2127
  if (result.success) {
2128
+ return { success: true, result: result.value, logs, timedOut: false, stats };
2129
+ }
2130
+ const error = result.error ?? { name: "Error", message: "Script execution failed" };
2131
+ if (error.code === "ENCLAVE_ERROR" && error.message?.startsWith(PARSE_FAILURE_PREFIX)) {
2132
+ const { message, location } = parseFailureOf(error.message);
1962
2133
  return {
1963
- success: true,
1964
- result: result.value,
2134
+ success: false,
2135
+ error: { message, name: "SyntaxError", code: "SYNTAX_ERROR", ...location ? { location } : {} },
1965
2136
  logs,
1966
2137
  timedOut: false,
1967
- stats: {
1968
- duration: result.stats.duration,
1969
- toolCallCount: result.stats.toolCallCount,
1970
- iterationCount: result.stats.iterationCount
1971
- }
2138
+ stats
1972
2139
  };
1973
2140
  }
1974
- const error = result.error;
1975
- const timedOut = error.message?.includes("timed out") || error.code === "TIMEOUT";
1976
- if (error.code === "VALIDATION_ERROR") {
1977
- const issues = error.data?.issues ?? [];
1978
- const blockedPatterns = [...new Set(issues.map((issue) => issue.code).filter((code) => !!code))];
2141
+ const toolFailure = [...toolFailures].reverse().find((failure) => failure.message === error.message && failure.name === error.name);
2142
+ if (toolFailure) {
1979
2143
  return {
1980
2144
  success: false,
1981
2145
  error: {
1982
2146
  message: error.message,
1983
- name: "ValidationError",
1984
- code: error.code,
1985
- ...blockedPatterns.length > 0 ? { blockedPatterns } : {}
2147
+ name: error.name,
2148
+ ...toolFailure.code ? { code: toolFailure.code } : {},
2149
+ toolName: toolFailure.toolName
1986
2150
  },
1987
2151
  logs,
1988
2152
  timedOut: false,
1989
- stats: {
1990
- duration: result.stats.duration,
1991
- toolCallCount: result.stats.toolCallCount,
1992
- iterationCount: result.stats.iterationCount
1993
- }
2153
+ stats
1994
2154
  };
1995
2155
  }
1996
- const errorData = error.data;
1997
- const toolName = errorData?.["toolName"];
1998
- if (toolName) {
2156
+ const timedOut = error.message?.includes("timed out") || error.code === "TIMEOUT";
2157
+ if (error.code === "VALIDATION_ERROR") {
2158
+ const issues = error.data?.issues ?? [];
2159
+ const blockedPatterns = [...new Set(issues.map((issue) => issue.code).filter((code) => !!code))];
1999
2160
  return {
2000
2161
  success: false,
2001
2162
  error: {
2002
- message: error.message,
2003
- name: error.name,
2004
- stack: error.stack,
2163
+ // The enclave names lines of the code it validated (the script wrapped and printed again),
2164
+ // not the script's own.
2165
+ message: withScriptLines(error.message, script),
2166
+ name: "ValidationError",
2005
2167
  code: error.code,
2006
- toolName,
2007
- toolInput: errorData?.["toolInput"],
2008
- details: errorData?.["details"]
2168
+ ...blockedPatterns.length > 0 ? { blockedPatterns } : {}
2009
2169
  },
2010
2170
  logs,
2011
- timedOut
2171
+ timedOut: false,
2172
+ stats
2012
2173
  };
2013
2174
  }
2014
2175
  return {
@@ -2021,11 +2182,7 @@ var EnclaveService = class {
2021
2182
  },
2022
2183
  logs,
2023
2184
  timedOut,
2024
- stats: {
2025
- duration: result.stats.duration,
2026
- toolCallCount: result.stats.toolCallCount,
2027
- iterationCount: result.stats.iterationCount
2028
- }
2185
+ stats
2029
2186
  };
2030
2187
  }
2031
2188
  };
@@ -2036,6 +2193,16 @@ EnclaveService = __decorateClass([
2036
2193
  scope: ProviderScope3.GLOBAL
2037
2194
  })
2038
2195
  ], EnclaveService);
2196
+ function createEnclave(options) {
2197
+ try {
2198
+ return new Enclave(options);
2199
+ } catch (error) {
2200
+ if (!options.toolNamespaces || !(error instanceof TypeError) || !error.message.startsWith("Invalid toolNamespaces")) {
2201
+ throw error;
2202
+ }
2203
+ return new Enclave({ ...options, toolNamespaces: void 0 });
2204
+ }
2205
+ }
2039
2206
 
2040
2207
  // plugins/plugin-codecall/src/tools/search.tool.ts
2041
2208
  import { getCallSurface, Tool, ToolContext } from "@frontmcp/sdk";
@@ -3136,7 +3303,11 @@ var runtimeErrorPayloadSchema = z7.object({
3136
3303
  var toolErrorPayloadSchema = z7.object({
3137
3304
  source: z7.literal("tool"),
3138
3305
  toolName: z7.string(),
3139
- toolInput: z7.unknown(),
3306
+ /**
3307
+ * @deprecated Never set: the sandbox resolves sidecar references in a call's arguments before
3308
+ * the tool sees them, so they may hold data the script itself never had.
3309
+ */
3310
+ toolInput: z7.unknown().optional(),
3140
3311
  message: z7.string(),
3141
3312
  code: z7.string().optional(),
3142
3313
  /** @deprecated Never set: the enclave's error data is not sanitized for clients. */
@@ -3355,6 +3526,16 @@ var ExecuteTool = class extends ToolContext5 {
3355
3526
  }
3356
3527
  if (!executionResult.success) {
3357
3528
  const error = executionResult.error;
3529
+ if (error.code === "SYNTAX_ERROR") {
3530
+ audit?.logExecutionFailure(executionId, script, durationMs, error.message);
3531
+ return {
3532
+ status: "syntax_error",
3533
+ error: {
3534
+ message: toClientErrorMessage(error.message) || "Syntax error in script",
3535
+ ...error.location ? { location: error.location } : {}
3536
+ }
3537
+ };
3538
+ }
3358
3539
  if (error.code === "VALIDATION_ERROR" || error.name === "ValidationError") {
3359
3540
  audit?.logSecurityAstBlocked(executionId, error.blockedPatterns?.join(", ") ?? "UNKNOWN", error.message);
3360
3541
  audit?.logExecutionFailure(executionId, script, durationMs, error.message);
@@ -3373,10 +3554,10 @@ var ExecuteTool = class extends ToolContext5 {
3373
3554
  error: {
3374
3555
  source: "tool",
3375
3556
  toolName: error.toolName,
3376
- toolInput: error.toolInput,
3377
3557
  message: toClientErrorMessage(error.message),
3378
3558
  code: error.code
3379
- // No `details`: the enclave's error data is not sanitized for clients.
3559
+ // No `details`: the enclave's error data is not sanitized for clients. No `toolInput`:
3560
+ // the arguments the tool saw may hold sidecar-resolved data the script never had.
3380
3561
  }
3381
3562
  };
3382
3563
  }
package/esm/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@frontmcp/plugin-codecall",
3
- "version": "1.8.3",
3
+ "version": "1.8.5",
4
4
  "description": "CodeCall plugin for FrontMCP - AgentScript-based meta-tools for orchestrating MCP tools",
5
5
  "author": "AgentFront <info@agentfront.dev>",
6
6
  "license": "Apache-2.0",
@@ -48,14 +48,16 @@
48
48
  }
49
49
  },
50
50
  "dependencies": {
51
+ "@enclave-vm/ast": "^2.15.3",
51
52
  "@enclave-vm/core": "^2.15.3",
52
- "@frontmcp/protocol": "1.8.3",
53
- "@frontmcp/sdk": "1.8.3",
53
+ "@frontmcp/protocol": "1.8.5",
54
+ "@frontmcp/sdk": "1.8.5",
55
+ "acorn": "^8.15.0",
54
56
  "vectoriadb": "^2.3.2"
55
57
  },
56
58
  "peerDependencies": {
57
- "@frontmcp/lazy-zod": "1.8.3",
58
- "@frontmcp/plugin-cache": "1.8.3"
59
+ "@frontmcp/lazy-zod": "1.8.5",
60
+ "@frontmcp/plugin-cache": "1.8.5"
59
61
  },
60
62
  "devDependencies": {
61
63
  "reflect-metadata": "^0.2.2"
package/index.js CHANGED
@@ -1823,9 +1823,29 @@ var UNBINDABLE_NAMESPACES = new Set(
1823
1823
  "localStorage sessionStorage indexedDB crypto performance structuredClone AbortController AbortSignal",
1824
1824
  "MessageChannel MessagePort BroadcastChannel TextEncoder TextDecoder Intl setTimeout setInterval",
1825
1825
  "setImmediate clearTimeout clearInterval clearImmediate queueMicrotask WebAssembly Worker SharedWorker",
1826
- "ServiceWorker WeakRef FinalizationRegistry BigInt Atomics SharedArrayBuffer ArrayBuffer DataView"
1826
+ "ServiceWorker WeakRef FinalizationRegistry BigInt Atomics SharedArrayBuffer ArrayBuffer DataView",
1827
+ "importScripts ShadowRealm Iterator AsyncIterator"
1827
1828
  ].join(" ").split(" ")
1828
1829
  );
1830
+ var UNCALLABLE_METHODS = new Set(
1831
+ [
1832
+ "process require module exports Buffer eval Function AsyncFunction GeneratorFunction arguments RegExp",
1833
+ "Promise Symbol Proxy Reflect Error TypeError ReferenceError SyntaxError RangeError URIError EvalError",
1834
+ "AggregateError fetch XMLHttpRequest WebSocket localStorage sessionStorage indexedDB crypto performance",
1835
+ "structuredClone AbortController AbortSignal MessageChannel MessagePort BroadcastChannel TextEncoder",
1836
+ "TextDecoder Intl setTimeout setInterval setImmediate clearTimeout clearInterval clearImmediate",
1837
+ "queueMicrotask WebAssembly Worker SharedWorker ServiceWorker WeakMap WeakSet WeakRef FinalizationRegistry",
1838
+ "Map Set Atomics SharedArrayBuffer importScripts ShadowRealm Iterator AsyncIterator"
1839
+ ].join(" ").split(" ")
1840
+ );
1841
+ var SANDBOX_TOOL_NAME_RE = /^[a-zA-Z][a-zA-Z0-9:._-]*$/;
1842
+ var MAX_SANDBOX_TOOL_NAME_LENGTH = 256;
1843
+ function isBindableNamespace(ns, reservedGlobals) {
1844
+ return IDENT_RE.test(ns) && !PROTOTYPE_KEYS.has(ns) && !ns.startsWith("__") && !RESERVED_NAMESPACES.has(ns) && !UNBINDABLE_NAMESPACES.has(ns) && !reservedGlobals.has(ns);
1845
+ }
1846
+ function isBindableMethod(ns, method, toolName) {
1847
+ return IDENT_RE.test(method) && !PROTOTYPE_KEYS.has(method) && !method.startsWith("__") && !UNCALLABLE_METHODS.has(method) && toolName === `${ns}.${method}` && toolName.length <= MAX_SANDBOX_TOOL_NAME_LENGTH && SANDBOX_TOOL_NAME_RE.test(toolName);
1848
+ }
1829
1849
  function buildToolNamespaces(tools) {
1830
1850
  const namespaces = /* @__PURE__ */ Object.create(null);
1831
1851
  const skipped = [];
@@ -1851,6 +1871,10 @@ function buildToolNamespaces(tools) {
1851
1871
  skipped.push({ name, reason: "reserved-namespace" });
1852
1872
  continue;
1853
1873
  }
1874
+ if (!isBindableMethod(ns, method, name)) {
1875
+ skipped.push({ name, reason: "unsupported-name" });
1876
+ continue;
1877
+ }
1854
1878
  const bucket = namespaces[ns] ?? (namespaces[ns] = /* @__PURE__ */ Object.create(null));
1855
1879
  if (Object.prototype.hasOwnProperty.call(bucket, method)) {
1856
1880
  skipped.push({ name, reason: "duplicate-method" });
@@ -1860,49 +1884,164 @@ function buildToolNamespaces(tools) {
1860
1884
  }
1861
1885
  return { namespaces, skipped };
1862
1886
  }
1863
- var NAMESPACE_CALL_HELPER = "__codecallNamespaceCall";
1864
- var NAMESPACE_CALL_HELPER_SOURCE = `const ${NAMESPACE_CALL_HELPER} = async (toolName, run, options) => { if (options && options.throwOnError === false) { try { return { success: true, data: await run() }; } catch (error) { return { success: false, error: { message: error && error.message, toolName: toolName } }; } } return await run(); };`;
1865
- function mentionsIdentifier(script, identifier) {
1866
- let from = 0;
1867
- for (; ; ) {
1868
- const at = script.indexOf(identifier, from);
1869
- if (at === -1) return false;
1870
- from = at + 1;
1871
- const before = at > 0 ? script[at - 1] : "";
1872
- const after = script[at + identifier.length] ?? "";
1873
- if (/[A-Za-z0-9_$'"`]/.test(before) || /[A-Za-z0-9_$]/.test(after)) continue;
1874
- if (before === "." && script.slice(Math.max(0, at - 3), at) !== "...") continue;
1875
- return true;
1876
- }
1877
- }
1878
- function wrapScriptWithToolNamespaces(script, namespaces) {
1879
- if (!namespaces) return script;
1880
- const declarations = [];
1887
+ function toSandboxToolNamespaces(namespaces, reservedGlobals = []) {
1888
+ if (!namespaces) return void 0;
1889
+ const reserved = new Set(reservedGlobals);
1890
+ const bindable = /* @__PURE__ */ Object.create(null);
1891
+ let count = 0;
1881
1892
  for (const ns of Object.keys(namespaces)) {
1882
- if (!IDENT_RE.test(ns) || RESERVED_NAMESPACES.has(ns) || UNBINDABLE_NAMESPACES.has(ns) || ns.startsWith("__")) {
1883
- continue;
1884
- }
1885
- if (PROTOTYPE_KEYS.has(ns) || !mentionsIdentifier(script, ns)) continue;
1893
+ if (!isBindableNamespace(ns, reserved)) continue;
1886
1894
  const methods = namespaces[ns];
1887
- const entries = [];
1895
+ const bucket = /* @__PURE__ */ Object.create(null);
1896
+ let methodCount = 0;
1888
1897
  for (const method of Object.keys(methods)) {
1889
1898
  const toolName = methods[method];
1890
- if (!IDENT_RE.test(method) || PROTOTYPE_KEYS.has(method) || toolName !== `${ns}.${method}`) continue;
1891
- const literal = JSON.stringify(toolName);
1892
- entries.push(
1893
- `${JSON.stringify(method)}: (input, options) => ${NAMESPACE_CALL_HELPER}(${literal}, () => callTool(${literal}, input === undefined ? {} : input), options)`
1894
- );
1899
+ if (typeof toolName !== "string" || !isBindableMethod(ns, method, toolName)) continue;
1900
+ bucket[method] = toolName;
1901
+ methodCount += 1;
1902
+ }
1903
+ if (methodCount > 0) {
1904
+ bindable[ns] = bucket;
1905
+ count += 1;
1906
+ }
1907
+ }
1908
+ return count > 0 ? bindable : void 0;
1909
+ }
1910
+
1911
+ // plugins/plugin-codecall/src/utils/script-lines.ts
1912
+ var import_ast = require("@enclave-vm/ast");
1913
+ var acorn = __toESM(require("acorn"));
1914
+ var PARSE_OPTIONS = { ecmaVersion: "latest", locations: true };
1915
+ var NON_CHILD_KEYS = /* @__PURE__ */ new Set(["type", "loc", "start", "end", "range"]);
1916
+ function isNode(value) {
1917
+ return typeof value === "object" && value !== null && typeof value.type === "string";
1918
+ }
1919
+ function isAddedByTransform(node) {
1920
+ if (node.type === "VariableDeclaration") {
1921
+ const [declaration] = node["declarations"] ?? [];
1922
+ const id = declaration?.["id"];
1923
+ return typeof id?.["name"] === "string" && id["name"].startsWith("__iter_");
1924
+ }
1925
+ if (node.type === "IfStatement") {
1926
+ const right = node["test"]?.["right"];
1927
+ return right?.type === "Identifier" && right["name"] === "__maxIterations";
1928
+ }
1929
+ return false;
1930
+ }
1931
+ function parseScript(script) {
1932
+ try {
1933
+ return { body: parseBody(script, "script"), offset: 0 };
1934
+ } catch {
1935
+ try {
1936
+ return { body: parseBody(script, "module"), offset: 0 };
1937
+ } catch {
1938
+ const wrapped = parseBody(`async function __temp__() {
1939
+ ${script}
1940
+ }`, "script");
1941
+ const fn = wrapped[0];
1942
+ const block = fn?.["body"];
1943
+ return { body: block?.["body"] ?? [], offset: 1 };
1895
1944
  }
1896
- if (entries.length > 0) {
1897
- declarations.push(`const ${ns} = { ${entries.join(", ")} };`);
1945
+ }
1946
+ }
1947
+ function parseBody(code, sourceType) {
1948
+ const program = acorn.parse(code, { ...PARSE_OPTIONS, sourceType });
1949
+ return program["body"] ?? [];
1950
+ }
1951
+ function treesOf(script) {
1952
+ try {
1953
+ const wrap = !(0, import_ast.isWrappedInMain)(script);
1954
+ const printed = parseBody((0, import_ast.transformAgentScript)(script, { wrapInMain: wrap }), "script");
1955
+ const { body, offset } = parseScript(script);
1956
+ if (!wrap) return { printed, script: body, offset };
1957
+ const main = printed[0]?.["body"];
1958
+ return { printed: main?.["body"] ?? [], script: body, offset };
1959
+ } catch {
1960
+ return void 0;
1961
+ }
1962
+ }
1963
+ function pairLists(printed, script, depth, out, offset) {
1964
+ const kept = printed.filter((node) => !(isNode(node) && isAddedByTransform(node)));
1965
+ if (kept.length !== script.length) return;
1966
+ kept.forEach((node, index) => {
1967
+ const own = script[index];
1968
+ if (isNode(node) && isNode(own)) pairNodes(node, own, depth, out, offset);
1969
+ });
1970
+ }
1971
+ function pairNodes(printed, script, depth, out, offset) {
1972
+ if (printed.type === "ReturnStatement" && script.type === "ExpressionStatement") {
1973
+ record(printed, script, depth, out, offset);
1974
+ const argument = printed["argument"];
1975
+ const expression = script["expression"];
1976
+ if (isNode(argument) && isNode(expression)) pairNodes(argument, expression, depth + 1, out, offset);
1977
+ return;
1978
+ }
1979
+ if (printed.type !== script.type) return;
1980
+ record(printed, script, depth, out, offset);
1981
+ for (const key of Object.keys(printed)) {
1982
+ if (NON_CHILD_KEYS.has(key)) continue;
1983
+ const printedChild = printed[key];
1984
+ const scriptChild = script[key];
1985
+ if (Array.isArray(printedChild) && Array.isArray(scriptChild)) {
1986
+ pairLists(printedChild, scriptChild, depth + 1, out, offset);
1987
+ } else if (isNode(printedChild) && isNode(scriptChild)) {
1988
+ pairNodes(printedChild, scriptChild, depth + 1, out, offset);
1898
1989
  }
1899
1990
  }
1900
- if (declarations.length === 0) return script;
1901
- return `${NAMESPACE_CALL_HELPER_SOURCE} ${declarations.join(" ")} return await (async () => {${script}
1902
- })();`;
1991
+ }
1992
+ function record(printed, script, depth, out, offset) {
1993
+ if (!printed.loc || !script.loc) return;
1994
+ out.push({
1995
+ printedStart: printed.loc.start.line,
1996
+ printedEnd: printed.loc.end.line,
1997
+ scriptLine: script.loc.start.line - offset,
1998
+ depth
1999
+ });
2000
+ }
2001
+ function validatedLineMapper(script) {
2002
+ const trees = treesOf(script);
2003
+ if (!trees) return () => void 0;
2004
+ const pairs = [];
2005
+ pairLists(trees.printed, trees.script, 0, pairs, trees.offset);
2006
+ return (printedLine) => {
2007
+ const starting = pairs.filter((pair) => pair.printedStart === printedLine);
2008
+ const candidates = starting.length > 0 ? starting : pairs.filter((pair) => pair.printedStart <= printedLine && printedLine <= pair.printedEnd);
2009
+ const best = candidates.reduce(
2010
+ (deepest, pair) => !deepest || pair.depth > deepest.depth ? pair : deepest,
2011
+ void 0
2012
+ );
2013
+ return best && best.scriptLine >= 1 ? best.scriptLine : void 0;
2014
+ };
2015
+ }
2016
+ var ISSUE_LINE_RE = / \(line (\d+)\)/g;
2017
+ function withScriptLines(message, script) {
2018
+ if (!message.includes("(line ")) return message;
2019
+ const lineOf = validatedLineMapper(script);
2020
+ return message.replace(ISSUE_LINE_RE, (_match, printed) => {
2021
+ const line = lineOf(Number(printed));
2022
+ return line === void 0 ? "" : ` (line ${line})`;
2023
+ });
1903
2024
  }
1904
2025
 
1905
2026
  // plugins/plugin-codecall/src/services/enclave.service.ts
2027
+ function toolFailureMessage(error, toolName) {
2028
+ if (typeof error === "string" && error) return error;
2029
+ const message = error?.message;
2030
+ return typeof message === "string" && message ? message : `Tool call failed: ${toolName}`;
2031
+ }
2032
+ function toolFailureName(error) {
2033
+ const name = error && typeof error === "object" ? error.name : void 0;
2034
+ return typeof name === "string" && name ? name.slice(0, 128) : "ToolError";
2035
+ }
2036
+ var PARSE_FAILURE_PREFIX = "Failed to parse AgentScript code: ";
2037
+ var PARSE_POSITION_RE = /\((\d+):(\d+)\)$/;
2038
+ function parseFailureOf(message) {
2039
+ const match = PARSE_POSITION_RE.exec(message);
2040
+ const line = match ? Number(match[1]) - 1 : 0;
2041
+ if (!match || line < 1) return { message };
2042
+ const column = Number(match[2]);
2043
+ return { message: `${message.slice(0, match.index)}(${line}:${column})`, location: { line, column } };
2044
+ }
1906
2045
  var ScriptTooLargeError = class extends Error {
1907
2046
  code = "SCRIPT_TOO_LARGE";
1908
2047
  scriptLength;
@@ -1940,8 +2079,20 @@ var EnclaveService = class {
1940
2079
  throw new ScriptTooLargeError(code.length, maxLength);
1941
2080
  }
1942
2081
  }
2082
+ const toolFailures = [];
1943
2083
  const toolHandler = async (toolName, args) => {
1944
- return environment.callTool(toolName, args);
2084
+ try {
2085
+ return await environment.callTool(toolName, args);
2086
+ } catch (error) {
2087
+ const code2 = error?.code;
2088
+ toolFailures.push({
2089
+ toolName,
2090
+ name: toolFailureName(error),
2091
+ message: toolFailureMessage(error, toolName),
2092
+ ...typeof code2 === "string" ? { code: code2 } : {}
2093
+ });
2094
+ throw error;
2095
+ }
1945
2096
  };
1946
2097
  const sidecar = this.sidecarOptions.enabled ? {
1947
2098
  enabled: true,
@@ -1951,8 +2102,29 @@ var EnclaveService = class {
1951
2102
  maxResolvedSize: this.sidecarOptions.maxResolvedSize,
1952
2103
  allowComposites: this.sidecarOptions.allowComposites
1953
2104
  } : void 0;
1954
- const source = wrapScriptWithToolNamespaces(code, environment.toolNamespaces);
1955
- const enclave = new import_core.Enclave({
2105
+ const { mcpLog, mcpNotify } = environment;
2106
+ const globals = {
2107
+ // Provide getTool as a custom global
2108
+ getTool: environment.getTool,
2109
+ // Provide logging functions if available
2110
+ ...mcpLog ? {
2111
+ mcpLog: (level, message, metadata) => {
2112
+ mcpLog(level, message, metadata);
2113
+ logs.push(`[mcp:${level}] ${message}`);
2114
+ }
2115
+ } : {},
2116
+ ...mcpNotify ? {
2117
+ mcpNotify: (event, payload) => {
2118
+ mcpNotify(event, payload);
2119
+ logs.push(`[notify] ${event}`);
2120
+ }
2121
+ } : {}
2122
+ // Note: enclave-vm v2.0.0+ provides its own __safe_console internally with rate limiting
2123
+ // and output size limits. Passing console in globals causes "Cannot redefine property"
2124
+ // errors due to Double VM architecture. Console output from user scripts goes to stdout
2125
+ // via enclave's internal console, not to this logs array. Only mcpLog/mcpNotify are captured.
2126
+ };
2127
+ const options = {
1956
2128
  timeout: this.vmOptions.timeoutMs,
1957
2129
  maxToolCalls: this.vmOptions.maxSteps || 100,
1958
2130
  maxIterations: 1e4,
@@ -1962,33 +2134,20 @@ var EnclaveService = class {
1962
2134
  validate: true,
1963
2135
  transform: true,
1964
2136
  sidecar,
2137
+ // Error stacks name no host file, whatever stage raised them.
2138
+ sanitizeStackTraces: true,
1965
2139
  // Allow functions in globals since we intentionally provide getTool, mcpLog, mcpNotify, and console
1966
2140
  allowFunctionsInGlobals: true,
1967
- globals: {
1968
- // Provide getTool as a custom global
1969
- getTool: environment.getTool,
1970
- // Provide logging functions if available
1971
- ...environment.mcpLog ? {
1972
- mcpLog: (level, message, metadata) => {
1973
- environment.mcpLog(level, message, metadata);
1974
- logs.push(`[mcp:${level}] ${message}`);
1975
- }
1976
- } : {},
1977
- ...environment.mcpNotify ? {
1978
- mcpNotify: (event, payload) => {
1979
- environment.mcpNotify(event, payload);
1980
- logs.push(`[notify] ${event}`);
1981
- }
1982
- } : {}
1983
- // Note: enclave-vm v2.0.0+ provides its own __safe_console internally with rate limiting
1984
- // and output size limits. Passing console in globals causes "Cannot redefine property"
1985
- // errors due to Double VM architecture. Console output from user scripts goes to stdout
1986
- // via enclave's internal console, not to this logs array. Only mcpLog/mcpNotify are captured.
1987
- }
1988
- });
2141
+ globals,
2142
+ // Tool namespaces (`acme.getUser()` for a tool named `acme.getUser`) are built by the sandbox
2143
+ // itself: a method call is exactly `callTool('acme.getUser', args, options)`, with the
2144
+ // sandbox's tool-call cap, rate limit, suspicious-sequence checks and `throwOnError`.
2145
+ toolNamespaces: toSandboxToolNamespaces(environment.toolNamespaces, Object.keys(globals))
2146
+ };
2147
+ const enclave = createEnclave(options);
1989
2148
  try {
1990
- const result = await enclave.run(source);
1991
- return this.mapEnclaveResult(result, logs);
2149
+ const result = await enclave.run(code);
2150
+ return this.mapEnclaveResult(result, logs, toolFailures, code);
1992
2151
  } finally {
1993
2152
  enclave.dispose();
1994
2153
  }
@@ -1996,58 +2155,58 @@ var EnclaveService = class {
1996
2155
  /**
1997
2156
  * Map Enclave ExecutionResult to EnclaveExecutionResult
1998
2157
  */
1999
- mapEnclaveResult(result, logs) {
2158
+ mapEnclaveResult(result, logs, toolFailures = [], script = "") {
2159
+ const stats = {
2160
+ duration: result.stats.duration,
2161
+ toolCallCount: result.stats.toolCallCount,
2162
+ iterationCount: result.stats.iterationCount
2163
+ };
2000
2164
  if (result.success) {
2165
+ return { success: true, result: result.value, logs, timedOut: false, stats };
2166
+ }
2167
+ const error = result.error ?? { name: "Error", message: "Script execution failed" };
2168
+ if (error.code === "ENCLAVE_ERROR" && error.message?.startsWith(PARSE_FAILURE_PREFIX)) {
2169
+ const { message, location } = parseFailureOf(error.message);
2001
2170
  return {
2002
- success: true,
2003
- result: result.value,
2171
+ success: false,
2172
+ error: { message, name: "SyntaxError", code: "SYNTAX_ERROR", ...location ? { location } : {} },
2004
2173
  logs,
2005
2174
  timedOut: false,
2006
- stats: {
2007
- duration: result.stats.duration,
2008
- toolCallCount: result.stats.toolCallCount,
2009
- iterationCount: result.stats.iterationCount
2010
- }
2175
+ stats
2011
2176
  };
2012
2177
  }
2013
- const error = result.error;
2014
- const timedOut = error.message?.includes("timed out") || error.code === "TIMEOUT";
2015
- if (error.code === "VALIDATION_ERROR") {
2016
- const issues = error.data?.issues ?? [];
2017
- const blockedPatterns = [...new Set(issues.map((issue) => issue.code).filter((code) => !!code))];
2178
+ const toolFailure = [...toolFailures].reverse().find((failure) => failure.message === error.message && failure.name === error.name);
2179
+ if (toolFailure) {
2018
2180
  return {
2019
2181
  success: false,
2020
2182
  error: {
2021
2183
  message: error.message,
2022
- name: "ValidationError",
2023
- code: error.code,
2024
- ...blockedPatterns.length > 0 ? { blockedPatterns } : {}
2184
+ name: error.name,
2185
+ ...toolFailure.code ? { code: toolFailure.code } : {},
2186
+ toolName: toolFailure.toolName
2025
2187
  },
2026
2188
  logs,
2027
2189
  timedOut: false,
2028
- stats: {
2029
- duration: result.stats.duration,
2030
- toolCallCount: result.stats.toolCallCount,
2031
- iterationCount: result.stats.iterationCount
2032
- }
2190
+ stats
2033
2191
  };
2034
2192
  }
2035
- const errorData = error.data;
2036
- const toolName = errorData?.["toolName"];
2037
- if (toolName) {
2193
+ const timedOut = error.message?.includes("timed out") || error.code === "TIMEOUT";
2194
+ if (error.code === "VALIDATION_ERROR") {
2195
+ const issues = error.data?.issues ?? [];
2196
+ const blockedPatterns = [...new Set(issues.map((issue) => issue.code).filter((code) => !!code))];
2038
2197
  return {
2039
2198
  success: false,
2040
2199
  error: {
2041
- message: error.message,
2042
- name: error.name,
2043
- stack: error.stack,
2200
+ // The enclave names lines of the code it validated (the script wrapped and printed again),
2201
+ // not the script's own.
2202
+ message: withScriptLines(error.message, script),
2203
+ name: "ValidationError",
2044
2204
  code: error.code,
2045
- toolName,
2046
- toolInput: errorData?.["toolInput"],
2047
- details: errorData?.["details"]
2205
+ ...blockedPatterns.length > 0 ? { blockedPatterns } : {}
2048
2206
  },
2049
2207
  logs,
2050
- timedOut
2208
+ timedOut: false,
2209
+ stats
2051
2210
  };
2052
2211
  }
2053
2212
  return {
@@ -2060,11 +2219,7 @@ var EnclaveService = class {
2060
2219
  },
2061
2220
  logs,
2062
2221
  timedOut,
2063
- stats: {
2064
- duration: result.stats.duration,
2065
- toolCallCount: result.stats.toolCallCount,
2066
- iterationCount: result.stats.iterationCount
2067
- }
2222
+ stats
2068
2223
  };
2069
2224
  }
2070
2225
  };
@@ -2075,6 +2230,16 @@ EnclaveService = __decorateClass([
2075
2230
  scope: import_sdk3.ProviderScope.GLOBAL
2076
2231
  })
2077
2232
  ], EnclaveService);
2233
+ function createEnclave(options) {
2234
+ try {
2235
+ return new import_core.Enclave(options);
2236
+ } catch (error) {
2237
+ if (!options.toolNamespaces || !(error instanceof TypeError) || !error.message.startsWith("Invalid toolNamespaces")) {
2238
+ throw error;
2239
+ }
2240
+ return new import_core.Enclave({ ...options, toolNamespaces: void 0 });
2241
+ }
2242
+ }
2078
2243
 
2079
2244
  // plugins/plugin-codecall/src/tools/search.tool.ts
2080
2245
  var import_sdk4 = require("@frontmcp/sdk");
@@ -3175,7 +3340,11 @@ var runtimeErrorPayloadSchema = import_lazy_zod7.z.object({
3175
3340
  var toolErrorPayloadSchema = import_lazy_zod7.z.object({
3176
3341
  source: import_lazy_zod7.z.literal("tool"),
3177
3342
  toolName: import_lazy_zod7.z.string(),
3178
- toolInput: import_lazy_zod7.z.unknown(),
3343
+ /**
3344
+ * @deprecated Never set: the sandbox resolves sidecar references in a call's arguments before
3345
+ * the tool sees them, so they may hold data the script itself never had.
3346
+ */
3347
+ toolInput: import_lazy_zod7.z.unknown().optional(),
3179
3348
  message: import_lazy_zod7.z.string(),
3180
3349
  code: import_lazy_zod7.z.string().optional(),
3181
3350
  /** @deprecated Never set: the enclave's error data is not sanitized for clients. */
@@ -3394,6 +3563,16 @@ var ExecuteTool = class extends import_sdk8.ToolContext {
3394
3563
  }
3395
3564
  if (!executionResult.success) {
3396
3565
  const error = executionResult.error;
3566
+ if (error.code === "SYNTAX_ERROR") {
3567
+ audit?.logExecutionFailure(executionId, script, durationMs, error.message);
3568
+ return {
3569
+ status: "syntax_error",
3570
+ error: {
3571
+ message: toClientErrorMessage(error.message) || "Syntax error in script",
3572
+ ...error.location ? { location: error.location } : {}
3573
+ }
3574
+ };
3575
+ }
3397
3576
  if (error.code === "VALIDATION_ERROR" || error.name === "ValidationError") {
3398
3577
  audit?.logSecurityAstBlocked(executionId, error.blockedPatterns?.join(", ") ?? "UNKNOWN", error.message);
3399
3578
  audit?.logExecutionFailure(executionId, script, durationMs, error.message);
@@ -3412,10 +3591,10 @@ var ExecuteTool = class extends import_sdk8.ToolContext {
3412
3591
  error: {
3413
3592
  source: "tool",
3414
3593
  toolName: error.toolName,
3415
- toolInput: error.toolInput,
3416
3594
  message: toClientErrorMessage(error.message),
3417
3595
  code: error.code
3418
- // No `details`: the enclave's error data is not sanitized for clients.
3596
+ // No `details`: the enclave's error data is not sanitized for clients. No `toolInput`:
3597
+ // the arguments the tool saw may hold sidecar-resolved data the script never had.
3419
3598
  }
3420
3599
  };
3421
3600
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@frontmcp/plugin-codecall",
3
- "version": "1.8.3",
3
+ "version": "1.8.5",
4
4
  "description": "CodeCall plugin for FrontMCP - AgentScript-based meta-tools for orchestrating MCP tools",
5
5
  "author": "AgentFront <info@agentfront.dev>",
6
6
  "license": "Apache-2.0",
@@ -48,14 +48,16 @@
48
48
  }
49
49
  },
50
50
  "dependencies": {
51
+ "@enclave-vm/ast": "^2.15.3",
51
52
  "@enclave-vm/core": "^2.15.3",
52
- "@frontmcp/protocol": "1.8.3",
53
- "@frontmcp/sdk": "1.8.3",
53
+ "@frontmcp/protocol": "1.8.5",
54
+ "@frontmcp/sdk": "1.8.5",
55
+ "acorn": "^8.15.0",
54
56
  "vectoriadb": "^2.3.2"
55
57
  },
56
58
  "peerDependencies": {
57
- "@frontmcp/lazy-zod": "1.8.3",
58
- "@frontmcp/plugin-cache": "1.8.3"
59
+ "@frontmcp/lazy-zod": "1.8.5",
60
+ "@frontmcp/plugin-cache": "1.8.5"
59
61
  },
60
62
  "devDependencies": {
61
63
  "reflect-metadata": "^0.2.2"
@@ -12,8 +12,12 @@ export interface EnclaveExecutionResult {
12
12
  stack?: string;
13
13
  code?: string;
14
14
  toolName?: string;
15
- toolInput?: unknown;
16
15
  details?: unknown;
16
+ /** For a script that doesn't parse (`code: 'SYNTAX_ERROR'`): where, in the script's own lines. */
17
+ location?: {
18
+ line: number;
19
+ column: number;
20
+ };
17
21
  /**
18
22
  * Distinct AST-validation issue codes, for the `codecall:security:ast-blocked` audit event.
19
23
  *
@@ -1 +1 @@
1
- {"version":3,"file":"enclave.service.d.ts","sourceRoot":"","sources":["../../src/services/enclave.service.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,qBAAqB,EAA6B,MAAM,oBAAoB,CAAC;AAE3F,OAAO,KAAK,cAAc,MAAM,+BAA+B,CAAC;AAGhE;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE;QACN,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,SAAS,CAAC,EAAE,OAAO,CAAC;QACpB,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB;;;;;WAKG;QACH,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;QAC3B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACxB,CAAC;IACF,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE;QACN,QAAQ,EAAE,MAAM,CAAC;QACjB,aAAa,EAAE,MAAM,CAAC;QACtB,cAAc,EAAE,MAAM,CAAC;KACxB,CAAC;CACH;AAED;;;;;;;;GAQG;AACH;;GAEG;AACH,qBAAa,mBAAoB,SAAQ,KAAK;IAC5C,QAAQ,CAAC,IAAI,sBAAsB;IACnC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;gBAEf,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;CASpD;AAOD,MAAM,CAAC,OAAO,OAAO,cAAc;IACjC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA4B;IACtD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAyB;gBAE5C,MAAM,EAAE,cAAc;IAOlC;;;;;;;OAOG;IACG,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,qBAAqB,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAsFhG;;OAEG;IACH,OAAO,CAAC,gBAAgB;CAgFzB"}
1
+ {"version":3,"file":"enclave.service.d.ts","sourceRoot":"","sources":["../../src/services/enclave.service.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,qBAAqB,EAA6B,MAAM,oBAAoB,CAAC;AAE3F,OAAO,KAAK,cAAc,MAAM,+BAA+B,CAAC;AAIhE;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE;QACN,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,kGAAkG;QAClG,QAAQ,CAAC,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,CAAA;SAAE,CAAC;QAC5C;;;;;WAKG;QACH,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;QAC3B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACxB,CAAC;IACF,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE;QACN,QAAQ,EAAE,MAAM,CAAC;QACjB,aAAa,EAAE,MAAM,CAAC;QACtB,cAAc,EAAE,MAAM,CAAC;KACxB,CAAC;CACH;AAkDD;;;;;;;;GAQG;AACH;;GAEG;AACH,qBAAa,mBAAoB,SAAQ,KAAK;IAC5C,QAAQ,CAAC,IAAI,sBAAsB;IACnC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;gBAEf,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;CASpD;AAOD,MAAM,CAAC,OAAO,OAAO,cAAc;IACjC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA4B;IACtD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAyB;gBAE5C,MAAM,EAAE,cAAc;IAOlC;;;;;;;OAOG;IACG,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,qBAAqB,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAwGhG;;OAEG;IACH,OAAO,CAAC,gBAAgB;CAyFzB"}
@@ -44,7 +44,7 @@ export declare const codeCallToolErrorResultSchema: import("@frontmcp/lazy-zod")
44
44
  error: import("@frontmcp/lazy-zod").ZodObject<{
45
45
  source: import("@frontmcp/lazy-zod").ZodLiteral<"tool">;
46
46
  toolName: import("@frontmcp/lazy-zod").ZodString;
47
- toolInput: import("@frontmcp/lazy-zod").ZodUnknown;
47
+ toolInput: import("@frontmcp/lazy-zod").ZodOptional<import("@frontmcp/lazy-zod").ZodUnknown>;
48
48
  message: import("@frontmcp/lazy-zod").ZodString;
49
49
  code: import("@frontmcp/lazy-zod").ZodOptional<import("@frontmcp/lazy-zod").ZodString>;
50
50
  details: import("@frontmcp/lazy-zod").ZodOptional<import("@frontmcp/lazy-zod").ZodUnknown>;
@@ -91,7 +91,7 @@ export declare const executeToolOutputSchema: import("@frontmcp/lazy-zod").ZodDi
91
91
  error: import("@frontmcp/lazy-zod").ZodObject<{
92
92
  source: import("@frontmcp/lazy-zod").ZodLiteral<"tool">;
93
93
  toolName: import("@frontmcp/lazy-zod").ZodString;
94
- toolInput: import("@frontmcp/lazy-zod").ZodUnknown;
94
+ toolInput: import("@frontmcp/lazy-zod").ZodOptional<import("@frontmcp/lazy-zod").ZodUnknown>;
95
95
  message: import("@frontmcp/lazy-zod").ZodString;
96
96
  code: import("@frontmcp/lazy-zod").ZodOptional<import("@frontmcp/lazy-zod").ZodString>;
97
97
  details: import("@frontmcp/lazy-zod").ZodOptional<import("@frontmcp/lazy-zod").ZodUnknown>;
@@ -1 +1 @@
1
- {"version":3,"file":"execute.schema.d.ts","sourceRoot":"","sources":["../../src/tools/execute.schema.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,oBAAoB,CAAC;AAKvC,eAAO,MAAM,sBAAsB,o7BAoBe,CAAC;AAEnD,eAAO,MAAM,sBAAsB;;;CAclC,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,sBAAsB,CAAC,CAAC,CAAC;AA8CnF;;GAEG;AACH,eAAO,MAAM,sBAAsB;;;;gCAIjC,CAAC;AAEH,eAAO,MAAM,+BAA+B;;;;;;;;;gCAG1C,CAAC;AAEH,eAAO,MAAM,iCAAiC;;;;;;gCAG5C,CAAC;AAEH,eAAO,MAAM,gCAAgC;;;;;;;;gCAG3C,CAAC;AAEH,eAAO,MAAM,6BAA6B;;;;;;;;;;gCAGxC,CAAC;AAEH,eAAO,MAAM,2BAA2B;;;;;gCAGtC,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4CAOlC,CAAC;AAEH;;;GAGG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AACtE,MAAM,MAAM,yBAAyB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,+BAA+B,CAAC,CAAC;AACxF,MAAM,MAAM,2BAA2B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iCAAiC,CAAC,CAAC;AAC5F,MAAM,MAAM,0BAA0B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gCAAgC,CAAC,CAAC;AAC1F,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,6BAA6B,CAAC,CAAC;AACpF,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC;AAEhF,MAAM,MAAM,qBAAqB,GAC7B,gBAAgB,GAChB,yBAAyB,GACzB,2BAA2B,GAC3B,0BAA0B,GAC1B,uBAAuB,GACvB,qBAAqB,CAAC"}
1
+ {"version":3,"file":"execute.schema.d.ts","sourceRoot":"","sources":["../../src/tools/execute.schema.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,oBAAoB,CAAC;AAKvC,eAAO,MAAM,sBAAsB,o7BAoBe,CAAC;AAEnD,eAAO,MAAM,sBAAsB;;;CAclC,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,sBAAsB,CAAC,CAAC,CAAC;AAkDnF;;GAEG;AACH,eAAO,MAAM,sBAAsB;;;;gCAIjC,CAAC;AAEH,eAAO,MAAM,+BAA+B;;;;;;;;;gCAG1C,CAAC;AAEH,eAAO,MAAM,iCAAiC;;;;;;gCAG5C,CAAC;AAEH,eAAO,MAAM,gCAAgC;;;;;;;;gCAG3C,CAAC;AAEH,eAAO,MAAM,6BAA6B;;;;;;;;;;gCAGxC,CAAC;AAEH,eAAO,MAAM,2BAA2B;;;;;gCAGtC,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4CAOlC,CAAC;AAEH;;;GAGG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AACtE,MAAM,MAAM,yBAAyB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,+BAA+B,CAAC,CAAC;AACxF,MAAM,MAAM,2BAA2B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iCAAiC,CAAC,CAAC;AAC5F,MAAM,MAAM,0BAA0B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gCAAgC,CAAC,CAAC;AAC1F,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,6BAA6B,CAAC,CAAC;AACpF,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC;AAEhF,MAAM,MAAM,qBAAqB,GAC7B,gBAAgB,GAChB,yBAAyB,GACzB,2BAA2B,GAC3B,0BAA0B,GAC1B,uBAAuB,GACvB,qBAAqB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"execute.tool.d.ts","sourceRoot":"","sources":["../../src/tools/execute.tool.ts"],"names":[],"mappings":"AAEA,OAAO,EAAwB,WAAW,EAAkB,MAAM,eAAe,CAAC;AAwBlF,OAAO,EAIL,KAAK,qBAAqB,EAC1B,KAAK,gBAAgB,EACtB,MAAM,kBAAkB,CAAC;AAyC1B,MAAM,CAAC,OAAO,OAAO,WAAY,SAAQ,WAAW;IAClD;;;;;;;OAOG;IACH,OAAO,CAAC,eAAe;IAIjB,OAAO,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,qBAAqB,CAAC;CAgVvE"}
1
+ {"version":3,"file":"execute.tool.d.ts","sourceRoot":"","sources":["../../src/tools/execute.tool.ts"],"names":[],"mappings":"AAEA,OAAO,EAAwB,WAAW,EAAkB,MAAM,eAAe,CAAC;AAwBlF,OAAO,EAIL,KAAK,qBAAqB,EAC1B,KAAK,gBAAgB,EACtB,MAAM,kBAAkB,CAAC;AAyC1B,MAAM,CAAC,OAAO,OAAO,WAAY,SAAQ,WAAW;IAClD;;;;;;;OAOG;IACH,OAAO,CAAC,eAAe;IAIjB,OAAO,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,qBAAqB,CAAC;CA4VvE"}
@@ -13,9 +13,9 @@ export type ToolNamespaces = Record<string, ToolNamespace>;
13
13
  * Reasons a tool may be skipped during namespace generation. Returned so the
14
14
  * caller can surface diagnostics without re-deriving the rules.
15
15
  */
16
- export type NamespaceSkipReason = 'no-namespace-prefix' | 'invalid-identifier' | 'reserved-namespace' | 'prototype-key' | 'duplicate-method';
16
+ export type NamespaceSkipReason = 'no-namespace-prefix' | 'invalid-identifier' | 'reserved-namespace' | 'prototype-key' | 'unsupported-name' | 'duplicate-method';
17
17
  export interface BuildToolNamespacesResult {
18
- /** The namespaces a script may use, as plain data. Render them with `wrapScriptWithToolNamespaces`. */
18
+ /** The namespaces a script may use, as plain data (the sandbox's `toolNamespaces`). */
19
19
  namespaces: ToolNamespaces;
20
20
  /** Tools that were skipped, with the reason. Useful for logs / lint output. */
21
21
  skipped: Array<{
@@ -32,25 +32,22 @@ export interface BuildToolNamespacesResult {
32
32
  * - Tools whose prefix collides with a reserved global or word are skipped.
33
33
  * - Tools whose prefix or suffix is a prototype key (`__proto__`, `constructor`,
34
34
  * `prototype`) are skipped.
35
+ * - Methods AgentScript refuses as property names (`fetch`, `Map`, `__x`), and tool names the
36
+ * sandbox can't carry (outside letters, digits, `:`, `.`, `_` and `-`, or not starting with a
37
+ * letter), are skipped.
35
38
  * - First registration wins on duplicate `{ns}.{method}` (subsequent are reported as skipped).
36
39
  *
37
- * The result is plain data (method → tool name). The namespace functions themselves are
38
- * written in AgentScript by `wrapScriptWithToolNamespaces`, so every call they make is a
39
- * `callTool()` inside the sandbox and goes through the sandbox's tool-call cap, rate limit
40
- * and suspicious-sequence checks, exactly like a direct `callTool()`.
40
+ * The result is plain data (method → tool name), handed to the sandbox as its `toolNamespaces`
41
+ * (see `toSandboxToolNamespaces`): the sandbox builds the namespace objects itself, and a method
42
+ * call `ns.method(args, options)` is exactly `callTool('ns.method', args, options)`, with the
43
+ * sandbox's tool-call cap, rate limit, suspicious-sequence checks and `throwOnError` handling.
41
44
  */
42
45
  export declare function buildToolNamespaces(tools: ReadonlyArray<NamespaceableTool>): BuildToolNamespacesResult;
43
46
  /**
44
- * Make the namespaces available to `script`, as AgentScript.
45
- *
46
- * Each namespace becomes a `const` object whose methods call `callTool('<ns>.<method>', input)`
47
- * inside the sandbox, so the enclave counts, rate-limits and pattern-checks them like any
48
- * other `callTool()`. (1.8.2 injected them as host functions, which reached the tool
49
- * pipeline without passing any of those checks.) The user's script runs in a nested async
50
- * function, so it can still declare its own variables with the same names.
51
- *
52
- * Only namespaces the script mentions are emitted; a script that uses none is returned as is.
53
- * Everything is emitted on the script's first line, so line numbers in parse errors are kept.
47
+ * The namespaces to hand the sandbox as its `toolNamespaces`: every namespace and method it can
48
+ * bind, next to custom globals named `reservedGlobals` (`getTool`, `mcpLog`, ...). Rechecks what
49
+ * `buildToolNamespaces` guarantees, since the sandbox refuses the whole configuration, and so fails
50
+ * every script, over a single name it can't bind. Returns undefined when nothing is left.
54
51
  */
55
- export declare function wrapScriptWithToolNamespaces(script: string, namespaces: ToolNamespaces | undefined): string;
52
+ export declare function toSandboxToolNamespaces(namespaces: ToolNamespaces | undefined, reservedGlobals?: Iterable<string>): ToolNamespaces | undefined;
56
53
  //# sourceMappingURL=build-tool-namespaces.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"build-tool-namespaces.d.ts","sourceRoot":"","sources":["../../src/utils/build-tool-namespaces.ts"],"names":[],"mappings":"AA2DA;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,qGAAqG;AACrG,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAEnD,+FAA+F;AAC/F,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;AAE3D;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAC3B,qBAAqB,GACrB,oBAAoB,GACpB,oBAAoB,GACpB,eAAe,GACf,kBAAkB,CAAC;AAEvB,MAAM,WAAW,yBAAyB;IACxC,uGAAuG;IACvG,UAAU,EAAE,cAAc,CAAC;IAC3B,+EAA+E;IAC/E,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,mBAAmB,CAAA;KAAE,CAAC,CAAC;CAC/D;AA4BD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,aAAa,CAAC,iBAAiB,CAAC,GAAG,yBAAyB,CAiDtG;AAgCD;;;;;;;;;;;GAWG;AACH,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,cAAc,GAAG,SAAS,GAAG,MAAM,CA0B3G"}
1
+ {"version":3,"file":"build-tool-namespaces.d.ts","sourceRoot":"","sources":["../../src/utils/build-tool-namespaces.ts"],"names":[],"mappings":"AA2DA;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,qGAAqG;AACrG,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAEnD,+FAA+F;AAC/F,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;AAE3D;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAC3B,qBAAqB,GACrB,oBAAoB,GACpB,oBAAoB,GACpB,eAAe,GACf,kBAAkB,GAClB,kBAAkB,CAAC;AAEvB,MAAM,WAAW,yBAAyB;IACxC,uFAAuF;IACvF,UAAU,EAAE,cAAc,CAAC;IAC3B,+EAA+E;IAC/E,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,mBAAmB,CAAA;KAAE,CAAC,CAAC;CAC/D;AAiFD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,aAAa,CAAC,iBAAiB,CAAC,GAAG,yBAAyB,CAsDtG;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,cAAc,GAAG,SAAS,EACtC,eAAe,GAAE,QAAQ,CAAC,MAAM,CAAM,GACrC,cAAc,GAAG,SAAS,CAsB5B"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * A function from a line of the code the enclave validated (for this script) to the script's own
3
+ * line, or `undefined` for a line that is none of the script's (the wrapper, a line the loop
4
+ * transform added) or a script that can't be parsed.
5
+ *
6
+ * @param script The script as the caller sent it
7
+ */
8
+ export declare function validatedLineMapper(script: string): (printedLine: number) => number | undefined;
9
+ /**
10
+ * `message` with the lines its issues name mapped back to the script's own lines. A line that is
11
+ * none of the script's is dropped rather than left pointing at the wrong line.
12
+ */
13
+ export declare function withScriptLines(message: string, script: string): string;
14
+ //# sourceMappingURL=script-lines.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"script-lines.d.ts","sourceRoot":"","sources":["../../src/utils/script-lines.ts"],"names":[],"mappings":"AA4IA;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,CAAC,WAAW,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAmB/F;AAKD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAOvE"}