@ai-ecoverse/slicc-kernel 1.142.3 → 1.143.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
@@ -406,6 +406,7 @@ The module's default export (or its `main` export) is called with a context and
406
406
  - **Only the named descriptors reach the child.** Others the program holds, the other end of a pair included, don't, and a grandchild gets fd 3 only if the child names it again.
407
407
  - **The parent's copy:** the program keeps `f` and closes it itself when it no longer needs it, so the child sees end of file once it's the only one left.
408
408
  - **Why a `Record`:** it can't name a child fd twice, and it reads like Node's `stdio` index, so it's this rather than a list of `{ fd, from }`.
409
+ - `asyncContext` (the Node entry only; absent in a browser, so a runtime feature-detects it; #1350, slicc-jsh#375) is `{ run(store, fn, ...args), getStore(), enterWith(store) }`, backed by one host `AsyncLocalStorage` the process worker makes for each program, since a program can't import `node:async_hooks` and the realm has no promise hooks of its own. A store follows the program's native `await` continuations and promise jobs, as an `AsyncLocalStorage` does in Node, so Next.js, OpenTelemetry and request-context loggers keep their context. Each process and each thread has its own. Only these three frozen functions on a frozen null-prototype object reach the program: they hold the host storage in a closure, `run` calls the program's function with its own arguments, and nothing they return or expose is a host object.
409
410
  - `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` and `arrayBuffers`. 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`; there is no `rss`, which is the whole host's. In a browser `memory()` answers `{}` for now.
410
411
  - **`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() }`.
411
412
  - **What a thread is:** a new process worker in the **same process**. It has the same pid, descriptor table, cwd, umask, credentials and lockdown, and a sync lane of its own, so `sync` calls in one thread don't hold another.
@@ -1279,6 +1279,7 @@ var escapeRoot = (name2) => name2.replace(/[%:]/g, (c) => `%${c.charCodeAt(0).to
1279
1279
  var LEGACY_RENAME_LOCK = /^slicc-rename:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
1280
1280
  var PAIRED = /* @__PURE__ */ new Set(["rename", "link", "copyFile"]);
1281
1281
  var LISTINGS = /* @__PURE__ */ new Set(["readdir", "readdirStat"]);
1282
+ var REMOVALS = /* @__PURE__ */ new Set(["rm", "rename"]);
1282
1283
  var RETRY = /* @__PURE__ */ Symbol("retry");
1283
1284
  var ACK_SAMPLES = 4096;
1284
1285
  var INTENT_POLL_MS = 5;
@@ -2757,10 +2758,11 @@ var OpfsFs = class {
2757
2758
  const running = [...this.inflight];
2758
2759
  const reached = await Promise.all(
2759
2760
  running.map(async (op) => {
2760
- if (op.paths.some((at) => touches(at, trees))) return true;
2761
+ const near = (at) => touches(at, trees, true, op.removing === true);
2762
+ if (op.paths.some(near)) return true;
2761
2763
  for (const at of op.paths) {
2762
2764
  const forms = await this.resolvedForms(at);
2763
- if (forms.some((form) => touches(form, trees))) return true;
2765
+ if (forms.some(near)) return true;
2764
2766
  }
2765
2767
  return false;
2766
2768
  })
@@ -2777,10 +2779,10 @@ var OpfsFs = class {
2777
2779
  })
2778
2780
  );
2779
2781
  }
2780
- peerAt(at, listing) {
2782
+ peerAt(at, listing, removing = false) {
2781
2783
  for (const move of this.peerMoves.values()) {
2782
2784
  if (this.ownLocks.has(move.lock)) continue;
2783
- if (touches(at, move.trees, listing)) return move;
2785
+ if (touches(at, move.trees, listing, removing)) return move;
2784
2786
  }
2785
2787
  return void 0;
2786
2788
  }
@@ -2815,11 +2817,11 @@ var OpfsFs = class {
2815
2817
  this.peerWaits.set(move.lock, wait2);
2816
2818
  return wait2;
2817
2819
  }
2818
- async peerSettled(at, listing) {
2820
+ async peerSettled(at, listing, removing) {
2819
2821
  await this.lookForRenames();
2820
2822
  for (let reals; ; ) {
2821
2823
  const forms = [at, ...reals ?? []];
2822
- const move = forms.map((form) => this.peerAt(form, listing)).find(Boolean);
2824
+ const move = forms.map((form) => this.peerAt(form, listing, removing)).find(Boolean);
2823
2825
  if (move) {
2824
2826
  this.peerWaited++;
2825
2827
  await this.peerMoved(move);
@@ -2857,13 +2859,14 @@ var OpfsFs = class {
2857
2859
  async peerOp(name2, args, inner) {
2858
2860
  const paths = (name2 === "symlink" ? args.slice(1, 2) : PAIRED.has(name2) ? args.slice(0, 2) : args.slice(0, 1)).filter((path) => typeof path === "string").map(normalizePath);
2859
2861
  const listing = LISTINGS.has(name2);
2862
+ const removing = REMOVALS.has(name2);
2860
2863
  const checked = [...paths];
2861
2864
  while (this.amongPeers()) {
2862
2865
  checked.length = 0;
2863
- for (const at of paths) checked.push(...await this.peerSettled(at, listing));
2864
- if (!checked.some((at) => this.peerAt(at, listing))) break;
2866
+ for (const at of paths) checked.push(...await this.peerSettled(at, listing, removing));
2867
+ if (!checked.some((at) => this.peerAt(at, listing, removing))) break;
2865
2868
  }
2866
- const busy = { paths: checked, release: () => void 0 };
2869
+ const busy = { paths: checked, removing, release: () => void 0 };
2867
2870
  const done5 = () => {
2868
2871
  this.inflight.delete(busy);
2869
2872
  busy.waiting?.resolve();
@@ -3288,9 +3291,9 @@ var OpfsFs = class {
3288
3291
  function nothing() {
3289
3292
  return void 0;
3290
3293
  }
3291
- function touches(at, trees, listing = true) {
3294
+ function touches(at, trees, listing = true, removing = false) {
3292
3295
  return trees.some(
3293
- ([from, to]) => within2(at, from) || within2(at, to) || listing && (at === parentOf3(from) || at === parentOf3(to))
3296
+ ([from, to]) => within2(at, from) || within2(at, to) || listing && (at === parentOf3(from) || at === parentOf3(to)) || removing && (at === "/" || within2(from, at) || within2(to, at))
3294
3297
  );
3295
3298
  }
3296
3299
  function byIntent(a, b) {
@@ -7595,7 +7598,7 @@ function satisfies(version, range2) {
7595
7598
  }
7596
7599
 
7597
7600
  // src/version.ts
7598
- var KERNEL_VERSION = true ? "1.142.3" : "0.0.0-dev";
7601
+ var KERNEL_VERSION = true ? "1.143.1" : "0.0.0-dev";
7599
7602
  var OS_RELEASE = "6.0.0-slicc";
7600
7603
  function procVersion() {
7601
7604
  return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
@@ -13577,7 +13580,7 @@ async function guardAndResolve(entry, path, req) {
13577
13580
  entry: { ...entry, fs: noLinks }
13578
13581
  };
13579
13582
  }
13580
- var REMOVALS = /* @__PURE__ */ new Set(["unlink", "rmdir", "rm"]);
13583
+ var REMOVALS2 = /* @__PURE__ */ new Set(["unlink", "rmdir", "rm"]);
13581
13584
  var CREATIONS = /* @__PURE__ */ new Set([
13582
13585
  "write",
13583
13586
  "mkdir",
@@ -13623,7 +13626,7 @@ async function dispatchPath(entry, req) {
13623
13626
  const { fs, cwd } = entry;
13624
13627
  try {
13625
13628
  const path = fs.resolvePath(cwd, req.path);
13626
- const device = REMOVALS.has(req.op) ? devRemoval(path, entry.cred?.()) : void 0;
13629
+ const device = REMOVALS2.has(req.op) ? devRemoval(path, entry.cred?.()) : void 0;
13627
13630
  if (device) return { ok: false, errno: device, message: `${path}: a device entry stays` };
13628
13631
  const made2 = await newDevName(entry, path, req);
13629
13632
  if (made2) return made2;