@ai-ecoverse/slicc-kernel 1.128.2 → 1.129.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
@@ -3821,14 +3821,14 @@ var Integrity = class {
3821
3821
  if (!this.root.version) return void 0;
3822
3822
  return `${real}\0${await this.root.version(real)}`;
3823
3823
  }
3824
- async read(path, caller, plain2, asked) {
3825
- return (await this.readKeyed(path, caller, plain2, asked)).bytes;
3824
+ async read(path, caller, plain3, asked) {
3825
+ return (await this.readKeyed(path, caller, plain3, asked)).bytes;
3826
3826
  }
3827
- async readKeyed(path, caller, plain2, asked) {
3827
+ async readKeyed(path, caller, plain3, asked) {
3828
3828
  const found = await this.real(path, asked);
3829
- if (found === void 0) return { bytes: await plain2() };
3829
+ if (found === void 0) return { bytes: await plain3() };
3830
3830
  const { real, name: name2 } = found;
3831
- const read = name2 !== real ? { bytes: await plain2(), version: void 0 } : this.root.readVersioned ? await this.root.readVersioned(real) : { bytes: await this.root.readFileBuffer(real), version: void 0 };
3831
+ const read = name2 !== real ? { bytes: await plain3(), version: void 0 } : this.root.readVersioned ? await this.root.readVersioned(real) : { bytes: await this.root.readFileBuffer(real), version: void 0 };
3832
3832
  const { bytes } = read;
3833
3833
  const keyed = read.version === void 0 ? { bytes } : { bytes, key: `${real}\0${read.version}` };
3834
3834
  await this.verify(name2, bytes, caller, EXEC_OPS);
@@ -3837,9 +3837,9 @@ var Integrity = class {
3837
3837
  get readsChecked() {
3838
3838
  return this.sources.length > 0;
3839
3839
  }
3840
- async readSource(path, caller, plain2) {
3840
+ async readSource(path, caller, plain3) {
3841
3841
  const found = await this.source(path);
3842
- return found === void 0 ? plain2() : this.checked(found, caller, plain2);
3842
+ return found === void 0 ? plain3() : this.checked(found, caller, plain3);
3843
3843
  }
3844
3844
  async openSource(path, caller, real) {
3845
3845
  const found = await this.source(path, real);
@@ -3849,10 +3849,10 @@ var Integrity = class {
3849
3849
  }
3850
3850
  await this.checked(found, caller, () => this.root.readFileBuffer(found.real));
3851
3851
  }
3852
- async checked(found, caller, plain2) {
3852
+ async checked(found, caller, plain3) {
3853
3853
  const { real, name: name2 } = found;
3854
3854
  if (name2 !== real || !this.root.readVersioned) {
3855
- const bytes2 = await plain2();
3855
+ const bytes2 = await plain3();
3856
3856
  await this.verify(name2, bytes2, caller, READ_OPS);
3857
3857
  return bytes2;
3858
3858
  }
@@ -6785,11 +6785,11 @@ function frame(opcode, payload) {
6785
6785
  return out;
6786
6786
  }
6787
6787
  function clientFrame(opcode, payload) {
6788
- const plain2 = frame(opcode, payload);
6789
- const head = plain2.length - payload.length;
6788
+ const plain3 = frame(opcode, payload);
6789
+ const head = plain3.length - payload.length;
6790
6790
  const mask = crypto.getRandomValues(new Uint8Array(4));
6791
- const out = new Uint8Array(plain2.length + 4);
6792
- out.set(plain2.subarray(0, head));
6791
+ const out = new Uint8Array(plain3.length + 4);
6792
+ out.set(plain3.subarray(0, head));
6793
6793
  out[1] = out[1] | 128;
6794
6794
  out.set(mask, head);
6795
6795
  for (let i = 0; i < payload.length; i++) {
@@ -7392,7 +7392,7 @@ function satisfies(version, range2) {
7392
7392
  }
7393
7393
 
7394
7394
  // src/version.ts
7395
- var KERNEL_VERSION = true ? "1.128.2" : "0.0.0-dev";
7395
+ var KERNEL_VERSION = true ? "1.129.0" : "0.0.0-dev";
7396
7396
  var OS_RELEASE = "6.0.0-slicc";
7397
7397
  function procVersion() {
7398
7398
  return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
@@ -12391,13 +12391,13 @@ async function chown(entry, path, req) {
12391
12391
  }
12392
12392
  async function runMkdir(entry, path, req) {
12393
12393
  const { fs } = entry;
12394
- const plain2 = plainDirMode(entry, req.mode);
12394
+ const plain3 = plainDirMode(entry, req.mode);
12395
12395
  const parentsMode = !req.exclusive ? plainParentsMode(entry) : void 0;
12396
12396
  const fixParents = parentsMode !== void 0 ? await missingParents(fs, path, parentsMode) : void 0;
12397
- const fresh2 = plain2 !== void 0 && !await fs.exists(path);
12397
+ const fresh2 = plain3 !== void 0 && !await fs.exists(path);
12398
12398
  await (req.exclusive ? mkdirExclusive(entry, path, req.mode) : fs.mkdir(path, mkdirOptions(entry, req.mode)));
12399
12399
  await fixParents?.();
12400
- if (fresh2) await fs.chmod(path, plain2);
12400
+ if (fresh2) await fs.chmod(path, plain3);
12401
12401
  return done;
12402
12402
  }
12403
12403
  async function shownAs(entry, path, st) {
@@ -12405,8 +12405,8 @@ async function shownAs(entry, path, st) {
12405
12405
  return callerStat(guardOf(entry), await real?.catch(() => path) ?? path, st);
12406
12406
  }
12407
12407
  function readSource(entry, path) {
12408
- const plain2 = () => entry.fs.readFileBuffer(path);
12409
- return entry.source ? entry.source.read(path, plain2) : plain2();
12408
+ const plain3 = () => entry.fs.readFileBuffer(path);
12409
+ return entry.source ? entry.source.read(path, plain3) : plain3();
12410
12410
  }
12411
12411
  async function run(entry, path, req) {
12412
12412
  const { fs, cwd } = entry;
@@ -18345,6 +18345,95 @@ async function substituteHead(head, ask) {
18345
18345
  `, values };
18346
18346
  }
18347
18347
 
18348
+ // src/kernel/net/sealed-smtp.ts
18349
+ var SMTP_LINE_MAX = 4096;
18350
+ var GREETING = ["EHLO ", "HELO "];
18351
+ function sniffSmtp(start2) {
18352
+ const upper = start2.toUpperCase();
18353
+ for (const word of GREETING) {
18354
+ if (upper.startsWith(word)) return "yes";
18355
+ if (word.startsWith(upper)) return "more";
18356
+ }
18357
+ return "no";
18358
+ }
18359
+ function decoded(b64) {
18360
+ if (!/^[A-Za-z0-9+/]+={0,2}$/.test(b64)) return void 0;
18361
+ try {
18362
+ return atob(b64);
18363
+ } catch {
18364
+ return void 0;
18365
+ }
18366
+ }
18367
+ async function swapped2(text, position, ask) {
18368
+ const placeholders = placeholdersIn(text);
18369
+ if (placeholders.length === 0 || placeholders.length > SESSION_PLACEHOLDERS) return void 0;
18370
+ const values = usable(await ask(position, placeholders));
18371
+ if (Object.keys(values).length === 0) return void 0;
18372
+ return { text: replaced(text, values), values };
18373
+ }
18374
+ async function plain2(b64, ask) {
18375
+ const text = decoded(b64);
18376
+ const fields = text?.split("\0");
18377
+ if (fields?.length !== 3) return { line: b64 };
18378
+ const [authz, user, pass2] = fields;
18379
+ if (placeholdersIn(authz + user).length > 0) return { line: b64 };
18380
+ const done4 = await swapped2(pass2, "auth-plain", ask);
18381
+ if (!done4) return { line: b64 };
18382
+ return { line: btoa(`${authz}\0${user}\0${done4.text}`), values: done4.values };
18383
+ }
18384
+ async function login(b64, ask) {
18385
+ const text = decoded(b64);
18386
+ const done4 = text === void 0 ? void 0 : await swapped2(text, "auth-login", ask);
18387
+ return done4 ? { line: btoa(done4.text), values: done4.values } : { line: b64 };
18388
+ }
18389
+ var SmtpClient = class {
18390
+ state = "command";
18391
+ ask;
18392
+ constructor(ask) {
18393
+ this.ask = ask;
18394
+ }
18395
+ get done() {
18396
+ return this.state === "done";
18397
+ }
18398
+ async line(text) {
18399
+ const state = this.state;
18400
+ if (state === "done") return { line: text };
18401
+ if (state === "plain" || state === "password") {
18402
+ this.state = "done";
18403
+ if (text === "*") return { line: text };
18404
+ return state === "plain" ? plain2(text, this.ask) : login(text, this.ask);
18405
+ }
18406
+ if (state === "user") {
18407
+ this.state = text === "*" ? "done" : "password";
18408
+ return { line: text };
18409
+ }
18410
+ return this.command(text);
18411
+ }
18412
+ async command(text) {
18413
+ const m = /^AUTH[ \t]+(PLAIN|LOGIN)(?:[ \t]+(\S+))?$/i.exec(text);
18414
+ if (!m) {
18415
+ if (/^(MAIL|RCPT|DATA|BDAT|AUTH)\b/i.test(text)) this.state = "done";
18416
+ return { line: text };
18417
+ }
18418
+ const mech = m[1].toUpperCase();
18419
+ const arg = m[2];
18420
+ if (mech === "LOGIN") {
18421
+ this.state = arg === void 0 ? "user" : "password";
18422
+ return { line: text };
18423
+ }
18424
+ if (arg === void 0) {
18425
+ this.state = "plain";
18426
+ return { line: text };
18427
+ }
18428
+ this.state = "done";
18429
+ const out = await plain2(arg, this.ask);
18430
+ return {
18431
+ line: `${text.slice(0, text.length - arg.length)}${out.line}`,
18432
+ ...out.values ? { values: out.values } : {}
18433
+ };
18434
+ }
18435
+ };
18436
+
18348
18437
  // src/kernel/net/sealed-conn.ts
18349
18438
  var HEAD_IDLE_MS = 2e3;
18350
18439
  function substitutes(s) {
@@ -18376,12 +18465,25 @@ function headEnd2(bytes) {
18376
18465
  }
18377
18466
  return -1;
18378
18467
  }
18379
- var Http1Writer = class {
18468
+ function modeOf(start2) {
18469
+ const http = sniffHttp1(start2);
18470
+ const smtp = sniffSmtp(start2);
18471
+ if (http === "yes") return "http1";
18472
+ if (smtp === "yes") return "smtp";
18473
+ return http === "no" && smtp === "no" ? "pass" : void 0;
18474
+ }
18475
+ function crlf(bytes) {
18476
+ for (let i = 0; i + 1 < bytes.length; i++) if (bytes[i] === 13 && bytes[i + 1] === 10) return i;
18477
+ return -1;
18478
+ }
18479
+ var SessionWriter = class {
18380
18480
  buffer = new Uint8Array(0);
18381
- passing = false;
18481
+ mode = "sniff";
18382
18482
  timer;
18383
18483
  chain = Promise.resolve();
18384
18484
  failed;
18485
+ session = sessionId();
18486
+ smtp;
18385
18487
  conn;
18386
18488
  s;
18387
18489
  scope;
@@ -18389,6 +18491,9 @@ var Http1Writer = class {
18389
18491
  this.conn = conn;
18390
18492
  this.s = s;
18391
18493
  this.scope = scope;
18494
+ this.smtp = new SmtpClient(
18495
+ (position, placeholders) => this.ask("smtp", position, placeholders)
18496
+ );
18392
18497
  }
18393
18498
  write(bytes) {
18394
18499
  const run2 = this.chain.then(() => this.take(bytes));
@@ -18398,30 +18503,78 @@ var Http1Writer = class {
18398
18503
  );
18399
18504
  return run2;
18400
18505
  }
18506
+ async ask(protocol, position, placeholders, head) {
18507
+ const s = this.s;
18508
+ const values = await s.broker.sessionMaterialize({
18509
+ stamp: await s.stamp(),
18510
+ session: this.session,
18511
+ host: s.host,
18512
+ port: s.port,
18513
+ protocol,
18514
+ position,
18515
+ verified: s.verified,
18516
+ handshakeAt: s.handshakeAt,
18517
+ exit: s.exit,
18518
+ placeholders,
18519
+ ...head ? { head } : {}
18520
+ });
18521
+ return values;
18522
+ }
18523
+ remember(values) {
18524
+ this.scope.add(
18525
+ Object.entries(values).map(([placeholder, value2]) => ({ name: "sealed", value: value2, placeholder }))
18526
+ );
18527
+ }
18401
18528
  async take(bytes) {
18402
18529
  if (this.failed !== void 0) throw this.failed;
18403
- if (this.passing) return this.conn.write(bytes);
18530
+ if (this.mode === "pass") return this.conn.write(bytes);
18404
18531
  clearTimeout(this.timer);
18405
18532
  const joined4 = new Uint8Array(this.buffer.length + bytes.length);
18406
18533
  joined4.set(this.buffer);
18407
18534
  joined4.set(bytes, this.buffer.length);
18408
18535
  this.buffer.fill(0);
18409
18536
  this.buffer = joined4;
18410
- const sniff = sniffHttp1(latin12(joined4.subarray(0, 8)));
18411
- const end = sniff === "yes" ? headEnd2(joined4) : -1;
18412
- if (sniff === "no" || end > HEAD_MAX || end < 0 && joined4.length > HEAD_MAX)
18413
- await this.release();
18414
- else if (end >= 0) await this.substitute(end);
18415
- else this.timer = setTimeout(() => this.idle(), HEAD_IDLE_MS);
18537
+ if (this.mode === "sniff") this.mode = modeOf(latin12(joined4.subarray(0, 8))) ?? "sniff";
18538
+ if (this.mode === "pass") await this.release();
18539
+ else if (this.mode === "http1") await this.http1();
18540
+ else if (this.mode === "smtp") await this.lines();
18541
+ if (this.mode !== "pass" && this.buffer.length > 0)
18542
+ this.timer = setTimeout(() => this.idle(), HEAD_IDLE_MS);
18416
18543
  return bytes.length;
18417
18544
  }
18545
+ async http1() {
18546
+ const end = headEnd2(this.buffer);
18547
+ if (end > HEAD_MAX || end < 0 && this.buffer.length > HEAD_MAX) await this.release();
18548
+ else if (end >= 0) await this.substitute(end);
18549
+ }
18550
+ async lines() {
18551
+ for (; ; ) {
18552
+ const at = crlf(this.buffer);
18553
+ if (at < 0) break;
18554
+ if (at > SMTP_LINE_MAX) return this.release();
18555
+ const all = this.buffer;
18556
+ this.buffer = all.slice(at + 2);
18557
+ const out = await this.smtp.line(latin12(all.subarray(0, at))).catch(() => ({ line: latin12(all.subarray(0, at)) }));
18558
+ all.fill(0);
18559
+ if ("values" in out && out.values) this.remember(out.values);
18560
+ const line = bytesOf(`${out.line}\r
18561
+ `);
18562
+ try {
18563
+ await writeAll4(this.conn, line);
18564
+ } finally {
18565
+ line.fill(0);
18566
+ }
18567
+ if (this.smtp.done) return this.release();
18568
+ }
18569
+ if (this.buffer.length > SMTP_LINE_MAX) await this.release();
18570
+ }
18418
18571
  idle() {
18419
18572
  this.chain = this.chain.then(() => this.release()).catch((err) => {
18420
18573
  this.failed ??= err;
18421
18574
  });
18422
18575
  }
18423
18576
  async release() {
18424
- this.passing = true;
18577
+ this.mode = "pass";
18425
18578
  const out = this.buffer;
18426
18579
  this.buffer = new Uint8Array(0);
18427
18580
  try {
@@ -18431,37 +18584,15 @@ var Http1Writer = class {
18431
18584
  }
18432
18585
  }
18433
18586
  async substitute(end) {
18434
- this.passing = true;
18587
+ this.mode = "pass";
18435
18588
  const all = this.buffer;
18436
18589
  this.buffer = new Uint8Array(0);
18437
- const s = this.s;
18438
- const session = sessionId();
18439
18590
  const done4 = await substituteHead(
18440
18591
  latin12(all.subarray(0, end)),
18441
- async (position, placeholders, head2) => s.broker.sessionMaterialize({
18442
- stamp: await s.stamp(),
18443
- session,
18444
- host: s.host,
18445
- port: s.port,
18446
- protocol: "http1",
18447
- position,
18448
- verified: s.verified,
18449
- handshakeAt: s.handshakeAt,
18450
- exit: s.exit,
18451
- placeholders,
18452
- head: head2
18453
- })
18592
+ (position, placeholders, head2) => this.ask("http1", position, placeholders, head2)
18454
18593
  ).catch(() => void 0);
18455
18594
  const head = done4 ? bytesOf(done4.head) : all.subarray(0, end);
18456
- if (done4) {
18457
- this.scope.add(
18458
- Object.entries(done4.values).map(([placeholder, value2]) => ({
18459
- name: "sealed",
18460
- value: value2,
18461
- placeholder
18462
- }))
18463
- );
18464
- }
18595
+ if (done4) this.remember(done4.values);
18465
18596
  try {
18466
18597
  await writeAll4(this.conn, head);
18467
18598
  await writeAll4(this.conn, all.subarray(end));
@@ -18472,14 +18603,14 @@ var Http1Writer = class {
18472
18603
  }
18473
18604
  flushed() {
18474
18605
  clearTimeout(this.timer);
18475
- this.chain = this.chain.then(() => this.passing ? void 0 : this.release());
18606
+ this.chain = this.chain.then(() => this.mode === "pass" ? void 0 : this.release());
18476
18607
  return this.chain;
18477
18608
  }
18478
18609
  drop() {
18479
18610
  clearTimeout(this.timer);
18480
18611
  this.buffer.fill(0);
18481
18612
  this.buffer = new Uint8Array(0);
18482
- this.passing = true;
18613
+ this.mode = "pass";
18483
18614
  }
18484
18615
  };
18485
18616
  var IDLE2 = /* @__PURE__ */ Symbol("idle");
@@ -18490,11 +18621,9 @@ var ScrubReader = class {
18490
18621
  held = false;
18491
18622
  ended = false;
18492
18623
  conn;
18493
- s;
18494
18624
  scope;
18495
- constructor(conn, s, scope) {
18625
+ constructor(conn, scope) {
18496
18626
  this.conn = conn;
18497
- this.s = s;
18498
18627
  this.scope = scope;
18499
18628
  }
18500
18629
  current() {
@@ -18553,8 +18682,8 @@ function idle() {
18553
18682
  }
18554
18683
  function sealedConn(conn, s) {
18555
18684
  const scope = s.broker.sessions.scope(s.pid, s.host);
18556
- const writer = substitutes(s) ? new Http1Writer(conn, s, scope) : void 0;
18557
- const reader = new ScrubReader(conn, s, scope);
18685
+ const writer = substitutes(s) ? new SessionWriter(conn, s, scope) : void 0;
18686
+ const reader = new ScrubReader(conn, scope);
18558
18687
  return {
18559
18688
  localAddr: conn.localAddr,
18560
18689
  remoteAddr: conn.remoteAddr,
@@ -19680,6 +19809,12 @@ function tlsOverTransport(req, proc) {
19680
19809
  return { fd: proc.fds.install(new OpenFile(mine), 3), alpnProtocol: "http/1.1", servername };
19681
19810
  }
19682
19811
 
19812
+ // src/kernel/test-hooks.ts
19813
+ var SYSCALL_HOOK = /* @__PURE__ */ Symbol.for("slicc-kernel.test.syscall");
19814
+ function testSyscallHook() {
19815
+ return globalThis[SYSCALL_HOOK];
19816
+ }
19817
+
19683
19818
  // src/kernel/vfs-file.ts
19684
19819
  var O_ACCMODE = 3;
19685
19820
  var O_WRONLY = 1;
@@ -20894,7 +21029,8 @@ var WasmProcess = class {
20894
21029
  cwd,
20895
21030
  ...moved2,
20896
21031
  ...group,
20897
- ...exec ? { exec } : {}
21032
+ ...exec ? { exec } : {},
21033
+ search: req.search
20898
21034
  };
20899
21035
  const pid = await this.children.spawn(spawned, stdio, inherit2);
20900
21036
  if (deathSignal !== void 0) this.onDeath(pgid === 0 || session ? -pid : pid, deathSignal);
@@ -20980,6 +21116,8 @@ var WasmProcess = class {
20980
21116
  return void 0;
20981
21117
  }
20982
21118
  async syscall(req, cancelled, block) {
21119
+ const hook = testSyscallHook();
21120
+ if (hook) await hook({ pid: this.pid, op: req.op });
20983
21121
  this.options.onSyscall?.(req);
20984
21122
  this.calls += 1;
20985
21123
  const started = performance.now();
@@ -21277,18 +21415,18 @@ var WasmProcess = class {
21277
21415
  }
21278
21416
  if (this.writesAt(req) && this.options.readonlyAt?.(path)) throw new KernelError("EROFS");
21279
21417
  const open = { ...req, path };
21280
- const plain2 = this.plainMode(req.mode);
21418
+ const plain3 = this.plainMode(req.mode);
21281
21419
  if (req.exclusive) {
21282
21420
  await nodes.createExclusive(path, this.newOwner(req.mode));
21283
- if (plain2 !== void 0) await fs.chmod?.(path, plain2);
21421
+ if (plain3 !== void 0) await fs.chmod?.(path, plain3);
21284
21422
  this.fds.installAt(fd, this.openVfsFile(open, void 0, fs));
21285
21423
  } else if (req.create) {
21286
21424
  await nodes.onEntry(path, async () => {
21287
- const marks = this.options.owners || plain2 !== void 0;
21425
+ const marks = this.options.owners || plain3 !== void 0;
21288
21426
  const fresh2 = marks && !await present3(fs, path, true);
21289
21427
  this.fds.installAt(fd, this.openVfsFile(open, await nodes.identify(path), fs));
21290
21428
  await this.fds.get(fd).file.stat?.();
21291
- if (fresh2 && plain2 !== void 0) await fs.chmod?.(path, plain2);
21429
+ if (fresh2 && plain3 !== void 0) await fs.chmod?.(path, plain3);
21292
21430
  else if (fresh2) {
21293
21431
  await fs.chown?.(path, { ...this.newOwner(req.mode), kind: "new" });
21294
21432
  }
@@ -23431,15 +23569,15 @@ function isRecord(value2) {
23431
23569
  return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
23432
23570
  }
23433
23571
  function serialized(reply) {
23434
- let plain2;
23572
+ let plain3;
23435
23573
  try {
23436
23574
  const text = JSON.stringify(reply);
23437
- plain2 = text === void 0 ? void 0 : JSON.parse(text);
23575
+ plain3 = text === void 0 ? void 0 : JSON.parse(text);
23438
23576
  } catch (err) {
23439
23577
  return JSON.stringify(errorReply("EIO", lineOf2(err)));
23440
23578
  }
23441
- if (!isRecord(plain2)) return JSON.stringify(errorReply("EIO", "the vault gave no reply"));
23442
- const { v: _, ...rest2 } = plain2;
23579
+ if (!isRecord(plain3)) return JSON.stringify(errorReply("EIO", "the vault gave no reply"));
23580
+ const { v: _, ...rest2 } = plain3;
23443
23581
  return JSON.stringify({ v: 1, ...rest2 });
23444
23582
  }
23445
23583
  function lineOf2(err) {
@@ -25473,13 +25611,13 @@ function splitWords(text) {
25473
25611
  while (piece.lastIndex < text.length) {
25474
25612
  const m = piece.exec(text);
25475
25613
  if (!m) return void 0;
25476
- const [, single, double, escaped, plain2, space] = m;
25614
+ const [, single, double, escaped, plain3, space] = m;
25477
25615
  if (space !== void 0) {
25478
25616
  if (word !== void 0) words2.push(word);
25479
25617
  word = void 0;
25480
25618
  continue;
25481
25619
  }
25482
- word = (word ?? "") + (single ?? (double !== void 0 ? unescaped(double) : escaped ?? plain2));
25620
+ word = (word ?? "") + (single ?? (double !== void 0 ? unescaped(double) : escaped ?? plain3));
25483
25621
  }
25484
25622
  if (word !== void 0) words2.push(word);
25485
25623
  return words2;
@@ -26668,16 +26806,52 @@ var Launcher = class {
26668
26806
  for (const bin of planned?.bins ?? []) await need(g, "exec", bin, R_OK | X_OK);
26669
26807
  if (planned?.target.copy) await need(g, "exec", planned.target.copy, R_OK | X_OK);
26670
26808
  }
26671
- async checkedPlan(req, { ppid, cred, scope }, fds) {
26672
- const refused3 = async (err) => {
26809
+ async checkedPlan(req, ctx, fds) {
26810
+ try {
26811
+ return await this.planOrSearch(req, ctx);
26812
+ } catch (err) {
26673
26813
  await fds.closeAll();
26674
- throw err.code === "EACCES" ? new SpawnError("EACCES") : err;
26814
+ throw err;
26815
+ }
26816
+ }
26817
+ async planOrSearch(req, ctx) {
26818
+ const bare = !req.file.includes("/") && !COMMAND2.test(req.file);
26819
+ try {
26820
+ return await this.planOne(req, ctx);
26821
+ } catch (err) {
26822
+ const code = codeOf7(err);
26823
+ const searched = bare && req.search !== false && (code === "ENOENT" || code === "ENOEXEC");
26824
+ if (!searched || await this.commandAt(req.file, ctx.scope)) throw err;
26825
+ const found = await this.onPath(req, ctx);
26826
+ if (found) return found;
26827
+ throw err;
26828
+ }
26829
+ }
26830
+ async onPath(req, ctx) {
26831
+ const path = req.env.PATH;
26832
+ if (typeof path !== "string") return void 0;
26833
+ let denied2 = false;
26834
+ for (const dir of path.split(":")) {
26835
+ const file = dir === "" ? `./${req.file}` : `${dir.replace(/\/+$/, "")}/${req.file}`;
26836
+ try {
26837
+ return await this.planOne({ ...req, file }, ctx);
26838
+ } catch (err) {
26839
+ const code = codeOf7(err);
26840
+ if (code === "EACCES") denied2 = true;
26841
+ else if (code !== "ENOENT" && code !== "ENOTDIR") throw err;
26842
+ }
26843
+ }
26844
+ if (denied2) throw new SpawnError("EACCES");
26845
+ return void 0;
26846
+ }
26847
+ async planOne(req, { ppid, cred, scope }) {
26848
+ const refused3 = (err) => {
26849
+ throw codeOf7(err) === "EACCES" ? new SpawnError("EACCES") : err;
26675
26850
  };
26676
26851
  const file = await this.execFile(req.file, req.cwd, this.execGuard(cred, ppid)).catch(refused3);
26677
26852
  const planned = await this.plan(file, req.argv, req.cwd, scope, req.argv0);
26678
26853
  await this.mayExec(cred, { ...req, file, pid: ppid }, planned).catch(refused3);
26679
26854
  if (planned) return planned;
26680
- await fds.closeAll();
26681
26855
  throw new SpawnError(await this.unrunnable(file, req.cwd, scope));
26682
26856
  }
26683
26857
  async enterable(g, cwd) {
@@ -26844,12 +27018,12 @@ var Launcher = class {
26844
27018
  return `${path}:${st.size}:${st.mtime.getTime()}`;
26845
27019
  }
26846
27020
  verified(path, caller, fs = this.base) {
26847
- const plain2 = () => fs.readFileBuffer(path);
26848
- return this.integrity ? this.integrity.read(path, caller, plain2) : plain2();
27021
+ const plain3 = () => fs.readFileBuffer(path);
27022
+ return this.integrity ? this.integrity.read(path, caller, plain3) : plain3();
26849
27023
  }
26850
27024
  keyed(path, caller, asked) {
26851
- const plain2 = async () => this.base.readFileBuffer(path);
26852
- return this.integrity ? this.integrity.readKeyed(path, caller, plain2, asked) : plain2().then((bytes) => ({ bytes }));
27025
+ const plain3 = async () => this.base.readFileBuffer(path);
27026
+ return this.integrity ? this.integrity.readKeyed(path, caller, plain3, asked) : plain3().then((bytes) => ({ bytes }));
26853
27027
  }
26854
27028
  cached(cache, key, load) {
26855
27029
  const hit = cache.get(key);
@@ -27046,7 +27220,7 @@ var Launcher = class {
27046
27220
  });
27047
27221
  return {
27048
27222
  source: {
27049
- read: (path, plain2) => integrity.readSource(path, caller(), plain2),
27223
+ read: (path, plain3) => integrity.readSource(path, caller(), plain3),
27050
27224
  open: (path, real) => integrity.openSource(path, caller(), real)
27051
27225
  }
27052
27226
  };
@@ -27953,9 +28127,9 @@ var Launcher = class {
27953
28127
  }
27954
28128
  );
27955
28129
  }
27956
- environment(cwd, extra, account, login = false) {
28130
+ environment(cwd, extra, account, login2 = false) {
27957
28131
  const env = {
27958
- ...login ? networkEnv(this.hostname) : this.env,
28132
+ ...login2 ? networkEnv(this.hostname) : this.env,
27959
28133
  ...userEnv(account, this.pnpmHome),
27960
28134
  PWD: cwd,
27961
28135
  ...extra
@@ -28182,6 +28356,9 @@ var Launcher = class {
28182
28356
  function cronLocks() {
28183
28357
  return globalThis.navigator?.locks;
28184
28358
  }
28359
+ function codeOf7(err) {
28360
+ return err?.code;
28361
+ }
28185
28362
 
28186
28363
  // src/node/loopback.ts
28187
28364
  import { AsyncLocalStorage } from "node:async_hooks";
@@ -28198,11 +28375,11 @@ function ipv4Place(address) {
28198
28375
  return void 0;
28199
28376
  }
28200
28377
  function placeOf(address) {
28201
- const plain2 = address.replace(/^\[(.*)\]$/, "$1").toLowerCase();
28202
- const kind = isIP3(plain2);
28203
- if (kind === 4) return ipv4Place(plain2);
28378
+ const plain3 = address.replace(/^\[(.*)\]$/, "$1").toLowerCase();
28379
+ const kind = isIP3(plain3);
28380
+ if (kind === 4) return ipv4Place(plain3);
28204
28381
  if (kind !== 6) return void 0;
28205
- const words2 = hextets2(plain2);
28382
+ const words2 = hextets2(plain3);
28206
28383
  const embedded2 = words2.slice(0, 5).every((w) => w === 0) && (words2[5] === 65535 || words2[5] === 0);
28207
28384
  if (embedded2 && (words2[5] === 65535 || words2[6] !== 0)) return ipv4Place(ipv4Of(words2));
28208
28385
  if (words2.slice(0, 7).every((w) => w === 0) && (words2[7] ?? 0) <= 1) return "loopback";
@@ -28251,10 +28428,10 @@ function connectRefusal(address, port, place) {
28251
28428
  return Object.assign(new Error(why), { status: 403, code: "EACCES" });
28252
28429
  }
28253
28430
  async function addressesOf(host, resolve2) {
28254
- const plain2 = host.replace(/^\[(.*)\]$/, "$1");
28255
- if (isIP3(plain2)) return [plain2];
28256
- if (loopbackName2(plain2)) return ["127.0.0.1"];
28257
- return resolve2(plain2).catch(() => []);
28431
+ const plain3 = host.replace(/^\[(.*)\]$/, "$1");
28432
+ if (isIP3(plain3)) return [plain3];
28433
+ if (loopbackName2(plain3)) return ["127.0.0.1"];
28434
+ return resolve2(plain3).catch(() => []);
28258
28435
  }
28259
28436
  async function checkDestination(target, policy, resolve2 = resolveHost) {
28260
28437
  const url = new URL(target);
@@ -28592,7 +28769,7 @@ import { connect as tls } from "node:tls";
28592
28769
  var PROBE_MS = 3e3;
28593
28770
  var PASSED = /* @__PURE__ */ new Set(["ECONNREFUSED", "EHOSTUNREACH", "ENETUNREACH", "ETIMEDOUT", "ECONNRESET"]);
28594
28771
  var NO_NAME = /* @__PURE__ */ new Set(["ENOTFOUND", "EAI_AGAIN", "EAI_NONAME", "EAI_FAIL", "ENODATA"]);
28595
- function codeOf7(e) {
28772
+ function codeOf8(e) {
28596
28773
  const code = e?.code;
28597
28774
  return typeof code === "string" ? code : void 0;
28598
28775
  }
@@ -28621,7 +28798,7 @@ function probe(secure2, host, port, ms, signal) {
28621
28798
  signal?.addEventListener("abort", stop, { once: true });
28622
28799
  socket.once(secure2 ? "secureConnect" : "connect", () => done4("EPROTO"));
28623
28800
  socket.once("error", (e) => {
28624
- const code = codeOf7(e) ?? "";
28801
+ const code = codeOf8(e) ?? "";
28625
28802
  done4(PASSED.has(code) ? code : "EPROTO");
28626
28803
  });
28627
28804
  });
@@ -28636,7 +28813,7 @@ async function diagnose(url, ms = PROBE_MS, signal) {
28636
28813
  await abortable(lookup3(host), signal);
28637
28814
  } catch (e) {
28638
28815
  if (signal?.aborted) throw signal.reason;
28639
- return NO_NAME.has(codeOf7(e) ?? "") ? "EAI_NONAME" : void 0;
28816
+ return NO_NAME.has(codeOf8(e) ?? "") ? "EAI_NONAME" : void 0;
28640
28817
  }
28641
28818
  const code = await probe(secure2, host, port, ms, signal);
28642
28819
  signal?.throwIfAborted();
@@ -28655,7 +28832,7 @@ function diagnosing(transport, check = byDefault) {
28655
28832
  try {
28656
28833
  return await open(request);
28657
28834
  } catch (e) {
28658
- if (request.signal.aborted || !(e instanceof Error) || codeOf7(e)) throw e;
28835
+ if (request.signal.aborted || !(e instanceof Error) || codeOf8(e)) throw e;
28659
28836
  const code = await abortable(
28660
28837
  check(request.url, request.signal).catch(() => void 0),
28661
28838
  request.signal