@ai-ecoverse/slicc-kernel 1.37.0 → 1.39.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.
@@ -259,11 +259,11 @@ var init_pages = __esm({
259
259
  runs.push({ offset: start, bytes });
260
260
  i = j;
261
261
  }
262
- const written = Math.max(this.stored, ...runs.map((r) => r.offset + r.bytes.length));
262
+ const written2 = Math.max(this.stored, ...runs.map((r) => r.offset + r.bytes.length));
263
263
  return {
264
264
  ...this.shrink !== void 0 ? { shrink: this.shrink } : {},
265
265
  runs,
266
- ...this.length > written ? { extend: this.length } : {}
266
+ ...this.length > written2 ? { extend: this.length } : {}
267
267
  };
268
268
  }
269
269
  flushed() {
@@ -691,7 +691,7 @@ function createHelpers(Fs, ops) {
691
691
  if (s.ranged) call2(() => s.ranged?.flush());
692
692
  else {
693
693
  const bytes = s.data.slice(0, s.len);
694
- call2(() => bridgeOf(node).writeFile(liveNodePath(node), bytes));
694
+ call2(() => bridgeOf(node).writeFile(liveNodePath(node), bytes, true));
695
695
  }
696
696
  s.dirty = false;
697
697
  s.stat = void 0;
@@ -920,6 +920,12 @@ function createStreamOps(h) {
920
920
  }
921
921
  }
922
922
  };
923
+ const opened = (node, on) => {
924
+ try {
925
+ bridgeOf(node).hold?.(liveNodePath(node), on, true);
926
+ } catch {
927
+ }
928
+ };
923
929
  return {
924
930
  open(stream) {
925
931
  if (!Fs.isFile(stream.node.mode)) return;
@@ -927,6 +933,7 @@ function createStreamOps(h) {
927
933
  if (s.openCount === 0 && !s.orphan) {
928
934
  const bridge = bridgeOf(stream.node);
929
935
  s.ranges = !!(bridge.pread && bridge.pwrite && bridge.truncate && statOf(stream.node).ranged);
936
+ rangedOf(stream.node);
930
937
  }
931
938
  if ((stream.flags & 3) !== 0) {
932
939
  try {
@@ -939,6 +946,7 @@ function createStreamOps(h) {
939
946
  }
940
947
  }
941
948
  stream.node.live.openCount++;
949
+ if (stream.node.live.openCount === 1) opened(stream.node, true);
942
950
  held(stream, 1);
943
951
  },
944
952
  dup(stream) {
@@ -964,6 +972,7 @@ function createStreamOps(h) {
964
972
  s.len = 0;
965
973
  s.loaded = false;
966
974
  held(stream, -1);
975
+ opened(node, false);
967
976
  }
968
977
  },
969
978
  read(stream, buffer, offset, length, position) {
@@ -1053,7 +1062,7 @@ function flushLiveVfs(Fs, plugin) {
1053
1062
  if (s.ranged) s.ranged.flush();
1054
1063
  else {
1055
1064
  const bytes = s.data.slice(0, s.len);
1056
- node.mount.opts.bridge.writeFile(liveNodePath(node), bytes);
1065
+ node.mount.opts.bridge.writeFile(liveNodePath(node), bytes, true);
1057
1066
  }
1058
1067
  s.dirty = false;
1059
1068
  } catch (err) {
@@ -1490,8 +1499,8 @@ function createSyncFsSabBridge(transport, opts = {}) {
1490
1499
  }
1491
1500
  return {
1492
1501
  readFile: (path) => bytes({ op: "read", path }, path),
1493
- writeFile: (path, data) => {
1494
- run({ op: "write", path, body: data }, path);
1502
+ writeFile: (path, data, open) => {
1503
+ run({ op: "write", path, body: data, ...open ? { mode: 1 } : {} }, path);
1495
1504
  },
1496
1505
  stat: (path) => {
1497
1506
  const s = parseSyncFsStat(json({ op: "stat", path }, path));
@@ -1558,8 +1567,8 @@ function createSyncFsSabBridge(transport, opts = {}) {
1558
1567
  lutimes: (path, atimeMs, mtimeMs) => {
1559
1568
  run({ op: "lutimes", path, atimeMs, mtimeMs }, path);
1560
1569
  },
1561
- hold: (path, held) => {
1562
- run({ op: "hold", path, mode: held ? 1 : 0 }, path);
1570
+ hold: (path, held, open) => {
1571
+ run({ op: "hold", path, mode: (held ? 1 : 0) | (open ? 2 : 0) }, path);
1563
1572
  },
1564
1573
  statfs: (path = "/") => parseSyncFsUsage(json({ op: "statfs", path }, path)),
1565
1574
  pread: (path, offset, length, version) => bytes({ op: "pread", path, offset, length, ...version ? { version } : {} }, path),
@@ -1790,8 +1799,8 @@ var init_kernel_streams = __esm({
1790
1799
  this.useTerminalNodes();
1791
1800
  const open = this.Fs.open.bind(this.Fs);
1792
1801
  this.Fs.open = (path, flags, mode) => {
1793
- const device = typeof path === "string" ? this.devicePath(path) : void 0;
1794
- if (device !== void 0 && TTY_PATH.test(device) && !this.terminalExists(device)) {
1802
+ const device2 = typeof path === "string" ? this.devicePath(path) : void 0;
1803
+ if (device2 !== void 0 && TTY_PATH.test(device2) && !this.terminalExists(device2)) {
1795
1804
  throw new this.Fs.ErrnoError(wasiErrno("ENOENT"));
1796
1805
  }
1797
1806
  const pty = this.openPty(open, path, flags, mode);
@@ -2709,15 +2718,15 @@ function describeInherited(Fs, sys, streams, livePath, actions = []) {
2709
2718
  return out;
2710
2719
  }
2711
2720
  function deviceOfStream(stream) {
2712
- const device = stream.path === void 0 ? void 0 : DEVICES[stream.path];
2713
- if (!device || stream.sliccKernelFd !== void 0) return void 0;
2721
+ const device2 = stream.path === void 0 ? void 0 : DEVICES[stream.path];
2722
+ if (!device2 || stream.sliccKernelFd !== void 0) return void 0;
2714
2723
  const access = ACCESS[stream.flags & O_ACCMODE2];
2715
- return { device, ...access ? { access } : {} };
2724
+ return { device: device2, ...access ? { access } : {} };
2716
2725
  }
2717
2726
  function inheritedSlot(fd, stream) {
2718
2727
  if (stream.sliccKernelFd === void 0) {
2719
- const device = deviceOfStream(stream);
2720
- return device ? { fd, ...device } : void 0;
2728
+ const device2 = deviceOfStream(stream);
2729
+ return device2 ? { fd, ...device2 } : void 0;
2721
2730
  }
2722
2731
  const flags = stream.sliccKernelSocket ? { flags: stream.flags } : {};
2723
2732
  return { fd, kernel: stream.sliccKernelFd, ...flags };
@@ -2893,8 +2902,8 @@ function createProcessKernel(deps) {
2893
2902
  if (!stream) return { none: true };
2894
2903
  promote?.(stream);
2895
2904
  if (stream.sliccKernelFd !== void 0) return { fd: stream.sliccKernelFd };
2896
- const device = deviceOfStream(stream);
2897
- if (device) return device;
2905
+ const device2 = deviceOfStream(stream);
2906
+ if (device2) return device2;
2898
2907
  return n === 0 ? { input: drain(Fs, stream) } : { capture: true };
2899
2908
  };
2900
2909
  const kernelWait = (pid, nohang, options = 0) => {
@@ -3831,8 +3840,8 @@ function wireKernelStdio(Fs, streams, sys) {
3831
3840
  const stream = Fs.getStream(fd);
3832
3841
  if (!stream) continue;
3833
3842
  const kind = sys?.kind?.(fd);
3834
- const device = kind === "device" ? sys?.device?.(fd) : void 0;
3835
- if (device && openDevice(Fs, fd, device)) continue;
3843
+ const device2 = kind === "device" ? sys?.device?.(fd) : void 0;
3844
+ if (device2 && openDevice(Fs, fd, device2)) continue;
3836
3845
  if (kind && PLACED.has(kind)) {
3837
3846
  const { flags } = stream;
3838
3847
  Fs.closeStream(fd);
@@ -3901,8 +3910,8 @@ async function runWasmProcess(init, port2, deps = {}) {
3901
3910
  }
3902
3911
  };
3903
3912
  const sys = kernelSys(transport);
3904
- const encoder3 = new TextEncoder();
3905
- const say = (fd) => (text) => sys.write(fd, encoder3.encode(`${text}
3913
+ const encoder4 = new TextEncoder();
3914
+ const say = (fd) => (text) => sys.write(fd, encoder4.encode(`${text}
3906
3915
  `));
3907
3916
  let ready;
3908
3917
  let failed2;
@@ -4301,7 +4310,7 @@ function cachingBridge(bridge, now = () => performance.now()) {
4301
4310
  return false;
4302
4311
  }
4303
4312
  },
4304
- writeFile: (p, bytes) => mutating(() => bridge.writeFile(p, bytes)),
4313
+ writeFile: (p, bytes, open) => mutating(() => bridge.writeFile(p, bytes, open)),
4305
4314
  mkdir: (p) => mutating(() => bridge.mkdir(p)),
4306
4315
  rm: (p) => mutating(() => bridge.rm(p)),
4307
4316
  rename: (from, to) => mutating(() => bridge.rename(from, to)),
@@ -4311,6 +4320,7 @@ function cachingBridge(bridge, now = () => performance.now()) {
4311
4320
  chmod: (p, mode) => mutating(() => bridge.chmod(p, mode)),
4312
4321
  utimes: (p, a, m) => mutating(() => bridge.utimes(p, a, m)),
4313
4322
  lutimes: (p, a, m) => mutating(() => bridge.lutimes(p, a, m)),
4323
+ ...bridge.hold ? { hold: bridge.hold.bind(bridge) } : {},
4314
4324
  ...bridge.pread && bridge.pwrite && bridge.truncate ? {
4315
4325
  pread: bridge.pread.bind(bridge),
4316
4326
  pwrite: (p, at, bytes, transfer) => mutating(() => bridge.pwrite?.(p, at, bytes, transfer)),
@@ -4455,7 +4465,7 @@ var init_wasi_files = __esm({
4455
4465
  if (this.ranged) this.ranged.flush();
4456
4466
  else if (!this.data) return;
4457
4467
  else if (this.whole || !this.fs.pwrite)
4458
- this.fs.writeFile(this.path, this.data.slice(0, this.length));
4468
+ this.fs.writeFile(this.path, this.data.slice(0, this.length), true);
4459
4469
  else this.fs.pwrite(this.path, this.from, this.data.slice(this.from, this.to), true);
4460
4470
  this.dirty = false;
4461
4471
  this.whole = false;
@@ -4606,14 +4616,14 @@ var init_wasi_fds = __esm({
4606
4616
  for (const fd of [0, 1, 2]) this.table.set(fd, kernelEntry2());
4607
4617
  const preopens = this.preopens(cwd, root);
4608
4618
  const top = 3 + preopens.length;
4609
- for (const { fd, kind, flags, device } of inherited) {
4619
+ for (const { fd, kind, flags, device: device2 } of inherited) {
4610
4620
  let at = fd;
4611
4621
  if (fd < top) {
4612
4622
  at = this.kernel.call({ op: "fd-dup", fd, min: top });
4613
4623
  this.kernel.sys.close(fd);
4614
4624
  }
4615
- if (device) {
4616
- this.table.set(at, deviceEntry(device));
4625
+ if (device2) {
4626
+ this.table.set(at, deviceEntry(device2));
4617
4627
  continue;
4618
4628
  }
4619
4629
  const nonblock = ((flags ?? 0) & O_NONBLOCK2) !== 0;
@@ -4828,7 +4838,10 @@ var init_wasi_fds = __esm({
4828
4838
  this.table.set(fd, { type: "kernel", kind: "file", nonblock: false, append: e.file.append });
4829
4839
  }
4830
4840
  for (const file of promoted.keys()) {
4831
- if (--file.buffer.opens <= 0) this.buffers.delete(file.path);
4841
+ if (--file.buffer.opens <= 0) {
4842
+ this.buffers.delete(file.path);
4843
+ this.letGo(file.buffer);
4844
+ }
4832
4845
  }
4833
4846
  }
4834
4847
  snapshot() {
@@ -4896,9 +4909,12 @@ var init_wasi_fds = __esm({
4896
4909
  if (e.type !== "file" || --e.file.refs > 0) return;
4897
4910
  const { buffer } = e.file;
4898
4911
  buffer.flush();
4899
- if (--buffer.opens === 0 && this.buffers.get(buffer.path) === buffer) {
4900
- this.buffers.delete(buffer.path);
4901
- }
4912
+ if (--buffer.opens > 0) return;
4913
+ if (this.buffers.get(buffer.path) === buffer) this.buffers.delete(buffer.path);
4914
+ this.letGo(buffer);
4915
+ }
4916
+ letGo(buffer) {
4917
+ this.fs.hold?.(buffer.path, false, true);
4902
4918
  }
4903
4919
  kind(fd, e) {
4904
4920
  if (!e.kind) {
@@ -4955,8 +4971,8 @@ var init_wasi_fds = __esm({
4955
4971
  return resolveUnder(this.dir(dirfd).path, path);
4956
4972
  }
4957
4973
  open(path, oflags, rights, fdflags) {
4958
- const device = deviceOf(path);
4959
- if (device) return this.install({ type: "device", device });
4974
+ const device2 = deviceOf(path);
4975
+ if (device2) return this.install({ type: "device", device: device2 });
4960
4976
  if (path === "/dev/tty" || /^\/dev\/tty\d+$/.test(path)) {
4961
4977
  const fd = this.kernel.sys.openTty?.(path === "/dev/tty" ? void 0 : path);
4962
4978
  if (fd === void 0) throw new WasiError("ENXIO");
@@ -4989,6 +5005,7 @@ var init_wasi_fds = __esm({
4989
5005
  const ranged = st.ranged ? st.size : void 0;
4990
5006
  buffer = new FileBuffer(this.fs, path, empty, st.maxFile, ranged, st.version);
4991
5007
  this.buffers.set(path, buffer);
5008
+ this.fs.hold?.(path, true, true);
4992
5009
  }
4993
5010
  buffer.opens++;
4994
5011
  return new LocalFile(buffer, readable, writable, (fdflags & FDFLAGS.APPEND) !== 0);
@@ -5095,11 +5112,11 @@ var init_wasi_memory = __esm({
5095
5112
  return at;
5096
5113
  }
5097
5114
  putStrings(list, ptrs, buf) {
5098
- const encoder3 = new TextEncoder();
5115
+ const encoder4 = new TextEncoder();
5099
5116
  const v = this.view();
5100
5117
  let at = buf;
5101
5118
  list.forEach((s, i) => {
5102
- const b = encoder3.encode(s);
5119
+ const b = encoder4.encode(s);
5103
5120
  v.setUint32(ptrs + i * 4, at, true);
5104
5121
  this.bytes(at, b.length).set(b);
5105
5122
  v.setUint8(at + b.length, 0);
@@ -5107,12 +5124,12 @@ var init_wasi_memory = __esm({
5107
5124
  });
5108
5125
  }
5109
5126
  putSizes(list, countPtr, sizePtr) {
5110
- const encoder3 = new TextEncoder();
5127
+ const encoder4 = new TextEncoder();
5111
5128
  const v = this.view();
5112
5129
  v.setUint32(countPtr, list.length, true);
5113
5130
  v.setUint32(
5114
5131
  sizePtr,
5115
- list.reduce((n, s) => n + encoder3.encode(s).length + 1, 0),
5132
+ list.reduce((n, s) => n + encoder4.encode(s).length + 1, 0),
5116
5133
  true
5117
5134
  );
5118
5135
  }
@@ -8254,6 +8271,320 @@ var init_js_kernel = __esm({
8254
8271
  }
8255
8272
  });
8256
8273
 
8274
+ // src/process/js/js-io.ts
8275
+ function typeOf(info) {
8276
+ if (info.meta && "dir" in info.meta) return "directory";
8277
+ if (info.meta && "device" in info.meta) return "device";
8278
+ if (info.tty || info.kind === "tty") return "tty";
8279
+ if (info.kind === "socket") return "socket";
8280
+ return info.kind === "file" ? "file" : "pipe";
8281
+ }
8282
+ function device(info) {
8283
+ return info.meta && "device" in info.meta ? info.meta : void 0;
8284
+ }
8285
+ function readDevice(info, max, random) {
8286
+ if (typeOf(info) === "directory") throw new JsCallError("EISDIR", "read");
8287
+ const dev = device(info);
8288
+ if (!dev) return void 0;
8289
+ if (dev.access === "write") throw new JsCallError("EBADF", "read");
8290
+ if (dev.device === "null") return new Uint8Array(0);
8291
+ const out = new Uint8Array(Math.min(max, CHUNK));
8292
+ if (dev.device === "urandom") random(out);
8293
+ return out;
8294
+ }
8295
+ function writeDevice(info) {
8296
+ if (typeOf(info) === "directory") throw new JsCallError("EISDIR", "write");
8297
+ const dev = device(info);
8298
+ if (!dev) return false;
8299
+ if (dev.access === "read") throw new JsCallError("EBADF", "write");
8300
+ if (dev.device === "full") throw new JsCallError("ENOSPC", "write");
8301
+ return true;
8302
+ }
8303
+ function brokenPipe(err, info) {
8304
+ return err instanceof JsCallError && err.code === "EPIPE" && typeOf(info) !== "socket";
8305
+ }
8306
+ function written(r, fallback) {
8307
+ return r.ok && r.kind === "json" && typeof r.json === "number" ? r.json : fallback;
8308
+ }
8309
+ function joined(parts, length) {
8310
+ if (parts.length === 1) return parts[0];
8311
+ const out = new Uint8Array(length);
8312
+ let at = 0;
8313
+ for (const part of parts) {
8314
+ out.set(part, at);
8315
+ at += part.length;
8316
+ }
8317
+ return out;
8318
+ }
8319
+ function fileWrite(fd, append, offset, body) {
8320
+ return append ? { op: "fd-write", fd, body } : { op: "fd-pwrite", fd, offset, body };
8321
+ }
8322
+ function isExclusive(o) {
8323
+ return o.create === true && o.exclusive === true;
8324
+ }
8325
+ function absent(err) {
8326
+ if (err instanceof JsCallError && err.code === "ENOENT") return void 0;
8327
+ throw err;
8328
+ }
8329
+ function checkOpen(abs, o, existing) {
8330
+ if (existing && isExclusive(o)) throw new JsCallError("EEXIST", abs);
8331
+ if (!existing && !o.create) throw new JsCallError("ENOENT", abs);
8332
+ if (existing?.isDirectory) throw new JsCallError("EISDIR", abs);
8333
+ }
8334
+ function flagsOf(o) {
8335
+ const write = o.write || o.append || o.truncate;
8336
+ const access = write ? o.read ? O_RDWR6 : O_WRONLY6 : 0;
8337
+ return access | (o.append ? O_APPEND3 : 0);
8338
+ }
8339
+ function openRequest(abs, o) {
8340
+ return {
8341
+ op: "fd-open-vfs",
8342
+ path: abs,
8343
+ flags: flagsOf(o),
8344
+ position: 0,
8345
+ ...isExclusive(o) ? { exclusive: true } : o.create ? { create: true } : { existing: true },
8346
+ ...o.truncate ? { truncate: true } : {}
8347
+ };
8348
+ }
8349
+ function index(n, what) {
8350
+ if (!Number.isSafeInteger(n) || n < 0) throw new JsCallError("EINVAL", what);
8351
+ }
8352
+ var CHUNK, MAX_IO, O_WRONLY6, O_RDWR6, O_APPEND3;
8353
+ var init_js_io = __esm({
8354
+ "src/process/js/js-io.ts"() {
8355
+ "use strict";
8356
+ init_js_kernel();
8357
+ CHUNK = 64 * 1024;
8358
+ MAX_IO = 1024 * 1024;
8359
+ O_WRONLY6 = 1;
8360
+ O_RDWR6 = 2;
8361
+ O_APPEND3 = 1024;
8362
+ }
8363
+ });
8364
+
8365
+ // src/process/js/js-sync.ts
8366
+ function laneOf(lane) {
8367
+ if (!lane) return () => ({ ok: false, errno: "ENOSYS", message: "no sync lane" });
8368
+ const transport = createSyncSabTransport(lane.sab, lane.port);
8369
+ return (req) => transport.call(req, Number.POSITIVE_INFINITY, req.op);
8370
+ }
8371
+ function syncOps(kernel, shared) {
8372
+ const { infos, handles, resolve } = shared;
8373
+ const info = (fd) => {
8374
+ const known = infos.get(fd);
8375
+ if (known) return known;
8376
+ const got = kernel.json({ op: "fd-info", fd });
8377
+ infos.set(fd, got);
8378
+ return got;
8379
+ };
8380
+ const read = (fd, max = CHUNK) => {
8381
+ index(max, "read");
8382
+ const emulated = readDevice(info(fd), max, shared.random);
8383
+ if (emulated) return emulated;
8384
+ const r = kernel.blocking({ op: "fd-read", fd, max: Math.min(max, MAX_IO) });
8385
+ return r.ok && r.kind === "bytes" ? r.bytes : new Uint8Array(0);
8386
+ };
8387
+ const write = (fd, data) => {
8388
+ const bytes = typeof data === "string" ? encoder2.encode(data) : data;
8389
+ const i = info(fd);
8390
+ if (writeDevice(i)) return;
8391
+ let at = 0;
8392
+ while (at < bytes.length) {
8393
+ const body = bytes.subarray(at, at + MAX_IO);
8394
+ try {
8395
+ at += written(kernel.blocking({ op: "fd-write", fd, body }), body.length);
8396
+ } catch (err) {
8397
+ if (brokenPipe(err, i)) kernel.call({ op: "proc-kill", pid: shared.pid, sig: SIG.PIPE });
8398
+ throw err;
8399
+ }
8400
+ }
8401
+ };
8402
+ const statOf = (op, path) => {
8403
+ const abs = resolve(path);
8404
+ kernel.call({ op: "fd-path-flush", path: abs });
8405
+ const s = parseSyncFsStat(kernel.json({ op, path: abs }));
8406
+ if (!s) throw new JsCallError("EIO", op);
8407
+ return s;
8408
+ };
8409
+ const open = (path, options = {}) => {
8410
+ const abs = resolve(path);
8411
+ let existing;
8412
+ try {
8413
+ existing = statOf(isExclusive(options) ? "lstat" : "stat", abs);
8414
+ } catch (err) {
8415
+ existing = absent(err);
8416
+ }
8417
+ checkOpen(abs, options, existing);
8418
+ const fd = kernel.json(openRequest(abs, options));
8419
+ try {
8420
+ kernel.call({ op: "fd-vfs-stat", fd });
8421
+ } catch (err) {
8422
+ kernel.raw({ op: "fd-close", fd });
8423
+ throw err;
8424
+ }
8425
+ infos.set(fd, { kind: "file" });
8426
+ const handle = syncFile(kernel, fd, abs, options.append === true, () => {
8427
+ infos.delete(fd);
8428
+ handles.delete(fd);
8429
+ });
8430
+ handles.set(fd, handle.invalidate);
8431
+ return handle.file;
8432
+ };
8433
+ return {
8434
+ read,
8435
+ write,
8436
+ close(fd) {
8437
+ handles.get(fd)?.();
8438
+ handles.delete(fd);
8439
+ infos.delete(fd);
8440
+ kernel.call({ op: "fd-close", fd });
8441
+ },
8442
+ open,
8443
+ fs: syncPathOps(kernel, resolve, statOf, open)
8444
+ };
8445
+ }
8446
+ function syncFile(kernel, fd, path, append, forget) {
8447
+ let open = true;
8448
+ const live = () => {
8449
+ if (!open) throw new JsCallError("EBADF", path);
8450
+ };
8451
+ const file = {
8452
+ fd,
8453
+ path,
8454
+ size() {
8455
+ live();
8456
+ return kernel.json({ op: "fd-vfs-stat", fd }).size;
8457
+ },
8458
+ read(position, length) {
8459
+ index(position, "read");
8460
+ index(length, "read");
8461
+ const parts = [];
8462
+ let got = 0;
8463
+ do {
8464
+ live();
8465
+ const max = Math.min(length - got, MAX_IO);
8466
+ if (max <= 0) break;
8467
+ const chunk = kernel.bytes({ op: "fd-pread", fd, offset: position + got, max });
8468
+ if (chunk.length === 0) break;
8469
+ parts.push(chunk);
8470
+ got += chunk.length;
8471
+ } while (got < length);
8472
+ return joined(parts, got);
8473
+ },
8474
+ write(position, data) {
8475
+ index(position, "write");
8476
+ let at = 0;
8477
+ do {
8478
+ live();
8479
+ if (at >= data.length) break;
8480
+ const body = data.subarray(at, at + MAX_IO);
8481
+ const n = kernel.json(fileWrite(fd, append, position + at, body));
8482
+ if (!(n > 0)) throw new JsCallError("EIO", "write");
8483
+ at += n;
8484
+ } while (at < data.length);
8485
+ return at;
8486
+ },
8487
+ truncate(size) {
8488
+ live();
8489
+ index(size, "truncate");
8490
+ kernel.call({ op: "fd-resize", fd, size });
8491
+ },
8492
+ sync() {
8493
+ live();
8494
+ kernel.call({ op: "fd-flush", fd });
8495
+ },
8496
+ close() {
8497
+ live();
8498
+ open = false;
8499
+ forget();
8500
+ kernel.call({ op: "fd-close", fd });
8501
+ }
8502
+ };
8503
+ return {
8504
+ file,
8505
+ invalidate: () => {
8506
+ open = false;
8507
+ }
8508
+ };
8509
+ }
8510
+ function syncPathOps(kernel, resolve, statOf, open) {
8511
+ return {
8512
+ stat: (path) => statOf("stat", path),
8513
+ lstat: (path) => statOf("lstat", path),
8514
+ exists: (path) => kernel.json({ op: "exists", path: resolve(path) }) === true,
8515
+ readdir: (path) => kernel.json({ op: "readdir", path: resolve(path) }),
8516
+ mkdir: (path) => void kernel.call({ op: "mkdir", path: resolve(path) }),
8517
+ rm: (path) => void kernel.call({ op: "rm", path: resolve(path) }),
8518
+ unlink: (path) => void kernel.call({ op: "unlink", path: resolve(path) }),
8519
+ rename: (from, to) => void kernel.call({ op: "rename", path: resolve(from), arg2: resolve(to) }),
8520
+ symlink: (target, path) => void kernel.call({ op: "symlink", path: resolve(path), arg2: target }),
8521
+ readlink: (path) => String(kernel.json({ op: "readlink", path: resolve(path) })),
8522
+ readFile(path) {
8523
+ const abs = resolve(path);
8524
+ kernel.call({ op: "fd-path-flush", path: abs });
8525
+ return kernel.bytes({ op: "read", path: abs });
8526
+ },
8527
+ writeFile(path, data) {
8528
+ const file = open(path, { write: true, create: true, truncate: true });
8529
+ try {
8530
+ file.write(0, typeof data === "string" ? encoder2.encode(data) : data);
8531
+ } finally {
8532
+ file.close();
8533
+ }
8534
+ }
8535
+ };
8536
+ }
8537
+ var encoder2, JsSyncKernel;
8538
+ var init_js_sync = __esm({
8539
+ "src/process/js/js-sync.ts"() {
8540
+ "use strict";
8541
+ init_signals();
8542
+ init_sync_fs_wire();
8543
+ init_sync_sab_bridge();
8544
+ init_js_io();
8545
+ init_js_kernel();
8546
+ encoder2 = new TextEncoder();
8547
+ JsSyncKernel = class {
8548
+ lane;
8549
+ kernel;
8550
+ unwind;
8551
+ constructor(lane, kernel, unwind = () => {
8552
+ }) {
8553
+ this.lane = lane;
8554
+ this.kernel = kernel;
8555
+ this.unwind = unwind;
8556
+ }
8557
+ raw(req) {
8558
+ this.unwind();
8559
+ const result = this.lane(req);
8560
+ this.kernel.deliver();
8561
+ this.unwind();
8562
+ return result;
8563
+ }
8564
+ call(req) {
8565
+ const result = this.raw(req);
8566
+ if (!result.ok) throw new JsCallError(result.errno, req.op);
8567
+ return result;
8568
+ }
8569
+ json(req) {
8570
+ const result = this.call(req);
8571
+ return result.ok && result.kind === "json" ? result.json : void 0;
8572
+ }
8573
+ bytes(req) {
8574
+ const result = this.call(req);
8575
+ return result.ok && result.kind === "bytes" ? result.bytes : new Uint8Array(0);
8576
+ }
8577
+ blocking(req) {
8578
+ for (; ; ) {
8579
+ const result = this.raw(req);
8580
+ if (result.ok) return result;
8581
+ if (result.errno !== "EINTR") throw new JsCallError(result.errno, req.op);
8582
+ }
8583
+ }
8584
+ };
8585
+ }
8586
+ });
8587
+
8257
8588
  // src/process/js/js-context.ts
8258
8589
  function identityOf(answer2, fallback) {
8259
8590
  const id = answer2;
@@ -8280,18 +8611,6 @@ function resolvePath(cwd, path) {
8280
8611
  }
8281
8612
  return `/${parts.join("/")}`;
8282
8613
  }
8283
- function typeOf(info) {
8284
- if (info.meta && "dir" in info.meta) return "directory";
8285
- if (info.meta && "device" in info.meta) return "device";
8286
- if (info.tty || info.kind === "tty") return "tty";
8287
- if (info.kind === "socket") return "socket";
8288
- return info.kind === "file" ? "file" : "pipe";
8289
- }
8290
- function flagsOf(o) {
8291
- const write = o.write || o.append || o.truncate;
8292
- const access = write ? o.read ? O_RDWR6 : O_WRONLY6 : 0;
8293
- return access | (o.append ? O_APPEND3 : 0);
8294
- }
8295
8614
  function createContext(o) {
8296
8615
  const { kernel } = o;
8297
8616
  const infos = /* @__PURE__ */ new Map();
@@ -8299,10 +8618,15 @@ function createContext(o) {
8299
8618
  const pending = /* @__PURE__ */ new Set();
8300
8619
  const random = o.random ?? ((bytes) => void crypto.getRandomValues(bytes));
8301
8620
  const resolve = (path) => resolvePath(o.cwd, path);
8621
+ let exiting;
8302
8622
  const exit = (code2 = 0) => {
8623
+ exiting ??= code2;
8303
8624
  o.exit(code2);
8304
8625
  throw new JsExit(code2);
8305
8626
  };
8627
+ const unwind = () => {
8628
+ if (exiting !== void 0) throw new JsExit(exiting);
8629
+ };
8306
8630
  const info = async (fd) => {
8307
8631
  const known = infos.get(fd);
8308
8632
  if (known) return known;
@@ -8310,48 +8634,30 @@ function createContext(o) {
8310
8634
  infos.set(fd, got);
8311
8635
  return got;
8312
8636
  };
8313
- const device = (i) => i.meta && "device" in i.meta ? i.meta : void 0;
8314
8637
  const read = async (fd, max = CHUNK) => {
8315
8638
  index(max, "read");
8316
- const i = await info(fd);
8317
- if (typeOf(i) === "directory") throw new JsCallError("EISDIR", "read");
8318
- const dev = device(i);
8319
- if (dev) {
8320
- if (dev.access === "write") throw new JsCallError("EBADF", "read");
8321
- if (dev.device === "null") return new Uint8Array(0);
8322
- const out = new Uint8Array(Math.min(max, CHUNK));
8323
- if (dev.device === "urandom") random(out);
8324
- return out;
8325
- }
8639
+ const emulated = readDevice(await info(fd), max, random);
8640
+ if (emulated) return emulated;
8326
8641
  const r = await kernel.blocking({ op: "fd-read", fd, max: Math.min(max, MAX_IO) });
8327
8642
  return r.ok && r.kind === "bytes" ? r.bytes : new Uint8Array(0);
8328
8643
  };
8329
8644
  const writeAll = async (fd, data) => {
8330
8645
  const i = await info(fd);
8331
- if (typeOf(i) === "directory") throw new JsCallError("EISDIR", "write");
8332
- const dev = device(i);
8333
- if (dev) {
8334
- if (dev.access === "read") throw new JsCallError("EBADF", "write");
8335
- if (dev.device === "full") throw new JsCallError("ENOSPC", "write");
8336
- return;
8337
- }
8646
+ if (writeDevice(i)) return;
8338
8647
  let at = 0;
8339
8648
  while (at < data.length) {
8340
8649
  const body = data.subarray(at, at + MAX_IO);
8341
8650
  try {
8342
8651
  const r = await kernel.blocking({ op: "fd-write", fd, body });
8343
- at += r.ok && r.kind === "json" && typeof r.json === "number" ? r.json : body.length;
8652
+ at += written(r, body.length);
8344
8653
  } catch (err) {
8345
- const broken = err instanceof JsCallError && err.code === "EPIPE";
8346
- if (broken && typeOf(i) !== "socket") {
8347
- await kernel.call({ op: "proc-kill", pid: o.pid, sig: SIG.PIPE });
8348
- }
8654
+ if (brokenPipe(err, i)) await kernel.call({ op: "proc-kill", pid: o.pid, sig: SIG.PIPE });
8349
8655
  throw err;
8350
8656
  }
8351
8657
  }
8352
8658
  };
8353
8659
  const write = (fd, data) => {
8354
- const bytes = typeof data === "string" ? encoder2.encode(data) : data;
8660
+ const bytes = typeof data === "string" ? encoder3.encode(data) : data;
8355
8661
  let settle;
8356
8662
  const settled = new Promise((resolve2) => settle = resolve2);
8357
8663
  pending.add(settled);
@@ -8374,22 +8680,9 @@ function createContext(o) {
8374
8680
  };
8375
8681
  const open = async (path, options = {}) => {
8376
8682
  const abs = resolve(path);
8377
- const exclusive = options.create === true && options.exclusive === true;
8378
- const existing = await statOf(exclusive ? "lstat" : "stat", abs).catch((err) => {
8379
- if (err instanceof JsCallError && err.code === "ENOENT") return void 0;
8380
- throw err;
8381
- });
8382
- if (existing && exclusive) throw new JsCallError("EEXIST", abs);
8383
- if (!existing && !options.create) throw new JsCallError("ENOENT", abs);
8384
- if (existing?.isDirectory) throw new JsCallError("EISDIR", abs);
8385
- const fd = await kernel.json({
8386
- op: "fd-open-vfs",
8387
- path: abs,
8388
- flags: flagsOf(options),
8389
- position: 0,
8390
- ...exclusive ? { exclusive: true } : options.create ? { create: true } : { existing: true },
8391
- ...options.truncate ? { truncate: true } : {}
8392
- });
8683
+ const existing = await statOf(isExclusive(options) ? "lstat" : "stat", abs).catch(absent);
8684
+ checkOpen(abs, options, existing);
8685
+ const fd = await kernel.json(openRequest(abs, options));
8393
8686
  try {
8394
8687
  await kernel.call({ op: "fd-vfs-stat", fd });
8395
8688
  } catch (err) {
@@ -8405,6 +8698,13 @@ function createContext(o) {
8405
8698
  return handle.file;
8406
8699
  };
8407
8700
  const fs = pathOps(kernel, resolve, statOf, open);
8701
+ const sync = syncOps(new JsSyncKernel(o.lane ?? laneOf(void 0), kernel, unwind), {
8702
+ pid: o.pid,
8703
+ resolve,
8704
+ random,
8705
+ infos,
8706
+ handles
8707
+ });
8408
8708
  const ctx = {
8409
8709
  argv: o.argv,
8410
8710
  env: o.env,
@@ -8446,6 +8746,7 @@ function createContext(o) {
8446
8746
  ignore: async (signal) => kernel.setHandler(signalNumber(signal), "ignore"),
8447
8747
  reset: async (signal) => kernel.setHandler(signalNumber(signal), "default")
8448
8748
  },
8749
+ sync,
8449
8750
  exit
8450
8751
  };
8451
8752
  const drain2 = async () => {
@@ -8484,14 +8785,7 @@ function fileHandle(kernel, fd, path, append, forget) {
8484
8785
  parts.push(chunk);
8485
8786
  got += chunk.length;
8486
8787
  } while (got < length);
8487
- if (parts.length === 1) return parts[0];
8488
- const out = new Uint8Array(got);
8489
- let at = 0;
8490
- for (const part of parts) {
8491
- out.set(part, at);
8492
- at += part.length;
8493
- }
8494
- return out;
8788
+ return joined(parts, got);
8495
8789
  },
8496
8790
  async write(position, data) {
8497
8791
  index(position, "write");
@@ -8500,9 +8794,7 @@ function fileHandle(kernel, fd, path, append, forget) {
8500
8794
  live();
8501
8795
  if (at >= data.length) break;
8502
8796
  const body = data.subarray(at, at + MAX_IO);
8503
- const n = await kernel.json(
8504
- append ? { op: "fd-write", fd, body } : { op: "fd-pwrite", fd, offset: position + at, body }
8505
- );
8797
+ const n = await kernel.json(fileWrite(fd, append, position + at, body));
8506
8798
  if (!(n > 0)) throw new JsCallError("EIO", "write");
8507
8799
  at += n;
8508
8800
  } while (at < data.length);
@@ -8531,9 +8823,6 @@ function fileHandle(kernel, fd, path, append, forget) {
8531
8823
  }
8532
8824
  };
8533
8825
  }
8534
- function index(n, what) {
8535
- if (!Number.isSafeInteger(n) || n < 0) throw new JsCallError("EINVAL", what);
8536
- }
8537
8826
  function pathOps(kernel, resolve, statOf, open) {
8538
8827
  return {
8539
8828
  stat: (path) => statOf("stat", path),
@@ -8554,20 +8843,22 @@ function pathOps(kernel, resolve, statOf, open) {
8554
8843
  async writeFile(path, data) {
8555
8844
  const file = await open(path, { write: true, create: true, truncate: true });
8556
8845
  try {
8557
- await file.write(0, typeof data === "string" ? encoder2.encode(data) : data);
8846
+ await file.write(0, typeof data === "string" ? encoder3.encode(data) : data);
8558
8847
  } finally {
8559
8848
  await file.close();
8560
8849
  }
8561
8850
  }
8562
8851
  };
8563
8852
  }
8564
- var JsExit, CHUNK, MAX_IO, O_WRONLY6, O_RDWR6, O_APPEND3, encoder2;
8853
+ var JsExit, encoder3;
8565
8854
  var init_js_context = __esm({
8566
8855
  "src/process/js/js-context.ts"() {
8567
8856
  "use strict";
8568
8857
  init_signals();
8569
8858
  init_sync_fs_wire();
8859
+ init_js_io();
8570
8860
  init_js_kernel();
8861
+ init_js_sync();
8571
8862
  JsExit = class extends Error {
8572
8863
  status;
8573
8864
  constructor(status2) {
@@ -8576,12 +8867,7 @@ var init_js_context = __esm({
8576
8867
  this.status = status2;
8577
8868
  }
8578
8869
  };
8579
- CHUNK = 64 * 1024;
8580
- MAX_IO = 1024 * 1024;
8581
- O_WRONLY6 = 1;
8582
- O_RDWR6 = 2;
8583
- O_APPEND3 = 1024;
8584
- encoder2 = new TextEncoder();
8870
+ encoder3 = new TextEncoder();
8585
8871
  }
8586
8872
  });
8587
8873
 
@@ -8709,7 +8995,8 @@ async function runJsProcess(init, port2, deps = {}) {
8709
8995
  pid: id.pid,
8710
8996
  ppid: id.ppid,
8711
8997
  cwd: init.cwd,
8712
- exit: (status3) => exited(statusOf(status3))
8998
+ exit: (status3) => exited(statusOf(status3)),
8999
+ lane: laneOf(init.lane)
8713
9000
  });
8714
9001
  const say = (text) => ctx.write(2, `${init.argv0}: ${text}
8715
9002
  `).catch(() => void 0);
@@ -8747,6 +9034,7 @@ var init_js_runtime = __esm({
8747
9034
  init_async_sab();
8748
9035
  init_js_context();
8749
9036
  init_js_kernel();
9037
+ init_js_sync();
8750
9038
  init_lockdown();
8751
9039
  NOT_RUNNABLE = 126;
8752
9040
  }