@frontmcp/plugin-codecall 1.8.3 → 1.8.4
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/codecall.symbol.d.ts +8 -6
- package/codecall.symbol.d.ts.map +1 -1
- package/esm/index.mjs +157 -97
- package/esm/package.json +5 -5
- package/index.js +154 -96
- package/package.json +5 -5
- package/services/enclave.service.d.ts +5 -0
- package/services/enclave.service.d.ts.map +1 -1
- package/tools/execute.tool.d.ts.map +1 -1
- package/utils/build-tool-namespaces.d.ts +14 -17
- package/utils/build-tool-namespaces.d.ts.map +1 -1
package/codecall.symbol.d.ts
CHANGED
|
@@ -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
|
|
87
|
-
* call `
|
|
88
|
-
* `
|
|
89
|
-
*
|
|
90
|
-
*
|
|
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
|
}
|
package/codecall.symbol.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codecall.symbol.d.ts","sourceRoot":"","sources":["../src/codecall.symbol.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAEhE,MAAM,WAAW,0BAA0B;IACzC,IAAI,EAAE,sBAAsB,GAAG,kBAAkB,GAAG,gBAAgB,GAAG,YAAY,CAAC;IACpF,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5C,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,2BAA2B;IAC1C,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,0BAA0B,EAAE,CAAC;IACrC,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC;;OAEG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,2BAA2B,CAAC,CAAC;CAChE;AAED;;;GAGG;AACH,MAAM,WAAW,yBAAyB;IACxC,MAAM,EAAE,gBAAgB,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,YAAY,EAAE,OAAO,CAAC;IACtB,gBAAgB,EAAE,MAAM,CAAC;IACzB,qBAAqB,EAAE,MAAM,CAAC;CAC/B;AAED;;;;GAIG;AACH,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC5C,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CAC9C;AAED;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IACpC
|
|
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 {
|
|
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,49 @@ function buildToolNamespaces(tools) {
|
|
|
1821
1847
|
}
|
|
1822
1848
|
return { namespaces, skipped };
|
|
1823
1849
|
}
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
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 (!
|
|
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
|
|
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 (
|
|
1852
|
-
|
|
1853
|
-
|
|
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;
|
|
1856
1865
|
}
|
|
1857
|
-
if (
|
|
1858
|
-
|
|
1866
|
+
if (methodCount > 0) {
|
|
1867
|
+
bindable[ns] = bucket;
|
|
1868
|
+
count += 1;
|
|
1859
1869
|
}
|
|
1860
1870
|
}
|
|
1861
|
-
|
|
1862
|
-
return `${NAMESPACE_CALL_HELPER_SOURCE} ${declarations.join(" ")} return await (async () => {${script}
|
|
1863
|
-
})();`;
|
|
1871
|
+
return count > 0 ? bindable : void 0;
|
|
1864
1872
|
}
|
|
1865
1873
|
|
|
1866
1874
|
// plugins/plugin-codecall/src/services/enclave.service.ts
|
|
1875
|
+
function toolFailureMessage(error, toolName) {
|
|
1876
|
+
if (typeof error === "string" && error) return error;
|
|
1877
|
+
const message = error?.message;
|
|
1878
|
+
return typeof message === "string" && message ? message : `Tool call failed: ${toolName}`;
|
|
1879
|
+
}
|
|
1880
|
+
function toolFailureName(error) {
|
|
1881
|
+
const name = error && typeof error === "object" ? error.name : void 0;
|
|
1882
|
+
return typeof name === "string" && name ? name.slice(0, 128) : "ToolError";
|
|
1883
|
+
}
|
|
1884
|
+
var PARSE_FAILURE_PREFIX = "Failed to parse AgentScript code: ";
|
|
1885
|
+
var PARSE_POSITION_RE = /\((\d+):(\d+)\)$/;
|
|
1886
|
+
function parseFailureOf(message) {
|
|
1887
|
+
const match = PARSE_POSITION_RE.exec(message);
|
|
1888
|
+
const line = match ? Number(match[1]) - 1 : 0;
|
|
1889
|
+
if (!match || line < 1) return { message };
|
|
1890
|
+
const column = Number(match[2]);
|
|
1891
|
+
return { message: `${message.slice(0, match.index)}(${line}:${column})`, location: { line, column } };
|
|
1892
|
+
}
|
|
1867
1893
|
var ScriptTooLargeError = class extends Error {
|
|
1868
1894
|
code = "SCRIPT_TOO_LARGE";
|
|
1869
1895
|
scriptLength;
|
|
@@ -1901,8 +1927,20 @@ var EnclaveService = class {
|
|
|
1901
1927
|
throw new ScriptTooLargeError(code.length, maxLength);
|
|
1902
1928
|
}
|
|
1903
1929
|
}
|
|
1930
|
+
const toolFailures = [];
|
|
1904
1931
|
const toolHandler = async (toolName, args) => {
|
|
1905
|
-
|
|
1932
|
+
try {
|
|
1933
|
+
return await environment.callTool(toolName, args);
|
|
1934
|
+
} catch (error) {
|
|
1935
|
+
const code2 = error?.code;
|
|
1936
|
+
toolFailures.push({
|
|
1937
|
+
toolName,
|
|
1938
|
+
name: toolFailureName(error),
|
|
1939
|
+
message: toolFailureMessage(error, toolName),
|
|
1940
|
+
...typeof code2 === "string" ? { code: code2 } : {}
|
|
1941
|
+
});
|
|
1942
|
+
throw error;
|
|
1943
|
+
}
|
|
1906
1944
|
};
|
|
1907
1945
|
const sidecar = this.sidecarOptions.enabled ? {
|
|
1908
1946
|
enabled: true,
|
|
@@ -1912,8 +1950,29 @@ var EnclaveService = class {
|
|
|
1912
1950
|
maxResolvedSize: this.sidecarOptions.maxResolvedSize,
|
|
1913
1951
|
allowComposites: this.sidecarOptions.allowComposites
|
|
1914
1952
|
} : void 0;
|
|
1915
|
-
const
|
|
1916
|
-
const
|
|
1953
|
+
const { mcpLog, mcpNotify } = environment;
|
|
1954
|
+
const globals = {
|
|
1955
|
+
// Provide getTool as a custom global
|
|
1956
|
+
getTool: environment.getTool,
|
|
1957
|
+
// Provide logging functions if available
|
|
1958
|
+
...mcpLog ? {
|
|
1959
|
+
mcpLog: (level, message, metadata) => {
|
|
1960
|
+
mcpLog(level, message, metadata);
|
|
1961
|
+
logs.push(`[mcp:${level}] ${message}`);
|
|
1962
|
+
}
|
|
1963
|
+
} : {},
|
|
1964
|
+
...mcpNotify ? {
|
|
1965
|
+
mcpNotify: (event, payload) => {
|
|
1966
|
+
mcpNotify(event, payload);
|
|
1967
|
+
logs.push(`[notify] ${event}`);
|
|
1968
|
+
}
|
|
1969
|
+
} : {}
|
|
1970
|
+
// Note: enclave-vm v2.0.0+ provides its own __safe_console internally with rate limiting
|
|
1971
|
+
// and output size limits. Passing console in globals causes "Cannot redefine property"
|
|
1972
|
+
// errors due to Double VM architecture. Console output from user scripts goes to stdout
|
|
1973
|
+
// via enclave's internal console, not to this logs array. Only mcpLog/mcpNotify are captured.
|
|
1974
|
+
};
|
|
1975
|
+
const options = {
|
|
1917
1976
|
timeout: this.vmOptions.timeoutMs,
|
|
1918
1977
|
maxToolCalls: this.vmOptions.maxSteps || 100,
|
|
1919
1978
|
maxIterations: 1e4,
|
|
@@ -1923,33 +1982,20 @@ var EnclaveService = class {
|
|
|
1923
1982
|
validate: true,
|
|
1924
1983
|
transform: true,
|
|
1925
1984
|
sidecar,
|
|
1985
|
+
// Error stacks name no host file, whatever stage raised them.
|
|
1986
|
+
sanitizeStackTraces: true,
|
|
1926
1987
|
// Allow functions in globals since we intentionally provide getTool, mcpLog, mcpNotify, and console
|
|
1927
1988
|
allowFunctionsInGlobals: true,
|
|
1928
|
-
globals
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
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
|
-
});
|
|
1989
|
+
globals,
|
|
1990
|
+
// Tool namespaces (`acme.getUser()` for a tool named `acme.getUser`) are built by the sandbox
|
|
1991
|
+
// itself: a method call is exactly `callTool('acme.getUser', args, options)`, with the
|
|
1992
|
+
// sandbox's tool-call cap, rate limit, suspicious-sequence checks and `throwOnError`.
|
|
1993
|
+
toolNamespaces: toSandboxToolNamespaces(environment.toolNamespaces, Object.keys(globals))
|
|
1994
|
+
};
|
|
1995
|
+
const enclave = createEnclave(options);
|
|
1950
1996
|
try {
|
|
1951
|
-
const result = await enclave.run(
|
|
1952
|
-
return this.mapEnclaveResult(result, logs);
|
|
1997
|
+
const result = await enclave.run(code);
|
|
1998
|
+
return this.mapEnclaveResult(result, logs, toolFailures);
|
|
1953
1999
|
} finally {
|
|
1954
2000
|
enclave.dispose();
|
|
1955
2001
|
}
|
|
@@ -1957,58 +2003,56 @@ var EnclaveService = class {
|
|
|
1957
2003
|
/**
|
|
1958
2004
|
* Map Enclave ExecutionResult to EnclaveExecutionResult
|
|
1959
2005
|
*/
|
|
1960
|
-
mapEnclaveResult(result, logs) {
|
|
2006
|
+
mapEnclaveResult(result, logs, toolFailures = []) {
|
|
2007
|
+
const stats = {
|
|
2008
|
+
duration: result.stats.duration,
|
|
2009
|
+
toolCallCount: result.stats.toolCallCount,
|
|
2010
|
+
iterationCount: result.stats.iterationCount
|
|
2011
|
+
};
|
|
1961
2012
|
if (result.success) {
|
|
2013
|
+
return { success: true, result: result.value, logs, timedOut: false, stats };
|
|
2014
|
+
}
|
|
2015
|
+
const error = result.error ?? { name: "Error", message: "Script execution failed" };
|
|
2016
|
+
if (error.code === "ENCLAVE_ERROR" && error.message?.startsWith(PARSE_FAILURE_PREFIX)) {
|
|
2017
|
+
const { message, location } = parseFailureOf(error.message);
|
|
1962
2018
|
return {
|
|
1963
|
-
success:
|
|
1964
|
-
|
|
2019
|
+
success: false,
|
|
2020
|
+
error: { message, name: "SyntaxError", code: "SYNTAX_ERROR", ...location ? { location } : {} },
|
|
1965
2021
|
logs,
|
|
1966
2022
|
timedOut: false,
|
|
1967
|
-
stats
|
|
1968
|
-
duration: result.stats.duration,
|
|
1969
|
-
toolCallCount: result.stats.toolCallCount,
|
|
1970
|
-
iterationCount: result.stats.iterationCount
|
|
1971
|
-
}
|
|
2023
|
+
stats
|
|
1972
2024
|
};
|
|
1973
2025
|
}
|
|
1974
|
-
const
|
|
1975
|
-
|
|
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))];
|
|
2026
|
+
const toolFailure = [...toolFailures].reverse().find((failure) => failure.message === error.message && failure.name === error.name);
|
|
2027
|
+
if (toolFailure) {
|
|
1979
2028
|
return {
|
|
1980
2029
|
success: false,
|
|
1981
2030
|
error: {
|
|
1982
2031
|
message: error.message,
|
|
1983
|
-
name:
|
|
1984
|
-
code:
|
|
1985
|
-
|
|
2032
|
+
name: error.name,
|
|
2033
|
+
...toolFailure.code ? { code: toolFailure.code } : {},
|
|
2034
|
+
toolName: toolFailure.toolName
|
|
1986
2035
|
},
|
|
1987
2036
|
logs,
|
|
1988
2037
|
timedOut: false,
|
|
1989
|
-
stats
|
|
1990
|
-
duration: result.stats.duration,
|
|
1991
|
-
toolCallCount: result.stats.toolCallCount,
|
|
1992
|
-
iterationCount: result.stats.iterationCount
|
|
1993
|
-
}
|
|
2038
|
+
stats
|
|
1994
2039
|
};
|
|
1995
2040
|
}
|
|
1996
|
-
const
|
|
1997
|
-
|
|
1998
|
-
|
|
2041
|
+
const timedOut = error.message?.includes("timed out") || error.code === "TIMEOUT";
|
|
2042
|
+
if (error.code === "VALIDATION_ERROR") {
|
|
2043
|
+
const issues = error.data?.issues ?? [];
|
|
2044
|
+
const blockedPatterns = [...new Set(issues.map((issue) => issue.code).filter((code) => !!code))];
|
|
1999
2045
|
return {
|
|
2000
2046
|
success: false,
|
|
2001
2047
|
error: {
|
|
2002
2048
|
message: error.message,
|
|
2003
|
-
name:
|
|
2004
|
-
stack: error.stack,
|
|
2049
|
+
name: "ValidationError",
|
|
2005
2050
|
code: error.code,
|
|
2006
|
-
|
|
2007
|
-
toolInput: errorData?.["toolInput"],
|
|
2008
|
-
details: errorData?.["details"]
|
|
2051
|
+
...blockedPatterns.length > 0 ? { blockedPatterns } : {}
|
|
2009
2052
|
},
|
|
2010
2053
|
logs,
|
|
2011
|
-
timedOut
|
|
2054
|
+
timedOut: false,
|
|
2055
|
+
stats
|
|
2012
2056
|
};
|
|
2013
2057
|
}
|
|
2014
2058
|
return {
|
|
@@ -2021,11 +2065,7 @@ var EnclaveService = class {
|
|
|
2021
2065
|
},
|
|
2022
2066
|
logs,
|
|
2023
2067
|
timedOut,
|
|
2024
|
-
stats
|
|
2025
|
-
duration: result.stats.duration,
|
|
2026
|
-
toolCallCount: result.stats.toolCallCount,
|
|
2027
|
-
iterationCount: result.stats.iterationCount
|
|
2028
|
-
}
|
|
2068
|
+
stats
|
|
2029
2069
|
};
|
|
2030
2070
|
}
|
|
2031
2071
|
};
|
|
@@ -2036,6 +2076,16 @@ EnclaveService = __decorateClass([
|
|
|
2036
2076
|
scope: ProviderScope3.GLOBAL
|
|
2037
2077
|
})
|
|
2038
2078
|
], EnclaveService);
|
|
2079
|
+
function createEnclave(options) {
|
|
2080
|
+
try {
|
|
2081
|
+
return new Enclave(options);
|
|
2082
|
+
} catch (error) {
|
|
2083
|
+
if (!options.toolNamespaces || !(error instanceof TypeError) || !error.message.startsWith("Invalid toolNamespaces")) {
|
|
2084
|
+
throw error;
|
|
2085
|
+
}
|
|
2086
|
+
return new Enclave({ ...options, toolNamespaces: void 0 });
|
|
2087
|
+
}
|
|
2088
|
+
}
|
|
2039
2089
|
|
|
2040
2090
|
// plugins/plugin-codecall/src/tools/search.tool.ts
|
|
2041
2091
|
import { getCallSurface, Tool, ToolContext } from "@frontmcp/sdk";
|
|
@@ -3355,6 +3405,16 @@ var ExecuteTool = class extends ToolContext5 {
|
|
|
3355
3405
|
}
|
|
3356
3406
|
if (!executionResult.success) {
|
|
3357
3407
|
const error = executionResult.error;
|
|
3408
|
+
if (error.code === "SYNTAX_ERROR") {
|
|
3409
|
+
audit?.logExecutionFailure(executionId, script, durationMs, error.message);
|
|
3410
|
+
return {
|
|
3411
|
+
status: "syntax_error",
|
|
3412
|
+
error: {
|
|
3413
|
+
message: toClientErrorMessage(error.message) || "Syntax error in script",
|
|
3414
|
+
...error.location ? { location: error.location } : {}
|
|
3415
|
+
}
|
|
3416
|
+
};
|
|
3417
|
+
}
|
|
3358
3418
|
if (error.code === "VALIDATION_ERROR" || error.name === "ValidationError") {
|
|
3359
3419
|
audit?.logSecurityAstBlocked(executionId, error.blockedPatterns?.join(", ") ?? "UNKNOWN", error.message);
|
|
3360
3420
|
audit?.logExecutionFailure(executionId, script, durationMs, error.message);
|
package/esm/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@frontmcp/plugin-codecall",
|
|
3
|
-
"version": "1.8.
|
|
3
|
+
"version": "1.8.4",
|
|
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",
|
|
@@ -49,13 +49,13 @@
|
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
51
|
"@enclave-vm/core": "^2.15.3",
|
|
52
|
-
"@frontmcp/protocol": "1.8.
|
|
53
|
-
"@frontmcp/sdk": "1.8.
|
|
52
|
+
"@frontmcp/protocol": "1.8.4",
|
|
53
|
+
"@frontmcp/sdk": "1.8.4",
|
|
54
54
|
"vectoriadb": "^2.3.2"
|
|
55
55
|
},
|
|
56
56
|
"peerDependencies": {
|
|
57
|
-
"@frontmcp/lazy-zod": "1.8.
|
|
58
|
-
"@frontmcp/plugin-cache": "1.8.
|
|
57
|
+
"@frontmcp/lazy-zod": "1.8.4",
|
|
58
|
+
"@frontmcp/plugin-cache": "1.8.4"
|
|
59
59
|
},
|
|
60
60
|
"devDependencies": {
|
|
61
61
|
"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,49 @@ function buildToolNamespaces(tools) {
|
|
|
1860
1884
|
}
|
|
1861
1885
|
return { namespaces, skipped };
|
|
1862
1886
|
}
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
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 (!
|
|
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
|
|
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 (
|
|
1891
|
-
|
|
1892
|
-
|
|
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;
|
|
1895
1902
|
}
|
|
1896
|
-
if (
|
|
1897
|
-
|
|
1903
|
+
if (methodCount > 0) {
|
|
1904
|
+
bindable[ns] = bucket;
|
|
1905
|
+
count += 1;
|
|
1898
1906
|
}
|
|
1899
1907
|
}
|
|
1900
|
-
|
|
1901
|
-
return `${NAMESPACE_CALL_HELPER_SOURCE} ${declarations.join(" ")} return await (async () => {${script}
|
|
1902
|
-
})();`;
|
|
1908
|
+
return count > 0 ? bindable : void 0;
|
|
1903
1909
|
}
|
|
1904
1910
|
|
|
1905
1911
|
// plugins/plugin-codecall/src/services/enclave.service.ts
|
|
1912
|
+
function toolFailureMessage(error, toolName) {
|
|
1913
|
+
if (typeof error === "string" && error) return error;
|
|
1914
|
+
const message = error?.message;
|
|
1915
|
+
return typeof message === "string" && message ? message : `Tool call failed: ${toolName}`;
|
|
1916
|
+
}
|
|
1917
|
+
function toolFailureName(error) {
|
|
1918
|
+
const name = error && typeof error === "object" ? error.name : void 0;
|
|
1919
|
+
return typeof name === "string" && name ? name.slice(0, 128) : "ToolError";
|
|
1920
|
+
}
|
|
1921
|
+
var PARSE_FAILURE_PREFIX = "Failed to parse AgentScript code: ";
|
|
1922
|
+
var PARSE_POSITION_RE = /\((\d+):(\d+)\)$/;
|
|
1923
|
+
function parseFailureOf(message) {
|
|
1924
|
+
const match = PARSE_POSITION_RE.exec(message);
|
|
1925
|
+
const line = match ? Number(match[1]) - 1 : 0;
|
|
1926
|
+
if (!match || line < 1) return { message };
|
|
1927
|
+
const column = Number(match[2]);
|
|
1928
|
+
return { message: `${message.slice(0, match.index)}(${line}:${column})`, location: { line, column } };
|
|
1929
|
+
}
|
|
1906
1930
|
var ScriptTooLargeError = class extends Error {
|
|
1907
1931
|
code = "SCRIPT_TOO_LARGE";
|
|
1908
1932
|
scriptLength;
|
|
@@ -1940,8 +1964,20 @@ var EnclaveService = class {
|
|
|
1940
1964
|
throw new ScriptTooLargeError(code.length, maxLength);
|
|
1941
1965
|
}
|
|
1942
1966
|
}
|
|
1967
|
+
const toolFailures = [];
|
|
1943
1968
|
const toolHandler = async (toolName, args) => {
|
|
1944
|
-
|
|
1969
|
+
try {
|
|
1970
|
+
return await environment.callTool(toolName, args);
|
|
1971
|
+
} catch (error) {
|
|
1972
|
+
const code2 = error?.code;
|
|
1973
|
+
toolFailures.push({
|
|
1974
|
+
toolName,
|
|
1975
|
+
name: toolFailureName(error),
|
|
1976
|
+
message: toolFailureMessage(error, toolName),
|
|
1977
|
+
...typeof code2 === "string" ? { code: code2 } : {}
|
|
1978
|
+
});
|
|
1979
|
+
throw error;
|
|
1980
|
+
}
|
|
1945
1981
|
};
|
|
1946
1982
|
const sidecar = this.sidecarOptions.enabled ? {
|
|
1947
1983
|
enabled: true,
|
|
@@ -1951,8 +1987,29 @@ var EnclaveService = class {
|
|
|
1951
1987
|
maxResolvedSize: this.sidecarOptions.maxResolvedSize,
|
|
1952
1988
|
allowComposites: this.sidecarOptions.allowComposites
|
|
1953
1989
|
} : void 0;
|
|
1954
|
-
const
|
|
1955
|
-
const
|
|
1990
|
+
const { mcpLog, mcpNotify } = environment;
|
|
1991
|
+
const globals = {
|
|
1992
|
+
// Provide getTool as a custom global
|
|
1993
|
+
getTool: environment.getTool,
|
|
1994
|
+
// Provide logging functions if available
|
|
1995
|
+
...mcpLog ? {
|
|
1996
|
+
mcpLog: (level, message, metadata) => {
|
|
1997
|
+
mcpLog(level, message, metadata);
|
|
1998
|
+
logs.push(`[mcp:${level}] ${message}`);
|
|
1999
|
+
}
|
|
2000
|
+
} : {},
|
|
2001
|
+
...mcpNotify ? {
|
|
2002
|
+
mcpNotify: (event, payload) => {
|
|
2003
|
+
mcpNotify(event, payload);
|
|
2004
|
+
logs.push(`[notify] ${event}`);
|
|
2005
|
+
}
|
|
2006
|
+
} : {}
|
|
2007
|
+
// Note: enclave-vm v2.0.0+ provides its own __safe_console internally with rate limiting
|
|
2008
|
+
// and output size limits. Passing console in globals causes "Cannot redefine property"
|
|
2009
|
+
// errors due to Double VM architecture. Console output from user scripts goes to stdout
|
|
2010
|
+
// via enclave's internal console, not to this logs array. Only mcpLog/mcpNotify are captured.
|
|
2011
|
+
};
|
|
2012
|
+
const options = {
|
|
1956
2013
|
timeout: this.vmOptions.timeoutMs,
|
|
1957
2014
|
maxToolCalls: this.vmOptions.maxSteps || 100,
|
|
1958
2015
|
maxIterations: 1e4,
|
|
@@ -1962,33 +2019,20 @@ var EnclaveService = class {
|
|
|
1962
2019
|
validate: true,
|
|
1963
2020
|
transform: true,
|
|
1964
2021
|
sidecar,
|
|
2022
|
+
// Error stacks name no host file, whatever stage raised them.
|
|
2023
|
+
sanitizeStackTraces: true,
|
|
1965
2024
|
// Allow functions in globals since we intentionally provide getTool, mcpLog, mcpNotify, and console
|
|
1966
2025
|
allowFunctionsInGlobals: true,
|
|
1967
|
-
globals
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
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
|
-
});
|
|
2026
|
+
globals,
|
|
2027
|
+
// Tool namespaces (`acme.getUser()` for a tool named `acme.getUser`) are built by the sandbox
|
|
2028
|
+
// itself: a method call is exactly `callTool('acme.getUser', args, options)`, with the
|
|
2029
|
+
// sandbox's tool-call cap, rate limit, suspicious-sequence checks and `throwOnError`.
|
|
2030
|
+
toolNamespaces: toSandboxToolNamespaces(environment.toolNamespaces, Object.keys(globals))
|
|
2031
|
+
};
|
|
2032
|
+
const enclave = createEnclave(options);
|
|
1989
2033
|
try {
|
|
1990
|
-
const result = await enclave.run(
|
|
1991
|
-
return this.mapEnclaveResult(result, logs);
|
|
2034
|
+
const result = await enclave.run(code);
|
|
2035
|
+
return this.mapEnclaveResult(result, logs, toolFailures);
|
|
1992
2036
|
} finally {
|
|
1993
2037
|
enclave.dispose();
|
|
1994
2038
|
}
|
|
@@ -1996,58 +2040,56 @@ var EnclaveService = class {
|
|
|
1996
2040
|
/**
|
|
1997
2041
|
* Map Enclave ExecutionResult to EnclaveExecutionResult
|
|
1998
2042
|
*/
|
|
1999
|
-
mapEnclaveResult(result, logs) {
|
|
2043
|
+
mapEnclaveResult(result, logs, toolFailures = []) {
|
|
2044
|
+
const stats = {
|
|
2045
|
+
duration: result.stats.duration,
|
|
2046
|
+
toolCallCount: result.stats.toolCallCount,
|
|
2047
|
+
iterationCount: result.stats.iterationCount
|
|
2048
|
+
};
|
|
2000
2049
|
if (result.success) {
|
|
2050
|
+
return { success: true, result: result.value, logs, timedOut: false, stats };
|
|
2051
|
+
}
|
|
2052
|
+
const error = result.error ?? { name: "Error", message: "Script execution failed" };
|
|
2053
|
+
if (error.code === "ENCLAVE_ERROR" && error.message?.startsWith(PARSE_FAILURE_PREFIX)) {
|
|
2054
|
+
const { message, location } = parseFailureOf(error.message);
|
|
2001
2055
|
return {
|
|
2002
|
-
success:
|
|
2003
|
-
|
|
2056
|
+
success: false,
|
|
2057
|
+
error: { message, name: "SyntaxError", code: "SYNTAX_ERROR", ...location ? { location } : {} },
|
|
2004
2058
|
logs,
|
|
2005
2059
|
timedOut: false,
|
|
2006
|
-
stats
|
|
2007
|
-
duration: result.stats.duration,
|
|
2008
|
-
toolCallCount: result.stats.toolCallCount,
|
|
2009
|
-
iterationCount: result.stats.iterationCount
|
|
2010
|
-
}
|
|
2060
|
+
stats
|
|
2011
2061
|
};
|
|
2012
2062
|
}
|
|
2013
|
-
const
|
|
2014
|
-
|
|
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))];
|
|
2063
|
+
const toolFailure = [...toolFailures].reverse().find((failure) => failure.message === error.message && failure.name === error.name);
|
|
2064
|
+
if (toolFailure) {
|
|
2018
2065
|
return {
|
|
2019
2066
|
success: false,
|
|
2020
2067
|
error: {
|
|
2021
2068
|
message: error.message,
|
|
2022
|
-
name:
|
|
2023
|
-
code:
|
|
2024
|
-
|
|
2069
|
+
name: error.name,
|
|
2070
|
+
...toolFailure.code ? { code: toolFailure.code } : {},
|
|
2071
|
+
toolName: toolFailure.toolName
|
|
2025
2072
|
},
|
|
2026
2073
|
logs,
|
|
2027
2074
|
timedOut: false,
|
|
2028
|
-
stats
|
|
2029
|
-
duration: result.stats.duration,
|
|
2030
|
-
toolCallCount: result.stats.toolCallCount,
|
|
2031
|
-
iterationCount: result.stats.iterationCount
|
|
2032
|
-
}
|
|
2075
|
+
stats
|
|
2033
2076
|
};
|
|
2034
2077
|
}
|
|
2035
|
-
const
|
|
2036
|
-
|
|
2037
|
-
|
|
2078
|
+
const timedOut = error.message?.includes("timed out") || error.code === "TIMEOUT";
|
|
2079
|
+
if (error.code === "VALIDATION_ERROR") {
|
|
2080
|
+
const issues = error.data?.issues ?? [];
|
|
2081
|
+
const blockedPatterns = [...new Set(issues.map((issue) => issue.code).filter((code) => !!code))];
|
|
2038
2082
|
return {
|
|
2039
2083
|
success: false,
|
|
2040
2084
|
error: {
|
|
2041
2085
|
message: error.message,
|
|
2042
|
-
name:
|
|
2043
|
-
stack: error.stack,
|
|
2086
|
+
name: "ValidationError",
|
|
2044
2087
|
code: error.code,
|
|
2045
|
-
|
|
2046
|
-
toolInput: errorData?.["toolInput"],
|
|
2047
|
-
details: errorData?.["details"]
|
|
2088
|
+
...blockedPatterns.length > 0 ? { blockedPatterns } : {}
|
|
2048
2089
|
},
|
|
2049
2090
|
logs,
|
|
2050
|
-
timedOut
|
|
2091
|
+
timedOut: false,
|
|
2092
|
+
stats
|
|
2051
2093
|
};
|
|
2052
2094
|
}
|
|
2053
2095
|
return {
|
|
@@ -2060,11 +2102,7 @@ var EnclaveService = class {
|
|
|
2060
2102
|
},
|
|
2061
2103
|
logs,
|
|
2062
2104
|
timedOut,
|
|
2063
|
-
stats
|
|
2064
|
-
duration: result.stats.duration,
|
|
2065
|
-
toolCallCount: result.stats.toolCallCount,
|
|
2066
|
-
iterationCount: result.stats.iterationCount
|
|
2067
|
-
}
|
|
2105
|
+
stats
|
|
2068
2106
|
};
|
|
2069
2107
|
}
|
|
2070
2108
|
};
|
|
@@ -2075,6 +2113,16 @@ EnclaveService = __decorateClass([
|
|
|
2075
2113
|
scope: import_sdk3.ProviderScope.GLOBAL
|
|
2076
2114
|
})
|
|
2077
2115
|
], EnclaveService);
|
|
2116
|
+
function createEnclave(options) {
|
|
2117
|
+
try {
|
|
2118
|
+
return new import_core.Enclave(options);
|
|
2119
|
+
} catch (error) {
|
|
2120
|
+
if (!options.toolNamespaces || !(error instanceof TypeError) || !error.message.startsWith("Invalid toolNamespaces")) {
|
|
2121
|
+
throw error;
|
|
2122
|
+
}
|
|
2123
|
+
return new import_core.Enclave({ ...options, toolNamespaces: void 0 });
|
|
2124
|
+
}
|
|
2125
|
+
}
|
|
2078
2126
|
|
|
2079
2127
|
// plugins/plugin-codecall/src/tools/search.tool.ts
|
|
2080
2128
|
var import_sdk4 = require("@frontmcp/sdk");
|
|
@@ -3394,6 +3442,16 @@ var ExecuteTool = class extends import_sdk8.ToolContext {
|
|
|
3394
3442
|
}
|
|
3395
3443
|
if (!executionResult.success) {
|
|
3396
3444
|
const error = executionResult.error;
|
|
3445
|
+
if (error.code === "SYNTAX_ERROR") {
|
|
3446
|
+
audit?.logExecutionFailure(executionId, script, durationMs, error.message);
|
|
3447
|
+
return {
|
|
3448
|
+
status: "syntax_error",
|
|
3449
|
+
error: {
|
|
3450
|
+
message: toClientErrorMessage(error.message) || "Syntax error in script",
|
|
3451
|
+
...error.location ? { location: error.location } : {}
|
|
3452
|
+
}
|
|
3453
|
+
};
|
|
3454
|
+
}
|
|
3397
3455
|
if (error.code === "VALIDATION_ERROR" || error.name === "ValidationError") {
|
|
3398
3456
|
audit?.logSecurityAstBlocked(executionId, error.blockedPatterns?.join(", ") ?? "UNKNOWN", error.message);
|
|
3399
3457
|
audit?.logExecutionFailure(executionId, script, durationMs, error.message);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@frontmcp/plugin-codecall",
|
|
3
|
-
"version": "1.8.
|
|
3
|
+
"version": "1.8.4",
|
|
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",
|
|
@@ -49,13 +49,13 @@
|
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
51
|
"@enclave-vm/core": "^2.15.3",
|
|
52
|
-
"@frontmcp/protocol": "1.8.
|
|
53
|
-
"@frontmcp/sdk": "1.8.
|
|
52
|
+
"@frontmcp/protocol": "1.8.4",
|
|
53
|
+
"@frontmcp/sdk": "1.8.4",
|
|
54
54
|
"vectoriadb": "^2.3.2"
|
|
55
55
|
},
|
|
56
56
|
"peerDependencies": {
|
|
57
|
-
"@frontmcp/lazy-zod": "1.8.
|
|
58
|
-
"@frontmcp/plugin-cache": "1.8.
|
|
57
|
+
"@frontmcp/lazy-zod": "1.8.4",
|
|
58
|
+
"@frontmcp/plugin-cache": "1.8.4"
|
|
59
59
|
},
|
|
60
60
|
"devDependencies": {
|
|
61
61
|
"reflect-metadata": "^0.2.2"
|
|
@@ -14,6 +14,11 @@ export interface EnclaveExecutionResult {
|
|
|
14
14
|
toolName?: string;
|
|
15
15
|
toolInput?: unknown;
|
|
16
16
|
details?: unknown;
|
|
17
|
+
/** For a script that doesn't parse (`code: 'SYNTAX_ERROR'`): where, in the script's own lines. */
|
|
18
|
+
location?: {
|
|
19
|
+
line: number;
|
|
20
|
+
column: number;
|
|
21
|
+
};
|
|
17
22
|
/**
|
|
18
23
|
* Distinct AST-validation issue codes, for the `codecall:security:ast-blocked` audit event.
|
|
19
24
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"enclave.service.d.ts","sourceRoot":"","sources":["../../src/services/enclave.service.ts"],"names":[],"mappings":"
|
|
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;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,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;CAsFzB"}
|
|
@@ -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;
|
|
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
|
|
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)
|
|
38
|
-
*
|
|
39
|
-
* `
|
|
40
|
-
*
|
|
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
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
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
|
|
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,
|
|
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"}
|