koishi-plugin-ishiki-workspace 0.0.2 → 0.0.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/lib/index.cjs +312 -9
- package/lib/index.js +305 -2
- package/lib/js-bootstrap.d.ts +5 -0
- package/package.json +3 -3
package/lib/index.cjs
CHANGED
|
@@ -355,7 +355,309 @@ var WorkspaceScheme = class extends import_koishi_plugin_ishiki2.FileScheme {
|
|
|
355
355
|
|
|
356
356
|
// src/sandbox.ts
|
|
357
357
|
var import_node_path4 = __toESM(require("node:path"));
|
|
358
|
-
|
|
358
|
+
|
|
359
|
+
// src/js-bootstrap.ts
|
|
360
|
+
var JAVASCRIPT_FS_BOOTSTRAP = String.raw`
|
|
361
|
+
(function () {
|
|
362
|
+
var hostKey = Object.getOwnPropertyNames(globalThis).filter(function (name) {
|
|
363
|
+
return name.indexOf('__jbHost_') === 0;
|
|
364
|
+
})[0];
|
|
365
|
+
if (!hostKey) throw new Error('js-exec host bridge is unavailable');
|
|
366
|
+
var host = globalThis[hostKey];
|
|
367
|
+
var fs = globalThis.fs;
|
|
368
|
+
function unwrap(result) {
|
|
369
|
+
if (!result || result.ok !== true) throw new Error(result && result.error || 'Host operation failed');
|
|
370
|
+
return result.value;
|
|
371
|
+
}
|
|
372
|
+
var raw = {};
|
|
373
|
+
var names = [
|
|
374
|
+
'readFileBuffer', 'readFileSync', 'writeFileSync', 'appendFileSync',
|
|
375
|
+
'statSync', 'lstatSync', 'readdirSync', 'mkdirSync', 'rmSync',
|
|
376
|
+
'symlinkSync', 'readlinkSync', 'chmodSync', 'realpathSync',
|
|
377
|
+
'renameSync', 'copyFileSync'
|
|
378
|
+
];
|
|
379
|
+
for (var index = 0; index < names.length; index++) raw[names[index]] = fs[names[index]];
|
|
380
|
+
|
|
381
|
+
var errnos = {
|
|
382
|
+
EPERM: -1,
|
|
383
|
+
ENOENT: -2,
|
|
384
|
+
EIO: -5,
|
|
385
|
+
EACCES: -13,
|
|
386
|
+
EEXIST: -17,
|
|
387
|
+
ENOTDIR: -20,
|
|
388
|
+
EISDIR: -21,
|
|
389
|
+
EINVAL: -22,
|
|
390
|
+
ENOSPC: -28,
|
|
391
|
+
EROFS: -30,
|
|
392
|
+
ENAMETOOLONG: -36,
|
|
393
|
+
ENOTEMPTY: -39,
|
|
394
|
+
ELOOP: -40
|
|
395
|
+
};
|
|
396
|
+
|
|
397
|
+
function failure(error, syscall, target, destination) {
|
|
398
|
+
if (!(error instanceof Error)) error = new Error(String(error));
|
|
399
|
+
var matched = /^([A-Z][A-Z0-9]+):/.exec(error.message);
|
|
400
|
+
if (matched) {
|
|
401
|
+
error.code = matched[1];
|
|
402
|
+
if (errnos[error.code] !== undefined) error.errno = errnos[error.code];
|
|
403
|
+
}
|
|
404
|
+
error.syscall = syscall;
|
|
405
|
+
if (target !== undefined) {
|
|
406
|
+
error.path = String(target);
|
|
407
|
+
error.message = error.message.replace(/'[^']*'(?=\s*$)/, "'" + String(target).replace(/'/g, "\\'") + "'");
|
|
408
|
+
}
|
|
409
|
+
if (destination !== undefined) error.dest = String(destination);
|
|
410
|
+
return error;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
function bridge(hostName, syscall, target, args, destination) {
|
|
414
|
+
try {
|
|
415
|
+
var operation = host[hostName];
|
|
416
|
+
if (args.length === 1) return unwrap(operation(args[0]));
|
|
417
|
+
if (args.length === 2) return unwrap(operation(args[0], args[1]));
|
|
418
|
+
if (args.length === 3) return unwrap(operation(args[0], args[1], args[2]));
|
|
419
|
+
return unwrap(operation(args[0], args[1], args[2], args[3]));
|
|
420
|
+
} catch (error) {
|
|
421
|
+
throw failure(error, syscall, target, destination);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
function bytes(value) {
|
|
426
|
+
if (value && value._data instanceof Uint8Array) return Array.from(value._data);
|
|
427
|
+
if (value && Array.isArray(value._data)) return value._data.slice();
|
|
428
|
+
if (Array.isArray(value)) return value.slice();
|
|
429
|
+
if (value instanceof Uint8Array) return Array.from(value);
|
|
430
|
+
return String(value);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
function stats(value) {
|
|
434
|
+
var mtime = value.mtime instanceof Date ? value.mtime : new Date(value.mtime);
|
|
435
|
+
var size = Number(value.size);
|
|
436
|
+
var result = {
|
|
437
|
+
dev: 0,
|
|
438
|
+
ino: 0,
|
|
439
|
+
mode: Number(value.mode),
|
|
440
|
+
nlink: value.isDirectory ? 2 : 1,
|
|
441
|
+
uid: 1000,
|
|
442
|
+
gid: 1000,
|
|
443
|
+
rdev: 0,
|
|
444
|
+
size: size,
|
|
445
|
+
blksize: 4096,
|
|
446
|
+
blocks: Math.ceil(size / 512),
|
|
447
|
+
atime: mtime,
|
|
448
|
+
mtime: mtime,
|
|
449
|
+
ctime: mtime,
|
|
450
|
+
birthtime: mtime,
|
|
451
|
+
atimeMs: mtime.getTime(),
|
|
452
|
+
mtimeMs: mtime.getTime(),
|
|
453
|
+
ctimeMs: mtime.getTime(),
|
|
454
|
+
birthtimeMs: mtime.getTime()
|
|
455
|
+
};
|
|
456
|
+
result.isFile = function () { return value.isFile; };
|
|
457
|
+
result.isDirectory = function () { return value.isDirectory; };
|
|
458
|
+
result.isSymbolicLink = function () { return value.isSymbolicLink; };
|
|
459
|
+
result.isBlockDevice = function () { return false; };
|
|
460
|
+
result.isCharacterDevice = function () { return false; };
|
|
461
|
+
result.isFIFO = function () { return false; };
|
|
462
|
+
result.isSocket = function () { return false; };
|
|
463
|
+
return result;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
function dirent(name, parentPath, value) {
|
|
467
|
+
var result = { name: String(name), parentPath: String(parentPath), path: String(parentPath) };
|
|
468
|
+
result.isFile = function () { return value.isFile; };
|
|
469
|
+
result.isDirectory = function () { return value.isDirectory; };
|
|
470
|
+
result.isSymbolicLink = function () { return value.isSymbolicLink; };
|
|
471
|
+
result.isBlockDevice = function () { return false; };
|
|
472
|
+
result.isCharacterDevice = function () { return false; };
|
|
473
|
+
result.isFIFO = function () { return false; };
|
|
474
|
+
result.isSocket = function () { return false; };
|
|
475
|
+
return result;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
function childPath(parent, name) {
|
|
479
|
+
return parent.charAt(parent.length - 1) === '/' ? parent + name : parent + '/' + name;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
function readStats(path, follow) {
|
|
483
|
+
return bridge('fsStat', follow ? 'stat' : 'lstat', path, [path, !follow]);
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
function collect(path, relative, options, output) {
|
|
487
|
+
var listing = bridge('fsReaddir', 'scandir', path, [path]);
|
|
488
|
+
for (var index = 0; index < listing.length; index++) {
|
|
489
|
+
var name = listing[index];
|
|
490
|
+
var nested = relative === '' ? name : relative + '/' + name;
|
|
491
|
+
var full = childPath(path, name);
|
|
492
|
+
var value = readStats(full, false);
|
|
493
|
+
output.push(options.withFileTypes ? dirent(name, path, value) : nested);
|
|
494
|
+
if (options.recursive && value.isDirectory) collect(full, nested, options, output);
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
function readdir(path, options) {
|
|
499
|
+
if (typeof options === 'string') options = { encoding: options };
|
|
500
|
+
options = options || {};
|
|
501
|
+
var output = [];
|
|
502
|
+
collect(path, '', { recursive: Boolean(options.recursive), withFileTypes: Boolean(options.withFileTypes) }, output);
|
|
503
|
+
if (options.encoding === 'buffer') return output.map(function (entry) {
|
|
504
|
+
return typeof entry === 'string' ? Buffer.from(entry) : entry;
|
|
505
|
+
});
|
|
506
|
+
return output;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
function firstCreated(path) {
|
|
510
|
+
var text = String(path);
|
|
511
|
+
var absolute = text.charAt(0) === '/';
|
|
512
|
+
var parts = text.split('/');
|
|
513
|
+
var current = '';
|
|
514
|
+
var found;
|
|
515
|
+
for (var index = 0; index < parts.length; index++) {
|
|
516
|
+
var part = parts[index];
|
|
517
|
+
if (part === '' || part === '.') continue;
|
|
518
|
+
if (current === '') current = absolute ? '/' + part : part;
|
|
519
|
+
else current = childPath(current, part);
|
|
520
|
+
if (!fs.existsSync(current)) {
|
|
521
|
+
found = current;
|
|
522
|
+
break;
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
return found;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
fs.readFileBuffer = function (path) {
|
|
529
|
+
try {
|
|
530
|
+
return raw.readFileBuffer(path);
|
|
531
|
+
} catch (error) {
|
|
532
|
+
throw failure(error, 'open', path);
|
|
533
|
+
}
|
|
534
|
+
};
|
|
535
|
+
fs.readFileSync = function (path, options) {
|
|
536
|
+
try {
|
|
537
|
+
return raw.readFileSync(path, options);
|
|
538
|
+
} catch (error) {
|
|
539
|
+
throw failure(error, 'open', path);
|
|
540
|
+
}
|
|
541
|
+
};
|
|
542
|
+
fs.writeFileSync = function (path, data) {
|
|
543
|
+
bridge('fsWrite', 'open', path, [path, bytes(data)]);
|
|
544
|
+
};
|
|
545
|
+
fs.appendFileSync = function (path, data) {
|
|
546
|
+
bridge('fsAppend', 'open', path, [path, bytes(data)]);
|
|
547
|
+
};
|
|
548
|
+
fs.statSync = function (path) {
|
|
549
|
+
return stats(readStats(path, true));
|
|
550
|
+
};
|
|
551
|
+
fs.lstatSync = function (path) {
|
|
552
|
+
return stats(readStats(path, false));
|
|
553
|
+
};
|
|
554
|
+
fs.readdirSync = readdir;
|
|
555
|
+
fs.mkdirSync = function (path, options) {
|
|
556
|
+
var recursive = Boolean(options && typeof options === 'object' && options.recursive);
|
|
557
|
+
var created = recursive ? firstCreated(path) : undefined;
|
|
558
|
+
bridge('fsMkdir', 'mkdir', path, [path, recursive]);
|
|
559
|
+
return created;
|
|
560
|
+
};
|
|
561
|
+
fs.rmSync = function (path, options) {
|
|
562
|
+
bridge('fsRm', 'rm', path, [path, Boolean(options && options.recursive), Boolean(options && options.force)]);
|
|
563
|
+
};
|
|
564
|
+
fs.existsSync = function (path) {
|
|
565
|
+
try {
|
|
566
|
+
return bridge('fsExists', 'access', path, [path]);
|
|
567
|
+
} catch (error) {
|
|
568
|
+
return false;
|
|
569
|
+
}
|
|
570
|
+
};
|
|
571
|
+
fs.symlinkSync = function (target, path) {
|
|
572
|
+
bridge('fsSymlink', 'symlink', path, [target, path]);
|
|
573
|
+
};
|
|
574
|
+
fs.readlinkSync = function (path) {
|
|
575
|
+
return bridge('fsReadlink', 'readlink', path, [path]);
|
|
576
|
+
};
|
|
577
|
+
fs.chmodSync = function (path, mode) {
|
|
578
|
+
bridge('fsChmod', 'chmod', path, [path, Number(mode)]);
|
|
579
|
+
};
|
|
580
|
+
fs.realpathSync = function (path) {
|
|
581
|
+
return bridge('fsRealpath', 'realpath', path, [path]);
|
|
582
|
+
};
|
|
583
|
+
fs.renameSync = function (from, to) {
|
|
584
|
+
bridge('fsRename', 'rename', from, [from, to], to);
|
|
585
|
+
};
|
|
586
|
+
fs.copyFileSync = function (from, to) {
|
|
587
|
+
bridge('fsCopy', 'copyfile', from, [from, to], to);
|
|
588
|
+
};
|
|
589
|
+
fs.unlinkSync = function (path) {
|
|
590
|
+
bridge('fsRm', 'unlink', path, [path, false, false]);
|
|
591
|
+
};
|
|
592
|
+
fs.rmdirSync = function (path, options) {
|
|
593
|
+
bridge('fsRm', 'rmdir', path, [path, Boolean(options && options.recursive), false]);
|
|
594
|
+
};
|
|
595
|
+
|
|
596
|
+
var callbackNames = [
|
|
597
|
+
['readFile', fs.readFileSync],
|
|
598
|
+
['writeFile', fs.writeFileSync],
|
|
599
|
+
['appendFile', fs.appendFileSync],
|
|
600
|
+
['stat', fs.statSync],
|
|
601
|
+
['lstat', fs.lstatSync],
|
|
602
|
+
['readdir', fs.readdirSync],
|
|
603
|
+
['mkdir', fs.mkdirSync],
|
|
604
|
+
['rm', fs.rmSync],
|
|
605
|
+
['symlink', fs.symlinkSync],
|
|
606
|
+
['readlink', fs.readlinkSync],
|
|
607
|
+
['chmod', fs.chmodSync],
|
|
608
|
+
['realpath', fs.realpathSync],
|
|
609
|
+
['rename', fs.renameSync],
|
|
610
|
+
['copyFile', fs.copyFileSync],
|
|
611
|
+
['unlink', fs.unlinkSync],
|
|
612
|
+
['rmdir', fs.rmdirSync]
|
|
613
|
+
];
|
|
614
|
+
function callbackify(name, sync) {
|
|
615
|
+
fs[name] = function () {
|
|
616
|
+
var args = Array.prototype.slice.call(arguments);
|
|
617
|
+
var callback = args.pop();
|
|
618
|
+
if (typeof callback !== 'function') throw new TypeError('The "cb" argument must be of type function. Received ' + typeof callback);
|
|
619
|
+
Promise.resolve().then(function () {
|
|
620
|
+
return sync.apply(fs, args);
|
|
621
|
+
}).then(function (value) {
|
|
622
|
+
callback(null, value);
|
|
623
|
+
}, function (error) {
|
|
624
|
+
callback(error);
|
|
625
|
+
});
|
|
626
|
+
};
|
|
627
|
+
}
|
|
628
|
+
for (var index = 0; index < callbackNames.length; index++) callbackify(callbackNames[index][0], callbackNames[index][1]);
|
|
629
|
+
fs.exists = function (path, callback) {
|
|
630
|
+
if (typeof callback !== 'function') throw new TypeError('The "cb" argument must be of type function. Received ' + typeof callback);
|
|
631
|
+
Promise.resolve().then(function () { callback(fs.existsSync(path)); });
|
|
632
|
+
};
|
|
633
|
+
|
|
634
|
+
var promiseNames = [
|
|
635
|
+
'readFile', 'writeFile', 'appendFile', 'stat', 'lstat', 'readdir',
|
|
636
|
+
'mkdir', 'rm', 'symlink', 'readlink', 'chmod', 'realpath',
|
|
637
|
+
'rename', 'copyFile', 'unlink', 'rmdir'
|
|
638
|
+
];
|
|
639
|
+
fs.promises = {};
|
|
640
|
+
for (var index = 0; index < promiseNames.length; index++) (function (name) {
|
|
641
|
+
var sync = fs[name + 'Sync'];
|
|
642
|
+
fs.promises[name] = function () {
|
|
643
|
+
var args = arguments;
|
|
644
|
+
return new Promise(function (resolve, reject) {
|
|
645
|
+
Promise.resolve().then(function () {
|
|
646
|
+
return sync.apply(fs, args);
|
|
647
|
+
}).then(resolve, reject);
|
|
648
|
+
});
|
|
649
|
+
};
|
|
650
|
+
})(promiseNames[index]);
|
|
651
|
+
fs.promises.access = function (path) {
|
|
652
|
+
return new Promise(function (resolve, reject) {
|
|
653
|
+
if (fs.existsSync(path)) resolve();
|
|
654
|
+
else reject(failure(new Error("ENOENT: no such file or directory, access '" + path + "'"), 'access', path));
|
|
655
|
+
});
|
|
656
|
+
};
|
|
657
|
+
|
|
658
|
+
globalThis.fs = fs;
|
|
659
|
+
})();
|
|
660
|
+
`;
|
|
359
661
|
|
|
360
662
|
// src/resource-fs.ts
|
|
361
663
|
var EROFS = /* @__PURE__ */ __name(() => new Error("EROFS: resource mounts are read-only"), "EROFS");
|
|
@@ -513,8 +815,9 @@ function traversable(stat2) {
|
|
|
513
815
|
}
|
|
514
816
|
__name(traversable, "traversable");
|
|
515
817
|
async function createSandbox(layout, options) {
|
|
818
|
+
const { Bash, InMemoryFs, MountableFs, OverlayFs, ReadWriteFs } = await import("just-bash");
|
|
516
819
|
const { home } = options;
|
|
517
|
-
class Writable extends
|
|
820
|
+
class Writable extends ReadWriteFs {
|
|
518
821
|
static {
|
|
519
822
|
__name(this, "Writable");
|
|
520
823
|
}
|
|
@@ -525,26 +828,26 @@ async function createSandbox(layout, options) {
|
|
|
525
828
|
return traversable(await super.lstat(path7));
|
|
526
829
|
}
|
|
527
830
|
}
|
|
528
|
-
const homeView = new
|
|
529
|
-
base: new
|
|
530
|
-
mounts: [{ mountPoint: HOME_MOUNT, filesystem: new
|
|
831
|
+
const homeView = new MountableFs({
|
|
832
|
+
base: new InMemoryFs(),
|
|
833
|
+
mounts: [{ mountPoint: HOME_MOUNT, filesystem: new OverlayFs({ root: home, mountPoint: "/", readOnly: true }) }]
|
|
531
834
|
});
|
|
532
|
-
const fs3 = new
|
|
835
|
+
const fs3 = new MountableFs({
|
|
533
836
|
base: homeView,
|
|
534
837
|
mounts: [
|
|
535
838
|
{ mountPoint: WORKSPACE_MOUNT, filesystem: new Writable({ root: import_node_path4.default.join(home, "workspace") }) },
|
|
536
839
|
...options.resources ? [{ mountPoint: ISHIKI_MOUNT, filesystem: new ResourceFs(options.resources) }] : [],
|
|
537
840
|
...layout.mounts.map((mount) => ({
|
|
538
841
|
mountPoint: mount.target,
|
|
539
|
-
filesystem: mount.readOnly ? new
|
|
842
|
+
filesystem: mount.readOnly ? new OverlayFs({ root: mount.source, mountPoint: "/", readOnly: true }) : new Writable({ root: mount.source })
|
|
540
843
|
}))
|
|
541
844
|
]
|
|
542
845
|
});
|
|
543
|
-
const bash = new
|
|
846
|
+
const bash = new Bash({
|
|
544
847
|
fs: fs3,
|
|
545
848
|
cwd: layout.cwd,
|
|
546
849
|
network: layout.network ? { dangerouslyAllowFullInternetAccess: true, denyPrivateRanges: true } : void 0,
|
|
547
|
-
javascript: layout.javascript,
|
|
850
|
+
javascript: layout.javascript ? { bootstrap: JAVASCRIPT_FS_BOOTSTRAP } : false,
|
|
548
851
|
python: layout.python,
|
|
549
852
|
executionLimits: { maxOutputSize: layout.maxExecutionOutputBytes }
|
|
550
853
|
});
|
package/lib/index.js
CHANGED
|
@@ -323,7 +323,309 @@ var WorkspaceScheme = class extends FileScheme {
|
|
|
323
323
|
|
|
324
324
|
// src/sandbox.ts
|
|
325
325
|
import path4 from "node:path";
|
|
326
|
-
|
|
326
|
+
|
|
327
|
+
// src/js-bootstrap.ts
|
|
328
|
+
var JAVASCRIPT_FS_BOOTSTRAP = String.raw`
|
|
329
|
+
(function () {
|
|
330
|
+
var hostKey = Object.getOwnPropertyNames(globalThis).filter(function (name) {
|
|
331
|
+
return name.indexOf('__jbHost_') === 0;
|
|
332
|
+
})[0];
|
|
333
|
+
if (!hostKey) throw new Error('js-exec host bridge is unavailable');
|
|
334
|
+
var host = globalThis[hostKey];
|
|
335
|
+
var fs = globalThis.fs;
|
|
336
|
+
function unwrap(result) {
|
|
337
|
+
if (!result || result.ok !== true) throw new Error(result && result.error || 'Host operation failed');
|
|
338
|
+
return result.value;
|
|
339
|
+
}
|
|
340
|
+
var raw = {};
|
|
341
|
+
var names = [
|
|
342
|
+
'readFileBuffer', 'readFileSync', 'writeFileSync', 'appendFileSync',
|
|
343
|
+
'statSync', 'lstatSync', 'readdirSync', 'mkdirSync', 'rmSync',
|
|
344
|
+
'symlinkSync', 'readlinkSync', 'chmodSync', 'realpathSync',
|
|
345
|
+
'renameSync', 'copyFileSync'
|
|
346
|
+
];
|
|
347
|
+
for (var index = 0; index < names.length; index++) raw[names[index]] = fs[names[index]];
|
|
348
|
+
|
|
349
|
+
var errnos = {
|
|
350
|
+
EPERM: -1,
|
|
351
|
+
ENOENT: -2,
|
|
352
|
+
EIO: -5,
|
|
353
|
+
EACCES: -13,
|
|
354
|
+
EEXIST: -17,
|
|
355
|
+
ENOTDIR: -20,
|
|
356
|
+
EISDIR: -21,
|
|
357
|
+
EINVAL: -22,
|
|
358
|
+
ENOSPC: -28,
|
|
359
|
+
EROFS: -30,
|
|
360
|
+
ENAMETOOLONG: -36,
|
|
361
|
+
ENOTEMPTY: -39,
|
|
362
|
+
ELOOP: -40
|
|
363
|
+
};
|
|
364
|
+
|
|
365
|
+
function failure(error, syscall, target, destination) {
|
|
366
|
+
if (!(error instanceof Error)) error = new Error(String(error));
|
|
367
|
+
var matched = /^([A-Z][A-Z0-9]+):/.exec(error.message);
|
|
368
|
+
if (matched) {
|
|
369
|
+
error.code = matched[1];
|
|
370
|
+
if (errnos[error.code] !== undefined) error.errno = errnos[error.code];
|
|
371
|
+
}
|
|
372
|
+
error.syscall = syscall;
|
|
373
|
+
if (target !== undefined) {
|
|
374
|
+
error.path = String(target);
|
|
375
|
+
error.message = error.message.replace(/'[^']*'(?=\s*$)/, "'" + String(target).replace(/'/g, "\\'") + "'");
|
|
376
|
+
}
|
|
377
|
+
if (destination !== undefined) error.dest = String(destination);
|
|
378
|
+
return error;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
function bridge(hostName, syscall, target, args, destination) {
|
|
382
|
+
try {
|
|
383
|
+
var operation = host[hostName];
|
|
384
|
+
if (args.length === 1) return unwrap(operation(args[0]));
|
|
385
|
+
if (args.length === 2) return unwrap(operation(args[0], args[1]));
|
|
386
|
+
if (args.length === 3) return unwrap(operation(args[0], args[1], args[2]));
|
|
387
|
+
return unwrap(operation(args[0], args[1], args[2], args[3]));
|
|
388
|
+
} catch (error) {
|
|
389
|
+
throw failure(error, syscall, target, destination);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
function bytes(value) {
|
|
394
|
+
if (value && value._data instanceof Uint8Array) return Array.from(value._data);
|
|
395
|
+
if (value && Array.isArray(value._data)) return value._data.slice();
|
|
396
|
+
if (Array.isArray(value)) return value.slice();
|
|
397
|
+
if (value instanceof Uint8Array) return Array.from(value);
|
|
398
|
+
return String(value);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
function stats(value) {
|
|
402
|
+
var mtime = value.mtime instanceof Date ? value.mtime : new Date(value.mtime);
|
|
403
|
+
var size = Number(value.size);
|
|
404
|
+
var result = {
|
|
405
|
+
dev: 0,
|
|
406
|
+
ino: 0,
|
|
407
|
+
mode: Number(value.mode),
|
|
408
|
+
nlink: value.isDirectory ? 2 : 1,
|
|
409
|
+
uid: 1000,
|
|
410
|
+
gid: 1000,
|
|
411
|
+
rdev: 0,
|
|
412
|
+
size: size,
|
|
413
|
+
blksize: 4096,
|
|
414
|
+
blocks: Math.ceil(size / 512),
|
|
415
|
+
atime: mtime,
|
|
416
|
+
mtime: mtime,
|
|
417
|
+
ctime: mtime,
|
|
418
|
+
birthtime: mtime,
|
|
419
|
+
atimeMs: mtime.getTime(),
|
|
420
|
+
mtimeMs: mtime.getTime(),
|
|
421
|
+
ctimeMs: mtime.getTime(),
|
|
422
|
+
birthtimeMs: mtime.getTime()
|
|
423
|
+
};
|
|
424
|
+
result.isFile = function () { return value.isFile; };
|
|
425
|
+
result.isDirectory = function () { return value.isDirectory; };
|
|
426
|
+
result.isSymbolicLink = function () { return value.isSymbolicLink; };
|
|
427
|
+
result.isBlockDevice = function () { return false; };
|
|
428
|
+
result.isCharacterDevice = function () { return false; };
|
|
429
|
+
result.isFIFO = function () { return false; };
|
|
430
|
+
result.isSocket = function () { return false; };
|
|
431
|
+
return result;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
function dirent(name, parentPath, value) {
|
|
435
|
+
var result = { name: String(name), parentPath: String(parentPath), path: String(parentPath) };
|
|
436
|
+
result.isFile = function () { return value.isFile; };
|
|
437
|
+
result.isDirectory = function () { return value.isDirectory; };
|
|
438
|
+
result.isSymbolicLink = function () { return value.isSymbolicLink; };
|
|
439
|
+
result.isBlockDevice = function () { return false; };
|
|
440
|
+
result.isCharacterDevice = function () { return false; };
|
|
441
|
+
result.isFIFO = function () { return false; };
|
|
442
|
+
result.isSocket = function () { return false; };
|
|
443
|
+
return result;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
function childPath(parent, name) {
|
|
447
|
+
return parent.charAt(parent.length - 1) === '/' ? parent + name : parent + '/' + name;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
function readStats(path, follow) {
|
|
451
|
+
return bridge('fsStat', follow ? 'stat' : 'lstat', path, [path, !follow]);
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
function collect(path, relative, options, output) {
|
|
455
|
+
var listing = bridge('fsReaddir', 'scandir', path, [path]);
|
|
456
|
+
for (var index = 0; index < listing.length; index++) {
|
|
457
|
+
var name = listing[index];
|
|
458
|
+
var nested = relative === '' ? name : relative + '/' + name;
|
|
459
|
+
var full = childPath(path, name);
|
|
460
|
+
var value = readStats(full, false);
|
|
461
|
+
output.push(options.withFileTypes ? dirent(name, path, value) : nested);
|
|
462
|
+
if (options.recursive && value.isDirectory) collect(full, nested, options, output);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
function readdir(path, options) {
|
|
467
|
+
if (typeof options === 'string') options = { encoding: options };
|
|
468
|
+
options = options || {};
|
|
469
|
+
var output = [];
|
|
470
|
+
collect(path, '', { recursive: Boolean(options.recursive), withFileTypes: Boolean(options.withFileTypes) }, output);
|
|
471
|
+
if (options.encoding === 'buffer') return output.map(function (entry) {
|
|
472
|
+
return typeof entry === 'string' ? Buffer.from(entry) : entry;
|
|
473
|
+
});
|
|
474
|
+
return output;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
function firstCreated(path) {
|
|
478
|
+
var text = String(path);
|
|
479
|
+
var absolute = text.charAt(0) === '/';
|
|
480
|
+
var parts = text.split('/');
|
|
481
|
+
var current = '';
|
|
482
|
+
var found;
|
|
483
|
+
for (var index = 0; index < parts.length; index++) {
|
|
484
|
+
var part = parts[index];
|
|
485
|
+
if (part === '' || part === '.') continue;
|
|
486
|
+
if (current === '') current = absolute ? '/' + part : part;
|
|
487
|
+
else current = childPath(current, part);
|
|
488
|
+
if (!fs.existsSync(current)) {
|
|
489
|
+
found = current;
|
|
490
|
+
break;
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
return found;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
fs.readFileBuffer = function (path) {
|
|
497
|
+
try {
|
|
498
|
+
return raw.readFileBuffer(path);
|
|
499
|
+
} catch (error) {
|
|
500
|
+
throw failure(error, 'open', path);
|
|
501
|
+
}
|
|
502
|
+
};
|
|
503
|
+
fs.readFileSync = function (path, options) {
|
|
504
|
+
try {
|
|
505
|
+
return raw.readFileSync(path, options);
|
|
506
|
+
} catch (error) {
|
|
507
|
+
throw failure(error, 'open', path);
|
|
508
|
+
}
|
|
509
|
+
};
|
|
510
|
+
fs.writeFileSync = function (path, data) {
|
|
511
|
+
bridge('fsWrite', 'open', path, [path, bytes(data)]);
|
|
512
|
+
};
|
|
513
|
+
fs.appendFileSync = function (path, data) {
|
|
514
|
+
bridge('fsAppend', 'open', path, [path, bytes(data)]);
|
|
515
|
+
};
|
|
516
|
+
fs.statSync = function (path) {
|
|
517
|
+
return stats(readStats(path, true));
|
|
518
|
+
};
|
|
519
|
+
fs.lstatSync = function (path) {
|
|
520
|
+
return stats(readStats(path, false));
|
|
521
|
+
};
|
|
522
|
+
fs.readdirSync = readdir;
|
|
523
|
+
fs.mkdirSync = function (path, options) {
|
|
524
|
+
var recursive = Boolean(options && typeof options === 'object' && options.recursive);
|
|
525
|
+
var created = recursive ? firstCreated(path) : undefined;
|
|
526
|
+
bridge('fsMkdir', 'mkdir', path, [path, recursive]);
|
|
527
|
+
return created;
|
|
528
|
+
};
|
|
529
|
+
fs.rmSync = function (path, options) {
|
|
530
|
+
bridge('fsRm', 'rm', path, [path, Boolean(options && options.recursive), Boolean(options && options.force)]);
|
|
531
|
+
};
|
|
532
|
+
fs.existsSync = function (path) {
|
|
533
|
+
try {
|
|
534
|
+
return bridge('fsExists', 'access', path, [path]);
|
|
535
|
+
} catch (error) {
|
|
536
|
+
return false;
|
|
537
|
+
}
|
|
538
|
+
};
|
|
539
|
+
fs.symlinkSync = function (target, path) {
|
|
540
|
+
bridge('fsSymlink', 'symlink', path, [target, path]);
|
|
541
|
+
};
|
|
542
|
+
fs.readlinkSync = function (path) {
|
|
543
|
+
return bridge('fsReadlink', 'readlink', path, [path]);
|
|
544
|
+
};
|
|
545
|
+
fs.chmodSync = function (path, mode) {
|
|
546
|
+
bridge('fsChmod', 'chmod', path, [path, Number(mode)]);
|
|
547
|
+
};
|
|
548
|
+
fs.realpathSync = function (path) {
|
|
549
|
+
return bridge('fsRealpath', 'realpath', path, [path]);
|
|
550
|
+
};
|
|
551
|
+
fs.renameSync = function (from, to) {
|
|
552
|
+
bridge('fsRename', 'rename', from, [from, to], to);
|
|
553
|
+
};
|
|
554
|
+
fs.copyFileSync = function (from, to) {
|
|
555
|
+
bridge('fsCopy', 'copyfile', from, [from, to], to);
|
|
556
|
+
};
|
|
557
|
+
fs.unlinkSync = function (path) {
|
|
558
|
+
bridge('fsRm', 'unlink', path, [path, false, false]);
|
|
559
|
+
};
|
|
560
|
+
fs.rmdirSync = function (path, options) {
|
|
561
|
+
bridge('fsRm', 'rmdir', path, [path, Boolean(options && options.recursive), false]);
|
|
562
|
+
};
|
|
563
|
+
|
|
564
|
+
var callbackNames = [
|
|
565
|
+
['readFile', fs.readFileSync],
|
|
566
|
+
['writeFile', fs.writeFileSync],
|
|
567
|
+
['appendFile', fs.appendFileSync],
|
|
568
|
+
['stat', fs.statSync],
|
|
569
|
+
['lstat', fs.lstatSync],
|
|
570
|
+
['readdir', fs.readdirSync],
|
|
571
|
+
['mkdir', fs.mkdirSync],
|
|
572
|
+
['rm', fs.rmSync],
|
|
573
|
+
['symlink', fs.symlinkSync],
|
|
574
|
+
['readlink', fs.readlinkSync],
|
|
575
|
+
['chmod', fs.chmodSync],
|
|
576
|
+
['realpath', fs.realpathSync],
|
|
577
|
+
['rename', fs.renameSync],
|
|
578
|
+
['copyFile', fs.copyFileSync],
|
|
579
|
+
['unlink', fs.unlinkSync],
|
|
580
|
+
['rmdir', fs.rmdirSync]
|
|
581
|
+
];
|
|
582
|
+
function callbackify(name, sync) {
|
|
583
|
+
fs[name] = function () {
|
|
584
|
+
var args = Array.prototype.slice.call(arguments);
|
|
585
|
+
var callback = args.pop();
|
|
586
|
+
if (typeof callback !== 'function') throw new TypeError('The "cb" argument must be of type function. Received ' + typeof callback);
|
|
587
|
+
Promise.resolve().then(function () {
|
|
588
|
+
return sync.apply(fs, args);
|
|
589
|
+
}).then(function (value) {
|
|
590
|
+
callback(null, value);
|
|
591
|
+
}, function (error) {
|
|
592
|
+
callback(error);
|
|
593
|
+
});
|
|
594
|
+
};
|
|
595
|
+
}
|
|
596
|
+
for (var index = 0; index < callbackNames.length; index++) callbackify(callbackNames[index][0], callbackNames[index][1]);
|
|
597
|
+
fs.exists = function (path, callback) {
|
|
598
|
+
if (typeof callback !== 'function') throw new TypeError('The "cb" argument must be of type function. Received ' + typeof callback);
|
|
599
|
+
Promise.resolve().then(function () { callback(fs.existsSync(path)); });
|
|
600
|
+
};
|
|
601
|
+
|
|
602
|
+
var promiseNames = [
|
|
603
|
+
'readFile', 'writeFile', 'appendFile', 'stat', 'lstat', 'readdir',
|
|
604
|
+
'mkdir', 'rm', 'symlink', 'readlink', 'chmod', 'realpath',
|
|
605
|
+
'rename', 'copyFile', 'unlink', 'rmdir'
|
|
606
|
+
];
|
|
607
|
+
fs.promises = {};
|
|
608
|
+
for (var index = 0; index < promiseNames.length; index++) (function (name) {
|
|
609
|
+
var sync = fs[name + 'Sync'];
|
|
610
|
+
fs.promises[name] = function () {
|
|
611
|
+
var args = arguments;
|
|
612
|
+
return new Promise(function (resolve, reject) {
|
|
613
|
+
Promise.resolve().then(function () {
|
|
614
|
+
return sync.apply(fs, args);
|
|
615
|
+
}).then(resolve, reject);
|
|
616
|
+
});
|
|
617
|
+
};
|
|
618
|
+
})(promiseNames[index]);
|
|
619
|
+
fs.promises.access = function (path) {
|
|
620
|
+
return new Promise(function (resolve, reject) {
|
|
621
|
+
if (fs.existsSync(path)) resolve();
|
|
622
|
+
else reject(failure(new Error("ENOENT: no such file or directory, access '" + path + "'"), 'access', path));
|
|
623
|
+
});
|
|
624
|
+
};
|
|
625
|
+
|
|
626
|
+
globalThis.fs = fs;
|
|
627
|
+
})();
|
|
628
|
+
`;
|
|
327
629
|
|
|
328
630
|
// src/resource-fs.ts
|
|
329
631
|
var EROFS = /* @__PURE__ */ __name(() => new Error("EROFS: resource mounts are read-only"), "EROFS");
|
|
@@ -481,6 +783,7 @@ function traversable(stat2) {
|
|
|
481
783
|
}
|
|
482
784
|
__name(traversable, "traversable");
|
|
483
785
|
async function createSandbox(layout, options) {
|
|
786
|
+
const { Bash, InMemoryFs, MountableFs, OverlayFs, ReadWriteFs } = await import("just-bash");
|
|
484
787
|
const { home } = options;
|
|
485
788
|
class Writable extends ReadWriteFs {
|
|
486
789
|
static {
|
|
@@ -512,7 +815,7 @@ async function createSandbox(layout, options) {
|
|
|
512
815
|
fs: fs3,
|
|
513
816
|
cwd: layout.cwd,
|
|
514
817
|
network: layout.network ? { dangerouslyAllowFullInternetAccess: true, denyPrivateRanges: true } : void 0,
|
|
515
|
-
javascript: layout.javascript,
|
|
818
|
+
javascript: layout.javascript ? { bootstrap: JAVASCRIPT_FS_BOOTSTRAP } : false,
|
|
516
819
|
python: layout.python,
|
|
517
820
|
executionLimits: { maxOutputSize: layout.maxExecutionOutputBytes }
|
|
518
821
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "koishi-plugin-ishiki-workspace",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"description": "Workspace tools for Ishiki: sandboxed or native shell, file tools and skills",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent",
|
|
@@ -44,11 +44,11 @@
|
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"koishi": "^4.18.11",
|
|
47
|
-
"koishi-plugin-ishiki": ">=0.0.
|
|
47
|
+
"koishi-plugin-ishiki": ">=0.0.4 <0.1.0"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
50
|
"koishi": "^4.18.11",
|
|
51
|
-
"koishi-plugin-ishiki": ">=0.0.
|
|
51
|
+
"koishi-plugin-ishiki": ">=0.0.4 <0.1.0"
|
|
52
52
|
},
|
|
53
53
|
"koishi": {
|
|
54
54
|
"description": {
|