@papicandela/mcx-core 0.2.2 → 0.2.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.
package/dist/index.js CHANGED
@@ -32,80 +32,132 @@ function generateNetworkIsolationCode(policy) {
32
32
  if (policy.mode === "blocked") {
33
33
  return `
34
34
  // Network isolation: BLOCKED
35
- const __original_fetch = globalThis.fetch;
36
- globalThis.fetch = async function(url, options) {
37
- throw new Error('Network access is blocked in sandbox. Use adapters instead.');
38
- };
35
+ (function() {
36
+ const blockedFetch = async function() {
37
+ throw new Error('Network access is blocked in sandbox. Use adapters instead.');
38
+ };
39
+ Object.defineProperty(globalThis, 'fetch', {
40
+ value: blockedFetch,
41
+ writable: false,
42
+ configurable: false
43
+ });
44
+ })();
39
45
 
40
46
  // Block XMLHttpRequest
41
- globalThis.XMLHttpRequest = class {
42
- constructor() {
43
- throw new Error('XMLHttpRequest is blocked in sandbox.');
44
- }
45
- };
47
+ Object.defineProperty(globalThis, 'XMLHttpRequest', {
48
+ value: class {
49
+ constructor() {
50
+ throw new Error('XMLHttpRequest is blocked in sandbox.');
51
+ }
52
+ },
53
+ writable: false,
54
+ configurable: false
55
+ });
46
56
 
47
57
  // Block WebSocket
48
- globalThis.WebSocket = class {
49
- constructor(url) {
50
- throw new Error('WebSocket is blocked in sandbox.');
51
- }
52
- };
58
+ Object.defineProperty(globalThis, 'WebSocket', {
59
+ value: class {
60
+ constructor() {
61
+ throw new Error('WebSocket is blocked in sandbox.');
62
+ }
63
+ },
64
+ writable: false,
65
+ configurable: false
66
+ });
53
67
 
54
68
  // Block EventSource (SSE)
55
- globalThis.EventSource = class {
56
- constructor(url) {
57
- throw new Error('EventSource is blocked in sandbox.');
58
- }
59
- };
69
+ Object.defineProperty(globalThis, 'EventSource', {
70
+ value: class {
71
+ constructor() {
72
+ throw new Error('EventSource is blocked in sandbox.');
73
+ }
74
+ },
75
+ writable: false,
76
+ configurable: false
77
+ });
60
78
  `;
61
79
  }
62
80
  const domainsJson = JSON.stringify(policy.domains);
63
81
  return `
64
82
  // Network isolation: ALLOWED (whitelist)
65
- const __allowed_domains = ${domainsJson};
66
- const __original_fetch = globalThis.fetch;
83
+ (function() {
84
+ const _domains = ${domainsJson};
85
+ const _real_fetch = globalThis.fetch;
67
86
 
68
- function __isUrlAllowed(url) {
69
- try {
70
- const hostname = new URL(url).hostname;
71
- return __allowed_domains.some(d => hostname === d || hostname.endsWith('.' + d));
72
- } catch {
73
- return false;
87
+ // Block private/link-local IPs to prevent DNS rebinding attacks
88
+ function _isPrivateIp(hostname) {
89
+ return /^(localhost|127\\.|10\\.|192\\.168\\.|172\\.(1[6-9]|2\\d|3[01])\\.|169\\.254\\.|\\[::1\\]|\\[fc|\\[fd)/.test(hostname);
74
90
  }
75
- }
76
91
 
77
- globalThis.fetch = async function(url, options) {
78
- const urlStr = typeof url === 'string' ? url : url instanceof URL ? url.toString() : url.url;
79
- if (!__isUrlAllowed(urlStr)) {
80
- const hostname = new URL(urlStr).hostname;
81
- throw new Error(\`Network access blocked: \${hostname} not in allowed domains: \${__allowed_domains.join(', ')}\`);
92
+ function _isUrlAllowed(url) {
93
+ try {
94
+ const parsed = new URL(url);
95
+ // Only allow http/https protocols
96
+ if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:') return false;
97
+ const hostname = parsed.hostname;
98
+ if (!hostname || _isPrivateIp(hostname)) return false;
99
+ return _domains.some(d => d && (hostname === d || hostname.endsWith('.' + d)));
100
+ } catch {
101
+ return false;
102
+ }
82
103
  }
83
- return __original_fetch(url, options);
84
- };
104
+
105
+ const whitelistedFetch = async function(url, options) {
106
+ // Safely extract URL string from various input types
107
+ let urlStr;
108
+ try {
109
+ if (typeof url === 'string') urlStr = url;
110
+ else if (url instanceof URL) urlStr = url.toString();
111
+ else if (url && typeof url.url === 'string') urlStr = url.url;
112
+ else throw new Error('Invalid URL type');
113
+ } catch {
114
+ throw new Error('Network access blocked: could not determine request URL.');
115
+ }
116
+ if (!_isUrlAllowed(urlStr)) {
117
+ throw new Error('Network access blocked: domain not in allowed list.');
118
+ }
119
+ return _real_fetch(url, options);
120
+ };
121
+
122
+ Object.defineProperty(globalThis, 'fetch', {
123
+ value: whitelistedFetch,
124
+ writable: false,
125
+ configurable: false
126
+ });
127
+ })();
85
128
 
86
129
  // Block XMLHttpRequest (not easily whitelistable)
87
- globalThis.XMLHttpRequest = class {
88
- constructor() {
89
- throw new Error('XMLHttpRequest is blocked. Use fetch() with allowed domains.');
90
- }
91
- };
130
+ Object.defineProperty(globalThis, 'XMLHttpRequest', {
131
+ value: class {
132
+ constructor() {
133
+ throw new Error('XMLHttpRequest is blocked. Use fetch() with allowed domains.');
134
+ }
135
+ },
136
+ writable: false,
137
+ configurable: false
138
+ });
92
139
 
93
- // Block WebSocket (would need separate whitelist)
94
- globalThis.WebSocket = class {
95
- constructor(url) {
96
- if (!__isUrlAllowed(url)) {
97
- throw new Error('WebSocket blocked: domain not in allowed list.');
140
+ // Block WebSocket - opaque error to prevent allowlist enumeration
141
+ Object.defineProperty(globalThis, 'WebSocket', {
142
+ value: class {
143
+ constructor() {
144
+ throw new Error('WebSocket is not supported in sandbox.');
98
145
  }
99
- throw new Error('WebSocket not supported in sandbox even for allowed domains.');
100
- }
101
- };
146
+ },
147
+ writable: false,
148
+ configurable: false
149
+ });
102
150
 
103
151
  // Block EventSource
104
- globalThis.EventSource = class {
105
- constructor(url) {
106
- throw new Error('EventSource is blocked in sandbox.');
107
- }
108
- };
152
+ Object.defineProperty(globalThis, 'EventSource', {
153
+ value: class {
154
+ constructor() {
155
+ throw new Error('EventSource is blocked in sandbox.');
156
+ }
157
+ },
158
+ writable: false,
159
+ configurable: false
160
+ });
109
161
  `;
110
162
  }
111
163
 
@@ -5587,24 +5639,31 @@ function isLiteralTrue(node) {
5587
5639
  return false;
5588
5640
  return node.type === "Literal" && node.value === true;
5589
5641
  }
5590
- function hasBreak(node) {
5642
+ function hasExitStatement(node) {
5591
5643
  if (node.type === "BreakStatement")
5592
5644
  return true;
5645
+ if (node.type === "ReturnStatement")
5646
+ return true;
5647
+ if (node.type === "ThrowStatement")
5648
+ return true;
5593
5649
  if (node.type === "WhileStatement" || node.type === "ForStatement" || node.type === "ForInStatement" || node.type === "ForOfStatement" || node.type === "DoWhileStatement" || node.type === "SwitchStatement") {
5594
5650
  return false;
5595
5651
  }
5652
+ if (node.type === "FunctionDeclaration" || node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression") {
5653
+ return false;
5654
+ }
5596
5655
  for (const key of Object.keys(node)) {
5597
5656
  const child = node[key];
5598
5657
  if (child && typeof child === "object") {
5599
5658
  if (Array.isArray(child)) {
5600
5659
  for (const item of child) {
5601
5660
  if (item && typeof item === "object" && "type" in item) {
5602
- if (hasBreak(item))
5661
+ if (hasExitStatement(item))
5603
5662
  return true;
5604
5663
  }
5605
5664
  }
5606
5665
  } else if ("type" in child) {
5607
- if (hasBreak(child))
5666
+ if (hasExitStatement(child))
5608
5667
  return true;
5609
5668
  }
5610
5669
  }
@@ -5614,25 +5673,35 @@ function hasBreak(node) {
5614
5673
  var rule = {
5615
5674
  name: "no-infinite-loop",
5616
5675
  severity: "error",
5617
- description: "Disallow infinite loops without break statements",
5618
- visits: ["WhileStatement", "ForStatement"],
5676
+ description: "Disallow infinite loops without exit statements",
5677
+ visits: ["WhileStatement", "ForStatement", "DoWhileStatement"],
5619
5678
  visitors: {
5620
5679
  WhileStatement(node, context) {
5621
5680
  const whileNode = node;
5622
- if (isLiteralTrue(whileNode.test) && !hasBreak(whileNode.body)) {
5681
+ if (isLiteralTrue(whileNode.test) && !hasExitStatement(whileNode.body)) {
5623
5682
  context.report({
5624
5683
  severity: "error",
5625
- message: "Infinite loop: while(true) without break",
5684
+ message: "Infinite loop: while(true) without break/return/throw",
5626
5685
  line: context.getLine(node)
5627
5686
  });
5628
5687
  }
5629
5688
  },
5630
5689
  ForStatement(node, context) {
5631
5690
  const forNode = node;
5632
- if (!forNode.test && !hasBreak(forNode.body)) {
5691
+ if (!forNode.test && !hasExitStatement(forNode.body)) {
5633
5692
  context.report({
5634
5693
  severity: "error",
5635
- message: "Infinite loop: for(;;) without break",
5694
+ message: "Infinite loop: for(;;) without break/return/throw",
5695
+ line: context.getLine(node)
5696
+ });
5697
+ }
5698
+ },
5699
+ DoWhileStatement(node, context) {
5700
+ const doWhileNode = node;
5701
+ if (isLiteralTrue(doWhileNode.test) && !hasExitStatement(doWhileNode.body)) {
5702
+ context.report({
5703
+ severity: "error",
5704
+ message: "Infinite loop: do...while(true) without break/return/throw",
5636
5705
  line: context.getLine(node)
5637
5706
  });
5638
5707
  }
@@ -5938,49 +6007,100 @@ var EVAL_NAME = "ev" + "al";
5938
6007
  var FUNC_CONSTRUCTOR = "Func" + "tion";
5939
6008
  var REQUIRE_NAME = "req" + "uire";
5940
6009
  var PROCESS_NAME = "pro" + "cess";
6010
+ var DANGEROUS_GLOBALS = ["globalThis", "self", "window"];
6011
+ function isConstructorOnFunction(node) {
6012
+ const prop = node.property;
6013
+ const isConstructorAccess = !node.computed && prop.type === "Identifier" && prop.name === "constructor" || node.computed && prop.type === "Literal" && prop.value === "constructor";
6014
+ if (!isConstructorAccess)
6015
+ return false;
6016
+ const obj = node.object;
6017
+ if (obj.type === "FunctionExpression" || obj.type === "ArrowFunctionExpression") {
6018
+ return true;
6019
+ }
6020
+ if (obj.type === "CallExpression") {
6021
+ const call = obj;
6022
+ if (call.callee.type === "MemberExpression") {
6023
+ const callee = call.callee;
6024
+ if (callee.object.type === "Identifier" && callee.object.name === "Object" && callee.property.type === "Identifier" && callee.property.name === "getPrototypeOf") {
6025
+ return true;
6026
+ }
6027
+ }
6028
+ }
6029
+ return false;
6030
+ }
5941
6031
  var rule5 = {
5942
6032
  name: "no-dangerous-globals",
5943
6033
  severity: "warn",
5944
- description: "Warn about dangerous globals not available in sandbox",
5945
- visits: ["CallExpression", "NewExpression", "Identifier", "MemberExpression"],
6034
+ description: "Block dangerous globals that could escape sandbox",
6035
+ visits: ["CallExpression", "NewExpression", "MemberExpression"],
5946
6036
  visitors: {
5947
6037
  CallExpression(node, context) {
5948
6038
  const callExpr = node;
5949
- if (callExpr.callee.type === "Identifier" && callExpr.callee.name === EVAL_NAME) {
6039
+ const calleeName = callExpr.callee.type === "Identifier" ? callExpr.callee.name : null;
6040
+ if (calleeName === EVAL_NAME) {
5950
6041
  context.report({
5951
- severity: "warn",
5952
- message: `${EVAL_NAME}() is not available in sandbox`,
6042
+ severity: "error",
6043
+ message: `${EVAL_NAME}() is blocked in sandbox - potential code injection`,
5953
6044
  line: context.getLine(node)
5954
6045
  });
5955
6046
  return;
5956
6047
  }
5957
- if (callExpr.callee.type === "Identifier" && callExpr.callee.name === REQUIRE_NAME) {
6048
+ if (calleeName === FUNC_CONSTRUCTOR) {
5958
6049
  context.report({
5959
- severity: "warn",
5960
- message: `${REQUIRE_NAME}() is not available in sandbox - use adapters instead`,
6050
+ severity: "error",
6051
+ message: `${FUNC_CONSTRUCTOR}() is blocked in sandbox - potential code injection`,
5961
6052
  line: context.getLine(node)
5962
6053
  });
5963
6054
  return;
5964
6055
  }
5965
- },
5966
- NewExpression(node, context) {
5967
- const newExpr = node;
5968
- if (newExpr.callee.type === "Identifier" && newExpr.callee.name === FUNC_CONSTRUCTOR) {
6056
+ if (calleeName === REQUIRE_NAME) {
5969
6057
  context.report({
5970
- severity: "warn",
5971
- message: `${FUNC_CONSTRUCTOR} constructor is not recommended in sandbox`,
6058
+ severity: "error",
6059
+ message: `${REQUIRE_NAME}() is blocked in sandbox - could access dangerous modules`,
5972
6060
  line: context.getLine(node)
5973
6061
  });
6062
+ return;
6063
+ }
6064
+ if (callExpr.callee.type === "MemberExpression") {
6065
+ if (isConstructorOnFunction(callExpr.callee)) {
6066
+ context.report({
6067
+ severity: "error",
6068
+ message: `Accessing .constructor on functions is blocked - potential sandbox escape`,
6069
+ line: context.getLine(node)
6070
+ });
6071
+ return;
6072
+ }
5974
6073
  }
5975
6074
  },
5976
- Identifier(node, context) {
5977
- const identifier = node;
5978
- if (identifier.name === PROCESS_NAME) {
6075
+ NewExpression(node, context) {
6076
+ const newExpr = node;
6077
+ if (newExpr.callee.type === "Identifier" && newExpr.callee.name === FUNC_CONSTRUCTOR) {
5979
6078
  context.report({
5980
- severity: "warn",
5981
- message: `'${PROCESS_NAME}' is not available in sandbox`,
6079
+ severity: "error",
6080
+ message: `${FUNC_CONSTRUCTOR} constructor is blocked in sandbox - potential code injection`,
5982
6081
  line: context.getLine(node)
5983
6082
  });
6083
+ return;
6084
+ }
6085
+ if (newExpr.callee.type === "MemberExpression") {
6086
+ if (isConstructorOnFunction(newExpr.callee)) {
6087
+ context.report({
6088
+ severity: "error",
6089
+ message: `Accessing .constructor on functions is blocked - potential sandbox escape`,
6090
+ line: context.getLine(node)
6091
+ });
6092
+ return;
6093
+ }
6094
+ }
6095
+ if (newExpr.callee.type === "MemberExpression") {
6096
+ const member = newExpr.callee;
6097
+ if (member.object.type === "Identifier" && DANGEROUS_GLOBALS.includes(member.object.name) && member.property.type === "Identifier" && member.property.name === FUNC_CONSTRUCTOR) {
6098
+ context.report({
6099
+ severity: "error",
6100
+ message: `${FUNC_CONSTRUCTOR} constructor is blocked in sandbox - potential code injection`,
6101
+ line: context.getLine(node)
6102
+ });
6103
+ }
5984
6104
  }
5985
6105
  },
5986
6106
  MemberExpression(node, context) {
@@ -5991,6 +6111,14 @@ var rule5 = {
5991
6111
  message: `'${PROCESS_NAME}' is not available in sandbox`,
5992
6112
  line: context.getLine(node)
5993
6113
  });
6114
+ return;
6115
+ }
6116
+ if (memberExpr.object.type === "Identifier" && DANGEROUS_GLOBALS.includes(memberExpr.object.name) && memberExpr.property.type === "Identifier" && memberExpr.property.name === FUNC_CONSTRUCTOR) {
6117
+ context.report({
6118
+ severity: "error",
6119
+ message: `Accessing ${FUNC_CONSTRUCTOR} via globals is blocked - potential sandbox escape`,
6120
+ line: context.getLine(node)
6121
+ });
5994
6122
  }
5995
6123
  }
5996
6124
  }
@@ -6130,7 +6258,7 @@ function analyze(code, config = {}) {
6130
6258
  const errors = findings.filter((f) => f.severity === "error");
6131
6259
  const elapsed = performance.now() - start;
6132
6260
  if (elapsed > 50) {
6133
- console.warn(`[mcx-analyzer] Exceeded 50ms budget: ${elapsed.toFixed(1)}ms`);
6261
+ console.error(`[mcx-analyzer] Exceeded 50ms budget: ${elapsed.toFixed(1)}ms`);
6134
6262
  }
6135
6263
  return { warnings, errors, elapsed };
6136
6264
  }
@@ -6210,14 +6338,17 @@ class BunWorkerSandbox {
6210
6338
  const url = URL.createObjectURL(blob);
6211
6339
  const worker = new Worker(url);
6212
6340
  let resolved = false;
6341
+ let timeoutId;
6213
6342
  const cleanup = () => {
6214
6343
  if (!resolved) {
6215
6344
  resolved = true;
6345
+ if (timeoutId)
6346
+ clearTimeout(timeoutId);
6216
6347
  worker.terminate();
6217
6348
  URL.revokeObjectURL(url);
6218
6349
  }
6219
6350
  };
6220
- const timeoutId = setTimeout(() => {
6351
+ timeoutId = setTimeout(() => {
6221
6352
  if (!resolved) {
6222
6353
  cleanup();
6223
6354
  resolve({
@@ -6229,6 +6360,8 @@ class BunWorkerSandbox {
6229
6360
  }
6230
6361
  }, this.config.timeout);
6231
6362
  worker.onmessage = async (event) => {
6363
+ if (resolved)
6364
+ return;
6232
6365
  const { type, ...data2 } = event.data;
6233
6366
  if (type === "ready") {
6234
6367
  worker.postMessage({ type: "execute", data: { code: normalizedCode } });
@@ -6246,7 +6379,6 @@ class BunWorkerSandbox {
6246
6379
  worker.postMessage({ type: "adapter_result", data: { id, error } });
6247
6380
  }
6248
6381
  } else if (type === "result") {
6249
- clearTimeout(timeoutId);
6250
6382
  cleanup();
6251
6383
  resolve({
6252
6384
  success: data2.success,
@@ -6258,7 +6390,6 @@ class BunWorkerSandbox {
6258
6390
  }
6259
6391
  };
6260
6392
  worker.onerror = (error) => {
6261
- clearTimeout(timeoutId);
6262
6393
  cleanup();
6263
6394
  resolve({
6264
6395
  success: false,
@@ -6287,11 +6418,27 @@ class BunWorkerSandbox {
6287
6418
  const pendingCalls = new Map();
6288
6419
  let callId = 0;
6289
6420
 
6421
+ // Safe stringify that handles BigInt and circular refs
6422
+ const safeStr = (val) => {
6423
+ if (typeof val !== 'object' || val === null) return String(val);
6424
+ try {
6425
+ const seen = new WeakSet();
6426
+ return JSON.stringify(val, (k, v) => {
6427
+ if (typeof v === 'bigint') return v.toString() + 'n';
6428
+ if (typeof v === 'object' && v !== null) {
6429
+ if (seen.has(v)) return '[Circular]';
6430
+ seen.add(v);
6431
+ }
6432
+ return v;
6433
+ });
6434
+ } catch { return String(val); }
6435
+ };
6436
+
6290
6437
  const console = {
6291
- log: (...args) => logs.push(args.map(a => typeof a === 'object' ? JSON.stringify(a) : String(a)).join(' ')),
6292
- warn: (...args) => logs.push('[WARN] ' + args.map(a => typeof a === 'object' ? JSON.stringify(a) : String(a)).join(' ')),
6293
- error: (...args) => logs.push('[ERROR] ' + args.map(a => typeof a === 'object' ? JSON.stringify(a) : String(a)).join(' ')),
6294
- info: (...args) => logs.push('[INFO] ' + args.map(a => typeof a === 'object' ? JSON.stringify(a) : String(a)).join(' ')),
6438
+ log: (...args) => logs.push(args.map(safeStr).join(' ')),
6439
+ warn: (...args) => logs.push('[WARN] ' + args.map(safeStr).join(' ')),
6440
+ error: (...args) => logs.push('[ERROR] ' + args.map(safeStr).join(' ')),
6441
+ info: (...args) => logs.push('[INFO] ' + args.map(safeStr).join(' ')),
6295
6442
  };
6296
6443
  globalThis.console = console;
6297
6444
 
@@ -6341,21 +6488,41 @@ class BunWorkerSandbox {
6341
6488
  return arr.slice(0, n);
6342
6489
  };
6343
6490
 
6491
+ // SECURITY: Reserved keys that must not be overwritten by user-provided variables/globals
6492
+ const RESERVED_KEYS = new Set([
6493
+ 'onmessage', 'postMessage', 'close', 'terminate', 'self',
6494
+ 'constructor', 'prototype', '__proto__',
6495
+ 'pendingCalls', 'callId', 'logs', 'console', 'adapters',
6496
+ 'fetch', 'XMLHttpRequest', 'WebSocket', 'EventSource',
6497
+ 'pick', 'table', 'count', 'sum', 'first', 'safeStr'
6498
+ ]);
6499
+
6344
6500
  self.onmessage = async (event) => {
6345
6501
  const { type, data } = event.data;
6346
6502
 
6347
6503
  if (type === 'init') {
6348
6504
  const { variables, adapterMethods, globals } = data;
6349
6505
 
6506
+ // Inject user variables (skip reserved keys to prevent internal state corruption)
6350
6507
  for (const [key, value] of Object.entries(variables || {})) {
6508
+ if (RESERVED_KEYS.has(key)) {
6509
+ logs.push('[WARN] Skipped reserved variable key: ' + key);
6510
+ continue;
6511
+ }
6351
6512
  globalThis[key] = value;
6352
6513
  }
6353
6514
 
6515
+ // Inject sandbox globals (skip reserved keys)
6354
6516
  for (const [key, value] of Object.entries(globals || {})) {
6517
+ if (RESERVED_KEYS.has(key)) {
6518
+ logs.push('[WARN] Skipped reserved globals key: ' + key);
6519
+ continue;
6520
+ }
6355
6521
  globalThis[key] = value;
6356
6522
  }
6357
6523
 
6358
- globalThis.adapters = {};
6524
+ // Create adapter proxies and freeze them to prevent user code modification
6525
+ const adaptersObj = {};
6359
6526
  for (const [adapterName, methods] of Object.entries(adapterMethods)) {
6360
6527
  const adapterObj = {};
6361
6528
  for (const methodName of methods) {
@@ -6373,9 +6540,23 @@ class BunWorkerSandbox {
6373
6540
  });
6374
6541
  };
6375
6542
  }
6376
- globalThis.adapters[adapterName] = adapterObj;
6377
- globalThis[adapterName] = adapterObj;
6543
+ // Freeze individual adapter to prevent method tampering
6544
+ Object.freeze(adapterObj);
6545
+ adaptersObj[adapterName] = adapterObj;
6546
+ // Also expose at top level but as non-writable
6547
+ Object.defineProperty(globalThis, adapterName, {
6548
+ value: adapterObj,
6549
+ writable: false,
6550
+ configurable: false
6551
+ });
6378
6552
  }
6553
+ // Freeze the adapters namespace and make it non-writable
6554
+ Object.freeze(adaptersObj);
6555
+ Object.defineProperty(globalThis, 'adapters', {
6556
+ value: adaptersObj,
6557
+ writable: false,
6558
+ configurable: false
6559
+ });
6379
6560
 
6380
6561
  self.postMessage({ type: 'ready' });
6381
6562
  }
@@ -6398,10 +6579,12 @@ class BunWorkerSandbox {
6398
6579
  const result = await fn();
6399
6580
  self.postMessage({ type: 'result', success: true, value: result, logs });
6400
6581
  } catch (err) {
6582
+ // Truncate stack to 5 lines to prevent context bloat
6583
+ const stack = err.stack ? err.stack.split('\\n').slice(0, 5).join('\\n') : undefined;
6401
6584
  self.postMessage({
6402
6585
  type: 'result',
6403
6586
  success: false,
6404
- error: { name: err.name, message: err.message, stack: err.stack },
6587
+ error: { name: err.name, message: err.message, stack },
6405
6588
  logs
6406
6589
  });
6407
6590
  }
@@ -10411,12 +10594,12 @@ function createParameterValidator(params) {
10411
10594
  default:
10412
10595
  schema = exports_external.unknown();
10413
10596
  }
10414
- if (param.default !== undefined) {
10415
- schema = schema.default(param.default);
10416
- }
10417
10597
  if (!param.required) {
10418
10598
  schema = schema.optional();
10419
10599
  }
10600
+ if (param.default !== undefined) {
10601
+ schema = schema.default(param.default);
10602
+ }
10420
10603
  shape[param.name] = schema;
10421
10604
  }
10422
10605
  return exports_external.object(shape);
@@ -10559,7 +10742,10 @@ var DEFAULT_CONFIG2 = {
10559
10742
  timeout: 5000,
10560
10743
  memoryLimit: 128,
10561
10744
  allowAsync: true,
10562
- globals: {}
10745
+ globals: {},
10746
+ networkPolicy: DEFAULT_NETWORK_POLICY,
10747
+ normalizeCode: true,
10748
+ analysis: DEFAULT_ANALYSIS_CONFIG
10563
10749
  },
10564
10750
  adaptersDir: "./adapters",
10565
10751
  skillsDir: "./skills"
@@ -10653,21 +10839,22 @@ function generateTypes(adapters, options = {}) {
10653
10839
  const safeName = sanitizeIdentifier(adapter.name);
10654
10840
  for (const [toolName, tool] of Object.entries(adapter.tools)) {
10655
10841
  if (tool.parameters && Object.keys(tool.parameters).length > 0) {
10656
- const inputTypeName = `${capitalize(safeName)}_${capitalize(toolName)}_Input`;
10842
+ const safeToolNameForType = sanitizeIdentifier(toolName);
10843
+ const inputTypeName = `${capitalize(safeName)}_${capitalize(safeToolNameForType)}_Input`;
10657
10844
  lines.push(generateInputInterface(inputTypeName, tool.parameters, includeDescriptions));
10658
10845
  lines.push("");
10659
10846
  }
10660
10847
  }
10661
10848
  if (includeDescriptions && adapter.description) {
10662
- lines.push(`/** ${adapter.description} */`);
10849
+ lines.push(`/** ${sanitizeJSDoc(adapter.description)} */`);
10663
10850
  }
10664
10851
  lines.push(`declare const ${safeName}: {`);
10665
10852
  for (const [toolName, tool] of Object.entries(adapter.tools)) {
10666
10853
  const safeToolName = sanitizeIdentifier(toolName);
10667
10854
  const hasParams = tool.parameters && Object.keys(tool.parameters).length > 0;
10668
- const inputTypeName = `${capitalize(safeName)}_${capitalize(toolName)}_Input`;
10855
+ const inputTypeName = `${capitalize(safeName)}_${capitalize(safeToolName)}_Input`;
10669
10856
  if (includeDescriptions && tool.description) {
10670
- lines.push(` /** ${tool.description} */`);
10857
+ lines.push(` /** ${sanitizeJSDoc(tool.description)} */`);
10671
10858
  }
10672
10859
  const paramStr = hasParams ? `params: ${inputTypeName}` : "";
10673
10860
  const returnType = asyncResults ? "Promise<unknown>" : "unknown";
@@ -10681,20 +10868,21 @@ function generateTypes(adapters, options = {}) {
10681
10868
  }
10682
10869
  function generateTypesSummary(adapters) {
10683
10870
  return adapters.map((adapter) => {
10684
- const methods = Object.keys(adapter.tools).join(", ");
10685
- return `${adapter.name}: { ${methods} }`;
10871
+ const count = Object.keys(adapter.tools).length;
10872
+ return `- ${adapter.name} (${count} methods)`;
10686
10873
  }).join(`
10687
10874
  `);
10688
10875
  }
10689
10876
  function generateInputInterface(typeName, parameters, includeDescriptions) {
10690
10877
  const lines = [`interface ${typeName} {`];
10691
10878
  for (const [paramName, param] of Object.entries(parameters)) {
10879
+ const safeParamName = sanitizeIdentifier(paramName);
10692
10880
  if (includeDescriptions && param.description) {
10693
- lines.push(` /** ${param.description} */`);
10881
+ lines.push(` /** ${sanitizeJSDoc(param.description)} */`);
10694
10882
  }
10695
10883
  const tsType = paramTypeToTS(param.type);
10696
10884
  const optional = param.required === false ? "?" : "";
10697
- lines.push(` ${paramName}${optional}: ${tsType};`);
10885
+ lines.push(` ${safeParamName}${optional}: ${tsType};`);
10698
10886
  }
10699
10887
  lines.push("}");
10700
10888
  return lines.join(`
@@ -10767,6 +10955,9 @@ function sanitizeIdentifier(name) {
10767
10955
  function capitalize(str) {
10768
10956
  return str.charAt(0).toUpperCase() + str.slice(1);
10769
10957
  }
10958
+ function sanitizeJSDoc(text) {
10959
+ return text.replace(/\*\//g, "* /").replace(/[\r\n]+/g, " ");
10960
+ }
10770
10961
  // src/executor.ts
10771
10962
  import { pathToFileURL } from "node:url";
10772
10963
  class MCXExecutor {
@@ -10823,7 +11014,7 @@ class MCXExecutor {
10823
11014
  }
10824
11015
  registerAdapter(adapter) {
10825
11016
  if (this.adapters.has(adapter.name)) {
10826
- console.warn(`Adapter "${adapter.name}" is being overwritten`);
11017
+ console.error(`[MCX] Adapter "${adapter.name}" is being overwritten`);
10827
11018
  }
10828
11019
  this.adapters.set(adapter.name, adapter);
10829
11020
  }
@@ -10838,7 +11029,7 @@ class MCXExecutor {
10838
11029
  }
10839
11030
  registerSkill(skill) {
10840
11031
  if (this.skills.has(skill.name)) {
10841
- console.warn(`Skill "${skill.name}" is being overwritten`);
11032
+ console.error(`[MCX] Skill "${skill.name}" is being overwritten`);
10842
11033
  }
10843
11034
  this.skills.set(skill.name, skill);
10844
11035
  }
@@ -10905,12 +11096,15 @@ class MCXExecutor {
10905
11096
  };
10906
11097
  } catch (error) {
10907
11098
  const err = error instanceof Error ? error : new Error(String(error));
11099
+ const stack = err.stack ? err.stack.split(`
11100
+ `).slice(0, 5).join(`
11101
+ `) : undefined;
10908
11102
  return {
10909
11103
  success: false,
10910
11104
  error: {
10911
11105
  name: err.name,
10912
11106
  message: err.message,
10913
- stack: err.stack
11107
+ stack
10914
11108
  },
10915
11109
  logs: [],
10916
11110
  executionTime: performance.now() - startTime