@papicandela/mcx-core 0.2.7 → 0.2.8
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 +104 -1
- package/package.json +1 -1
- package/src/sandbox/bun-worker.ts +104 -1
package/dist/index.js
CHANGED
|
@@ -6537,13 +6537,116 @@ class BunWorkerSandbox {
|
|
|
6537
6537
|
throw new Error('waitFor timeout after ' + timeout + 'ms');
|
|
6538
6538
|
};
|
|
6539
6539
|
|
|
6540
|
+
/**
|
|
6541
|
+
* Get lines around a specific line number (1-indexed).
|
|
6542
|
+
* @param file - File object with .lines array
|
|
6543
|
+
* @param line - Line number (1-indexed)
|
|
6544
|
+
* @param ctx - Context lines before/after (default 10)
|
|
6545
|
+
*/
|
|
6546
|
+
globalThis.around = (file, line, ctx = 10) => {
|
|
6547
|
+
const lines = file?.lines;
|
|
6548
|
+
if (!Array.isArray(lines)) return [];
|
|
6549
|
+
if (line < 1 || line > lines.length) return [];
|
|
6550
|
+
const idx = line - 1;
|
|
6551
|
+
return lines.slice(Math.max(0, idx - ctx), Math.min(lines.length, idx + ctx + 1));
|
|
6552
|
+
};
|
|
6553
|
+
|
|
6554
|
+
/**
|
|
6555
|
+
* Extract code block containing a line (detects by indentation).
|
|
6556
|
+
* @param file - File object with .lines array
|
|
6557
|
+
* @param line - Line number (1-indexed)
|
|
6558
|
+
*/
|
|
6559
|
+
globalThis.block = (file, line) => {
|
|
6560
|
+
const lines = file?.lines;
|
|
6561
|
+
if (!Array.isArray(lines)) return [];
|
|
6562
|
+
const idx = line - 1;
|
|
6563
|
+
if (idx < 0 || idx >= lines.length) return [];
|
|
6564
|
+
|
|
6565
|
+
const targetIndent = lines[idx].search(/\\S/);
|
|
6566
|
+
if (targetIndent < 0) return [lines[idx]];
|
|
6567
|
+
|
|
6568
|
+
// Find block start
|
|
6569
|
+
let start = idx;
|
|
6570
|
+
for (let i = idx - 1; i >= 0; i--) {
|
|
6571
|
+
const lineIndent = lines[i].search(/\\S/);
|
|
6572
|
+
if (lineIndent >= 0 && lineIndent < targetIndent) { start = i; break; }
|
|
6573
|
+
if (lineIndent === 0 && lines[i].trim()) { start = i; break; }
|
|
6574
|
+
}
|
|
6575
|
+
|
|
6576
|
+
// Find block end
|
|
6577
|
+
const startIndent = lines[start].search(/\\S/);
|
|
6578
|
+
let end = idx;
|
|
6579
|
+
for (let i = idx + 1; i < lines.length; i++) {
|
|
6580
|
+
const lineIndent = lines[i].search(/\\S/);
|
|
6581
|
+
if (lineIndent >= 0 && lineIndent <= startIndent && lines[i].trim()) { end = i - 1; break; }
|
|
6582
|
+
end = i;
|
|
6583
|
+
}
|
|
6584
|
+
|
|
6585
|
+
return lines.slice(start, end + 1);
|
|
6586
|
+
};
|
|
6587
|
+
|
|
6588
|
+
/**
|
|
6589
|
+
* Grep with context lines.
|
|
6590
|
+
* @param file - File object with .lines array
|
|
6591
|
+
* @param pattern - String or regex pattern
|
|
6592
|
+
* @param ctx - Context lines (default 3)
|
|
6593
|
+
*/
|
|
6594
|
+
globalThis.grep = (file, pattern, ctx = 3) => {
|
|
6595
|
+
const lines = file?.lines;
|
|
6596
|
+
if (!Array.isArray(lines)) return [];
|
|
6597
|
+
const regex = typeof pattern === 'string' ? new RegExp(pattern, 'i') : pattern;
|
|
6598
|
+
const results = [];
|
|
6599
|
+
|
|
6600
|
+
for (let i = 0; i < lines.length; i++) {
|
|
6601
|
+
if (regex.test(lines[i])) {
|
|
6602
|
+
results.push({
|
|
6603
|
+
line: i + 1,
|
|
6604
|
+
match: lines[i],
|
|
6605
|
+
context: lines.slice(Math.max(0, i - ctx), i + ctx + 1)
|
|
6606
|
+
});
|
|
6607
|
+
}
|
|
6608
|
+
}
|
|
6609
|
+
return results;
|
|
6610
|
+
};
|
|
6611
|
+
|
|
6612
|
+
/**
|
|
6613
|
+
* Extract outline (function/class signatures).
|
|
6614
|
+
* @param file - File object with .lines array
|
|
6615
|
+
*/
|
|
6616
|
+
globalThis.outline = (file) => {
|
|
6617
|
+
const lines = file?.lines;
|
|
6618
|
+
if (!Array.isArray(lines)) return [];
|
|
6619
|
+
const signatures = [];
|
|
6620
|
+
const patterns = [
|
|
6621
|
+
/^(export\\s+)?(async\\s+)?function\\s+\\w+/,
|
|
6622
|
+
/^(export\\s+)?(const|let|var)\\s+\\w+\\s*=\\s*(async\\s+)?\\(/,
|
|
6623
|
+
/^(export\\s+)?(const|let|var)\\s+\\w+\\s*=\\s*(async\\s+)?function/,
|
|
6624
|
+
/^(export\\s+)?class\\s+\\w+/,
|
|
6625
|
+
/^(export\\s+)?interface\\s+\\w+/,
|
|
6626
|
+
/^(export\\s+)?type\\s+\\w+/,
|
|
6627
|
+
/^\\s+(async\\s+)?\\w+\\s*\\([^)]*\\)\\s*[:{]/,
|
|
6628
|
+
];
|
|
6629
|
+
|
|
6630
|
+
for (let i = 0; i < lines.length; i++) {
|
|
6631
|
+
const line = lines[i];
|
|
6632
|
+
for (const pat of patterns) {
|
|
6633
|
+
if (pat.test(line)) {
|
|
6634
|
+
signatures.push((i + 1) + ': ' + line.trim().slice(0, 80));
|
|
6635
|
+
break;
|
|
6636
|
+
}
|
|
6637
|
+
}
|
|
6638
|
+
}
|
|
6639
|
+
return signatures;
|
|
6640
|
+
};
|
|
6641
|
+
|
|
6540
6642
|
// SECURITY: Reserved keys that must not be overwritten by user-provided variables/globals
|
|
6541
6643
|
const RESERVED_KEYS = new Set([
|
|
6542
6644
|
'onmessage', 'postMessage', 'close', 'terminate', 'self',
|
|
6543
6645
|
'constructor', 'prototype', '__proto__',
|
|
6544
6646
|
'pendingCalls', 'callId', 'logs', 'console', 'adapters',
|
|
6545
6647
|
'fetch', 'XMLHttpRequest', 'WebSocket', 'EventSource',
|
|
6546
|
-
'pick', 'table', 'count', 'sum', 'first', 'safeStr', 'poll', 'waitFor'
|
|
6648
|
+
'pick', 'table', 'count', 'sum', 'first', 'safeStr', 'poll', 'waitFor',
|
|
6649
|
+
'around', 'block', 'grep', 'outline'
|
|
6547
6650
|
]);
|
|
6548
6651
|
|
|
6549
6652
|
self.onmessage = async (event) => {
|
package/package.json
CHANGED
|
@@ -334,13 +334,116 @@ export class BunWorkerSandbox implements ISandbox {
|
|
|
334
334
|
throw new Error('waitFor timeout after ' + timeout + 'ms');
|
|
335
335
|
};
|
|
336
336
|
|
|
337
|
+
/**
|
|
338
|
+
* Get lines around a specific line number (1-indexed).
|
|
339
|
+
* @param file - File object with .lines array
|
|
340
|
+
* @param line - Line number (1-indexed)
|
|
341
|
+
* @param ctx - Context lines before/after (default 10)
|
|
342
|
+
*/
|
|
343
|
+
globalThis.around = (file, line, ctx = 10) => {
|
|
344
|
+
const lines = file?.lines;
|
|
345
|
+
if (!Array.isArray(lines)) return [];
|
|
346
|
+
if (line < 1 || line > lines.length) return [];
|
|
347
|
+
const idx = line - 1;
|
|
348
|
+
return lines.slice(Math.max(0, idx - ctx), Math.min(lines.length, idx + ctx + 1));
|
|
349
|
+
};
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Extract code block containing a line (detects by indentation).
|
|
353
|
+
* @param file - File object with .lines array
|
|
354
|
+
* @param line - Line number (1-indexed)
|
|
355
|
+
*/
|
|
356
|
+
globalThis.block = (file, line) => {
|
|
357
|
+
const lines = file?.lines;
|
|
358
|
+
if (!Array.isArray(lines)) return [];
|
|
359
|
+
const idx = line - 1;
|
|
360
|
+
if (idx < 0 || idx >= lines.length) return [];
|
|
361
|
+
|
|
362
|
+
const targetIndent = lines[idx].search(/\\S/);
|
|
363
|
+
if (targetIndent < 0) return [lines[idx]];
|
|
364
|
+
|
|
365
|
+
// Find block start
|
|
366
|
+
let start = idx;
|
|
367
|
+
for (let i = idx - 1; i >= 0; i--) {
|
|
368
|
+
const lineIndent = lines[i].search(/\\S/);
|
|
369
|
+
if (lineIndent >= 0 && lineIndent < targetIndent) { start = i; break; }
|
|
370
|
+
if (lineIndent === 0 && lines[i].trim()) { start = i; break; }
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// Find block end
|
|
374
|
+
const startIndent = lines[start].search(/\\S/);
|
|
375
|
+
let end = idx;
|
|
376
|
+
for (let i = idx + 1; i < lines.length; i++) {
|
|
377
|
+
const lineIndent = lines[i].search(/\\S/);
|
|
378
|
+
if (lineIndent >= 0 && lineIndent <= startIndent && lines[i].trim()) { end = i - 1; break; }
|
|
379
|
+
end = i;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
return lines.slice(start, end + 1);
|
|
383
|
+
};
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* Grep with context lines.
|
|
387
|
+
* @param file - File object with .lines array
|
|
388
|
+
* @param pattern - String or regex pattern
|
|
389
|
+
* @param ctx - Context lines (default 3)
|
|
390
|
+
*/
|
|
391
|
+
globalThis.grep = (file, pattern, ctx = 3) => {
|
|
392
|
+
const lines = file?.lines;
|
|
393
|
+
if (!Array.isArray(lines)) return [];
|
|
394
|
+
const regex = typeof pattern === 'string' ? new RegExp(pattern, 'i') : pattern;
|
|
395
|
+
const results = [];
|
|
396
|
+
|
|
397
|
+
for (let i = 0; i < lines.length; i++) {
|
|
398
|
+
if (regex.test(lines[i])) {
|
|
399
|
+
results.push({
|
|
400
|
+
line: i + 1,
|
|
401
|
+
match: lines[i],
|
|
402
|
+
context: lines.slice(Math.max(0, i - ctx), i + ctx + 1)
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
return results;
|
|
407
|
+
};
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* Extract outline (function/class signatures).
|
|
411
|
+
* @param file - File object with .lines array
|
|
412
|
+
*/
|
|
413
|
+
globalThis.outline = (file) => {
|
|
414
|
+
const lines = file?.lines;
|
|
415
|
+
if (!Array.isArray(lines)) return [];
|
|
416
|
+
const signatures = [];
|
|
417
|
+
const patterns = [
|
|
418
|
+
/^(export\\s+)?(async\\s+)?function\\s+\\w+/,
|
|
419
|
+
/^(export\\s+)?(const|let|var)\\s+\\w+\\s*=\\s*(async\\s+)?\\(/,
|
|
420
|
+
/^(export\\s+)?(const|let|var)\\s+\\w+\\s*=\\s*(async\\s+)?function/,
|
|
421
|
+
/^(export\\s+)?class\\s+\\w+/,
|
|
422
|
+
/^(export\\s+)?interface\\s+\\w+/,
|
|
423
|
+
/^(export\\s+)?type\\s+\\w+/,
|
|
424
|
+
/^\\s+(async\\s+)?\\w+\\s*\\([^)]*\\)\\s*[:{]/,
|
|
425
|
+
];
|
|
426
|
+
|
|
427
|
+
for (let i = 0; i < lines.length; i++) {
|
|
428
|
+
const line = lines[i];
|
|
429
|
+
for (const pat of patterns) {
|
|
430
|
+
if (pat.test(line)) {
|
|
431
|
+
signatures.push((i + 1) + ': ' + line.trim().slice(0, 80));
|
|
432
|
+
break;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
return signatures;
|
|
437
|
+
};
|
|
438
|
+
|
|
337
439
|
// SECURITY: Reserved keys that must not be overwritten by user-provided variables/globals
|
|
338
440
|
const RESERVED_KEYS = new Set([
|
|
339
441
|
'onmessage', 'postMessage', 'close', 'terminate', 'self',
|
|
340
442
|
'constructor', 'prototype', '__proto__',
|
|
341
443
|
'pendingCalls', 'callId', 'logs', 'console', 'adapters',
|
|
342
444
|
'fetch', 'XMLHttpRequest', 'WebSocket', 'EventSource',
|
|
343
|
-
'pick', 'table', 'count', 'sum', 'first', 'safeStr', 'poll', 'waitFor'
|
|
445
|
+
'pick', 'table', 'count', 'sum', 'first', 'safeStr', 'poll', 'waitFor',
|
|
446
|
+
'around', 'block', 'grep', 'outline'
|
|
344
447
|
]);
|
|
345
448
|
|
|
346
449
|
self.onmessage = async (event) => {
|