@ai-ecoverse/slicc-kernel 1.62.3 → 1.63.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.
package/dist/node.js CHANGED
@@ -331,15 +331,24 @@ async function present(fs, path, directory) {
331
331
  const st = await fs.lstat(path).catch(() => void 0);
332
332
  return st !== void 0 && (!directory || st.isDirectory);
333
333
  }
334
+ async function finalOf(fs, walked, want, options) {
335
+ const perm = walked.perm;
336
+ if ((want & X_OK) === 0 || options.directory !== void 0) {
337
+ return [perm, options.directory !== false];
338
+ }
339
+ const look = options.follow === false ? fs.lstat : fs.stat;
340
+ const st = await look.call(fs, walked.path).catch(() => void 0);
341
+ return st ? [permOf(st), st.isDirectory] : [perm, false];
342
+ }
334
343
  async function access(fs, cred, path, want, options = {}) {
335
344
  const walked = await walk(fs, cred, path, options.follow !== false);
336
345
  if (walked.denied !== void 0) {
337
346
  if (await present(fs, walked.denied, true)) return walked;
338
347
  return { path, perm: void 0, missing: true };
339
348
  }
340
- const { perm } = walked;
341
- if (!perm) return { ...walked, missing: true };
342
- if (want === 0 || permits(cred, perm, want, options.directory !== false)) return walked;
349
+ if (!walked.perm) return { ...walked, missing: true };
350
+ const [perm, directory] = await finalOf(fs, walked, want, options);
351
+ if (want === 0 || permits(cred, perm, want, directory)) return walked;
343
352
  if (await present(fs, walked.path, false)) return { ...walked, denied: walked.path };
344
353
  return { ...walked, missing: true };
345
354
  }
@@ -350,6 +359,7 @@ function refused(path, errno = "EACCES") {
350
359
  // src/fs/dac.ts
351
360
  var MAX_DENIAL_KEYS = 1e4;
352
361
  var S_ISGID2 = 1024;
362
+ var DIR = { directory: true };
353
363
  var Dac = class {
354
364
  mode;
355
365
  hook;
@@ -386,6 +396,17 @@ var Dac = class {
386
396
  );
387
397
  }
388
398
  };
399
+ var MAX_CREATED = 1024;
400
+ var Created = class {
401
+ paths = /* @__PURE__ */ new Set();
402
+ add(path) {
403
+ if (this.paths.size >= MAX_CREATED) this.paths.clear();
404
+ this.paths.add(normalizePath(path));
405
+ }
406
+ take(path) {
407
+ return this.paths.delete(normalizePath(path));
408
+ }
409
+ };
389
410
  function deny(g, op, path, errno = "EACCES") {
390
411
  g.dac.denied({ pid: g.pid, uid: g.cred.euid, op, path, errno });
391
412
  }
@@ -394,20 +415,30 @@ async function need(g, op, path, want, options = {}, shown = path) {
394
415
  if (walked.denied !== void 0) deny(g, op, shown);
395
416
  return walked;
396
417
  }
418
+ function entryIn(dir, path) {
419
+ return joinName(dir.path, path.slice(path.lastIndexOf("/") + 1));
420
+ }
397
421
  async function stickyEntry(g, op, path, dir) {
398
422
  const perm = dir.perm;
399
423
  if (!perm || sticky(g.cred, perm, perm)) return;
400
- const entry = joinName(dir.path, path.slice(path.lastIndexOf("/") + 1));
424
+ const entry = entryIn(dir, path);
401
425
  if (sticky(g.cred, perm, (await ancestryOf(g.fs, entry)).at(-1))) return;
402
426
  if (await present(g.fs, entry, false)) deny(g, op, path, "EPERM");
403
427
  }
404
428
  async function inParent(g, op, path, old = false) {
405
- const dir = await need(g, op, parentOf(path), W_OK | X_OK, {}, path);
406
- if (old && dir.denied === void 0) await stickyEntry(g, op, path, dir);
429
+ if (old === "replaced") {
430
+ const dir2 = await need(g, op, parentOf(path), W_OK | X_OK, DIR, path);
431
+ return dir2.denied === void 0 ? stickyEntry(g, op, path, dir2) : void 0;
432
+ }
433
+ if (!old) return void await need(g, op, parentOf(path), W_OK | X_OK, DIR, path);
434
+ const dir = await access(g.fs, g.cred, parentOf(path), W_OK | X_OK, DIR);
435
+ if (dir.denied === void 0) return stickyEntry(g, op, path, dir);
436
+ const lookup2 = dir.denied === dir.path && dir.perm && permits(g.cred, dir.perm, X_OK);
437
+ if (!lookup2 || await present(g.fs, entryIn(dir, path), false)) deny(g, op, path);
407
438
  }
408
439
  async function makeIn(g, op, path) {
409
440
  for (let dir = parentOf(path); ; dir = parentOf(dir)) {
410
- const walked = await access(g.fs, g.cred, dir, W_OK | X_OK);
441
+ const walked = await access(g.fs, g.cred, dir, W_OK | X_OK, DIR);
411
442
  if (walked.denied !== void 0) {
412
443
  if (!await present(g.fs, path, true)) deny(g, op, path);
413
444
  return;
@@ -433,7 +464,7 @@ async function removable(g, op, path) {
433
464
  async function renamable(g, from, to) {
434
465
  if (from === to) return void await need(g, "rename", from, 0, { follow: false });
435
466
  await inParent(g, "rename", from, true);
436
- await inParent(g, "rename", to, true);
467
+ await inParent(g, "rename", to, "replaced");
437
468
  if (g.cred.euid === 0 || parentOf(from) === parentOf(to)) return;
438
469
  const st = await g.fs.lstat(from).catch(() => void 0);
439
470
  if (st?.isDirectory && !permits(g.cred, permOf(st), W_OK)) deny(g, "rename", from);
@@ -459,8 +490,20 @@ async function chmodMode(g, path, mode) {
459
490
  if (!g.dac.enforcing || !perm || g.cred.euid === 0 || inGroup(g.cred, perm.gid)) return mode;
460
491
  return mode & ~S_ISGID2;
461
492
  }
462
- async function retimable(g, op, path) {
463
- await ownerOnly(g, op, path, op !== "lutimes");
493
+ async function retimable(g, op, path, now = false) {
494
+ const follow2 = op !== "lutimes";
495
+ if (!now) return void await ownerOnly(g, op, path, follow2);
496
+ const walked = await need(g, op, path, 0, { follow: follow2 });
497
+ const perm = walked.perm;
498
+ if (!perm || g.cred.euid === 0 || perm.uid === g.cred.euid) return;
499
+ if (permits(g.cred, perm, W_OK, false)) return;
500
+ if (await present(g.fs, walked.path, false)) deny(g, op, path);
501
+ }
502
+ async function fileWritable(g, op, path) {
503
+ await need(g, op, path, W_OK, { directory: false });
504
+ }
505
+ function realIds(cred) {
506
+ return { ...cred, groups: [...cred.groups], euid: cred.ruid, egid: cred.rgid };
464
507
  }
465
508
  async function listable(g, op, path) {
466
509
  await need(g, op, path, R_OK | X_OK, { directory: true });
@@ -472,10 +515,16 @@ async function readable(g, op, path) {
472
515
  await need(g, op, path, R_OK, { directory: false });
473
516
  }
474
517
  async function writable(g, op, path) {
475
- const st = await g.fs.stat(path).catch(() => void 0);
476
- if (st) return void await need(g, op, path, W_OK, { directory: st.isDirectory });
518
+ await openable(g, op, path, W_OK, true);
519
+ }
520
+ async function creatable(g, op, path) {
477
521
  const target = await need(g, op, path, 0);
478
- if (target.denied === void 0) await need(g, op, parentOf(target.path), W_OK | X_OK, {}, path);
522
+ if (target.denied === void 0) await need(g, op, parentOf(target.path), W_OK | X_OK, DIR, path);
523
+ }
524
+ async function openable(g, op, path, want, create) {
525
+ const st = create ? await g.fs.stat(path).catch(() => void 0) : void 0;
526
+ if (create && !st) return creatable(g, op, path);
527
+ await need(g, op, path, want, { directory: st?.isDirectory ?? false });
479
528
  }
480
529
 
481
530
  // src/kernel/pipe.ts
@@ -2983,11 +3032,16 @@ var OpfsFs = class {
2983
3032
  }
2984
3033
  async ancestry(path) {
2985
3034
  const entries = await this.meta.get(chain(path));
2986
- return entries.map((entry, i) => ({
2987
- ...ownOf(entry) ?? (i === 0 ? ROOT_OWNER : inherit(entries.slice(0, i))),
2988
- ...entry?.mode !== void 0 ? { mode: entry.mode } : {},
2989
- ...entry?.link !== void 0 ? { link: entry.link } : {}
2990
- }));
3035
+ const out = [];
3036
+ for (const [i, entry] of entries.entries()) {
3037
+ const link2 = entry?.link !== void 0 && !await this.real(entry.path);
3038
+ out.push({
3039
+ ...ownOf(entry) ?? (i === 0 ? ROOT_OWNER : inherit(entries.slice(0, i))),
3040
+ ...entry?.mode !== void 0 ? { mode: entry.mode } : {},
3041
+ ...link2 ? { link: entry.link } : {}
3042
+ });
3043
+ }
3044
+ return out;
2991
3045
  }
2992
3046
  async handedTo(dir) {
2993
3047
  return inherit(await this.meta.get(chain(dir)));
@@ -6477,6 +6531,9 @@ function revokeSyncFsToken(token) {
6477
6531
  }
6478
6532
 
6479
6533
  // src/realm/sync-fs-wire.ts
6534
+ var HOLD_READ = 4;
6535
+ var HOLD_WRITE = 8;
6536
+ var HOLD_CREATED = 16;
6480
6537
  var SYNC_FS_REQUEST_TIMEOUT_MS = 25e3;
6481
6538
  function syncError(code, label) {
6482
6539
  return Object.assign(new Error(`${code}: ${label}`), { code });
@@ -6537,17 +6594,8 @@ function mkdirOptions(entry, mode = 511) {
6537
6594
  return { recursive: true, owner: { ...owner, parents } };
6538
6595
  }
6539
6596
  async function mkdirExclusive(entry, path, mode) {
6540
- const { fs } = entry;
6541
- const { owner } = mkdirOptions(entry, mode);
6542
- const own = owner ? { owner } : {};
6543
- try {
6544
- await fs.mkdir(path, own);
6545
- } catch (err) {
6546
- if (err?.code !== "ENOENT") throw err;
6547
- const above = owner ? { owner: { ...owner, mode: owner.parents } } : {};
6548
- await fs.mkdir(path.slice(0, path.lastIndexOf("/")) || "/", { recursive: true, ...above });
6549
- await fs.mkdir(path, own);
6550
- }
6597
+ const owner = ownerFor2(entry, mode ?? 511);
6598
+ await entry.fs.mkdir(path, owner ? { owner } : {});
6551
6599
  }
6552
6600
  async function chown(entry, path, req) {
6553
6601
  const cred = entry.cred?.();
@@ -6609,6 +6657,7 @@ async function run(entry, path, req) {
6609
6657
  return done;
6610
6658
  case "create":
6611
6659
  await createExclusive(fs, path, ownerFor2(entry, req.mode ?? 438));
6660
+ entry.created?.add(path);
6612
6661
  return done;
6613
6662
  case "readlink":
6614
6663
  return json2(await fs.readlink(path));
@@ -6665,11 +6714,47 @@ async function guard(g, path, req, cwd) {
6665
6714
  return linkable(g, path, other(), req.mode === 1);
6666
6715
  case "utimes":
6667
6716
  case "lutimes":
6668
- return retimable(g, op, path);
6717
+ return retimable(g, op, path, req.now === true);
6718
+ case "read":
6719
+ case "pread":
6720
+ return req.handle === void 0 ? readable(g, op, path) : void 0;
6721
+ case "pwrite":
6722
+ case "truncate":
6723
+ return req.handle === void 0 ? fileWritable(g, op, path) : void 0;
6724
+ case "write":
6725
+ return req.handle === void 0 && req.mode !== 1 ? writable(g, op, path) : void 0;
6669
6726
  default:
6670
6727
  return void 0;
6671
6728
  }
6672
6729
  }
6730
+ async function opening(entry, path, mode) {
6731
+ const g = guardOf(entry);
6732
+ const want = (mode & HOLD_READ ? R_OK : 0) | (mode & HOLD_WRITE ? W_OK : 0);
6733
+ const created3 = (mode & HOLD_CREATED) !== 0 && entry.created?.take(path) === true;
6734
+ if (g && want !== 0 && !created3) {
6735
+ await need(g, "open", path, want, { directory: false });
6736
+ }
6737
+ }
6738
+ async function holdOp(entry, path, req) {
6739
+ const mode = req.mode ?? 0;
6740
+ const [on, open] = [(mode & 1) === 1, (mode & 2) === 2];
6741
+ if (on && open) {
6742
+ await opening(entry, path, mode);
6743
+ const real = await entry.fs.realpath?.(path, true).catch(() => path);
6744
+ return json2(entry.hold?.(path, on, open, real) ?? null);
6745
+ }
6746
+ entry.hold?.(path, on, open, void 0, req.handle);
6747
+ return done;
6748
+ }
6749
+ async function accessOp(entry, path, req) {
6750
+ const g = guardOf(entry);
6751
+ if (!g) return done;
6752
+ const open = req.arg2 === "open";
6753
+ const cred = open || req.arg2 === "eaccess" ? g.cred : realIds(g.cred);
6754
+ const options = { follow: req.nofollow !== true, ...open ? { directory: false } : {} };
6755
+ await need({ ...g, cred }, open ? "open" : "access", path, req.mode ?? 0, options);
6756
+ return done;
6757
+ }
6673
6758
  async function guarded(entry, path, req) {
6674
6759
  const g = guardOf(entry);
6675
6760
  if (!g) return void 0;
@@ -6733,16 +6818,6 @@ async function owned(entry, own, req, path, target) {
6733
6818
  }
6734
6819
  return own(target, () => run(entry, path, req));
6735
6820
  }
6736
- async function holdOp(entry, path, req) {
6737
- const mode = req.mode ?? 0;
6738
- const [on, open] = [(mode & 1) === 1, (mode & 2) === 2];
6739
- if (on && open) {
6740
- const real = await entry.fs.realpath?.(path, true).catch(() => path);
6741
- return json2(entry.hold?.(path, on, open, real) ?? null);
6742
- }
6743
- entry.hold?.(path, on, open, void 0, req.handle);
6744
- return done;
6745
- }
6746
6821
  var IDENTITY_OPS = /* @__PURE__ */ new Set([
6747
6822
  "write",
6748
6823
  "pwrite",
@@ -6779,7 +6854,8 @@ async function dispatchOne(entry, req) {
6779
6854
  const path = fs.resolvePath(cwd, req.path);
6780
6855
  if (req.op === "kept") return json2(entry.keptFor?.(req.handle ?? -1) !== void 0);
6781
6856
  if (req.op === "stat" && req.handle !== void 0) return await keptStat(entry, req);
6782
- if (req.op === "hold") return holdOp(entry, path, req);
6857
+ if (req.op === "access") return await accessOp(entry, path, req);
6858
+ if (req.op === "hold") return await holdOp(entry, path, req);
6783
6859
  const refused2 = await guarded(entry, path, req);
6784
6860
  if (refused2) return refused2;
6785
6861
  if (req.op === "statfs") return json2(await entry.statfs?.(path) ?? await storageUsage());
@@ -6975,188 +7051,6 @@ function ownNames(hostname) {
6975
7051
  return [.../* @__PURE__ */ new Set([hostname.toLowerCase(), ...LIBC_HOSTNAMES])];
6976
7052
  }
6977
7053
 
6978
- // src/process/process-fds.ts
6979
- var field2 = (text) => (text || "none").replace(/[\s\\]/g, (c) => `\\${c.charCodeAt(0).toString(8).padStart(3, "0")}`);
6980
- function mountTable(mounts = []) {
6981
- const root = globalThis.navigator?.storage ? "opfs" : "memory";
6982
- const lines2 = [`${root} / ${root} rw 0 0`, "devfs /dev devfs rw 0 0", "proc /proc proc rw 0 0"];
6983
- for (const m of mounts) {
6984
- const options = Object.entries(m.options).map(([k, v]) => v === "" ? k : `${k}=${v}`);
6985
- if (m.state !== "ok") options.push(m.state);
6986
- const access2 = options.includes("ro") ? [] : ["rw"];
6987
- lines2.push(
6988
- `${field2(m.source)} ${field2(m.target)} ${m.type} ${[...access2, ...options].join(",")} 0 0`
6989
- );
6990
- }
6991
- return `${lines2.join("\n")}
6992
- `;
6993
- }
6994
-
6995
- // src/process/procfs.ts
6996
- var HZ = 100;
6997
- var KIB = 1024;
6998
- var FALLBACK_MEMORY = 4 * KIB * KIB * KIB;
6999
- var PID_FILES = ["cmdline", "comm", "stat", "statm", "status"];
7000
- var SYSTEM_FILES = ["loadavg", "meminfo", "stat", "uptime"];
7001
- function commOf(info) {
7002
- const name2 = info.argv[0] ?? "";
7003
- return name2.slice(name2.lastIndexOf("/") + 1).slice(0, 15);
7004
- }
7005
- function ttyNumber(tty) {
7006
- const pts = tty && /^\/dev\/pts\/(\d+)$/.exec(tty);
7007
- if (pts) return 136 << 8 | Number(pts[1]);
7008
- const vt = tty && /^\/dev\/tty(\d+)$/.exec(tty);
7009
- return vt ? 4 << 8 | Number(vt[1]) : 0;
7010
- }
7011
- function pages(bytes) {
7012
- return Math.ceil(bytes / 4096);
7013
- }
7014
- function ticks(ms) {
7015
- return Math.max(0, Math.floor(ms * HZ / 1e3));
7016
- }
7017
- function pidStat(info, boot) {
7018
- const fields = [
7019
- info.pid,
7020
- `(${commOf(info)})`,
7021
- info.state,
7022
- info.ppid,
7023
- info.pgid,
7024
- info.sid,
7025
- ttyNumber(info.tty),
7026
- info.tty ? info.pgid : -1,
7027
- 4194304,
7028
- 0,
7029
- 0,
7030
- 0,
7031
- 0,
7032
- 0,
7033
- 0,
7034
- 0,
7035
- 0,
7036
- 20,
7037
- 0,
7038
- 1,
7039
- 0,
7040
- ticks(info.started - boot),
7041
- info.memory,
7042
- pages(info.memory),
7043
- "18446744073709551615",
7044
- ...Array(12).fill(0),
7045
- 17,
7046
- 0,
7047
- 0,
7048
- 0,
7049
- 0,
7050
- 0,
7051
- 0,
7052
- ...Array(7).fill(0),
7053
- 0
7054
- ];
7055
- return `${fields.join(" ")}
7056
- `;
7057
- }
7058
- var sigMask = (mask = 0) => (mask >>> 1).toString(16).padStart(16, "0");
7059
- function pidStatus(info) {
7060
- const state = info.state === "Z" ? "Z (zombie)" : "S (sleeping)";
7061
- const c = info.cred ?? ROOT;
7062
- const ids = (r, e, s) => `${r} ${e} ${s} ${e}`;
7063
- return [
7064
- `Name: ${commOf(info)}`,
7065
- `Umask: ${(info.umask ?? 18).toString(8).padStart(4, "0")}`,
7066
- `State: ${state}`,
7067
- `Tgid: ${info.pid}`,
7068
- "Ngid: 0",
7069
- `Pid: ${info.pid}`,
7070
- `PPid: ${info.ppid}`,
7071
- "TracerPid: 0",
7072
- `Uid: ${ids(c.ruid, c.euid, c.suid)}`,
7073
- `Gid: ${ids(c.rgid, c.egid, c.sgid)}`,
7074
- "FDSize: 64",
7075
- `VmSize: ${Math.ceil(info.memory / KIB)} kB`,
7076
- `VmRSS: ${Math.ceil(info.memory / KIB)} kB`,
7077
- `Groups: ${c.groups.join(" ")}`,
7078
- `NSpid: ${info.pid}`,
7079
- `NSpgid: ${info.pgid}`,
7080
- `NSsid: ${info.sid}`,
7081
- "Threads: 1",
7082
- "SigQ: 0/0",
7083
- "SigPnd: 0000000000000000",
7084
- "ShdPnd: 0000000000000000",
7085
- "SigBlk: 0000000000000000",
7086
- `SigIgn: ${sigMask(info.sigIgn)}`,
7087
- `SigCgt: ${sigMask(info.sigCgt)}`,
7088
- ""
7089
- ].join("\n");
7090
- }
7091
- function pidFile(name2, info, boot) {
7092
- if (name2 === "cmdline") return info.state === "Z" ? "" : `${info.argv.join("\0")}\0`;
7093
- if (name2 === "comm") return `${commOf(info)}
7094
- `;
7095
- if (name2 === "stat") return pidStat(info, boot);
7096
- if (name2 === "statm") {
7097
- const p = pages(info.memory);
7098
- return `${p} ${p} 0 0 0 ${p} 0
7099
- `;
7100
- }
7101
- return pidStatus(info);
7102
- }
7103
- function memoryInfo(source, used = 0) {
7104
- const total = source.deviceMemory ? source.deviceMemory * KIB * KIB * KIB : FALLBACK_MEMORY;
7105
- const free = Math.max(0, total - used - (source.usedHeap ?? 0));
7106
- const kb = (bytes) => `${Math.floor(bytes / KIB)} kB`;
7107
- return [
7108
- ["MemTotal", kb(total)],
7109
- ["MemFree", kb(free)],
7110
- ["MemAvailable", kb(free)],
7111
- ["Buffers", kb(0)],
7112
- ["Cached", kb(0)],
7113
- ["SwapCached", kb(0)],
7114
- ["Shmem", kb(0)],
7115
- ["SReclaimable", kb(0)],
7116
- ["SwapTotal", kb(0)],
7117
- ["SwapFree", kb(0)]
7118
- ].map(([key, value]) => `${`${key}:`.padEnd(16)}${value.padStart(12)}`).concat("").join("\n");
7119
- }
7120
- function systemFile(name2, listing, now, memory) {
7121
- const up = Math.max(0, now - listing.boot) / 1e3;
7122
- if (name2 === "uptime") return `${up.toFixed(2)} ${up.toFixed(2)}
7123
- `;
7124
- if (name2 === "meminfo") {
7125
- return memoryInfo(
7126
- memory,
7127
- listing.processes.reduce((sum, p) => sum + p.memory, 0)
7128
- );
7129
- }
7130
- const live = listing.processes.filter((p) => p.state !== "Z");
7131
- if (name2 === "loadavg") {
7132
- const last = Math.max(0, ...listing.processes.map((p) => p.pid));
7133
- return `0.00 0.00 0.00 1/${live.length} ${last}
7134
- `;
7135
- }
7136
- const idle = ticks(now - listing.boot);
7137
- return [
7138
- `cpu 0 0 0 ${idle} 0 0 0 0 0 0`,
7139
- `cpu0 0 0 0 ${idle} 0 0 0 0 0 0`,
7140
- "intr 0",
7141
- "ctxt 0",
7142
- `btime ${Math.floor(listing.boot / 1e3)}`,
7143
- `processes ${listing.processes.length}`,
7144
- "procs_running 1",
7145
- "procs_blocked 0",
7146
- ""
7147
- ].join("\n");
7148
- }
7149
- function memorySource(scope = globalThis) {
7150
- const nav = scope.navigator;
7151
- const perf = scope.performance;
7152
- const deviceMemory = nav?.deviceMemory;
7153
- const used = perf?.memory?.usedJSHeapSize;
7154
- return {
7155
- ...typeof deviceMemory === "number" && deviceMemory > 0 ? { deviceMemory } : {},
7156
- ...typeof used === "number" ? { usedHeap: used } : {}
7157
- };
7158
- }
7159
-
7160
7054
  // src/fs/pages.ts
7161
7055
  var PAGE = 64 * 1024;
7162
7056
  var READAHEAD = 1024 * 1024;
@@ -7382,6 +7276,191 @@ var AsyncRangedFile = class {
7382
7276
  }
7383
7277
  };
7384
7278
 
7279
+ // src/realm/live-vfs-fs.ts
7280
+ var EARLY_WHOLE_FILE = 64 * 1024;
7281
+
7282
+ // src/process/process-fds.ts
7283
+ var field2 = (text) => (text || "none").replace(/[\s\\]/g, (c) => `\\${c.charCodeAt(0).toString(8).padStart(3, "0")}`);
7284
+ function mountTable(mounts = []) {
7285
+ const root = globalThis.navigator?.storage ? "opfs" : "memory";
7286
+ const lines2 = [`${root} / ${root} rw 0 0`, "devfs /dev devfs rw 0 0", "proc /proc proc rw 0 0"];
7287
+ for (const m of mounts) {
7288
+ const options = Object.entries(m.options).map(([k, v]) => v === "" ? k : `${k}=${v}`);
7289
+ if (m.state !== "ok") options.push(m.state);
7290
+ const access2 = options.includes("ro") ? [] : ["rw"];
7291
+ lines2.push(
7292
+ `${field2(m.source)} ${field2(m.target)} ${m.type} ${[...access2, ...options].join(",")} 0 0`
7293
+ );
7294
+ }
7295
+ return `${lines2.join("\n")}
7296
+ `;
7297
+ }
7298
+
7299
+ // src/process/procfs.ts
7300
+ var HZ = 100;
7301
+ var KIB = 1024;
7302
+ var FALLBACK_MEMORY = 4 * KIB * KIB * KIB;
7303
+ var PID_FILES = ["cmdline", "comm", "stat", "statm", "status"];
7304
+ var SYSTEM_FILES = ["loadavg", "meminfo", "stat", "uptime"];
7305
+ function commOf(info) {
7306
+ const name2 = info.argv[0] ?? "";
7307
+ return name2.slice(name2.lastIndexOf("/") + 1).slice(0, 15);
7308
+ }
7309
+ function ttyNumber(tty) {
7310
+ const pts = tty && /^\/dev\/pts\/(\d+)$/.exec(tty);
7311
+ if (pts) return 136 << 8 | Number(pts[1]);
7312
+ const vt = tty && /^\/dev\/tty(\d+)$/.exec(tty);
7313
+ return vt ? 4 << 8 | Number(vt[1]) : 0;
7314
+ }
7315
+ function pages(bytes) {
7316
+ return Math.ceil(bytes / 4096);
7317
+ }
7318
+ function ticks(ms) {
7319
+ return Math.max(0, Math.floor(ms * HZ / 1e3));
7320
+ }
7321
+ function pidStat(info, boot) {
7322
+ const fields = [
7323
+ info.pid,
7324
+ `(${commOf(info)})`,
7325
+ info.state,
7326
+ info.ppid,
7327
+ info.pgid,
7328
+ info.sid,
7329
+ ttyNumber(info.tty),
7330
+ info.tty ? info.pgid : -1,
7331
+ 4194304,
7332
+ 0,
7333
+ 0,
7334
+ 0,
7335
+ 0,
7336
+ 0,
7337
+ 0,
7338
+ 0,
7339
+ 0,
7340
+ 20,
7341
+ 0,
7342
+ 1,
7343
+ 0,
7344
+ ticks(info.started - boot),
7345
+ info.memory,
7346
+ pages(info.memory),
7347
+ "18446744073709551615",
7348
+ ...Array(12).fill(0),
7349
+ 17,
7350
+ 0,
7351
+ 0,
7352
+ 0,
7353
+ 0,
7354
+ 0,
7355
+ 0,
7356
+ ...Array(7).fill(0),
7357
+ 0
7358
+ ];
7359
+ return `${fields.join(" ")}
7360
+ `;
7361
+ }
7362
+ var sigMask = (mask = 0) => (mask >>> 1).toString(16).padStart(16, "0");
7363
+ function pidStatus(info) {
7364
+ const state = info.state === "Z" ? "Z (zombie)" : "S (sleeping)";
7365
+ const c = info.cred ?? ROOT;
7366
+ const ids = (r, e, s) => `${r} ${e} ${s} ${e}`;
7367
+ return [
7368
+ `Name: ${commOf(info)}`,
7369
+ `Umask: ${(info.umask ?? 18).toString(8).padStart(4, "0")}`,
7370
+ `State: ${state}`,
7371
+ `Tgid: ${info.pid}`,
7372
+ "Ngid: 0",
7373
+ `Pid: ${info.pid}`,
7374
+ `PPid: ${info.ppid}`,
7375
+ "TracerPid: 0",
7376
+ `Uid: ${ids(c.ruid, c.euid, c.suid)}`,
7377
+ `Gid: ${ids(c.rgid, c.egid, c.sgid)}`,
7378
+ "FDSize: 64",
7379
+ `VmSize: ${Math.ceil(info.memory / KIB)} kB`,
7380
+ `VmRSS: ${Math.ceil(info.memory / KIB)} kB`,
7381
+ `Groups: ${c.groups.join(" ")}`,
7382
+ `NSpid: ${info.pid}`,
7383
+ `NSpgid: ${info.pgid}`,
7384
+ `NSsid: ${info.sid}`,
7385
+ "Threads: 1",
7386
+ "SigQ: 0/0",
7387
+ "SigPnd: 0000000000000000",
7388
+ "ShdPnd: 0000000000000000",
7389
+ "SigBlk: 0000000000000000",
7390
+ `SigIgn: ${sigMask(info.sigIgn)}`,
7391
+ `SigCgt: ${sigMask(info.sigCgt)}`,
7392
+ ""
7393
+ ].join("\n");
7394
+ }
7395
+ function pidFile(name2, info, boot) {
7396
+ if (name2 === "cmdline") return info.state === "Z" ? "" : `${info.argv.join("\0")}\0`;
7397
+ if (name2 === "comm") return `${commOf(info)}
7398
+ `;
7399
+ if (name2 === "stat") return pidStat(info, boot);
7400
+ if (name2 === "statm") {
7401
+ const p = pages(info.memory);
7402
+ return `${p} ${p} 0 0 0 ${p} 0
7403
+ `;
7404
+ }
7405
+ return pidStatus(info);
7406
+ }
7407
+ function memoryInfo(source, used = 0) {
7408
+ const total = source.deviceMemory ? source.deviceMemory * KIB * KIB * KIB : FALLBACK_MEMORY;
7409
+ const free = Math.max(0, total - used - (source.usedHeap ?? 0));
7410
+ const kb = (bytes) => `${Math.floor(bytes / KIB)} kB`;
7411
+ return [
7412
+ ["MemTotal", kb(total)],
7413
+ ["MemFree", kb(free)],
7414
+ ["MemAvailable", kb(free)],
7415
+ ["Buffers", kb(0)],
7416
+ ["Cached", kb(0)],
7417
+ ["SwapCached", kb(0)],
7418
+ ["Shmem", kb(0)],
7419
+ ["SReclaimable", kb(0)],
7420
+ ["SwapTotal", kb(0)],
7421
+ ["SwapFree", kb(0)]
7422
+ ].map(([key, value]) => `${`${key}:`.padEnd(16)}${value.padStart(12)}`).concat("").join("\n");
7423
+ }
7424
+ function systemFile(name2, listing, now, memory) {
7425
+ const up = Math.max(0, now - listing.boot) / 1e3;
7426
+ if (name2 === "uptime") return `${up.toFixed(2)} ${up.toFixed(2)}
7427
+ `;
7428
+ if (name2 === "meminfo") {
7429
+ return memoryInfo(
7430
+ memory,
7431
+ listing.processes.reduce((sum, p) => sum + p.memory, 0)
7432
+ );
7433
+ }
7434
+ const live = listing.processes.filter((p) => p.state !== "Z");
7435
+ if (name2 === "loadavg") {
7436
+ const last = Math.max(0, ...listing.processes.map((p) => p.pid));
7437
+ return `0.00 0.00 0.00 1/${live.length} ${last}
7438
+ `;
7439
+ }
7440
+ const idle = ticks(now - listing.boot);
7441
+ return [
7442
+ `cpu 0 0 0 ${idle} 0 0 0 0 0 0`,
7443
+ `cpu0 0 0 0 ${idle} 0 0 0 0 0 0`,
7444
+ "intr 0",
7445
+ "ctxt 0",
7446
+ `btime ${Math.floor(listing.boot / 1e3)}`,
7447
+ `processes ${listing.processes.length}`,
7448
+ "procs_running 1",
7449
+ "procs_blocked 0",
7450
+ ""
7451
+ ].join("\n");
7452
+ }
7453
+ function memorySource(scope = globalThis) {
7454
+ const nav = scope.navigator;
7455
+ const perf = scope.performance;
7456
+ const deviceMemory = nav?.deviceMemory;
7457
+ const used = perf?.memory?.usedJSHeapSize;
7458
+ return {
7459
+ ...typeof deviceMemory === "number" && deviceMemory > 0 ? { deviceMemory } : {},
7460
+ ...typeof used === "number" ? { usedHeap: used } : {}
7461
+ };
7462
+ }
7463
+
7385
7464
  // src/process/wasi/wasi-files.ts
7386
7465
  function normalize(path) {
7387
7466
  const out = [];
@@ -8570,11 +8649,11 @@ function realmCa(owner, store) {
8570
8649
  opened.set(store, cas);
8571
8650
  let ca = cas.get(owner);
8572
8651
  if (!ca) {
8573
- const opening = RealmCa.open(owner, store);
8574
- ca = opening;
8575
- cas.set(owner, opening);
8576
- opening.catch(() => {
8577
- if (cas.get(owner) === opening) cas.delete(owner);
8652
+ const opening2 = RealmCa.open(owner, store);
8653
+ ca = opening2;
8654
+ cas.set(owner, opening2);
8655
+ opening2.catch(() => {
8656
+ if (cas.get(owner) === opening2) cas.delete(owner);
8578
8657
  });
8579
8658
  }
8580
8659
  return ca;
@@ -10981,6 +11060,7 @@ var WasmProcess = class {
10981
11060
  throw Object.assign(new Error(alias.refused), { code: alias.refused });
10982
11061
  if (alias !== void 0) return this.openProc(req, alias);
10983
11062
  await refuseReadonly(this.options.fs, req.path, req.flags, req);
11063
+ await this.mayOpen(req);
10984
11064
  const fd = this.fds.install(heldFile(), 3);
10985
11065
  try {
10986
11066
  const nodes = this.nodes;
@@ -11026,6 +11106,17 @@ var WasmProcess = class {
11026
11106
  };
11027
11107
  return fs.exclusive ? fs.exclusive(first.path, look) : look();
11028
11108
  }
11109
+ async mayOpen(req) {
11110
+ const { guard: guard2 } = this.options;
11111
+ const inherited2 = req.orphan || req.contents !== void 0 || req.handle !== void 0;
11112
+ if (!guard2 || inherited2 || req.pin !== void 0) return;
11113
+ const g = { fs: guard2.fs, dac: guard2.dac, cred: this.cred, pid: this.pid };
11114
+ if (req.exclusive) return inParent(g, "open", req.path);
11115
+ if (req.created && guard2.created?.take(req.path)) return;
11116
+ const access2 = req.flags & WRITE_ACCESS;
11117
+ const want = (access2 === 1 ? 0 : R_OK) | (access2 !== 0 || req.truncate ? W_OK : 0);
11118
+ await openable(g, "open", req.path, want, req.create === true);
11119
+ }
11029
11120
  newOwner() {
11030
11121
  if (!this.options.owners) return void 0;
11031
11122
  return { uid: this.cred.euid, gid: this.cred.egid, mode: 438 & ~this.umask };
@@ -11710,7 +11801,7 @@ function inherited(opts) {
11710
11801
  function holdingToken(opts, holds, caller) {
11711
11802
  return mintSyncFsToken({
11712
11803
  ...opts.owners ? caller : {},
11713
- ...opts.dac ? { dac: opts.dac, pid: opts.pid } : {},
11804
+ ...opts.dac ? { dac: opts.dac, pid: opts.pid, created: caller.created } : {},
11714
11805
  fs: opts.fs,
11715
11806
  cwd: opts.cwd,
11716
11807
  ...opts.statfs ? { statfs: opts.statfs } : {},
@@ -11723,10 +11814,11 @@ function holdingToken(opts, holds, caller) {
11723
11814
  renamed: (from, to) => holds.renamed(from, to)
11724
11815
  });
11725
11816
  }
11726
- function processOptions(opts, header4, hooks) {
11817
+ function processOptions(opts, header4, hooks, created3) {
11727
11818
  return {
11728
11819
  ...inherited(opts),
11729
11820
  ...opts.owners ? { owners: true } : {},
11821
+ ...opts.dac ? { guard: { dac: opts.dac, fs: opts.fs, created: created3 } } : {},
11730
11822
  ...opts.identity ? { identity: opts.identity } : {},
11731
11823
  ...opts.onSyscall ? { onSyscall: opts.onSyscall } : {},
11732
11824
  ...opts.settling ? { settling: opts.settling } : {},
@@ -11760,20 +11852,27 @@ function spawnWasmProcess(opts) {
11760
11852
  const sab = new SharedArrayBuffer(SAB_HEADER_BYTES + SAB_DEFAULT_WINDOW_BYTES);
11761
11853
  const header4 = new Int32Array(sab, 0, SAB_HEADER_I32);
11762
11854
  const threadSignals = /* @__PURE__ */ new Map();
11855
+ const created3 = new Created();
11763
11856
  const process2 = new WasmProcess(
11764
11857
  opts.pid,
11765
11858
  opts.fds,
11766
- processOptions(opts, header4, {
11767
- raise: (sig) => signal(sig),
11768
- threadKill: (tid, sig) => killThread(threadSignals.get(tid), process2.signalMasks().caught, sig)
11769
- })
11859
+ processOptions(
11860
+ opts,
11861
+ header4,
11862
+ {
11863
+ raise: (sig) => signal(sig),
11864
+ threadKill: (tid, sig) => killThread(threadSignals.get(tid), process2.signalMasks().caught, sig)
11865
+ },
11866
+ created3
11867
+ )
11770
11868
  );
11771
11869
  publishStops(process2, header4);
11772
11870
  const holds = new HeldPaths();
11773
11871
  opts.held?.add(holds);
11774
11872
  const token = holdingToken(opts, holds, {
11775
11873
  cred: () => process2.cred,
11776
- umask: () => process2.umask
11874
+ umask: () => process2.umask,
11875
+ created: created3
11777
11876
  });
11778
11877
  process2.keptPath = (path) => holds.keptAt(path)?.hidden;
11779
11878
  process2.keptHandle = (handle2) => holds.keptFor(handle2)?.hidden;
@@ -12886,16 +12985,16 @@ function hostfsHandlers(current, againMs = RESTORE_AGAIN_MS) {
12886
12985
  });
12887
12986
  async function writable2(client, path, flags) {
12888
12987
  const { ifMatch: _, ...asked } = flags;
12889
- const opening = () => client.call("open", { path: rel(path), ...asked });
12988
+ const opening2 = () => client.call("open", { path: rel(path), ...asked });
12890
12989
  try {
12891
- return { opened: await opening(), restore: void 0 };
12990
+ return { opened: await opening2(), restore: void 0 };
12892
12991
  } catch (err) {
12893
12992
  if (!flags.write || codeOf4(err) !== "EACCES") throw err;
12894
12993
  const was = await client.call("stat", { path: rel(path) });
12895
12994
  const mode = was.mode ?? 0;
12896
12995
  if (mode & 128) throw err;
12897
12996
  const restore = { path: rel(path), mode, was };
12898
- const opened2 = await client.call("setattr", { path: rel(path), mode: mode | 128 }).then(opening).catch(async (again) => {
12997
+ const opened2 = await client.call("setattr", { path: rel(path), mode: mode | 128 }).then(opening2).catch(async (again) => {
12899
12998
  await settle(client, restore).catch(() => {
12900
12999
  });
12901
13000
  throw again;
@@ -14256,15 +14355,33 @@ var Launcher = class {
14256
14355
  return void 0;
14257
14356
  }
14258
14357
  const inner = await this.interpreted(interp, [interp, ...passed], cwd, scope, depth + 1);
14259
- return inner && { ...inner, target: withScriptEnv(inner.target, command) };
14358
+ const via = [interp, ...inner?.via ?? []];
14359
+ return inner && { ...inner, target: withScriptEnv(inner.target, command), via };
14260
14360
  }
14261
14361
  const target = withScriptEnv(found, command);
14262
- return { target, args: [...target.prefix ?? [], ...passed] };
14362
+ return { target, args: [...target.prefix ?? [], ...passed], via: [interp] };
14263
14363
  }
14264
14364
  async plan(file, argv, cwd, scope) {
14265
14365
  const direct = await this.resolve(file, argv[0] ?? file, cwd, scope);
14266
14366
  if (direct) return { target: direct, args: [...direct.prefix ?? [], ...argv.slice(1)] };
14267
- return this.interpreted(file, argv, cwd, scope);
14367
+ const script = await this.interpreted(file, argv, cwd, scope);
14368
+ return script && { ...script, script: true };
14369
+ }
14370
+ async mayExec(cred, req, planned) {
14371
+ const { dac } = this;
14372
+ if (!dac) return;
14373
+ const g = { fs: this.fs, cred, pid: req.pid, dac };
14374
+ const byPath = (file) => file.includes("/") && !COMMAND2.test(file);
14375
+ if (byPath(req.file)) {
14376
+ const path = this.fs.resolvePath(req.cwd, req.file);
14377
+ await need(g, "exec", path, planned?.script ? R_OK | X_OK : X_OK);
14378
+ }
14379
+ const via = planned?.via ?? [];
14380
+ for (const [i, file] of via.entries()) {
14381
+ if (!byPath(file)) continue;
14382
+ const want = i < via.length - 1 ? R_OK | X_OK : X_OK;
14383
+ await need(g, "exec", this.fs.resolvePath(req.cwd, file), want);
14384
+ }
14268
14385
  }
14269
14386
  async unrunnable(file, cwd, scope) {
14270
14387
  const path = this.fs.resolvePath(cwd, file);
@@ -14484,6 +14601,12 @@ var Launcher = class {
14484
14601
  return async (req, fds) => {
14485
14602
  const scope = await this.scopeOf(this.credOf(ppid).euid);
14486
14603
  const planned = await this.plan(req.file, req.argv, req.cwd, scope);
14604
+ try {
14605
+ await this.mayExec(this.credOf(ppid), { ...req, pid: ppid }, planned);
14606
+ } catch (err) {
14607
+ await fds.closeAll();
14608
+ throw err.code === "EACCES" ? new SpawnError("EACCES") : err;
14609
+ }
14487
14610
  if (!planned) {
14488
14611
  await fds.closeAll();
14489
14612
  throw new SpawnError(await this.unrunnable(req.file, req.cwd, scope));
@@ -14693,8 +14816,13 @@ var Launcher = class {
14693
14816
  this.fs
14694
14817
  );
14695
14818
  void this.unlinked.sweep(entry.target);
14819
+ if (this.pnpmHome.startsWith(`${entry.target.replace(/\/$/, "")}/`))
14820
+ await this.provisionPnpmHome();
14696
14821
  return entry;
14697
14822
  }
14823
+ async provisionPnpmHome() {
14824
+ await this.base.mkdir(this.pnpmHome, { recursive: true }).catch(() => void 0);
14825
+ }
14698
14826
  mountedBy(spec, cred) {
14699
14827
  if (!this.owners || cred.euid === 0 && cred.egid === 0) return spec;
14700
14828
  const ids = { uid: String(cred.euid), gid: String(cred.egid) };
@@ -14762,6 +14890,8 @@ var Launcher = class {
14762
14890
  }
14763
14891
  async prepare() {
14764
14892
  for (const dir of SHARED_DIRS) await this.base.mkdir(dir, { recursive: true });
14893
+ if (this.owners) await this.base.chmod("/tmp", 1023);
14894
+ await this.provisionPnpmHome();
14765
14895
  await this.users.ensure();
14766
14896
  await writeCaFile(this.base, this.ca).catch(() => void 0);
14767
14897
  this.fstab = this.mountFstab();
@@ -14808,7 +14938,9 @@ var Launcher = class {
14808
14938
  const cwd = await physicalPathAsync(this.base, start2.startsWith("/") ? start2 : `/${start2}`);
14809
14939
  const [file = ""] = argv;
14810
14940
  await this.base.mkdir(cwd, { recursive: true });
14811
- return { cwd, file, planned: await this.plan(file, argv, cwd, scope) };
14941
+ const planned = await this.plan(file, argv, cwd, scope);
14942
+ await this.mayExec(credOf(account), { file, cwd, pid: 0 }, planned);
14943
+ return { cwd, file, planned };
14812
14944
  }
14813
14945
  async openTerminal(argv, options) {
14814
14946
  const account = await this.account(options.user);