@ai-ecoverse/slicc-kernel 1.165.2 → 1.166.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,7 +424,7 @@ 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, 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`.
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`, `new Function` or `eval` code named by `//# sourceURL`, #1632, and code such a body `eval`s, #1648), `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
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.
@@ -8464,7 +8464,7 @@ function satisfies(version, range2) {
8464
8464
  }
8465
8465
 
8466
8466
  // src/version.ts
8467
- var KERNEL_VERSION = true ? "1.165.2" : "0.0.0-dev";
8467
+ var KERNEL_VERSION = true ? "1.166.0" : "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
@@ -24325,6 +24325,7 @@ function within8(path, root) {
24325
24325
  return path === root || path.startsWith(root.endsWith("/") ? root : `${root}/`);
24326
24326
  }
24327
24327
  var VfsNode = class {
24328
+ fid;
24328
24329
  data;
24329
24330
  ranged;
24330
24331
  pin;
@@ -24632,6 +24633,7 @@ var VfsNodes = class {
24632
24633
  keepsOnDisk = false;
24633
24634
  changed;
24634
24635
  movedAway;
24636
+ opened;
24635
24637
  dirtied;
24636
24638
  fs;
24637
24639
  entries;
@@ -24791,6 +24793,7 @@ var VfsNodes = class {
24791
24793
  node.ino ??= ino;
24792
24794
  node.opens++;
24793
24795
  if (writable2) node.writers++;
24796
+ if (node.opens === 1) this.opened?.(node);
24794
24797
  return node;
24795
24798
  }
24796
24799
  adopt(path, contents2, dirty, writable2 = false, id2) {
@@ -24802,6 +24805,7 @@ var VfsNodes = class {
24802
24805
  }
24803
24806
  node.opens++;
24804
24807
  if (writable2) node.writers++;
24808
+ if (node.opens === 1) this.opened?.(node);
24805
24809
  return node;
24806
24810
  }
24807
24811
  holds(prefix) {
@@ -24828,6 +24832,32 @@ var VfsNodes = class {
24828
24832
  held() {
24829
24833
  return this.byPath.keys();
24830
24834
  }
24835
+ heldIds() {
24836
+ const out = [];
24837
+ for (const [path, node] of this.byPath) if (!this.kept.has(node)) out.push([path, node.fid]);
24838
+ return out;
24839
+ }
24840
+ holdsAt(path) {
24841
+ return this.byPath.has(path);
24842
+ }
24843
+ async bindIds(id2) {
24844
+ for (const [path, node] of [...this.byPath]) {
24845
+ if (node.fid !== void 0 || this.kept.has(node)) continue;
24846
+ node.fid = await id2(path)?.catch(() => void 0);
24847
+ }
24848
+ }
24849
+ keepBound(paths, fid, file) {
24850
+ for (const at of paths) {
24851
+ const node = this.byPath.get(at);
24852
+ if (!node || this.kept.has(node) || node.fid !== fid) continue;
24853
+ this.byPath.delete(at);
24854
+ node.renamedTo(file.hidden);
24855
+ this.byPath.set(file.hidden, node);
24856
+ this.kept.set(node, file);
24857
+ return true;
24858
+ }
24859
+ return false;
24860
+ }
24831
24861
  owns() {
24832
24862
  return false;
24833
24863
  }
@@ -31459,7 +31489,7 @@ var Launcher = class {
31459
31489
  enableCdp(this.net, this.cdp);
31460
31490
  this.facades.enable(this.net);
31461
31491
  const fs = this.commandFs(this.base);
31462
- this.nodes = new VfsNodes(fs, (path) => this.released(path));
31492
+ this.nodes = this.openNodes(fs);
31463
31493
  this.nodes.keepsOnDisk = true;
31464
31494
  this.openFiles.add(this.nodes);
31465
31495
  options.fs.onPeer?.(() => this.flushOpen());
@@ -33020,8 +33050,8 @@ var Launcher = class {
33020
33050
  const at = normalizePath(path);
33021
33051
  this.unlinked.closed(at);
33022
33052
  this.writers?.unlinked.closed(at);
33023
- if (![...this.held].some((holds2) => holds2.holding(at)))
33024
- void this.rootFs.announceHolds?.([], [at], false);
33053
+ const holding = [...this.held].some((holds2) => holds2.holding(at)) || [...this.openFiles].some((open3) => open3.holdsAt(at));
33054
+ if (!holding) void this.rootFs.announceHolds?.([], [at], false);
33025
33055
  const open2 = [...this.openFiles].some((nodes) => nodes.writes(at)) || heldUnder(this.held, at);
33026
33056
  if (!open2) void this.mounts.commit(at).catch(() => void 0);
33027
33057
  }
@@ -33547,13 +33577,34 @@ var Launcher = class {
33547
33577
  (holds2) => [holds2, [...holds2.boundAt(path, fid), ...holds2.boundAt(hidden, fid)]]
33548
33578
  );
33549
33579
  const keeping = bound3.filter(([, ids]) => ids.length > 0);
33550
- const file = this.unlinked.adopt(hidden, Math.max(keeping.length, 1));
33551
- if (keeping.length === 0) file.release();
33580
+ const nodes = [...this.openFiles].filter(
33581
+ (open2) => [path, hidden].some((at) => open2.holdsAt(at))
33582
+ );
33583
+ const file = this.unlinked.adopt(hidden, Math.max(keeping.length + nodes.length, 1));
33584
+ const kept = nodes.filter((open2) => open2.keepBound([hidden, path], fid, file)).length;
33585
+ for (let i = kept; i < nodes.length; i++) file.release();
33586
+ if (keeping.length === 0 && nodes.length === 0) file.release();
33552
33587
  for (const [holds2, ids] of keeping) holds2.keepBound(ids, path, file);
33553
33588
  void this.rootFs.announceHolds?.([], [path, hidden], false);
33554
33589
  }
33590
+ openNodes(fs, entries) {
33591
+ const nodes = new VfsNodes(fs, (path) => this.released(path), entries);
33592
+ nodes.opened = (node) => this.nodeOpened(node);
33593
+ return nodes;
33594
+ }
33595
+ nodeOpened(node) {
33596
+ const path = node.path;
33597
+ if (this.locks.shared?.() !== true || this.mounts.locate(path) !== void 0) return;
33598
+ void (async () => {
33599
+ node.fid ??= await this.rootFileId(path)?.catch(() => void 0);
33600
+ if (node.opens > 0) await this.rootFs.announceHolds?.([[node.path, node.fid]], [], false);
33601
+ })();
33602
+ }
33555
33603
  announceHeld() {
33556
- const held = this.held.heldIds().filter(([path]) => this.mounts.locate(path) === void 0);
33604
+ const nodes = [...this.openFiles].flatMap((open2) => open2.heldIds());
33605
+ const held = [...this.held.heldIds(), ...nodes].filter(
33606
+ ([path]) => this.mounts.locate(path) === void 0 && !path.startsWith(`/${UNLINKED_DIR}/`)
33607
+ );
33557
33608
  return held.length === 0 ? void 0 : this.rootFs.announceHolds?.(held, [], false);
33558
33609
  }
33559
33610
  rootFileId(path) {
@@ -33567,7 +33618,9 @@ var Launcher = class {
33567
33618
  this.changes.flush();
33568
33619
  this.changes.foreign(crowded);
33569
33620
  if (crowded) {
33570
- void this.held?.bindIds((path) => this.rootFileId(path)).then(() => this.announceHeld());
33621
+ void this.held.bindIds((path) => this.rootFileId(path)).then(
33622
+ () => Promise.all([...this.openFiles].map((open2) => open2.bindIds((p) => this.rootFileId(p))))
33623
+ ).then(() => this.announceHeld());
33571
33624
  for (const nodes of this.openFiles) nodes.shared();
33572
33625
  }
33573
33626
  });
@@ -33592,7 +33645,7 @@ var Launcher = class {
33592
33645
  writerStack() {
33593
33646
  const mounted = this.mounts.wrap(this.unguardedRoot);
33594
33647
  const fs = this.commandFs(this.rooted(mounted));
33595
- const nodes = new VfsNodes(fs, (path) => this.released(path), this.nodes.entries);
33648
+ const nodes = this.openNodes(fs, this.nodes.entries);
33596
33649
  nodes.keepsOnDisk = true;
33597
33650
  this.openFiles.add(nodes);
33598
33651
  const unlinked = new UnlinkedKeeper(
@@ -33657,6 +33710,7 @@ var Launcher = class {
33657
33710
  moved(from, to, source) {
33658
33711
  this.renameLog.add(from, to);
33659
33712
  for (const holds2 of this.held) holds2.renamed(from, to);
33713
+ if (this.mounts.locate(to) === void 0) this.rootFs.rehold?.(from, to);
33660
33714
  if (source) return;
33661
33715
  for (const nodes of this.openFiles) nodes.renamed(from, to);
33662
33716
  this.watchers.moved(from, to);