@ai-ecoverse/slicc-kernel 1.166.0 → 1.166.2

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
@@ -429,11 +429,11 @@ The module's default export (or its `main` export) is called with a context and
429
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
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.
431
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`.
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.
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. For a `SyntaxError` from the native `JSON.parse`, called directly by the program's own code, it gives the parsed text's line (#1649); a `JSON.parse` called from Node's or the kernel's code gives `undefined`.
433
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.
434
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).
435
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.
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.
436
+ - **Kernel frames in a program's stacks** (#1583, #1656): on the Node entry, each process worker compiles its strict CommonJS bundle as a classic script named `slicc-kernel:/node-process-worker.js`. That is V8's script name, not just a `sourceURL`: kernel frames in a program's own errors, failed `ctx` calls and `runScript` use it in `.stack` and in every CallSite path method, including `getFileName()` and `getEvalOrigin()`. The bootstrap keeps its bindings private and uses a virtual base for builtin loading; no host bundle URL enters the worker. Its V8 code cache is made in workers and kept only in host memory, separate from the program module compile cache. 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 point into `dist/node-process-worker.cjs` on the default Node entry. **Documented exception: `--enable-source-maps`** allows Node to map frames back to source paths; don't enable it if program-visible paths matter. In a browser the frames keep the bundle's URL, because Chrome ignores `sourceURL` in a module worker loaded by URL. An explicit `worker` override keeps the embedder's worker script and its naming.
437
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.
438
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`.
439
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() }`.
@@ -8464,7 +8464,7 @@ function satisfies(version, range2) {
8464
8464
  }
8465
8465
 
8466
8466
  // src/version.ts
8467
- var KERNEL_VERSION = true ? "1.166.0" : "0.0.0-dev";
8467
+ var KERNEL_VERSION = true ? "1.166.2" : "0.0.0-dev";
8468
8468
  var OS_RELEASE = "6.0.0-slicc";
8469
8469
  function procVersion() {
8470
8470
  return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
@@ -1518,6 +1518,10 @@ var isEval = proto.isEval;
1518
1518
  var originOf = proto.getEvalOrigin;
1519
1519
  var lineOf = proto.getLineNumber;
1520
1520
  var nameOf = proto.getScriptNameOrSourceURL;
1521
+ var functionOf = proto.getFunctionName;
1522
+ var typeOf = proto.getTypeName;
1523
+ var syntaxProto = SyntaxError.prototype;
1524
+ var protoOf = Object.getPrototypeOf;
1521
1525
  var ownNames = /* @__PURE__ */ new Set([
1522
1526
  apply(fileOf, self, []),
1523
1527
  apply(proto.getScriptNameOrSourceURL, self, [])
@@ -1611,7 +1615,8 @@ function record(positions, error, trace) {
1611
1615
  if (typeof error === "object" && error !== null && trace.length > 0) {
1612
1616
  noteSourceUrls(trace);
1613
1617
  const site = trace[0];
1614
- apply(mapSet, seen, [error, { site, at: positionsAt(positions, error, site) }]);
1618
+ const next = trace[1];
1619
+ apply(mapSet, seen, [error, { site, next, at: positionsAt(positions, error, site) }]);
1615
1620
  }
1616
1621
  }
1617
1622
  function stackDispatcher(fallback, positions) {
@@ -1694,6 +1699,18 @@ if (found) {
1694
1699
  setRawStack(rawReader(found.overrides, found.fallback));
1695
1700
  }
1696
1701
  }
1702
+ function programFrame(site) {
1703
+ if (site === void 0 || !keptFrame(site)) return false;
1704
+ if (apply(isEval, site, []) === true) return true;
1705
+ const file = apply(fileOf, site, []);
1706
+ return typeof file === "string" && apply(startsWith, file, ["node:"]) !== true;
1707
+ }
1708
+ function jsonParseSite(error, got) {
1709
+ const { site, next } = got;
1710
+ if (protoOf(error) !== syntaxProto || apply(fileOf, site, []) !== null) return false;
1711
+ if (apply(functionOf, site, []) !== "parse" || apply(typeOf, site, []) !== "JSON") return false;
1712
+ return programFrame(next);
1713
+ }
1697
1714
  function errorSourceOf(error) {
1698
1715
  if (typeof error !== "object" || error === null || !isNativeError(error)) return void 0;
1699
1716
  try {
@@ -1707,8 +1724,13 @@ function errorSourceOf(error) {
1707
1724
  if (!at || typeof at.sourceLine !== "string" || typeof at.lineNumber !== "number")
1708
1725
  return void 0;
1709
1726
  if (apply(setHas, ownNames, [at.scriptResourceName]) === true) return void 0;
1727
+ if (jsonParseSite(error, got))
1728
+ return at.scriptResourceName === void 0 ? answer(at) : void 0;
1710
1729
  const file = scriptOf(site);
1711
1730
  if (at.scriptResourceName !== file || apply(lineOf, site, []) !== at.lineNumber) return void 0;
1731
+ return answer(at);
1732
+ }
1733
+ function answer(at) {
1712
1734
  const out = blank(null);
1713
1735
  out.sourceLine = at.sourceLine;
1714
1736
  out.lineNumber = at.lineNumber;