@ai-ecoverse/slicc-kernel 1.64.1 → 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
  }
@@ -7305,8 +7322,10 @@ var EARLY_WHOLE_FILE = 64 * 1024;
7305
7322
 
7306
7323
  // src/process/process-fds.ts
7307
7324
  var field2 = (text) => (text || "none").replace(/[\s\\]/g, (c) => `\\${c.charCodeAt(0).toString(8).padStart(3, "0")}`);
7325
+ var pinnedRoot;
7326
+ var rootKind = () => globalThis.navigator?.storage ? "opfs" : "memory";
7308
7327
  function mountTable(mounts = []) {
7309
- const root = globalThis.navigator?.storage ? "opfs" : "memory";
7328
+ const root = pinnedRoot ?? rootKind();
7310
7329
  const lines2 = [`${root} / ${root} rw 0 0`, "devfs /dev devfs rw 0 0", "proc /proc proc rw 0 0"];
7311
7330
  for (const m of mounts) {
7312
7331
  const options = Object.entries(m.options).map(([k, v]) => v === "" ? k : `${k}=${v}`);
@@ -7684,6 +7703,7 @@ var HOST_OPS = [
7684
7703
  "async-resolve",
7685
7704
  "async-hold",
7686
7705
  "async-cancel",
7706
+ "async-settle",
7687
7707
  "async-close"
7688
7708
  ];
7689
7709
  var json3 = (value) => ({ ok: true, kind: "json", json: value });
@@ -7715,12 +7735,16 @@ var LockTable = class {
7715
7735
  for (const path of [...this.held.keys()]) this.unlock(pid, path);
7716
7736
  }
7717
7737
  };
7738
+ var KEPT_OPS = /* @__PURE__ */ new Set(["fd-write"]);
7739
+ var unknownSettled = false;
7718
7740
  var AsyncOps = class {
7719
7741
  next = 1;
7720
7742
  results = /* @__PURE__ */ new Map();
7721
7743
  ready = [];
7722
7744
  running = /* @__PURE__ */ new Map();
7723
7745
  waiters = /* @__PURE__ */ new Set();
7746
+ taken = /* @__PURE__ */ new Map();
7747
+ kept = /* @__PURE__ */ new Set();
7724
7748
  closed = false;
7725
7749
  run;
7726
7750
  onReady;
@@ -7730,6 +7754,7 @@ var AsyncOps = class {
7730
7754
  }
7731
7755
  submit(req) {
7732
7756
  const id2 = this.hold();
7757
+ if (KEPT_OPS.has(req.op)) this.kept.add(id2);
7733
7758
  const running = new AbortController();
7734
7759
  this.running.set(id2, running);
7735
7760
  this.run(req, running.signal).then(
@@ -7753,9 +7778,26 @@ var AsyncOps = class {
7753
7778
  const result = this.results.get(id2);
7754
7779
  if (!result) throw new KernelError("EAGAIN");
7755
7780
  this.forget(id2);
7781
+ if (this.kept.delete(id2)) this.taken.set(id2, result);
7756
7782
  return result;
7757
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
+ }
7758
7799
  cancel(id2) {
7800
+ this.kept.delete(id2);
7759
7801
  this.running.get(id2)?.abort();
7760
7802
  this.forget(id2);
7761
7803
  }
@@ -7831,6 +7873,7 @@ async function hostSyscall(req, ctx) {
7831
7873
  return done2;
7832
7874
  case "async-submit":
7833
7875
  if (!ctx.valid(req.req)) throw new KernelError("EINVAL");
7876
+ if (req.ack) ctx.ops.ack(req.ack);
7834
7877
  return json3(ctx.ops.submit(req.req));
7835
7878
  case "async-wait":
7836
7879
  return json3(await ctx.ops.wait(req.timeoutMs, ctx.blocking));
@@ -7843,6 +7886,8 @@ async function hostSyscall(req, ctx) {
7843
7886
  case "async-cancel":
7844
7887
  ctx.ops.cancel(req.id);
7845
7888
  return done2;
7889
+ case "async-settle":
7890
+ return json3(await ctx.ops.settle(req.ids));
7846
7891
  case "async-close":
7847
7892
  ctx.ops.close();
7848
7893
  return done2;
@@ -9671,8 +9716,8 @@ var KernelTty = class {
9671
9716
  get canonical() {
9672
9717
  return (this.termios.c_lflag & ICANON) !== 0;
9673
9718
  }
9674
- cc(slot) {
9675
- return this.termios.c_cc[slot] ?? 0;
9719
+ cc(slot2) {
9720
+ return this.termios.c_cc[slot2] ?? 0;
9676
9721
  }
9677
9722
  key(input) {
9678
9723
  const { c_iflag, c_lflag } = this.termios;
@@ -10027,6 +10072,84 @@ function ptySyscall(req, ctx) {
10027
10072
  }
10028
10073
  }
10029
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
+
10030
10153
  // src/kernel/select.ts
10031
10154
  function ready(fds, read, write) {
10032
10155
  const hangup = /* @__PURE__ */ new Set();
@@ -10823,6 +10946,8 @@ var SYSCALL_OPS = /* @__PURE__ */ new Set([
10823
10946
  "proc-spawn",
10824
10947
  "proc-wait",
10825
10948
  "proc-captured",
10949
+ "proc-run",
10950
+ "proc-exit",
10826
10951
  "proc-fork",
10827
10952
  "proc-kill",
10828
10953
  "thread-kill",
@@ -10943,6 +11068,14 @@ var WasmProcess = class {
10943
11068
  else this.adoptExec(pid);
10944
11069
  return pid;
10945
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
+ }
10946
11079
  adoptExec(pid) {
10947
11080
  this.execChild = pid;
10948
11081
  this.children.watch(pid, (state, sig) => state === "stopped" ? this.stop(sig) : this.cont());
@@ -11491,6 +11624,12 @@ var WasmProcess = class {
11491
11624
  return { ok: true, kind: "json", json: await this.spawn(req) };
11492
11625
  case "proc-wait":
11493
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;
11494
11633
  case "proc-identity":
11495
11634
  return { ok: true, kind: "json", json: await this.options.identity?.() ?? null };
11496
11635
  case "proc-exec": {
@@ -11897,6 +12036,7 @@ function processOptions(opts, header4, hooks, created3) {
11897
12036
  hasPending: () => Atomics.load(header4, SAB_I_SIGNALS) !== 0 || Atomics.load(header4, SAB_I_TIMERS) !== 0,
11898
12037
  raise: hooks.raise,
11899
12038
  threadKill: hooks.threadKill,
12039
+ ...hooks.exitNow ? { exitNow: hooks.exitNow } : {},
11900
12040
  ...opts.program.abi === "wasi" || opts.program.abi === "js" ? { pendingBits: () => Atomics.load(header4, SAB_I_SIGNALS) } : {}
11901
12041
  };
11902
12042
  }
@@ -11913,7 +12053,8 @@ function spawnWasmProcess(opts) {
11913
12053
  header4,
11914
12054
  {
11915
12055
  raise: (sig) => signal(sig),
11916
- 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) } : {}
11917
12058
  },
11918
12059
  created3
11919
12060
  )
@@ -11954,12 +12095,15 @@ function spawnWasmProcess(opts) {
11954
12095
  () => settle(code)
11955
12096
  );
11956
12097
  };
12098
+ const exitNow = (code) => {
12099
+ queueMicrotask(() => finish(...dying.status(code)));
12100
+ };
11957
12101
  const handle = (data) => {
11958
12102
  if (data?.type === WASM_PROCESS_EXIT) {
11959
12103
  finish(...dying.status(data.code));
11960
12104
  } else if (data?.type === WASM_PROCESS_ERROR) {
11961
12105
  if (!dying.ending) opts.onError?.(String(data.message));
11962
- finish(...dying.status(CRASHED));
12106
+ finish(...dying.status(data.code));
11963
12107
  } else if (data?.type === WASM_THREAD_SPAWN && data.thread) {
11964
12108
  spawnThread(data.thread);
11965
12109
  }
@@ -12689,15 +12833,15 @@ function granted(handle) {
12689
12833
  );
12690
12834
  }
12691
12835
  function removableMedium(onLost, open = (handle) => new OpfsFs(handle)) {
12692
- const slot = mediumSlot(
12836
+ const slot2 = mediumSlot(
12693
12837
  async (err, handle) => denied(err) && !await granted(handle),
12694
12838
  onLost
12695
12839
  );
12696
12840
  return {
12697
- handlers: slot.handlers,
12698
- present: slot.present,
12699
- insert: (handle) => slot.insert(handle, kernelFsHandlers(open(handle))),
12700
- eject: slot.eject
12841
+ handlers: slot2.handlers,
12842
+ present: slot2.present,
12843
+ insert: (handle) => slot2.insert(handle, kernelFsHandlers(open(handle))),
12844
+ eject: slot2.eject
12701
12845
  };
12702
12846
  }
12703
12847
 
@@ -13575,7 +13719,7 @@ function grantConnect(hook, fetch2, liveness = {}) {
13575
13719
  async function openHostfs(spec, connect, timing = {}) {
13576
13720
  const readonly2 = spec.options?.ro !== void 0;
13577
13721
  const { port1, port2 } = new MessageChannel();
13578
- const slot = mediumSlot(
13722
+ const slot2 = mediumSlot(
13579
13723
  async (err) => unreachable(err),
13580
13724
  () => watching.kick()
13581
13725
  );
@@ -13588,7 +13732,7 @@ async function openHostfs(spec, connect, timing = {}) {
13588
13732
  });
13589
13733
  const served = serveFilesystem(
13590
13734
  port2,
13591
- { ...slot.handlers, mount: ranged2 },
13735
+ { ...slot2.handlers, mount: ranged2 },
13592
13736
  {
13593
13737
  symlinks: true,
13594
13738
  chmod: true,
@@ -13602,12 +13746,12 @@ async function openHostfs(spec, connect, timing = {}) {
13602
13746
  connect: () => connect(spec.source, { readonly: readonly2 }),
13603
13747
  up(client) {
13604
13748
  active = timed(client, timing.callMs ?? HOSTFS_CALL_MS);
13605
- slot.insert(client, handlers);
13749
+ slot2.insert(client, handlers);
13606
13750
  served.invalidate(true);
13607
13751
  },
13608
13752
  event: (event) => served.invalidate(invalidation(event)),
13609
13753
  down() {
13610
- slot.eject();
13754
+ slot2.eject();
13611
13755
  served.invalidate(true);
13612
13756
  },
13613
13757
  ...timing
@@ -13617,7 +13761,7 @@ async function openHostfs(spec, connect, timing = {}) {
13617
13761
  await watching.ready;
13618
13762
  return {
13619
13763
  port: port1,
13620
- present: slot.present,
13764
+ present: slot2.present,
13621
13765
  dispose() {
13622
13766
  stop.abort();
13623
13767
  port1.close();
@@ -14920,16 +15064,16 @@ var Launcher = class {
14920
15064
  }
14921
15065
  async insert(target, handle, source) {
14922
15066
  const at = normalizePath(target);
14923
- const slot = this.removable.get(at);
14924
- if (!slot) throw fsError("EINVAL", `${at} is not a removable mount`);
14925
- 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}`) {
14926
15070
  throw fsError("EINVAL", `${at} is no longer the drive ${source}`);
14927
15071
  }
14928
15072
  if (!await granted(handle)) throw fsError("EACCES", `${at}: no permission for this folder`);
14929
- this.inserted.set(slot.id, handle);
14930
- await this.media.put(slot.id, handle);
14931
- slot.medium.insert(handle);
14932
- 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);
14933
15077
  void this.unlinked.sweep(at);
14934
15078
  }
14935
15079
  umount(target, detach = false) {