@ai-ecoverse/slicc-kernel 1.133.3 → 1.133.5

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
@@ -4161,6 +4161,7 @@ var RemoteWatch = class {
4161
4161
  settled = false;
4162
4162
  quiet;
4163
4163
  crowd;
4164
+ gone;
4164
4165
  told;
4165
4166
  counted = 0;
4166
4167
  recount() {
@@ -4250,6 +4251,7 @@ var RemoteWatch = class {
4250
4251
  this.peers.delete(peer);
4251
4252
  this.rebuild();
4252
4253
  this.recount();
4254
+ this.gone?.();
4253
4255
  for (const wait2 of this.waiting.values()) {
4254
4256
  if (wait2.left.delete(peer) && wait2.left.size === 0) wait2.done();
4255
4257
  }
@@ -4285,14 +4287,16 @@ var RemoteWatch = class {
4285
4287
  async prune() {
4286
4288
  if (!this.locks) return;
4287
4289
  const held = new Set(((await this.locks.query()).held ?? []).map((lock) => lock.name));
4290
+ let left = false;
4288
4291
  for (const tab of /* @__PURE__ */ new Set([...this.others.keys(), ...this.peers])) {
4289
4292
  if (!held.has(this.lockOf(tab))) {
4293
+ if (this.peers.delete(tab)) left = true;
4290
4294
  this.others.delete(tab);
4291
- this.peers.delete(tab);
4292
4295
  }
4293
4296
  }
4294
4297
  this.rebuild();
4295
4298
  this.recount();
4299
+ if (left) this.gone?.();
4296
4300
  }
4297
4301
  watched() {
4298
4302
  return this.union.size > 0;
@@ -4382,6 +4386,7 @@ var REPLACED_ATTEMPTS = 4;
4382
4386
  var RECONCILE_LISTINGS = 8;
4383
4387
  var EXECUTABLE = /\/node_modules\/(?:@[^/]+\/)?[^/]+\/bin\//;
4384
4388
  var RENAMES = "/.slicc-renames";
4389
+ var RENAME_LOCK = "slicc-rename:";
4385
4390
  function movable(handle) {
4386
4391
  return typeof handle.move === "function";
4387
4392
  }
@@ -4544,8 +4549,11 @@ var OpfsFs = class {
4544
4549
  this.lockPrefix = `slicc-excl:${channel ?? ""}:`;
4545
4550
  this.rootName = channel;
4546
4551
  this.channel = channel === void 0 ? void 0 : new BroadcastChannel(channel);
4547
- this.remote = channel === void 0 ? void 0 : new RemoteWatch(`${channel}:watch`);
4548
- if (this.remote) this.remote.quiet = () => this.quiet().then(() => this.settle?.());
4552
+ this.remote = channel === void 0 ? void 0 : new RemoteWatch(`${channel}:watch`, { locks: this.locks ?? null });
4553
+ if (this.remote) {
4554
+ this.remote.quiet = () => this.quiet().then(() => this.settle?.());
4555
+ this.remote.gone = () => void this.orphans();
4556
+ }
4549
4557
  if (this.channel) {
4550
4558
  const remote = this.remote;
4551
4559
  meta.listen?.((c) => {
@@ -5556,6 +5564,9 @@ var OpfsFs = class {
5556
5564
  }
5557
5565
  }
5558
5566
  await this.meta.remove([found.path]);
5567
+ if (found.handle?.kind === "directory") {
5568
+ await this.meta.update(found.path, (entry) => entry ?? vacatedAt(found.path));
5569
+ }
5559
5570
  this.touch(Date.now(), parentOf4(found.path));
5560
5571
  }
5561
5572
  links() {
@@ -5618,14 +5629,17 @@ var OpfsFs = class {
5618
5629
  const dir = parent.handle;
5619
5630
  const name2 = baseOf(destination);
5620
5631
  const swap = targetStat?.isDirectory === true;
5632
+ let lock;
5621
5633
  const staging = swap ? `.${name2}.${crypto.randomUUID()}` : name2;
5622
5634
  const copying = sourceStat.isDirectory && !movable(source.handle);
5623
5635
  const staged = resolvePath(parent.path, staging);
5624
5636
  const place = async () => {
5625
5637
  this.forget(destination);
5626
5638
  const timed2 = await this.explicitTimes(source.path);
5627
- const first = copying ? await this.intend({ from: source.path, to: staged }) : void 0;
5628
- const second = copying && swap ? await this.intend({ from: staged, to: destination, replace: true }) : void 0;
5639
+ const root = { ino: inodeOf(source.path), ...moving };
5640
+ const owned4 = lock ? { lock } : {};
5641
+ const first = copying ? await this.intend({ from: source.path, to: staged, root, ...owned4 }) : void 0;
5642
+ const second = copying && swap ? await this.intend({ from: staged, to: destination, replace: true, root, ...owned4 }) : void 0;
5629
5643
  const moved2 = await this.replacingTarget(
5630
5644
  targetStat !== null,
5631
5645
  () => this.place(source.handle, dir, staging)
@@ -5634,7 +5648,7 @@ var OpfsFs = class {
5634
5648
  throw err;
5635
5649
  });
5636
5650
  if (swap) await this.rm(destination, { recursive: true });
5637
- if (second) await this.intend({ from: staged, to: destination }, second);
5651
+ if (second) await this.intend({ from: staged, to: destination, root, ...owned4 }, second);
5638
5652
  await this.meta.move(source.path, destination, carry, left);
5639
5653
  this.movePending(source.path, destination);
5640
5654
  if (!moved2) {
@@ -5659,7 +5673,11 @@ var OpfsFs = class {
5659
5673
  const entry = { from: source.path, to: destination, done: promise };
5660
5674
  this.renamingDirs.add(entry);
5661
5675
  try {
5662
- await place();
5676
+ const locks = this.locks;
5677
+ if (locks) {
5678
+ lock = `${RENAME_LOCK}${crypto.randomUUID()}`;
5679
+ await locks.request(lock, place);
5680
+ } else await place();
5663
5681
  } finally {
5664
5682
  this.renamingDirs.delete(entry);
5665
5683
  resolve2();
@@ -5691,12 +5709,40 @@ var OpfsFs = class {
5691
5709
  } catch {
5692
5710
  }
5693
5711
  }
5694
- async finishRenames() {
5695
- const intents = (await this.meta.under(RENAMES)).filter((entry) => entry.rename !== void 0).sort(
5712
+ replaying = Promise.resolve();
5713
+ orphans() {
5714
+ this.replaying = this.replaying.then(() => this.finishRenames(true)).catch(() => 0);
5715
+ return this.replaying;
5716
+ }
5717
+ async finishRenames(orphaned = false) {
5718
+ const locks = this.locks;
5719
+ const held = /* @__PURE__ */ new Set();
5720
+ if (orphaned && locks) {
5721
+ const { held: h = [], pending = [] } = await locks.query();
5722
+ for (const lock of [...h, ...pending]) held.add(lock.name);
5723
+ }
5724
+ const intents = (await this.meta.under(RENAMES)).filter(
5725
+ (entry) => entry.rename !== void 0 && (!orphaned || locks !== void 0 && entry.rename.lock !== void 0 && !held.has(entry.rename.lock))
5726
+ ).sort(
5696
5727
  (a, b) => a.rename.at - b.rename.at
5697
5728
  );
5698
5729
  for (const entry of intents) {
5699
- const { from, to, replace } = entry.rename;
5730
+ const lock = entry.rename.lock;
5731
+ if (!orphaned || !locks || !lock) await this.finishRename(entry);
5732
+ else await locks.request(lock, () => this.finishRename(entry));
5733
+ }
5734
+ return intents.length;
5735
+ }
5736
+ async finishRename(entry) {
5737
+ const [current] = await this.meta.under(entry.path);
5738
+ if (current?.rename === void 0) return;
5739
+ const { from, to, replace, root } = current.rename;
5740
+ const { promise, resolve: resolve2 } = Promise.withResolvers();
5741
+ const barrier = { from, to, done: promise };
5742
+ this.renamingDirs.add(barrier);
5743
+ this.forget(from);
5744
+ this.forget(to);
5745
+ try {
5700
5746
  const left = await this.real(from);
5701
5747
  if (left && replace && await this.real(to)) await this.rm(to, { recursive: true });
5702
5748
  if (left) {
@@ -5713,11 +5759,23 @@ var OpfsFs = class {
5713
5759
  this.forget(to);
5714
5760
  }
5715
5761
  if ((await this.meta.under(from)).length > 0) {
5716
- await this.meta.move(from, to, (moved2) => ({ ...occupied(moved2), path: to }));
5762
+ await this.meta.move(
5763
+ from,
5764
+ to,
5765
+ (moved2) => ({
5766
+ ...occupied(moved2),
5767
+ ...root,
5768
+ ino: occupied(moved2).ino ?? root?.ino ?? inodeOf(from),
5769
+ path: to
5770
+ }),
5771
+ void 0
5772
+ );
5717
5773
  }
5718
5774
  await this.meta.update(entry.path, () => void 0);
5775
+ } finally {
5776
+ this.renamingDirs.delete(barrier);
5777
+ resolve2();
5719
5778
  }
5720
- return intents.length;
5721
5779
  }
5722
5780
  async settledRename(path) {
5723
5781
  if (this.renamingDirs.size === 0 && this.copying.size === 0 || typeof path !== "string")
@@ -6001,7 +6059,10 @@ var OpfsFs = class {
6001
6059
  };
6002
6060
  }
6003
6061
  async reconcile() {
6004
- if (this.remote && await this.remote.peered()) return 0;
6062
+ if (this.remote && await this.remote.peered()) {
6063
+ await this.orphans();
6064
+ return 0;
6065
+ }
6005
6066
  await this.finishRenames();
6006
6067
  let removed = 0;
6007
6068
  const entries = await this.meta.all();
@@ -7403,7 +7464,7 @@ function satisfies(version, range2) {
7403
7464
  }
7404
7465
 
7405
7466
  // src/version.ts
7406
- var KERNEL_VERSION = true ? "1.133.3" : "0.0.0-dev";
7467
+ var KERNEL_VERSION = true ? "1.133.5" : "0.0.0-dev";
7407
7468
  var OS_RELEASE = "6.0.0-slicc";
7408
7469
  function procVersion() {
7409
7470
  return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
@@ -10737,6 +10798,88 @@ var FifoTable = class {
10737
10798
  }
10738
10799
  };
10739
10800
 
10801
+ // src/kernel/held-cwd.ts
10802
+ var CWD_SLOTS = 1024;
10803
+ var UNTRACKED = CWD_SLOTS - 1;
10804
+ var under4 = (path, changed) => changed === "/" || path === changed || path.startsWith(`${changed}/`);
10805
+ var CwdTable = class {
10806
+ sab = new SharedArrayBuffer(CWD_SLOTS * 4);
10807
+ view = new Int32Array(this.sab);
10808
+ held = /* @__PURE__ */ new Map();
10809
+ free = [];
10810
+ next = 0;
10811
+ checks = 0;
10812
+ inodeOf;
10813
+ constructor(inodeOf2) {
10814
+ this.inodeOf = inodeOf2;
10815
+ }
10816
+ async hold(path, from) {
10817
+ const shared = from === void 0 ? void 0 : this.held.get(from);
10818
+ if (shared && shared.path === path) return this.share(from);
10819
+ const ino = await this.inodeOf(path).catch(() => void 0);
10820
+ const slot2 = this.free.pop() ?? (this.next < UNTRACKED ? this.next++ : UNTRACKED);
10821
+ if (slot2 === UNTRACKED) return slot2;
10822
+ this.held.set(slot2, {
10823
+ path,
10824
+ ino,
10825
+ refs: 1,
10826
+ dead: false,
10827
+ verified: Atomics.load(this.view, slot2)
10828
+ });
10829
+ return slot2;
10830
+ }
10831
+ share(slot2) {
10832
+ const held = slot2 === void 0 ? void 0 : this.held.get(slot2);
10833
+ if (!held) return UNTRACKED;
10834
+ held.refs++;
10835
+ return slot2;
10836
+ }
10837
+ release(slot2) {
10838
+ const held = slot2 === void 0 ? void 0 : this.held.get(slot2);
10839
+ if (!held || --held.refs > 0) return;
10840
+ this.held.delete(slot2);
10841
+ Atomics.add(this.view, slot2, 1);
10842
+ this.free.push(slot2);
10843
+ }
10844
+ stateOf(slot2) {
10845
+ const held = this.held.get(slot2);
10846
+ return { seen: held?.verified ?? Atomics.load(this.view, slot2), dead: held?.dead === true };
10847
+ }
10848
+ touched(paths, trees = []) {
10849
+ if (this.held.size === 0) return;
10850
+ for (const [slot2, held] of this.held) {
10851
+ if (held.dead) continue;
10852
+ if (paths.some((p) => under4(held.path, p)) || trees.some((t) => under4(held.path, t))) {
10853
+ Atomics.add(this.view, slot2, 1);
10854
+ }
10855
+ }
10856
+ }
10857
+ async check(slot2) {
10858
+ this.checks++;
10859
+ const gen = Atomics.load(this.view, slot2);
10860
+ const held = this.held.get(slot2);
10861
+ if (!held) return { gen, alive: true };
10862
+ if (!held.dead) {
10863
+ const ino = await this.inodeOf(held.path).catch(() => null);
10864
+ held.dead = ino === null || held.ino !== void 0 && ino !== held.ino;
10865
+ held.verified = gen;
10866
+ }
10867
+ return { gen, alive: !held.dead };
10868
+ }
10869
+ };
10870
+ function heldInit(o) {
10871
+ if (!o.cwds || o.cwdSlot === void 0) return {};
10872
+ const state = o.cwdState ?? { seen: 0, dead: false };
10873
+ return { held: { sab: o.cwds, slot: o.cwdSlot, ...state } };
10874
+ }
10875
+ function heldHooks(o) {
10876
+ if (!o.cwdCheck || !o.cwdChdir) return {};
10877
+ return { cwdCheck: o.cwdCheck, cwdChdir: o.cwdChdir };
10878
+ }
10879
+ function inheritedCwd(chdir, parent) {
10880
+ return chdir ? void 0 : parent;
10881
+ }
10882
+
10740
10883
  // src/fs/copy.ts
10741
10884
  async function present2(fs, path) {
10742
10885
  return fs.lstat(path).then(
@@ -20936,6 +21079,8 @@ var SYSCALL_OPS = /* @__PURE__ */ new Set([
20936
21079
  "fd-list",
20937
21080
  "proc-alarm",
20938
21081
  "proc-umask",
21082
+ "cwd-check",
21083
+ "cwd-chdir",
20939
21084
  "proc-cred",
20940
21085
  "proc-setcred",
20941
21086
  "dl-log",
@@ -22261,6 +22406,14 @@ var WasmProcess = class {
22261
22406
  return { ok: true, kind: "void" };
22262
22407
  case "proc-umask":
22263
22408
  return { ok: true, kind: "json", json: this.setUmask(req.mask) };
22409
+ case "cwd-check":
22410
+ return {
22411
+ ok: true,
22412
+ kind: "json",
22413
+ json: await this.options.cwdCheck?.() ?? { gen: 0, alive: true }
22414
+ };
22415
+ case "cwd-chdir":
22416
+ return { ok: true, kind: "json", json: await this.options.cwdChdir?.(req.path) ?? {} };
22264
22417
  case "proc-cred":
22265
22418
  return { ok: true, kind: "json", json: copyCred(this.cred) };
22266
22419
  case "proc-setcred":
@@ -22810,6 +22963,7 @@ function processInit(opts, sab, umask, cred, lane) {
22810
22963
  umask,
22811
22964
  cred,
22812
22965
  ...opts.changes ? { changes: opts.changes } : {},
22966
+ ...heldInit(opts),
22813
22967
  ...opts.owners ? { owners: true } : {},
22814
22968
  ...opts.links !== void 0 ? { links: true } : {},
22815
22969
  ...opts.ppid !== void 0 ? { ppid: opts.ppid } : {}
@@ -22883,6 +23037,7 @@ function processOptions(opts, header4, hooks, created4) {
22883
23037
  ...opts.identity ? { identity: opts.identity } : {},
22884
23038
  ...opts.onSyscall ? { onSyscall: opts.onSyscall } : {},
22885
23039
  ...opts.settling ? { settling: opts.settling } : {},
23040
+ ...heldHooks(opts),
22886
23041
  spawner: opts.spawner,
22887
23042
  forker: opts.forker,
22888
23043
  ...opts.fork?.dl ? { dl: opts.fork.dl } : {},
@@ -22933,6 +23088,7 @@ function threadInit(opts, program, sab, cred, thread, main) {
22933
23088
  owners: opts.owners === true,
22934
23089
  ...opts.links !== void 0 ? { links: true } : {},
22935
23090
  ...opts.changes ? { changes: opts.changes } : {},
23091
+ ...heldInit(opts),
22936
23092
  ...opts.ppid !== void 0 ? { ppid: opts.ppid } : {},
22937
23093
  thread,
22938
23094
  signals: main
@@ -26632,6 +26788,11 @@ var Launcher = class {
26632
26788
  hostname;
26633
26789
  watchers = new FsWatchers();
26634
26790
  changes = new FileChanges();
26791
+ cwds = new CwdTable(async (path) => {
26792
+ const { dev, ino } = await this.base.stat(path);
26793
+ return `${dev ?? 0}:${ino}`;
26794
+ });
26795
+ cwdSlots = /* @__PURE__ */ new Map();
26635
26796
  pnpmHome;
26636
26797
  pnpmChain;
26637
26798
  pnpmMade;
@@ -26688,7 +26849,10 @@ var Launcher = class {
26688
26849
  this.sealed.tickets.normalise = (path) => physicalPathAsync(this.base, path);
26689
26850
  this.sealed.userOf = async (uid) => (await this.users.lookup(uid))?.name;
26690
26851
  if (this.owners) options.fs.trackOwners?.();
26691
- this.watchers.tap((paths) => this.changes.publish(...paths));
26852
+ this.watchers.tap((paths) => {
26853
+ this.changes.publish(...paths);
26854
+ this.cwds.touched(paths);
26855
+ });
26692
26856
  this.watchers.onReshape(() => {
26693
26857
  for (const nodes of this.openFiles) nodes.reshaped();
26694
26858
  });
@@ -26758,6 +26922,7 @@ var Launcher = class {
26758
26922
  options.fs.onPeer?.(() => this.flushOpen());
26759
26923
  options.fs.remoteChanges?.((change) => {
26760
26924
  this.changes.flush();
26925
+ this.cwds.touched(change.paths, change.trees);
26761
26926
  this.rewritten(change.paths, change.trees);
26762
26927
  });
26763
26928
  const holders = [this.held, this.openFiles];
@@ -27540,11 +27705,12 @@ var Launcher = class {
27540
27705
  }
27541
27706
  const done4 = this.heldUrl(program);
27542
27707
  try {
27708
+ const cwdSlot = await this.cwds.hold(cwd, req.cwdFrom);
27543
27709
  const handle = await this.admitted(
27544
27710
  program.abi !== "js",
27545
27711
  req.fds,
27546
- (fds, quietOom) => this.start({ ...req, fds, quietOom, cwd, program, argv0: target.argv0, args, env })
27547
- );
27712
+ (fds, quietOom) => this.start({ ...req, fds, quietOom, cwd, program, argv0: target.argv0, args, env, cwdSlot })
27713
+ ).finally(() => this.cwds.release(cwdSlot));
27548
27714
  void handle.exited.finally(done4);
27549
27715
  return handle;
27550
27716
  } catch (err) {
@@ -27631,6 +27797,8 @@ var Launcher = class {
27631
27797
  throw new SpawnError("ESRCH");
27632
27798
  }
27633
27799
  const pid = req.pid ?? this.nextPid++;
27800
+ const cwdSlot = this.cwds.share(req.cwdSlot);
27801
+ this.cwdSlots.set(pid, cwdSlot);
27634
27802
  const scrubs = this.treeScrubs(req);
27635
27803
  const stack = this.stackFor(req.tag);
27636
27804
  const terminal = req.fds.stdioTerminal();
@@ -27665,6 +27833,7 @@ var Launcher = class {
27665
27833
  ...this.dac ? { dac: this.dac } : {},
27666
27834
  program: req.program,
27667
27835
  changes: this.changes.sab,
27836
+ ...this.heldFor(pid, cwdSlot),
27668
27837
  argv0: req.argv0,
27669
27838
  args: req.args,
27670
27839
  env: req.env,
@@ -27739,6 +27908,8 @@ var Launcher = class {
27739
27908
  (state) => state === "stopped" ? this.stopped.add(pid) : this.stopped.delete(pid)
27740
27909
  );
27741
27910
  void handle.exited.then(() => {
27911
+ this.cwds.release(this.cwdSlots.get(pid));
27912
+ this.cwdSlots.delete(pid);
27742
27913
  this.freshModules.forget(pid);
27743
27914
  const spent = handle.times?.();
27744
27915
  if (spent) this.spent.set(pid, spent);
@@ -27970,6 +28141,7 @@ var Launcher = class {
27970
28141
  const handle = await this.launch(planned, {
27971
28142
  ...deciding ? { decided: deciding.promise } : {},
27972
28143
  cwd: req.cwd,
28144
+ cwdFrom: inheritedCwd(req.chdir, this.cwdSlots.get(ppid)),
27973
28145
  ...redeemed,
27974
28146
  fds,
27975
28147
  report,
@@ -28031,6 +28203,24 @@ var Launcher = class {
28031
28203
  for (const resolve2 of waiting) resolve2(true);
28032
28204
  }, 0);
28033
28205
  }
28206
+ heldFor(pid, slot2) {
28207
+ return {
28208
+ cwds: this.cwds.sab,
28209
+ cwdSlot: slot2,
28210
+ cwdState: this.cwds.stateOf(slot2),
28211
+ cwdCheck: async () => {
28212
+ const current = this.cwdSlots.get(pid);
28213
+ return { ...await this.cwds.check(current), slot: current };
28214
+ },
28215
+ cwdChdir: (path) => this.chdirHeld(pid, path)
28216
+ };
28217
+ }
28218
+ async chdirHeld(pid, path) {
28219
+ this.cwds.release(this.cwdSlots.get(pid));
28220
+ const slot2 = await this.cwds.hold(path);
28221
+ this.cwdSlots.set(pid, slot2);
28222
+ return { slot: slot2, ...this.cwds.stateOf(slot2) };
28223
+ }
28034
28224
  forker(ppid, parent) {
28035
28225
  const { exec: _exec, pgid: _pgid, group: _group, pid: _pid, scrub: _scrub, ...image } = parent;
28036
28226
  return async (state, given) => {
@@ -28038,6 +28228,7 @@ var Launcher = class {
28038
28228
  ...image,
28039
28229
  quietOom,
28040
28230
  cwd: state.cwd ?? parent.cwd,
28231
+ cwdSlot: this.cwdSlots.get(ppid),
28041
28232
  fds,
28042
28233
  ppid,
28043
28234
  fork: state,