@ai-ecoverse/slicc-kernel 1.39.1 → 1.39.3

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
@@ -2606,6 +2606,210 @@ var OpfsFs = class {
2606
2606
  }
2607
2607
  };
2608
2608
 
2609
+ // src/fs/unlinked.ts
2610
+ var UNLINKED_DIR = ".slicc-unlinked";
2611
+ function pidOwner(proc) {
2612
+ return {
2613
+ id: `p${proc.pid}`,
2614
+ alive(id) {
2615
+ try {
2616
+ proc.kill(Number(id.slice(1)), 0);
2617
+ return true;
2618
+ } catch (err) {
2619
+ return err.code !== "ESRCH";
2620
+ }
2621
+ }
2622
+ };
2623
+ }
2624
+ function webLocks() {
2625
+ return globalThis.navigator?.locks;
2626
+ }
2627
+ var within2 = (path, target) => path === target || target === "/" || path.startsWith(`${target}/`);
2628
+ var parentOf3 = (path) => path.slice(0, path.lastIndexOf("/")) || "/";
2629
+ var lockName = (instance) => `slicc-unlinked:${instance}`;
2630
+ var dirOf = (root) => root === "/" ? `/${UNLINKED_DIR}` : `${root}/${UNLINKED_DIR}`;
2631
+ var PathGate = class {
2632
+ tails = /* @__PURE__ */ new Map();
2633
+ async acquire(path) {
2634
+ const prev = this.tails.get(path) ?? Promise.resolve();
2635
+ const { promise, resolve } = Promise.withResolvers();
2636
+ const tail = prev.then(() => promise);
2637
+ this.tails.set(path, tail);
2638
+ await prev;
2639
+ return () => {
2640
+ resolve();
2641
+ if (this.tails.get(path) === tail) this.tails.delete(path);
2642
+ };
2643
+ }
2644
+ async run(path, op) {
2645
+ const release = await this.acquire(path);
2646
+ try {
2647
+ return await op();
2648
+ } finally {
2649
+ release();
2650
+ }
2651
+ }
2652
+ };
2653
+ var UnlinkedKeeper = class {
2654
+ fs;
2655
+ holders;
2656
+ rootOf;
2657
+ locks;
2658
+ busy;
2659
+ waiting = /* @__PURE__ */ new Set();
2660
+ owner;
2661
+ instance;
2662
+ gate = new PathGate();
2663
+ queue = Promise.resolve();
2664
+ count = 0;
2665
+ constructor(fs, holders, rootOf, options = {}) {
2666
+ const { locks, owner } = options;
2667
+ this.fs = fs;
2668
+ this.holders = holders;
2669
+ this.rootOf = rootOf;
2670
+ this.locks = locks;
2671
+ this.busy = options.busy ?? (() => false);
2672
+ this.owner = owner;
2673
+ this.instance = owner ? `${owner.id}~${crypto.randomUUID()}` : crypto.randomUUID();
2674
+ void locks?.request(lockName(this.instance), () => new Promise(() => void 0));
2675
+ }
2676
+ serial(op) {
2677
+ const next = this.queue.then(op);
2678
+ this.queue = next.catch(() => void 0);
2679
+ return next;
2680
+ }
2681
+ wrap(fs = this.fs) {
2682
+ const keeper = this;
2683
+ const visible = (names) => names.filter((name2) => name2 !== UNLINKED_DIR);
2684
+ return {
2685
+ ...fs,
2686
+ async rm(path, options) {
2687
+ const target = fs.resolvePath("/", path);
2688
+ const pinned = await keeper.pin(target);
2689
+ if (pinned.moved.has(target)) pinned.commit();
2690
+ else await keeper.settle(pinned, () => fs.rm(path, options));
2691
+ },
2692
+ async rename(from, to) {
2693
+ const target = fs.resolvePath("/", to);
2694
+ if (target === fs.resolvePath("/", from)) return fs.rename(from, to);
2695
+ const pinned = await keeper.pin(target);
2696
+ await keeper.settle(pinned, () => fs.rename(from, to));
2697
+ },
2698
+ readdir: async (path) => visible(await fs.readdir(path)),
2699
+ readdirStat: async (path) => (await fs.readdirStat(path)).filter(([name2]) => name2 !== UNLINKED_DIR)
2700
+ };
2701
+ }
2702
+ async settle(pinned, op) {
2703
+ try {
2704
+ await op();
2705
+ } catch (err) {
2706
+ await pinned.rollback();
2707
+ throw err;
2708
+ }
2709
+ pinned.commit();
2710
+ }
2711
+ async pin(target) {
2712
+ const held = /* @__PURE__ */ new Map();
2713
+ for (const holder of this.holders) {
2714
+ if (holder.owns(target)) continue;
2715
+ for (const path of holder.held()) {
2716
+ if (!within2(path, target) || holder.isKept(path)) continue;
2717
+ held.set(path, [...held.get(path) ?? [], holder]);
2718
+ }
2719
+ }
2720
+ const paths = [...held.keys()].sort();
2721
+ const releases = [];
2722
+ for (const path of paths) releases.push(await this.gate.acquire(path));
2723
+ const hidden = /* @__PURE__ */ new Map();
2724
+ for (const path of paths) {
2725
+ const at = await this.hide(path);
2726
+ if (at !== void 0) hidden.set(path, at);
2727
+ }
2728
+ const done4 = () => {
2729
+ for (const release of releases) release();
2730
+ };
2731
+ const files = /* @__PURE__ */ new Map();
2732
+ for (const [path, at] of hidden) {
2733
+ const holders = held.get(path);
2734
+ const file = this.keptFile(at, { refs: holders.length + 1 });
2735
+ files.set(path, file);
2736
+ for (const holder of holders) holder.keep(path, file);
2737
+ }
2738
+ return {
2739
+ moved: new Set(hidden.keys()),
2740
+ commit: () => {
2741
+ for (const file of files.values()) file.release();
2742
+ done4();
2743
+ },
2744
+ rollback: async () => {
2745
+ for (const [path, file] of files) {
2746
+ for (const holder of held.get(path)) holder.unkeep(path, file);
2747
+ await this.serial(async () => {
2748
+ await Promise.allSettled([this.fs.rename(file.hidden, path)]);
2749
+ await this.tidy(parentOf3(file.hidden));
2750
+ });
2751
+ }
2752
+ done4();
2753
+ }
2754
+ };
2755
+ }
2756
+ keptFile(hidden, entry) {
2757
+ return {
2758
+ hidden,
2759
+ release: () => {
2760
+ if (--entry.refs === 0) void this.serial(() => this.drop(hidden));
2761
+ }
2762
+ };
2763
+ }
2764
+ hide(path) {
2765
+ return this.serial(async () => {
2766
+ const dir = dirOf(this.rootOf(path));
2767
+ const hidden = `${dir}/${this.instance}.${++this.count}`;
2768
+ try {
2769
+ await this.fs.mkdir(dir, { recursive: true });
2770
+ await this.fs.rename(path, hidden);
2771
+ return hidden;
2772
+ } catch {
2773
+ await this.tidy(dir);
2774
+ return void 0;
2775
+ }
2776
+ });
2777
+ }
2778
+ closed(path) {
2779
+ if (this.waiting.delete(path)) void this.serial(() => this.drop(path));
2780
+ }
2781
+ async drop(hidden) {
2782
+ if (this.busy(hidden)) {
2783
+ this.waiting.add(hidden);
2784
+ return;
2785
+ }
2786
+ await this.fs.rm(hidden).catch(() => void 0);
2787
+ await this.tidy(parentOf3(hidden));
2788
+ }
2789
+ async tidy(dir) {
2790
+ const left = await this.fs.readdir(dir).catch(() => [UNLINKED_DIR]);
2791
+ if (left.length === 0) await this.fs.rm(dir, { recursive: true }).catch(() => void 0);
2792
+ }
2793
+ sweep(root) {
2794
+ const query = this.locks?.query?.bind(this.locks);
2795
+ const owner = this.owner;
2796
+ if (!query && !owner) return Promise.resolve();
2797
+ return this.serial(async () => {
2798
+ const dir = dirOf(root);
2799
+ const names = await this.fs.readdir(dir).catch(() => void 0);
2800
+ if (!names) return;
2801
+ const held = query && new Set(((await query()).held ?? []).map((lock) => lock.name));
2802
+ for (const name2 of names) {
2803
+ const id = name2.slice(0, name2.lastIndexOf("."));
2804
+ const at = id.indexOf("~");
2805
+ const dead = id !== this.instance && (at < 0 ? held !== void 0 && !held.has(lockName(id)) : owner?.alive(id.slice(0, at)) === false);
2806
+ if (dead) await this.fs.rm(`${dir}/${name2}`, { recursive: true }).catch(() => void 0);
2807
+ }
2808
+ await this.tidy(dir);
2809
+ });
2810
+ }
2811
+ };
2812
+
2609
2813
  // src/kernel/net/http1.ts
2610
2814
  var HttpError = class extends Error {
2611
2815
  status;
@@ -3674,186 +3878,6 @@ function withCommandDirs(fs, names) {
3674
3878
  };
3675
3879
  }
3676
3880
 
3677
- // src/fs/unlinked.ts
3678
- var UNLINKED_DIR = ".slicc-unlinked";
3679
- function webLocks() {
3680
- return globalThis.navigator?.locks;
3681
- }
3682
- var within2 = (path, target) => path === target || target === "/" || path.startsWith(`${target}/`);
3683
- var parentOf3 = (path) => path.slice(0, path.lastIndexOf("/")) || "/";
3684
- var lockName = (instance) => `slicc-unlinked:${instance}`;
3685
- var dirOf = (root) => root === "/" ? `/${UNLINKED_DIR}` : `${root}/${UNLINKED_DIR}`;
3686
- var PathGate = class {
3687
- tails = /* @__PURE__ */ new Map();
3688
- async acquire(path) {
3689
- const prev = this.tails.get(path) ?? Promise.resolve();
3690
- const { promise, resolve } = Promise.withResolvers();
3691
- const tail = prev.then(() => promise);
3692
- this.tails.set(path, tail);
3693
- await prev;
3694
- return () => {
3695
- resolve();
3696
- if (this.tails.get(path) === tail) this.tails.delete(path);
3697
- };
3698
- }
3699
- async run(path, op) {
3700
- const release = await this.acquire(path);
3701
- try {
3702
- return await op();
3703
- } finally {
3704
- release();
3705
- }
3706
- }
3707
- };
3708
- var UnlinkedKeeper = class {
3709
- fs;
3710
- holders;
3711
- rootOf;
3712
- locks;
3713
- busy;
3714
- waiting = /* @__PURE__ */ new Set();
3715
- instance = crypto.randomUUID();
3716
- gate = new PathGate();
3717
- queue = Promise.resolve();
3718
- count = 0;
3719
- constructor(fs, holders, rootOf, locks, busy = () => false) {
3720
- this.fs = fs;
3721
- this.holders = holders;
3722
- this.rootOf = rootOf;
3723
- this.locks = locks;
3724
- this.busy = busy;
3725
- void locks?.request(lockName(this.instance), () => new Promise(() => void 0));
3726
- }
3727
- serial(op) {
3728
- const next = this.queue.then(op);
3729
- this.queue = next.catch(() => void 0);
3730
- return next;
3731
- }
3732
- wrap() {
3733
- const fs = this.fs;
3734
- const keeper = this;
3735
- const visible = (names) => names.filter((name2) => name2 !== UNLINKED_DIR);
3736
- return {
3737
- ...fs,
3738
- async rm(path, options) {
3739
- const target = fs.resolvePath("/", path);
3740
- const pinned = await keeper.pin(target);
3741
- if (pinned.moved.has(target)) pinned.commit();
3742
- else await keeper.settle(pinned, () => fs.rm(path, options));
3743
- },
3744
- async rename(from, to) {
3745
- const pinned = await keeper.pin(fs.resolvePath("/", to));
3746
- await keeper.settle(pinned, () => fs.rename(from, to));
3747
- },
3748
- readdir: async (path) => visible(await fs.readdir(path)),
3749
- readdirStat: async (path) => (await fs.readdirStat(path)).filter(([name2]) => name2 !== UNLINKED_DIR)
3750
- };
3751
- }
3752
- async settle(pinned, op) {
3753
- try {
3754
- await op();
3755
- } catch (err) {
3756
- await pinned.rollback();
3757
- throw err;
3758
- }
3759
- pinned.commit();
3760
- }
3761
- async pin(target) {
3762
- const held = /* @__PURE__ */ new Map();
3763
- for (const holder of this.holders) {
3764
- if (holder.owns(target)) continue;
3765
- for (const path of holder.opens.keys()) {
3766
- if (!within2(path, target) || holder.unlinked.has(path)) continue;
3767
- held.set(path, [...held.get(path) ?? [], holder]);
3768
- }
3769
- }
3770
- const paths = [...held.keys()].sort();
3771
- const releases = [];
3772
- for (const path of paths) releases.push(await this.gate.acquire(path));
3773
- const hidden = /* @__PURE__ */ new Map();
3774
- for (const path of paths) {
3775
- const at = await this.hide(path);
3776
- if (at !== void 0) hidden.set(path, at);
3777
- }
3778
- const done4 = () => {
3779
- for (const release of releases) release();
3780
- };
3781
- return {
3782
- moved: new Set(hidden.keys()),
3783
- commit: () => {
3784
- for (const [path, at] of hidden) {
3785
- const holders = held.get(path);
3786
- const file = this.keptFile(at, { refs: holders.length });
3787
- for (const holder of holders) holder.unlinked.set(path, file);
3788
- }
3789
- done4();
3790
- },
3791
- rollback: async () => {
3792
- for (const [path, at] of hidden) {
3793
- await this.serial(async () => {
3794
- await Promise.allSettled([this.fs.rename(at, path)]);
3795
- await this.tidy(parentOf3(at));
3796
- });
3797
- }
3798
- done4();
3799
- }
3800
- };
3801
- }
3802
- keptFile(hidden, entry) {
3803
- return {
3804
- hidden,
3805
- release: () => {
3806
- if (--entry.refs === 0) void this.serial(() => this.drop(hidden));
3807
- }
3808
- };
3809
- }
3810
- hide(path) {
3811
- return this.serial(async () => {
3812
- const dir = dirOf(this.rootOf(path));
3813
- const hidden = `${dir}/${this.instance}.${++this.count}`;
3814
- try {
3815
- await this.fs.mkdir(dir, { recursive: true });
3816
- await this.fs.rename(path, hidden);
3817
- return hidden;
3818
- } catch {
3819
- await this.tidy(dir);
3820
- return void 0;
3821
- }
3822
- });
3823
- }
3824
- closed(path) {
3825
- if (this.waiting.delete(path)) void this.serial(() => this.drop(path));
3826
- }
3827
- async drop(hidden) {
3828
- if (this.busy(hidden)) {
3829
- this.waiting.add(hidden);
3830
- return;
3831
- }
3832
- await this.fs.rm(hidden).catch(() => void 0);
3833
- await this.tidy(parentOf3(hidden));
3834
- }
3835
- async tidy(dir) {
3836
- const left = await this.fs.readdir(dir).catch(() => [UNLINKED_DIR]);
3837
- if (left.length === 0) await this.fs.rm(dir, { recursive: true }).catch(() => void 0);
3838
- }
3839
- sweep(root) {
3840
- const query = this.locks?.query?.bind(this.locks);
3841
- if (!query) return Promise.resolve();
3842
- return this.serial(async () => {
3843
- const dir = dirOf(root);
3844
- const names = await this.fs.readdir(dir).catch(() => void 0);
3845
- if (!names) return;
3846
- const held = new Set(((await query()).held ?? []).map((lock) => lock.name));
3847
- for (const name2 of names) {
3848
- const owner = name2.slice(0, name2.lastIndexOf("."));
3849
- if (owner === this.instance || held.has(lockName(owner))) continue;
3850
- await this.fs.rm(`${dir}/${name2}`, { recursive: true }).catch(() => void 0);
3851
- }
3852
- await this.tidy(dir);
3853
- });
3854
- }
3855
- };
3856
-
3857
3881
  // src/fs/watch.ts
3858
3882
  var WATCH_BATCH_LIMIT = 1e3;
3859
3883
  var under2 = (path, dir) => dir === "/" || path.startsWith(`${dir}/`);
@@ -4050,6 +4074,7 @@ var ChildTable = class {
4050
4074
  if ("fd" in slot) return this.parentFds.get(slot.fd).retain();
4051
4075
  if ("input" in slot) return bytesSource(slot.input);
4052
4076
  if ("device" in slot) return deviceFile(slot.device, slot.access);
4077
+ if ("dir" in slot) return heldFile({ dir: slot.dir });
4053
4078
  if ("capture" in slot) {
4054
4079
  const chunks2 = [];
4055
4080
  captured.set(n, chunks2);
@@ -4281,6 +4306,18 @@ var HeldPaths = class extends Map {
4281
4306
  holding(path) {
4282
4307
  return this.opens.has(this.keyOf(path));
4283
4308
  }
4309
+ held() {
4310
+ return this.opens.keys();
4311
+ }
4312
+ isKept(path) {
4313
+ return this.unlinked.has(path);
4314
+ }
4315
+ keep(path, file) {
4316
+ this.unlinked.set(path, file);
4317
+ }
4318
+ unkeep(path) {
4319
+ this.unlinked.delete(path);
4320
+ }
4284
4321
  hold(path, on, open = false, real) {
4285
4322
  if (open) {
4286
4323
  const key = real ?? this.keyOf(path);
@@ -5148,6 +5185,9 @@ async function run(entry, path, req) {
5148
5185
  case "symlink":
5149
5186
  await fs.symlink(req.arg2 ?? "", path);
5150
5187
  return done;
5188
+ case "create":
5189
+ await createExclusive(fs, path);
5190
+ return done;
5151
5191
  case "readlink":
5152
5192
  return json2(await fs.readlink(path));
5153
5193
  case "chmod":
@@ -5167,6 +5207,15 @@ async function run(entry, path, req) {
5167
5207
  return { ok: false, errno: "EINVAL", message: `sync-fs: unknown op '${req.op}'` };
5168
5208
  }
5169
5209
  }
5210
+ async function createExclusive(fs, path) {
5211
+ if (fs.createExclusive) return fs.createExclusive(path);
5212
+ if (await fs.lstat(path).then(
5213
+ () => true,
5214
+ () => false
5215
+ ))
5216
+ throw syncError("EEXIST", path);
5217
+ await fs.writeFile(path, new Uint8Array(0));
5218
+ }
5170
5219
  async function ranged(fs, path, req) {
5171
5220
  const ops = rangedOps(fs);
5172
5221
  if (!ops) throw syncError("ENOSYS", path);
@@ -8126,6 +8175,8 @@ var VfsNode = class {
8126
8175
  };
8127
8176
  var VfsNodes = class {
8128
8177
  byPath = /* @__PURE__ */ new Map();
8178
+ kept = /* @__PURE__ */ new Map();
8179
+ keepsOnDisk = false;
8129
8180
  fs;
8130
8181
  entries = /* @__PURE__ */ new Map();
8131
8182
  onClosed;
@@ -8208,15 +8259,47 @@ var VfsNodes = class {
8208
8259
  return;
8209
8260
  }
8210
8261
  if (this.byPath.get(node.path) === node) this.byPath.delete(node.path);
8262
+ this.kept.get(node)?.release();
8263
+ this.kept.delete(node);
8211
8264
  this.onClosed?.(node.path);
8212
8265
  }
8266
+ held() {
8267
+ return this.byPath.keys();
8268
+ }
8269
+ owns() {
8270
+ return false;
8271
+ }
8272
+ isKept() {
8273
+ return false;
8274
+ }
8275
+ keep(path, file) {
8276
+ const node = this.byPath.get(path);
8277
+ if (!node) {
8278
+ file.release();
8279
+ return;
8280
+ }
8281
+ this.byPath.delete(path);
8282
+ node.renamedTo(file.hidden);
8283
+ this.byPath.set(file.hidden, node);
8284
+ this.kept.set(node, file);
8285
+ }
8286
+ unkeep(path, file) {
8287
+ const node = this.byPath.get(file.hidden);
8288
+ if (!node) return;
8289
+ this.byPath.delete(file.hidden);
8290
+ node.renamedTo(path);
8291
+ this.byPath.set(path, node);
8292
+ this.kept.delete(node);
8293
+ }
8213
8294
  async flush(path) {
8214
8295
  for (const [p, node] of this.byPath) if (within5(p, path)) await node.serial(() => node.flush());
8215
8296
  }
8216
8297
  async unlinking(path) {
8217
8298
  for (const [held, node] of [...this.byPath]) {
8218
8299
  if (!within5(held, path)) continue;
8219
- await node.serial(async () => void await Promise.all([node.keep(), node.limit()]));
8300
+ await node.serial(async () => {
8301
+ await Promise.all([this.keepsOnDisk || node.keep(), node.limit()]);
8302
+ });
8220
8303
  }
8221
8304
  }
8222
8305
  revoke(prefix) {
@@ -8346,6 +8429,7 @@ function keepingOpen(fs, nodes) {
8346
8429
  });
8347
8430
  },
8348
8431
  writeFile: (path, content) => nodes.onEntry(fs.resolvePath("/", path), () => fs.writeFile(path, content)),
8432
+ createExclusive: async (path) => nodes.createExclusive(await nodes.entryKey(fs.resolvePath("/", path))),
8349
8433
  symlink: (target, path) => nodes.onEntry(fs.resolvePath("/", path), () => fs.symlink(target, path)),
8350
8434
  mkdir: (path, options) => nodes.onEntry(fs.resolvePath("/", path), () => fs.mkdir(path, options))
8351
8435
  };
@@ -9171,13 +9255,13 @@ var Dying = class {
9171
9255
  timer;
9172
9256
  busy = 0;
9173
9257
  finish;
9174
- start(code, sig, header3, process, finish) {
9258
+ start(code, sig, header3, process2, finish) {
9175
9259
  if (this.ending) return;
9176
9260
  this.ending = { code, sig };
9177
9261
  this.finish = finish;
9178
9262
  this.arm();
9179
9263
  Atomics.store(header3, SAB_I_KILLED, code);
9180
- process.die();
9264
+ process2.die();
9181
9265
  }
9182
9266
  async serving(work) {
9183
9267
  this.busy++;
@@ -9213,8 +9297,8 @@ function notifiers(header3) {
9213
9297
  }
9214
9298
  };
9215
9299
  }
9216
- function publishStops(process, header3) {
9217
- process.onState((state) => {
9300
+ function publishStops(process2, header3) {
9301
+ process2.onState((state) => {
9218
9302
  Atomics.store(header3, SAB_I_STOP, state === "stopped" ? 1 : 0);
9219
9303
  Atomics.notify(header3, SAB_I_STOP);
9220
9304
  });
@@ -9284,7 +9368,7 @@ function holdingToken(opts, holds) {
9284
9368
  function spawnWasmProcess(opts) {
9285
9369
  const sab = new SharedArrayBuffer(SAB_HEADER_BYTES + SAB_DEFAULT_WINDOW_BYTES);
9286
9370
  const header3 = new Int32Array(sab, 0, SAB_HEADER_I32);
9287
- const process = new WasmProcess(opts.pid, opts.fds, {
9371
+ const process2 = new WasmProcess(opts.pid, opts.fds, {
9288
9372
  ...inherited(opts),
9289
9373
  ...opts.identity ? { identity: opts.identity } : {},
9290
9374
  ...opts.onSyscall ? { onSyscall: opts.onSyscall } : {},
@@ -9312,14 +9396,14 @@ function spawnWasmProcess(opts) {
9312
9396
  raise: (sig) => signal(sig),
9313
9397
  ...opts.program.abi === "wasi" || opts.program.abi === "js" ? { pendingBits: () => Atomics.load(header3, SAB_I_SIGNALS) } : {}
9314
9398
  });
9315
- publishStops(process, header3);
9399
+ publishStops(process2, header3);
9316
9400
  const holds = new HeldPaths();
9317
9401
  opts.held?.add(holds);
9318
9402
  const token = holdingToken(opts, holds);
9319
- process.keptPath = (path) => holds.keptAt(path)?.hidden;
9403
+ process2.keptPath = (path) => holds.keptAt(path)?.hidden;
9320
9404
  const worker = opts.createWorker();
9321
9405
  const dying = new Dying();
9322
- const dispatch2 = (req) => dying.serving(() => isWasmSyscall(req) ? process.syscall(req) : dispatchSyncFs(req));
9406
+ const dispatch2 = (req) => dying.serving(() => isWasmSyscall(req) ? process2.syscall(req) : dispatchSyncFs(req));
9323
9407
  const responder = attachSyncSabResponder(worker, sab, token, { dispatch: dispatch2 });
9324
9408
  const lane = opts.program.abi === "js" ? openLane(token, dispatch2) : void 0;
9325
9409
  const { promise: exited, resolve: settle } = Promise.withResolvers();
@@ -9329,7 +9413,7 @@ function spawnWasmProcess(opts) {
9329
9413
  if (done4) return;
9330
9414
  done4 = true;
9331
9415
  dying.clear();
9332
- endedBy = sig ?? process.execTermsig;
9416
+ endedBy = sig ?? process2.execTermsig;
9333
9417
  worker.removeEventListener("message", onMessage);
9334
9418
  worker.removeEventListener("error", onError);
9335
9419
  for (const tid of [...threads.keys()]) endThread(tid);
@@ -9338,7 +9422,7 @@ function spawnWasmProcess(opts) {
9338
9422
  revokeSyncFsToken(token);
9339
9423
  opts.held?.delete(holds);
9340
9424
  worker.terminate();
9341
- void process.exit().then(
9425
+ void process2.exit().then(
9342
9426
  () => settle(code),
9343
9427
  () => settle(code)
9344
9428
  );
@@ -9406,14 +9490,14 @@ function spawnWasmProcess(opts) {
9406
9490
  tw.postMessage(tinit);
9407
9491
  };
9408
9492
  worker.postMessage(
9409
- processInit(opts, sab, process.umask, lane?.lane),
9493
+ processInit(opts, sab, process2.umask, lane?.lane),
9410
9494
  transferOf(opts, lane?.lane)
9411
9495
  );
9412
9496
  const signal = (sig) => {
9413
- if (process.signal(sig) !== "terminate") return;
9497
+ if (process2.signal(sig) !== "terminate") return;
9414
9498
  const code = sig === SIG.KILL ? 137 : 128 + sig;
9415
9499
  if (opts.program.abi !== "wasi" || done4) finish(code, sig);
9416
- else dying.start(code, sig, header3, process, () => finish(code, sig));
9500
+ else dying.start(code, sig, header3, process2, () => finish(code, sig));
9417
9501
  };
9418
9502
  const kill = (code = 137) => finish(code, code > 128 && code < 160 ? code - 128 : void 0);
9419
9503
  return {
@@ -9422,10 +9506,10 @@ function spawnWasmProcess(opts) {
9422
9506
  kill,
9423
9507
  signal,
9424
9508
  termsig: () => endedBy,
9425
- onState: (listener) => process.onState(listener),
9509
+ onState: (listener) => process2.onState(listener),
9426
9510
  memory: () => Atomics.load(header3, SAB_I_MEMORY) * 65536,
9427
- ignoredSignals: (fork) => process.inheritable(fork),
9428
- umask: () => process.umask,
9511
+ ignoredSignals: (fork) => process2.inheritable(fork),
9512
+ umask: () => process2.umask,
9429
9513
  writesBack: () => opts.program.abi === "wasi" && !done4
9430
9514
  };
9431
9515
  }
@@ -11013,15 +11097,20 @@ var Launcher = class {
11013
11097
  enableCdp(this.net, this.cdp);
11014
11098
  const fs = withCommandDirs(this.base, async () => new Set((await this.commands()).keys()));
11015
11099
  this.nodes = new VfsNodes(fs, (path) => this.released(path));
11100
+ this.nodes.keepsOnDisk = true;
11016
11101
  this.openFiles.add(this.nodes);
11102
+ const holders = [this.held, [this.nodes]];
11017
11103
  this.unlinked = new UnlinkedKeeper(
11018
11104
  fs,
11019
- this.held,
11105
+ { [Symbol.iterator]: () => holders.flatMap((set2) => [...set2]).values() },
11020
11106
  (path) => this.mountRoot(path),
11021
- webLocks(),
11022
- (path) => [...this.openFiles].some((nodes) => nodes.holds(path))
11107
+ {
11108
+ locks: webLocks(),
11109
+ busy: (path) => [...this.openFiles].some((nodes) => nodes.holds(path)),
11110
+ owner: options.unlinkOwner
11111
+ }
11023
11112
  );
11024
- this.fs = keepingOpen(this.unlinked.wrap(), this.nodes);
11113
+ this.fs = this.unlinked.wrap(keepingOpen(fs, this.nodes));
11025
11114
  void this.unlinked.sweep("/");
11026
11115
  this.watchers.watch([this.modulesDir, this.pnpmHome], { recursive: true }, () => {
11027
11116
  this.catalog = void 0;
@@ -12718,6 +12807,7 @@ async function createNodeKernel(options = {}) {
12718
12807
  const transport = options.network?.transport;
12719
12808
  const launcher = new Launcher({
12720
12809
  fs,
12810
+ unlinkOwner: pidOwner(process),
12721
12811
  createWorker: () => nodeWorker(file, live, terminated),
12722
12812
  createDriverWorker: () => nodeWorker(
12723
12813
  options.driverWorker ?? new URL("./node-driver-worker.js", import.meta.url),