@ai-ecoverse/slicc-kernel 1.164.4 → 1.165.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/README.md CHANGED
@@ -424,14 +424,16 @@ The module's default export (or its `main` export) is called with a context and
424
424
  - `sync.promiseState(promise)` (#1531, slicc-jsh#974) tells a native promise's state synchronously, as Node's `util.inspect` does: `{ state: 'pending' | 'fulfilled' | 'rejected', value }`. `value` is the very fulfillment value or rejection reason (`undefined` while pending), and probing doesn't handle a rejection. On the Node entry it reads the promise through an inspector session the process worker opens on first use, one per process and per thread; the probe runs no program code. Anything that isn't a native promise (a thenable, a proxy) is a `TypeError`. It answers `undefined` in a browser, where a worker has no inspector, on a Node built without one, once a program has changed `Object.prototype` or put a `toJSON` on a built-in prototype, and when the global object can't take a new property (`Object.preventExtensions(globalThis)`, or a frozen global).
425
425
  - `sync.setStackFormatter(fn | null)` (#1612, slicc-jsh#1091) is Node only, so check it with `typeof ctx.sync.setStackFormatter === 'function'`. It returns the previous formatter, and `null` removes it.
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
- - **What `fn` gets:** a fresh array of V8 CallSites holding only the program's own frames (its modules, `data:` imports, `sync.runScript` scripts and code they `eval`), `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`.
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` gets filtered frames on the Node entry** (#1631). The process worker replaces Node's stack callback with a copy of Node 26's order, so a program's own `Error.prepareStackTrace` (jest, depd, callsites, source-map-support) and a host preload's get the same filtered CallSite array as the formatter: no kernel frame and no host path. They're called with their `Error` as receiver, and their result and throws are the stack, as in Node. 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
- - `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`. 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.
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. A program's own `Error.prepareStackTrace` and the stack formatter 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.4" : "0.0.0-dev";
8443
+ var KERNEL_VERSION = true ? "1.165.0" : "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;
@@ -1498,6 +1517,7 @@ var hashOf = proto.getScriptHash;
1498
1517
  var isEval = proto.isEval;
1499
1518
  var originOf = proto.getEvalOrigin;
1500
1519
  var lineOf = proto.getLineNumber;
1520
+ var nameOf = proto.getScriptNameOrSourceURL;
1501
1521
  var ownNames = /* @__PURE__ */ new Set([
1502
1522
  apply(fileOf, self, []),
1503
1523
  apply(proto.getScriptNameOrSourceURL, self, [])
@@ -1531,12 +1551,22 @@ function rootOrigin(origin) {
1531
1551
  }
1532
1552
  return apply(slice, at, [0, end]);
1533
1553
  }
1554
+ function evalAt(origin) {
1555
+ return apply(startsWith, origin, ["eval at "]) === true;
1556
+ }
1557
+ function scriptOf(site) {
1558
+ if (apply(isEval, site, []) !== true) return apply(fileOf, site, []);
1559
+ const origin = apply(originOf, site, []);
1560
+ if (typeof origin !== "string" || evalAt(origin)) return void 0;
1561
+ return apply(nameOf, site, []);
1562
+ }
1534
1563
  function keptFrame(site) {
1535
1564
  const hash = apply(hashOf, site, []);
1536
1565
  if (hash === ownHash) return false;
1537
1566
  if (apply(isEval, site, []) === true) {
1538
1567
  const origin = apply(originOf, site, []);
1539
- return typeof origin === "string" && programName(rootOrigin(origin));
1568
+ if (typeof origin !== "string") return false;
1569
+ return !evalAt(origin) || programName(rootOrigin(origin));
1540
1570
  }
1541
1571
  const file = apply(fileOf, site, []);
1542
1572
  if (typeof file !== "string") return true;
@@ -1552,6 +1582,7 @@ function keptFrames(trace) {
1552
1582
  return out;
1553
1583
  }
1554
1584
  var formatter = null;
1585
+ var withOwn = false;
1555
1586
  var formatting = false;
1556
1587
  var seen = /* @__PURE__ */ new WeakMap();
1557
1588
  function positionsAt(positions, error, site) {
@@ -1562,17 +1593,20 @@ function positionsAt(positions, error, site) {
1562
1593
  return void 0;
1563
1594
  }
1564
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
+ }
1565
1602
  function stackDispatcher(fallback, positions) {
1566
1603
  return (error, trace) => {
1567
- if (typeof error === "object" && error !== null && trace.length > 0) {
1568
- const site = trace[0];
1569
- apply(mapSet, seen, [error, { site, at: positionsAt(positions, error, site) }]);
1570
- }
1571
- const fn = formatter;
1572
- 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]);
1573
1607
  formatting = true;
1574
1608
  try {
1575
- const out = apply(fn, void 0, [error, keptFrames(trace)]);
1609
+ const out = apply(fn2, void 0, [error, keptFrames(trace)]);
1576
1610
  if (typeof out === "string") return out;
1577
1611
  } catch {
1578
1612
  } finally {
@@ -1581,8 +1615,70 @@ function stackDispatcher(fallback, positions) {
1581
1615
  return apply(fallback, void 0, [error, trace]);
1582
1616
  };
1583
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 calling(() => apply(own.fn, own.self, [error, keptFrames(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
+ }
1584
1673
  var found = internals();
1585
- 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
+ }
1586
1682
  function errorSourceOf(error) {
1587
1683
  if (typeof error !== "object" || error === null || !isNativeError(error)) return void 0;
1588
1684
  try {
@@ -1596,7 +1692,7 @@ function errorSourceOf(error) {
1596
1692
  if (!at || typeof at.sourceLine !== "string" || typeof at.lineNumber !== "number")
1597
1693
  return void 0;
1598
1694
  if (apply(setHas, ownNames, [at.scriptResourceName]) === true) return void 0;
1599
- const file = apply(isEval, site, []) === true ? void 0 : apply(fileOf, site, []);
1695
+ const file = scriptOf(site);
1600
1696
  if (at.scriptResourceName !== file || apply(lineOf, site, []) !== at.lineNumber) return void 0;
1601
1697
  const out = blank(null);
1602
1698
  out.sourceLine = at.sourceLine;