@ai-ecoverse/slicc-kernel 1.64.2 → 1.65.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
@@ -5264,6 +5264,23 @@ var CONTINUED_STATUS = 65535;
5264
5264
  function waitStatus(code, termsig) {
5265
5265
  return termsig ? termsig & 127 : (code & 255) << 8;
5266
5266
  }
5267
+ function capturing(chunks2, max = Number.POSITIVE_INFINITY, overflow) {
5268
+ let size = 0;
5269
+ let over = false;
5270
+ return (bytes) => {
5271
+ if (over) return;
5272
+ const room = max - size;
5273
+ if (bytes.length > room) {
5274
+ over = true;
5275
+ if (room > 0) chunks2.push(bytes.slice(0, room));
5276
+ size = max;
5277
+ overflow?.();
5278
+ return;
5279
+ }
5280
+ chunks2.push(bytes);
5281
+ size += bytes.length;
5282
+ };
5283
+ }
5267
5284
  function concat2(chunks2) {
5268
5285
  const out = new Uint8Array(chunks2.reduce((n, c) => n + c.length, 0));
5269
5286
  let offset = 0;
@@ -5297,15 +5314,15 @@ var ChildTable = class {
5297
5314
  const fds = new FdTable();
5298
5315
  const captured = /* @__PURE__ */ new Map();
5299
5316
  try {
5300
- for (const [n, slot] of stdio.entries()) fds.installAt(n, this.openSlot(slot, n, captured));
5301
- for (const slot of inherit2) {
5302
- if (slot.fd <= 2) continue;
5303
- if ("device" in slot) {
5304
- fds.installAt(slot.fd, deviceFile(slot.device, slot.access));
5317
+ for (const [n, slot2] of stdio.entries()) fds.installAt(n, this.openSlot(slot2, n, captured));
5318
+ for (const slot2 of inherit2) {
5319
+ if (slot2.fd <= 2) continue;
5320
+ if ("device" in slot2) {
5321
+ fds.installAt(slot2.fd, deviceFile(slot2.device, slot2.access));
5305
5322
  continue;
5306
5323
  }
5307
- fds.installAt(slot.fd, this.parentFds.get(slot.kernel).retain());
5308
- if (slot.flags !== void 0) fds.setStatusFlags(slot.fd, slot.flags);
5324
+ fds.installAt(slot2.fd, this.parentFds.get(slot2.kernel).retain());
5325
+ if (slot2.flags !== void 0) fds.setStatusFlags(slot2.fd, slot2.flags);
5309
5326
  }
5310
5327
  } catch (e) {
5311
5328
  await fds.closeAll();
@@ -5346,15 +5363,15 @@ var ChildTable = class {
5346
5363
  this.watchers.set(pid, listener);
5347
5364
  if (child.stoppedBy !== void 0) listener("stopped", child.stoppedBy);
5348
5365
  }
5349
- openSlot(slot, n, captured) {
5350
- if ("fd" in slot) return this.parentFds.get(slot.fd).retain();
5351
- if ("input" in slot) return bytesSource(slot.input);
5352
- if ("device" in slot) return deviceFile(slot.device, slot.access);
5353
- if ("dir" in slot) return heldFile({ dir: slot.dir });
5354
- if ("capture" in slot) {
5366
+ openSlot(slot2, n, captured) {
5367
+ if ("fd" in slot2) return this.parentFds.get(slot2.fd).retain();
5368
+ if ("input" in slot2) return bytesSource(slot2.input);
5369
+ if ("device" in slot2) return deviceFile(slot2.device, slot2.access);
5370
+ if ("dir" in slot2) return heldFile({ dir: slot2.dir });
5371
+ if ("capture" in slot2) {
5355
5372
  const chunks2 = [];
5356
5373
  captured.set(n, chunks2);
5357
- return sinkFile((bytes) => chunks2.push(bytes));
5374
+ return sinkFile(capturing(chunks2, slot2.max, slot2.overflow));
5358
5375
  }
5359
5376
  return deviceFile("null");
5360
5377
  }
@@ -5421,11 +5438,11 @@ var ChildTable = class {
5421
5438
  pids() {
5422
5439
  return [...this.children.keys()];
5423
5440
  }
5424
- captured(pid, slot) {
5441
+ captured(pid, slot2) {
5425
5442
  const slots = this.leftovers.get(pid);
5426
- const chunks2 = slots?.get(slot);
5443
+ const chunks2 = slots?.get(slot2);
5427
5444
  if (!slots || !chunks2) return new Uint8Array(0);
5428
- slots.delete(slot);
5445
+ slots.delete(slot2);
5429
5446
  if (slots.size === 0) this.leftovers.delete(pid);
5430
5447
  return concat2(chunks2);
5431
5448
  }
@@ -7686,6 +7703,7 @@ var HOST_OPS = [
7686
7703
  "async-resolve",
7687
7704
  "async-hold",
7688
7705
  "async-cancel",
7706
+ "async-settle",
7689
7707
  "async-close"
7690
7708
  ];
7691
7709
  var json3 = (value) => ({ ok: true, kind: "json", json: value });
@@ -7717,12 +7735,16 @@ var LockTable = class {
7717
7735
  for (const path of [...this.held.keys()]) this.unlock(pid, path);
7718
7736
  }
7719
7737
  };
7738
+ var KEPT_OPS = /* @__PURE__ */ new Set(["fd-write"]);
7739
+ var unknownSettled = false;
7720
7740
  var AsyncOps = class {
7721
7741
  next = 1;
7722
7742
  results = /* @__PURE__ */ new Map();
7723
7743
  ready = [];
7724
7744
  running = /* @__PURE__ */ new Map();
7725
7745
  waiters = /* @__PURE__ */ new Set();
7746
+ taken = /* @__PURE__ */ new Map();
7747
+ kept = /* @__PURE__ */ new Set();
7726
7748
  closed = false;
7727
7749
  run;
7728
7750
  onReady;
@@ -7732,6 +7754,7 @@ var AsyncOps = class {
7732
7754
  }
7733
7755
  submit(req) {
7734
7756
  const id2 = this.hold();
7757
+ if (KEPT_OPS.has(req.op)) this.kept.add(id2);
7735
7758
  const running = new AbortController();
7736
7759
  this.running.set(id2, running);
7737
7760
  this.run(req, running.signal).then(
@@ -7755,9 +7778,26 @@ var AsyncOps = class {
7755
7778
  const result = this.results.get(id2);
7756
7779
  if (!result) throw new KernelError("EAGAIN");
7757
7780
  this.forget(id2);
7781
+ if (this.kept.delete(id2)) this.taken.set(id2, result);
7758
7782
  return result;
7759
7783
  }
7784
+ ack(ids) {
7785
+ for (const id2 of ids) this.taken.delete(id2);
7786
+ }
7787
+ async settle(ids) {
7788
+ const never = new AbortController().signal;
7789
+ while (ids.some((id2) => this.running.has(id2))) await this.sleep(void 0, never);
7790
+ return ids.map((id2) => {
7791
+ const result = this.results.get(id2) ?? this.taken.get(id2) ?? null;
7792
+ if (!result && !unknownSettled) {
7793
+ unknownSettled = true;
7794
+ console.warn(`async-settle: no result for op ${id2}; its write counts as made`);
7795
+ }
7796
+ return result;
7797
+ });
7798
+ }
7760
7799
  cancel(id2) {
7800
+ this.kept.delete(id2);
7761
7801
  this.running.get(id2)?.abort();
7762
7802
  this.forget(id2);
7763
7803
  }
@@ -7833,6 +7873,7 @@ async function hostSyscall(req, ctx) {
7833
7873
  return done2;
7834
7874
  case "async-submit":
7835
7875
  if (!ctx.valid(req.req)) throw new KernelError("EINVAL");
7876
+ if (req.ack) ctx.ops.ack(req.ack);
7836
7877
  return json3(ctx.ops.submit(req.req));
7837
7878
  case "async-wait":
7838
7879
  return json3(await ctx.ops.wait(req.timeoutMs, ctx.blocking));
@@ -7845,6 +7886,8 @@ async function hostSyscall(req, ctx) {
7845
7886
  case "async-cancel":
7846
7887
  ctx.ops.cancel(req.id);
7847
7888
  return done2;
7889
+ case "async-settle":
7890
+ return json3(await ctx.ops.settle(req.ids));
7848
7891
  case "async-close":
7849
7892
  ctx.ops.close();
7850
7893
  return done2;
@@ -9673,8 +9716,8 @@ var KernelTty = class {
9673
9716
  get canonical() {
9674
9717
  return (this.termios.c_lflag & ICANON) !== 0;
9675
9718
  }
9676
- cc(slot) {
9677
- return this.termios.c_cc[slot] ?? 0;
9719
+ cc(slot2) {
9720
+ return this.termios.c_cc[slot2] ?? 0;
9678
9721
  }
9679
9722
  key(input) {
9680
9723
  const { c_iflag, c_lflag } = this.termios;
@@ -10029,6 +10072,84 @@ function ptySyscall(req, ctx) {
10029
10072
  }
10030
10073
  }
10031
10074
 
10075
+ // src/kernel/run-child.ts
10076
+ var RUN_CAPTURE_CAP = 64 * 1024 * 1024;
10077
+ var RUN_MAX_BUFFER = 1024 * 1024;
10078
+ function capLimit(maxBuffer) {
10079
+ const asked = maxBuffer === void 0 ? RUN_MAX_BUFFER : maxBuffer;
10080
+ return Math.max(0, Math.min(asked, RUN_CAPTURE_CAP));
10081
+ }
10082
+ function slot(how, n, extra) {
10083
+ if (how === "inherit") return { fd: n };
10084
+ if (how === "ignore") return { none: true };
10085
+ return extra;
10086
+ }
10087
+ function frame2(outcome, out, err) {
10088
+ const head = new TextEncoder().encode(JSON.stringify(outcome));
10089
+ const bytes = new Uint8Array(4 + head.length + out.length + err.length);
10090
+ new DataView(bytes.buffer).setUint32(0, head.length, true);
10091
+ bytes.set(head, 4);
10092
+ bytes.set(out, 4 + head.length);
10093
+ bytes.set(err, 4 + head.length + out.length);
10094
+ return bytes;
10095
+ }
10096
+ async function reaped(deps, pid) {
10097
+ for (; ; ) {
10098
+ try {
10099
+ return (await deps.children.wait(pid, false, deps.interrupt()))[1];
10100
+ } catch (e) {
10101
+ if (!(e instanceof KernelError && e.code === "EINTR") || deps.dying()) throw e;
10102
+ }
10103
+ }
10104
+ }
10105
+ async function runChild(req, deps) {
10106
+ const max = capLimit(req.maxBuffer);
10107
+ let failure;
10108
+ let pid = 0;
10109
+ const kill = () => void Promise.allSettled([deps.kill(pid, req.killSignal)]);
10110
+ const stop = (code) => {
10111
+ if (failure !== void 0) return;
10112
+ failure = code;
10113
+ if (pid !== 0) kill();
10114
+ };
10115
+ const capture = () => ({ capture: true, max, overflow: () => stop("ENOBUFS") });
10116
+ const stdio = [
10117
+ slot(req.stdin, 0, { input: req.input ?? new Uint8Array(0) }),
10118
+ slot(req.stdout, 1, capture()),
10119
+ slot(req.stderr, 2, capture())
10120
+ ];
10121
+ try {
10122
+ pid = await deps.children.spawn(
10123
+ { file: req.file, argv: req.argv, env: req.env, cwd: req.cwd },
10124
+ stdio
10125
+ );
10126
+ } catch (e) {
10127
+ if (!(e instanceof SpawnError)) throw e;
10128
+ const outcome2 = { pid: 0, status: null, error: { code: e.code }, out: 0, err: 0 };
10129
+ return frame2(outcome2, new Uint8Array(0), new Uint8Array(0));
10130
+ }
10131
+ if (failure !== void 0) kill();
10132
+ const timer = req.timeoutMs !== void 0 && req.timeoutMs > 0 ? setTimeout(() => stop("ETIMEDOUT"), req.timeoutMs) : void 0;
10133
+ let status;
10134
+ try {
10135
+ status = await reaped(deps, pid);
10136
+ } finally {
10137
+ clearTimeout(timer);
10138
+ }
10139
+ const out = deps.children.captured(pid, 1);
10140
+ const err = deps.children.captured(pid, 2);
10141
+ const termsig = status & 127;
10142
+ const outcome = {
10143
+ pid,
10144
+ status: termsig ? null : status >> 8 & 255,
10145
+ ...termsig ? { signal: termsig } : {},
10146
+ ...failure !== void 0 ? { error: { code: failure } } : {},
10147
+ out: out.length,
10148
+ err: err.length
10149
+ };
10150
+ return frame2(outcome, out, err);
10151
+ }
10152
+
10032
10153
  // src/kernel/select.ts
10033
10154
  function ready(fds, read, write) {
10034
10155
  const hangup = /* @__PURE__ */ new Set();
@@ -10825,6 +10946,8 @@ var SYSCALL_OPS = /* @__PURE__ */ new Set([
10825
10946
  "proc-spawn",
10826
10947
  "proc-wait",
10827
10948
  "proc-captured",
10949
+ "proc-run",
10950
+ "proc-exit",
10828
10951
  "proc-fork",
10829
10952
  "proc-kill",
10830
10953
  "thread-kill",
@@ -10945,6 +11068,14 @@ var WasmProcess = class {
10945
11068
  else this.adoptExec(pid);
10946
11069
  return pid;
10947
11070
  }
11071
+ run(req) {
11072
+ return runChild(req, {
11073
+ children: this.children,
11074
+ kill: (pid, sig) => this.options.kill?.(pid, sig),
11075
+ interrupt: () => this.interrupt.signal,
11076
+ dying: () => this.dying
11077
+ });
11078
+ }
10948
11079
  adoptExec(pid) {
10949
11080
  this.execChild = pid;
10950
11081
  this.children.watch(pid, (state, sig) => state === "stopped" ? this.stop(sig) : this.cont());
@@ -11493,6 +11624,12 @@ var WasmProcess = class {
11493
11624
  return { ok: true, kind: "json", json: await this.spawn(req) };
11494
11625
  case "proc-wait":
11495
11626
  return { ok: true, kind: "json", json: await this.procWait(req, cancelled) };
11627
+ case "proc-run":
11628
+ return { ok: true, kind: "bytes", bytes: await this.run(req) };
11629
+ case "proc-exit":
11630
+ if (!this.options.exitNow) throw new KernelError("ENOSYS");
11631
+ this.options.exitNow(req.status & 255);
11632
+ return DYING;
11496
11633
  case "proc-identity":
11497
11634
  return { ok: true, kind: "json", json: await this.options.identity?.() ?? null };
11498
11635
  case "proc-exec": {
@@ -11899,6 +12036,7 @@ function processOptions(opts, header4, hooks, created3) {
11899
12036
  hasPending: () => Atomics.load(header4, SAB_I_SIGNALS) !== 0 || Atomics.load(header4, SAB_I_TIMERS) !== 0,
11900
12037
  raise: hooks.raise,
11901
12038
  threadKill: hooks.threadKill,
12039
+ ...hooks.exitNow ? { exitNow: hooks.exitNow } : {},
11902
12040
  ...opts.program.abi === "wasi" || opts.program.abi === "js" ? { pendingBits: () => Atomics.load(header4, SAB_I_SIGNALS) } : {}
11903
12041
  };
11904
12042
  }
@@ -11915,7 +12053,8 @@ function spawnWasmProcess(opts) {
11915
12053
  header4,
11916
12054
  {
11917
12055
  raise: (sig) => signal(sig),
11918
- threadKill: (tid, sig) => killThread(threadSignals.get(tid), process2.signalMasks().caught, sig)
12056
+ threadKill: (tid, sig) => killThread(threadSignals.get(tid), process2.signalMasks().caught, sig),
12057
+ ...opts.program.abi === "js" ? { exitNow: (code) => exitNow(code) } : {}
11919
12058
  },
11920
12059
  created3
11921
12060
  )
@@ -11956,6 +12095,9 @@ function spawnWasmProcess(opts) {
11956
12095
  () => settle(code)
11957
12096
  );
11958
12097
  };
12098
+ const exitNow = (code) => {
12099
+ queueMicrotask(() => finish(...dying.status(code)));
12100
+ };
11959
12101
  const handle = (data) => {
11960
12102
  if (data?.type === WASM_PROCESS_EXIT) {
11961
12103
  finish(...dying.status(data.code));
@@ -12691,15 +12833,15 @@ function granted(handle) {
12691
12833
  );
12692
12834
  }
12693
12835
  function removableMedium(onLost, open = (handle) => new OpfsFs(handle)) {
12694
- const slot = mediumSlot(
12836
+ const slot2 = mediumSlot(
12695
12837
  async (err, handle) => denied(err) && !await granted(handle),
12696
12838
  onLost
12697
12839
  );
12698
12840
  return {
12699
- handlers: slot.handlers,
12700
- present: slot.present,
12701
- insert: (handle) => slot.insert(handle, kernelFsHandlers(open(handle))),
12702
- eject: slot.eject
12841
+ handlers: slot2.handlers,
12842
+ present: slot2.present,
12843
+ insert: (handle) => slot2.insert(handle, kernelFsHandlers(open(handle))),
12844
+ eject: slot2.eject
12703
12845
  };
12704
12846
  }
12705
12847
 
@@ -13577,7 +13719,7 @@ function grantConnect(hook, fetch2, liveness = {}) {
13577
13719
  async function openHostfs(spec, connect, timing = {}) {
13578
13720
  const readonly2 = spec.options?.ro !== void 0;
13579
13721
  const { port1, port2 } = new MessageChannel();
13580
- const slot = mediumSlot(
13722
+ const slot2 = mediumSlot(
13581
13723
  async (err) => unreachable(err),
13582
13724
  () => watching.kick()
13583
13725
  );
@@ -13590,7 +13732,7 @@ async function openHostfs(spec, connect, timing = {}) {
13590
13732
  });
13591
13733
  const served = serveFilesystem(
13592
13734
  port2,
13593
- { ...slot.handlers, mount: ranged2 },
13735
+ { ...slot2.handlers, mount: ranged2 },
13594
13736
  {
13595
13737
  symlinks: true,
13596
13738
  chmod: true,
@@ -13604,12 +13746,12 @@ async function openHostfs(spec, connect, timing = {}) {
13604
13746
  connect: () => connect(spec.source, { readonly: readonly2 }),
13605
13747
  up(client) {
13606
13748
  active = timed(client, timing.callMs ?? HOSTFS_CALL_MS);
13607
- slot.insert(client, handlers);
13749
+ slot2.insert(client, handlers);
13608
13750
  served.invalidate(true);
13609
13751
  },
13610
13752
  event: (event) => served.invalidate(invalidation(event)),
13611
13753
  down() {
13612
- slot.eject();
13754
+ slot2.eject();
13613
13755
  served.invalidate(true);
13614
13756
  },
13615
13757
  ...timing
@@ -13619,7 +13761,7 @@ async function openHostfs(spec, connect, timing = {}) {
13619
13761
  await watching.ready;
13620
13762
  return {
13621
13763
  port: port1,
13622
- present: slot.present,
13764
+ present: slot2.present,
13623
13765
  dispose() {
13624
13766
  stop.abort();
13625
13767
  port1.close();
@@ -14922,16 +15064,16 @@ var Launcher = class {
14922
15064
  }
14923
15065
  async insert(target, handle, source) {
14924
15066
  const at = normalizePath(target);
14925
- const slot = this.removable.get(at);
14926
- if (!slot) throw fsError("EINVAL", `${at} is not a removable mount`);
14927
- if (source !== void 0 && source !== `fsa:${slot.id}`) {
15067
+ const slot2 = this.removable.get(at);
15068
+ if (!slot2) throw fsError("EINVAL", `${at} is not a removable mount`);
15069
+ if (source !== void 0 && source !== `fsa:${slot2.id}`) {
14928
15070
  throw fsError("EINVAL", `${at} is no longer the drive ${source}`);
14929
15071
  }
14930
15072
  if (!await granted(handle)) throw fsError("EACCES", `${at}: no permission for this folder`);
14931
- this.inserted.set(slot.id, handle);
14932
- await this.media.put(slot.id, handle);
14933
- slot.medium.insert(handle);
14934
- slot.served.invalidate(true);
15073
+ this.inserted.set(slot2.id, handle);
15074
+ await this.media.put(slot2.id, handle);
15075
+ slot2.medium.insert(handle);
15076
+ slot2.served.invalidate(true);
14935
15077
  void this.unlinked.sweep(at);
14936
15078
  }
14937
15079
  umount(target, detach = false) {