@ai-ecoverse/slicc-kernel 1.83.0 → 1.84.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.
@@ -7487,9 +7487,13 @@ function withCommandDirs(fs, names, userDir = async () => void 0, owners = false
7487
7487
  // src/fs/fresh-modules.ts
7488
7488
  var MAGIC = [0, 97, 115, 109];
7489
7489
  var MAX_FRESH = 65536;
7490
+ var DEFAULT_UMASK = 18;
7490
7491
  function isModule(bytes) {
7491
7492
  return MAGIC.every((b, i) => bytes[i] === b);
7492
7493
  }
7494
+ function within4(path, dir) {
7495
+ return path.startsWith(dir === "/" ? "/" : `${dir}/`);
7496
+ }
7493
7497
  var FreshModules = class {
7494
7498
  fresh = /* @__PURE__ */ new Map();
7495
7499
  add(path, umask, pid) {
@@ -7497,17 +7501,40 @@ var FreshModules = class {
7497
7501
  this.fresh.delete(key);
7498
7502
  const oldest = this.fresh.size >= MAX_FRESH ? this.fresh.keys().next().value : void 0;
7499
7503
  if (oldest !== void 0) this.fresh.delete(oldest);
7500
- this.fresh.set(key, { umask: umask & 511, pid, added: 0 });
7504
+ const mask = umask & 511;
7505
+ this.fresh.set(key, { umask: mask, pid, added: 0, setup: mask !== DEFAULT_UMASK });
7501
7506
  }
7502
7507
  forget(pid) {
7503
7508
  for (const [path, fresh2] of this.fresh) if (fresh2.pid === pid) this.fresh.delete(path);
7504
7509
  }
7510
+ drop(fresh2) {
7511
+ for (const [key, note] of [...this.fresh]) if (note === fresh2) this.fresh.delete(key);
7512
+ }
7513
+ moved(from, to) {
7514
+ const source = normalizePath(from);
7515
+ const target = normalizePath(to);
7516
+ if (source === target) return;
7517
+ for (const key of [...this.fresh.keys()]) {
7518
+ if (key === target || within4(key, target)) this.fresh.delete(key);
7519
+ }
7520
+ for (const [key, fresh2] of [...this.fresh]) {
7521
+ if (key !== source && !within4(key, source)) continue;
7522
+ this.fresh.delete(key);
7523
+ this.fresh.set(target + key.slice(source.length), fresh2);
7524
+ }
7525
+ }
7505
7526
  wrap(fs) {
7506
- const decide = async (given, bytes) => {
7527
+ const head = async (path) => {
7528
+ if (fs.pread) return fs.pread(path, 0, MAGIC.length);
7529
+ return (await fs.readFileBuffer(path)).subarray(0, MAGIC.length);
7530
+ };
7531
+ const decide = async (given, known) => {
7507
7532
  const path = normalizePath(given);
7508
7533
  const fresh2 = this.fresh.get(path);
7509
- if (!fresh2 || typeof bytes === "string" || bytes.length < MAGIC.length) return;
7534
+ if (!fresh2) return;
7535
+ const bytes = known && known.length >= MAGIC.length ? known : await head(path);
7510
7536
  const want = isModule(bytes) ? 73 & ~fresh2.umask : 0;
7537
+ fresh2.setup = false;
7511
7538
  if (want === fresh2.added) return;
7512
7539
  const mode = (await fs.stat(path)).mode & 4095;
7513
7540
  await fs.chmod(path, mode & ~fresh2.added | want);
@@ -7516,32 +7543,47 @@ var FreshModules = class {
7516
7543
  const overrides = {
7517
7544
  writeFile: async (path, content, owner) => {
7518
7545
  await fs.writeFile(path, content, owner);
7519
- await decide(path, content);
7546
+ if (this.fresh.has(normalizePath(path))) {
7547
+ await decide(
7548
+ path,
7549
+ typeof content === "string" ? new TextEncoder().encode(content) : content
7550
+ );
7551
+ }
7520
7552
  },
7521
7553
  chmod: async (path, mode) => {
7522
7554
  const fresh2 = this.fresh.get(normalizePath(path));
7523
- const creating = fresh2?.added === 0 && (mode & 4095) === (438 & ~fresh2.umask);
7524
- if (!creating) this.fresh.delete(normalizePath(path));
7555
+ if (fresh2?.setup && (mode & 4095) === (438 & ~fresh2.umask)) fresh2.setup = false;
7556
+ else if (fresh2) this.drop(fresh2);
7525
7557
  await fs.chmod(path, mode);
7526
7558
  },
7527
7559
  rm: async (path, options) => {
7528
- this.fresh.delete(normalizePath(path));
7529
7560
  await fs.rm(path, options);
7561
+ const at = normalizePath(path);
7562
+ for (const key of [...this.fresh.keys()]) {
7563
+ if (key === at || within4(key, at)) this.fresh.delete(key);
7564
+ }
7530
7565
  },
7531
7566
  rename: async (from, to) => {
7532
7567
  await fs.rename(from, to);
7533
- const fresh2 = this.fresh.get(normalizePath(from));
7534
- this.fresh.delete(normalizePath(from));
7535
- this.fresh.delete(normalizePath(to));
7568
+ this.moved(from, to);
7569
+ },
7570
+ link: async (from, to, follow2) => {
7571
+ await fs.link(from, to, follow2);
7572
+ const source = follow2 && fs.realpath ? await fs.realpath(from, true) : from;
7573
+ const fresh2 = this.fresh.get(normalizePath(source));
7536
7574
  if (fresh2) this.fresh.set(normalizePath(to), fresh2);
7537
7575
  }
7538
7576
  };
7539
7577
  const ranged2 = rangedOps(fs);
7540
7578
  if (ranged2) {
7541
7579
  overrides.pwrite = async (path, at, bytes, transfer) => {
7542
- const head = at === 0 && this.fresh.has(normalizePath(path)) ? bytes.slice(0, 4) : void 0;
7580
+ const touches2 = at < MAGIC.length && this.fresh.has(normalizePath(path));
7543
7581
  await ranged2.pwrite(path, at, bytes, transfer);
7544
- if (head) await decide(path, head);
7582
+ if (touches2) await decide(path);
7583
+ };
7584
+ overrides.truncate = async (path, size) => {
7585
+ await ranged2.truncate(path, size);
7586
+ if (size < MAGIC.length && this.fresh.has(normalizePath(path))) await decide(path);
7545
7587
  };
7546
7588
  }
7547
7589
  const bound2 = /* @__PURE__ */ new WeakMap();
@@ -7613,7 +7655,7 @@ var UNLINKED_DIR = ".slicc-unlinked";
7613
7655
  function webLocks() {
7614
7656
  return globalThis.navigator?.locks;
7615
7657
  }
7616
- var within4 = (path, target) => path === target || target === "/" || path.startsWith(`${target}/`);
7658
+ var within5 = (path, target) => path === target || target === "/" || path.startsWith(`${target}/`);
7617
7659
  var parentOf5 = (path) => path.slice(0, path.lastIndexOf("/")) || "/";
7618
7660
  var lockName = (instance) => `slicc-unlinked:${instance}`;
7619
7661
  var dirOf = (root) => root === "/" ? `/${UNLINKED_DIR}` : `${root}/${UNLINKED_DIR}`;
@@ -7713,7 +7755,7 @@ var UnlinkedKeeper = class {
7713
7755
  for (const holder of this.holders) {
7714
7756
  if (holder.owns(target)) continue;
7715
7757
  for (const path of holder.held()) {
7716
- if (!within4(path, target) || holder.isKept(path)) continue;
7758
+ if (!within5(path, target) || holder.isKept(path)) continue;
7717
7759
  held.set(path, [...held.get(path) ?? [], holder]);
7718
7760
  }
7719
7761
  }
@@ -8336,7 +8378,7 @@ function parseSize(text) {
8336
8378
  if (!match) throw errnoError("EINVAL", `not a size: ${text}`);
8337
8379
  return Math.floor(Number(match[1]) * UNITS[match[2].toLowerCase()]);
8338
8380
  }
8339
- var within5 = (path, target) => path === target || target === "/" || path.startsWith(`${target}/`);
8381
+ var within6 = (path, target) => path === target || target === "/" || path.startsWith(`${target}/`);
8340
8382
  var HeldSet = class extends Set {
8341
8383
  idle;
8342
8384
  constructor(idle) {
@@ -8355,7 +8397,7 @@ var HeldSet = class extends Set {
8355
8397
  }
8356
8398
  };
8357
8399
  function heldUnder(held, target) {
8358
- for (const paths of held) for (const path of paths.keys()) if (within5(path, target)) return true;
8400
+ for (const paths of held) for (const path of paths.keys()) if (within6(path, target)) return true;
8359
8401
  return false;
8360
8402
  }
8361
8403
  var HeldPaths = class extends Map {
@@ -8471,24 +8513,24 @@ var HeldPaths = class extends Map {
8471
8513
  return this.owning === path;
8472
8514
  }
8473
8515
  revoke(prefix) {
8474
- for (const path of this.keys()) if (within5(path, prefix)) this.revoked.add(path);
8516
+ for (const path of this.keys()) if (within6(path, prefix)) this.revoked.add(path);
8475
8517
  }
8476
8518
  renamed(from, to) {
8477
8519
  for (const [path, count2] of [...this]) {
8478
- if (!within5(path, from)) continue;
8520
+ if (!within6(path, from)) continue;
8479
8521
  const moved2 = to + path.slice(from.length);
8480
8522
  this.delete(path);
8481
8523
  this.set(moved2, (this.get(moved2) ?? 0) + count2);
8482
8524
  if (this.revoked.delete(path)) this.revoked.add(moved2);
8483
8525
  }
8484
8526
  for (const [path, count2] of [...this.opens]) {
8485
- if (!within5(path, from)) continue;
8527
+ if (!within6(path, from)) continue;
8486
8528
  const moved2 = to + path.slice(from.length);
8487
8529
  this.opens.delete(path);
8488
8530
  this.opens.set(moved2, (this.opens.get(moved2) ?? 0) + count2);
8489
8531
  }
8490
8532
  for (const [id2, key] of this.handles) {
8491
- if (within5(key, from)) this.handles.set(id2, to + key.slice(from.length));
8533
+ if (within6(key, from)) this.handles.set(id2, to + key.slice(from.length));
8492
8534
  }
8493
8535
  }
8494
8536
  isRevoked(path) {
@@ -8595,7 +8637,7 @@ var MountTable = class {
8595
8637
  locate(path) {
8596
8638
  let best;
8597
8639
  for (const mount of this.mounts.values()) {
8598
- if (within5(path, mount.target) && (!best || mount.target.length > best.target.length))
8640
+ if (within6(path, mount.target) && (!best || mount.target.length > best.target.length))
8599
8641
  best = mount;
8600
8642
  }
8601
8643
  if (!best) return void 0;
@@ -8738,7 +8780,7 @@ var MountTable = class {
8738
8780
  async commitUnder(prefix) {
8739
8781
  const at = normalizePath(prefix);
8740
8782
  await Promise.all(
8741
- [...this.sessions.keys()].filter((p) => within5(p, at)).map((p) => this.commit(p))
8783
+ [...this.sessions.keys()].filter((p) => within6(p, at)).map((p) => this.commit(p))
8742
8784
  );
8743
8785
  }
8744
8786
  async commitOverlapping(real, offset, length2) {
@@ -8773,10 +8815,10 @@ var MountTable = class {
8773
8815
  }
8774
8816
  forget(mount, path) {
8775
8817
  mount.epoch++;
8776
- for (const key of [...mount.attrs.keys()]) if (within5(key, path)) mount.attrs.delete(key);
8818
+ for (const key of [...mount.attrs.keys()]) if (within6(key, path)) mount.attrs.delete(key);
8777
8819
  mount.lists.delete(path);
8778
8820
  mount.lists.delete(parentOf7(path));
8779
- for (const key of [...mount.lists.keys()]) if (within5(key, path)) mount.lists.delete(key);
8821
+ for (const key of [...mount.lists.keys()]) if (within6(key, path)) mount.lists.delete(key);
8780
8822
  }
8781
8823
  async getattr(mount, path, rel2, settled = false) {
8782
8824
  for (let round = 1; ; round++) {
@@ -9411,6 +9453,11 @@ function statJson(s) {
9411
9453
  async function readdirStat(fs, dir) {
9412
9454
  return (await fs.readdirStat(dir)).map(([name2, stat]) => [name2, stat && statJson(stat)]);
9413
9455
  }
9456
+ async function usageAt(entry, path) {
9457
+ if (!entry.statfs) return void 0;
9458
+ const real = await realTarget(entry.fs, path).catch(() => path);
9459
+ return entry.statfs(real);
9460
+ }
9414
9461
  async function storageUsage() {
9415
9462
  const estimate = await globalThis.navigator?.storage?.estimate?.();
9416
9463
  if (typeof estimate?.quota !== "number") return null;
@@ -9727,7 +9774,7 @@ async function dispatchOne(entry, req) {
9727
9774
  if (req.op === "hold") return await holdOp(entry, path, req);
9728
9775
  const refused2 = await guarded(entry, path, req);
9729
9776
  if (refused2) return refused2;
9730
- if (req.op === "statfs") return json2(await entry.statfs?.(path) ?? await storageUsage());
9777
+ if (req.op === "statfs") return json2(await usageAt(entry, path) ?? await storageUsage());
9731
9778
  if (entry.revoked?.(path)) return { ok: false, errno: "EIO", message: `${path} was unmounted` };
9732
9779
  if (req.op === "write" && req.mode === 1 || UNLINKED_OPS.has(req.op)) {
9733
9780
  const serve = async () => run(entry, await keptOr(entry, path, req.handle), req);
@@ -11961,7 +12008,7 @@ function isMissing(err) {
11961
12008
  if (err?.code === "ENOENT") return true;
11962
12009
  return err instanceof Error && err.message.startsWith("ENOENT");
11963
12010
  }
11964
- function within6(path, root) {
12011
+ function within7(path, root) {
11965
12012
  return path === root || path.startsWith(root.endsWith("/") ? root : `${root}/`);
11966
12013
  }
11967
12014
  var VfsNode = class {
@@ -12282,12 +12329,12 @@ var VfsNodes = class {
12282
12329
  return node;
12283
12330
  }
12284
12331
  holds(prefix) {
12285
- for (const path of this.byPath.keys()) if (within6(path, prefix)) return true;
12332
+ for (const path of this.byPath.keys()) if (within7(path, prefix)) return true;
12286
12333
  return false;
12287
12334
  }
12288
12335
  writes(prefix) {
12289
12336
  for (const [path, node] of this.byPath)
12290
- if (node.writers > 0 && within6(path, prefix)) return true;
12337
+ if (node.writers > 0 && within7(path, prefix)) return true;
12291
12338
  return false;
12292
12339
  }
12293
12340
  closed(node, writable2 = false) {
@@ -12331,11 +12378,11 @@ var VfsNodes = class {
12331
12378
  this.kept.delete(node);
12332
12379
  }
12333
12380
  async flush(path) {
12334
- for (const [p, node] of this.byPath) if (within6(p, path)) await node.serial(() => node.flush());
12381
+ for (const [p, node] of this.byPath) if (within7(p, path)) await node.serial(() => node.flush());
12335
12382
  }
12336
12383
  async unlinking(path) {
12337
12384
  for (const [held, node] of [...this.byPath]) {
12338
- if (!within6(held, path)) continue;
12385
+ if (!within7(held, path)) continue;
12339
12386
  await node.serial(async () => {
12340
12387
  await Promise.all([this.keepsOnDisk || node.keep(), node.limit()]);
12341
12388
  });
@@ -12343,14 +12390,14 @@ var VfsNodes = class {
12343
12390
  }
12344
12391
  revoke(prefix) {
12345
12392
  for (const [path, node] of [...this.byPath]) {
12346
- if (!within6(path, prefix)) continue;
12393
+ if (!within7(path, prefix)) continue;
12347
12394
  node.revoke();
12348
12395
  this.forget(node);
12349
12396
  }
12350
12397
  }
12351
12398
  unlinked(path) {
12352
12399
  for (const [held, node] of [...this.byPath]) {
12353
- if (!within6(held, path) || this.byPath.get(held) !== node) continue;
12400
+ if (!within7(held, path) || this.byPath.get(held) !== node) continue;
12354
12401
  if (!this.dropName(held, node)) this.orphan(node);
12355
12402
  }
12356
12403
  }
@@ -12358,8 +12405,8 @@ var VfsNodes = class {
12358
12405
  if (from === to) return;
12359
12406
  const moved2 = [];
12360
12407
  for (const [p, node] of [...this.byPath]) {
12361
- if (within6(p, from)) moved2.push([p, node]);
12362
- else if (within6(p, to) && this.byPath.get(p) === node && !this.dropName(p, node)) {
12408
+ if (within7(p, from)) moved2.push([p, node]);
12409
+ else if (within7(p, to) && this.byPath.get(p) === node && !this.dropName(p, node)) {
12363
12410
  this.orphan(node);
12364
12411
  }
12365
12412
  }
@@ -12638,7 +12685,7 @@ function isWasmSyscall(req) {
12638
12685
  var MAX_READ = 1024 * 1024;
12639
12686
  var WRITE_ACCESS = 3;
12640
12687
  var KEYBOARD = /* @__PURE__ */ new Set([SIG.INT, SIG.QUIT, SIG.TSTP]);
12641
- var DEFAULT_UMASK = 18;
12688
+ var DEFAULT_UMASK2 = 18;
12642
12689
  function words(value) {
12643
12690
  if (!Array.isArray(value) || !value.every((w) => typeof w === "string")) {
12644
12691
  throw new KernelError("EINVAL");
@@ -12666,7 +12713,7 @@ var WasmProcess = class {
12666
12713
  interrupt = new AbortController();
12667
12714
  gone = new AbortController();
12668
12715
  dying = false;
12669
- umask = DEFAULT_UMASK;
12716
+ umask = DEFAULT_UMASK2;
12670
12717
  cred;
12671
12718
  execChild;
12672
12719
  killed = false;
@@ -12688,7 +12735,7 @@ var WasmProcess = class {
12688
12735
  this.fds = fds;
12689
12736
  this.options = options;
12690
12737
  this.inherited = options.ignored ?? 0;
12691
- this.umask = options.umask ?? DEFAULT_UMASK;
12738
+ this.umask = options.umask ?? DEFAULT_UMASK2;
12692
12739
  this.cred = copyCred(options.cred ?? ROOT);
12693
12740
  this.children = new ChildTable(fds, options.spawner, options.forker);
12694
12741
  this.nodes = options.nodes ?? new VfsNodes(options.fs);
@@ -18271,7 +18318,7 @@ var Launcher = class {
18271
18318
  }
18272
18319
  }
18273
18320
  umaskOf(pid) {
18274
- return this.processes.get(pid)?.umask?.() ?? DEFAULT_UMASK;
18321
+ return this.processes.get(pid)?.umask?.() ?? DEFAULT_UMASK2;
18275
18322
  }
18276
18323
  imageOf(pid) {
18277
18324
  const members = this.jobs.list();