@ai-ecoverse/slicc-kernel 1.128.1 → 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.
@@ -544,14 +544,14 @@ var Integrity = class {
544
544
  if (!this.root.version) return void 0;
545
545
  return `${real}\0${await this.root.version(real)}`;
546
546
  }
547
- async read(path, caller, plain2, asked) {
548
- return (await this.readKeyed(path, caller, plain2, asked)).bytes;
547
+ async read(path, caller, plain3, asked) {
548
+ return (await this.readKeyed(path, caller, plain3, asked)).bytes;
549
549
  }
550
- async readKeyed(path, caller, plain2, asked) {
550
+ async readKeyed(path, caller, plain3, asked) {
551
551
  const found = await this.real(path, asked);
552
- if (found === void 0) return { bytes: await plain2() };
552
+ if (found === void 0) return { bytes: await plain3() };
553
553
  const { real, name: name2 } = found;
554
- 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 };
554
+ 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 };
555
555
  const { bytes } = read;
556
556
  const keyed = read.version === void 0 ? { bytes } : { bytes, key: `${real}\0${read.version}` };
557
557
  await this.verify(name2, bytes, caller, EXEC_OPS);
@@ -560,9 +560,9 @@ var Integrity = class {
560
560
  get readsChecked() {
561
561
  return this.sources.length > 0;
562
562
  }
563
- async readSource(path, caller, plain2) {
563
+ async readSource(path, caller, plain3) {
564
564
  const found = await this.source(path);
565
- return found === void 0 ? plain2() : this.checked(found, caller, plain2);
565
+ return found === void 0 ? plain3() : this.checked(found, caller, plain3);
566
566
  }
567
567
  async openSource(path, caller, real) {
568
568
  const found = await this.source(path, real);
@@ -572,10 +572,10 @@ var Integrity = class {
572
572
  }
573
573
  await this.checked(found, caller, () => this.root.readFileBuffer(found.real));
574
574
  }
575
- async checked(found, caller, plain2) {
575
+ async checked(found, caller, plain3) {
576
576
  const { real, name: name2 } = found;
577
577
  if (name2 !== real || !this.root.readVersioned) {
578
- const bytes2 = await plain2();
578
+ const bytes2 = await plain3();
579
579
  await this.verify(name2, bytes2, caller, READ_OPS);
580
580
  return bytes2;
581
581
  }
@@ -3232,11 +3232,11 @@ function frame(opcode, payload) {
3232
3232
  return out;
3233
3233
  }
3234
3234
  function clientFrame(opcode, payload) {
3235
- const plain2 = frame(opcode, payload);
3236
- const head = plain2.length - payload.length;
3235
+ const plain3 = frame(opcode, payload);
3236
+ const head = plain3.length - payload.length;
3237
3237
  const mask = crypto.getRandomValues(new Uint8Array(4));
3238
- const out = new Uint8Array(plain2.length + 4);
3239
- out.set(plain2.subarray(0, head));
3238
+ const out = new Uint8Array(plain3.length + 4);
3239
+ out.set(plain3.subarray(0, head));
3240
3240
  out[1] = out[1] | 128;
3241
3241
  out.set(mask, head);
3242
3242
  for (let i = 0; i < payload.length; i++) {
@@ -7020,7 +7020,7 @@ function satisfies(version, range2) {
7020
7020
  }
7021
7021
 
7022
7022
  // src/version.ts
7023
- var KERNEL_VERSION = true ? "1.128.1" : "0.0.0-dev";
7023
+ var KERNEL_VERSION = true ? "1.129.0" : "0.0.0-dev";
7024
7024
  var OS_RELEASE = "6.0.0-slicc";
7025
7025
  function procVersion() {
7026
7026
  return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
@@ -9772,8 +9772,9 @@ var FreshModules = class {
9772
9772
  if (ranged2) {
9773
9773
  overrides.pwrite = async (path, at, bytes, transfer) => {
9774
9774
  const touches2 = at < MAGIC.length && this.fresh.has(normalizePath(path));
9775
+ const first = at === 0 && bytes.length >= MAGIC.length ? bytes.slice(0, MAGIC.length) : void 0;
9775
9776
  await ranged2.pwrite(path, at, bytes, transfer);
9776
- if (touches2) await decide(path);
9777
+ if (touches2) await decide(path, first);
9777
9778
  };
9778
9779
  overrides.truncate = async (path, size) => {
9779
9780
  await ranged2.truncate(path, size);
@@ -12377,13 +12378,13 @@ async function chown(entry, path, req) {
12377
12378
  }
12378
12379
  async function runMkdir(entry, path, req) {
12379
12380
  const { fs } = entry;
12380
- const plain2 = plainDirMode(entry, req.mode);
12381
+ const plain3 = plainDirMode(entry, req.mode);
12381
12382
  const parentsMode = !req.exclusive ? plainParentsMode(entry) : void 0;
12382
12383
  const fixParents = parentsMode !== void 0 ? await missingParents(fs, path, parentsMode) : void 0;
12383
- const fresh2 = plain2 !== void 0 && !await fs.exists(path);
12384
+ const fresh2 = plain3 !== void 0 && !await fs.exists(path);
12384
12385
  await (req.exclusive ? mkdirExclusive(entry, path, req.mode) : fs.mkdir(path, mkdirOptions(entry, req.mode)));
12385
12386
  await fixParents?.();
12386
- if (fresh2) await fs.chmod(path, plain2);
12387
+ if (fresh2) await fs.chmod(path, plain3);
12387
12388
  return done2;
12388
12389
  }
12389
12390
  async function shownAs(entry, path, st) {
@@ -12391,8 +12392,8 @@ async function shownAs(entry, path, st) {
12391
12392
  return callerStat(guardOf(entry), await real?.catch(() => path) ?? path, st);
12392
12393
  }
12393
12394
  function readSource(entry, path) {
12394
- const plain2 = () => entry.fs.readFileBuffer(path);
12395
- return entry.source ? entry.source.read(path, plain2) : plain2();
12395
+ const plain3 = () => entry.fs.readFileBuffer(path);
12396
+ return entry.source ? entry.source.read(path, plain3) : plain3();
12396
12397
  }
12397
12398
  async function run(entry, path, req) {
12398
12399
  const { fs, cwd } = entry;
@@ -18489,6 +18490,95 @@ async function substituteHead(head, ask) {
18489
18490
  `, values };
18490
18491
  }
18491
18492
 
18493
+ // src/kernel/net/sealed-smtp.ts
18494
+ var SMTP_LINE_MAX = 4096;
18495
+ var GREETING = ["EHLO ", "HELO "];
18496
+ function sniffSmtp(start2) {
18497
+ const upper = start2.toUpperCase();
18498
+ for (const word of GREETING) {
18499
+ if (upper.startsWith(word)) return "yes";
18500
+ if (word.startsWith(upper)) return "more";
18501
+ }
18502
+ return "no";
18503
+ }
18504
+ function decoded(b64) {
18505
+ if (!/^[A-Za-z0-9+/]+={0,2}$/.test(b64)) return void 0;
18506
+ try {
18507
+ return atob(b64);
18508
+ } catch {
18509
+ return void 0;
18510
+ }
18511
+ }
18512
+ async function swapped2(text, position, ask) {
18513
+ const placeholders = placeholdersIn(text);
18514
+ if (placeholders.length === 0 || placeholders.length > SESSION_PLACEHOLDERS) return void 0;
18515
+ const values = usable(await ask(position, placeholders));
18516
+ if (Object.keys(values).length === 0) return void 0;
18517
+ return { text: replaced(text, values), values };
18518
+ }
18519
+ async function plain2(b64, ask) {
18520
+ const text = decoded(b64);
18521
+ const fields = text?.split("\0");
18522
+ if (fields?.length !== 3) return { line: b64 };
18523
+ const [authz, user, pass2] = fields;
18524
+ if (placeholdersIn(authz + user).length > 0) return { line: b64 };
18525
+ const done5 = await swapped2(pass2, "auth-plain", ask);
18526
+ if (!done5) return { line: b64 };
18527
+ return { line: btoa(`${authz}\0${user}\0${done5.text}`), values: done5.values };
18528
+ }
18529
+ async function login(b64, ask) {
18530
+ const text = decoded(b64);
18531
+ const done5 = text === void 0 ? void 0 : await swapped2(text, "auth-login", ask);
18532
+ return done5 ? { line: btoa(done5.text), values: done5.values } : { line: b64 };
18533
+ }
18534
+ var SmtpClient = class {
18535
+ state = "command";
18536
+ ask;
18537
+ constructor(ask) {
18538
+ this.ask = ask;
18539
+ }
18540
+ get done() {
18541
+ return this.state === "done";
18542
+ }
18543
+ async line(text) {
18544
+ const state = this.state;
18545
+ if (state === "done") return { line: text };
18546
+ if (state === "plain" || state === "password") {
18547
+ this.state = "done";
18548
+ if (text === "*") return { line: text };
18549
+ return state === "plain" ? plain2(text, this.ask) : login(text, this.ask);
18550
+ }
18551
+ if (state === "user") {
18552
+ this.state = text === "*" ? "done" : "password";
18553
+ return { line: text };
18554
+ }
18555
+ return this.command(text);
18556
+ }
18557
+ async command(text) {
18558
+ const m = /^AUTH[ \t]+(PLAIN|LOGIN)(?:[ \t]+(\S+))?$/i.exec(text);
18559
+ if (!m) {
18560
+ if (/^(MAIL|RCPT|DATA|BDAT|AUTH)\b/i.test(text)) this.state = "done";
18561
+ return { line: text };
18562
+ }
18563
+ const mech = m[1].toUpperCase();
18564
+ const arg = m[2];
18565
+ if (mech === "LOGIN") {
18566
+ this.state = arg === void 0 ? "user" : "password";
18567
+ return { line: text };
18568
+ }
18569
+ if (arg === void 0) {
18570
+ this.state = "plain";
18571
+ return { line: text };
18572
+ }
18573
+ this.state = "done";
18574
+ const out = await plain2(arg, this.ask);
18575
+ return {
18576
+ line: `${text.slice(0, text.length - arg.length)}${out.line}`,
18577
+ ...out.values ? { values: out.values } : {}
18578
+ };
18579
+ }
18580
+ };
18581
+
18492
18582
  // src/kernel/net/sealed-conn.ts
18493
18583
  var HEAD_IDLE_MS = 2e3;
18494
18584
  function substitutes(s) {
@@ -18520,12 +18610,25 @@ function headEnd2(bytes) {
18520
18610
  }
18521
18611
  return -1;
18522
18612
  }
18523
- var Http1Writer = class {
18613
+ function modeOf(start2) {
18614
+ const http = sniffHttp1(start2);
18615
+ const smtp = sniffSmtp(start2);
18616
+ if (http === "yes") return "http1";
18617
+ if (smtp === "yes") return "smtp";
18618
+ return http === "no" && smtp === "no" ? "pass" : void 0;
18619
+ }
18620
+ function crlf(bytes) {
18621
+ for (let i = 0; i + 1 < bytes.length; i++) if (bytes[i] === 13 && bytes[i + 1] === 10) return i;
18622
+ return -1;
18623
+ }
18624
+ var SessionWriter = class {
18524
18625
  buffer = new Uint8Array(0);
18525
- passing = false;
18626
+ mode = "sniff";
18526
18627
  timer;
18527
18628
  chain = Promise.resolve();
18528
18629
  failed;
18630
+ session = sessionId();
18631
+ smtp;
18529
18632
  conn;
18530
18633
  s;
18531
18634
  scope;
@@ -18533,6 +18636,9 @@ var Http1Writer = class {
18533
18636
  this.conn = conn;
18534
18637
  this.s = s;
18535
18638
  this.scope = scope;
18639
+ this.smtp = new SmtpClient(
18640
+ (position, placeholders) => this.ask("smtp", position, placeholders)
18641
+ );
18536
18642
  }
18537
18643
  write(bytes) {
18538
18644
  const run2 = this.chain.then(() => this.take(bytes));
@@ -18542,30 +18648,78 @@ var Http1Writer = class {
18542
18648
  );
18543
18649
  return run2;
18544
18650
  }
18651
+ async ask(protocol, position, placeholders, head) {
18652
+ const s = this.s;
18653
+ const values = await s.broker.sessionMaterialize({
18654
+ stamp: await s.stamp(),
18655
+ session: this.session,
18656
+ host: s.host,
18657
+ port: s.port,
18658
+ protocol,
18659
+ position,
18660
+ verified: s.verified,
18661
+ handshakeAt: s.handshakeAt,
18662
+ exit: s.exit,
18663
+ placeholders,
18664
+ ...head ? { head } : {}
18665
+ });
18666
+ return values;
18667
+ }
18668
+ remember(values) {
18669
+ this.scope.add(
18670
+ Object.entries(values).map(([placeholder, value2]) => ({ name: "sealed", value: value2, placeholder }))
18671
+ );
18672
+ }
18545
18673
  async take(bytes) {
18546
18674
  if (this.failed !== void 0) throw this.failed;
18547
- if (this.passing) return this.conn.write(bytes);
18675
+ if (this.mode === "pass") return this.conn.write(bytes);
18548
18676
  clearTimeout(this.timer);
18549
18677
  const joined4 = new Uint8Array(this.buffer.length + bytes.length);
18550
18678
  joined4.set(this.buffer);
18551
18679
  joined4.set(bytes, this.buffer.length);
18552
18680
  this.buffer.fill(0);
18553
18681
  this.buffer = joined4;
18554
- const sniff = sniffHttp1(latin12(joined4.subarray(0, 8)));
18555
- const end = sniff === "yes" ? headEnd2(joined4) : -1;
18556
- if (sniff === "no" || end > HEAD_MAX || end < 0 && joined4.length > HEAD_MAX)
18557
- await this.release();
18558
- else if (end >= 0) await this.substitute(end);
18559
- else this.timer = setTimeout(() => this.idle(), HEAD_IDLE_MS);
18682
+ if (this.mode === "sniff") this.mode = modeOf(latin12(joined4.subarray(0, 8))) ?? "sniff";
18683
+ if (this.mode === "pass") await this.release();
18684
+ else if (this.mode === "http1") await this.http1();
18685
+ else if (this.mode === "smtp") await this.lines();
18686
+ if (this.mode !== "pass" && this.buffer.length > 0)
18687
+ this.timer = setTimeout(() => this.idle(), HEAD_IDLE_MS);
18560
18688
  return bytes.length;
18561
18689
  }
18690
+ async http1() {
18691
+ const end = headEnd2(this.buffer);
18692
+ if (end > HEAD_MAX || end < 0 && this.buffer.length > HEAD_MAX) await this.release();
18693
+ else if (end >= 0) await this.substitute(end);
18694
+ }
18695
+ async lines() {
18696
+ for (; ; ) {
18697
+ const at = crlf(this.buffer);
18698
+ if (at < 0) break;
18699
+ if (at > SMTP_LINE_MAX) return this.release();
18700
+ const all = this.buffer;
18701
+ this.buffer = all.slice(at + 2);
18702
+ const out = await this.smtp.line(latin12(all.subarray(0, at))).catch(() => ({ line: latin12(all.subarray(0, at)) }));
18703
+ all.fill(0);
18704
+ if ("values" in out && out.values) this.remember(out.values);
18705
+ const line = bytesOf(`${out.line}\r
18706
+ `);
18707
+ try {
18708
+ await writeAll4(this.conn, line);
18709
+ } finally {
18710
+ line.fill(0);
18711
+ }
18712
+ if (this.smtp.done) return this.release();
18713
+ }
18714
+ if (this.buffer.length > SMTP_LINE_MAX) await this.release();
18715
+ }
18562
18716
  idle() {
18563
18717
  this.chain = this.chain.then(() => this.release()).catch((err) => {
18564
18718
  this.failed ??= err;
18565
18719
  });
18566
18720
  }
18567
18721
  async release() {
18568
- this.passing = true;
18722
+ this.mode = "pass";
18569
18723
  const out = this.buffer;
18570
18724
  this.buffer = new Uint8Array(0);
18571
18725
  try {
@@ -18575,37 +18729,15 @@ var Http1Writer = class {
18575
18729
  }
18576
18730
  }
18577
18731
  async substitute(end) {
18578
- this.passing = true;
18732
+ this.mode = "pass";
18579
18733
  const all = this.buffer;
18580
18734
  this.buffer = new Uint8Array(0);
18581
- const s = this.s;
18582
- const session = sessionId();
18583
18735
  const done5 = await substituteHead(
18584
18736
  latin12(all.subarray(0, end)),
18585
- async (position, placeholders, head2) => s.broker.sessionMaterialize({
18586
- stamp: await s.stamp(),
18587
- session,
18588
- host: s.host,
18589
- port: s.port,
18590
- protocol: "http1",
18591
- position,
18592
- verified: s.verified,
18593
- handshakeAt: s.handshakeAt,
18594
- exit: s.exit,
18595
- placeholders,
18596
- head: head2
18597
- })
18737
+ (position, placeholders, head2) => this.ask("http1", position, placeholders, head2)
18598
18738
  ).catch(() => void 0);
18599
18739
  const head = done5 ? bytesOf(done5.head) : all.subarray(0, end);
18600
- if (done5) {
18601
- this.scope.add(
18602
- Object.entries(done5.values).map(([placeholder, value2]) => ({
18603
- name: "sealed",
18604
- value: value2,
18605
- placeholder
18606
- }))
18607
- );
18608
- }
18740
+ if (done5) this.remember(done5.values);
18609
18741
  try {
18610
18742
  await writeAll4(this.conn, head);
18611
18743
  await writeAll4(this.conn, all.subarray(end));
@@ -18616,14 +18748,14 @@ var Http1Writer = class {
18616
18748
  }
18617
18749
  flushed() {
18618
18750
  clearTimeout(this.timer);
18619
- this.chain = this.chain.then(() => this.passing ? void 0 : this.release());
18751
+ this.chain = this.chain.then(() => this.mode === "pass" ? void 0 : this.release());
18620
18752
  return this.chain;
18621
18753
  }
18622
18754
  drop() {
18623
18755
  clearTimeout(this.timer);
18624
18756
  this.buffer.fill(0);
18625
18757
  this.buffer = new Uint8Array(0);
18626
- this.passing = true;
18758
+ this.mode = "pass";
18627
18759
  }
18628
18760
  };
18629
18761
  var IDLE2 = /* @__PURE__ */ Symbol("idle");
@@ -18634,11 +18766,9 @@ var ScrubReader = class {
18634
18766
  held = false;
18635
18767
  ended = false;
18636
18768
  conn;
18637
- s;
18638
18769
  scope;
18639
- constructor(conn, s, scope) {
18770
+ constructor(conn, scope) {
18640
18771
  this.conn = conn;
18641
- this.s = s;
18642
18772
  this.scope = scope;
18643
18773
  }
18644
18774
  current() {
@@ -18697,8 +18827,8 @@ function idle() {
18697
18827
  }
18698
18828
  function sealedConn(conn, s) {
18699
18829
  const scope = s.broker.sessions.scope(s.pid, s.host);
18700
- const writer = substitutes(s) ? new Http1Writer(conn, s, scope) : void 0;
18701
- const reader = new ScrubReader(conn, s, scope);
18830
+ const writer = substitutes(s) ? new SessionWriter(conn, s, scope) : void 0;
18831
+ const reader = new ScrubReader(conn, scope);
18702
18832
  return {
18703
18833
  localAddr: conn.localAddr,
18704
18834
  remoteAddr: conn.remoteAddr,
@@ -19824,6 +19954,12 @@ function tlsOverTransport(req, proc) {
19824
19954
  return { fd: proc.fds.install(new OpenFile(mine), 3), alpnProtocol: "http/1.1", servername };
19825
19955
  }
19826
19956
 
19957
+ // src/kernel/test-hooks.ts
19958
+ var SYSCALL_HOOK = /* @__PURE__ */ Symbol.for("slicc-kernel.test.syscall");
19959
+ function testSyscallHook() {
19960
+ return globalThis[SYSCALL_HOOK];
19961
+ }
19962
+
19827
19963
  // src/kernel/vfs-file.ts
19828
19964
  var O_ACCMODE = 3;
19829
19965
  var O_WRONLY = 1;
@@ -21038,7 +21174,8 @@ var WasmProcess = class {
21038
21174
  cwd,
21039
21175
  ...moved2,
21040
21176
  ...group,
21041
- ...exec ? { exec } : {}
21177
+ ...exec ? { exec } : {},
21178
+ search: req.search
21042
21179
  };
21043
21180
  const pid = await this.children.spawn(spawned, stdio, inherit2);
21044
21181
  if (deathSignal !== void 0) this.onDeath(pgid === 0 || session ? -pid : pid, deathSignal);
@@ -21124,6 +21261,8 @@ var WasmProcess = class {
21124
21261
  return void 0;
21125
21262
  }
21126
21263
  async syscall(req, cancelled, block) {
21264
+ const hook = testSyscallHook();
21265
+ if (hook) await hook({ pid: this.pid, op: req.op });
21127
21266
  this.options.onSyscall?.(req);
21128
21267
  this.calls += 1;
21129
21268
  const started = performance.now();
@@ -21421,18 +21560,18 @@ var WasmProcess = class {
21421
21560
  }
21422
21561
  if (this.writesAt(req) && this.options.readonlyAt?.(path)) throw new KernelError("EROFS");
21423
21562
  const open2 = { ...req, path };
21424
- const plain2 = this.plainMode(req.mode);
21563
+ const plain3 = this.plainMode(req.mode);
21425
21564
  if (req.exclusive) {
21426
21565
  await nodes.createExclusive(path, this.newOwner(req.mode));
21427
- if (plain2 !== void 0) await fs.chmod?.(path, plain2);
21566
+ if (plain3 !== void 0) await fs.chmod?.(path, plain3);
21428
21567
  this.fds.installAt(fd, this.openVfsFile(open2, void 0, fs));
21429
21568
  } else if (req.create) {
21430
21569
  await nodes.onEntry(path, async () => {
21431
- const marks = this.options.owners || plain2 !== void 0;
21570
+ const marks = this.options.owners || plain3 !== void 0;
21432
21571
  const fresh2 = marks && !await present3(fs, path, true);
21433
21572
  this.fds.installAt(fd, this.openVfsFile(open2, await nodes.identify(path), fs));
21434
21573
  await this.fds.get(fd).file.stat?.();
21435
- if (fresh2 && plain2 !== void 0) await fs.chmod?.(path, plain2);
21574
+ if (fresh2 && plain3 !== void 0) await fs.chmod?.(path, plain3);
21436
21575
  else if (fresh2) {
21437
21576
  await fs.chown?.(path, { ...this.newOwner(req.mode), kind: "new" });
21438
21577
  }
@@ -23575,15 +23714,15 @@ function isRecord(value2) {
23575
23714
  return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
23576
23715
  }
23577
23716
  function serialized(reply) {
23578
- let plain2;
23717
+ let plain3;
23579
23718
  try {
23580
23719
  const text = JSON.stringify(reply);
23581
- plain2 = text === void 0 ? void 0 : JSON.parse(text);
23720
+ plain3 = text === void 0 ? void 0 : JSON.parse(text);
23582
23721
  } catch (err) {
23583
23722
  return JSON.stringify(errorReply("EIO", lineOf2(err)));
23584
23723
  }
23585
- if (!isRecord(plain2)) return JSON.stringify(errorReply("EIO", "the vault gave no reply"));
23586
- const { v: _, ...rest2 } = plain2;
23724
+ if (!isRecord(plain3)) return JSON.stringify(errorReply("EIO", "the vault gave no reply"));
23725
+ const { v: _, ...rest2 } = plain3;
23587
23726
  return JSON.stringify({ v: 1, ...rest2 });
23588
23727
  }
23589
23728
  function lineOf2(err) {
@@ -25545,13 +25684,13 @@ function splitWords(text) {
25545
25684
  while (piece.lastIndex < text.length) {
25546
25685
  const m = piece.exec(text);
25547
25686
  if (!m) return void 0;
25548
- const [, single, double, escaped, plain2, space] = m;
25687
+ const [, single, double, escaped, plain3, space] = m;
25549
25688
  if (space !== void 0) {
25550
25689
  if (word !== void 0) words2.push(word);
25551
25690
  word = void 0;
25552
25691
  continue;
25553
25692
  }
25554
- word = (word ?? "") + (single ?? (double !== void 0 ? unescaped(double) : escaped ?? plain2));
25693
+ word = (word ?? "") + (single ?? (double !== void 0 ? unescaped(double) : escaped ?? plain3));
25555
25694
  }
25556
25695
  if (word !== void 0) words2.push(word);
25557
25696
  return words2;
@@ -26744,16 +26883,52 @@ var Launcher = class {
26744
26883
  for (const bin of planned?.bins ?? []) await need(g, "exec", bin, R_OK | X_OK);
26745
26884
  if (planned?.target.copy) await need(g, "exec", planned.target.copy, R_OK | X_OK);
26746
26885
  }
26747
- async checkedPlan(req, { ppid, cred, scope }, fds) {
26748
- const refused3 = async (err) => {
26886
+ async checkedPlan(req, ctx, fds) {
26887
+ try {
26888
+ return await this.planOrSearch(req, ctx);
26889
+ } catch (err) {
26749
26890
  await fds.closeAll();
26750
- throw err.code === "EACCES" ? new SpawnError("EACCES") : err;
26891
+ throw err;
26892
+ }
26893
+ }
26894
+ async planOrSearch(req, ctx) {
26895
+ const bare = !req.file.includes("/") && !COMMAND2.test(req.file);
26896
+ try {
26897
+ return await this.planOne(req, ctx);
26898
+ } catch (err) {
26899
+ const code = codeOf7(err);
26900
+ const searched = bare && req.search !== false && (code === "ENOENT" || code === "ENOEXEC");
26901
+ if (!searched || await this.commandAt(req.file, ctx.scope)) throw err;
26902
+ const found = await this.onPath(req, ctx);
26903
+ if (found) return found;
26904
+ throw err;
26905
+ }
26906
+ }
26907
+ async onPath(req, ctx) {
26908
+ const path = req.env.PATH;
26909
+ if (typeof path !== "string") return void 0;
26910
+ let denied2 = false;
26911
+ for (const dir of path.split(":")) {
26912
+ const file = dir === "" ? `./${req.file}` : `${dir.replace(/\/+$/, "")}/${req.file}`;
26913
+ try {
26914
+ return await this.planOne({ ...req, file }, ctx);
26915
+ } catch (err) {
26916
+ const code = codeOf7(err);
26917
+ if (code === "EACCES") denied2 = true;
26918
+ else if (code !== "ENOENT" && code !== "ENOTDIR") throw err;
26919
+ }
26920
+ }
26921
+ if (denied2) throw new SpawnError("EACCES");
26922
+ return void 0;
26923
+ }
26924
+ async planOne(req, { ppid, cred, scope }) {
26925
+ const refused3 = (err) => {
26926
+ throw codeOf7(err) === "EACCES" ? new SpawnError("EACCES") : err;
26751
26927
  };
26752
26928
  const file = await this.execFile(req.file, req.cwd, this.execGuard(cred, ppid)).catch(refused3);
26753
26929
  const planned = await this.plan(file, req.argv, req.cwd, scope, req.argv0);
26754
26930
  await this.mayExec(cred, { ...req, file, pid: ppid }, planned).catch(refused3);
26755
26931
  if (planned) return planned;
26756
- await fds.closeAll();
26757
26932
  throw new SpawnError(await this.unrunnable(file, req.cwd, scope));
26758
26933
  }
26759
26934
  async enterable(g, cwd) {
@@ -26920,12 +27095,12 @@ var Launcher = class {
26920
27095
  return `${path}:${st.size}:${st.mtime.getTime()}`;
26921
27096
  }
26922
27097
  verified(path, caller, fs = this.base) {
26923
- const plain2 = () => fs.readFileBuffer(path);
26924
- return this.integrity ? this.integrity.read(path, caller, plain2) : plain2();
27098
+ const plain3 = () => fs.readFileBuffer(path);
27099
+ return this.integrity ? this.integrity.read(path, caller, plain3) : plain3();
26925
27100
  }
26926
27101
  keyed(path, caller, asked) {
26927
- const plain2 = async () => this.base.readFileBuffer(path);
26928
- return this.integrity ? this.integrity.readKeyed(path, caller, plain2, asked) : plain2().then((bytes) => ({ bytes }));
27102
+ const plain3 = async () => this.base.readFileBuffer(path);
27103
+ return this.integrity ? this.integrity.readKeyed(path, caller, plain3, asked) : plain3().then((bytes) => ({ bytes }));
26929
27104
  }
26930
27105
  cached(cache, key, load) {
26931
27106
  const hit = cache.get(key);
@@ -27122,7 +27297,7 @@ var Launcher = class {
27122
27297
  });
27123
27298
  return {
27124
27299
  source: {
27125
- read: (path, plain2) => integrity.readSource(path, caller(), plain2),
27300
+ read: (path, plain3) => integrity.readSource(path, caller(), plain3),
27126
27301
  open: (path, real) => integrity.openSource(path, caller(), real)
27127
27302
  }
27128
27303
  };
@@ -28029,9 +28204,9 @@ var Launcher = class {
28029
28204
  }
28030
28205
  );
28031
28206
  }
28032
- environment(cwd, extra, account, login = false) {
28207
+ environment(cwd, extra, account, login2 = false) {
28033
28208
  const env = {
28034
- ...login ? networkEnv(this.hostname) : this.env,
28209
+ ...login2 ? networkEnv(this.hostname) : this.env,
28035
28210
  ...userEnv(account, this.pnpmHome),
28036
28211
  PWD: cwd,
28037
28212
  ...extra
@@ -28258,6 +28433,9 @@ var Launcher = class {
28258
28433
  function cronLocks() {
28259
28434
  return globalThis.navigator?.locks;
28260
28435
  }
28436
+ function codeOf7(err) {
28437
+ return err?.code;
28438
+ }
28261
28439
 
28262
28440
  // src/pin.ts
28263
28441
  function pinScript(url) {