@ai-ecoverse/slicc-kernel 1.32.3 → 1.34.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.
package/dist/node.js CHANGED
@@ -3064,7 +3064,7 @@ function argsOf(pkg, raw) {
3064
3064
  }
3065
3065
  function abiOf(raw, fallback) {
3066
3066
  const abi = raw ?? fallback;
3067
- return abi === "emscripten" || abi === "wasi" ? abi : void 0;
3067
+ return abi === "emscripten" || abi === "wasi" || abi === "js" ? abi : void 0;
3068
3068
  }
3069
3069
  function commandOf(pkg, name2, raw, packageAbi, shared) {
3070
3070
  const withEnv = envFields({ ...shared, ...envOf(pkg, raw.env) });
@@ -3073,11 +3073,25 @@ function commandOf(pkg, name2, raw, packageAbi, shared) {
3073
3073
  return { name: name2, abi: packageAbi, glue: script, wasm: script, argv0: name2, script, ...withEnv };
3074
3074
  }
3075
3075
  const abi = abiOf(raw.abi, packageAbi);
3076
+ const argv0 = typeof raw.argv0 === "string" && raw.argv0 ? raw.argv0 : name2;
3077
+ const args = argsOf(pkg, raw.args);
3078
+ if (abi === "js") {
3079
+ const module = inside(pkg, raw.module);
3080
+ if (!module) return void 0;
3081
+ return {
3082
+ name: name2,
3083
+ abi,
3084
+ glue: module,
3085
+ wasm: module,
3086
+ argv0,
3087
+ ...raw.argv0Path === true ? { argv0Path: true } : {},
3088
+ ...args ? { args } : {},
3089
+ ...withEnv
3090
+ };
3091
+ }
3076
3092
  const wasm = inside(pkg, raw.wasm);
3077
3093
  const glue = abi === "wasi" ? wasm : inside(pkg, raw.glue);
3078
3094
  if (!abi || !glue || !wasm) return void 0;
3079
- const argv0 = typeof raw.argv0 === "string" && raw.argv0 ? raw.argv0 : name2;
3080
- const args = argsOf(pkg, raw.args);
3081
3095
  const imports = abi === "wasi" ? inside(pkg, raw.imports) : void 0;
3082
3096
  return {
3083
3097
  name: name2,
@@ -3784,12 +3798,12 @@ var MountTable = class {
3784
3798
  }
3785
3799
  list() {
3786
3800
  const mounted = [...this.mounts.values()].map(
3787
- ({ type, source, target, options, state, error, present }) => ({
3801
+ ({ type, source, target, options, state, error, present: present2 }) => ({
3788
3802
  type,
3789
3803
  source,
3790
3804
  target,
3791
3805
  options: { ...options },
3792
- state: state === "ok" && present?.() === false ? "nomedium" : state,
3806
+ state: state === "ok" && present2?.() === false ? "nomedium" : state,
3793
3807
  ...error ? { error } : {}
3794
3808
  })
3795
3809
  );
@@ -4498,6 +4512,8 @@ var SAB_I_MEMORY = 10;
4498
4512
  var SAB_I_TOTAL_HI = 11;
4499
4513
  var SAB_I_OFFSET_HI = 12;
4500
4514
  var SAB_I_KILLED = 13;
4515
+ var SAB_I_ASYNC = 14;
4516
+ var SAB_I_STOP = 15;
4501
4517
  var U32 = 2 ** 32;
4502
4518
  function storeU53(header3, lo, hi, value) {
4503
4519
  Atomics.store(header3, hi, Math.floor(value / U32));
@@ -4679,8 +4695,10 @@ var AsyncOps = class {
4679
4695
  waiters = /* @__PURE__ */ new Set();
4680
4696
  closed = false;
4681
4697
  run;
4682
- constructor(run2) {
4698
+ onReady;
4699
+ constructor(run2, onReady) {
4683
4700
  this.run = run2;
4701
+ this.onReady = onReady;
4684
4702
  }
4685
4703
  submit(req) {
4686
4704
  const id = this.hold();
@@ -4757,6 +4775,7 @@ var AsyncOps = class {
4757
4775
  this.results.set(id, result);
4758
4776
  this.ready.push(id);
4759
4777
  this.wake();
4778
+ this.onReady?.();
4760
4779
  }
4761
4780
  wake() {
4762
4781
  for (const wake of [...this.waiters]) wake();
@@ -6267,6 +6286,8 @@ var KernelTty = class {
6267
6286
  waiters = [];
6268
6287
  hungUp = false;
6269
6288
  name;
6289
+ onRead;
6290
+ readers = 0;
6270
6291
  screen;
6271
6292
  signal;
6272
6293
  constructor(screen, signal) {
@@ -6417,7 +6438,19 @@ var KernelTty = class {
6417
6438
  }
6418
6439
  this.screen.write(Uint8Array.from(out));
6419
6440
  }
6441
+ get reading() {
6442
+ return this.readers > 0;
6443
+ }
6420
6444
  async read(max, signal) {
6445
+ this.onRead?.();
6446
+ this.readers++;
6447
+ try {
6448
+ return await this.take(max, signal);
6449
+ } finally {
6450
+ this.readers--;
6451
+ }
6452
+ }
6453
+ async take(max, signal) {
6421
6454
  while (this.readable.length === 0) {
6422
6455
  if (this.hungUp) return new Uint8Array(0);
6423
6456
  await this.changed(signal);
@@ -6482,13 +6515,14 @@ var PtyPair = class {
6482
6515
  slaveSeen = false;
6483
6516
  index;
6484
6517
  onFree;
6485
- constructor(index, signal, onFree) {
6518
+ constructor(index, signal, onFree, onRead) {
6486
6519
  this.index = index;
6487
6520
  this.onFree = onFree;
6488
6521
  this.slave = new KernelTty(
6489
6522
  { write: (bytes) => this.fromSlave(bytes) },
6490
6523
  (sig) => signal(this.slave, sig)
6491
6524
  );
6525
+ if (onRead) this.slave.onRead = () => onRead(this.slave);
6492
6526
  this.slave.name = `/dev/pts/${index}`;
6493
6527
  }
6494
6528
  master() {
@@ -6586,13 +6620,15 @@ var PtyPair = class {
6586
6620
  var PtyTable = class {
6587
6621
  pairs = /* @__PURE__ */ new Map();
6588
6622
  signal;
6589
- constructor(signal) {
6623
+ onRead;
6624
+ constructor(signal, onRead) {
6590
6625
  this.signal = signal;
6626
+ this.onRead = onRead;
6591
6627
  }
6592
6628
  open() {
6593
6629
  let index = 0;
6594
6630
  while (this.pairs.has(index)) index += 1;
6595
- const pair = new PtyPair(index, this.signal, (p) => this.pairs.delete(p.index));
6631
+ const pair = new PtyPair(index, this.signal, (p) => this.pairs.delete(p.index), this.onRead);
6596
6632
  this.pairs.set(index, pair);
6597
6633
  return { pair, master: pair.master() };
6598
6634
  }
@@ -7117,6 +7153,9 @@ var VfsNode = class {
7117
7153
  }
7118
7154
  return this.data;
7119
7155
  }
7156
+ holds() {
7157
+ return this.dirty;
7158
+ }
7120
7159
  replace(contents2) {
7121
7160
  this.ranged = void 0;
7122
7161
  this.data = new Uint8Array(contents2);
@@ -7227,9 +7266,34 @@ var VfsNode = class {
7227
7266
  var VfsNodes = class {
7228
7267
  byPath = /* @__PURE__ */ new Map();
7229
7268
  fs;
7269
+ entries = /* @__PURE__ */ new Map();
7230
7270
  constructor(fs) {
7231
7271
  this.fs = fs;
7232
7272
  }
7273
+ async onEntry(path, op) {
7274
+ const key = await this.entryKey(path);
7275
+ const run2 = (this.entries.get(key) ?? Promise.resolve()).then(op);
7276
+ const tail = run2.catch(() => void 0);
7277
+ this.entries.set(key, tail);
7278
+ void tail.then(() => {
7279
+ if (this.entries.get(key) === tail) this.entries.delete(key);
7280
+ });
7281
+ return run2;
7282
+ }
7283
+ async entryKey(path) {
7284
+ const parent = parentOf5(path);
7285
+ const dir = await realDir(this.fs, parent).catch(() => parent);
7286
+ const name2 = path.slice(path.lastIndexOf("/") + 1);
7287
+ return dir === "/" ? `/${name2}` : `${dir}/${name2}`;
7288
+ }
7289
+ createExclusive(path) {
7290
+ return this.onEntry(path, async () => {
7291
+ const node = this.byPath.get(path);
7292
+ const held = node ? await node.serial(async () => node.holds()) : false;
7293
+ if (held || await present(this.fs, path)) throw fsError("EEXIST", path);
7294
+ await this.fs.writeFile(path, new Uint8Array(0));
7295
+ });
7296
+ }
7233
7297
  open(path, pin) {
7234
7298
  let node = this.byPath.get(path);
7235
7299
  if (!node) {
@@ -7298,6 +7362,16 @@ var VfsNodes = class {
7298
7362
  }
7299
7363
  }
7300
7364
  };
7365
+ async function present(fs, path, follow = false) {
7366
+ const look = (follow ? void 0 : fs.lstat) ?? fs.stat;
7367
+ try {
7368
+ await (look ? look.call(fs, path) : fs.readFileBuffer(path));
7369
+ return true;
7370
+ } catch (err) {
7371
+ if (err?.code === "ENOENT") return false;
7372
+ throw err;
7373
+ }
7374
+ }
7301
7375
  var MAX_LINKS5 = 40;
7302
7376
  function parentOf5(path) {
7303
7377
  return path.slice(0, path.lastIndexOf("/")) || "/";
@@ -7362,12 +7436,17 @@ function keepingOpen(fs, nodes) {
7362
7436
  await fs.rm(path, options);
7363
7437
  nodes.unlinked(at);
7364
7438
  },
7365
- async rename(from, to) {
7439
+ rename(from, to) {
7366
7440
  const [a, b] = [fs.resolvePath("/", from), fs.resolvePath("/", to)];
7367
- await nodes.unlinking(b);
7368
- await fs.rename(from, to);
7369
- nodes.renamed(a, b);
7370
- }
7441
+ return nodes.onEntry(b, async () => {
7442
+ await nodes.unlinking(b);
7443
+ await fs.rename(from, to);
7444
+ nodes.renamed(a, b);
7445
+ });
7446
+ },
7447
+ writeFile: (path, content) => nodes.onEntry(fs.resolvePath("/", path), () => fs.writeFile(path, content)),
7448
+ symlink: (target, path) => nodes.onEntry(fs.resolvePath("/", path), () => fs.symlink(target, path)),
7449
+ mkdir: (path, options) => nodes.onEntry(fs.resolvePath("/", path), () => fs.mkdir(path, options))
7371
7450
  };
7372
7451
  }
7373
7452
  function vfsFile(fs, opts, nodes) {
@@ -7706,6 +7785,21 @@ var WasmProcess = class {
7706
7785
  this.options.hasPending?.() ? AbortSignal.abort() : this.interrupt.signal
7707
7786
  );
7708
7787
  }
7788
+ async openVfs(req) {
7789
+ await refuseReadonly(this.options.fs, req.path, req.flags, req);
7790
+ const fd = this.fds.install(heldFile(), 3);
7791
+ try {
7792
+ if (req.exclusive) await this.nodes.createExclusive(req.path);
7793
+ this.fds.installAt(fd, this.openVfsFile(req));
7794
+ if (req.existing && !await present(this.options.fs, req.path, true)) {
7795
+ throw new KernelError("ENOENT");
7796
+ }
7797
+ } catch (err) {
7798
+ await Promise.resolve(this.fds.close(fd));
7799
+ throw err;
7800
+ }
7801
+ return fd;
7802
+ }
7709
7803
  openVfsFile(req) {
7710
7804
  return vfsFile(
7711
7805
  this.options.fs,
@@ -7748,8 +7842,7 @@ var WasmProcess = class {
7748
7842
  case "fd-poll":
7749
7843
  return { ok: true, kind: "json", json: pollFile(this.fds.get(req.fd).file) };
7750
7844
  case "fd-open-vfs":
7751
- await refuseReadonly(this.options.fs, req.path, req.flags, req);
7752
- return { ok: true, kind: "json", json: this.fds.install(this.openVfsFile(req), 3) };
7845
+ return { ok: true, kind: "json", json: await this.openVfs(req) };
7753
7846
  case "fd-info":
7754
7847
  return { ok: true, kind: "json", json: this.fdInfo(req.fd) };
7755
7848
  case "fd-list":
@@ -8027,6 +8120,7 @@ var WasmProcess = class {
8027
8120
  case "sig-mask":
8028
8121
  this.caught = req.caught;
8029
8122
  this.ignored = req.ignored;
8123
+ this.inherited &= ~(req.defaults ?? 0);
8030
8124
  return { ok: true, kind: "void" };
8031
8125
  case "sig-pause":
8032
8126
  return this.pause();
@@ -8056,7 +8150,10 @@ var WasmProcess = class {
8056
8150
  }
8057
8151
  alarm;
8058
8152
  dlLog = [];
8059
- asyncOps = new AsyncOps((req) => this.syscall(req));
8153
+ asyncOps = new AsyncOps(
8154
+ (req) => this.syscall(req),
8155
+ () => this.options.onAsync?.()
8156
+ );
8060
8157
  alarmEvery;
8061
8158
  setAlarm(sig, first, every, timer) {
8062
8159
  if (!isSignal(sig)) throw new KernelError("EINVAL");
@@ -8084,6 +8181,7 @@ var WasmProcess = class {
8084
8181
  async exit() {
8085
8182
  if (this.exited) return;
8086
8183
  this.exited = true;
8184
+ this.die();
8087
8185
  this.clearAlarm();
8088
8186
  this.interrupt.abort();
8089
8187
  this.options.locks?.release(this.pid);
@@ -8165,6 +8263,26 @@ var Dying = class {
8165
8263
  return [typeof reported === "number" ? reported : CRASHED, void 0];
8166
8264
  }
8167
8265
  };
8266
+ function processInit(opts, sab) {
8267
+ const base = {
8268
+ type: WASM_PROCESS_INIT,
8269
+ pid: opts.shownPid ?? opts.pid,
8270
+ argv0: opts.argv0,
8271
+ args: opts.args,
8272
+ env: opts.env,
8273
+ cwd: opts.cwd,
8274
+ sab,
8275
+ ...opts.ppid !== void 0 ? { ppid: opts.ppid } : {}
8276
+ };
8277
+ if (opts.program.abi === "js") {
8278
+ return { ...base, program: opts.program, fds: inheritedFds(opts.fds) };
8279
+ }
8280
+ return {
8281
+ ...base,
8282
+ program: opts.program,
8283
+ ...opts.fork ? { fork: opts.fork } : { fds: inheritedFds(opts.fds) }
8284
+ };
8285
+ }
8168
8286
  function spawnWasmProcess(opts) {
8169
8287
  const sab = new SharedArrayBuffer(SAB_HEADER_BYTES + SAB_DEFAULT_WINDOW_BYTES);
8170
8288
  const header3 = new Int32Array(sab, 0, SAB_HEADER_I32);
@@ -8190,11 +8308,22 @@ function spawnWasmProcess(opts) {
8190
8308
  locks: opts.locks,
8191
8309
  onReap: opts.onReap,
8192
8310
  resolver: opts.resolver,
8193
- onPending: (sig) => void Atomics.or(header3, SAB_I_SIGNALS, sigbit(sig)),
8311
+ onPending: (sig) => {
8312
+ Atomics.or(header3, SAB_I_SIGNALS, sigbit(sig));
8313
+ Atomics.notify(header3, SAB_I_SIGNALS);
8314
+ },
8315
+ onAsync: () => {
8316
+ Atomics.add(header3, SAB_I_ASYNC, 1);
8317
+ Atomics.notify(header3, SAB_I_ASYNC);
8318
+ },
8194
8319
  onTimer: (which) => void Atomics.or(header3, SAB_I_TIMERS, 1 << which),
8195
8320
  hasPending: () => Atomics.load(header3, SAB_I_SIGNALS) !== 0 || Atomics.load(header3, SAB_I_TIMERS) !== 0,
8196
8321
  raise: (sig) => signal(sig),
8197
- ...opts.program.abi === "wasi" ? { pendingBits: () => Atomics.load(header3, SAB_I_SIGNALS) } : {}
8322
+ ...opts.program.abi === "wasi" || opts.program.abi === "js" ? { pendingBits: () => Atomics.load(header3, SAB_I_SIGNALS) } : {}
8323
+ });
8324
+ process.onState((state) => {
8325
+ Atomics.store(header3, SAB_I_STOP, state === "stopped" ? 1 : 0);
8326
+ Atomics.notify(header3, SAB_I_STOP);
8198
8327
  });
8199
8328
  const holds = new HeldPaths();
8200
8329
  opts.held?.add(holds);
@@ -8255,7 +8384,8 @@ function spawnWasmProcess(opts) {
8255
8384
  end?.();
8256
8385
  };
8257
8386
  const spawnThread = (thread) => {
8258
- if (done4) return;
8387
+ const { program } = opts;
8388
+ if (done4 || program.abi === "js") return;
8259
8389
  if (threads.size >= WASM_MAX_THREADS - 1) {
8260
8390
  opts.onError?.(`more than ${WASM_MAX_THREADS} threads`);
8261
8391
  finish(CRASHED);
@@ -8280,7 +8410,7 @@ function spawnWasmProcess(opts) {
8280
8410
  const tinit = {
8281
8411
  type: WASM_THREAD_INIT,
8282
8412
  pid: opts.shownPid ?? opts.pid,
8283
- program: opts.program,
8413
+ program,
8284
8414
  argv0: opts.argv0,
8285
8415
  args: opts.args,
8286
8416
  env: opts.env,
@@ -8291,18 +8421,7 @@ function spawnWasmProcess(opts) {
8291
8421
  };
8292
8422
  tw.postMessage(tinit);
8293
8423
  };
8294
- const init = {
8295
- type: WASM_PROCESS_INIT,
8296
- pid: opts.shownPid ?? opts.pid,
8297
- program: opts.program,
8298
- argv0: opts.argv0,
8299
- args: opts.args,
8300
- env: opts.env,
8301
- cwd: opts.cwd,
8302
- sab,
8303
- ...opts.ppid !== void 0 ? { ppid: opts.ppid } : {},
8304
- ...opts.fork ? { fork: opts.fork } : { fds: inheritedFds(opts.fds) }
8305
- };
8424
+ const init = processInit(opts, sab);
8306
8425
  worker.postMessage(init, opts.fork ? [opts.fork.memory.buffer] : []);
8307
8426
  const signal = (sig) => {
8308
8427
  if (process.signal(sig) !== "terminate") return;
@@ -8475,13 +8594,16 @@ var SETUP_OPS = /* @__PURE__ */ new Set([
8475
8594
  "fd-info",
8476
8595
  "sig-mask",
8477
8596
  "proc-setpgid",
8478
- "tty-pgrp-set"
8597
+ "tty-pgrp-set",
8598
+ "proc-exec",
8599
+ "proc-spawn"
8479
8600
  ]);
8480
- var SETTLE_MS = 250;
8601
+ var SETTLE_MS = 2e3;
8481
8602
  var KEY_SIGNALS = /* @__PURE__ */ new Set([2, 3, 20]);
8482
8603
  var SettlingChildren = class {
8483
8604
  children = /* @__PURE__ */ new Map();
8484
8605
  held = [];
8606
+ parked = [];
8485
8607
  pgidOf;
8486
8608
  settleMs;
8487
8609
  constructor(pgidOf, settleMs = SETTLE_MS) {
@@ -8489,7 +8611,15 @@ var SettlingChildren = class {
8489
8611
  this.settleMs = settleMs;
8490
8612
  }
8491
8613
  started(pid, ppid) {
8492
- this.children.set(pid, { ppid });
8614
+ const parent = this.children.get(ppid);
8615
+ this.children.set(pid, parent ? { ppid: parent.ppid, execer: ppid } : { ppid });
8616
+ const group = this.pgidOf(ppid);
8617
+ for (const p of this.parked) if (p.pgid === group) this.held.push({ ...p, copy: true });
8618
+ this.parked = this.parked.filter((p) => p.pgid !== group);
8619
+ }
8620
+ reading(pgid) {
8621
+ this.parked = this.parked.filter((p) => p.pgid !== pgid);
8622
+ this.held = this.held.filter((h) => !(h.copy && h.pgid === pgid));
8493
8623
  }
8494
8624
  syscall(pid, op) {
8495
8625
  const child = this.children.get(pid);
@@ -8505,13 +8635,25 @@ var SettlingChildren = class {
8505
8635
  if (!child) return;
8506
8636
  clearTimeout(child.timer);
8507
8637
  this.children.delete(pid);
8638
+ if (child.execer !== void 0) this.settled(child.execer);
8508
8639
  const ready2 = this.held.filter((h) => !this.blocking(h.pgid));
8509
8640
  this.held = this.held.filter((h) => this.blocking(h.pgid));
8510
8641
  for (const h of ready2) h.send();
8511
8642
  }
8512
- deliver(sig, pgid, send) {
8513
- if (KEY_SIGNALS.has(sig) && this.blocking(pgid)) this.held.push({ pgid, send });
8514
- else send();
8643
+ deliver(sig, pgid, send, foreground) {
8644
+ if (!KEY_SIGNALS.has(sig)) {
8645
+ send();
8646
+ } else if (this.blocking(pgid)) {
8647
+ this.held.push({ pgid, send });
8648
+ } else if (foreground) {
8649
+ send();
8650
+ const moved2 = () => {
8651
+ if (foreground() !== pgid) send();
8652
+ };
8653
+ this.parked.push({ pgid, send: moved2 });
8654
+ } else {
8655
+ send();
8656
+ }
8515
8657
  }
8516
8658
  blocking(pgid) {
8517
8659
  for (const { ppid } of this.children.values()) if (this.pgidOf(ppid) === pgid) return true;
@@ -9790,11 +9932,8 @@ var Launcher = class {
9790
9932
  locks = new LockTable();
9791
9933
  settling = new SettlingChildren((pid) => this.jobs.pgidOf(pid));
9792
9934
  ptys = new PtyTable(
9793
- (tty, sig) => this.settling.deliver(
9794
- sig,
9795
- this.jobs.tcgetpgrp(tty, 0),
9796
- () => this.jobs.signalOwnedForeground(tty, sig)
9797
- )
9935
+ (tty, sig) => this.keySignal(tty, 0, sig, () => this.jobs.signalOwnedForeground(tty, sig)),
9936
+ (tty) => this.settling.reading(this.jobs.tcgetpgrp(tty, 0))
9798
9937
  );
9799
9938
  net = new LoopbackNet();
9800
9939
  cdp;
@@ -9984,6 +10123,9 @@ var Launcher = class {
9984
10123
  return await this.base.exists(optional) ? optional : void 0;
9985
10124
  }
9986
10125
  async program(target, env) {
10126
+ if (target.abi === "js") {
10127
+ return { abi: "js", glue: await this.base.readFile(target.wasm), path: target.wasm };
10128
+ }
9987
10129
  if (target.abi !== "wasi") {
9988
10130
  const [glue, { module: module2 }] = await Promise.all([
9989
10131
  this.base.readFile(target.glue),
@@ -10207,6 +10349,11 @@ var Launcher = class {
10207
10349
  })
10208
10350
  );
10209
10351
  }
10352
+ keySignal(tty, fallback, sig, send) {
10353
+ const pgid = this.jobs.tcgetpgrp(tty, fallback);
10354
+ const foreground = () => this.jobs.tcgetpgrp(tty, fallback);
10355
+ this.settling.deliver(sig, pgid, send, tty.reading ? void 0 : foreground);
10356
+ }
10210
10357
  ignoredBy(pid, fork = false) {
10211
10358
  return this.processes.get(pid)?.ignoredSignals(fork) ?? 0;
10212
10359
  }
@@ -10402,12 +10549,9 @@ var Launcher = class {
10402
10549
  let leader = 0;
10403
10550
  const tty = new KernelTty(
10404
10551
  { write: (bytes) => options.onData(bytes.slice()) },
10405
- (sig) => this.settling.deliver(
10406
- sig,
10407
- this.jobs.tcgetpgrp(tty, leader),
10408
- () => this.jobs.signalForeground(tty, leader, sig)
10409
- )
10552
+ (sig) => this.keySignal(tty, leader, sig, () => this.jobs.signalForeground(tty, leader, sig))
10410
10553
  );
10554
+ tty.onRead = () => this.settling.reading(this.jobs.tcgetpgrp(tty, leader));
10411
10555
  tty.name = `/dev/tty${++this.terminals}`;
10412
10556
  tty.setSize(options.cols ?? 80, options.rows ?? 24);
10413
10557
  const fds = new FdTable();