@ai-ecoverse/slicc-kernel 1.85.1 → 1.87.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.
@@ -1112,10 +1112,14 @@ function liveNodePath(node) {
1112
1112
  const root = node.mount.opts.root.replace(/\/+$/, "");
1113
1113
  return parts.length === 0 ? root || "/" : `${root}/${parts.reverse().join("/")}`;
1114
1114
  }
1115
- function modeFromStat(st) {
1115
+ function exactIn(node) {
1116
+ return node?.mount.opts.bridge.owners === true;
1117
+ }
1118
+ function modeFromStat(st, exact = false) {
1116
1119
  const type = st.isSymbolicLink ? S_IFLNK : st.isDirectory ? S_IFDIR : S_IFREG;
1117
1120
  const fallback = st.isDirectory || st.isSymbolicLink ? 511 : 438;
1118
- return type | ((st.mode ?? fallback) & PERM_MASK || fallback);
1121
+ const perm = (st.mode ?? fallback) & PERM_MASK;
1122
+ return type | (exact ? perm : perm || fallback);
1119
1123
  }
1120
1124
  function toMs(v) {
1121
1125
  if (v === void 0 || v === null) return void 0;
@@ -1223,7 +1227,7 @@ function createHelpers(Fs, ops) {
1223
1227
  return { ...stat ? { stat, statAt } : {}, len: 0, loaded: false, dirty: false, openCount: 0 };
1224
1228
  }
1225
1229
  function makeNode(parent, name2, st) {
1226
- const node = Fs.createNode(parent, name2, modeFromStat(st), 0);
1230
+ const node = Fs.createNode(parent, name2, modeFromStat(st, exactIn(parent)), 0);
1227
1231
  node.node_ops = ops.node;
1228
1232
  node.stream_ops = ops.stream;
1229
1233
  node.live = freshState(st);
@@ -1237,7 +1241,7 @@ function createHelpers(Fs, ops) {
1237
1241
  if (!cachedStat(node.live, Fs.isDir(node.mode))) {
1238
1242
  const st = call2(() => bridgeOf(node).lstat(liveNodePath(linked.holder(node))));
1239
1243
  Object.assign(node.live, { stat: st, statAt: syncCallCount() });
1240
- node.mode = modeFromStat(st);
1244
+ node.mode = modeFromStat(st, exactIn(node));
1241
1245
  }
1242
1246
  return node.live.stat;
1243
1247
  }
@@ -1575,9 +1579,21 @@ function createStreamOps(h) {
1575
1579
  }
1576
1580
  return want;
1577
1581
  };
1582
+ const directory = (stream) => {
1583
+ const bridge = bridgeOf(stream.node);
1584
+ if (!bridge.owners || !Fs.isDir(stream.node.mode) || stream.flags & O_PATH) return;
1585
+ try {
1586
+ h.call(
1587
+ () => bridge.access?.(liveNodePath(stream.node), accessOf(wantOf(stream.flags)), "open")
1588
+ );
1589
+ } catch (err) {
1590
+ if (stream.fd !== void 0) Fs.closeStream?.(stream.fd);
1591
+ throw err;
1592
+ }
1593
+ };
1578
1594
  return {
1579
1595
  open(stream) {
1580
- if (!Fs.isFile(stream.node.mode)) return;
1596
+ if (!Fs.isFile(stream.node.mode)) return directory(stream);
1581
1597
  const s = stream.node.live;
1582
1598
  const created = s.created === true;
1583
1599
  s.created = void 0;
@@ -1709,6 +1725,7 @@ function createLiveVfsPlugin(Fs) {
1709
1725
  const st = h.call(() => mount.opts.bridge.stat(mount.opts.root));
1710
1726
  if (!st.isDirectory) throw new Fs.ErrnoError(wasiErrno("ENOTDIR"));
1711
1727
  const root = h.makeNode(null, "/", st);
1728
+ root.mode = modeFromStat(st, mount.opts.bridge.owners === true);
1712
1729
  mounts.add(mount);
1713
1730
  return root;
1714
1731
  }
@@ -1918,7 +1935,7 @@ function useLiveChown(Fs) {
1918
1935
  Fs.chown(target, uid, gid);
1919
1936
  };
1920
1937
  }
1921
- var S_IFDIR, S_IFREG, S_IFLNK, PERM_MASK, DEFAULT_DIR_PERM, UMASK, SEEK_CUR, SEEK_END, EARLY_WHOLE_FILE, O_ACCMODE, O_TRUNC, stale;
1938
+ var S_IFDIR, S_IFREG, S_IFLNK, PERM_MASK, DEFAULT_DIR_PERM, UMASK, SEEK_CUR, SEEK_END, EARLY_WHOLE_FILE, O_ACCMODE, O_TRUNC, O_PATH, stale;
1922
1939
  var init_live_vfs_fs = __esm({
1923
1940
  "src/realm/live-vfs-fs.ts"() {
1924
1941
  "use strict";
@@ -1938,6 +1955,7 @@ var init_live_vfs_fs = __esm({
1938
1955
  EARLY_WHOLE_FILE = 64 * 1024;
1939
1956
  O_ACCMODE = 3;
1940
1957
  O_TRUNC = 512;
1958
+ O_PATH = 2097152;
1941
1959
  stale = (s) => !!s.orphan && !s.kept;
1942
1960
  }
1943
1961
  });
@@ -2360,7 +2378,7 @@ var init_kernel_streams = __esm({
2360
2378
  openSealed(open, path, flags, mode) {
2361
2379
  const { openSealed } = this.sys;
2362
2380
  if (path !== SEALED_PATH || !openSealed) return void 0;
2363
- const kfd = this.call(() => openSealed.call(this.sys));
2381
+ const kfd = this.call(() => openSealed.call(this.sys, flags & 3));
2364
2382
  return this.vessel(open, kfd, { path, flags, mode }, false);
2365
2383
  }
2366
2384
  openClipboard(open, path, flags, mode) {
@@ -2757,7 +2775,7 @@ function pathOpensLinks(Fs) {
2757
2775
  const fs = Fs;
2758
2776
  const { mayOpen, isLink } = fs;
2759
2777
  if (!mayOpen || !isLink) return;
2760
- fs.mayOpen = (node, flags) => flags & O_PATH && isLink.call(fs, node.mode) ? 0 : mayOpen.call(fs, node, flags);
2778
+ fs.mayOpen = (node, flags) => flags & O_PATH2 && isLink.call(fs, node.mode) ? 0 : mayOpen.call(fs, node, flags);
2761
2779
  }
2762
2780
  function importKey(namespace, name2, glue) {
2763
2781
  const own = glue?.[name2];
@@ -3237,7 +3255,24 @@ function kernelAccess(imports, fs, memory, glue) {
3237
3255
  }
3238
3256
  });
3239
3257
  }
3258
+ function kernelChdir(Fs) {
3259
+ const { chdir, lookupPath, ErrnoError } = Fs;
3260
+ if (!chdir || !lookupPath || !ErrnoError) return;
3261
+ Fs.chdir = (path) => {
3262
+ const { node } = lookupPath.call(Fs, path, { follow: true });
3263
+ const directory = Fs.isDir?.(node.mode) === true;
3264
+ const bridge = node.live && directory ? node.mount.opts.bridge : void 0;
3265
+ try {
3266
+ bridge?.access?.(liveNodePath(node), X_ACCESS, "eaccess", false);
3267
+ } catch (err) {
3268
+ throw new ErrnoError(errnoOf(err));
3269
+ }
3270
+ chdir.call(Fs, path);
3271
+ };
3272
+ }
3240
3273
  function linuxDevices(Fs) {
3274
+ Fs.ignorePermissions = true;
3275
+ kernelChdir(Fs);
3241
3276
  const { chmod } = Fs;
3242
3277
  if (!chmod) return;
3243
3278
  for (const [path, mode] of DEVICE_MODES) {
@@ -3247,7 +3282,7 @@ function linuxDevices(Fs) {
3247
3282
  }
3248
3283
  }
3249
3284
  }
3250
- var O_CLOEXEC, FD_CLOEXEC, F_DUPFD, F_GETFD, F_SETFD, F_GETFL, F_DUPFD_CLOEXEC, tracked, IMPORT_NAMES, EBADF, AT_SYMLINK_NOFOLLOW, EMSCRIPTEN_EPERM, O_PATH, LITERALS, UTIME_NOW, UTIME_OMIT, PROT_WRITE, MAP_PRIVATE, MAP_TYPE, O_WRONLY, MAP_ALIGN, DIR_MODE, LINK_MODE, CHAR_DEVICE, O_ACCMODE2, O_CREAT2, field, pinnedRoot, rootKind, NAME, AT_FDCWD, AT_EACCESS, W_ACCESS, DEVICE_MODES;
3285
+ var O_CLOEXEC, FD_CLOEXEC, F_DUPFD, F_GETFD, F_SETFD, F_GETFL, F_DUPFD_CLOEXEC, tracked, IMPORT_NAMES, EBADF, AT_SYMLINK_NOFOLLOW, EMSCRIPTEN_EPERM, O_PATH2, LITERALS, UTIME_NOW, UTIME_OMIT, PROT_WRITE, MAP_PRIVATE, MAP_TYPE, O_WRONLY, MAP_ALIGN, DIR_MODE, LINK_MODE, CHAR_DEVICE, O_ACCMODE2, O_CREAT2, field, pinnedRoot, rootKind, NAME, AT_FDCWD, AT_EACCESS, W_ACCESS, X_ACCESS, DEVICE_MODES;
3251
3286
  var init_process_fds = __esm({
3252
3287
  "src/process/process-fds.ts"() {
3253
3288
  "use strict";
@@ -3275,7 +3310,7 @@ var init_process_fds = __esm({
3275
3310
  EBADF = 8;
3276
3311
  AT_SYMLINK_NOFOLLOW = 256;
3277
3312
  EMSCRIPTEN_EPERM = 63;
3278
- O_PATH = 2097152;
3313
+ O_PATH2 = 2097152;
3279
3314
  LITERALS = {
3280
3315
  openat: "__syscall_openat",
3281
3316
  mkdirat: "__syscall_mkdirat",
@@ -3307,6 +3342,7 @@ var init_process_fds = __esm({
3307
3342
  AT_FDCWD = -100;
3308
3343
  AT_EACCESS = 512;
3309
3344
  W_ACCESS = 2;
3345
+ X_ACCESS = 1;
3310
3346
  DEVICE_MODES = [
3311
3347
  ["/", 493],
3312
3348
  ["/dev", 493],
@@ -3397,8 +3433,8 @@ function describeInherited(Fs, sys, streams, livePath, actions = []) {
3397
3433
  const out = [];
3398
3434
  for (const [fd, stream] of slots3) {
3399
3435
  promote(stream);
3400
- const slot = inheritedSlot(fd, stream);
3401
- if (slot) out.push(slot);
3436
+ const slot2 = inheritedSlot(fd, stream);
3437
+ if (slot2) out.push(slot2);
3402
3438
  }
3403
3439
  return out;
3404
3440
  }
@@ -3616,7 +3652,7 @@ function createProcessKernel(deps) {
3616
3652
  const reaped = /* @__PURE__ */ new Map();
3617
3653
  const call2 = (req, label) => transport.call(req, Infinity, label);
3618
3654
  const at = (path) => path === "" || path.startsWith("/") ? path : `${Fs.cwd()}/${path}`;
3619
- const slot = (fd, n, promote) => {
3655
+ const slot2 = (fd, n, promote) => {
3620
3656
  const stream = fd >= 0 ? Fs.getStream(fd) : null;
3621
3657
  if (!stream) return { none: true };
3622
3658
  promote?.(stream);
@@ -3665,7 +3701,7 @@ function createProcessKernel(deps) {
3665
3701
  const unflushed = flushed(deps.beforeSpawn);
3666
3702
  if (unflushed < 0) return unflushed;
3667
3703
  const promote = deps.stdioPromoter?.();
3668
- const stdio = [0, 1, 2].map((n) => slot(fds[n] ?? -1, n, promote));
3704
+ const stdio = [0, 1, 2].map((n) => slot2(fds[n] ?? -1, n, promote));
3669
3705
  const inherit = deps.inherit?.(actions) ?? [];
3670
3706
  const req = {
3671
3707
  op: "proc-spawn",
@@ -4609,8 +4645,8 @@ function kernelSys(transport) {
4609
4645
  openPts(n, noctty) {
4610
4646
  return json2(call2({ op: "pty-slave-open", n, noctty }, `pty-slave-open ${n}`));
4611
4647
  },
4612
- openSealed() {
4613
- return json2(call2({ op: "fd-open-sealed" }, "fd-open-sealed"));
4648
+ openSealed(flags) {
4649
+ return json2(call2({ op: "fd-open-sealed", flags }, "fd-open-sealed"));
4614
4650
  },
4615
4651
  openClipboard(flags) {
4616
4652
  return json2(call2({ op: "fd-open-clipboard", flags }, "fd-open-clipboard"));
@@ -6297,12 +6333,10 @@ var init_wasi_fds = __esm({
6297
6333
  let fd;
6298
6334
  let kind;
6299
6335
  if (path === SEALED_PATH2 && openSealed) {
6300
- if (oflags & OFLAGS.DIRECTORY) throw new WasiError("ENOTDIR");
6301
- if (oflags & OFLAGS.CREAT && oflags & OFLAGS.EXCL) throw new WasiError("EEXIST");
6302
- fd = openSealed.call(this.kernel.sys);
6336
+ fd = this.openCharDevice(openSealed, oflags, rights);
6303
6337
  kind = "sealed";
6304
6338
  } else if (path === CLIPBOARD_PATH2 && openClipboard) {
6305
- fd = this.openClipboard(openClipboard, oflags, rights);
6339
+ fd = this.openCharDevice(openClipboard, oflags, rights);
6306
6340
  kind = "clipboard";
6307
6341
  } else if (path === "/dev/tty" || /^\/dev\/tty\d+$/.test(path)) {
6308
6342
  fd = openTty?.call(this.kernel.sys, path === "/dev/tty" ? void 0 : path);
@@ -6313,12 +6347,12 @@ var init_wasi_fds = __esm({
6313
6347
  this.bump();
6314
6348
  return fd;
6315
6349
  }
6316
- openClipboard(openClipboard, oflags, rights) {
6350
+ openCharDevice(openDevice2, oflags, rights) {
6317
6351
  if (oflags & OFLAGS.DIRECTORY) throw new WasiError("ENOTDIR");
6318
6352
  if (oflags & OFLAGS.CREAT && oflags & OFLAGS.EXCL) throw new WasiError("EEXIST");
6319
6353
  const want = wantOf2(oflags, rights);
6320
6354
  const flags = want === 6 ? O_RDWR4 : want === 2 ? O_WRONLY4 : 0;
6321
- return openClipboard.call(this.kernel.sys, flags);
6355
+ return openDevice2.call(this.kernel.sys, flags);
6322
6356
  }
6323
6357
  open(path, oflags, rights, fdflags) {
6324
6358
  const device2 = deviceOf(path);
@@ -6904,7 +6938,7 @@ var init_wasi_host = __esm({
6904
6938
  }
6905
6939
  return path;
6906
6940
  };
6907
- const modeOf = (st) => (st.mode ?? 0) & 4095;
6941
+ const modeOf2 = (st) => (st.mode ?? 0) & 4095;
6908
6942
  const chown = (path, uid, gid, follow2) => {
6909
6943
  const { chown: own } = this.o.fs;
6910
6944
  if (!own) throw new WasiError("ENOSYS");
@@ -6983,7 +7017,7 @@ var init_wasi_host = __esm({
6983
7017
  fd_mode: (fd, out) => {
6984
7018
  const e = fds.get(fd);
6985
7019
  const kind = e.type === "kernel" ? fds.kind(fd, e) : void 0;
6986
- const mode = kind === "stream" ? S_IFIFO | 384 : kind === "sealed" || kind === "clipboard" ? SEALED_MODE : modeOf(this.o.fs.stat(pathOf(fd)));
7020
+ const mode = kind === "stream" ? S_IFIFO | 384 : kind === "sealed" || kind === "clipboard" ? SEALED_MODE : modeOf2(this.o.fs.stat(pathOf(fd)));
6987
7021
  mem.view().setUint32(out, mode, true);
6988
7022
  },
6989
7023
  path_mode: (dirfd, p, l, flags, out) => {
@@ -6991,7 +7025,7 @@ var init_wasi_host = __esm({
6991
7025
  if (this.synthetic(path) && deviceOf(path) === void 0)
6992
7026
  return void mem.view().setUint32(out, SEALED_MODE, true);
6993
7027
  const st = flags & AT_SYMLINK_NOFOLLOW2 ? this.o.fs.lstat(path) : this.o.fs.stat(path);
6994
- mem.view().setUint32(out, modeOf(st), true);
7028
+ mem.view().setUint32(out, modeOf2(st), true);
6995
7029
  }
6996
7030
  });
6997
7031
  }
@@ -8005,7 +8039,7 @@ function importsContext({
8005
8039
  }
8006
8040
  function processes(host, call2, inThread) {
8007
8041
  const close = (fd) => void call2({ op: "fd-close", fd });
8008
- const slot = (n, how, mine, theirs) => {
8042
+ const slot2 = (n, how, mine, theirs) => {
8009
8043
  if (how === "inherit") return { fd: n };
8010
8044
  if (how === "null") return { none: true };
8011
8045
  const [read2, write2] = call2({ op: "fd-pipe" });
@@ -8019,7 +8053,7 @@ function processes(host, call2, inThread) {
8019
8053
  const theirs = [];
8020
8054
  host.fds.promoteFiles();
8021
8055
  try {
8022
- const stdio = STDIO.map((name2, n) => slot(n, o[name2] ?? "inherit", mine, theirs));
8056
+ const stdio = STDIO.map((name2, n) => slot2(n, o[name2] ?? "inherit", mine, theirs));
8023
8057
  const req = {
8024
8058
  op: "proc-spawn",
8025
8059
  file: o.argv[0],
@@ -11088,6 +11122,12 @@ var init_async_sab = __esm({
11088
11122
  });
11089
11123
 
11090
11124
  // src/process/js/js-kernel.ts
11125
+ function modeOf(mode) {
11126
+ if (!Number.isInteger(mode) || mode < 0 || mode > 4095) {
11127
+ throw new JsCallError("EINVAL", "chmod");
11128
+ }
11129
+ return mode;
11130
+ }
11091
11131
  function callError(result, op) {
11092
11132
  const { errno: errno2, message: message2 } = result;
11093
11133
  const detailed = typeof message2 === "string" && message2 !== errno2 && DETAILED.has(op);
@@ -11341,7 +11381,7 @@ function writable(io, fd) {
11341
11381
  abort: () => io.close(fd)
11342
11382
  });
11343
11383
  }
11344
- function childOps(kernel, io, defaults) {
11384
+ function childOps(kernel, io, defaults, sync) {
11345
11385
  const wait2 = async (pid) => {
11346
11386
  const r = await kernel.blocking({ op: "proc-wait", pid, nohang: false });
11347
11387
  const [, status2] = r.ok && r.kind === "json" ? r.json : [0, 0];
@@ -11361,25 +11401,43 @@ function childOps(kernel, io, defaults) {
11361
11401
  kill: (signal) => kill(pid, signal)
11362
11402
  };
11363
11403
  };
11364
- const spawn = async (o) => {
11404
+ const request = (o) => {
11365
11405
  const [file] = o.argv;
11366
11406
  if (file === void 0) throw new JsCallError("EINVAL", "spawn");
11367
11407
  const group = groupOf(o, "spawn");
11368
11408
  const named = argv0Of(o.argv0, "spawn");
11409
+ return (stdio) => ({
11410
+ op: "proc-spawn",
11411
+ file,
11412
+ argv: [...o.argv],
11413
+ ...named,
11414
+ env: { ...o.env ?? defaults.env },
11415
+ cwd: o.cwd ?? defaults.cwd,
11416
+ stdio,
11417
+ ...group
11418
+ });
11419
+ };
11420
+ const spawnSync = (o) => {
11421
+ const spawning = request(o);
11422
+ const mine = [];
11423
+ const theirs = [];
11424
+ try {
11425
+ const stdio = slotsSync(sync, o, mine, theirs);
11426
+ return childOf(sync.json(spawning(stdio)), mine);
11427
+ } catch (err) {
11428
+ closeAllSync(sync, mine);
11429
+ throw err;
11430
+ } finally {
11431
+ closeAllSync(sync, theirs);
11432
+ }
11433
+ };
11434
+ const spawn = async (o) => {
11435
+ const spawning = request(o);
11369
11436
  const mine = [];
11370
11437
  const theirs = [];
11371
11438
  try {
11372
11439
  const stdio = await slots2(kernel, o, mine, theirs);
11373
- const pid = await kernel.json({
11374
- op: "proc-spawn",
11375
- file,
11376
- argv: [...o.argv],
11377
- ...named,
11378
- env: { ...o.env ?? defaults.env },
11379
- cwd: o.cwd ?? defaults.cwd,
11380
- stdio,
11381
- ...group
11382
- });
11440
+ const pid = await kernel.json(spawning(stdio));
11383
11441
  return childOf(pid, mine);
11384
11442
  } catch (err) {
11385
11443
  await closeAll(io, mine);
@@ -11388,7 +11446,7 @@ function childOps(kernel, io, defaults) {
11388
11446
  await closeAll(io, theirs);
11389
11447
  }
11390
11448
  };
11391
- return { spawn, wait: wait2, kill };
11449
+ return { spawn, wait: wait2, kill, spawnSync };
11392
11450
  }
11393
11451
  function groupOf(o, call2) {
11394
11452
  const { pgid, session } = o;
@@ -11407,27 +11465,43 @@ function argv0Of(argv0, call2) {
11407
11465
  async function closeAll(io, fds) {
11408
11466
  for (const fd of fds) if (fd !== void 0) await io.close(fd).catch(() => void 0);
11409
11467
  }
11410
- async function preflight(kernel, hows) {
11468
+ function closeAllSync(sync, fds) {
11469
+ for (const fd of fds) if (fd !== void 0) sync.raw({ op: "fd-close", fd });
11470
+ }
11471
+ function checked(hows) {
11472
+ const fds = [];
11411
11473
  for (const [n, how] of hows.entries()) {
11412
11474
  if (how === "pipe" || how === "null") continue;
11413
11475
  if (how !== "inherit" && typeof how !== "number") throw new JsCallError("EINVAL", "spawn");
11414
- await kernel.json({ op: "fd-info", fd: how === "inherit" ? n : how });
11476
+ fds.push(how === "inherit" ? n : how);
11415
11477
  }
11478
+ return fds;
11479
+ }
11480
+ async function preflight(kernel, hows) {
11481
+ for (const fd of checked(hows)) await kernel.json({ op: "fd-info", fd });
11482
+ }
11483
+ function slot(n, how, pipe, mine, theirs) {
11484
+ if (how === "inherit") return { fd: n };
11485
+ if (how === "null") return { none: true };
11486
+ if (typeof how === "number") return { fd: how };
11487
+ const [read2, write2] = pipe();
11488
+ mine[n] = n === 0 ? write2 : read2;
11489
+ theirs.push(n === 0 ? read2 : write2);
11490
+ return { fd: n === 0 ? read2 : write2 };
11491
+ }
11492
+ function slotsSync(sync, o, mine, theirs) {
11493
+ const hows = STDIO2.map((name2) => o[name2] ?? "inherit");
11494
+ for (const fd of checked(hows)) sync.json({ op: "fd-info", fd });
11495
+ const pipe = () => sync.json({ op: "fd-pipe" });
11496
+ return hows.map((how, n) => slot(n, how, pipe, mine, theirs));
11416
11497
  }
11417
11498
  async function slots2(kernel, o, mine, theirs) {
11418
11499
  const hows = STDIO2.map((name2) => o[name2] ?? "inherit");
11419
11500
  await preflight(kernel, hows);
11420
11501
  const stdio = [];
11421
11502
  for (const [n, how] of hows.entries()) {
11422
- if (how === "inherit") stdio.push({ fd: n });
11423
- else if (how === "null") stdio.push({ none: true });
11424
- else if (typeof how === "number") stdio.push({ fd: how });
11425
- else {
11426
- const [read2, write2] = await kernel.json({ op: "fd-pipe" });
11427
- mine[n] = n === 0 ? write2 : read2;
11428
- theirs.push(n === 0 ? read2 : write2);
11429
- stdio.push({ fd: n === 0 ? read2 : write2 });
11430
- }
11503
+ const pair = how === "pipe" ? await kernel.json({ op: "fd-pipe" }) : [];
11504
+ stdio.push(slot(n, how, () => pair, mine, theirs));
11431
11505
  }
11432
11506
  return stdio;
11433
11507
  }
@@ -11693,6 +11767,10 @@ function* aliasOf(fd, abs, o) {
11693
11767
  }
11694
11768
  return { fd: copy2, file };
11695
11769
  }
11770
+ function accessFlags(o) {
11771
+ const write2 = o.write === true || o.append === true || o.truncate === true;
11772
+ return write2 ? o.read === true ? 2 : 1 : 0;
11773
+ }
11696
11774
  function* opened(abs, o) {
11697
11775
  const node = yield* lookup(abs);
11698
11776
  if (isExclusive(o)) throw new JsCallError("EEXIST", abs);
@@ -11701,13 +11779,13 @@ function* opened(abs, o) {
11701
11779
  return { fd: yield openRequest(abs, { ...o, create: false }), file: false };
11702
11780
  case "tty":
11703
11781
  return { fd: yield { op: "fd-open-tty" }, file: false };
11704
- case "clipboard": {
11705
- const write2 = o.write === true || o.append === true || o.truncate === true;
11706
- const flags = write2 ? o.read === true ? 2 : 1 : 0;
11707
- return { fd: yield { op: "fd-open-clipboard", flags }, file: false };
11708
- }
11782
+ case "clipboard":
11783
+ return {
11784
+ fd: yield { op: "fd-open-clipboard", flags: accessFlags(o) },
11785
+ file: false
11786
+ };
11709
11787
  case "sealed":
11710
- return { fd: yield { op: "fd-open-sealed" }, file: false };
11788
+ return { fd: yield { op: "fd-open-sealed", flags: accessFlags(o) }, file: false };
11711
11789
  case "terminal": {
11712
11790
  const req = node.pts === void 0 ? { op: "fd-open-tty", name: node.name } : { op: "pty-slave-open", n: node.pts, noctty: true };
11713
11791
  return { fd: yield req, file: false };
@@ -12700,10 +12778,15 @@ function syncPathOps(kernel, resolve, statOf, open) {
12700
12778
  if (inDev(abs)) return devSync(kernel, devReaddir(abs));
12701
12779
  return kernel.json({ op: "readdir", path: abs });
12702
12780
  },
12703
- mkdir: (path) => void kernel.call({ op: "mkdir", path: resolve(path) }),
12781
+ mkdir: (path, options) => void kernel.call({
12782
+ op: "mkdir",
12783
+ path: resolve(path),
12784
+ ...options?.recursive === false ? { exclusive: true } : {}
12785
+ }),
12704
12786
  rm: (path) => void kernel.call({ op: "rm", path: resolve(path) }),
12705
12787
  unlink: (path) => void kernel.call({ op: "unlink", path: resolve(path) }),
12706
12788
  rename: (from, to) => void kernel.call({ op: "rename", path: resolve(from), arg2: resolve(to) }),
12789
+ chmod: (path, mode) => void kernel.call({ op: "chmod", path: resolve(path), mode: modeOf(mode) }),
12707
12790
  link: (from, to) => void kernel.call({ op: "link", path: resolve(from), arg2: resolve(to) }),
12708
12791
  symlink: (target, path) => void kernel.call({ op: "symlink", path: resolve(path), arg2: target }),
12709
12792
  readlink(path) {
@@ -13199,6 +13282,7 @@ function createContext(o) {
13199
13282
  const sync = {
13200
13283
  ...syncOps(syncKernel, { pid: o.pid, resolve, random, infos, handles }),
13201
13284
  run: (options) => runSync(syncKernel, { env: o.env, cwd: o.cwd, resolve, signal: signalNumber }, options),
13285
+ spawn: (options) => spawnSync(options),
13202
13286
  exit: (status2 = 0) => {
13203
13287
  exiting ??= status2 & 255;
13204
13288
  return exitAtOnce(lane, [...writes], terminal.modes(), exiting);
@@ -13206,12 +13290,15 @@ function createContext(o) {
13206
13290
  kill: killer({ self: o.pid, kernel, syncKernel, lane, writes, modes: terminal.modes }),
13207
13291
  cred: () => syncKernel.json({ op: "proc-cred" }),
13208
13292
  setcred(change) {
13209
- if (typeof change !== "object" || change === null) throw new JsCallError("EINVAL", "setcred");
13293
+ if (typeof change !== "object" || change === null || Array.isArray(change)) {
13294
+ throw new JsCallError("EINVAL", "setcred");
13295
+ }
13210
13296
  return syncKernel.json({ op: "proc-setcred", change: { ...change } });
13211
13297
  }
13212
13298
  };
13213
13299
  const io = { read: read2, send: writeAll, close: (fd) => ctx.close(fd) };
13214
- const children = childOps(kernel, io, { env: o.env, cwd: o.cwd, signal: signalNumber });
13300
+ const defaults = { env: o.env, cwd: o.cwd, signal: signalNumber };
13301
+ const { spawnSync, ...children } = childOps(kernel, io, defaults, syncKernel);
13215
13302
  const strays = o.strays ?? { exception: /* @__PURE__ */ new Set(), rejection: /* @__PURE__ */ new Set() };
13216
13303
  const ctx = {
13217
13304
  argv: o.argv,
@@ -13402,10 +13489,15 @@ function pathOps(kernel, resolve, statOf, open) {
13402
13489
  if (inDev(abs)) return devAsync(kernel, devReaddir(abs));
13403
13490
  return await kernel.json({ op: "readdir", path: abs });
13404
13491
  },
13405
- mkdir: async (path) => void await kernel.call({ op: "mkdir", path: resolve(path) }),
13492
+ mkdir: async (path, options) => void await kernel.call({
13493
+ op: "mkdir",
13494
+ path: resolve(path),
13495
+ ...options?.recursive === false ? { exclusive: true } : {}
13496
+ }),
13406
13497
  rm: async (path) => void await kernel.call({ op: "rm", path: resolve(path) }),
13407
13498
  unlink: async (path) => void await kernel.call({ op: "unlink", path: resolve(path) }),
13408
13499
  rename: async (from, to) => void await kernel.call({ op: "rename", path: resolve(from), arg2: resolve(to) }),
13500
+ chmod: async (path, mode) => void await kernel.call({ op: "chmod", path: resolve(path), mode: modeOf(mode) }),
13409
13501
  link: async (from, to) => void await kernel.call({ op: "link", path: resolve(from), arg2: resolve(to) }),
13410
13502
  symlink: async (target, path) => void await kernel.call({ op: "symlink", path: resolve(path), arg2: target }),
13411
13503
  async readlink(path) {