@ai-ecoverse/slicc-kernel 1.39.1 → 1.39.2

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}/`);
@@ -4281,6 +4305,18 @@ var HeldPaths = class extends Map {
4281
4305
  holding(path) {
4282
4306
  return this.opens.has(this.keyOf(path));
4283
4307
  }
4308
+ held() {
4309
+ return this.opens.keys();
4310
+ }
4311
+ isKept(path) {
4312
+ return this.unlinked.has(path);
4313
+ }
4314
+ keep(path, file) {
4315
+ this.unlinked.set(path, file);
4316
+ }
4317
+ unkeep(path) {
4318
+ this.unlinked.delete(path);
4319
+ }
4284
4320
  hold(path, on, open = false, real) {
4285
4321
  if (open) {
4286
4322
  const key = real ?? this.keyOf(path);
@@ -5148,6 +5184,9 @@ async function run(entry, path, req) {
5148
5184
  case "symlink":
5149
5185
  await fs.symlink(req.arg2 ?? "", path);
5150
5186
  return done;
5187
+ case "create":
5188
+ await createExclusive(fs, path);
5189
+ return done;
5151
5190
  case "readlink":
5152
5191
  return json2(await fs.readlink(path));
5153
5192
  case "chmod":
@@ -5167,6 +5206,15 @@ async function run(entry, path, req) {
5167
5206
  return { ok: false, errno: "EINVAL", message: `sync-fs: unknown op '${req.op}'` };
5168
5207
  }
5169
5208
  }
5209
+ async function createExclusive(fs, path) {
5210
+ if (fs.createExclusive) return fs.createExclusive(path);
5211
+ if (await fs.lstat(path).then(
5212
+ () => true,
5213
+ () => false
5214
+ ))
5215
+ throw syncError("EEXIST", path);
5216
+ await fs.writeFile(path, new Uint8Array(0));
5217
+ }
5170
5218
  async function ranged(fs, path, req) {
5171
5219
  const ops = rangedOps(fs);
5172
5220
  if (!ops) throw syncError("ENOSYS", path);
@@ -8126,6 +8174,8 @@ var VfsNode = class {
8126
8174
  };
8127
8175
  var VfsNodes = class {
8128
8176
  byPath = /* @__PURE__ */ new Map();
8177
+ kept = /* @__PURE__ */ new Map();
8178
+ keepsOnDisk = false;
8129
8179
  fs;
8130
8180
  entries = /* @__PURE__ */ new Map();
8131
8181
  onClosed;
@@ -8208,15 +8258,47 @@ var VfsNodes = class {
8208
8258
  return;
8209
8259
  }
8210
8260
  if (this.byPath.get(node.path) === node) this.byPath.delete(node.path);
8261
+ this.kept.get(node)?.release();
8262
+ this.kept.delete(node);
8211
8263
  this.onClosed?.(node.path);
8212
8264
  }
8265
+ held() {
8266
+ return this.byPath.keys();
8267
+ }
8268
+ owns() {
8269
+ return false;
8270
+ }
8271
+ isKept() {
8272
+ return false;
8273
+ }
8274
+ keep(path, file) {
8275
+ const node = this.byPath.get(path);
8276
+ if (!node) {
8277
+ file.release();
8278
+ return;
8279
+ }
8280
+ this.byPath.delete(path);
8281
+ node.renamedTo(file.hidden);
8282
+ this.byPath.set(file.hidden, node);
8283
+ this.kept.set(node, file);
8284
+ }
8285
+ unkeep(path, file) {
8286
+ const node = this.byPath.get(file.hidden);
8287
+ if (!node) return;
8288
+ this.byPath.delete(file.hidden);
8289
+ node.renamedTo(path);
8290
+ this.byPath.set(path, node);
8291
+ this.kept.delete(node);
8292
+ }
8213
8293
  async flush(path) {
8214
8294
  for (const [p, node] of this.byPath) if (within5(p, path)) await node.serial(() => node.flush());
8215
8295
  }
8216
8296
  async unlinking(path) {
8217
8297
  for (const [held, node] of [...this.byPath]) {
8218
8298
  if (!within5(held, path)) continue;
8219
- await node.serial(async () => void await Promise.all([node.keep(), node.limit()]));
8299
+ await node.serial(async () => {
8300
+ await Promise.all([this.keepsOnDisk || node.keep(), node.limit()]);
8301
+ });
8220
8302
  }
8221
8303
  }
8222
8304
  revoke(prefix) {
@@ -8346,6 +8428,7 @@ function keepingOpen(fs, nodes) {
8346
8428
  });
8347
8429
  },
8348
8430
  writeFile: (path, content) => nodes.onEntry(fs.resolvePath("/", path), () => fs.writeFile(path, content)),
8431
+ createExclusive: async (path) => nodes.createExclusive(await nodes.entryKey(fs.resolvePath("/", path))),
8349
8432
  symlink: (target, path) => nodes.onEntry(fs.resolvePath("/", path), () => fs.symlink(target, path)),
8350
8433
  mkdir: (path, options) => nodes.onEntry(fs.resolvePath("/", path), () => fs.mkdir(path, options))
8351
8434
  };
@@ -9171,13 +9254,13 @@ var Dying = class {
9171
9254
  timer;
9172
9255
  busy = 0;
9173
9256
  finish;
9174
- start(code, sig, header3, process, finish) {
9257
+ start(code, sig, header3, process2, finish) {
9175
9258
  if (this.ending) return;
9176
9259
  this.ending = { code, sig };
9177
9260
  this.finish = finish;
9178
9261
  this.arm();
9179
9262
  Atomics.store(header3, SAB_I_KILLED, code);
9180
- process.die();
9263
+ process2.die();
9181
9264
  }
9182
9265
  async serving(work) {
9183
9266
  this.busy++;
@@ -9213,8 +9296,8 @@ function notifiers(header3) {
9213
9296
  }
9214
9297
  };
9215
9298
  }
9216
- function publishStops(process, header3) {
9217
- process.onState((state) => {
9299
+ function publishStops(process2, header3) {
9300
+ process2.onState((state) => {
9218
9301
  Atomics.store(header3, SAB_I_STOP, state === "stopped" ? 1 : 0);
9219
9302
  Atomics.notify(header3, SAB_I_STOP);
9220
9303
  });
@@ -9284,7 +9367,7 @@ function holdingToken(opts, holds) {
9284
9367
  function spawnWasmProcess(opts) {
9285
9368
  const sab = new SharedArrayBuffer(SAB_HEADER_BYTES + SAB_DEFAULT_WINDOW_BYTES);
9286
9369
  const header3 = new Int32Array(sab, 0, SAB_HEADER_I32);
9287
- const process = new WasmProcess(opts.pid, opts.fds, {
9370
+ const process2 = new WasmProcess(opts.pid, opts.fds, {
9288
9371
  ...inherited(opts),
9289
9372
  ...opts.identity ? { identity: opts.identity } : {},
9290
9373
  ...opts.onSyscall ? { onSyscall: opts.onSyscall } : {},
@@ -9312,14 +9395,14 @@ function spawnWasmProcess(opts) {
9312
9395
  raise: (sig) => signal(sig),
9313
9396
  ...opts.program.abi === "wasi" || opts.program.abi === "js" ? { pendingBits: () => Atomics.load(header3, SAB_I_SIGNALS) } : {}
9314
9397
  });
9315
- publishStops(process, header3);
9398
+ publishStops(process2, header3);
9316
9399
  const holds = new HeldPaths();
9317
9400
  opts.held?.add(holds);
9318
9401
  const token = holdingToken(opts, holds);
9319
- process.keptPath = (path) => holds.keptAt(path)?.hidden;
9402
+ process2.keptPath = (path) => holds.keptAt(path)?.hidden;
9320
9403
  const worker = opts.createWorker();
9321
9404
  const dying = new Dying();
9322
- const dispatch2 = (req) => dying.serving(() => isWasmSyscall(req) ? process.syscall(req) : dispatchSyncFs(req));
9405
+ const dispatch2 = (req) => dying.serving(() => isWasmSyscall(req) ? process2.syscall(req) : dispatchSyncFs(req));
9323
9406
  const responder = attachSyncSabResponder(worker, sab, token, { dispatch: dispatch2 });
9324
9407
  const lane = opts.program.abi === "js" ? openLane(token, dispatch2) : void 0;
9325
9408
  const { promise: exited, resolve: settle } = Promise.withResolvers();
@@ -9329,7 +9412,7 @@ function spawnWasmProcess(opts) {
9329
9412
  if (done4) return;
9330
9413
  done4 = true;
9331
9414
  dying.clear();
9332
- endedBy = sig ?? process.execTermsig;
9415
+ endedBy = sig ?? process2.execTermsig;
9333
9416
  worker.removeEventListener("message", onMessage);
9334
9417
  worker.removeEventListener("error", onError);
9335
9418
  for (const tid of [...threads.keys()]) endThread(tid);
@@ -9338,7 +9421,7 @@ function spawnWasmProcess(opts) {
9338
9421
  revokeSyncFsToken(token);
9339
9422
  opts.held?.delete(holds);
9340
9423
  worker.terminate();
9341
- void process.exit().then(
9424
+ void process2.exit().then(
9342
9425
  () => settle(code),
9343
9426
  () => settle(code)
9344
9427
  );
@@ -9406,14 +9489,14 @@ function spawnWasmProcess(opts) {
9406
9489
  tw.postMessage(tinit);
9407
9490
  };
9408
9491
  worker.postMessage(
9409
- processInit(opts, sab, process.umask, lane?.lane),
9492
+ processInit(opts, sab, process2.umask, lane?.lane),
9410
9493
  transferOf(opts, lane?.lane)
9411
9494
  );
9412
9495
  const signal = (sig) => {
9413
- if (process.signal(sig) !== "terminate") return;
9496
+ if (process2.signal(sig) !== "terminate") return;
9414
9497
  const code = sig === SIG.KILL ? 137 : 128 + sig;
9415
9498
  if (opts.program.abi !== "wasi" || done4) finish(code, sig);
9416
- else dying.start(code, sig, header3, process, () => finish(code, sig));
9499
+ else dying.start(code, sig, header3, process2, () => finish(code, sig));
9417
9500
  };
9418
9501
  const kill = (code = 137) => finish(code, code > 128 && code < 160 ? code - 128 : void 0);
9419
9502
  return {
@@ -9422,10 +9505,10 @@ function spawnWasmProcess(opts) {
9422
9505
  kill,
9423
9506
  signal,
9424
9507
  termsig: () => endedBy,
9425
- onState: (listener) => process.onState(listener),
9508
+ onState: (listener) => process2.onState(listener),
9426
9509
  memory: () => Atomics.load(header3, SAB_I_MEMORY) * 65536,
9427
- ignoredSignals: (fork) => process.inheritable(fork),
9428
- umask: () => process.umask,
9510
+ ignoredSignals: (fork) => process2.inheritable(fork),
9511
+ umask: () => process2.umask,
9429
9512
  writesBack: () => opts.program.abi === "wasi" && !done4
9430
9513
  };
9431
9514
  }
@@ -11013,15 +11096,20 @@ var Launcher = class {
11013
11096
  enableCdp(this.net, this.cdp);
11014
11097
  const fs = withCommandDirs(this.base, async () => new Set((await this.commands()).keys()));
11015
11098
  this.nodes = new VfsNodes(fs, (path) => this.released(path));
11099
+ this.nodes.keepsOnDisk = true;
11016
11100
  this.openFiles.add(this.nodes);
11101
+ const holders = [this.held, [this.nodes]];
11017
11102
  this.unlinked = new UnlinkedKeeper(
11018
11103
  fs,
11019
- this.held,
11104
+ { [Symbol.iterator]: () => holders.flatMap((set2) => [...set2]).values() },
11020
11105
  (path) => this.mountRoot(path),
11021
- webLocks(),
11022
- (path) => [...this.openFiles].some((nodes) => nodes.holds(path))
11106
+ {
11107
+ locks: webLocks(),
11108
+ busy: (path) => [...this.openFiles].some((nodes) => nodes.holds(path)),
11109
+ owner: options.unlinkOwner
11110
+ }
11023
11111
  );
11024
- this.fs = keepingOpen(this.unlinked.wrap(), this.nodes);
11112
+ this.fs = this.unlinked.wrap(keepingOpen(fs, this.nodes));
11025
11113
  void this.unlinked.sweep("/");
11026
11114
  this.watchers.watch([this.modulesDir, this.pnpmHome], { recursive: true }, () => {
11027
11115
  this.catalog = void 0;
@@ -12718,6 +12806,7 @@ async function createNodeKernel(options = {}) {
12718
12806
  const transport = options.network?.transport;
12719
12807
  const launcher = new Launcher({
12720
12808
  fs,
12809
+ unlinkOwner: pidOwner(process),
12721
12810
  createWorker: () => nodeWorker(file, live, terminated),
12722
12811
  createDriverWorker: () => nodeWorker(
12723
12812
  options.driverWorker ?? new URL("./node-driver-worker.js", import.meta.url),