@ai-ecoverse/slicc-kernel 1.168.0 → 1.169.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/dist/node.js CHANGED
@@ -3695,7 +3695,7 @@ function satisfies(version, range2) {
3695
3695
  }
3696
3696
 
3697
3697
  // src/version.ts
3698
- var KERNEL_VERSION = true ? "1.168.0" : "0.0.0-dev";
3698
+ var KERNEL_VERSION = true ? "1.169.0" : "0.0.0-dev";
3699
3699
  var OS_RELEASE = "6.0.0-slicc";
3700
3700
  function procVersion() {
3701
3701
  return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
@@ -12248,6 +12248,8 @@ var SYS_TREE = {
12248
12248
  slicc_opfs_ops: (listing) => `${listing.opfsOps ?? 0}
12249
12249
  `,
12250
12250
  slicc_cwd_checks: (listing) => `${listing.cwdChecks ?? 0}
12251
+ `,
12252
+ slicc_package_swaps: ({ swaps }) => `${swaps?.swaps ?? 0} ${(swaps?.longestMs ?? 0).toFixed(1)} ${swaps?.waits ?? 0} ${(swaps?.waitedMs ?? 0).toFixed(1)}
12251
12253
  `,
12252
12254
  slicc_rename_ack_busy: (listing) => `${listing.renameAcks?.busy ?? 0}
12253
12255
  `,
@@ -25239,6 +25241,105 @@ function replayingHops(inner, heldMs = HELD_MS) {
25239
25241
  };
25240
25242
  }
25241
25243
 
25244
+ // src/kernel/package-swaps.ts
25245
+ var SWAP_GAP_MS = 2e3;
25246
+ var STAGES = ["_tmp_", "_pacquet-stage_"];
25247
+ function staged(source, target) {
25248
+ if (parentOf(source) !== parentOf(target)) return false;
25249
+ const name2 = target.slice(target.lastIndexOf("/") + 1);
25250
+ const from = source.slice(source.lastIndexOf("/") + 1);
25251
+ return from.startsWith(`.${name2}-`) || STAGES.some((stage) => from.startsWith(`${name2}${stage}`));
25252
+ }
25253
+ var PackageSwaps = class {
25254
+ gaps = /* @__PURE__ */ new Map();
25255
+ isRoot;
25256
+ hold;
25257
+ closed;
25258
+ gapMs;
25259
+ tally = { swaps: 0, longestMs: 0, waits: 0, waitedMs: 0 };
25260
+ constructor(isRoot, hold, closed, gapMs = SWAP_GAP_MS) {
25261
+ this.isRoot = isRoot;
25262
+ this.hold = hold;
25263
+ this.closed = closed;
25264
+ this.gapMs = gapMs;
25265
+ }
25266
+ counts() {
25267
+ return { ...this.tally };
25268
+ }
25269
+ settled() {
25270
+ if (this.gaps.size === 0) return Promise.resolve();
25271
+ const started = performance.now();
25272
+ this.tally.waits++;
25273
+ return Promise.all([...this.gaps.values()].map((gap) => gap.settled)).then(() => {
25274
+ this.tally.waitedMs += performance.now() - started;
25275
+ });
25276
+ }
25277
+ wrap(fs) {
25278
+ return { ...fs, rename: (from, to) => this.rename(fs, from, to) };
25279
+ }
25280
+ async rename(fs, from, to) {
25281
+ const source = fs.resolvePath("/", from);
25282
+ const target = fs.resolvePath("/", to);
25283
+ const gap = this.gaps.get(target);
25284
+ if (gap) return this.land(gap, target, () => fs.rename(from, to));
25285
+ if (source === target || this.gaps.has(source) || staged(source, target) || !this.isRoot(source)) {
25286
+ return fs.rename(from, to);
25287
+ }
25288
+ const release = await this.hold(source);
25289
+ let kept = false;
25290
+ try {
25291
+ await fs.rename(from, to);
25292
+ kept = await fs.stat(`${target}/package.json`).then(
25293
+ (st) => st.isFile,
25294
+ () => false
25295
+ );
25296
+ if (kept) this.open(source, release);
25297
+ } finally {
25298
+ if (!kept) release();
25299
+ }
25300
+ }
25301
+ open(root, release) {
25302
+ const { promise, resolve: resolve2 } = Promise.withResolvers();
25303
+ const gap = {
25304
+ release,
25305
+ done: () => resolve2(),
25306
+ settled: promise,
25307
+ timer: void 0,
25308
+ landing: 0,
25309
+ opened: performance.now()
25310
+ };
25311
+ this.gaps.set(root, gap);
25312
+ this.tally.swaps++;
25313
+ this.arm(root, gap);
25314
+ }
25315
+ arm(root, gap) {
25316
+ const timer = setTimeout(() => this.close(root, gap), this.gapMs);
25317
+ timer.unref?.();
25318
+ gap.timer = timer;
25319
+ }
25320
+ close(root, gap) {
25321
+ if (this.gaps.get(root) !== gap) return;
25322
+ clearTimeout(gap.timer);
25323
+ this.gaps.delete(root);
25324
+ this.tally.longestMs = Math.max(this.tally.longestMs, performance.now() - gap.opened);
25325
+ this.closed();
25326
+ gap.done();
25327
+ gap.release();
25328
+ }
25329
+ async land(gap, root, run2) {
25330
+ gap.landing++;
25331
+ clearTimeout(gap.timer);
25332
+ try {
25333
+ await run2();
25334
+ } catch (err) {
25335
+ gap.landing--;
25336
+ if (gap.landing === 0 && this.gaps.get(root) === gap) this.arm(root, gap);
25337
+ throw err;
25338
+ }
25339
+ this.close(root, gap);
25340
+ }
25341
+ };
25342
+
25242
25343
  // src/kernel/rename-log.ts
25243
25344
  var RENAME_LOG_SIZE = 4096;
25244
25345
  function within8(path, root) {
@@ -25307,6 +25408,18 @@ var PackageLocks = class {
25307
25408
  const names2 = roots.map((root) => replacingLock(this.metadata, root));
25308
25409
  return shared(this.locks, names2, run2, false);
25309
25410
  }
25411
+ holding(root) {
25412
+ const { locks } = this;
25413
+ if (!locks) return Promise.resolve(() => {
25414
+ });
25415
+ const { promise: held, resolve: release } = Promise.withResolvers();
25416
+ return new Promise((granted2, failed3) => {
25417
+ locks.request(replacingLock(this.metadata, root), { mode: "exclusive" }, () => {
25418
+ granted2(() => release());
25419
+ return held;
25420
+ }).catch(failed3);
25421
+ });
25422
+ }
25310
25423
  };
25311
25424
 
25312
25425
  // src/kernel/settling.ts
@@ -27242,15 +27355,15 @@ var OpfsFs = class {
27242
27355
  const hooks = {};
27243
27356
  const staging = swap ? `.${name2}.${crypto.randomUUID()}` : name2;
27244
27357
  const copying = sourceStat.isDirectory && !movable(source.handle);
27245
- const staged = resolvePath(parent.path, staging);
27358
+ const staged2 = resolvePath(parent.path, staging);
27246
27359
  const place = async () => {
27247
27360
  this.forget(destination);
27248
27361
  const copies = /* @__PURE__ */ new Map();
27249
27362
  const root = { ino: inodeOf(source.path), ...moving };
27250
27363
  const owned4 = lock ? { lock } : {};
27251
27364
  hooks.notify?.();
27252
- const first = copying ? await this.intend({ from: source.path, to: staged, root, ...owned4 }) : void 0;
27253
- const second = copying && swap ? await this.intend({ from: staged, to: destination, replace: true, root, ...owned4 }) : void 0;
27365
+ const first = copying ? await this.intend({ from: source.path, to: staged2, root, ...owned4 }) : void 0;
27366
+ const second = copying && swap ? await this.intend({ from: staged2, to: destination, replace: true, root, ...owned4 }) : void 0;
27254
27367
  await hooks.started?.().catch(async (err) => {
27255
27368
  for (const intent of [first, second]) {
27256
27369
  if (intent) await this.meta.update(intent, () => void 0);
@@ -27261,11 +27374,11 @@ var OpfsFs = class {
27261
27374
  targetStat !== null,
27262
27375
  () => this.place(source.handle, dir, staging, copies)
27263
27376
  ).catch(async (err) => {
27264
- if (first) await this.rollBack(staged, source.path, [first, second]);
27377
+ if (first) await this.rollBack(staged2, source.path, [first, second]);
27265
27378
  throw err;
27266
27379
  });
27267
27380
  if (swap) await this.rm(destination, { recursive: true });
27268
- if (second) await this.intend({ from: staged, to: destination, root, ...owned4 }, second);
27381
+ if (second) await this.intend({ from: staged2, to: destination, root, ...owned4 }, second);
27269
27382
  await this.meta.move(source.path, destination, carry, left);
27270
27383
  this.movePending(source.path, destination);
27271
27384
  if (!moved2) {
@@ -29955,15 +30068,15 @@ var UserDb = class {
29955
30068
  (r) => r !== row && this.fs.resolvePath("/", r.home) === home
29956
30069
  );
29957
30070
  const removeHome = !options.keepHome && !shared2 && HOME_DIR.test(home) && await this.fs.exists(home);
29958
- const staged = `/home/.${name2}.removed-${Date.now()}`;
30071
+ const staged2 = `/home/.${name2}.removed-${Date.now()}`;
29959
30072
  await this.commit(
29960
30073
  formatPasswd(passwd.filter((r) => r !== row)),
29961
30074
  formatGroup(keptGroups),
29962
- removeHome ? () => this.fs.rename(home, staged) : void 0
30075
+ removeHome ? () => this.fs.rename(home, staged2) : void 0
29963
30076
  );
29964
30077
  this.umasks.delete(name2);
29965
30078
  if (removeHome)
29966
- await this.fs.rm(staged, { recursive: true, force: true }).catch(() => void 0);
30079
+ await this.fs.rm(staged2, { recursive: true, force: true }).catch(() => void 0);
29967
30080
  return true;
29968
30081
  });
29969
30082
  }
@@ -30700,6 +30813,11 @@ var Launcher = class {
30700
30813
  jobs = new JobTable();
30701
30814
  locks;
30702
30815
  packageLocks;
30816
+ swaps = new PackageSwaps(
30817
+ (path) => this.packageRootIs(path),
30818
+ (root) => this.packageLocks.holding(root),
30819
+ () => this.resetCatalogs()
30820
+ );
30703
30821
  fifos = new FifoTable();
30704
30822
  memories;
30705
30823
  sems = new SemTable();
@@ -30990,7 +31108,7 @@ var Launcher = class {
30990
31108
  commands(scope = "") {
30991
31109
  let found = this.catalogs.get(scope);
30992
31110
  if (!found) {
30993
- found = this.trustedAppended().then(async (appended2) => {
31111
+ found = this.swaps.settled().then(() => this.trustedAppended()).then(async (appended2) => {
30994
31112
  const tiers = await this.tiers(scope, appended2);
30995
31113
  const refused3 = [];
30996
31114
  const commands = await scanCommands(
@@ -31835,6 +31953,13 @@ var Launcher = class {
31835
31953
  if (readsEtcHostname(program)) setOrDrop(env, "HOSTNAME", own);
31836
31954
  return { planned, env, program, exeId };
31837
31955
  }
31956
+ packageRootIs(path) {
31957
+ const at = normalizePath(path);
31958
+ const within10 = `${at}/`;
31959
+ const roots = [this.modulesDir, ...this.appended];
31960
+ const root = PACKAGE_ROOT.exec(within10)?.[1] ?? packageRootOf(within10, roots);
31961
+ return root === at;
31962
+ }
31838
31963
  packageRoots(planned) {
31839
31964
  const packages2 = [this.modulesDir, ...this.appended];
31840
31965
  const roots = /* @__PURE__ */ new Set();
@@ -32020,6 +32145,7 @@ var Launcher = class {
32020
32145
  opfsOps: this.rootFs.opfsOps?.() ?? 0,
32021
32146
  cwdChecks: this.cwds.checks,
32022
32147
  renameAcks: this.rootFs.renameWaits?.(),
32148
+ swaps: this.swaps.counts(),
32023
32149
  staleFds: staleFdCount(),
32024
32150
  fileIds: this.rootFs.fileIdWrites?.() ?? 0,
32025
32151
  holds: this.rootFs.holdCounts?.()
@@ -32276,6 +32402,7 @@ var Launcher = class {
32276
32402
  spawner(ppid, report) {
32277
32403
  return async (req, fds, grant) => {
32278
32404
  const booked = this.takeTicket(req);
32405
+ await this.swaps.settled();
32279
32406
  if (grant && !await this.grantedCwd(grant.caller, req.cwd)) {
32280
32407
  await fds.closeAll();
32281
32408
  throw new SpawnError("EACCES");
@@ -33188,10 +33315,12 @@ var Launcher = class {
33188
33315
  nodes.changed = (path) => this.changes.publish(path);
33189
33316
  nodes.movedAway = (from, to) => this.moved(from, to, nodes);
33190
33317
  nodes.dirtied = (delta) => this.changes.dirtied(delta);
33191
- return unlinked.wrap(keepingOpen(fs, nodes, (path) => this.changes.publish(path)));
33318
+ const kept = keepingOpen(fs, nodes, (path) => this.changes.publish(path));
33319
+ return this.swaps.wrap(unlinked.wrap(kept));
33192
33320
  }
33193
33321
  async starting(argv, dir, account, tags, base) {
33194
33322
  const tag = tags?.[0];
33323
+ await this.swaps.settled();
33195
33324
  this.resetCatalogs();
33196
33325
  const scope = account.uid === 0 ? "" : pnpmHomeOf(account, this.pnpmHome);
33197
33326
  const start2 = dir ?? "/";
@@ -33365,7 +33494,7 @@ function sendableClose(code) {
33365
33494
  function blockedReason(url, e) {
33366
33495
  const name2 = e?.name;
33367
33496
  if (name2 === "SecurityError" && url.startsWith("ws:")) {
33368
- return `${url}: ws:// is blocked from an https page; use wss:// or slicc-node`;
33497
+ return `${url}: ws:// is blocked from an https page; use wss://, or link a slicc CLI (npx sliccy@next)`;
33369
33498
  }
33370
33499
  return `${url}: ${e instanceof Error ? e.message : String(e)}`;
33371
33500
  }