@ai-ecoverse/slicc-kernel 1.51.1 → 1.53.0

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.
@@ -42,19 +42,35 @@ function hide(target, names) {
42
42
  }
43
43
  }
44
44
  }
45
+ function vacate(target, names) {
46
+ for (const name2 of names) {
47
+ for (let at = target; at && at !== Object.prototype; ) {
48
+ if (Object.getOwnPropertyDescriptor(at, name2)?.configurable) Reflect.deleteProperty(at, name2);
49
+ at = Object.getPrototypeOf(at);
50
+ }
51
+ Reflect.defineProperty(target, name2, {
52
+ value: void 0,
53
+ writable: true,
54
+ enumerable: false,
55
+ configurable: true
56
+ });
57
+ if (Reflect.get(target, name2) !== void 0) {
58
+ throw new Error(`slicc-kernel: cannot withhold ${name2} from a JS program`);
59
+ }
60
+ }
61
+ }
45
62
  function lockdown(scope2 = globalThis) {
46
63
  hide(scope2, BLOCKED_GLOBALS);
64
+ vacate(scope2, OPEN_SLOTS);
47
65
  const navigator = scope2.navigator;
48
66
  if (navigator && typeof navigator === "object") hide(navigator, BLOCKED_NAVIGATOR);
49
67
  }
50
- var BLOCKED_GLOBALS, BLOCKED_NAVIGATOR;
68
+ var BLOCKED_GLOBALS, BLOCKED_NAVIGATOR, OPEN_SLOTS;
51
69
  var init_lockdown = __esm({
52
70
  "src/process/js/lockdown.ts"() {
53
71
  "use strict";
54
72
  BLOCKED_GLOBALS = [
55
- "fetch",
56
73
  "XMLHttpRequest",
57
- "WebSocket",
58
74
  "WebSocketStream",
59
75
  "WebTransport",
60
76
  "EventSource",
@@ -69,6 +85,7 @@ var init_lockdown = __esm({
69
85
  "close"
70
86
  ];
71
87
  BLOCKED_NAVIGATOR = ["storage", "locks", "serviceWorker"];
88
+ OPEN_SLOTS = ["fetch", "WebSocket"];
72
89
  }
73
90
  });
74
91
 
@@ -969,6 +986,10 @@ function kernelEntry() {
969
986
  function deviceEntry(meta) {
970
987
  return { type: "device", device: meta.device, ...meta.access ? { access: meta.access } : {} };
971
988
  }
989
+ function refuseWrite(s, oflags, rights) {
990
+ const writes = (rights & RIGHTS.FD_WRITE) !== 0n || (oflags & OFLAGS.TRUNC) !== 0;
991
+ if (s?.readonly && writes) throw new WasiError("EROFS");
992
+ }
972
993
  function preopenOf(e) {
973
994
  return {
974
995
  ...e.preopen ? { preopen: e.preopen } : {},
@@ -1436,6 +1457,7 @@ var init_wasi_fds = __esm({
1436
1457
  return this.install({ type: "dir", path });
1437
1458
  }
1438
1459
  if (!s && !(oflags & OFLAGS.CREAT)) throw new WasiError("ENOENT");
1460
+ refuseWrite(s, oflags, rights);
1439
1461
  if (this.shared) return this.kernelFile(path, s, oflags, rights, fdflags);
1440
1462
  return this.install({ type: "file", file: this.file(path, s, oflags, rights, fdflags) });
1441
1463
  }
@@ -4444,10 +4466,25 @@ function ttyOps(kernel) {
4444
4466
  await kernel.call({ op: "tty-pgrp-set", fd, pgrp });
4445
4467
  }
4446
4468
  };
4469
+ const openOn = async (terminal, fd) => {
4470
+ const open = await kernel.json({ op: "fd-list" });
4471
+ const on = open.filter((entry) => entry.terminal === terminal);
4472
+ return (on.find((entry) => entry.fd === fd) ?? on[0])?.fd;
4473
+ };
4474
+ const reopened = async (terminal, termios) => {
4475
+ const fd = await kernel.json({ op: "fd-open-tty", name: terminal });
4476
+ try {
4477
+ await setAttr(fd, termios);
4478
+ } finally {
4479
+ await kernel.call({ op: "fd-close", fd });
4480
+ }
4481
+ };
4447
4482
  const restore = async () => {
4448
4483
  for (const [terminal, { fd, termios }] of [...saved].reverse()) {
4449
4484
  saved.delete(terminal);
4450
- await setAttr(fd, termios).catch(() => void 0);
4485
+ const at = await openOn(terminal, fd).catch(() => void 0);
4486
+ const back = at === void 0 ? reopened(terminal, termios) : setAttr(at, termios);
4487
+ await back.catch(() => void 0);
4451
4488
  }
4452
4489
  };
4453
4490
  return { tty, restore };
@@ -8625,6 +8662,191 @@ var init_wasi_module = __esm({
8625
8662
  }
8626
8663
  });
8627
8664
 
8665
+ // src/process/wasi/wasi-procfs.ts
8666
+ function inProc(path) {
8667
+ return path === "/proc" || path.startsWith("/proc/");
8668
+ }
8669
+ function procfsBridge(fs, tree) {
8670
+ const over = {
8671
+ readFile: (p) => inProc(p) ? tree.read(p) : fs.readFile(p),
8672
+ stat: (p) => inProc(p) ? tree.stat(p) : fs.stat(p),
8673
+ lstat: (p) => inProc(p) ? tree.stat(p, false) : fs.lstat(p),
8674
+ readdir: (p) => {
8675
+ if (inProc(p)) return tree.readdir(p);
8676
+ const names = fs.readdir(p);
8677
+ return p === "/" && !names.includes("proc") ? [...names, "proc"] : names;
8678
+ },
8679
+ exists: (p) => inProc(p) ? tree.exists(p) : fs.exists(p),
8680
+ readlink: (p) => inProc(p) ? tree.readlink(p) : fs.readlink(p),
8681
+ readdirStat: (p) => {
8682
+ if (!inProc(p)) {
8683
+ const listed = fs.readdirStat(p);
8684
+ if (p !== "/" || listed.some(([name2]) => name2 === "proc")) return listed;
8685
+ return [...listed, ["proc", tree.stat("/proc")]];
8686
+ }
8687
+ return tree.readdir(p).map((name2) => {
8688
+ try {
8689
+ return [name2, tree.stat(`${p}/${name2}`, false)];
8690
+ } catch {
8691
+ return [name2, null];
8692
+ }
8693
+ });
8694
+ },
8695
+ rename: (from, to) => {
8696
+ if (inProc(from) || inProc(to)) throw syncError("EROFS", from);
8697
+ fs.rename(from, to);
8698
+ },
8699
+ hold: (p, ...rest2) => inProc(p) ? void 0 : fs.hold?.(p, ...rest2),
8700
+ ...fs.pread ? {
8701
+ pread: (p, at, n, version) => inProc(p) ? tree.read(p).subarray(at, at + n) : fs.pread(p, at, n, version)
8702
+ } : {}
8703
+ };
8704
+ for (const name2 of READ_ONLY) {
8705
+ const fn = fs[name2];
8706
+ if (!fn) continue;
8707
+ over[name2] = (p, ...rest2) => {
8708
+ if (inProc(p)) throw syncError("EROFS", p);
8709
+ return fn.call(fs, p, ...rest2);
8710
+ };
8711
+ }
8712
+ return new Proxy(fs, {
8713
+ get: (target, key, receiver) => key in over ? over[key] : Reflect.get(target, key, receiver)
8714
+ });
8715
+ }
8716
+ var DIR_MODE3, FILE_MODE2, LINK_MODE3, PID_NAMES, SYSTEM_NAMES, ProcTree, READ_ONLY;
8717
+ var init_wasi_procfs = __esm({
8718
+ "src/process/wasi/wasi-procfs.ts"() {
8719
+ "use strict";
8720
+ init_sync_fs_wire();
8721
+ init_process_fds();
8722
+ init_procfs();
8723
+ DIR_MODE3 = 16749;
8724
+ FILE_MODE2 = 33060;
8725
+ LINK_MODE3 = 41471;
8726
+ PID_NAMES = PID_FILES;
8727
+ SYSTEM_NAMES = SYSTEM_FILES;
8728
+ ProcTree = class {
8729
+ source;
8730
+ pid;
8731
+ memory;
8732
+ constructor(source, pid, memory = memorySource()) {
8733
+ this.source = source;
8734
+ this.pid = pid;
8735
+ this.memory = memory;
8736
+ }
8737
+ listing() {
8738
+ return this.source.procList();
8739
+ }
8740
+ alive(pid) {
8741
+ return this.listing().processes.some((p) => p.pid === pid);
8742
+ }
8743
+ node(parts) {
8744
+ const [top, leaf, ...rest2] = parts;
8745
+ if (top === void 0) {
8746
+ return {
8747
+ kind: "dir",
8748
+ names: () => [
8749
+ ...SYSTEM_NAMES,
8750
+ "mounts",
8751
+ "self",
8752
+ ...this.listing().processes.map((p) => String(p.pid))
8753
+ ]
8754
+ };
8755
+ }
8756
+ if (top === "self") {
8757
+ return leaf === void 0 ? { kind: "link", target: String(this.pid) } : void 0;
8758
+ }
8759
+ if (leaf === void 0 && top === "mounts") {
8760
+ return { kind: "file", content: () => mountTable(this.source.mountList()) };
8761
+ }
8762
+ if (leaf === void 0 && SYSTEM_NAMES.includes(top)) {
8763
+ return {
8764
+ kind: "file",
8765
+ content: () => systemFile(top, this.listing(), Date.now(), this.memory)
8766
+ };
8767
+ }
8768
+ if (!/^[1-9]\d*$/.test(top) || rest2.length > 0 || !this.alive(Number(top))) return void 0;
8769
+ if (leaf === void 0) return { kind: "dir", names: () => [...PID_NAMES] };
8770
+ if (!PID_NAMES.includes(leaf)) return void 0;
8771
+ return {
8772
+ kind: "file",
8773
+ content: () => {
8774
+ const listing = this.listing();
8775
+ const info = listing.processes.find((p) => p.pid === Number(top));
8776
+ if (!info) throw syncError("ENOENT", `/proc/${top}/${leaf}`);
8777
+ return pidFile(leaf, info, listing.boot);
8778
+ }
8779
+ };
8780
+ }
8781
+ parts(path, follow2) {
8782
+ const parts = path.split("/").filter((p) => p !== "").slice(1);
8783
+ if (parts[0] === "self" && (follow2 || parts.length > 1)) parts[0] = String(this.pid);
8784
+ return parts;
8785
+ }
8786
+ find(path, follow2) {
8787
+ const node = this.node(this.parts(path, follow2));
8788
+ if (!node) throw syncError("ENOENT", path);
8789
+ return node;
8790
+ }
8791
+ stat(path, follow2 = true) {
8792
+ const node = this.find(path, follow2);
8793
+ const base = {
8794
+ isFile: false,
8795
+ isDirectory: false,
8796
+ size: 0,
8797
+ mtimeMs: Date.now(),
8798
+ readonly: true
8799
+ };
8800
+ if (node.kind === "dir") return { ...base, isDirectory: true, mode: DIR_MODE3 };
8801
+ if (node.kind === "link") {
8802
+ return { ...base, isSymbolicLink: true, mode: LINK_MODE3, size: node.target.length };
8803
+ }
8804
+ return { ...base, isFile: true, mode: FILE_MODE2, size: this.bytes(node).length };
8805
+ }
8806
+ bytes(node) {
8807
+ return new TextEncoder().encode(node.kind === "file" ? node.content() : "");
8808
+ }
8809
+ read(path) {
8810
+ const node = this.find(path, true);
8811
+ if (node.kind !== "file") throw syncError("EISDIR", path);
8812
+ return this.bytes(node);
8813
+ }
8814
+ readdir(path) {
8815
+ const node = this.find(path, true);
8816
+ if (node.kind !== "dir") throw syncError("ENOTDIR", path);
8817
+ return node.names();
8818
+ }
8819
+ readlink(path) {
8820
+ const node = this.find(path, false);
8821
+ if (node.kind !== "link") throw syncError("EINVAL", path);
8822
+ return node.target;
8823
+ }
8824
+ exists(path) {
8825
+ try {
8826
+ this.find(path, true);
8827
+ return true;
8828
+ } catch {
8829
+ return false;
8830
+ }
8831
+ }
8832
+ };
8833
+ READ_ONLY = [
8834
+ "writeFile",
8835
+ "mkdir",
8836
+ "rm",
8837
+ "unlink",
8838
+ "rmdir",
8839
+ "symlink",
8840
+ "chmod",
8841
+ "utimes",
8842
+ "lutimes",
8843
+ "create",
8844
+ "pwrite",
8845
+ "truncate"
8846
+ ];
8847
+ }
8848
+ });
8849
+
8628
8850
  // src/process/wasi/wasi-signals.ts
8629
8851
  var DELIVERED_MASK, KERNEL_DEFAULTS, LIBC_DEFAULT_EXIT, SA_RESTART, DISPOSITION_IGNORE, DISPOSITION_HANDLER, withBit, WASIX_LIBC_DEFAULT_LINE, WasiSignals;
8630
8852
  var init_wasi_signals = __esm({
@@ -10768,6 +10990,15 @@ async function instantiate(host, module, memory, threads, {
10768
10990
  }
10769
10991
  return { instance, driver };
10770
10992
  }
10993
+ function procTree(call2, pid) {
10994
+ return new ProcTree(
10995
+ {
10996
+ procList: () => call2({ op: "proc-list" }),
10997
+ mountList: () => call2({ op: "mount-list" })
10998
+ },
10999
+ pid
11000
+ );
11001
+ }
10771
11002
  function exportedTable(instance) {
10772
11003
  const table = instance.exports.__indirect_function_table;
10773
11004
  return table instanceof WebAssembly.Table ? table : void 0;
@@ -10839,7 +11070,10 @@ async function runWasiProcess(init, port3) {
10839
11070
  ppid: id.ppid,
10840
11071
  parent: () => identify(transport, init).ppid,
10841
11072
  kernel: { sys: traced(stats, "kernel", sys), call: call2 },
10842
- fs: cachingBridge(traced(stats, "fs", createSyncFsSabBridge(transport))),
11073
+ fs: procfsBridge(
11074
+ cachingBridge(traced(stats, "fs", createSyncFsSabBridge(transport))),
11075
+ procTree(call2, id.pid)
11076
+ ),
10843
11077
  ...descriptors(init, fork, threads)
10844
11078
  });
10845
11079
  if (threads) {
@@ -10930,7 +11164,7 @@ async function runWasiThread(init, port3) {
10930
11164
  ppid: id.ppid,
10931
11165
  parent: () => identify(transport, init).ppid,
10932
11166
  kernel: { sys, call: call2 },
10933
- fs: cachingBridge(createSyncFsSabBridge(transport)),
11167
+ fs: procfsBridge(cachingBridge(createSyncFsSabBridge(transport)), procTree(call2, id.pid)),
10934
11168
  shared: threads.ids
10935
11169
  });
10936
11170
  const program = await programImports(init.program, host, transport, thread.tid);
@@ -10985,6 +11219,7 @@ var init_wasi_runtime = __esm({
10985
11219
  init_wasi_host();
10986
11220
  init_wasi_imports();
10987
11221
  init_wasi_module();
11222
+ init_wasi_procfs();
10988
11223
  init_wasi_signals();
10989
11224
  init_wasi_stats();
10990
11225
  init_wasi_threads();
@@ -11084,23 +11319,6 @@ var NODE_SLOTS = [
11084
11319
  "setImmediate",
11085
11320
  "clearImmediate"
11086
11321
  ];
11087
- function vacate(target, names) {
11088
- for (const name2 of names) {
11089
- for (let at = target; at && at !== Object.prototype; ) {
11090
- if (Object.getOwnPropertyDescriptor(at, name2)?.configurable) Reflect.deleteProperty(at, name2);
11091
- at = Object.getPrototypeOf(at);
11092
- }
11093
- Reflect.defineProperty(target, name2, {
11094
- value: void 0,
11095
- writable: true,
11096
- enumerable: false,
11097
- configurable: true
11098
- });
11099
- if (Reflect.get(target, name2) !== void 0) {
11100
- throw new Error(`slicc-kernel: cannot withhold ${name2} from a JS program`);
11101
- }
11102
- }
11103
- }
11104
11322
  function refused(specifier) {
11105
11323
  return Object.assign(new Error(`slicc-kernel: a JS program cannot import ${specifier}`), {
11106
11324
  code: "ERR_ACCESS_DENIED"