@ai-ecoverse/slicc-kernel 1.73.3 → 1.75.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.
@@ -1343,7 +1343,7 @@ function promoteRequest(fd, f, handed) {
1343
1343
  ...f.buffer.handle !== void 0 ? { handle: f.buffer.handle } : {}
1344
1344
  };
1345
1345
  }
1346
- var SYNTHETIC_DIRS, O_NONBLOCK, O_WRONLY, O_RDWR, O_APPEND, SEALED_PATH, WasiFds, GEN;
1346
+ var SYNTHETIC_DIRS, O_NONBLOCK, O_WRONLY, O_RDWR, O_APPEND, SEALED_PATH, CLIPBOARD_PATH, WasiFds, GEN;
1347
1347
  var init_wasi_fds = __esm({
1348
1348
  "src/process/wasi/wasi-fds.ts"() {
1349
1349
  "use strict";
@@ -1357,6 +1357,7 @@ var init_wasi_fds = __esm({
1357
1357
  O_RDWR = 2;
1358
1358
  O_APPEND = 1024;
1359
1359
  SEALED_PATH = "/dev/sealed";
1360
+ CLIPBOARD_PATH = "/dev/clipboard";
1360
1361
  WasiFds = class {
1361
1362
  table = /* @__PURE__ */ new Map();
1362
1363
  buffers = /* @__PURE__ */ new Map();
@@ -1657,9 +1658,12 @@ var init_wasi_fds = __esm({
1657
1658
  const e = this.get(fd);
1658
1659
  this.table.delete(fd);
1659
1660
  this.cloexec.delete(fd);
1660
- this.kernel.sys.close(fd);
1661
- this.release(e);
1662
- this.bump();
1661
+ try {
1662
+ this.kernel.sys.close(fd);
1663
+ } finally {
1664
+ this.release(e);
1665
+ this.bump();
1666
+ }
1663
1667
  }
1664
1668
  renumber(from, to, keep = false) {
1665
1669
  const e = this.get(from);
@@ -1822,8 +1826,8 @@ var init_wasi_fds = __esm({
1822
1826
  const joined2 = path.startsWith("/") ? path : `${this.dir(dirfd).path}/${path}`;
1823
1827
  return joined2.split("/").includes("..") ? physical(this.fs, joined2) : normalize(joined2);
1824
1828
  }
1825
- openKernelDevice(path, oflags, fdflags) {
1826
- const { openSealed, openTty } = this.kernel.sys;
1829
+ openKernelDevice(path, oflags, fdflags, rights) {
1830
+ const { openSealed, openClipboard, openTty } = this.kernel.sys;
1827
1831
  const nonblock = (fdflags & FDFLAGS.NONBLOCK) !== 0;
1828
1832
  let fd;
1829
1833
  let kind;
@@ -1832,6 +1836,9 @@ var init_wasi_fds = __esm({
1832
1836
  if (oflags & OFLAGS.CREAT && oflags & OFLAGS.EXCL) throw new WasiError("EEXIST");
1833
1837
  fd = openSealed.call(this.kernel.sys);
1834
1838
  kind = "sealed";
1839
+ } else if (path === CLIPBOARD_PATH && openClipboard) {
1840
+ fd = this.openClipboard(openClipboard, oflags, rights);
1841
+ kind = "clipboard";
1835
1842
  } else if (path === "/dev/tty" || /^\/dev\/tty\d+$/.test(path)) {
1836
1843
  fd = openTty?.call(this.kernel.sys, path === "/dev/tty" ? void 0 : path);
1837
1844
  if (fd === void 0) throw new WasiError("ENXIO");
@@ -1841,10 +1848,17 @@ var init_wasi_fds = __esm({
1841
1848
  this.bump();
1842
1849
  return fd;
1843
1850
  }
1851
+ openClipboard(openClipboard, oflags, rights) {
1852
+ if (oflags & OFLAGS.DIRECTORY) throw new WasiError("ENOTDIR");
1853
+ if (oflags & OFLAGS.CREAT && oflags & OFLAGS.EXCL) throw new WasiError("EEXIST");
1854
+ const want = wantOf(oflags, rights);
1855
+ const flags = want === 6 ? O_RDWR : want === 2 ? O_WRONLY : 0;
1856
+ return openClipboard.call(this.kernel.sys, flags);
1857
+ }
1844
1858
  open(path, oflags, rights, fdflags) {
1845
1859
  const device2 = deviceOf(path);
1846
1860
  if (device2) return this.install({ type: "device", device: device2 });
1847
- const kernelDevice = this.openKernelDevice(path, oflags, fdflags);
1861
+ const kernelDevice = this.openKernelDevice(path, oflags, fdflags, rights);
1848
1862
  if (kernelDevice !== void 0) return kernelDevice;
1849
1863
  const alias = stdioAlias(path);
1850
1864
  if (alias !== void 0) return this.reopen(alias);
@@ -2287,6 +2301,7 @@ function kernelFiletype(kind) {
2287
2301
  switch (kind) {
2288
2302
  case "tty":
2289
2303
  case "sealed":
2304
+ case "clipboard":
2290
2305
  return { filetype: FILETYPE.CHARACTER_DEVICE, seeks: false };
2291
2306
  case "device":
2292
2307
  return { filetype: FILETYPE.CHARACTER_DEVICE, seeks: true };
@@ -2444,7 +2459,7 @@ var init_wasi_host = __esm({
2444
2459
  const e = fds.get(fd);
2445
2460
  if (e.type === "device") return ROOT_IDS;
2446
2461
  const kind = e.type === "kernel" ? fds.kind(fd, e) : "file";
2447
- if (kind === "sealed") return ROOT_IDS;
2462
+ if (kind === "sealed" || kind === "clipboard") return ROOT_IDS;
2448
2463
  if (kind !== "file") return void 0;
2449
2464
  try {
2450
2465
  return this.o.fs.stat(pathOf(fd));
@@ -2501,12 +2516,12 @@ var init_wasi_host = __esm({
2501
2516
  fd_mode: (fd, out) => {
2502
2517
  const e = fds.get(fd);
2503
2518
  const kind = e.type === "kernel" ? fds.kind(fd, e) : void 0;
2504
- const mode = kind === "stream" ? S_IFIFO | 384 : kind === "sealed" ? SEALED_MODE : modeOf(this.o.fs.stat(pathOf(fd)));
2519
+ const mode = kind === "stream" ? S_IFIFO | 384 : kind === "sealed" || kind === "clipboard" ? SEALED_MODE : modeOf(this.o.fs.stat(pathOf(fd)));
2505
2520
  mem.view().setUint32(out, mode, true);
2506
2521
  },
2507
2522
  path_mode: (dirfd, p, l, flags, out) => {
2508
2523
  const path = at(dirfd, p, l);
2509
- if (path === SEALED_PATH && this.o.kernel.sys.openSealed)
2524
+ if (this.synthetic(path) && deviceOf(path) === void 0)
2510
2525
  return void mem.view().setUint32(out, SEALED_MODE, true);
2511
2526
  const st = flags & AT_SYMLINK_NOFOLLOW ? this.o.fs.lstat(path) : this.o.fs.stat(path);
2512
2527
  mem.view().setUint32(out, modeOf(st), true);
@@ -3009,7 +3024,7 @@ var init_wasi_host = __esm({
3009
3024
  return gone ? { ...out, nlink: 0n } : out;
3010
3025
  }
3011
3026
  synthetic(path) {
3012
- return deviceOf(path) !== void 0 || path === SEALED_PATH && !!this.o.kernel.sys.openSealed;
3027
+ return deviceOf(path) !== void 0 || path === SEALED_PATH && !!this.o.kernel.sys.openSealed || path === CLIPBOARD_PATH && !!this.o.kernel.sys.openClipboard;
3013
3028
  }
3014
3029
  pathFilestat(path, lookup2) {
3015
3030
  if (this.synthetic(path)) {
@@ -3737,6 +3752,11 @@ var init_signals = __esm({
3737
3752
  });
3738
3753
 
3739
3754
  // src/process/js/js-kernel.ts
3755
+ function callError(result, op) {
3756
+ const { errno: errno2, message: message2 } = result;
3757
+ const detailed = typeof message2 === "string" && message2 !== errno2 && DETAILED.has(op);
3758
+ return new JsCallError(errno2, detailed ? `${op}: ${message2}` : op);
3759
+ }
3740
3760
  function untilAborted(work, signal) {
3741
3761
  if (!signal) return work;
3742
3762
  return new Promise((resolve) => {
@@ -3753,7 +3773,7 @@ function caughtOf(handlers) {
3753
3773
  for (const sig of handlers.keys()) caught |= sigbit(sig);
3754
3774
  return caught;
3755
3775
  }
3756
- var JsCallError, JsKernel;
3776
+ var JsCallError, DETAILED, JsKernel;
3757
3777
  var init_js_kernel = __esm({
3758
3778
  "src/process/js/js-kernel.ts"() {
3759
3779
  "use strict";
@@ -3768,6 +3788,12 @@ var init_js_kernel = __esm({
3768
3788
  this.code = code2;
3769
3789
  }
3770
3790
  };
3791
+ DETAILED = /* @__PURE__ */ new Set([
3792
+ "fd-read",
3793
+ "fd-write",
3794
+ "fd-close",
3795
+ "fd-open-clipboard"
3796
+ ]);
3771
3797
  JsKernel = class {
3772
3798
  header;
3773
3799
  transport;
@@ -3794,7 +3820,7 @@ var init_js_kernel = __esm({
3794
3820
  }
3795
3821
  async call(req) {
3796
3822
  const result = await this.raw(req);
3797
- if (!result.ok) throw new JsCallError(result.errno, req.op);
3823
+ if (!result.ok) throw callError(result, req.op);
3798
3824
  return result;
3799
3825
  }
3800
3826
  async json(req) {
@@ -3810,7 +3836,7 @@ var init_js_kernel = __esm({
3810
3836
  const id = await this.submit(req, track);
3811
3837
  const result = await this.settled(id, signal);
3812
3838
  if (result.ok) return result;
3813
- if (result.errno !== "EINTR") throw new JsCallError(result.errno, req.op);
3839
+ if (result.errno !== "EINTR") throw callError(result, req.op);
3814
3840
  }
3815
3841
  }
3816
3842
  acks = [];
@@ -4002,6 +4028,7 @@ function childOps(kernel, io, defaults) {
4002
4028
  const spawn = async (o) => {
4003
4029
  const [file] = o.argv;
4004
4030
  if (file === void 0) throw new JsCallError("EINVAL", "spawn");
4031
+ const group = groupOf(o, "spawn");
4005
4032
  const mine = [];
4006
4033
  const theirs = [];
4007
4034
  try {
@@ -4012,7 +4039,8 @@ function childOps(kernel, io, defaults) {
4012
4039
  argv: [...o.argv],
4013
4040
  env: { ...o.env ?? defaults.env },
4014
4041
  cwd: o.cwd ?? defaults.cwd,
4015
- stdio
4042
+ stdio,
4043
+ ...group
4016
4044
  });
4017
4045
  return childOf(pid, mine);
4018
4046
  } catch (err) {
@@ -4024,6 +4052,15 @@ function childOps(kernel, io, defaults) {
4024
4052
  };
4025
4053
  return { spawn, wait: wait2, kill };
4026
4054
  }
4055
+ function groupOf(o, call2) {
4056
+ const { pgid, session } = o;
4057
+ const valid = pgid === void 0 || Number.isInteger(pgid) && pgid >= 0;
4058
+ if (!valid || session !== void 0 && typeof session !== "boolean") {
4059
+ throw new JsCallError("EINVAL", call2);
4060
+ }
4061
+ if (session && pgid !== void 0) throw new JsCallError("EINVAL", call2);
4062
+ return session ? { session: true } : pgid !== void 0 ? { pgid } : {};
4063
+ }
4027
4064
  async function closeAll(io, fds) {
4028
4065
  for (const fd of fds) if (fd !== void 0) await io.close(fd).catch(() => void 0);
4029
4066
  }
@@ -4179,6 +4216,7 @@ function* lookup(abs) {
4179
4216
  const name2 = abs.slice("/dev/".length);
4180
4217
  if (DEVICES.includes(name2)) return { kind: "device" };
4181
4218
  if (name2 === "tty") return { kind: "tty" };
4219
+ if (name2 === "clipboard") return { kind: "clipboard" };
4182
4220
  const std = STDIO3.indexOf(name2);
4183
4221
  if (std >= 0) return { kind: "link", target: `${SELF_FD}/${std}`, fd: std };
4184
4222
  if (name2 === "fd") return { kind: "link", target: SELF_FD };
@@ -4222,7 +4260,8 @@ function* fdStat(fd, path) {
4222
4260
  return yield* pathStat(file.path);
4223
4261
  }
4224
4262
  if (info.terminal) return yield* terminalStat(info.terminal);
4225
- if (info.kind === "device" || info.kind === "tty") return nodeStat(CHAR | 438);
4263
+ if (info.kind === "device" || info.kind === "tty" || info.kind === "clipboard")
4264
+ return nodeStat(CHAR | 438);
4226
4265
  if (info.kind === "socket") return nodeStat(49663);
4227
4266
  return nodeStat(4480);
4228
4267
  }
@@ -4232,6 +4271,7 @@ function* fdTarget(fd, path) {
4232
4271
  if (info.kind === "file") return (yield { op: "fd-vfs-stat", fd }).path;
4233
4272
  if (info.terminal) return info.terminal;
4234
4273
  if (info.meta && "device" in info.meta) return `/dev/${info.meta.device}`;
4274
+ if (info.kind === "clipboard") return "/dev/clipboard";
4235
4275
  return `${info.kind === "socket" ? "socket" : "pipe"}:[${fd}]`;
4236
4276
  }
4237
4277
  function linkStat(target) {
@@ -4244,6 +4284,7 @@ function* devStat(abs, follow2) {
4244
4284
  return nodeStat(node.mode);
4245
4285
  case "device":
4246
4286
  case "tty":
4287
+ case "clipboard":
4247
4288
  return nodeStat(CHAR | 438);
4248
4289
  case "terminal":
4249
4290
  return yield* terminalStat(node.name);
@@ -4278,7 +4319,7 @@ function* devReaddir(abs) {
4278
4319
  if (node.kind !== "dir") throw new JsCallError("ENOTDIR", abs);
4279
4320
  const names = yield { op: "fd-tty-names" };
4280
4321
  const ttys = names.filter((n) => /^\/dev\/tty\d+$/.test(n)).map((n) => n.slice(5));
4281
- return [...DEVICES, "tty", "fd", ...STDIO3, ...ttys].sort();
4322
+ return [...DEVICES, "clipboard", "tty", "fd", ...STDIO3, ...ttys].sort();
4282
4323
  }
4283
4324
  function* aliasOf(fd, abs, o) {
4284
4325
  const info = yield* fdInfo(fd, abs);
@@ -4307,6 +4348,11 @@ function* opened(abs, o) {
4307
4348
  return { fd: yield openRequest(abs, { ...o, create: false }), file: false };
4308
4349
  case "tty":
4309
4350
  return { fd: yield { op: "fd-open-tty" }, file: false };
4351
+ case "clipboard": {
4352
+ const write2 = o.write === true || o.append === true || o.truncate === true;
4353
+ const flags = write2 ? o.read === true ? 2 : 1 : 0;
4354
+ return { fd: yield { op: "fd-open-clipboard", flags }, file: false };
4355
+ }
4310
4356
  case "terminal": {
4311
4357
  const req = node.pts === void 0 ? { op: "fd-open-tty", name: node.name } : { op: "pty-slave-open", n: node.pts, noctty: true };
4312
4358
  return { fd: yield req, file: false };
@@ -5080,6 +5126,7 @@ function decodeRun(bytes, stdout, stderr) {
5080
5126
  function runSync(kernel, d, o) {
5081
5127
  const [file] = o.argv;
5082
5128
  if (file === void 0) throw new JsCallError("EINVAL", "run");
5129
+ const group = groupOf(o, "run");
5083
5130
  const stdout = stdioOf(o.stdout);
5084
5131
  const stderr = stderrOf(o.stderr);
5085
5132
  const input = typeof o.input === "string" ? encoder2.encode(o.input) : o.input;
@@ -5091,6 +5138,7 @@ function runSync(kernel, d, o) {
5091
5138
  argv: [...o.argv],
5092
5139
  env: { ...o.env ?? d.env },
5093
5140
  cwd: o.cwd === void 0 ? d.cwd : d.resolve(o.cwd),
5141
+ ...group,
5094
5142
  stdin: stdioOf(o.stdin),
5095
5143
  ...input ? { input } : {},
5096
5144
  stdout,
@@ -5106,6 +5154,7 @@ var encoder2, STDIO4;
5106
5154
  var init_js_run = __esm({
5107
5155
  "src/process/js/js-run.ts"() {
5108
5156
  "use strict";
5157
+ init_js_children();
5109
5158
  init_js_kernel();
5110
5159
  encoder2 = new TextEncoder();
5111
5160
  STDIO4 = /* @__PURE__ */ new Set(["pipe", "ignore", "inherit"]);
@@ -5604,7 +5653,7 @@ var init_js_sync = __esm({
5604
5653
  }
5605
5654
  call(req) {
5606
5655
  const result = this.raw(req);
5607
- if (!result.ok) throw new JsCallError(result.errno, req.op);
5656
+ if (!result.ok) throw callError(result, req.op);
5608
5657
  return result;
5609
5658
  }
5610
5659
  json(req) {
@@ -5619,7 +5668,7 @@ var init_js_sync = __esm({
5619
5668
  for (; ; ) {
5620
5669
  const result = this.raw(req);
5621
5670
  if (result.ok) return result;
5622
- if (result.errno !== "EINTR") throw new JsCallError(result.errno, req.op);
5671
+ if (result.errno !== "EINTR") throw callError(result, req.op);
5623
5672
  }
5624
5673
  }
5625
5674
  };
@@ -6211,7 +6260,7 @@ async function receiveSome(kernel, fd, max, signal) {
6211
6260
  signal.throwIfAborted();
6212
6261
  const r = await kernel.raw({ op: "fd-read", fd, max, nonblock: true });
6213
6262
  if (r.ok) return r.kind === "bytes" ? r.bytes : new Uint8Array(0);
6214
- if (r.errno !== "EAGAIN") throw new JsCallError(r.errno, "fd-read");
6263
+ if (r.errno !== "EAGAIN") throw callError(r, "fd-read");
6215
6264
  await kernel.blocking({ op: "fd-select", read: [fd], write: [], timeoutMs: -1 }, signal);
6216
6265
  }
6217
6266
  }
@@ -6220,7 +6269,7 @@ async function sendSome(kernel, fd, body, signal) {
6220
6269
  signal.throwIfAborted();
6221
6270
  const r = await kernel.raw({ op: "fd-write", fd, body, nonblock: true });
6222
6271
  if (r.ok) return written(r, body.length);
6223
- if (r.errno !== "EAGAIN") throw new JsCallError(r.errno, "fd-write");
6272
+ if (r.errno !== "EAGAIN") throw callError(r, "fd-write");
6224
6273
  await kernel.blocking({ op: "fd-select", read: [], write: [fd], timeoutMs: -1 }, signal);
6225
6274
  }
6226
6275
  }
@@ -7394,7 +7443,7 @@ function ptyStat(path) {
7394
7443
  ctime: now
7395
7444
  };
7396
7445
  }
7397
- function sealedStat() {
7446
+ function sealedStat(minor = 250) {
7398
7447
  const now = /* @__PURE__ */ new Date();
7399
7448
  return {
7400
7449
  dev: 22,
@@ -7403,7 +7452,7 @@ function sealedStat() {
7403
7452
  nlink: 1,
7404
7453
  uid: 0,
7405
7454
  gid: 0,
7406
- rdev: 10 << 8 | 250,
7455
+ rdev: 10 << 8 | minor,
7407
7456
  size: 0,
7408
7457
  blksize: 4096,
7409
7458
  blocks: 0,
@@ -7415,7 +7464,7 @@ function sealedStat() {
7415
7464
  function nonblocking(stream) {
7416
7465
  return (stream.flags & O_NONBLOCK2) !== 0 ? { nonblock: true } : void 0;
7417
7466
  }
7418
- 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;
7467
+ var POLLIN, POLLOUT, POLLERR, POLLHUP, POLLRDNORM, POLLWRNORM, TCSETSF, O_NONBLOCK2, SOCKET_MODE, PTY_PATH, TTY_PATH, TTY_NAME, SEALED_PATH2, STRERROR, CLIPBOARD_PATH2, O_CREAT, O_EXCL, O_NOCTTY, O_TRUNC2, KILLED_BY_SIGPIPE, ProcessExit, SyscallError, KernelStreams;
7419
7468
  var init_kernel_streams = __esm({
7420
7469
  "src/process/kernel-streams.ts"() {
7421
7470
  "use strict";
@@ -7433,6 +7482,16 @@ var init_kernel_streams = __esm({
7433
7482
  TTY_PATH = /^\/dev\/tty\d+$/;
7434
7483
  TTY_NAME = /^tty\d+$/;
7435
7484
  SEALED_PATH2 = "/dev/sealed";
7485
+ STRERROR = {
7486
+ EACCES: "Permission denied",
7487
+ EIO: "I/O error",
7488
+ ENOTSUP: "Not supported",
7489
+ EOPNOTSUPP: "Not supported",
7490
+ EFBIG: "File too large",
7491
+ EILSEQ: "Illegal byte sequence",
7492
+ EINTR: "Interrupted system call"
7493
+ };
7494
+ CLIPBOARD_PATH2 = "/dev/clipboard";
7436
7495
  O_CREAT = 64;
7437
7496
  O_EXCL = 128;
7438
7497
  O_NOCTTY = 256;
@@ -7508,10 +7567,64 @@ var init_kernel_streams = __esm({
7508
7567
  }
7509
7568
  listSealed() {
7510
7569
  const { analyzePath, mkdev, makedev } = this.Fs;
7511
- if (!this.sys.openSealed || !analyzePath || !mkdev || !makedev) return;
7512
- if (analyzePath.call(this.Fs, SEALED_PATH2).exists) return;
7570
+ if (!analyzePath || !mkdev || !makedev) return;
7571
+ const nodes = [
7572
+ [SEALED_PATH2, 250, this.sys.openSealed],
7573
+ [CLIPBOARD_PATH2, 251, this.sys.openClipboard]
7574
+ ];
7575
+ for (const [path, minor, present] of nodes) {
7576
+ if (!present || analyzePath.call(this.Fs, path).exists) continue;
7577
+ try {
7578
+ mkdev.call(this.Fs, path, makedev.call(this.Fs, 10, minor));
7579
+ } catch {
7580
+ }
7581
+ }
7582
+ }
7583
+ reporting = /* @__PURE__ */ new Set();
7584
+ reportClose(kfd) {
7585
+ this.reporting.add(kfd);
7586
+ }
7587
+ quitting = false;
7588
+ atExit = false;
7589
+ failedAtExit = false;
7590
+ committed = /* @__PURE__ */ new Set();
7591
+ exiting() {
7592
+ this.atExit = true;
7593
+ return () => {
7594
+ this.atExit = false;
7595
+ };
7596
+ }
7597
+ commitStdout() {
7598
+ const kfd = this.Fs.getStream(1)?.sliccKernelFd;
7599
+ if (kfd === void 0 || !this.reporting.delete(kfd)) return;
7600
+ this.committed.add(kfd);
7513
7601
  try {
7514
- mkdev.call(this.Fs, SEALED_PATH2, makedev.call(this.Fs, 10, 250));
7602
+ this.sys.close(kfd);
7603
+ } catch (e) {
7604
+ if (e instanceof SyscallError) this.stdoutFailed(e.code);
7605
+ }
7606
+ }
7607
+ exitStatus(status2) {
7608
+ return this.failedAtExit && status2 === 0 ? 1 : status2;
7609
+ }
7610
+ reportedClose(stream, kfd) {
7611
+ try {
7612
+ this.sys.close(kfd);
7613
+ } catch (e) {
7614
+ if (this.quitting && stream.fd === 1 && e instanceof SyscallError) this.stdoutFailed(e.code);
7615
+ this.call(() => {
7616
+ throw e;
7617
+ });
7618
+ }
7619
+ }
7620
+ stdoutFailed(code2) {
7621
+ this.failedAtExit = true;
7622
+ const stderr = this.Fs.getStream(2)?.sliccKernelFd;
7623
+ if (stderr === void 0) return;
7624
+ const line = `${this.options.program ?? "program"}: write error: ${STRERROR[code2] ?? code2}
7625
+ `;
7626
+ try {
7627
+ this.sys.write(stderr, new TextEncoder().encode(line));
7515
7628
  } catch {
7516
7629
  }
7517
7630
  }
@@ -7614,7 +7727,7 @@ var init_kernel_streams = __esm({
7614
7727
  if (device2 !== void 0 && TTY_PATH.test(device2) && !this.terminalExists(device2)) {
7615
7728
  throw new this.Fs.ErrnoError(wasiErrno("ENOENT"));
7616
7729
  }
7617
- const pty = this.openPty(open, path, flags, mode) ?? this.openSealed(open, path, flags, mode);
7730
+ const pty = this.openPty(open, path, flags, mode) ?? this.openSealed(open, path, flags, mode) ?? this.openClipboard(open, path, flags, mode);
7618
7731
  if (pty) return pty;
7619
7732
  this.refuseExclusiveLink(path, flags);
7620
7733
  const stream = this.openRacing(open, path, flags, mode);
@@ -7680,6 +7793,14 @@ var init_kernel_streams = __esm({
7680
7793
  const kfd = this.call(() => openSealed.call(this.sys));
7681
7794
  return this.vessel(open, kfd, { path, flags, mode }, false);
7682
7795
  }
7796
+ openClipboard(open, path, flags, mode) {
7797
+ const { openClipboard } = this.sys;
7798
+ if (path !== CLIPBOARD_PATH2 || !openClipboard) return void 0;
7799
+ const kfd = this.call(() => openClipboard.call(this.sys, flags & 3));
7800
+ const stream = this.vessel(open, kfd, { path, flags, mode }, false);
7801
+ this.reportClose(kfd);
7802
+ return stream;
7803
+ }
7683
7804
  vessel(open, kfd, at, terminal) {
7684
7805
  let stream;
7685
7806
  try {
@@ -7704,6 +7825,7 @@ var init_kernel_streams = __esm({
7704
7825
  if (typeof original !== "function") continue;
7705
7826
  fs[name2] = (path, ...rest2) => {
7706
7827
  if (path === SEALED_PATH2 && this.sys.openSealed) return sealedStat();
7828
+ if (path === CLIPBOARD_PATH2 && this.sys.openClipboard) return sealedStat(251);
7707
7829
  const owned = this.ownedTty(path);
7708
7830
  if (owned && isPtyPath(path)) return this.owned(path, ptyStat(path));
7709
7831
  if (!isPtyPath(path)) {
@@ -7844,6 +7966,7 @@ var init_kernel_streams = __esm({
7844
7966
  this.refs.set(kfd, (this.refs.get(kfd) ?? 0) + 1);
7845
7967
  },
7846
7968
  close: (stream) => {
7969
+ if (this.atExit && stream.fd === 2 && this.reporting.size > 0) this.commitStdout();
7847
7970
  try {
7848
7971
  base.close?.(stream);
7849
7972
  } catch {
@@ -7854,6 +7977,11 @@ var init_kernel_streams = __esm({
7854
7977
  return;
7855
7978
  }
7856
7979
  this.refs.delete(kfd);
7980
+ if (this.committed.size > 0 && this.committed.delete(kfd)) return;
7981
+ if (this.reporting.size > 0 && this.reporting.delete(kfd)) {
7982
+ this.reportedClose(stream, kfd);
7983
+ return;
7984
+ }
7857
7985
  try {
7858
7986
  this.sys.close(kfd);
7859
7987
  } catch {
@@ -8701,7 +8829,7 @@ function place(Fs, stream, fd) {
8701
8829
  function placeholder(Fs, streams, entry) {
8702
8830
  if (entry.kind === "socket") return streams.socketStream(entry.flags ?? O_RDWR4);
8703
8831
  if (entry.kind === "tty") return Fs.open("/dev/tty", O_RDWR4);
8704
- if (entry.kind === "stream") return Fs.open("/dev/null", O_RDWR4);
8832
+ if (entry.kind === "stream" || entry.kind === "clipboard") return Fs.open("/dev/null", O_RDWR4);
8705
8833
  Fs.mkdirTree(PLACEHOLDER_DIR);
8706
8834
  return Fs.open(`${PLACEHOLDER_DIR}/${entry.fd}`, O_RDWR4 | O_CREAT3);
8707
8835
  }
@@ -8725,6 +8853,7 @@ function placeKernelStream(Fs, streams, entry) {
8725
8853
  streams.sizeFromKernel(stream, entry.kernel);
8726
8854
  } else if (entry.kind === "socket") streams.attachSocket(stream, entry.kernel);
8727
8855
  else streams.attach(stream, entry.kernel, entry.kind === "tty");
8856
+ if (entry.kind === "clipboard") streams.reportClose(entry.kernel);
8728
8857
  if (entry.kind === "tty") streams.nameTerminal(stream);
8729
8858
  if (entry.kind === "stream") {
8730
8859
  asFifo(stream, streams, entry.desc !== void 0 ? `d${entry.desc}` : `k${entry.kernel}`);
@@ -9865,6 +9994,9 @@ function kernelSys(transport) {
9865
9994
  openSealed() {
9866
9995
  return json2(call2({ op: "fd-open-sealed" }, "fd-open-sealed"));
9867
9996
  },
9997
+ openClipboard(flags) {
9998
+ return json2(call2({ op: "fd-open-clipboard", flags }, "fd-open-clipboard"));
9999
+ },
9868
10000
  ptyNumbers() {
9869
10001
  return json2(call2({ op: "pty-list" }, "pty-list"));
9870
10002
  },
@@ -10021,6 +10153,8 @@ async function runWasmProcess(init, port3, deps = {}) {
10021
10153
  let failed5;
10022
10154
  let memory;
10023
10155
  let exports;
10156
+ let atExit = () => () => {
10157
+ };
10024
10158
  const initialized = new Promise((resolve, reject) => {
10025
10159
  ready = resolve;
10026
10160
  failed5 = reject;
@@ -10062,7 +10196,10 @@ async function runWasmProcess(init, port3, deps = {}) {
10062
10196
  memory = wasmMemory(instance, imports);
10063
10197
  exports = instance.exports;
10064
10198
  publishMemory(init.sab, memory?.buffer.byteLength ?? 0);
10065
- done(instance, init.program.module);
10199
+ done(
10200
+ withExitHook(instance, () => atExit()),
10201
+ init.program.module
10202
+ );
10066
10203
  }, failed5);
10067
10204
  return {};
10068
10205
  },
@@ -10095,9 +10232,17 @@ async function runWasmProcess(init, port3, deps = {}) {
10095
10232
  const sigpipe = () => running.sliccSigpipe?.() === 1;
10096
10233
  const restartable = () => signals.restartable();
10097
10234
  const owners = init.owners ? { owners: true } : {};
10098
- const streams = new KernelStreams(running.FS, sys, { sigpipe, restartable, ...owners });
10235
+ const streams = new KernelStreams(running.FS, sys, {
10236
+ sigpipe,
10237
+ restartable,
10238
+ ...owners,
10239
+ program: init.argv0
10240
+ });
10099
10241
  trackCloseOnExec(running.FS);
10100
- quietQuit(running.FS);
10242
+ quietQuit(running.FS, (on) => {
10243
+ streams.quitting = on;
10244
+ });
10245
+ atExit = () => streams.exiting();
10101
10246
  useMounts(running.FS, init.env, true);
10102
10247
  useZeroDevices(running.FS);
10103
10248
  useProcfs(running.FS, sys, init.pid);
@@ -10143,7 +10288,7 @@ async function runWasmProcess(init, port3, deps = {}) {
10143
10288
  restartable
10144
10289
  });
10145
10290
  try {
10146
- return runMain(running, init);
10291
+ return streams.exitStatus(runMain(running, init));
10147
10292
  } finally {
10148
10293
  try {
10149
10294
  vfs.flush();
@@ -10151,10 +10296,27 @@ async function runWasmProcess(init, port3, deps = {}) {
10151
10296
  }
10152
10297
  }
10153
10298
  }
10154
- function quietQuit(Fs) {
10299
+ function withExitHook(instance, begin) {
10300
+ const funcs = instance.exports.__funcs_on_exit;
10301
+ if (typeof funcs !== "function") return instance;
10302
+ const run = funcs;
10303
+ const exported = Object.assign(/* @__PURE__ */ Object.create(null), instance.exports, {
10304
+ __funcs_on_exit: () => {
10305
+ const end = begin();
10306
+ try {
10307
+ run();
10308
+ } finally {
10309
+ end();
10310
+ }
10311
+ }
10312
+ });
10313
+ return { exports: exported };
10314
+ }
10315
+ function quietQuit(Fs, quitting) {
10155
10316
  const { quit, close } = Fs;
10156
10317
  if (!quit) return;
10157
10318
  Fs.quit = () => {
10319
+ quitting?.(true);
10158
10320
  Fs.close = (stream) => {
10159
10321
  try {
10160
10322
  close.call(Fs, stream);
@@ -10164,6 +10326,7 @@ function quietQuit(Fs) {
10164
10326
  try {
10165
10327
  quit.call(Fs);
10166
10328
  } finally {
10329
+ quitting?.(false);
10167
10330
  Fs.close = close;
10168
10331
  }
10169
10332
  };
@@ -10216,7 +10379,7 @@ var init_process_runtime = __esm({
10216
10379
  O_ACCMODE4 = 3;
10217
10380
  O_DIRECTORY = 65536;
10218
10381
  accessMode = (access) => access === "read" ? O_RDONLY : access === "write" ? O_WRONLY6 : O_RDWR6;
10219
- PLACED = /* @__PURE__ */ new Set(["stream", "file", "socket"]);
10382
+ PLACED = /* @__PURE__ */ new Set(["stream", "file", "socket", "clipboard"]);
10220
10383
  GLUE_TRAILER = [
10221
10384
  "if (typeof ENV !== 'undefined') Object.assign(ENV, Module.sliccEnv);",
10222
10385
  "const __sliccTake = (name, value) => {",