@ai-ecoverse/slicc-kernel 1.67.1 → 1.69.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.
@@ -1164,6 +1164,34 @@ var init_cred = __esm({
1164
1164
  }
1165
1165
  });
1166
1166
 
1167
+ // src/kernel/pipe.ts
1168
+ var PIPE_CAPACITY;
1169
+ var init_pipe = __esm({
1170
+ "src/kernel/pipe.ts"() {
1171
+ "use strict";
1172
+ PIPE_CAPACITY = 64 * 1024;
1173
+ }
1174
+ });
1175
+
1176
+ // src/kernel/fd-table.ts
1177
+ function deviceAt(path) {
1178
+ return DEVICE_PATHS.get(path);
1179
+ }
1180
+ var DEVICE_PATHS;
1181
+ var init_fd_table = __esm({
1182
+ "src/kernel/fd-table.ts"() {
1183
+ "use strict";
1184
+ init_pipe();
1185
+ DEVICE_PATHS = /* @__PURE__ */ new Map([
1186
+ ["/dev/null", "null"],
1187
+ ["/dev/zero", "zero"],
1188
+ ["/dev/full", "full"],
1189
+ ["/dev/urandom", "urandom"],
1190
+ ["/dev/random", "urandom"]
1191
+ ]);
1192
+ }
1193
+ });
1194
+
1167
1195
  // src/realm/sync-fs-wire.ts
1168
1196
  function parseSyncFsUsage(json2) {
1169
1197
  const u = json2;
@@ -1247,7 +1275,7 @@ function stdioAlias(path) {
1247
1275
  return m[1] ? 0 : m[2] ? 1 : m[3] ? 2 : Number(m[4]);
1248
1276
  }
1249
1277
  function deviceOf(path) {
1250
- return DEVICES[path];
1278
+ return deviceAt(path);
1251
1279
  }
1252
1280
  function within(path, root) {
1253
1281
  return path === root || path.startsWith(root === "/" ? "/" : `${root}/`);
@@ -1315,10 +1343,11 @@ function promoteRequest(fd, f, handed) {
1315
1343
  ...f.buffer.handle !== void 0 ? { handle: f.buffer.handle } : {}
1316
1344
  };
1317
1345
  }
1318
- var SYNTHETIC_DIRS, O_NONBLOCK, O_WRONLY, O_RDWR, O_APPEND, DEVICES, WasiFds, GEN;
1346
+ var SYNTHETIC_DIRS, O_NONBLOCK, O_WRONLY, O_RDWR, O_APPEND, SEALED_PATH, WasiFds, GEN;
1319
1347
  var init_wasi_fds = __esm({
1320
1348
  "src/process/wasi/wasi-fds.ts"() {
1321
1349
  "use strict";
1350
+ init_fd_table();
1322
1351
  init_sync_fs_wire();
1323
1352
  init_wasi_abi();
1324
1353
  init_wasi_files();
@@ -1327,13 +1356,7 @@ var init_wasi_fds = __esm({
1327
1356
  O_WRONLY = 1;
1328
1357
  O_RDWR = 2;
1329
1358
  O_APPEND = 1024;
1330
- DEVICES = {
1331
- "/dev/null": "null",
1332
- "/dev/zero": "zero",
1333
- "/dev/full": "full",
1334
- "/dev/urandom": "urandom",
1335
- "/dev/random": "urandom"
1336
- };
1359
+ SEALED_PATH = "/dev/sealed";
1337
1360
  WasiFds = class {
1338
1361
  table = /* @__PURE__ */ new Map();
1339
1362
  buffers = /* @__PURE__ */ new Map();
@@ -1798,16 +1821,30 @@ var init_wasi_fds = __esm({
1798
1821
  const joined2 = path.startsWith("/") ? path : `${this.dir(dirfd).path}/${path}`;
1799
1822
  return joined2.split("/").includes("..") ? physical(this.fs, joined2) : normalize(joined2);
1800
1823
  }
1824
+ openKernelDevice(path, oflags, fdflags) {
1825
+ const { openSealed, openTty } = this.kernel.sys;
1826
+ const nonblock = (fdflags & FDFLAGS.NONBLOCK) !== 0;
1827
+ let fd;
1828
+ let kind;
1829
+ if (path === SEALED_PATH && openSealed) {
1830
+ if (oflags & OFLAGS.DIRECTORY) throw new WasiError("ENOTDIR");
1831
+ if (oflags & OFLAGS.CREAT && oflags & OFLAGS.EXCL) throw new WasiError("EEXIST");
1832
+ fd = openSealed.call(this.kernel.sys);
1833
+ kind = "sealed";
1834
+ } else if (path === "/dev/tty" || /^\/dev\/tty\d+$/.test(path)) {
1835
+ fd = openTty?.call(this.kernel.sys, path === "/dev/tty" ? void 0 : path);
1836
+ if (fd === void 0) throw new WasiError("ENXIO");
1837
+ kind = "tty";
1838
+ } else return void 0;
1839
+ this.adopt(fd, kind, nonblock);
1840
+ this.bump();
1841
+ return fd;
1842
+ }
1801
1843
  open(path, oflags, rights, fdflags) {
1802
1844
  const device2 = deviceOf(path);
1803
1845
  if (device2) return this.install({ type: "device", device: device2 });
1804
- if (path === "/dev/tty" || /^\/dev\/tty\d+$/.test(path)) {
1805
- const fd = this.kernel.sys.openTty?.(path === "/dev/tty" ? void 0 : path);
1806
- if (fd === void 0) throw new WasiError("ENXIO");
1807
- this.table.set(fd, { ...kernelEntry(), kind: "tty" });
1808
- this.bump();
1809
- return fd;
1810
- }
1846
+ const kernelDevice = this.openKernelDevice(path, oflags, fdflags);
1847
+ if (kernelDevice !== void 0) return kernelDevice;
1811
1848
  const alias = stdioAlias(path);
1812
1849
  if (alias !== void 0) return this.reopen(alias);
1813
1850
  const exclusive = (oflags & OFLAGS.CREAT) !== 0 && (oflags & OFLAGS.EXCL) !== 0;
@@ -2248,6 +2285,7 @@ function filestatOf(path, s) {
2248
2285
  function kernelFiletype(kind) {
2249
2286
  switch (kind) {
2250
2287
  case "tty":
2288
+ case "sealed":
2251
2289
  return { filetype: FILETYPE.CHARACTER_DEVICE, seeks: false };
2252
2290
  case "device":
2253
2291
  return { filetype: FILETYPE.CHARACTER_DEVICE, seeks: true };
@@ -2288,7 +2326,7 @@ function wrap(table) {
2288
2326
  }
2289
2327
  return out;
2290
2328
  }
2291
- var WasiExit, IDS, NS_PER_MS, AT_SYMLINK_NOFOLLOW, AT_EACCESS, ROOT_IDS, GONE, S_IFIFO, DEFAULT_UMASK, MONOTONIC_BASE, MAX_READ, SIGPIPE_EXIT, WasiHost;
2329
+ var WasiExit, IDS, NS_PER_MS, AT_SYMLINK_NOFOLLOW, AT_EACCESS, ROOT_IDS, GONE, S_IFIFO, DEFAULT_UMASK, MONOTONIC_BASE, MAX_READ, SIGPIPE_EXIT, SEALED_MODE, WasiHost;
2292
2330
  var init_wasi_host = __esm({
2293
2331
  "src/process/wasi/wasi-host.ts"() {
2294
2332
  "use strict";
@@ -2318,6 +2356,7 @@ var init_wasi_host = __esm({
2318
2356
  MONOTONIC_BASE = BigInt(Math.round(performance.timeOrigin)) * NS_PER_MS;
2319
2357
  MAX_READ = 1024 * 1024;
2320
2358
  SIGPIPE_EXIT = 141;
2359
+ SEALED_MODE = 8630;
2321
2360
  WasiHost = class {
2322
2361
  mem = new WasiMemory();
2323
2362
  fds;
@@ -2403,7 +2442,9 @@ var init_wasi_host = __esm({
2403
2442
  const fdOwned = (fd) => {
2404
2443
  const e = fds.get(fd);
2405
2444
  if (e.type === "device") return ROOT_IDS;
2406
- if (e.type === "kernel" && fds.kind(fd, e) !== "file") return void 0;
2445
+ const kind = e.type === "kernel" ? fds.kind(fd, e) : "file";
2446
+ if (kind === "sealed") return ROOT_IDS;
2447
+ if (kind !== "file") return void 0;
2407
2448
  try {
2408
2449
  return this.o.fs.stat(pathOf(fd));
2409
2450
  } catch (err) {
@@ -2412,7 +2453,7 @@ var init_wasi_host = __esm({
2412
2453
  }
2413
2454
  };
2414
2455
  const pathOwned = (path, follow2) => {
2415
- if (deviceOf(path)) return ROOT_IDS;
2456
+ if (this.synthetic(path)) return ROOT_IDS;
2416
2457
  return follow2 ? this.o.fs.stat(path) : this.o.fs.lstat(path);
2417
2458
  };
2418
2459
  return wrap({
@@ -2427,11 +2468,11 @@ var init_wasi_host = __esm({
2427
2468
  this.writeFilestat(statOut, this.fdFilestat(fd));
2428
2469
  owner(fdOwned(fd), out);
2429
2470
  },
2430
- path_filestat_owner: (dirfd, lookup, p, l, statOut, out) => {
2471
+ path_filestat_owner: (dirfd, lookup2, p, l, statOut, out) => {
2431
2472
  if (!this.o.fs.owners) throw new WasiError("ENOTSUP");
2432
2473
  const path = at(dirfd, p, l);
2433
- this.writeFilestat(statOut, this.pathFilestat(path, lookup));
2434
- owner(pathOwned(path, (lookup & LOOKUP_SYMLINK_FOLLOW) !== 0), out);
2474
+ this.writeFilestat(statOut, this.pathFilestat(path, lookup2));
2475
+ owner(pathOwned(path, (lookup2 & LOOKUP_SYMLINK_FOLLOW) !== 0), out);
2435
2476
  },
2436
2477
  path_owner: (dirfd, p, l, flags, out) => {
2437
2478
  if (!this.o.fs.owners) throw new WasiError("ENOTSUP");
@@ -2441,7 +2482,7 @@ var init_wasi_host = __esm({
2441
2482
  path_access: (dirfd, p, l, amode, flags) => {
2442
2483
  const path = at(dirfd, p, l);
2443
2484
  const nofollow = (flags & AT_SYMLINK_NOFOLLOW) !== 0;
2444
- if (deviceOf(path)) {
2485
+ if (this.synthetic(path)) {
2445
2486
  if (this.o.fs.owners && amode & 1) throw new WasiError("EACCES");
2446
2487
  return;
2447
2488
  }
@@ -2458,12 +2499,14 @@ var init_wasi_host = __esm({
2458
2499
  },
2459
2500
  fd_mode: (fd, out) => {
2460
2501
  const e = fds.get(fd);
2461
- const pipe = e.type === "kernel" && fds.kind(fd, e) === "stream";
2462
- const mode = pipe ? S_IFIFO | 384 : modeOf(this.o.fs.stat(pathOf(fd)));
2502
+ const kind = e.type === "kernel" ? fds.kind(fd, e) : void 0;
2503
+ const mode = kind === "stream" ? S_IFIFO | 384 : kind === "sealed" ? SEALED_MODE : modeOf(this.o.fs.stat(pathOf(fd)));
2463
2504
  mem.view().setUint32(out, mode, true);
2464
2505
  },
2465
2506
  path_mode: (dirfd, p, l, flags, out) => {
2466
2507
  const path = at(dirfd, p, l);
2508
+ if (path === SEALED_PATH && this.o.kernel.sys.openSealed)
2509
+ return void mem.view().setUint32(out, SEALED_MODE, true);
2467
2510
  const st = flags & AT_SYMLINK_NOFOLLOW ? this.o.fs.lstat(path) : this.o.fs.stat(path);
2468
2511
  mem.view().setUint32(out, modeOf(st), true);
2469
2512
  }
@@ -2651,15 +2694,15 @@ var init_wasi_host = __esm({
2651
2694
  path_open: (dirfd, _lookup, p, l, oflags, rights, _inheriting, fdflags, out) => {
2652
2695
  const path = at(dirfd, p, l);
2653
2696
  if (deviceOf(path)) this.interrupted?.();
2654
- const fresh = (oflags & OFLAGS.CREAT) !== 0 && !o.fs.exists(path);
2697
+ const fresh = (oflags & OFLAGS.CREAT) !== 0 && !this.synthetic(path) && !o.fs.exists(path);
2655
2698
  mem.view().setUint32(out, fds.open(path, oflags, rights, fdflags), true);
2656
2699
  if (fresh) this.created(path, 438);
2657
2700
  },
2658
- path_filestat_get: (dirfd, lookup, p, l, out) => void this.writeFilestat(out, this.pathFilestat(at(dirfd, p, l), lookup)),
2659
- path_filestat_set_times: (dirfd, lookup, p, l, atim, mtim, flags) => {
2701
+ path_filestat_get: (dirfd, lookup2, p, l, out) => void this.writeFilestat(out, this.pathFilestat(at(dirfd, p, l), lookup2)),
2702
+ path_filestat_set_times: (dirfd, lookup2, p, l, atim, mtim, flags) => {
2660
2703
  const path = at(dirfd, p, l);
2661
2704
  fds.flushPath(path);
2662
- this.setTimes(path, atim, mtim, flags, (lookup & LOOKUP_SYMLINK_FOLLOW) !== 0);
2705
+ this.setTimes(path, atim, mtim, flags, (lookup2 & LOOKUP_SYMLINK_FOLLOW) !== 0);
2663
2706
  },
2664
2707
  path_create_directory: (dirfd, p, l) => {
2665
2708
  const path = at(dirfd, p, l);
@@ -2692,10 +2735,10 @@ var init_wasi_host = __esm({
2692
2735
  mem.bytes(buf, n).set(target.subarray(0, n));
2693
2736
  mem.view().setUint32(used, n, true);
2694
2737
  },
2695
- path_link: (fd, lookup, p, l, fd2, p2, l2) => {
2738
+ path_link: (fd, lookup2, p, l, fd2, p2, l2) => {
2696
2739
  const from = at(fd, p, l);
2697
2740
  const to = at(fd2, p2, l2);
2698
- const follow2 = (lookup & LOOKUP_SYMLINK_FOLLOW) !== 0;
2741
+ const follow2 = (lookup2 & LOOKUP_SYMLINK_FOLLOW) !== 0;
2699
2742
  const source = follow2 ? physicalPath(o.fs, from) : from;
2700
2743
  fds.flushPath(from);
2701
2744
  if (source !== from) fds.flushPath(source);
@@ -2960,8 +3003,11 @@ var init_wasi_host = __esm({
2960
3003
  const out = this.sized(path, s, size);
2961
3004
  return gone ? { ...out, nlink: 0n } : out;
2962
3005
  }
2963
- pathFilestat(path, lookup) {
2964
- if (deviceOf(path)) {
3006
+ synthetic(path) {
3007
+ return deviceOf(path) !== void 0 || path === SEALED_PATH && !!this.o.kernel.sys.openSealed;
3008
+ }
3009
+ pathFilestat(path, lookup2) {
3010
+ if (this.synthetic(path)) {
2965
3011
  return this.local({
2966
3012
  filetype: FILETYPE.CHARACTER_DEVICE,
2967
3013
  size: 0n,
@@ -2970,7 +3016,7 @@ var init_wasi_host = __esm({
2970
3016
  });
2971
3017
  }
2972
3018
  this.fds.flushPath(path);
2973
- const follow2 = (lookup & LOOKUP_SYMLINK_FOLLOW) !== 0;
3019
+ const follow2 = (lookup2 & LOOKUP_SYMLINK_FOLLOW) !== 0;
2974
3020
  return filestatOf(path, follow2 ? this.o.fs.stat(path) : this.o.fs.lstat(path));
2975
3021
  }
2976
3022
  setTimes(path, atim, mtim, flags, follow2 = true) {
@@ -3097,12 +3143,12 @@ var init_wasix_process = __esm({
3097
3143
  fds.promoteFiles();
3098
3144
  const map = fds.inheritable();
3099
3145
  const nulls = /* @__PURE__ */ new Set();
3100
- const opened = [];
3146
+ const opened2 = [];
3101
3147
  let cwd = this.host.cwd;
3102
3148
  try {
3103
- for (const op of ops) cwd = this.applyFdOp(op, { map, nulls, opened }, cwd);
3149
+ for (const op of ops) cwd = this.applyFdOp(op, { map, nulls, opened: opened2 }, cwd);
3104
3150
  } catch (e) {
3105
- for (const kfd of opened) this.host.o.kernel.sys.close(kfd);
3151
+ for (const kfd of opened2) this.host.o.kernel.sys.close(kfd);
3106
3152
  throw e;
3107
3153
  }
3108
3154
  const stdio = [0, 1, 2].map((fd) => {
@@ -3113,10 +3159,10 @@ var init_wasix_process = __esm({
3113
3159
  ...[...map].filter(([fd]) => fd > 2).map(([fd, kernel]) => ({ fd, kernel })),
3114
3160
  ...[...nulls].filter((fd) => fd > 2).map((fd) => ({ fd, device: "null" }))
3115
3161
  ];
3116
- return { stdio, inherit, cwd, opened };
3162
+ return { stdio, inherit, cwd, opened: opened2 };
3117
3163
  }
3118
3164
  applyFdOp(op, slots3, cwd) {
3119
- const { map, nulls, opened } = slots3;
3165
+ const { map, nulls, opened: opened2 } = slots3;
3120
3166
  const { fds } = this.host;
3121
3167
  const point = (fd, kfd) => {
3122
3168
  if (kfd === void 0) {
@@ -3139,7 +3185,7 @@ var init_wasix_process = __esm({
3139
3185
  point(op.fd, void 0);
3140
3186
  } else if (op.cmd === "open") {
3141
3187
  const kfd = this.openFor(op, cwd);
3142
- opened.push(kfd);
3188
+ opened2.push(kfd);
3143
3189
  point(op.fd, kfd);
3144
3190
  } else if (op.cmd === "chdir") return this.physicalFrom(cwd, op.path);
3145
3191
  else return physicalPath(this.host.o.fs, fds.dir(op.fd).path);
@@ -3161,7 +3207,7 @@ var init_wasix_process = __esm({
3161
3207
  });
3162
3208
  }
3163
3209
  spawn(req, exec = false) {
3164
- const { stdio, inherit, cwd, opened } = this.childFds(req.ops ?? []);
3210
+ const { stdio, inherit, cwd, opened: opened2 } = this.childFds(req.ops ?? []);
3165
3211
  try {
3166
3212
  const spawn = {
3167
3213
  op: "proc-spawn",
@@ -3176,7 +3222,7 @@ var init_wasix_process = __esm({
3176
3222
  };
3177
3223
  return restarted(() => this.call(spawn));
3178
3224
  } finally {
3179
- for (const kfd of opened) this.host.o.kernel.sys.close(kfd);
3225
+ for (const kfd of opened2) this.host.o.kernel.sys.close(kfd);
3180
3226
  this.host.o.fs.invalidate?.();
3181
3227
  }
3182
3228
  }
@@ -3697,6 +3743,11 @@ function untilAborted(work, signal) {
3697
3743
  work.then(done, done);
3698
3744
  });
3699
3745
  }
3746
+ function caughtOf(handlers) {
3747
+ let caught = 0;
3748
+ for (const sig of handlers.keys()) caught |= sigbit(sig);
3749
+ return caught;
3750
+ }
3700
3751
  var JsCallError, JsKernel;
3701
3752
  var init_js_kernel = __esm({
3702
3753
  "src/process/js/js-kernel.ts"() {
@@ -3724,6 +3775,7 @@ var init_js_kernel = __esm({
3724
3775
  reported = { caught: 0, ignored: 0 };
3725
3776
  watching = false;
3726
3777
  faulted = false;
3778
+ syncLane;
3727
3779
  constructor(o) {
3728
3780
  this.header = new Int32Array(o.sab, 0, SAB_HEADER_I32);
3729
3781
  this.transport = o.transport;
@@ -3826,16 +3878,41 @@ var init_js_kernel = __esm({
3826
3878
  if (sig === SIG.KILL || sig === SIG.STOP) {
3827
3879
  return Promise.reject(new JsCallError("EINVAL", "signal"));
3828
3880
  }
3881
+ if (this.syncLane) {
3882
+ try {
3883
+ this.changeNow(this.syncLane, sig, handler);
3884
+ return Promise.resolve();
3885
+ } catch (err) {
3886
+ return Promise.reject(err);
3887
+ }
3888
+ }
3829
3889
  const run = this.changing.then(() => this.change(sig, handler));
3830
3890
  this.changing = run.catch(() => void 0);
3831
3891
  return run;
3832
3892
  }
3833
- async change(sig, handler) {
3893
+ changeNow(lane, sig, handler) {
3894
+ const { handlers, ignored } = this.disposed(sig, handler);
3895
+ const defaults = handler === "default" ? sigbit(sig) : 0;
3896
+ const caught = caughtOf(handlers);
3897
+ if (caught !== this.reported.caught || ignored !== this.reported.ignored || defaults !== 0) {
3898
+ const r = lane({ op: "sig-mask", caught, ignored, ...defaults ? { defaults } : {} });
3899
+ if (!r.ok) throw new JsCallError(r.errno, "sig-mask");
3900
+ this.reported = { caught, ignored };
3901
+ }
3902
+ this.handlers = handlers;
3903
+ this.ignored = ignored;
3904
+ if (handlers.size > 0) void this.watch();
3905
+ }
3906
+ disposed(sig, handler) {
3834
3907
  const handlers = new Map(this.handlers);
3835
3908
  handlers.delete(sig);
3836
3909
  let ignored = this.ignored & ~sigbit(sig);
3837
3910
  if (handler === "ignore") ignored |= sigbit(sig);
3838
3911
  else if (handler !== "default") handlers.set(sig, handler);
3912
+ return { handlers, ignored };
3913
+ }
3914
+ async change(sig, handler) {
3915
+ const { handlers, ignored } = this.disposed(sig, handler);
3839
3916
  await this.report(handlers, ignored, handler === "default" ? sigbit(sig) : 0);
3840
3917
  this.handlers = handlers;
3841
3918
  this.ignored = ignored;
@@ -3845,8 +3922,7 @@ var init_js_kernel = __esm({
3845
3922
  this.call({ op: "proc-kill", pid: this.pid, sig }).catch(this.onError);
3846
3923
  }
3847
3924
  async report(handlers, ignored, defaults) {
3848
- let caught = 0;
3849
- for (const sig of handlers.keys()) caught |= sigbit(sig);
3925
+ const caught = caughtOf(handlers);
3850
3926
  const same = caught === this.reported.caught && ignored === this.reported.ignored;
3851
3927
  if (same && defaults === 0) return;
3852
3928
  this.reported = { caught, ignored };
@@ -4066,6 +4142,344 @@ var init_js_io = __esm({
4066
4142
  }
4067
4143
  });
4068
4144
 
4145
+ // src/process/js/js-dev.ts
4146
+ function inDev(abs) {
4147
+ return abs.startsWith("/dev") && (abs.length === 4 || abs[4] === "/");
4148
+ }
4149
+ function missing(path) {
4150
+ throw new JsCallError("ENOENT", path);
4151
+ }
4152
+ function nodeStat(mode, size = 0, owner) {
4153
+ return {
4154
+ isFile: false,
4155
+ isDirectory: (mode & S_IFMT) === DIR,
4156
+ isSymbolicLink: (mode & S_IFMT) === LINK,
4157
+ size,
4158
+ mode,
4159
+ mtimeMs: BORN,
4160
+ atimeMs: BORN,
4161
+ ctimeMs: BORN,
4162
+ nlink: 1,
4163
+ uid: owner?.uid ?? 0,
4164
+ gid: owner?.gid ?? 0
4165
+ };
4166
+ }
4167
+ function* lookup(abs) {
4168
+ if (abs === "/dev") return { kind: "dir", mode: DIR | 493 };
4169
+ const name2 = abs.slice("/dev/".length);
4170
+ if (DEVICES.includes(name2)) return { kind: "device" };
4171
+ if (name2 === "tty") return { kind: "tty" };
4172
+ const std = STDIO3.indexOf(name2);
4173
+ if (std >= 0) return { kind: "link", target: `${SELF_FD}/${std}`, fd: std };
4174
+ if (name2 === "fd") return { kind: "link", target: SELF_FD };
4175
+ const fd = /^fd\/(\d+)$/.exec(name2)?.[1];
4176
+ if (fd !== void 0) return { kind: "fd", fd: Number(fd) };
4177
+ if (/^tty\d+$/.test(name2)) {
4178
+ const names = yield { op: "fd-tty-names" };
4179
+ if (names.includes(abs)) return { kind: "terminal", name: abs };
4180
+ }
4181
+ const pts = /^pts\/(\d+)$/.exec(name2)?.[1];
4182
+ if (pts !== void 0) {
4183
+ const open = yield { op: "pty-list" };
4184
+ if (open.includes(Number(pts))) return { kind: "terminal", name: abs, pts: Number(pts) };
4185
+ }
4186
+ return missing(abs);
4187
+ }
4188
+ function* fdInfo(fd, path) {
4189
+ try {
4190
+ return yield { op: "fd-info", fd };
4191
+ } catch (err) {
4192
+ if (err instanceof JsCallError && err.code === "EBADF") return missing(path);
4193
+ throw err;
4194
+ }
4195
+ }
4196
+ function* pathStat(path) {
4197
+ const s = parseSyncFsStat(yield { op: "stat", path });
4198
+ if (!s) throw new JsCallError("EIO", "stat");
4199
+ return s;
4200
+ }
4201
+ function* terminalStat(name2) {
4202
+ const owner = yield { op: "fd-tty-owner", name: name2 };
4203
+ if (owner) return nodeStat(CHAR | (owner.mode ?? 400), 0, owner);
4204
+ return nodeStat(CHAR | (name2.startsWith("/dev/pts/") ? 400 : 438));
4205
+ }
4206
+ function* fdStat(fd, path) {
4207
+ const info = yield* fdInfo(fd, path);
4208
+ if (info.meta && "dir" in info.meta) return yield* pathStat(info.meta.dir);
4209
+ if (info.kind === "file") {
4210
+ const file = yield { op: "fd-vfs-stat", fd };
4211
+ if (file.orphan) return { ...nodeStat(33152, file.size), isFile: true };
4212
+ return yield* pathStat(file.path);
4213
+ }
4214
+ if (info.terminal) return yield* terminalStat(info.terminal);
4215
+ if (info.kind === "device" || info.kind === "tty") return nodeStat(CHAR | 438);
4216
+ if (info.kind === "socket") return nodeStat(49663);
4217
+ return nodeStat(4480);
4218
+ }
4219
+ function* fdTarget(fd, path) {
4220
+ const info = yield* fdInfo(fd, path);
4221
+ if (info.meta && "dir" in info.meta) return info.meta.dir;
4222
+ if (info.kind === "file") return (yield { op: "fd-vfs-stat", fd }).path;
4223
+ if (info.terminal) return info.terminal;
4224
+ if (info.meta && "device" in info.meta) return `/dev/${info.meta.device}`;
4225
+ return `${info.kind === "socket" ? "socket" : "pipe"}:[${fd}]`;
4226
+ }
4227
+ function linkStat(target) {
4228
+ return nodeStat(LINK | 511, target.length);
4229
+ }
4230
+ function* devStat(abs, follow2) {
4231
+ const node = yield* lookup(abs);
4232
+ switch (node.kind) {
4233
+ case "dir":
4234
+ return nodeStat(node.mode);
4235
+ case "device":
4236
+ case "tty":
4237
+ return nodeStat(CHAR | 438);
4238
+ case "terminal":
4239
+ return yield* terminalStat(node.name);
4240
+ case "link":
4241
+ if (!follow2) return linkStat(node.target);
4242
+ return node.fd === void 0 ? nodeStat(DIR | 365) : yield* fdStat(node.fd, abs);
4243
+ case "fd":
4244
+ return follow2 ? yield* fdStat(node.fd, abs) : linkStat(yield* fdTarget(node.fd, abs));
4245
+ }
4246
+ }
4247
+ function* devExists(abs) {
4248
+ try {
4249
+ yield* devStat(abs, true);
4250
+ return true;
4251
+ } catch (err) {
4252
+ if (err instanceof JsCallError) return false;
4253
+ throw err;
4254
+ }
4255
+ }
4256
+ function* devReadlink(abs) {
4257
+ const node = yield* lookup(abs);
4258
+ if (node.kind === "link") return node.target;
4259
+ if (node.kind === "fd") return yield* fdTarget(node.fd, abs);
4260
+ throw new JsCallError("EINVAL", abs);
4261
+ }
4262
+ function* devReaddir(abs) {
4263
+ if (abs === "/dev/fd") {
4264
+ const fds = yield { op: "fd-list" };
4265
+ return fds.map(({ fd }) => String(fd));
4266
+ }
4267
+ const node = yield* lookup(abs);
4268
+ if (node.kind !== "dir") throw new JsCallError("ENOTDIR", abs);
4269
+ const names = yield { op: "fd-tty-names" };
4270
+ const ttys = names.filter((n) => /^\/dev\/tty\d+$/.test(n)).map((n) => n.slice(5));
4271
+ return [...DEVICES, "tty", "fd", ...STDIO3, ...ttys].sort();
4272
+ }
4273
+ function* aliasOf(fd, abs, o) {
4274
+ const info = yield* fdInfo(fd, abs);
4275
+ const file = info.kind === "file";
4276
+ if (file) {
4277
+ const at = yield { op: "fd-vfs-stat", fd };
4278
+ if (!at.orphan)
4279
+ return { fd: yield openRequest(at.path, { ...o, create: false }), file };
4280
+ }
4281
+ const copy2 = yield { op: "fd-dup", fd, min: 3 };
4282
+ if (file && o.truncate) {
4283
+ try {
4284
+ yield { op: "fd-resize", fd: copy2, size: 0 };
4285
+ } catch (err) {
4286
+ yield { op: "fd-close", fd: copy2 };
4287
+ throw err;
4288
+ }
4289
+ }
4290
+ return { fd: copy2, file };
4291
+ }
4292
+ function* opened(abs, o) {
4293
+ const node = yield* lookup(abs);
4294
+ if (isExclusive(o)) throw new JsCallError("EEXIST", abs);
4295
+ switch (node.kind) {
4296
+ case "device":
4297
+ return { fd: yield openRequest(abs, { ...o, create: false }), file: false };
4298
+ case "tty":
4299
+ return { fd: yield { op: "fd-open-tty" }, file: false };
4300
+ case "terminal": {
4301
+ const req = node.pts === void 0 ? { op: "fd-open-tty", name: node.name } : { op: "pty-slave-open", n: node.pts, noctty: true };
4302
+ return { fd: yield req, file: false };
4303
+ }
4304
+ case "fd":
4305
+ return yield* aliasOf(node.fd, abs, o);
4306
+ case "link":
4307
+ if (node.fd !== void 0) return yield* aliasOf(node.fd, abs, o);
4308
+ throw new JsCallError("EISDIR", abs);
4309
+ case "dir":
4310
+ throw new JsCallError("EISDIR", abs);
4311
+ }
4312
+ }
4313
+ function* devOpen(abs, o) {
4314
+ const write2 = o.write === true || o.append === true || o.truncate === true;
4315
+ return { ...yield* opened(abs, o), read: o.read === true || !write2, write: write2 };
4316
+ }
4317
+ async function devAsync(kernel, step) {
4318
+ let next2 = step.next();
4319
+ while (!next2.done) {
4320
+ let answer2;
4321
+ try {
4322
+ answer2 = { value: await kernel.json(next2.value) };
4323
+ } catch (error) {
4324
+ answer2 = { error };
4325
+ }
4326
+ next2 = "value" in answer2 ? step.next(answer2.value) : step.throw(answer2.error);
4327
+ }
4328
+ return next2.value;
4329
+ }
4330
+ function devSync(kernel, step) {
4331
+ let next2 = step.next();
4332
+ while (!next2.done) {
4333
+ let answer2;
4334
+ try {
4335
+ answer2 = { value: kernel.json(next2.value) };
4336
+ } catch (error) {
4337
+ answer2 = { error };
4338
+ }
4339
+ next2 = "value" in answer2 ? step.next(answer2.value) : step.throw(answer2.error);
4340
+ }
4341
+ return next2.value;
4342
+ }
4343
+ function tooLarge(got) {
4344
+ if (got > DEV_READ_MAX) throw new JsCallError("EFBIG", "readFile");
4345
+ }
4346
+ function liveness(path) {
4347
+ let open = true;
4348
+ return {
4349
+ live: () => {
4350
+ if (!open) throw new JsCallError("EBADF", path);
4351
+ },
4352
+ end: () => {
4353
+ open = false;
4354
+ }
4355
+ };
4356
+ }
4357
+ function allowed(may, what) {
4358
+ if (!may) throw new JsCallError("EBADF", what);
4359
+ }
4360
+ function streamFile(fd, path, io, access) {
4361
+ const { live, end } = liveness(path);
4362
+ const file = {
4363
+ fd,
4364
+ path,
4365
+ async size() {
4366
+ live();
4367
+ return 0;
4368
+ },
4369
+ async read(position, length) {
4370
+ index2(position, "read");
4371
+ index2(length, "read");
4372
+ live();
4373
+ allowed(access.read, "read");
4374
+ return length === 0 ? new Uint8Array(0) : io.read(fd, Math.min(length, MAX_IO));
4375
+ },
4376
+ async write(position, data) {
4377
+ index2(position, "write");
4378
+ live();
4379
+ allowed(access.write, "write");
4380
+ await io.write(fd, data);
4381
+ return data.length;
4382
+ },
4383
+ async truncate(size) {
4384
+ live();
4385
+ index2(size, "truncate");
4386
+ throw new JsCallError("EINVAL", "truncate");
4387
+ },
4388
+ sync: async () => live(),
4389
+ async close() {
4390
+ live();
4391
+ end();
4392
+ await io.close(fd);
4393
+ }
4394
+ };
4395
+ return { file, invalidate: end };
4396
+ }
4397
+ function streamSyncFile(fd, path, io, access) {
4398
+ const { live, end } = liveness(path);
4399
+ const file = {
4400
+ fd,
4401
+ path,
4402
+ size() {
4403
+ live();
4404
+ return 0;
4405
+ },
4406
+ read(position, length) {
4407
+ index2(position, "read");
4408
+ index2(length, "read");
4409
+ live();
4410
+ allowed(access.read, "read");
4411
+ return length === 0 ? new Uint8Array(0) : io.read(fd, Math.min(length, MAX_IO));
4412
+ },
4413
+ write(position, data) {
4414
+ index2(position, "write");
4415
+ live();
4416
+ allowed(access.write, "write");
4417
+ io.write(fd, data);
4418
+ return data.length;
4419
+ },
4420
+ truncate(size) {
4421
+ live();
4422
+ index2(size, "truncate");
4423
+ throw new JsCallError("EINVAL", "truncate");
4424
+ },
4425
+ sync: () => live(),
4426
+ close() {
4427
+ live();
4428
+ end();
4429
+ io.close(fd);
4430
+ }
4431
+ };
4432
+ return { file, invalidate: end };
4433
+ }
4434
+ async function readWhole(file) {
4435
+ try {
4436
+ const parts = [];
4437
+ let got = 0;
4438
+ for (; ; ) {
4439
+ const chunk = await file.read(got, MAX_IO);
4440
+ if (chunk.length === 0) return joined(parts, got);
4441
+ got += chunk.length;
4442
+ tooLarge(got);
4443
+ parts.push(chunk);
4444
+ }
4445
+ } finally {
4446
+ await file.close();
4447
+ }
4448
+ }
4449
+ function readWholeSync(file) {
4450
+ try {
4451
+ const parts = [];
4452
+ let got = 0;
4453
+ for (; ; ) {
4454
+ const chunk = file.read(got, MAX_IO);
4455
+ if (chunk.length === 0) return joined(parts, got);
4456
+ got += chunk.length;
4457
+ tooLarge(got);
4458
+ parts.push(chunk);
4459
+ }
4460
+ } finally {
4461
+ file.close();
4462
+ }
4463
+ }
4464
+ var DEV_READ_MAX, DEVICES, STDIO3, SELF_FD, S_IFMT, DIR, LINK, CHAR, BORN;
4465
+ var init_js_dev = __esm({
4466
+ "src/process/js/js-dev.ts"() {
4467
+ "use strict";
4468
+ init_sync_fs_wire();
4469
+ init_js_io();
4470
+ init_js_kernel();
4471
+ DEV_READ_MAX = 64 * 1024 * 1024;
4472
+ DEVICES = ["null", "zero", "full", "random", "urandom"];
4473
+ STDIO3 = ["stdin", "stdout", "stderr"];
4474
+ SELF_FD = "/proc/self/fd";
4475
+ S_IFMT = 61440;
4476
+ DIR = 16384;
4477
+ LINK = 40960;
4478
+ CHAR = 8192;
4479
+ BORN = Date.now();
4480
+ }
4481
+ });
4482
+
4069
4483
  // src/process/js/js-exit.ts
4070
4484
  function json(r) {
4071
4485
  return r.ok && r.kind === "json" ? r.json : void 0;
@@ -4078,10 +4492,10 @@ function restoreMode(lane, { terminal, fd, termios }) {
4078
4492
  lane({ op: "tty-set", fd: at, termios });
4079
4493
  return;
4080
4494
  }
4081
- const opened = json(lane({ op: "fd-open-tty", name: terminal }));
4082
- if (typeof opened !== "number") return;
4083
- lane({ op: "tty-set", fd: opened, termios });
4084
- lane({ op: "fd-close", fd: opened });
4495
+ const opened2 = json(lane({ op: "fd-open-tty", name: terminal }));
4496
+ if (typeof opened2 !== "number") return;
4497
+ lane({ op: "tty-set", fd: opened2, termios });
4498
+ lane({ op: "fd-close", fd: opened2 });
4085
4499
  }
4086
4500
  function writeOut(lane, fd, data) {
4087
4501
  let at = 0;
@@ -4530,7 +4944,7 @@ function netOps(kernel, io) {
4530
4944
  const r = await kernel.blocking({ op: "sock-resolve", name: host, family: 4 }, signal);
4531
4945
  return (r.ok && r.kind === "json" ? r.json : [])[0];
4532
4946
  };
4533
- const opened = async (use) => {
4947
+ const opened2 = async (use) => {
4534
4948
  const fd = await kernel.json({ op: "sock-open", domain: "inet" });
4535
4949
  try {
4536
4950
  return await use(fd);
@@ -4572,7 +4986,7 @@ function netOps(kernel, io) {
4572
4986
  };
4573
4987
  };
4574
4988
  return {
4575
- listen: (options = {}) => opened(async (fd) => {
4989
+ listen: (options = {}) => opened2(async (fd) => {
4576
4990
  const addr = {
4577
4991
  family: "inet",
4578
4992
  host: options.host ?? "127.0.0.1",
@@ -4592,7 +5006,7 @@ function netOps(kernel, io) {
4592
5006
  host: await resolve(host, signal),
4593
5007
  port: port(options.port)
4594
5008
  };
4595
- return opened(async (fd) => {
5009
+ return opened2(async (fd) => {
4596
5010
  const r = await kernel.raw({ op: "sock-connect", fd, addr, nonblock: true });
4597
5011
  if (!r.ok && r.errno !== "EINPROGRESS") throw new JsCallError(r.errno, "connect");
4598
5012
  await kernel.blocking({ op: "fd-select", read: [], write: [fd], timeoutMs: -1 }, signal);
@@ -4626,7 +5040,7 @@ var init_js_net = __esm({
4626
5040
  // src/process/js/js-run.ts
4627
5041
  function stdioOf(how) {
4628
5042
  if (how === void 0) return "pipe";
4629
- if (!STDIO3.has(how)) throw new JsCallError("EINVAL", "run");
5043
+ if (!STDIO4.has(how)) throw new JsCallError("EINVAL", "run");
4630
5044
  return how;
4631
5045
  }
4632
5046
  function limit(value2) {
@@ -4674,13 +5088,13 @@ function runSync(kernel, d, o) {
4674
5088
  });
4675
5089
  return decodeRun(bytes, stdout, stderr);
4676
5090
  }
4677
- var encoder2, STDIO3;
5091
+ var encoder2, STDIO4;
4678
5092
  var init_js_run = __esm({
4679
5093
  "src/process/js/js-run.ts"() {
4680
5094
  "use strict";
4681
5095
  init_js_kernel();
4682
5096
  encoder2 = new TextEncoder();
4683
- STDIO3 = /* @__PURE__ */ new Set(["pipe", "ignore", "inherit"]);
5097
+ STDIO4 = /* @__PURE__ */ new Set(["pipe", "ignore", "inherit"]);
4684
5098
  }
4685
5099
  });
4686
5100
 
@@ -4974,13 +5388,30 @@ function syncOps(kernel, shared) {
4974
5388
  };
4975
5389
  const statOf = (op, path) => {
4976
5390
  const abs = resolve(path);
5391
+ if (inDev(abs)) return devSync(kernel, devStat(abs, op === "stat"));
4977
5392
  kernel.call({ op: "fd-path-flush", path: abs });
4978
5393
  const s = parseSyncFsStat(kernel.json({ op, path: abs }));
4979
5394
  if (!s) throw new JsCallError("EIO", op);
4980
5395
  return s;
4981
5396
  };
5397
+ const openDev2 = (abs, options) => {
5398
+ const { fd, file, ...access } = devSync(kernel, devOpen(abs, options));
5399
+ const forget = () => {
5400
+ infos.delete(fd);
5401
+ handles.delete(fd);
5402
+ };
5403
+ if (file) infos.set(fd, { kind: "file" });
5404
+ const close = (n) => {
5405
+ forget();
5406
+ kernel.call({ op: "fd-close", fd: n });
5407
+ };
5408
+ const handle = file ? syncFile(kernel, fd, abs, options.append === true, forget) : streamSyncFile(fd, abs, { read: (n, max) => read2(n, max), write: write2, close }, access);
5409
+ handles.set(fd, handle.invalidate);
5410
+ return handle.file;
5411
+ };
4982
5412
  const open = (path, options = {}) => {
4983
5413
  const abs = resolve(path);
5414
+ if (inDev(abs)) return openDev2(abs, options);
4984
5415
  let existing;
4985
5416
  try {
4986
5417
  existing = statOf(isExclusive(options) ? "lstat" : "stat", abs);
@@ -5084,17 +5515,30 @@ function syncPathOps(kernel, resolve, statOf, open) {
5084
5515
  return {
5085
5516
  stat: (path) => statOf("stat", path),
5086
5517
  lstat: (path) => statOf("lstat", path),
5087
- exists: (path) => kernel.json({ op: "exists", path: resolve(path) }) === true,
5088
- readdir: (path) => kernel.json({ op: "readdir", path: resolve(path) }),
5518
+ exists(path) {
5519
+ const abs = resolve(path);
5520
+ if (inDev(abs)) return devSync(kernel, devExists(abs));
5521
+ return kernel.json({ op: "exists", path: abs }) === true;
5522
+ },
5523
+ readdir(path) {
5524
+ const abs = resolve(path);
5525
+ if (inDev(abs)) return devSync(kernel, devReaddir(abs));
5526
+ return kernel.json({ op: "readdir", path: abs });
5527
+ },
5089
5528
  mkdir: (path) => void kernel.call({ op: "mkdir", path: resolve(path) }),
5090
5529
  rm: (path) => void kernel.call({ op: "rm", path: resolve(path) }),
5091
5530
  unlink: (path) => void kernel.call({ op: "unlink", path: resolve(path) }),
5092
5531
  rename: (from, to) => void kernel.call({ op: "rename", path: resolve(from), arg2: resolve(to) }),
5093
5532
  link: (from, to) => void kernel.call({ op: "link", path: resolve(from), arg2: resolve(to) }),
5094
5533
  symlink: (target, path) => void kernel.call({ op: "symlink", path: resolve(path), arg2: target }),
5095
- readlink: (path) => String(kernel.json({ op: "readlink", path: resolve(path) })),
5534
+ readlink(path) {
5535
+ const abs = resolve(path);
5536
+ if (inDev(abs)) return devSync(kernel, devReadlink(abs));
5537
+ return String(kernel.json({ op: "readlink", path: abs }));
5538
+ },
5096
5539
  readFile(path) {
5097
5540
  const abs = resolve(path);
5541
+ if (inDev(abs)) return readWholeSync(open(abs));
5098
5542
  kernel.call({ op: "fd-path-flush", path: abs });
5099
5543
  return kernel.bytes({ op: "read", path: abs });
5100
5544
  },
@@ -5115,6 +5559,7 @@ var init_js_sync = __esm({
5115
5559
  init_signals();
5116
5560
  init_sync_fs_wire();
5117
5561
  init_sync_sab_bridge();
5562
+ init_js_dev();
5118
5563
  init_js_io();
5119
5564
  init_js_kernel();
5120
5565
  encoder3 = new TextEncoder();
@@ -5515,6 +5960,7 @@ function createContext(o) {
5515
5960
  const writable2 = (fd) => new WritableStream({ write: (chunk) => write2(fd, chunk) });
5516
5961
  const statOf = async (op, path) => {
5517
5962
  const abs = resolve(path);
5963
+ if (inDev(abs)) return devAsync(kernel, devStat(abs, op === "stat"));
5518
5964
  await kernel.call({ op: "fd-path-flush", path: abs });
5519
5965
  const s = parseSyncFsStat(await kernel.json({ op, path: abs }));
5520
5966
  if (!s) throw new JsCallError("EIO", op);
@@ -5522,6 +5968,7 @@ function createContext(o) {
5522
5968
  };
5523
5969
  const open = async (path, options = {}) => {
5524
5970
  const abs = resolve(path);
5971
+ if (inDev(abs)) return openDev(kernel, abs, options, { infos, handles, read: read2, write: writeAll });
5525
5972
  const existing = await statOf(isExclusive(options) ? "lstat" : "stat", abs).catch(absent);
5526
5973
  checkOpen(abs, options, existing);
5527
5974
  const fd = await kernel.json(openRequest(abs, options));
@@ -5541,6 +5988,7 @@ function createContext(o) {
5541
5988
  };
5542
5989
  const fs = pathOps(kernel, resolve, statOf, open);
5543
5990
  const lane = o.lane ?? laneOf(void 0);
5991
+ if (o.lane) kernel.syncLane = o.lane;
5544
5992
  const syncKernel = new JsSyncKernel(lane, kernel, unwind);
5545
5993
  const terminal = ttyOps(kernel);
5546
5994
  const sync = {
@@ -5621,6 +6069,26 @@ function createContext(o) {
5621
6069
  };
5622
6070
  return { ctx, drain: drain2 };
5623
6071
  }
6072
+ async function openDev(kernel, abs, options, state) {
6073
+ const { fd, file, ...access } = await devAsync(kernel, devOpen(abs, options));
6074
+ const forget = () => {
6075
+ state.infos.delete(fd);
6076
+ state.handles.delete(fd);
6077
+ };
6078
+ if (file) state.infos.set(fd, { kind: "file" });
6079
+ const close = async (n) => {
6080
+ forget();
6081
+ await kernel.call({ op: "fd-close", fd: n });
6082
+ };
6083
+ const handle = file ? fileHandle(kernel, fd, abs, options.append === true, forget) : streamFile(
6084
+ fd,
6085
+ abs,
6086
+ { read: (n, max) => state.read(n, max), write: state.write, close },
6087
+ access
6088
+ );
6089
+ state.handles.set(fd, handle.invalidate);
6090
+ return handle.file;
6091
+ }
5624
6092
  function fileHandle(kernel, fd, path, append, forget) {
5625
6093
  let open = true;
5626
6094
  const live = () => {
@@ -5713,17 +6181,30 @@ function pathOps(kernel, resolve, statOf, open) {
5713
6181
  return {
5714
6182
  stat: (path) => statOf("stat", path),
5715
6183
  lstat: (path) => statOf("lstat", path),
5716
- exists: async (path) => await kernel.json({ op: "exists", path: resolve(path) }) === true,
5717
- readdir: async (path) => await kernel.json({ op: "readdir", path: resolve(path) }),
6184
+ async exists(path) {
6185
+ const abs = resolve(path);
6186
+ if (inDev(abs)) return devAsync(kernel, devExists(abs));
6187
+ return await kernel.json({ op: "exists", path: abs }) === true;
6188
+ },
6189
+ async readdir(path) {
6190
+ const abs = resolve(path);
6191
+ if (inDev(abs)) return devAsync(kernel, devReaddir(abs));
6192
+ return await kernel.json({ op: "readdir", path: abs });
6193
+ },
5718
6194
  mkdir: async (path) => void await kernel.call({ op: "mkdir", path: resolve(path) }),
5719
6195
  rm: async (path) => void await kernel.call({ op: "rm", path: resolve(path) }),
5720
6196
  unlink: async (path) => void await kernel.call({ op: "unlink", path: resolve(path) }),
5721
6197
  rename: async (from, to) => void await kernel.call({ op: "rename", path: resolve(from), arg2: resolve(to) }),
5722
6198
  link: async (from, to) => void await kernel.call({ op: "link", path: resolve(from), arg2: resolve(to) }),
5723
6199
  symlink: async (target, path) => void await kernel.call({ op: "symlink", path: resolve(path), arg2: target }),
5724
- readlink: async (path) => String(await kernel.json({ op: "readlink", path: resolve(path) })),
6200
+ async readlink(path) {
6201
+ const abs = resolve(path);
6202
+ if (inDev(abs)) return devAsync(kernel, devReadlink(abs));
6203
+ return String(await kernel.json({ op: "readlink", path: abs }));
6204
+ },
5725
6205
  async readFile(path) {
5726
6206
  const abs = resolve(path);
6207
+ if (inDev(abs)) return readWhole(await open(abs));
5727
6208
  await kernel.call({ op: "fd-path-flush", path: abs });
5728
6209
  return kernel.bytes({ op: "read", path: abs });
5729
6210
  },
@@ -5744,6 +6225,7 @@ var init_js_context = __esm({
5744
6225
  init_signals();
5745
6226
  init_sync_fs_wire();
5746
6227
  init_js_children();
6228
+ init_js_dev();
5747
6229
  init_js_exit();
5748
6230
  init_js_fetch();
5749
6231
  init_js_io();
@@ -6398,7 +6880,7 @@ function createStreamOps(h) {
6398
6880
  }
6399
6881
  }
6400
6882
  };
6401
- const opened = (node, on, want = 0) => {
6883
+ const opened2 = (node, on, want = 0) => {
6402
6884
  const s = node.live;
6403
6885
  try {
6404
6886
  const handle = bridgeOf(node).hold?.(liveNodePath(node), on, true, s.handle, want);
@@ -6449,7 +6931,7 @@ function createStreamOps(h) {
6449
6931
  const want = permitted(stream, created);
6450
6932
  live.openCount++;
6451
6933
  counted = true;
6452
- if (live.openCount === 1) opened(stream.node, true, want);
6934
+ if (live.openCount === 1) opened2(stream.node, true, want);
6453
6935
  } catch (err) {
6454
6936
  if (counted) live.openCount--;
6455
6937
  if (stream.fd !== void 0) Fs.closeStream?.(stream.fd);
@@ -6480,7 +6962,7 @@ function createStreamOps(h) {
6480
6962
  s.len = 0;
6481
6963
  s.loaded = false;
6482
6964
  held(stream, -1);
6483
- opened(node, false);
6965
+ opened2(node, false);
6484
6966
  }
6485
6967
  },
6486
6968
  read(stream, buffer, offset, length, position) {
@@ -6857,10 +7339,28 @@ function ptyStat(path) {
6857
7339
  ctime: now
6858
7340
  };
6859
7341
  }
7342
+ function sealedStat() {
7343
+ const now = /* @__PURE__ */ new Date();
7344
+ return {
7345
+ dev: 22,
7346
+ ino: 1,
7347
+ mode: 8630,
7348
+ nlink: 1,
7349
+ uid: 0,
7350
+ gid: 0,
7351
+ rdev: 10 << 8 | 250,
7352
+ size: 0,
7353
+ blksize: 4096,
7354
+ blocks: 0,
7355
+ atime: now,
7356
+ mtime: now,
7357
+ ctime: now
7358
+ };
7359
+ }
6860
7360
  function nonblocking(stream) {
6861
7361
  return (stream.flags & O_NONBLOCK2) !== 0 ? { nonblock: true } : void 0;
6862
7362
  }
6863
- var POLLIN, POLLOUT, POLLERR, POLLHUP, POLLRDNORM, POLLWRNORM, TCSETSF, O_NONBLOCK2, SOCKET_MODE, PTY_PATH, TTY_PATH, TTY_NAME, O_CREAT, O_EXCL, O_NOCTTY, O_TRUNC2, KILLED_BY_SIGPIPE, ProcessExit, SyscallError, KernelStreams;
7363
+ var POLLIN, POLLOUT, POLLERR, POLLHUP, POLLRDNORM, POLLWRNORM, TCSETSF, O_NONBLOCK2, SOCKET_MODE, PTY_PATH, TTY_PATH, TTY_NAME, SEALED_PATH2, O_CREAT, O_EXCL, O_NOCTTY, O_TRUNC2, KILLED_BY_SIGPIPE, ProcessExit, SyscallError, KernelStreams;
6864
7364
  var init_kernel_streams = __esm({
6865
7365
  "src/process/kernel-streams.ts"() {
6866
7366
  "use strict";
@@ -6877,6 +7377,7 @@ var init_kernel_streams = __esm({
6877
7377
  PTY_PATH = /^\/dev\/(?:ptmx|pts\/(\d+))$/;
6878
7378
  TTY_PATH = /^\/dev\/tty\d+$/;
6879
7379
  TTY_NAME = /^tty\d+$/;
7380
+ SEALED_PATH2 = "/dev/sealed";
6880
7381
  O_CREAT = 64;
6881
7382
  O_EXCL = 128;
6882
7383
  O_NOCTTY = 256;
@@ -6950,6 +7451,15 @@ var init_kernel_streams = __esm({
6950
7451
  if (typeof this.Fs.stat !== "function") return;
6951
7452
  stream.stream_ops = { ...stream.stream_ops, getattr: () => this.Fs.stat?.(name2) ?? {} };
6952
7453
  }
7454
+ listSealed() {
7455
+ const { analyzePath, mkdev, makedev } = this.Fs;
7456
+ if (!this.sys.openSealed || !analyzePath || !mkdev || !makedev) return;
7457
+ if (analyzePath.call(this.Fs, SEALED_PATH2).exists) return;
7458
+ try {
7459
+ mkdev.call(this.Fs, SEALED_PATH2, makedev.call(this.Fs, 10, 250));
7460
+ } catch {
7461
+ }
7462
+ }
6953
7463
  creatingTerminal = false;
6954
7464
  useTerminalNodes() {
6955
7465
  const fs = this.Fs;
@@ -6976,8 +7486,8 @@ var init_kernel_streams = __esm({
6976
7486
  fs.readdir = (path) => {
6977
7487
  const names = readdir.call(fs, path);
6978
7488
  if (path.replace(/\/+$/, "") !== "/dev") return names;
6979
- const missing = ttyNames().map((tty) => tty.slice("/dev/".length)).filter((name2) => TTY_NAME.test(name2) && !names.includes(name2));
6980
- return [...names, ...missing];
7489
+ const missing2 = ttyNames().map((tty) => tty.slice("/dev/".length)).filter((name2) => TTY_NAME.test(name2) && !names.includes(name2));
7490
+ return [...names, ...missing2];
6981
7491
  };
6982
7492
  }
6983
7493
  ttyNode(name2) {
@@ -7042,13 +7552,14 @@ var init_kernel_streams = __esm({
7042
7552
  if (typeof this.Fs.open !== "function") return;
7043
7553
  this.usePtyPaths();
7044
7554
  this.useTerminalNodes();
7555
+ this.listSealed();
7045
7556
  const open = this.Fs.open.bind(this.Fs);
7046
7557
  this.Fs.open = (path, flags, mode) => {
7047
7558
  const device2 = typeof path === "string" ? this.devicePath(path) : void 0;
7048
7559
  if (device2 !== void 0 && TTY_PATH.test(device2) && !this.terminalExists(device2)) {
7049
7560
  throw new this.Fs.ErrnoError(wasiErrno("ENOENT"));
7050
7561
  }
7051
- const pty = this.openPty(open, path, flags, mode);
7562
+ const pty = this.openPty(open, path, flags, mode) ?? this.openSealed(open, path, flags, mode);
7052
7563
  if (pty) return pty;
7053
7564
  this.refuseExclusiveLink(path, flags);
7054
7565
  const stream = this.openRacing(open, path, flags, mode);
@@ -7106,15 +7617,24 @@ var init_kernel_streams = __esm({
7106
7617
  const kfd = this.call(
7107
7618
  () => pts ? openPts(Number(pts[1]), (flags & O_NOCTTY) !== 0) : openPty()
7108
7619
  );
7620
+ return this.vessel(open, kfd, { path, flags, mode }, true);
7621
+ }
7622
+ openSealed(open, path, flags, mode) {
7623
+ const { openSealed } = this.sys;
7624
+ if (path !== SEALED_PATH2 || !openSealed) return void 0;
7625
+ const kfd = this.call(() => openSealed.call(this.sys));
7626
+ return this.vessel(open, kfd, { path, flags, mode }, false);
7627
+ }
7628
+ vessel(open, kfd, at, terminal) {
7109
7629
  let stream;
7110
7630
  try {
7111
- stream = open("/dev/null", flags & ~(O_CREAT | O_EXCL | O_TRUNC2), mode);
7631
+ stream = open("/dev/null", at.flags & ~(O_CREAT | O_EXCL | O_TRUNC2), at.mode);
7112
7632
  } catch (e) {
7113
7633
  this.sys.close(kfd);
7114
7634
  throw e;
7115
7635
  }
7116
- this.attach(stream, kfd, true);
7117
- this.nameStream(stream, path);
7636
+ this.attach(stream, kfd, terminal);
7637
+ this.nameStream(stream, at.path);
7118
7638
  return stream;
7119
7639
  }
7120
7640
  usePtyPaths() {
@@ -7128,6 +7648,7 @@ var init_kernel_streams = __esm({
7128
7648
  const original = fs[name2];
7129
7649
  if (typeof original !== "function") continue;
7130
7650
  fs[name2] = (path, ...rest2) => {
7651
+ if (path === SEALED_PATH2 && this.sys.openSealed) return sealedStat();
7131
7652
  const owned = this.ownedTty(path);
7132
7653
  if (owned && isPtyPath(path)) return this.owned(path, ptyStat(path));
7133
7654
  if (!isPtyPath(path)) {
@@ -7744,13 +8265,13 @@ function describeFdDir(Fs) {
7744
8265
  return;
7745
8266
  }
7746
8267
  const ops = dir?.node_ops;
7747
- const lookup = ops?.lookup;
7748
- if (!dir || !lookup || ops.getattr) return;
8268
+ const lookup2 = ops?.lookup;
8269
+ if (!dir || !lookup2 || ops.getattr) return;
7749
8270
  dir.node_ops = {
7750
8271
  ...ops,
7751
8272
  getattr: () => syntheticAttr(DIR_MODE, 1),
7752
8273
  lookup: (parent, name2) => {
7753
- const entry = lookup(parent, name2);
8274
+ const entry = lookup2(parent, name2);
7754
8275
  entry.node_ops = {
7755
8276
  ...entry.node_ops,
7756
8277
  getattr: () => syntheticAttr(LINK_MODE, entry.id ?? 0)
@@ -8290,7 +8811,7 @@ function createProcessKernel(deps) {
8290
8811
  if (!stream) return { none: true };
8291
8812
  promote?.(stream);
8292
8813
  if (stream.sliccKernelFd !== void 0) return { fd: stream.sliccKernelFd };
8293
- if (((stream.node?.mode ?? 0) & S_IFMT) === S_IFDIR2 && stream.path) return { dir: stream.path };
8814
+ if (((stream.node?.mode ?? 0) & S_IFMT2) === S_IFDIR2 && stream.path) return { dir: stream.path };
8294
8815
  const device2 = deviceOfStream(stream);
8295
8816
  if (device2) return device2;
8296
8817
  return n === 0 ? { input: drain(Fs, stream) } : { capture: true };
@@ -8437,13 +8958,13 @@ function createProcessKernel(deps) {
8437
8958
  }
8438
8959
  };
8439
8960
  }
8440
- var S_IFMT, S_IFDIR2, POLLIN2, POLLOUT2, POLLERR2, POLLHUP2, POLLNVAL, SELECT_SLICE_MS, WUNTRACED, WCONTINUED;
8961
+ var S_IFMT2, S_IFDIR2, POLLIN2, POLLOUT2, POLLERR2, POLLHUP2, POLLNVAL, SELECT_SLICE_MS, WUNTRACED, WCONTINUED;
8441
8962
  var init_process_children = __esm({
8442
8963
  "src/process/process-children.ts"() {
8443
8964
  "use strict";
8444
8965
  init_process_fork();
8445
8966
  init_wasi_errno();
8446
- S_IFMT = 61440;
8967
+ S_IFMT2 = 61440;
8447
8968
  S_IFDIR2 = 16384;
8448
8969
  POLLIN2 = 1;
8449
8970
  POLLOUT2 = 4;
@@ -9018,7 +9539,7 @@ function useProcfs(Fs, sys, pid, memory = memorySource()) {
9018
9539
  return found;
9019
9540
  };
9020
9541
  const procOps = proc.node_ops;
9021
- const lookup = procOps.lookup?.bind(procOps);
9542
+ const lookup2 = procOps.lookup?.bind(procOps);
9022
9543
  const readdir = procOps.readdir?.bind(procOps);
9023
9544
  const listAll = (node) => {
9024
9545
  const names = new Set(readdir ? readdir(node) : [".", ".."]);
@@ -9041,8 +9562,8 @@ function useProcfs(Fs, sys, pid, memory = memorySource()) {
9041
9562
  () => systemFile(name2, procList(), Date.now(), memory)
9042
9563
  );
9043
9564
  }
9044
- if (!lookup) throw error();
9045
- return lookup(parent, name2);
9565
+ if (!lookup2) throw error();
9566
+ return lookup2(parent, name2);
9046
9567
  },
9047
9568
  readdir: (node) => listAll(node)
9048
9569
  };
@@ -9255,6 +9776,9 @@ function kernelSys(transport) {
9255
9776
  openPts(n, noctty) {
9256
9777
  return json2(call2({ op: "pty-slave-open", n, noctty }, `pty-slave-open ${n}`));
9257
9778
  },
9779
+ openSealed() {
9780
+ return json2(call2({ op: "fd-open-sealed" }, "fd-open-sealed"));
9781
+ },
9258
9782
  ptyNumbers() {
9259
9783
  return json2(call2({ op: "pty-list" }, "pty-list"));
9260
9784
  },
@@ -11774,8 +12298,8 @@ var init_wasix_host = __esm({
11774
12298
  mem.view().setUint16(out, host.fds.cloexec.has(fd) ? FDFLAGSEXT_CLOEXEC : 0, true);
11775
12299
  },
11776
12300
  fd_fdflags_set: (fd, flags) => void host.fds.setCloexec(fd, (flags & FDFLAGSEXT_CLOEXEC) !== 0),
11777
- path_open2: (dirfd, lookup, p, l, oflags, rights, inheriting, fdflags, fdflagsext, out) => {
11778
- const r = preview1.path_open(dirfd, lookup, p, l, oflags, rights, inheriting, fdflags, out);
12301
+ path_open2: (dirfd, lookup2, p, l, oflags, rights, inheriting, fdflags, fdflagsext, out) => {
12302
+ const r = preview1.path_open(dirfd, lookup2, p, l, oflags, rights, inheriting, fdflags, out);
11779
12303
  if (r === E.SUCCESS && fdflagsext & FDFLAGSEXT_CLOEXEC)
11780
12304
  host.fds.setCloexec(mem.view().getUint32(out, true), true);
11781
12305
  return r;