@ai-ecoverse/slicc-kernel 1.164.5 → 1.165.1

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/README.md CHANGED
@@ -426,12 +426,14 @@ The module's default export (or its `main` export) is called with a context and
426
426
  - **When `fn` runs:** it formats an error's `.stack` the way V8's prepare-stack-trace callback does, as `fn(error, callSites)` returning the string. It runs only when no own `Error.prepareStackTrace` function is set, as in Node, so `Error.prepareStackTrace` stays an ordinary property: after `delete` it's `undefined`, `Object.getPrototypeOf(Error)` stays `Function.prototype`, and an assignment to a frozen subclass throws in strict mode.
427
427
  - **What `fn` gets:** a fresh array of V8 CallSites holding only the program's own frames (its modules, `data:` imports, `sync.runScript` scripts, code they `eval`, and `new Function` or `eval` code named by `//# sourceURL`, #1632), `node:` frames and native frames. Kernel frames are dropped by script identity, so a script named like a kernel file doesn't let them through, and so are host files. A program's strict frames give `getFunction()` and `getThis()` as `undefined`.
428
428
  - **Fallback:** if `fn` throws or returns a non-string, or an error is formatted while `fn` runs, the default stack is used.
429
+ - **`{ own: true }`** (#1631): `setStackFormatter(fn, { own: true })` calls `fn(error, callSites, own)` for every stack. `own` is the program's own `Error.prepareStackTrace` (the realm's `Error`, then the main one, read as Node 26 reads it), or `undefined` when none is set or it's Node's default. `fn`'s result is the stack whatever its type, and a throw propagates out of the `.stack` read, as with Node's own callback.
430
+ - **An own `Error.prepareStackTrace` on the Node entry** (#1631): the process worker replaces Node's stack callback with a copy of Node 26's order. A program's own `Error.prepareStackTrace`, and a host preload's, still gets V8's CallSites as in Node, kernel frames included (named `slicc-kernel:/node-process-worker.js`), with its `Error` as receiver; its result and throws are the stack. To hand it the filtered CallSites instead (no kernel frame, no host path), use `setStackFormatter(fn, { own: true })` and call `own` from `fn`. 1.165.0 filtered by default, which broke runtimes that read their own frames through an own `prepareStackTrace`; the release after it went back to V8's CallSites. Node's own internal overrides still come first with raw frames, and so do the kernel's own diagnostics: a crash report and a WASI trap backtrace still show kernel and wasm frames.
429
431
  - **How it works:** process workers start with `--expose-internals`, so the worker can install the formatter before the lockdown. Host flags a worker refuses are dropped. If the worker still can't start with the flag, the method is absent. Every `internal/*` and `node:internal/*` module stays refused to programs, as do `node:module` and `node:worker_threads`.
430
432
  - `sync.errorSource(error)` (#1610, slicc-jsh#1082) is Node only, so check it with `typeof ctx.sync.errorSource === 'function'`. It gives `{ sourceLine, lineNumber, startColumn }` (null-prototype and frozen), the source line Node prints over an uncaught error, for an error in the program's own code. The kernel takes V8's position while the stack is formatted (#1633), so this also works after `.stack` was read, and for a call of a non-function, a ReferenceError, a TDZ error or a thrown `Error`. For code named by `//# sourceURL` it matches on that name (#1632). That includes a direct `eval` of a value that isn't a string literal (`const s = 'null.d'; eval(s)` gives `null.d` and line 1) and a `sync.runScript` script.
431
433
  - **Only the program's own code:** it answers only when the error's top frame is a program frame and the position V8 kept is in that same script and line.
432
- - **`undefined` cases:** kernel-made errors; values that aren't native errors; a script that borrows the kernel worker's name; and an error an own `Error.prepareStackTrace` formats.
434
+ - **`undefined` cases:** kernel-made errors; values that aren't native errors; and a script that borrows the kernel worker's name. An error an own `Error.prepareStackTrace` formats answers too (#1631).
433
435
  - **How it works:** it reads V8's message through Node's internal errors binding, which the worker loads at start-up through the same `--expose-internals` as `setStackFormatter`. It prints no warning and needs no inspector.
434
- - **Kernel frames in a program's stacks** (#1583): on the Node entry, the process worker's bundle names itself `slicc-kernel:/node-process-worker.js` (a `sourceURL`), so the kernel's own frames in an error a program sees (its own errors, a failed `ctx` call, `runScript`) show that name and not the host directory the kernel is installed in. The same holds in `CallSite.toString()` and `getScriptNameOrSourceURL()`, which a program's own `Error.prepareStackTrace` gets; `getFileName()` still returns the bundle's file URL. Line and column numbers are unchanged, so they still point into `dist/node-process-worker.js`. Don't run an embedder with `--enable-source-maps` if program-visible paths matter: Node then maps the kernel's frames back to the absolute paths of its sources. In a browser the frames keep the bundle's URL, because Chrome ignores `sourceURL` in a module worker loaded by URL.
436
+ - **Kernel frames in a program's stacks** (#1583): on the Node entry, the process worker's bundle names itself `slicc-kernel:/node-process-worker.js` (a `sourceURL`), so the kernel's own frames in an error a program sees (its own errors, a failed `ctx` call, `runScript`) show that name and not the host directory the kernel is installed in. The stack formatter, and an own `Error.prepareStackTrace` called through `{ own: true }`, get no kernel CallSites at all (#1612, #1631). Line and column numbers are unchanged, so they still point into `dist/node-process-worker.js`. Don't run an embedder with `--enable-source-maps` if program-visible paths matter: Node then maps the kernel's frames back to the absolute paths of its sources. In a browser the frames keep the bundle's URL, because Chrome ignores `sourceURL` in a module worker loaded by URL.
435
437
  - `module` (#1598, slicc-jsh#566) is a frozen `{ path }` with the command module's own path in the kernel's file system (e.g. `/usr/lib/node_modules/jsh/dist/jsh.mjs`), so a program can read its package's other files through `ctx.fs` on first use. It's the path the kernel found the package under, with symlinks left as they are (a pnpm-style `node_modules/<name>` link stays in it), and reads the same files through `ctx.fs`. It's a kernel path, never a host one, and a thread gets the same. It's absent for the kernel's built-in programs (`sudo`, `crontab`) and for a program run from inline source with no file.
436
438
  - `memory()`, synchronous and without a kernel call, measures the calling isolate: each `thread` answers for its own (#1240, slicc-jsh#397). It returns a fresh plain object of numbers in bytes, each field only where it's measured: `heapUsed`, `heapTotal`, `heapLimit` (V8's heap size limit), `external`, `arrayBuffers` and `rss`. On the Node entry they come from V8's heap statistics and Node's memory usage, through functions the worker captured before its lockdown, so nothing reachable from the program leads back to `process` or `v8`. `rss` is the host process's resident set size, as a Node worker thread reports it in `process.memoryUsage().rss`: it isn't per process, but shared by every process and thread of the kernel, and by any other kernel in that host process (#1563, slicc-jsh#539). In a browser `memory()` answers `{}` for now, with no `rss`.
437
439
  - **`thread`, kernel threads of the same process** ([#1094](https://github.com/ai-ecoverse/slicc-kernel/issues/1094)), the base for Node's `worker_threads` (tinypool, piscina, vitest's and jest's thread pools, eslint's concurrency). `thread.spawn({ data, transfer })` resolves with `{ tid, port, exited, terminate() }`.
@@ -8440,7 +8440,7 @@ function satisfies(version, range2) {
8440
8440
  }
8441
8441
 
8442
8442
  // src/version.ts
8443
- var KERNEL_VERSION = true ? "1.164.5" : "0.0.0-dev";
8443
+ var KERNEL_VERSION = true ? "1.165.1" : "0.0.0-dev";
8444
8444
  var OS_RELEASE = "6.0.0-slicc";
8445
8445
  function procVersion() {
8446
8446
  return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
@@ -564,23 +564,23 @@ function errorWithCode(message) {
564
564
  }
565
565
  function dialStream(port, onClose) {
566
566
  let closed = false;
567
- let reader;
567
+ let reader2;
568
568
  const acks = [];
569
569
  const readable = new ReadableStream({
570
570
  start(controller) {
571
- reader = controller;
571
+ reader2 = controller;
572
572
  },
573
573
  pull() {
574
574
  if (!closed) port.postMessage({ more: true });
575
575
  },
576
576
  cancel() {
577
- reader = void 0;
577
+ reader2 = void 0;
578
578
  close();
579
579
  }
580
580
  });
581
581
  const finish = (fail2) => {
582
- const controller = reader;
583
- reader = void 0;
582
+ const controller = reader2;
583
+ reader2 = void 0;
584
584
  for (const ack of acks.splice(0)) {
585
585
  if (fail2) ack.reject(fail2);
586
586
  else ack.resolve();
@@ -601,7 +601,7 @@ function dialStream(port, onClose) {
601
601
  finish();
602
602
  }
603
603
  port.addEventListener("message", ({ data }) => {
604
- if (data instanceof Uint8Array) reader?.enqueue(data);
604
+ if (data instanceof Uint8Array) reader2?.enqueue(data);
605
605
  else if ("ack" in data) acks.shift()?.resolve();
606
606
  else if ("end" in data) finish();
607
607
  else finish(errorWithCode(data.error));
@@ -636,8 +636,8 @@ var latin1 = new TextDecoder("latin1");
636
636
  var ByteSource = class {
637
637
  buffered = new Uint8Array(0);
638
638
  reader;
639
- constructor(reader) {
640
- this.reader = reader;
639
+ constructor(reader2) {
640
+ this.reader = reader2;
641
641
  }
642
642
  async more() {
643
643
  const { done, value } = await this.reader.read();
@@ -1423,6 +1423,14 @@ import { types as types2 } from "node:util";
1423
1423
  // src/node-stack.ts
1424
1424
  import { createRequire } from "node:module";
1425
1425
  import { types } from "node:util";
1426
+
1427
+ // src/process/raw-stack.ts
1428
+ var reader = (error) => error.stack;
1429
+ function setRawStack(read) {
1430
+ reader = read;
1431
+ }
1432
+
1433
+ // src/node-stack.ts
1426
1434
  function quietly(target, run) {
1427
1435
  const emit = target.emitWarning;
1428
1436
  target.emitWarning = () => {
@@ -1433,18 +1441,20 @@ function quietly(target, run) {
1433
1441
  target.emitWarning = emit;
1434
1442
  }
1435
1443
  }
1436
- function positionsOf(load) {
1444
+ function bindingOf(load) {
1437
1445
  try {
1438
1446
  const { internalBinding } = quietly(
1439
1447
  process,
1440
1448
  () => load("internal/test/binding")
1441
1449
  );
1442
- const get = internalBinding("errors").getErrorSourcePositions;
1443
- return typeof get === "function" ? get : void 0;
1450
+ return internalBinding("errors");
1444
1451
  } catch {
1445
- return void 0;
1452
+ return {};
1446
1453
  }
1447
1454
  }
1455
+ function fn(value) {
1456
+ return typeof value === "function" ? value : void 0;
1457
+ }
1448
1458
  var apply = Reflect.apply;
1449
1459
  var push = Array.prototype.push;
1450
1460
  var startsWith = String.prototype.startsWith;
@@ -1455,6 +1465,9 @@ var setHas = Set.prototype.has;
1455
1465
  var setAdd = Set.prototype.add;
1456
1466
  var mapGet = WeakMap.prototype.get;
1457
1467
  var mapSet = WeakMap.prototype.set;
1468
+ var mapHas = WeakMap.prototype.has;
1469
+ var mapDelete = WeakMap.prototype.delete;
1470
+ var MainError = Error;
1458
1471
  var isNativeError = types.isNativeError;
1459
1472
  var freeze = Object.freeze;
1460
1473
  var blank = Object.create;
@@ -1467,11 +1480,17 @@ function internals() {
1467
1480
  if (process.sourceMapsEnabled) {
1468
1481
  fallback = load("internal/source_map/prepare_stack_trace").prepareStackTraceWithSourceMaps;
1469
1482
  }
1470
- if (typeof set !== "function" || typeof fallback !== "function") return void 0;
1483
+ const overrides = errors.overrideStackTrace;
1484
+ const usable = typeof set === "function" && typeof fallback === "function";
1485
+ if (!usable || !types.isWeakMap(overrides)) return void 0;
1486
+ const binding = bindingOf(load);
1471
1487
  return {
1472
1488
  setInternalPrepareStackTrace: set,
1473
1489
  fallback,
1474
- positions: positionsOf(load)
1490
+ positions: fn(binding.getErrorSourcePositions),
1491
+ setCallback: fn(binding.setPrepareStackTraceCallback),
1492
+ overrides,
1493
+ nodeDefault: errors.ErrorPrepareStackTrace
1475
1494
  };
1476
1495
  } catch {
1477
1496
  return void 0;
@@ -1563,6 +1582,7 @@ function keptFrames(trace) {
1563
1582
  return out;
1564
1583
  }
1565
1584
  var formatter = null;
1585
+ var withOwn = false;
1566
1586
  var formatting = false;
1567
1587
  var seen = /* @__PURE__ */ new WeakMap();
1568
1588
  function positionsAt(positions, error, site) {
@@ -1573,17 +1593,20 @@ function positionsAt(positions, error, site) {
1573
1593
  return void 0;
1574
1594
  }
1575
1595
  }
1596
+ function record(positions, error, trace) {
1597
+ if (typeof error === "object" && error !== null && trace.length > 0) {
1598
+ const site = trace[0];
1599
+ apply(mapSet, seen, [error, { site, at: positionsAt(positions, error, site) }]);
1600
+ }
1601
+ }
1576
1602
  function stackDispatcher(fallback, positions) {
1577
1603
  return (error, trace) => {
1578
- if (typeof error === "object" && error !== null && trace.length > 0) {
1579
- const site = trace[0];
1580
- apply(mapSet, seen, [error, { site, at: positionsAt(positions, error, site) }]);
1581
- }
1582
- const fn = formatter;
1583
- if (fn === null || formatting) return apply(fallback, void 0, [error, trace]);
1604
+ record(positions, error, trace);
1605
+ const fn2 = formatter;
1606
+ if (fn2 === null || formatting) return apply(fallback, void 0, [error, trace]);
1584
1607
  formatting = true;
1585
1608
  try {
1586
- const out = apply(fn, void 0, [error, keptFrames(trace)]);
1609
+ const out = apply(fn2, void 0, [error, keptFrames(trace)]);
1587
1610
  if (typeof out === "string") return out;
1588
1611
  } catch {
1589
1612
  } finally {
@@ -1592,8 +1615,70 @@ function stackDispatcher(fallback, positions) {
1592
1615
  return apply(fallback, void 0, [error, trace]);
1593
1616
  };
1594
1617
  }
1618
+ function errorOf2(realm) {
1619
+ return realm === null || realm === void 0 ? void 0 : realm.Error;
1620
+ }
1621
+ function prepareOf(holder) {
1622
+ return holder === null || holder === void 0 ? void 0 : holder.prepareStackTrace;
1623
+ }
1624
+ function ownPrepare(realm, nodeDefault) {
1625
+ let self2;
1626
+ if (typeof prepareOf(errorOf2(realm)) === "function") self2 = errorOf2(realm);
1627
+ else if (typeof prepareOf(MainError) === "function") self2 = MainError;
1628
+ else return void 0;
1629
+ const value = prepareOf(self2);
1630
+ return value === nodeDefault ? void 0 : { fn: value, self: self2 };
1631
+ }
1632
+ function calling(run) {
1633
+ formatting = true;
1634
+ try {
1635
+ return run();
1636
+ } finally {
1637
+ formatting = false;
1638
+ }
1639
+ }
1640
+ function kernelCallback(internal, dispatch2) {
1641
+ const { fallback, positions, overrides, nodeDefault } = internal;
1642
+ return (realm, error, trace) => {
1643
+ if (apply(mapHas, overrides, [error]) === true) {
1644
+ const override = apply(mapGet, overrides, [error]);
1645
+ apply(mapDelete, overrides, [error]);
1646
+ return apply(override, void 0, [error, trace]);
1647
+ }
1648
+ const own = ownPrepare(realm, nodeDefault);
1649
+ if (formatting) return apply(fallback, void 0, [error, keptFrames(trace)]);
1650
+ const fmt = formatter;
1651
+ if (fmt !== null && withOwn) {
1652
+ record(positions, error, trace);
1653
+ return calling(() => apply(fmt, void 0, [error, keptFrames(trace), own?.fn]));
1654
+ }
1655
+ if (own === void 0) return apply(dispatch2, void 0, [error, trace]);
1656
+ record(positions, error, trace);
1657
+ return apply(own.fn, own.self, [error, trace]);
1658
+ };
1659
+ }
1660
+ function rawReader(overrides, fallback) {
1661
+ return (error) => {
1662
+ apply(mapSet, overrides, [
1663
+ error,
1664
+ (e, trace) => apply(fallback, void 0, [e, trace])
1665
+ ]);
1666
+ try {
1667
+ return error.stack;
1668
+ } finally {
1669
+ apply(mapDelete, overrides, [error]);
1670
+ }
1671
+ };
1672
+ }
1595
1673
  var found = internals();
1596
- if (found) found.setInternalPrepareStackTrace(stackDispatcher(found.fallback, found.positions));
1674
+ if (found) {
1675
+ const dispatch2 = stackDispatcher(found.fallback, found.positions);
1676
+ found.setInternalPrepareStackTrace(dispatch2);
1677
+ if (found.setCallback) {
1678
+ found.setCallback(kernelCallback(found, dispatch2));
1679
+ setRawStack(rawReader(found.overrides, found.fallback));
1680
+ }
1681
+ }
1597
1682
  function errorSourceOf(error) {
1598
1683
  if (typeof error !== "object" || error === null || !isNativeError(error)) return void 0;
1599
1684
  try {