@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.
@@ -429,11 +429,16 @@ var OpfsFs = class {
429
429
  }
430
430
  async ancestry(path) {
431
431
  const entries = await this.meta.get(chain(path));
432
- return entries.map((entry, i) => ({
433
- ...ownOf(entry) ?? (i === 0 ? ROOT_OWNER : inherit(entries.slice(0, i))),
434
- ...entry?.mode !== void 0 ? { mode: entry.mode } : {},
435
- ...entry?.link !== void 0 ? { link: entry.link } : {}
436
- }));
432
+ const out = [];
433
+ for (const [i, entry] of entries.entries()) {
434
+ const link2 = entry?.link !== void 0 && !await this.real(entry.path);
435
+ out.push({
436
+ ...ownOf(entry) ?? (i === 0 ? ROOT_OWNER : inherit(entries.slice(0, i))),
437
+ ...entry?.mode !== void 0 ? { mode: entry.mode } : {},
438
+ ...link2 ? { link: entry.link } : {}
439
+ });
440
+ }
441
+ return out;
437
442
  }
438
443
  async handedTo(dir) {
439
444
  return inherit(await this.meta.get(chain(dir)));
@@ -1397,15 +1402,24 @@ async function present(fs, path, directory) {
1397
1402
  const st = await fs.lstat(path).catch(() => void 0);
1398
1403
  return st !== void 0 && (!directory || st.isDirectory);
1399
1404
  }
1405
+ async function finalOf(fs, walked, want, options) {
1406
+ const perm = walked.perm;
1407
+ if ((want & X_OK) === 0 || options.directory !== void 0) {
1408
+ return [perm, options.directory !== false];
1409
+ }
1410
+ const look = options.follow === false ? fs.lstat : fs.stat;
1411
+ const st = await look.call(fs, walked.path).catch(() => void 0);
1412
+ return st ? [permOf(st), st.isDirectory] : [perm, false];
1413
+ }
1400
1414
  async function access(fs, cred, path, want, options = {}) {
1401
1415
  const walked = await walk(fs, cred, path, options.follow !== false);
1402
1416
  if (walked.denied !== void 0) {
1403
1417
  if (await present(fs, walked.denied, true)) return walked;
1404
1418
  return { path, perm: void 0, missing: true };
1405
1419
  }
1406
- const { perm } = walked;
1407
- if (!perm) return { ...walked, missing: true };
1408
- if (want === 0 || permits(cred, perm, want, options.directory !== false)) return walked;
1420
+ if (!walked.perm) return { ...walked, missing: true };
1421
+ const [perm, directory] = await finalOf(fs, walked, want, options);
1422
+ if (want === 0 || permits(cred, perm, want, directory)) return walked;
1409
1423
  if (await present(fs, walked.path, false)) return { ...walked, denied: walked.path };
1410
1424
  return { ...walked, missing: true };
1411
1425
  }
@@ -1416,6 +1430,7 @@ function refused(path, errno = "EACCES") {
1416
1430
  // src/fs/dac.ts
1417
1431
  var MAX_DENIAL_KEYS = 1e4;
1418
1432
  var S_ISGID3 = 1024;
1433
+ var DIR = { directory: true };
1419
1434
  var Dac = class {
1420
1435
  mode;
1421
1436
  hook;
@@ -1452,6 +1467,17 @@ var Dac = class {
1452
1467
  );
1453
1468
  }
1454
1469
  };
1470
+ var MAX_CREATED = 1024;
1471
+ var Created = class {
1472
+ paths = /* @__PURE__ */ new Set();
1473
+ add(path) {
1474
+ if (this.paths.size >= MAX_CREATED) this.paths.clear();
1475
+ this.paths.add(normalizePath(path));
1476
+ }
1477
+ take(path) {
1478
+ return this.paths.delete(normalizePath(path));
1479
+ }
1480
+ };
1455
1481
  function deny(g, op, path, errno = "EACCES") {
1456
1482
  g.dac.denied({ pid: g.pid, uid: g.cred.euid, op, path, errno });
1457
1483
  }
@@ -1460,20 +1486,30 @@ async function need(g, op, path, want, options = {}, shown = path) {
1460
1486
  if (walked.denied !== void 0) deny(g, op, shown);
1461
1487
  return walked;
1462
1488
  }
1489
+ function entryIn(dir, path) {
1490
+ return joinName(dir.path, path.slice(path.lastIndexOf("/") + 1));
1491
+ }
1463
1492
  async function stickyEntry(g, op, path, dir) {
1464
1493
  const perm = dir.perm;
1465
1494
  if (!perm || sticky(g.cred, perm, perm)) return;
1466
- const entry = joinName(dir.path, path.slice(path.lastIndexOf("/") + 1));
1495
+ const entry = entryIn(dir, path);
1467
1496
  if (sticky(g.cred, perm, (await ancestryOf(g.fs, entry)).at(-1))) return;
1468
1497
  if (await present(g.fs, entry, false)) deny(g, op, path, "EPERM");
1469
1498
  }
1470
1499
  async function inParent(g, op, path, old = false) {
1471
- const dir = await need(g, op, parentOf3(path), W_OK | X_OK, {}, path);
1472
- if (old && dir.denied === void 0) await stickyEntry(g, op, path, dir);
1500
+ if (old === "replaced") {
1501
+ const dir2 = await need(g, op, parentOf3(path), W_OK | X_OK, DIR, path);
1502
+ return dir2.denied === void 0 ? stickyEntry(g, op, path, dir2) : void 0;
1503
+ }
1504
+ if (!old) return void await need(g, op, parentOf3(path), W_OK | X_OK, DIR, path);
1505
+ const dir = await access(g.fs, g.cred, parentOf3(path), W_OK | X_OK, DIR);
1506
+ if (dir.denied === void 0) return stickyEntry(g, op, path, dir);
1507
+ const lookup = dir.denied === dir.path && dir.perm && permits(g.cred, dir.perm, X_OK);
1508
+ if (!lookup || await present(g.fs, entryIn(dir, path), false)) deny(g, op, path);
1473
1509
  }
1474
1510
  async function makeIn(g, op, path) {
1475
1511
  for (let dir = parentOf3(path); ; dir = parentOf3(dir)) {
1476
- const walked = await access(g.fs, g.cred, dir, W_OK | X_OK);
1512
+ const walked = await access(g.fs, g.cred, dir, W_OK | X_OK, DIR);
1477
1513
  if (walked.denied !== void 0) {
1478
1514
  if (!await present(g.fs, path, true)) deny(g, op, path);
1479
1515
  return;
@@ -1499,7 +1535,7 @@ async function removable(g, op, path) {
1499
1535
  async function renamable(g, from, to) {
1500
1536
  if (from === to) return void await need(g, "rename", from, 0, { follow: false });
1501
1537
  await inParent(g, "rename", from, true);
1502
- await inParent(g, "rename", to, true);
1538
+ await inParent(g, "rename", to, "replaced");
1503
1539
  if (g.cred.euid === 0 || parentOf3(from) === parentOf3(to)) return;
1504
1540
  const st = await g.fs.lstat(from).catch(() => void 0);
1505
1541
  if (st?.isDirectory && !permits(g.cred, permOf(st), W_OK)) deny(g, "rename", from);
@@ -1525,8 +1561,20 @@ async function chmodMode(g, path, mode) {
1525
1561
  if (!g.dac.enforcing || !perm || g.cred.euid === 0 || inGroup(g.cred, perm.gid)) return mode;
1526
1562
  return mode & ~S_ISGID3;
1527
1563
  }
1528
- async function retimable(g, op, path) {
1529
- await ownerOnly(g, op, path, op !== "lutimes");
1564
+ async function retimable(g, op, path, now = false) {
1565
+ const follow2 = op !== "lutimes";
1566
+ if (!now) return void await ownerOnly(g, op, path, follow2);
1567
+ const walked = await need(g, op, path, 0, { follow: follow2 });
1568
+ const perm = walked.perm;
1569
+ if (!perm || g.cred.euid === 0 || perm.uid === g.cred.euid) return;
1570
+ if (permits(g.cred, perm, W_OK, false)) return;
1571
+ if (await present(g.fs, walked.path, false)) deny(g, op, path);
1572
+ }
1573
+ async function fileWritable(g, op, path) {
1574
+ await need(g, op, path, W_OK, { directory: false });
1575
+ }
1576
+ function realIds(cred) {
1577
+ return { ...cred, groups: [...cred.groups], euid: cred.ruid, egid: cred.rgid };
1530
1578
  }
1531
1579
  async function listable(g, op, path) {
1532
1580
  await need(g, op, path, R_OK | X_OK, { directory: true });
@@ -1538,10 +1586,16 @@ async function readable(g, op, path) {
1538
1586
  await need(g, op, path, R_OK, { directory: false });
1539
1587
  }
1540
1588
  async function writable(g, op, path) {
1541
- const st = await g.fs.stat(path).catch(() => void 0);
1542
- if (st) return void await need(g, op, path, W_OK, { directory: st.isDirectory });
1589
+ await openable(g, op, path, W_OK, true);
1590
+ }
1591
+ async function creatable(g, op, path) {
1543
1592
  const target = await need(g, op, path, 0);
1544
- if (target.denied === void 0) await need(g, op, parentOf3(target.path), W_OK | X_OK, {}, path);
1593
+ if (target.denied === void 0) await need(g, op, parentOf3(target.path), W_OK | X_OK, DIR, path);
1594
+ }
1595
+ async function openable(g, op, path, want, create) {
1596
+ const st = create ? await g.fs.stat(path).catch(() => void 0) : void 0;
1597
+ if (create && !st) return creatable(g, op, path);
1598
+ await need(g, op, path, want, { directory: st?.isDirectory ?? false });
1545
1599
  }
1546
1600
 
1547
1601
  // src/kernel/pipe.ts
@@ -4980,11 +5034,11 @@ function realmCa(owner, store) {
4980
5034
  opened.set(store, cas);
4981
5035
  let ca = cas.get(owner);
4982
5036
  if (!ca) {
4983
- const opening = RealmCa.open(owner, store);
4984
- ca = opening;
4985
- cas.set(owner, opening);
4986
- opening.catch(() => {
4987
- if (cas.get(owner) === opening) cas.delete(owner);
5037
+ const opening2 = RealmCa.open(owner, store);
5038
+ ca = opening2;
5039
+ cas.set(owner, opening2);
5040
+ opening2.catch(() => {
5041
+ if (cas.get(owner) === opening2) cas.delete(owner);
4988
5042
  });
4989
5043
  }
4990
5044
  return ca;
@@ -8052,6 +8106,9 @@ function revokeSyncFsToken(token) {
8052
8106
  }
8053
8107
 
8054
8108
  // src/realm/sync-fs-wire.ts
8109
+ var HOLD_READ = 4;
8110
+ var HOLD_WRITE = 8;
8111
+ var HOLD_CREATED = 16;
8055
8112
  var SYNC_FS_REQUEST_TIMEOUT_MS = 25e3;
8056
8113
  function syncError(code, label) {
8057
8114
  return Object.assign(new Error(`${code}: ${label}`), { code });
@@ -8112,17 +8169,8 @@ function mkdirOptions(entry, mode = 511) {
8112
8169
  return { recursive: true, owner: { ...owner, parents } };
8113
8170
  }
8114
8171
  async function mkdirExclusive(entry, path, mode) {
8115
- const { fs } = entry;
8116
- const { owner } = mkdirOptions(entry, mode);
8117
- const own = owner ? { owner } : {};
8118
- try {
8119
- await fs.mkdir(path, own);
8120
- } catch (err) {
8121
- if (err?.code !== "ENOENT") throw err;
8122
- const above = owner ? { owner: { ...owner, mode: owner.parents } } : {};
8123
- await fs.mkdir(path.slice(0, path.lastIndexOf("/")) || "/", { recursive: true, ...above });
8124
- await fs.mkdir(path, own);
8125
- }
8172
+ const owner = ownerFor2(entry, mode ?? 511);
8173
+ await entry.fs.mkdir(path, owner ? { owner } : {});
8126
8174
  }
8127
8175
  async function chown(entry, path, req) {
8128
8176
  const cred = entry.cred?.();
@@ -8184,6 +8232,7 @@ async function run(entry, path, req) {
8184
8232
  return done;
8185
8233
  case "create":
8186
8234
  await createExclusive(fs, path, ownerFor2(entry, req.mode ?? 438));
8235
+ entry.created?.add(path);
8187
8236
  return done;
8188
8237
  case "readlink":
8189
8238
  return json2(await fs.readlink(path));
@@ -8240,11 +8289,47 @@ async function guard(g, path, req, cwd) {
8240
8289
  return linkable(g, path, other(), req.mode === 1);
8241
8290
  case "utimes":
8242
8291
  case "lutimes":
8243
- return retimable(g, op, path);
8292
+ return retimable(g, op, path, req.now === true);
8293
+ case "read":
8294
+ case "pread":
8295
+ return req.handle === void 0 ? readable(g, op, path) : void 0;
8296
+ case "pwrite":
8297
+ case "truncate":
8298
+ return req.handle === void 0 ? fileWritable(g, op, path) : void 0;
8299
+ case "write":
8300
+ return req.handle === void 0 && req.mode !== 1 ? writable(g, op, path) : void 0;
8244
8301
  default:
8245
8302
  return void 0;
8246
8303
  }
8247
8304
  }
8305
+ async function opening(entry, path, mode) {
8306
+ const g = guardOf(entry);
8307
+ const want = (mode & HOLD_READ ? R_OK : 0) | (mode & HOLD_WRITE ? W_OK : 0);
8308
+ const created3 = (mode & HOLD_CREATED) !== 0 && entry.created?.take(path) === true;
8309
+ if (g && want !== 0 && !created3) {
8310
+ await need(g, "open", path, want, { directory: false });
8311
+ }
8312
+ }
8313
+ async function holdOp(entry, path, req) {
8314
+ const mode = req.mode ?? 0;
8315
+ const [on, open] = [(mode & 1) === 1, (mode & 2) === 2];
8316
+ if (on && open) {
8317
+ await opening(entry, path, mode);
8318
+ const real = await entry.fs.realpath?.(path, true).catch(() => path);
8319
+ return json2(entry.hold?.(path, on, open, real) ?? null);
8320
+ }
8321
+ entry.hold?.(path, on, open, void 0, req.handle);
8322
+ return done;
8323
+ }
8324
+ async function accessOp(entry, path, req) {
8325
+ const g = guardOf(entry);
8326
+ if (!g) return done;
8327
+ const open = req.arg2 === "open";
8328
+ const cred = open || req.arg2 === "eaccess" ? g.cred : realIds(g.cred);
8329
+ const options = { follow: req.nofollow !== true, ...open ? { directory: false } : {} };
8330
+ await need({ ...g, cred }, open ? "open" : "access", path, req.mode ?? 0, options);
8331
+ return done;
8332
+ }
8248
8333
  async function guarded(entry, path, req) {
8249
8334
  const g = guardOf(entry);
8250
8335
  if (!g) return void 0;
@@ -8308,16 +8393,6 @@ async function owned(entry, own, req, path, target) {
8308
8393
  }
8309
8394
  return own(target, () => run(entry, path, req));
8310
8395
  }
8311
- async function holdOp(entry, path, req) {
8312
- const mode = req.mode ?? 0;
8313
- const [on, open] = [(mode & 1) === 1, (mode & 2) === 2];
8314
- if (on && open) {
8315
- const real = await entry.fs.realpath?.(path, true).catch(() => path);
8316
- return json2(entry.hold?.(path, on, open, real) ?? null);
8317
- }
8318
- entry.hold?.(path, on, open, void 0, req.handle);
8319
- return done;
8320
- }
8321
8396
  var IDENTITY_OPS = /* @__PURE__ */ new Set([
8322
8397
  "write",
8323
8398
  "pwrite",
@@ -8354,7 +8429,8 @@ async function dispatchOne(entry, req) {
8354
8429
  const path = fs.resolvePath(cwd, req.path);
8355
8430
  if (req.op === "kept") return json2(entry.keptFor?.(req.handle ?? -1) !== void 0);
8356
8431
  if (req.op === "stat" && req.handle !== void 0) return await keptStat(entry, req);
8357
- if (req.op === "hold") return holdOp(entry, path, req);
8432
+ if (req.op === "access") return await accessOp(entry, path, req);
8433
+ if (req.op === "hold") return await holdOp(entry, path, req);
8358
8434
  const refused2 = await guarded(entry, path, req);
8359
8435
  if (refused2) return refused2;
8360
8436
  if (req.op === "statfs") return json2(await entry.statfs?.(path) ?? await storageUsage());
@@ -8523,188 +8599,6 @@ function attachSyncSabResponder(port, sab, token, opts) {
8523
8599
  };
8524
8600
  }
8525
8601
 
8526
- // src/process/process-fds.ts
8527
- var field2 = (text) => (text || "none").replace(/[\s\\]/g, (c) => `\\${c.charCodeAt(0).toString(8).padStart(3, "0")}`);
8528
- function mountTable(mounts = []) {
8529
- const root = globalThis.navigator?.storage ? "opfs" : "memory";
8530
- const lines2 = [`${root} / ${root} rw 0 0`, "devfs /dev devfs rw 0 0", "proc /proc proc rw 0 0"];
8531
- for (const m of mounts) {
8532
- const options = Object.entries(m.options).map(([k, v]) => v === "" ? k : `${k}=${v}`);
8533
- if (m.state !== "ok") options.push(m.state);
8534
- const access2 = options.includes("ro") ? [] : ["rw"];
8535
- lines2.push(
8536
- `${field2(m.source)} ${field2(m.target)} ${m.type} ${[...access2, ...options].join(",")} 0 0`
8537
- );
8538
- }
8539
- return `${lines2.join("\n")}
8540
- `;
8541
- }
8542
-
8543
- // src/process/procfs.ts
8544
- var HZ = 100;
8545
- var KIB = 1024;
8546
- var FALLBACK_MEMORY = 4 * KIB * KIB * KIB;
8547
- var PID_FILES = ["cmdline", "comm", "stat", "statm", "status"];
8548
- var SYSTEM_FILES = ["loadavg", "meminfo", "stat", "uptime"];
8549
- function commOf(info) {
8550
- const name2 = info.argv[0] ?? "";
8551
- return name2.slice(name2.lastIndexOf("/") + 1).slice(0, 15);
8552
- }
8553
- function ttyNumber(tty) {
8554
- const pts = tty && /^\/dev\/pts\/(\d+)$/.exec(tty);
8555
- if (pts) return 136 << 8 | Number(pts[1]);
8556
- const vt = tty && /^\/dev\/tty(\d+)$/.exec(tty);
8557
- return vt ? 4 << 8 | Number(vt[1]) : 0;
8558
- }
8559
- function pages(bytes) {
8560
- return Math.ceil(bytes / 4096);
8561
- }
8562
- function ticks(ms) {
8563
- return Math.max(0, Math.floor(ms * HZ / 1e3));
8564
- }
8565
- function pidStat(info, boot) {
8566
- const fields = [
8567
- info.pid,
8568
- `(${commOf(info)})`,
8569
- info.state,
8570
- info.ppid,
8571
- info.pgid,
8572
- info.sid,
8573
- ttyNumber(info.tty),
8574
- info.tty ? info.pgid : -1,
8575
- 4194304,
8576
- 0,
8577
- 0,
8578
- 0,
8579
- 0,
8580
- 0,
8581
- 0,
8582
- 0,
8583
- 0,
8584
- 20,
8585
- 0,
8586
- 1,
8587
- 0,
8588
- ticks(info.started - boot),
8589
- info.memory,
8590
- pages(info.memory),
8591
- "18446744073709551615",
8592
- ...Array(12).fill(0),
8593
- 17,
8594
- 0,
8595
- 0,
8596
- 0,
8597
- 0,
8598
- 0,
8599
- 0,
8600
- ...Array(7).fill(0),
8601
- 0
8602
- ];
8603
- return `${fields.join(" ")}
8604
- `;
8605
- }
8606
- var sigMask = (mask = 0) => (mask >>> 1).toString(16).padStart(16, "0");
8607
- function pidStatus(info) {
8608
- const state = info.state === "Z" ? "Z (zombie)" : "S (sleeping)";
8609
- const c = info.cred ?? ROOT;
8610
- const ids = (r, e, s) => `${r} ${e} ${s} ${e}`;
8611
- return [
8612
- `Name: ${commOf(info)}`,
8613
- `Umask: ${(info.umask ?? 18).toString(8).padStart(4, "0")}`,
8614
- `State: ${state}`,
8615
- `Tgid: ${info.pid}`,
8616
- "Ngid: 0",
8617
- `Pid: ${info.pid}`,
8618
- `PPid: ${info.ppid}`,
8619
- "TracerPid: 0",
8620
- `Uid: ${ids(c.ruid, c.euid, c.suid)}`,
8621
- `Gid: ${ids(c.rgid, c.egid, c.sgid)}`,
8622
- "FDSize: 64",
8623
- `VmSize: ${Math.ceil(info.memory / KIB)} kB`,
8624
- `VmRSS: ${Math.ceil(info.memory / KIB)} kB`,
8625
- `Groups: ${c.groups.join(" ")}`,
8626
- `NSpid: ${info.pid}`,
8627
- `NSpgid: ${info.pgid}`,
8628
- `NSsid: ${info.sid}`,
8629
- "Threads: 1",
8630
- "SigQ: 0/0",
8631
- "SigPnd: 0000000000000000",
8632
- "ShdPnd: 0000000000000000",
8633
- "SigBlk: 0000000000000000",
8634
- `SigIgn: ${sigMask(info.sigIgn)}`,
8635
- `SigCgt: ${sigMask(info.sigCgt)}`,
8636
- ""
8637
- ].join("\n");
8638
- }
8639
- function pidFile(name2, info, boot) {
8640
- if (name2 === "cmdline") return info.state === "Z" ? "" : `${info.argv.join("\0")}\0`;
8641
- if (name2 === "comm") return `${commOf(info)}
8642
- `;
8643
- if (name2 === "stat") return pidStat(info, boot);
8644
- if (name2 === "statm") {
8645
- const p = pages(info.memory);
8646
- return `${p} ${p} 0 0 0 ${p} 0
8647
- `;
8648
- }
8649
- return pidStatus(info);
8650
- }
8651
- function memoryInfo(source, used = 0) {
8652
- const total = source.deviceMemory ? source.deviceMemory * KIB * KIB * KIB : FALLBACK_MEMORY;
8653
- const free = Math.max(0, total - used - (source.usedHeap ?? 0));
8654
- const kb = (bytes) => `${Math.floor(bytes / KIB)} kB`;
8655
- return [
8656
- ["MemTotal", kb(total)],
8657
- ["MemFree", kb(free)],
8658
- ["MemAvailable", kb(free)],
8659
- ["Buffers", kb(0)],
8660
- ["Cached", kb(0)],
8661
- ["SwapCached", kb(0)],
8662
- ["Shmem", kb(0)],
8663
- ["SReclaimable", kb(0)],
8664
- ["SwapTotal", kb(0)],
8665
- ["SwapFree", kb(0)]
8666
- ].map(([key, value]) => `${`${key}:`.padEnd(16)}${value.padStart(12)}`).concat("").join("\n");
8667
- }
8668
- function systemFile(name2, listing, now, memory) {
8669
- const up = Math.max(0, now - listing.boot) / 1e3;
8670
- if (name2 === "uptime") return `${up.toFixed(2)} ${up.toFixed(2)}
8671
- `;
8672
- if (name2 === "meminfo") {
8673
- return memoryInfo(
8674
- memory,
8675
- listing.processes.reduce((sum, p) => sum + p.memory, 0)
8676
- );
8677
- }
8678
- const live = listing.processes.filter((p) => p.state !== "Z");
8679
- if (name2 === "loadavg") {
8680
- const last = Math.max(0, ...listing.processes.map((p) => p.pid));
8681
- return `0.00 0.00 0.00 1/${live.length} ${last}
8682
- `;
8683
- }
8684
- const idle = ticks(now - listing.boot);
8685
- return [
8686
- `cpu 0 0 0 ${idle} 0 0 0 0 0 0`,
8687
- `cpu0 0 0 0 ${idle} 0 0 0 0 0 0`,
8688
- "intr 0",
8689
- "ctxt 0",
8690
- `btime ${Math.floor(listing.boot / 1e3)}`,
8691
- `processes ${listing.processes.length}`,
8692
- "procs_running 1",
8693
- "procs_blocked 0",
8694
- ""
8695
- ].join("\n");
8696
- }
8697
- function memorySource(scope = globalThis) {
8698
- const nav = scope.navigator;
8699
- const perf = scope.performance;
8700
- const deviceMemory = nav?.deviceMemory;
8701
- const used = perf?.memory?.usedJSHeapSize;
8702
- return {
8703
- ...typeof deviceMemory === "number" && deviceMemory > 0 ? { deviceMemory } : {},
8704
- ...typeof used === "number" ? { usedHeap: used } : {}
8705
- };
8706
- }
8707
-
8708
8602
  // src/fs/pages.ts
8709
8603
  var PAGE = 64 * 1024;
8710
8604
  var READAHEAD = 1024 * 1024;
@@ -8930,6 +8824,191 @@ var AsyncRangedFile = class {
8930
8824
  }
8931
8825
  };
8932
8826
 
8827
+ // src/realm/live-vfs-fs.ts
8828
+ var EARLY_WHOLE_FILE = 64 * 1024;
8829
+
8830
+ // src/process/process-fds.ts
8831
+ var field2 = (text) => (text || "none").replace(/[\s\\]/g, (c) => `\\${c.charCodeAt(0).toString(8).padStart(3, "0")}`);
8832
+ function mountTable(mounts = []) {
8833
+ const root = globalThis.navigator?.storage ? "opfs" : "memory";
8834
+ const lines2 = [`${root} / ${root} rw 0 0`, "devfs /dev devfs rw 0 0", "proc /proc proc rw 0 0"];
8835
+ for (const m of mounts) {
8836
+ const options = Object.entries(m.options).map(([k, v]) => v === "" ? k : `${k}=${v}`);
8837
+ if (m.state !== "ok") options.push(m.state);
8838
+ const access2 = options.includes("ro") ? [] : ["rw"];
8839
+ lines2.push(
8840
+ `${field2(m.source)} ${field2(m.target)} ${m.type} ${[...access2, ...options].join(",")} 0 0`
8841
+ );
8842
+ }
8843
+ return `${lines2.join("\n")}
8844
+ `;
8845
+ }
8846
+
8847
+ // src/process/procfs.ts
8848
+ var HZ = 100;
8849
+ var KIB = 1024;
8850
+ var FALLBACK_MEMORY = 4 * KIB * KIB * KIB;
8851
+ var PID_FILES = ["cmdline", "comm", "stat", "statm", "status"];
8852
+ var SYSTEM_FILES = ["loadavg", "meminfo", "stat", "uptime"];
8853
+ function commOf(info) {
8854
+ const name2 = info.argv[0] ?? "";
8855
+ return name2.slice(name2.lastIndexOf("/") + 1).slice(0, 15);
8856
+ }
8857
+ function ttyNumber(tty) {
8858
+ const pts = tty && /^\/dev\/pts\/(\d+)$/.exec(tty);
8859
+ if (pts) return 136 << 8 | Number(pts[1]);
8860
+ const vt = tty && /^\/dev\/tty(\d+)$/.exec(tty);
8861
+ return vt ? 4 << 8 | Number(vt[1]) : 0;
8862
+ }
8863
+ function pages(bytes) {
8864
+ return Math.ceil(bytes / 4096);
8865
+ }
8866
+ function ticks(ms) {
8867
+ return Math.max(0, Math.floor(ms * HZ / 1e3));
8868
+ }
8869
+ function pidStat(info, boot) {
8870
+ const fields = [
8871
+ info.pid,
8872
+ `(${commOf(info)})`,
8873
+ info.state,
8874
+ info.ppid,
8875
+ info.pgid,
8876
+ info.sid,
8877
+ ttyNumber(info.tty),
8878
+ info.tty ? info.pgid : -1,
8879
+ 4194304,
8880
+ 0,
8881
+ 0,
8882
+ 0,
8883
+ 0,
8884
+ 0,
8885
+ 0,
8886
+ 0,
8887
+ 0,
8888
+ 20,
8889
+ 0,
8890
+ 1,
8891
+ 0,
8892
+ ticks(info.started - boot),
8893
+ info.memory,
8894
+ pages(info.memory),
8895
+ "18446744073709551615",
8896
+ ...Array(12).fill(0),
8897
+ 17,
8898
+ 0,
8899
+ 0,
8900
+ 0,
8901
+ 0,
8902
+ 0,
8903
+ 0,
8904
+ ...Array(7).fill(0),
8905
+ 0
8906
+ ];
8907
+ return `${fields.join(" ")}
8908
+ `;
8909
+ }
8910
+ var sigMask = (mask = 0) => (mask >>> 1).toString(16).padStart(16, "0");
8911
+ function pidStatus(info) {
8912
+ const state = info.state === "Z" ? "Z (zombie)" : "S (sleeping)";
8913
+ const c = info.cred ?? ROOT;
8914
+ const ids = (r, e, s) => `${r} ${e} ${s} ${e}`;
8915
+ return [
8916
+ `Name: ${commOf(info)}`,
8917
+ `Umask: ${(info.umask ?? 18).toString(8).padStart(4, "0")}`,
8918
+ `State: ${state}`,
8919
+ `Tgid: ${info.pid}`,
8920
+ "Ngid: 0",
8921
+ `Pid: ${info.pid}`,
8922
+ `PPid: ${info.ppid}`,
8923
+ "TracerPid: 0",
8924
+ `Uid: ${ids(c.ruid, c.euid, c.suid)}`,
8925
+ `Gid: ${ids(c.rgid, c.egid, c.sgid)}`,
8926
+ "FDSize: 64",
8927
+ `VmSize: ${Math.ceil(info.memory / KIB)} kB`,
8928
+ `VmRSS: ${Math.ceil(info.memory / KIB)} kB`,
8929
+ `Groups: ${c.groups.join(" ")}`,
8930
+ `NSpid: ${info.pid}`,
8931
+ `NSpgid: ${info.pgid}`,
8932
+ `NSsid: ${info.sid}`,
8933
+ "Threads: 1",
8934
+ "SigQ: 0/0",
8935
+ "SigPnd: 0000000000000000",
8936
+ "ShdPnd: 0000000000000000",
8937
+ "SigBlk: 0000000000000000",
8938
+ `SigIgn: ${sigMask(info.sigIgn)}`,
8939
+ `SigCgt: ${sigMask(info.sigCgt)}`,
8940
+ ""
8941
+ ].join("\n");
8942
+ }
8943
+ function pidFile(name2, info, boot) {
8944
+ if (name2 === "cmdline") return info.state === "Z" ? "" : `${info.argv.join("\0")}\0`;
8945
+ if (name2 === "comm") return `${commOf(info)}
8946
+ `;
8947
+ if (name2 === "stat") return pidStat(info, boot);
8948
+ if (name2 === "statm") {
8949
+ const p = pages(info.memory);
8950
+ return `${p} ${p} 0 0 0 ${p} 0
8951
+ `;
8952
+ }
8953
+ return pidStatus(info);
8954
+ }
8955
+ function memoryInfo(source, used = 0) {
8956
+ const total = source.deviceMemory ? source.deviceMemory * KIB * KIB * KIB : FALLBACK_MEMORY;
8957
+ const free = Math.max(0, total - used - (source.usedHeap ?? 0));
8958
+ const kb = (bytes) => `${Math.floor(bytes / KIB)} kB`;
8959
+ return [
8960
+ ["MemTotal", kb(total)],
8961
+ ["MemFree", kb(free)],
8962
+ ["MemAvailable", kb(free)],
8963
+ ["Buffers", kb(0)],
8964
+ ["Cached", kb(0)],
8965
+ ["SwapCached", kb(0)],
8966
+ ["Shmem", kb(0)],
8967
+ ["SReclaimable", kb(0)],
8968
+ ["SwapTotal", kb(0)],
8969
+ ["SwapFree", kb(0)]
8970
+ ].map(([key, value]) => `${`${key}:`.padEnd(16)}${value.padStart(12)}`).concat("").join("\n");
8971
+ }
8972
+ function systemFile(name2, listing, now, memory) {
8973
+ const up = Math.max(0, now - listing.boot) / 1e3;
8974
+ if (name2 === "uptime") return `${up.toFixed(2)} ${up.toFixed(2)}
8975
+ `;
8976
+ if (name2 === "meminfo") {
8977
+ return memoryInfo(
8978
+ memory,
8979
+ listing.processes.reduce((sum, p) => sum + p.memory, 0)
8980
+ );
8981
+ }
8982
+ const live = listing.processes.filter((p) => p.state !== "Z");
8983
+ if (name2 === "loadavg") {
8984
+ const last = Math.max(0, ...listing.processes.map((p) => p.pid));
8985
+ return `0.00 0.00 0.00 1/${live.length} ${last}
8986
+ `;
8987
+ }
8988
+ const idle = ticks(now - listing.boot);
8989
+ return [
8990
+ `cpu 0 0 0 ${idle} 0 0 0 0 0 0`,
8991
+ `cpu0 0 0 0 ${idle} 0 0 0 0 0 0`,
8992
+ "intr 0",
8993
+ "ctxt 0",
8994
+ `btime ${Math.floor(listing.boot / 1e3)}`,
8995
+ `processes ${listing.processes.length}`,
8996
+ "procs_running 1",
8997
+ "procs_blocked 0",
8998
+ ""
8999
+ ].join("\n");
9000
+ }
9001
+ function memorySource(scope = globalThis) {
9002
+ const nav = scope.navigator;
9003
+ const perf = scope.performance;
9004
+ const deviceMemory = nav?.deviceMemory;
9005
+ const used = perf?.memory?.usedJSHeapSize;
9006
+ return {
9007
+ ...typeof deviceMemory === "number" && deviceMemory > 0 ? { deviceMemory } : {},
9008
+ ...typeof used === "number" ? { usedHeap: used } : {}
9009
+ };
9010
+ }
9011
+
8933
9012
  // src/process/wasi/wasi-files.ts
8934
9013
  function normalize(path) {
8935
9014
  const out = [];
@@ -11208,6 +11287,7 @@ var WasmProcess = class {
11208
11287
  throw Object.assign(new Error(alias.refused), { code: alias.refused });
11209
11288
  if (alias !== void 0) return this.openProc(req, alias);
11210
11289
  await refuseReadonly(this.options.fs, req.path, req.flags, req);
11290
+ await this.mayOpen(req);
11211
11291
  const fd = this.fds.install(heldFile(), 3);
11212
11292
  try {
11213
11293
  const nodes = this.nodes;
@@ -11253,6 +11333,17 @@ var WasmProcess = class {
11253
11333
  };
11254
11334
  return fs.exclusive ? fs.exclusive(first.path, look) : look();
11255
11335
  }
11336
+ async mayOpen(req) {
11337
+ const { guard: guard2 } = this.options;
11338
+ const inherited2 = req.orphan || req.contents !== void 0 || req.handle !== void 0;
11339
+ if (!guard2 || inherited2 || req.pin !== void 0) return;
11340
+ const g = { fs: guard2.fs, dac: guard2.dac, cred: this.cred, pid: this.pid };
11341
+ if (req.exclusive) return inParent(g, "open", req.path);
11342
+ if (req.created && guard2.created?.take(req.path)) return;
11343
+ const access2 = req.flags & WRITE_ACCESS;
11344
+ const want = (access2 === 1 ? 0 : R_OK) | (access2 !== 0 || req.truncate ? W_OK : 0);
11345
+ await openable(g, "open", req.path, want, req.create === true);
11346
+ }
11256
11347
  newOwner() {
11257
11348
  if (!this.options.owners) return void 0;
11258
11349
  return { uid: this.cred.euid, gid: this.cred.egid, mode: 438 & ~this.umask };
@@ -11937,7 +12028,7 @@ function inherited(opts) {
11937
12028
  function holdingToken(opts, holds, caller) {
11938
12029
  return mintSyncFsToken({
11939
12030
  ...opts.owners ? caller : {},
11940
- ...opts.dac ? { dac: opts.dac, pid: opts.pid } : {},
12031
+ ...opts.dac ? { dac: opts.dac, pid: opts.pid, created: caller.created } : {},
11941
12032
  fs: opts.fs,
11942
12033
  cwd: opts.cwd,
11943
12034
  ...opts.statfs ? { statfs: opts.statfs } : {},
@@ -11950,10 +12041,11 @@ function holdingToken(opts, holds, caller) {
11950
12041
  renamed: (from, to) => holds.renamed(from, to)
11951
12042
  });
11952
12043
  }
11953
- function processOptions(opts, header3, hooks) {
12044
+ function processOptions(opts, header3, hooks, created3) {
11954
12045
  return {
11955
12046
  ...inherited(opts),
11956
12047
  ...opts.owners ? { owners: true } : {},
12048
+ ...opts.dac ? { guard: { dac: opts.dac, fs: opts.fs, created: created3 } } : {},
11957
12049
  ...opts.identity ? { identity: opts.identity } : {},
11958
12050
  ...opts.onSyscall ? { onSyscall: opts.onSyscall } : {},
11959
12051
  ...opts.settling ? { settling: opts.settling } : {},
@@ -11987,20 +12079,27 @@ function spawnWasmProcess(opts) {
11987
12079
  const sab = new SharedArrayBuffer(SAB_HEADER_BYTES + SAB_DEFAULT_WINDOW_BYTES);
11988
12080
  const header3 = new Int32Array(sab, 0, SAB_HEADER_I32);
11989
12081
  const threadSignals = /* @__PURE__ */ new Map();
12082
+ const created3 = new Created();
11990
12083
  const process = new WasmProcess(
11991
12084
  opts.pid,
11992
12085
  opts.fds,
11993
- processOptions(opts, header3, {
11994
- raise: (sig) => signal(sig),
11995
- threadKill: (tid, sig) => killThread(threadSignals.get(tid), process.signalMasks().caught, sig)
11996
- })
12086
+ processOptions(
12087
+ opts,
12088
+ header3,
12089
+ {
12090
+ raise: (sig) => signal(sig),
12091
+ threadKill: (tid, sig) => killThread(threadSignals.get(tid), process.signalMasks().caught, sig)
12092
+ },
12093
+ created3
12094
+ )
11997
12095
  );
11998
12096
  publishStops(process, header3);
11999
12097
  const holds = new HeldPaths();
12000
12098
  opts.held?.add(holds);
12001
12099
  const token = holdingToken(opts, holds, {
12002
12100
  cred: () => process.cred,
12003
- umask: () => process.umask
12101
+ umask: () => process.umask,
12102
+ created: created3
12004
12103
  });
12005
12104
  process.keptPath = (path) => holds.keptAt(path)?.hidden;
12006
12105
  process.keptHandle = (handle2) => holds.keptFor(handle2)?.hidden;
@@ -13113,16 +13212,16 @@ function hostfsHandlers(current, againMs = RESTORE_AGAIN_MS) {
13113
13212
  });
13114
13213
  async function writable2(client, path, flags) {
13115
13214
  const { ifMatch: _, ...asked } = flags;
13116
- const opening = () => client.call("open", { path: rel(path), ...asked });
13215
+ const opening2 = () => client.call("open", { path: rel(path), ...asked });
13117
13216
  try {
13118
- return { opened: await opening(), restore: void 0 };
13217
+ return { opened: await opening2(), restore: void 0 };
13119
13218
  } catch (err) {
13120
13219
  if (!flags.write || codeOf4(err) !== "EACCES") throw err;
13121
13220
  const was = await client.call("stat", { path: rel(path) });
13122
13221
  const mode = was.mode ?? 0;
13123
13222
  if (mode & 128) throw err;
13124
13223
  const restore = { path: rel(path), mode, was };
13125
- const opened2 = await client.call("setattr", { path: rel(path), mode: mode | 128 }).then(opening).catch(async (again) => {
13224
+ const opened2 = await client.call("setattr", { path: rel(path), mode: mode | 128 }).then(opening2).catch(async (again) => {
13126
13225
  await settle3(client, restore).catch(() => {
13127
13226
  });
13128
13227
  throw again;
@@ -14380,15 +14479,33 @@ var Launcher = class {
14380
14479
  return void 0;
14381
14480
  }
14382
14481
  const inner = await this.interpreted(interp, [interp, ...passed], cwd, scope, depth + 1);
14383
- return inner && { ...inner, target: withScriptEnv(inner.target, command) };
14482
+ const via = [interp, ...inner?.via ?? []];
14483
+ return inner && { ...inner, target: withScriptEnv(inner.target, command), via };
14384
14484
  }
14385
14485
  const target = withScriptEnv(found, command);
14386
- return { target, args: [...target.prefix ?? [], ...passed] };
14486
+ return { target, args: [...target.prefix ?? [], ...passed], via: [interp] };
14387
14487
  }
14388
14488
  async plan(file, argv, cwd, scope) {
14389
14489
  const direct = await this.resolve(file, argv[0] ?? file, cwd, scope);
14390
14490
  if (direct) return { target: direct, args: [...direct.prefix ?? [], ...argv.slice(1)] };
14391
- return this.interpreted(file, argv, cwd, scope);
14491
+ const script = await this.interpreted(file, argv, cwd, scope);
14492
+ return script && { ...script, script: true };
14493
+ }
14494
+ async mayExec(cred, req, planned) {
14495
+ const { dac } = this;
14496
+ if (!dac) return;
14497
+ const g = { fs: this.fs, cred, pid: req.pid, dac };
14498
+ const byPath = (file) => file.includes("/") && !COMMAND2.test(file);
14499
+ if (byPath(req.file)) {
14500
+ const path = this.fs.resolvePath(req.cwd, req.file);
14501
+ await need(g, "exec", path, planned?.script ? R_OK | X_OK : X_OK);
14502
+ }
14503
+ const via = planned?.via ?? [];
14504
+ for (const [i, file] of via.entries()) {
14505
+ if (!byPath(file)) continue;
14506
+ const want = i < via.length - 1 ? R_OK | X_OK : X_OK;
14507
+ await need(g, "exec", this.fs.resolvePath(req.cwd, file), want);
14508
+ }
14392
14509
  }
14393
14510
  async unrunnable(file, cwd, scope) {
14394
14511
  const path = this.fs.resolvePath(cwd, file);
@@ -14608,6 +14725,12 @@ var Launcher = class {
14608
14725
  return async (req, fds) => {
14609
14726
  const scope = await this.scopeOf(this.credOf(ppid).euid);
14610
14727
  const planned = await this.plan(req.file, req.argv, req.cwd, scope);
14728
+ try {
14729
+ await this.mayExec(this.credOf(ppid), { ...req, pid: ppid }, planned);
14730
+ } catch (err) {
14731
+ await fds.closeAll();
14732
+ throw err.code === "EACCES" ? new SpawnError("EACCES") : err;
14733
+ }
14611
14734
  if (!planned) {
14612
14735
  await fds.closeAll();
14613
14736
  throw new SpawnError(await this.unrunnable(req.file, req.cwd, scope));
@@ -14817,8 +14940,13 @@ var Launcher = class {
14817
14940
  this.fs
14818
14941
  );
14819
14942
  void this.unlinked.sweep(entry.target);
14943
+ if (this.pnpmHome.startsWith(`${entry.target.replace(/\/$/, "")}/`))
14944
+ await this.provisionPnpmHome();
14820
14945
  return entry;
14821
14946
  }
14947
+ async provisionPnpmHome() {
14948
+ await this.base.mkdir(this.pnpmHome, { recursive: true }).catch(() => void 0);
14949
+ }
14822
14950
  mountedBy(spec, cred) {
14823
14951
  if (!this.owners || cred.euid === 0 && cred.egid === 0) return spec;
14824
14952
  const ids = { uid: String(cred.euid), gid: String(cred.egid) };
@@ -14886,6 +15014,8 @@ var Launcher = class {
14886
15014
  }
14887
15015
  async prepare() {
14888
15016
  for (const dir of SHARED_DIRS) await this.base.mkdir(dir, { recursive: true });
15017
+ if (this.owners) await this.base.chmod("/tmp", 1023);
15018
+ await this.provisionPnpmHome();
14889
15019
  await this.users.ensure();
14890
15020
  await writeCaFile(this.base, this.ca).catch(() => void 0);
14891
15021
  this.fstab = this.mountFstab();
@@ -14932,7 +15062,9 @@ var Launcher = class {
14932
15062
  const cwd = await physicalPathAsync(this.base, start2.startsWith("/") ? start2 : `/${start2}`);
14933
15063
  const [file = ""] = argv;
14934
15064
  await this.base.mkdir(cwd, { recursive: true });
14935
- return { cwd, file, planned: await this.plan(file, argv, cwd, scope) };
15065
+ const planned = await this.plan(file, argv, cwd, scope);
15066
+ await this.mayExec(credOf(account), { file, cwd, pid: 0 }, planned);
15067
+ return { cwd, file, planned };
14936
15068
  }
14937
15069
  async openTerminal(argv, options) {
14938
15070
  const account = await this.account(options.user);