@ai-ecoverse/slicc-kernel 1.82.0 → 1.83.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.
@@ -131,8 +131,8 @@ function descendants(path) {
131
131
  return IDBKeyRange.bound(`${path}/`, `${path}0`, false, true);
132
132
  }
133
133
  function settle(transaction, value) {
134
- return new Promise((resolve, reject) => {
135
- transaction.oncomplete = () => resolve(value());
134
+ return new Promise((resolve2, reject) => {
135
+ transaction.oncomplete = () => resolve2(value());
136
136
  transaction.onabort = () => reject(transaction.error ?? new Error("metadata transaction aborted"));
137
137
  });
138
138
  }
@@ -249,14 +249,14 @@ var IndexedDbMeta = class {
249
249
  }
250
250
  };
251
251
  function openMeta(name2, factory) {
252
- return new Promise((resolve, reject) => {
252
+ return new Promise((resolve2, reject) => {
253
253
  const request2 = factory.open(name2, META_VERSION);
254
254
  request2.onupgradeneeded = (event) => {
255
255
  if (event.oldVersion < 1) {
256
256
  request2.result.createObjectStore(META_STORE, { keyPath: "path" }).createIndex("dir", "dir");
257
257
  }
258
258
  };
259
- request2.onsuccess = () => resolve(new IndexedDbMeta(request2.result));
259
+ request2.onsuccess = () => resolve2(new IndexedDbMeta(request2.result));
260
260
  request2.onerror = () => reject(request2.error);
261
261
  });
262
262
  }
@@ -740,11 +740,11 @@ var RemoteWatch = class {
740
740
  const seq2 = ++this.seq;
741
741
  this.channel.postMessage({ tab: this.tab, paths: this.mine, seq: seq2 });
742
742
  if (this.peers.size === 0) return Promise.resolve();
743
- return new Promise((resolve) => {
743
+ return new Promise((resolve2) => {
744
744
  const done4 = () => {
745
745
  clearTimeout(timer);
746
746
  this.waiting.delete(seq2);
747
- resolve();
747
+ resolve2();
748
748
  };
749
749
  const timer = setTimeout(() => {
750
750
  done4();
@@ -840,7 +840,7 @@ async function openSync(handle) {
840
840
  const delay = SYNC_BACKOFF_MS[attempt];
841
841
  if (!LOCKED.has(err?.name)) throw err;
842
842
  if (delay === void 0) return void 0;
843
- await new Promise((resolve) => setTimeout(resolve, delay));
843
+ await new Promise((resolve2) => setTimeout(resolve2, delay));
844
844
  }
845
845
  }
846
846
  }
@@ -1297,7 +1297,7 @@ var OpfsFs = class {
1297
1297
  const again = name2 === "NotReadableError" || locks && LOCKED.has(name2);
1298
1298
  if (!again || attempt >= READ_ATTEMPTS)
1299
1299
  throw translate(err, path, locks ? "write" : "read");
1300
- await new Promise((resolve) => setTimeout(resolve, attempt * 10));
1300
+ await new Promise((resolve2) => setTimeout(resolve2, attempt * 10));
1301
1301
  }
1302
1302
  }
1303
1303
  }
@@ -1354,8 +1354,8 @@ var OpfsFs = class {
1354
1354
  }
1355
1355
  async truncate(path, size) {
1356
1356
  const handle = await this.existing(path, true);
1357
- const resolve = this.ranged || this.remote?.watched();
1358
- const target = resolve ? (await this.locate(path, true)).path : path;
1357
+ const resolve2 = this.ranged || this.remote?.watched();
1358
+ const target = resolve2 ? (await this.locate(path, true)).path : path;
1359
1359
  await this.retrying(path, () => positioned(handle, (io) => io.truncate(size)), true);
1360
1360
  this.written(target);
1361
1361
  }
@@ -1779,8 +1779,8 @@ function memoryMedia() {
1779
1779
  };
1780
1780
  }
1781
1781
  function settle2(request2, value) {
1782
- return new Promise((resolve, reject) => {
1783
- request2.onsuccess = () => resolve(value());
1782
+ return new Promise((resolve2, reject) => {
1783
+ request2.onsuccess = () => resolve2(value());
1784
1784
  request2.onerror = () => reject(request2.error);
1785
1785
  });
1786
1786
  }
@@ -1818,7 +1818,7 @@ function pinScript(url) {
1818
1818
 
1819
1819
  // src/cdp/port.ts
1820
1820
  function portCdpHook(ask, gone) {
1821
- return (request2) => new Promise((resolve, reject) => {
1821
+ return (request2) => new Promise((resolve2, reject) => {
1822
1822
  const { port1, port2 } = new MessageChannel();
1823
1823
  let closed = false;
1824
1824
  const conn = {
@@ -1836,7 +1836,7 @@ function portCdpHook(ask, gone) {
1836
1836
  };
1837
1837
  port1.addEventListener("message", ({ data }) => {
1838
1838
  if ("m" in data) conn.onmessage?.(data.m);
1839
- else if ("open" in data) resolve(conn);
1839
+ else if ("open" in data) resolve2(conn);
1840
1840
  else if ("error" in data) {
1841
1841
  closed = true;
1842
1842
  port1.close();
@@ -2370,9 +2370,9 @@ var KernelPipe = class {
2370
2370
  let filled = 0;
2371
2371
  for (const chunk2 of this.chunks) {
2372
2372
  if (filled === out.length) break;
2373
- const count = Math.min(chunk2.length, out.length - filled);
2374
- out.set(chunk2.subarray(0, count), filled);
2375
- filled += count;
2373
+ const count2 = Math.min(chunk2.length, out.length - filled);
2374
+ out.set(chunk2.subarray(0, count2), filled);
2375
+ filled += count2;
2376
2376
  }
2377
2377
  return out;
2378
2378
  }
@@ -2403,25 +2403,25 @@ var KernelPipe = class {
2403
2403
  let filled = 0;
2404
2404
  while (filled < n) {
2405
2405
  const head = this.chunks[0];
2406
- const count = Math.min(head.length, n - filled);
2407
- out.set(head.subarray(0, count), filled);
2408
- filled += count;
2409
- if (count === head.length) this.chunks.shift();
2410
- else this.chunks[0] = head.subarray(count);
2406
+ const count2 = Math.min(head.length, n - filled);
2407
+ out.set(head.subarray(0, count2), filled);
2408
+ filled += count2;
2409
+ if (count2 === head.length) this.chunks.shift();
2410
+ else this.chunks[0] = head.subarray(count2);
2411
2411
  }
2412
2412
  this.size -= n;
2413
2413
  return out;
2414
2414
  }
2415
2415
  changed(signal) {
2416
2416
  if (signal?.aborted) return Promise.reject(new PipeError("EINTR"));
2417
- return new Promise((resolve, reject) => {
2417
+ return new Promise((resolve2, reject) => {
2418
2418
  const onAbort = () => {
2419
2419
  this.waiters = this.waiters.filter((w) => w !== waiter);
2420
2420
  reject(new PipeError("EINTR"));
2421
2421
  };
2422
2422
  const waiter = () => {
2423
2423
  signal?.removeEventListener("abort", onAbort);
2424
- resolve();
2424
+ resolve2();
2425
2425
  };
2426
2426
  this.waiters.push(waiter);
2427
2427
  signal?.addEventListener("abort", onAbort, { once: true });
@@ -2430,7 +2430,7 @@ var KernelPipe = class {
2430
2430
  wake() {
2431
2431
  const waiters = this.waiters;
2432
2432
  this.waiters = [];
2433
- for (const resolve of waiters) resolve();
2433
+ for (const resolve2 of waiters) resolve2();
2434
2434
  }
2435
2435
  };
2436
2436
 
@@ -2891,14 +2891,14 @@ var Changes = class {
2891
2891
  waiters = [];
2892
2892
  wait(signal) {
2893
2893
  if (signal?.aborted) return Promise.reject(new KernelError("EINTR"));
2894
- return new Promise((resolve, reject) => {
2894
+ return new Promise((resolve2, reject) => {
2895
2895
  const onAbort = () => {
2896
2896
  this.waiters = this.waiters.filter((w) => w !== waiter);
2897
2897
  reject(new KernelError("EINTR"));
2898
2898
  };
2899
2899
  const waiter = () => {
2900
2900
  signal?.removeEventListener("abort", onAbort);
2901
- resolve();
2901
+ resolve2();
2902
2902
  };
2903
2903
  this.waiters.push(waiter);
2904
2904
  signal?.addEventListener("abort", onAbort, { once: true });
@@ -2907,7 +2907,7 @@ var Changes = class {
2907
2907
  wake() {
2908
2908
  const waiters = this.waiters;
2909
2909
  this.waiters = [];
2910
- for (const resolve of waiters) resolve();
2910
+ for (const resolve2 of waiters) resolve2();
2911
2911
  }
2912
2912
  };
2913
2913
  function link(a, b) {
@@ -3075,7 +3075,7 @@ var KernelSocket = class _KernelSocket {
3075
3075
  });
3076
3076
  const { host, port } = addr;
3077
3077
  const dialled = new Promise(
3078
- (resolve) => resolve(route.uplink.dial({ network: "tcp", host, port, signal: abort.signal }))
3078
+ (resolve2) => resolve2(route.uplink.dial({ network: "tcp", host, port, signal: abort.signal }))
3079
3079
  );
3080
3080
  dialled.then(
3081
3081
  (conn) => abort.signal.aborted && conn.close(),
@@ -3425,8 +3425,8 @@ var MessageQueue = class {
3425
3425
  this.overflow = overflow;
3426
3426
  this.limit = limit;
3427
3427
  this.taken = taken;
3428
- this.closed = new Promise((resolve) => {
3429
- this.settle = resolve;
3428
+ this.closed = new Promise((resolve2) => {
3429
+ this.settle = resolve2;
3430
3430
  });
3431
3431
  }
3432
3432
  push(message3) {
@@ -3465,8 +3465,8 @@ var MessageQueue = class {
3465
3465
  continue;
3466
3466
  }
3467
3467
  if (this.ended) return;
3468
- await new Promise((resolve) => {
3469
- this.waiter = resolve;
3468
+ await new Promise((resolve2) => {
3469
+ this.waiter = resolve2;
3470
3470
  });
3471
3471
  }
3472
3472
  }
@@ -3557,8 +3557,8 @@ function serveTransport(peer, transport, { closeWaitMs = CLOSE_WAIT_MS } = {}) {
3557
3557
  const relay = async (nid, socket) => {
3558
3558
  let ending;
3559
3559
  let late;
3560
- const unanswered = new Promise((resolve) => {
3561
- late = () => resolve("late");
3560
+ const unanswered = new Promise((resolve2) => {
3561
+ late = () => resolve2("late");
3562
3562
  });
3563
3563
  const flow = {
3564
3564
  inflight: 0,
@@ -3586,8 +3586,8 @@ function serveTransport(peer, transport, { closeWaitMs = CLOSE_WAIT_MS } = {}) {
3586
3586
  }
3587
3587
  flow.inflight += payloadSize(data);
3588
3588
  while (flow.inflight > INBOUND_LIMIT && !flow.closing) {
3589
- await new Promise((resolve) => {
3590
- flow.wake = resolve;
3589
+ await new Promise((resolve2) => {
3590
+ flow.wake = resolve2;
3591
3591
  });
3592
3592
  }
3593
3593
  }
@@ -3606,7 +3606,7 @@ function serveTransport(peer, transport, { closeWaitMs = CLOSE_WAIT_MS } = {}) {
3606
3606
  if (!socket) return;
3607
3607
  socket.send(call.data);
3608
3608
  while (socket.buffered > SEND_BUFFER && sockets.has(call.nid)) {
3609
- await new Promise((resolve) => setTimeout(resolve, 10));
3609
+ await new Promise((resolve2) => setTimeout(resolve2, 10));
3610
3610
  }
3611
3611
  peer.postMessage({ net: "ws-acked", nid: call.nid, n: payloadSize(call.data) });
3612
3612
  };
@@ -5113,10 +5113,10 @@ var Budget = class {
5113
5113
  async acquire(n, signal) {
5114
5114
  while (this.free < n) {
5115
5115
  signal.throwIfAborted();
5116
- await new Promise((resolve) => {
5116
+ await new Promise((resolve2) => {
5117
5117
  const done4 = () => {
5118
5118
  signal.removeEventListener("abort", done4);
5119
- resolve();
5119
+ resolve2();
5120
5120
  };
5121
5121
  this.waiters.push(done4);
5122
5122
  signal.addEventListener("abort", done4, { once: true });
@@ -5258,14 +5258,14 @@ async function watchHangup(conn, abort, until) {
5258
5258
  }
5259
5259
  }
5260
5260
  function untilAborted(response, signal) {
5261
- return new Promise((resolve, reject) => {
5261
+ return new Promise((resolve2, reject) => {
5262
5262
  const onAbort = () => {
5263
5263
  reject(signal.reason ?? new KernelError("EINTR"));
5264
5264
  response.then((late) => late.cancel()).catch(() => void 0);
5265
5265
  };
5266
5266
  if (signal.aborted) return onAbort();
5267
5267
  signal.addEventListener("abort", onAbort, { once: true });
5268
- response.then(resolve, reject).finally(() => signal.removeEventListener("abort", onAbort));
5268
+ response.then(resolve2, reject).finally(() => signal.removeEventListener("abort", onAbort));
5269
5269
  });
5270
5270
  }
5271
5271
  function plainResponse(status, message3) {
@@ -5298,8 +5298,8 @@ function wireCode(code) {
5298
5298
  return sendableCode(code) ? code : 1011;
5299
5299
  }
5300
5300
  function quietly(ms) {
5301
- return new Promise((resolve) => {
5302
- AbortSignal.timeout(ms).addEventListener("abort", () => resolve(), { once: true });
5301
+ return new Promise((resolve2) => {
5302
+ AbortSignal.timeout(ms).addEventListener("abort", () => resolve2(), { once: true });
5303
5303
  });
5304
5304
  }
5305
5305
  var RealmProxy = class {
@@ -5397,7 +5397,7 @@ var RealmProxy = class {
5397
5397
  return false;
5398
5398
  }
5399
5399
  const url = ctx.origin ? tunnelRequestUrl(req, ctx.origin) : requestUrl(req);
5400
- const keep = keepsAlive(req);
5400
+ const keep2 = keepsAlive(req);
5401
5401
  const framing = requestFraming(req.headers);
5402
5402
  const reserve = framing.kind === "length" ? framing.length : framing.kind === "chunked" ? this.cap() : 0;
5403
5403
  if (reserve > this.cap()) throw new HttpError(413, `request body over ${this.cap()} bytes`);
@@ -5420,7 +5420,7 @@ var RealmProxy = class {
5420
5420
  } finally {
5421
5421
  this.bodies.release(reserve);
5422
5422
  }
5423
- return await this.relay(conn, req.method, req.minor, response, keep);
5423
+ return await this.relay(conn, req.method, req.minor, response, keep2);
5424
5424
  } finally {
5425
5425
  this.stop.signal.removeEventListener("abort", stopExchange);
5426
5426
  abort.abort();
@@ -5468,8 +5468,8 @@ var RealmProxy = class {
5468
5468
  bodiless: bodiless2
5469
5469
  });
5470
5470
  const chunked = !bodiless2 && minor >= 1;
5471
- const keep = keepAlive && (bodiless2 || chunked);
5472
- headers.push(["Connection", keep ? "keep-alive" : "close"]);
5471
+ const keep2 = keepAlive && (bodiless2 || chunked);
5472
+ headers.push(["Connection", keep2 ? "keep-alive" : "close"]);
5473
5473
  if (chunked) headers.push(["Transfer-Encoding", "chunked"]);
5474
5474
  const signal = this.stop.signal;
5475
5475
  await conn.write(
@@ -5478,7 +5478,7 @@ var RealmProxy = class {
5478
5478
  );
5479
5479
  if (bodiless2) {
5480
5480
  await response.cancel();
5481
- return keep;
5481
+ return keep2;
5482
5482
  }
5483
5483
  try {
5484
5484
  for await (const piece of response.body) {
@@ -5489,7 +5489,7 @@ var RealmProxy = class {
5489
5489
  return false;
5490
5490
  }
5491
5491
  if (chunked) await conn.write(LAST_CHUNK, signal);
5492
- return keep;
5492
+ return keep2;
5493
5493
  }
5494
5494
  async connect(conn, incoming, req, idle) {
5495
5495
  const target = tunnelTarget(req);
@@ -5712,10 +5712,10 @@ function header(der, at) {
5712
5712
  let len = der[at + 1];
5713
5713
  let start2 = at + 2;
5714
5714
  if (len & 128) {
5715
- const count = len & 127;
5715
+ const count2 = len & 127;
5716
5716
  len = 0;
5717
- for (let i = 0; i < count; i++) len = len * 256 + der[start2 + i];
5718
- start2 += count;
5717
+ for (let i = 0; i < count2; i++) len = len * 256 + der[start2 + i];
5718
+ start2 += count2;
5719
5719
  }
5720
5720
  if (start2 + len > der.length) throw new Error("truncated DER");
5721
5721
  return [tag, start2, start2 + len];
@@ -5833,18 +5833,18 @@ var LEAF_LIFETIME = 7 * DAY;
5833
5833
  var ECDSA = { name: "ECDSA", namedCurve: "P-256" };
5834
5834
  var SIGN = { name: "ECDSA", hash: "SHA-256" };
5835
5835
  function request(req) {
5836
- return new Promise((resolve, reject) => {
5837
- req.onsuccess = () => resolve(req.result);
5836
+ return new Promise((resolve2, reject) => {
5837
+ req.onsuccess = () => resolve2(req.result);
5838
5838
  req.onerror = () => reject(req.error);
5839
5839
  });
5840
5840
  }
5841
5841
  function indexedDbCaStore(dbName = "slicc-realm-ca") {
5842
5842
  let db;
5843
5843
  const open = () => {
5844
- db ??= new Promise((resolve, reject) => {
5844
+ db ??= new Promise((resolve2, reject) => {
5845
5845
  const req = indexedDB.open(dbName, 1);
5846
5846
  req.onupgradeneeded = () => req.result.createObjectStore("ca");
5847
- req.onsuccess = () => resolve(req.result);
5847
+ req.onsuccess = () => resolve2(req.result);
5848
5848
  req.onerror = () => reject(req.error);
5849
5849
  });
5850
5850
  db.catch(() => {
@@ -5868,8 +5868,8 @@ function indexedDbCaStore(dbName = "slicc-realm-ca") {
5868
5868
  if (kept === record) store.put(record, owner);
5869
5869
  else stored = kept;
5870
5870
  };
5871
- await new Promise((resolve, reject) => {
5872
- tx.oncomplete = () => resolve();
5871
+ await new Promise((resolve2, reject) => {
5872
+ tx.oncomplete = () => resolve2();
5873
5873
  tx.onerror = () => reject(tx.error);
5874
5874
  });
5875
5875
  return stored;
@@ -6398,8 +6398,8 @@ var RemoteTransport = class {
6398
6398
  }
6399
6399
  ask(call) {
6400
6400
  if (this.failure) return Promise.reject(this.failure);
6401
- return new Promise((resolve, reject) => {
6402
- this.waiting.set(call.nid, { resolve, reject });
6401
+ return new Promise((resolve2, reject) => {
6402
+ this.waiting.set(call.nid, { resolve: resolve2, reject });
6403
6403
  this.port.postMessage(call);
6404
6404
  });
6405
6405
  }
@@ -6804,7 +6804,7 @@ var CdpFacade = class {
6804
6804
  const conn = await this.host(runtime);
6805
6805
  try {
6806
6806
  const reply = await new Promise(
6807
- (resolve, reject) => {
6807
+ (resolve2, reject) => {
6808
6808
  const timer = setTimeout(
6809
6809
  () => reject(new HttpError(504, "the CDP host did not answer Target.getTargets")),
6810
6810
  this.options.listTimeout ?? LIST_TIMEOUT
@@ -6817,7 +6817,7 @@ var CdpFacade = class {
6817
6817
  const parsed2 = JSON.parse(message3);
6818
6818
  if (parsed2.id !== 1) return;
6819
6819
  clearTimeout(timer);
6820
- resolve(parsed2);
6820
+ resolve2(parsed2);
6821
6821
  };
6822
6822
  conn.send(JSON.stringify({ id: 1, method: "Target.getTargets" }));
6823
6823
  }
@@ -6877,9 +6877,9 @@ var Relay = class {
6877
6877
  }
6878
6878
  async start(head) {
6879
6879
  await this.send(head);
6880
- const hostGone = new Promise((resolve) => {
6880
+ const hostGone = new Promise((resolve2) => {
6881
6881
  this.host.onclose = (reason) => {
6882
- void this.end(reason ? CLOSE.error : CLOSE.normal, reason ?? "").then(() => resolve());
6882
+ void this.end(reason ? CLOSE.error : CLOSE.normal, reason ?? "").then(() => resolve2());
6883
6883
  };
6884
6884
  });
6885
6885
  this.host.onmessage = (message3) => {
@@ -6893,8 +6893,8 @@ var Relay = class {
6893
6893
  await Promise.race([pumping, hostGone]);
6894
6894
  await this.writes;
6895
6895
  let timer;
6896
- const waited = new Promise((resolve) => {
6897
- timer = setTimeout(resolve, this.closeWaitMs);
6896
+ const waited = new Promise((resolve2) => {
6897
+ timer = setTimeout(resolve2, this.closeWaitMs);
6898
6898
  });
6899
6899
  await Promise.race([pumping, waited]);
6900
6900
  clearTimeout(timer);
@@ -7544,16 +7544,16 @@ var FreshModules = class {
7544
7544
  if (head) await decide(path, head);
7545
7545
  };
7546
7546
  }
7547
- const bound = /* @__PURE__ */ new WeakMap();
7547
+ const bound2 = /* @__PURE__ */ new WeakMap();
7548
7548
  return new Proxy(fs, {
7549
7549
  get(target, key, receiver) {
7550
7550
  if (Object.hasOwn(overrides, key)) return overrides[key];
7551
7551
  const value = Reflect.get(target, key, receiver);
7552
7552
  if (typeof value !== "function") return value;
7553
- let method = bound.get(value);
7553
+ let method = bound2.get(value);
7554
7554
  if (method === void 0) {
7555
7555
  method = value.bind(target);
7556
- bound.set(value, method);
7556
+ bound2.set(value, method);
7557
7557
  }
7558
7558
  return method;
7559
7559
  }
@@ -7621,12 +7621,12 @@ var PathGate = class {
7621
7621
  tails = /* @__PURE__ */ new Map();
7622
7622
  async acquire(path) {
7623
7623
  const prev = this.tails.get(path) ?? Promise.resolve();
7624
- const { promise, resolve } = Promise.withResolvers();
7624
+ const { promise, resolve: resolve2 } = Promise.withResolvers();
7625
7625
  const tail = prev.then(() => promise);
7626
7626
  this.tails.set(path, tail);
7627
7627
  await prev;
7628
7628
  return () => {
7629
- resolve();
7629
+ resolve2();
7630
7630
  if (this.tails.get(path) === tail) this.tails.delete(path);
7631
7631
  };
7632
7632
  }
@@ -8104,7 +8104,7 @@ var ChildTable = class {
8104
8104
  }
8105
8105
  async nextChange(candidates, flags2, interrupt) {
8106
8106
  let wake;
8107
- const stateChange = new Promise((resolve) => wake = resolve);
8107
+ const stateChange = new Promise((resolve2) => wake = resolve2);
8108
8108
  const watching = flags2.untraced || flags2.continued;
8109
8109
  if (watching && wake) this.stateChanged.push(wake);
8110
8110
  try {
@@ -8151,6 +8151,65 @@ var ChildTable = class {
8151
8151
  }
8152
8152
  };
8153
8153
 
8154
+ // src/kernel/exec-ticket.ts
8155
+ var TICKET_ENV = "SLICC_SEALED_TICKET";
8156
+ var TICKET_TTL_MS = 3e4;
8157
+ var MAX_TICKETS = 256;
8158
+ var TICKET = /^[0-9a-f]{32}$/;
8159
+ async function argvDigest(argv) {
8160
+ const bytes = new TextEncoder().encode(JSON.stringify(argv));
8161
+ const hash = new Uint8Array(await crypto.subtle.digest("SHA-256", bytes));
8162
+ return [...hash].map((b) => b.toString(16).padStart(2, "0")).join("");
8163
+ }
8164
+ function isStrings(value) {
8165
+ return Array.isArray(value) && value.every((item) => typeof item === "string");
8166
+ }
8167
+ function stringRecord(value) {
8168
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
8169
+ const entries = Object.entries(value);
8170
+ return entries.every(([, v]) => typeof v === "string") ? Object.fromEntries(entries) : void 0;
8171
+ }
8172
+ var TicketBook = class {
8173
+ booked = /* @__PURE__ */ new Map();
8174
+ now;
8175
+ normalise = async (path) => path;
8176
+ constructor(now = Date.now) {
8177
+ this.now = now;
8178
+ }
8179
+ get size() {
8180
+ return this.booked.size;
8181
+ }
8182
+ async record(req, reply, pid) {
8183
+ const { ticket, error } = reply;
8184
+ if (error !== void 0 || typeof ticket !== "string" || !TICKET.test(ticket)) return;
8185
+ const { path, argv, cwd } = req;
8186
+ const entry = {
8187
+ pid,
8188
+ path: await this.normalise(path),
8189
+ requested: path,
8190
+ requestedCwd: cwd,
8191
+ argv: await argvDigest(argv),
8192
+ cwd: await this.normalise(cwd),
8193
+ at: this.now()
8194
+ };
8195
+ this.prune();
8196
+ while (this.booked.size >= MAX_TICKETS)
8197
+ this.booked.delete(this.booked.keys().next().value);
8198
+ this.booked.set(ticket, entry);
8199
+ }
8200
+ take(ticket) {
8201
+ const booked = this.booked.get(ticket);
8202
+ this.booked.delete(ticket);
8203
+ return booked && this.now() - booked.at < TICKET_TTL_MS ? booked : void 0;
8204
+ }
8205
+ prune() {
8206
+ const now = this.now();
8207
+ for (const [ticket, booked] of this.booked) {
8208
+ if (now - booked.at >= TICKET_TTL_MS) this.booked.delete(ticket);
8209
+ }
8210
+ }
8211
+ };
8212
+
8154
8213
  // src/mount/protocol.ts
8155
8214
  var DRIVER_PROTOCOL = [1, 2];
8156
8215
  function driverVersionError(theirs) {
@@ -8221,7 +8280,7 @@ var DriverConnection = class _DriverConnection {
8221
8280
  call(call, transfer = []) {
8222
8281
  if (this.failure) return Promise.reject(this.failure);
8223
8282
  const id2 = ++this.nextId;
8224
- return new Promise((resolve, reject) => {
8283
+ return new Promise((resolve2, reject) => {
8225
8284
  const timer = unref(
8226
8285
  setTimeout(() => {
8227
8286
  this.waiting.delete(id2);
@@ -8234,7 +8293,7 @@ var DriverConnection = class _DriverConnection {
8234
8293
  this.onFail?.(error);
8235
8294
  }, this.timeoutMs)
8236
8295
  );
8237
- this.waiting.set(id2, { resolve, reject, timer });
8296
+ this.waiting.set(id2, { resolve: resolve2, reject, timer });
8238
8297
  this.port.postMessage({ ...call, id: id2 }, transfer);
8239
8298
  });
8240
8299
  }
@@ -8377,8 +8436,8 @@ var HeldPaths = class extends Map {
8377
8436
  this.keptHandles.delete(handle);
8378
8437
  if (kept) this.letGo(kept);
8379
8438
  }
8380
- const count = (this.opens.get(key) ?? 0) + (on ? 1 : -1);
8381
- if (count > 0) this.opens.set(key, count);
8439
+ const count2 = (this.opens.get(key) ?? 0) + (on ? 1 : -1);
8440
+ if (count2 > 0) this.opens.set(key, count2);
8382
8441
  else {
8383
8442
  this.opens.delete(key);
8384
8443
  for (const id2 of this.handlesAt(key)) this.handles.delete(id2);
@@ -8392,8 +8451,8 @@ var HeldPaths = class extends Map {
8392
8451
  return this.lastHandle;
8393
8452
  }
8394
8453
  holdWrite(path, on) {
8395
- const count = (this.get(path) ?? 0) + (on ? 1 : -1);
8396
- if (count > 0) this.set(path, count);
8454
+ const count2 = (this.get(path) ?? 0) + (on ? 1 : -1);
8455
+ if (count2 > 0) this.set(path, count2);
8397
8456
  else {
8398
8457
  this.delete(path);
8399
8458
  this.revoked.delete(path);
@@ -8415,18 +8474,18 @@ var HeldPaths = class extends Map {
8415
8474
  for (const path of this.keys()) if (within5(path, prefix)) this.revoked.add(path);
8416
8475
  }
8417
8476
  renamed(from, to) {
8418
- for (const [path, count] of [...this]) {
8477
+ for (const [path, count2] of [...this]) {
8419
8478
  if (!within5(path, from)) continue;
8420
8479
  const moved2 = to + path.slice(from.length);
8421
8480
  this.delete(path);
8422
- this.set(moved2, (this.get(moved2) ?? 0) + count);
8481
+ this.set(moved2, (this.get(moved2) ?? 0) + count2);
8423
8482
  if (this.revoked.delete(path)) this.revoked.add(moved2);
8424
8483
  }
8425
- for (const [path, count] of [...this.opens]) {
8484
+ for (const [path, count2] of [...this.opens]) {
8426
8485
  if (!within5(path, from)) continue;
8427
8486
  const moved2 = to + path.slice(from.length);
8428
8487
  this.opens.delete(path);
8429
- this.opens.set(moved2, (this.opens.get(moved2) ?? 0) + count);
8488
+ this.opens.set(moved2, (this.opens.get(moved2) ?? 0) + count2);
8430
8489
  }
8431
8490
  for (const [id2, key] of this.handles) {
8432
8491
  if (within5(key, from)) this.handles.set(id2, to + key.slice(from.length));
@@ -10720,7 +10779,7 @@ var AsyncOps = class {
10720
10779
  this.wake();
10721
10780
  }
10722
10781
  sleep(timeoutMs, signal) {
10723
- return new Promise((resolve, reject) => {
10782
+ return new Promise((resolve2, reject) => {
10724
10783
  let timer;
10725
10784
  const cleanup = () => {
10726
10785
  clearTimeout(timer);
@@ -10729,7 +10788,7 @@ var AsyncOps = class {
10729
10788
  };
10730
10789
  const wake = () => {
10731
10790
  cleanup();
10732
- resolve(true);
10791
+ resolve2(true);
10733
10792
  };
10734
10793
  const abort = () => {
10735
10794
  cleanup();
@@ -10740,7 +10799,7 @@ var AsyncOps = class {
10740
10799
  if (timeoutMs !== void 0) {
10741
10800
  timer = setTimeout(() => {
10742
10801
  cleanup();
10743
- resolve(false);
10802
+ resolve2(false);
10744
10803
  }, timeoutMs);
10745
10804
  }
10746
10805
  });
@@ -11162,7 +11221,7 @@ var Resolver = class {
11162
11221
  };
11163
11222
  function waitFor(lookup, signal) {
11164
11223
  lookup.waiters++;
11165
- return new Promise((resolve, reject) => {
11224
+ return new Promise((resolve2, reject) => {
11166
11225
  const abort = () => {
11167
11226
  if (--lookup.waiters === 0) lookup.abort.abort(new KernelError("EINTR"));
11168
11227
  reject(new KernelError("EINTR"));
@@ -11172,7 +11231,7 @@ function waitFor(lookup, signal) {
11172
11231
  if (signal?.aborted) return;
11173
11232
  lookup.waiters--;
11174
11233
  signal?.removeEventListener("abort", abort);
11175
- resolve(value);
11234
+ resolve2(value);
11176
11235
  });
11177
11236
  });
11178
11237
  }
@@ -11353,8 +11412,8 @@ var KernelTty = class {
11353
11412
  }
11354
11413
  rubOut(n) {
11355
11414
  const dropped2 = this.line.splice(this.line.length - n, n);
11356
- const utf82 = (this.termios.c_iflag & IUTF8) !== 0;
11357
- const cells = utf82 ? dropped2.filter((b) => !isContinuation(b)).length : dropped2.length;
11415
+ const utf83 = (this.termios.c_iflag & IUTF8) !== 0;
11416
+ const cells = utf83 ? dropped2.filter((b) => !isContinuation(b)).length : dropped2.length;
11358
11417
  if (cells > 0 && this.termios.c_lflag & ECHO) {
11359
11418
  this.output(encoder3.encode("\b \b".repeat(cells)), false);
11360
11419
  }
@@ -11424,14 +11483,14 @@ var KernelTty = class {
11424
11483
  }
11425
11484
  changed(signal) {
11426
11485
  if (signal?.aborted) return Promise.reject(new KernelError("EINTR"));
11427
- return new Promise((resolve, reject) => {
11486
+ return new Promise((resolve2, reject) => {
11428
11487
  const onAbort = () => {
11429
11488
  this.waiters = this.waiters.filter((w) => w !== waiter);
11430
11489
  reject(new KernelError("EINTR"));
11431
11490
  };
11432
11491
  const waiter = () => {
11433
11492
  signal?.removeEventListener("abort", onAbort);
11434
- resolve();
11493
+ resolve2();
11435
11494
  };
11436
11495
  this.waiters.push(waiter);
11437
11496
  signal?.addEventListener("abort", onAbort, { once: true });
@@ -11440,7 +11499,7 @@ var KernelTty = class {
11440
11499
  wake() {
11441
11500
  const waiters = this.waiters;
11442
11501
  this.waiters = [];
11443
- for (const resolve of waiters) resolve();
11502
+ for (const resolve2 of waiters) resolve2();
11444
11503
  }
11445
11504
  };
11446
11505
 
@@ -11539,14 +11598,14 @@ var PtyPair = class {
11539
11598
  }
11540
11599
  changed(signal) {
11541
11600
  if (signal?.aborted) return Promise.reject(new KernelError("EINTR"));
11542
- return new Promise((resolve, reject) => {
11601
+ return new Promise((resolve2, reject) => {
11543
11602
  const onAbort = () => {
11544
11603
  this.waiters = this.waiters.filter((w) => w !== waiter);
11545
11604
  reject(new KernelError("EINTR"));
11546
11605
  };
11547
11606
  const waiter = () => {
11548
11607
  signal?.removeEventListener("abort", onAbort);
11549
- resolve();
11608
+ resolve2();
11550
11609
  };
11551
11610
  this.waiters.push(waiter);
11552
11611
  signal?.addEventListener("abort", onAbort, { once: true });
@@ -11555,7 +11614,7 @@ var PtyPair = class {
11555
11614
  wake() {
11556
11615
  const waiters = this.waiters;
11557
11616
  this.waiters = [];
11558
- for (const resolve of waiters) resolve();
11617
+ for (const resolve2 of waiters) resolve2();
11559
11618
  }
11560
11619
  };
11561
11620
  var PtyTable = class {
@@ -11620,7 +11679,8 @@ function ptySyscall(req, ctx) {
11620
11679
  if (!ctx.ptys) throw new KernelError("ENOENT");
11621
11680
  const pair = ctx.ptys.get(req.n);
11622
11681
  ttyOpenable(ctx.guard, pair.slave);
11623
- const fd = ctx.fds.install(pair.openSlave(), 3);
11682
+ const slave = pair.openSlave();
11683
+ const fd = ctx.fds.install(ctx.ttyFilter?.(slave) ?? slave, 3);
11624
11684
  if (!req.noctty) ctx.jobs?.acquireTerminal(ctx.pid, pair.slave);
11625
11685
  return json4(fd);
11626
11686
  }
@@ -11693,8 +11753,8 @@ async function runChild(req, deps) {
11693
11753
  };
11694
11754
  const controls = [];
11695
11755
  const capture = () => {
11696
- const { promise, resolve } = Promise.withResolvers();
11697
- const control = { shut: false, ended: resolve, eof: promise };
11756
+ const { promise, resolve: resolve2 } = Promise.withResolvers();
11757
+ const control = { shut: false, ended: resolve2, eof: promise };
11698
11758
  controls.push(control);
11699
11759
  return { capture: true, max, overflow: () => stop("ENOBUFS"), control };
11700
11760
  };
@@ -11787,7 +11847,7 @@ async function waitReady(fds, read, write, deadline, interrupted2) {
11787
11847
  return file.changed === void 0 ? [] : [file.changed(round.signal).catch(() => void 0)];
11788
11848
  });
11789
11849
  let timer;
11790
- const expiry = deadline === Number.POSITIVE_INFINITY ? [] : [new Promise((resolve) => timer = setTimeout(resolve, deadline - Date.now()))];
11850
+ const expiry = deadline === Number.POSITIVE_INFINITY ? [] : [new Promise((resolve2) => timer = setTimeout(resolve2, deadline - Date.now()))];
11791
11851
  try {
11792
11852
  await Promise.race([...changes, ...expiry, interrupted2]);
11793
11853
  } finally {
@@ -11871,10 +11931,10 @@ async function socketSyscall(req, proc) {
11871
11931
  }
11872
11932
  }
11873
11933
  function interruptible2(dialing, signal) {
11874
- return new Promise((resolve, reject) => {
11934
+ return new Promise((resolve2, reject) => {
11875
11935
  const abort = () => reject(new KernelError("EINTR"));
11876
11936
  signal.addEventListener("abort", abort, { once: true });
11877
- dialing.then(resolve, reject).finally(() => signal.removeEventListener("abort", abort));
11937
+ dialing.then(resolve2, reject).finally(() => signal.removeEventListener("abort", abort));
11878
11938
  });
11879
11939
  }
11880
11940
  function unnamed(domain) {
@@ -12721,7 +12781,7 @@ var WasmProcess = class {
12721
12781
  if (this.stopped) return "stop";
12722
12782
  this.stopped = sig;
12723
12783
  this.stops++;
12724
- this.resumed = new Promise((resolve) => this.wake = resolve);
12784
+ this.resumed = new Promise((resolve2) => this.wake = resolve2);
12725
12785
  const blocked = this.interrupt;
12726
12786
  this.interrupt = new AbortController();
12727
12787
  blocked.abort();
@@ -12786,7 +12846,9 @@ var WasmProcess = class {
12786
12846
  const { ptys, jobs } = this.options;
12787
12847
  const owner = this.options.owners ? this.ttyOwner() : void 0;
12788
12848
  const guard2 = this.guarded();
12789
- return ptySyscall(req, { pid: this.pid, fds: this.fds, ptys, jobs, guard: guard2, owner });
12849
+ const { ttyFilter } = this.options;
12850
+ const ctx = { pid: this.pid, fds: this.fds, ptys, jobs, guard: guard2, owner, ttyFilter };
12851
+ return ptySyscall(req, ctx);
12790
12852
  }
12791
12853
  return await this.procSyscall(req, cancelled);
12792
12854
  } catch (e) {
@@ -12961,7 +13023,8 @@ var WasmProcess = class {
12961
13023
  const tty = name2 === void 0 ? this.controllingTerminal() : this.options.jobs?.terminalNamed(name2);
12962
13024
  if (!tty) throw new KernelError("ENXIO");
12963
13025
  if (name2 !== void 0) ttyOpenable(this.guarded(), tty);
12964
- return this.fds.install(tty.file(), 3);
13026
+ const file = tty.file();
13027
+ return this.fds.install(this.options.ttyFilter?.(file) ?? file, 3);
12965
13028
  }
12966
13029
  openSealed() {
12967
13030
  const broker = this.options.sealed;
@@ -13001,15 +13064,8 @@ var WasmProcess = class {
13001
13064
  async sealedCaller() {
13002
13065
  const shown = await this.options.identity?.();
13003
13066
  const broker = this.options.sealed;
13004
- const tag = broker.tagOf(this.pid);
13005
- return {
13006
- pid: shown?.pid ?? this.pid,
13007
- ppid: shown?.ppid ?? 0,
13008
- uid: this.cred.euid,
13009
- gid: this.cred.egid,
13010
- ...tag !== void 0 ? { tag } : {},
13011
- users: broker.users
13012
- };
13067
+ const ids = { pid: shown?.pid ?? this.pid, ppid: shown?.ppid ?? 0 };
13068
+ return broker.stamp(ids, this.cred, broker.tagOf(this.pid));
13013
13069
  }
13014
13070
  guarded() {
13015
13071
  const { guard: guard2 } = this.options;
@@ -13517,13 +13573,13 @@ var WasmProcess = class {
13517
13573
  while (this.dlLock.depth > 0 && this.dlLock.owner !== owner) {
13518
13574
  if (this.dying) throw new KernelError("EINTR");
13519
13575
  const interrupt = this.interrupt.signal;
13520
- const gone = await new Promise((resolve) => {
13576
+ const gone = await new Promise((resolve2) => {
13521
13577
  const waiter = {
13522
13578
  owner,
13523
13579
  wake: (ended) => {
13524
13580
  this.dlLock.waiters.delete(waiter);
13525
13581
  interrupt.removeEventListener("abort", recheck);
13526
- resolve(ended);
13582
+ resolve2(ended);
13527
13583
  }
13528
13584
  };
13529
13585
  const recheck = () => waiter.wake(false);
@@ -13779,6 +13835,7 @@ function processOptions(opts, header3, hooks, created3) {
13779
13835
  ...inherited(opts),
13780
13836
  ...opts.owners ? { owners: true } : {},
13781
13837
  ...opts.sealed ? { sealed: opts.sealed } : {},
13838
+ ...opts.ttyFilter ? { ttyFilter: opts.ttyFilter } : {},
13782
13839
  ...opts.clipboard ? { clipboard: opts.clipboard, ...clipboardName(opts) } : {},
13783
13840
  ...opts.readonlyAt ? { readonlyAt: opts.readonlyAt } : {},
13784
13841
  ...opts.dac ? { guard: { dac: opts.dac, fs: opts.fs, created: created3 } } : {},
@@ -14273,6 +14330,523 @@ function replayingHops(inner, heldMs = HELD_MS) {
14273
14330
  };
14274
14331
  }
14275
14332
 
14333
+ // node_modules/@ai-ecoverse/slicc-scrub/dist/index.js
14334
+ var FRAGMENT = 16;
14335
+ var MIN_VALUE = 8;
14336
+ var MIN_BASE64 = 8;
14337
+ var encoder4 = new TextEncoder();
14338
+ var STD = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
14339
+ function utf82(text) {
14340
+ return encoder4.encode(text);
14341
+ }
14342
+ function base642(bytes, padded = true) {
14343
+ let out = "";
14344
+ for (let i = 0; i < bytes.length; i += 3) {
14345
+ const a = bytes[i];
14346
+ const b = i + 1 < bytes.length ? bytes[i + 1] : 0;
14347
+ const c = i + 2 < bytes.length ? bytes[i + 2] : 0;
14348
+ const triple = a << 16 | b << 8 | c;
14349
+ const left = bytes.length - i;
14350
+ out += STD[triple >> 18 & 63] + STD[triple >> 12 & 63];
14351
+ out += left > 1 ? STD[triple >> 6 & 63] : padded ? "=" : "";
14352
+ out += left > 2 ? STD[triple & 63] : padded ? "=" : "";
14353
+ }
14354
+ return out;
14355
+ }
14356
+ function urlSafe(text) {
14357
+ return text.replace(/\+/g, "-").replace(/\//g, "_");
14358
+ }
14359
+ function hex2(bytes) {
14360
+ let out = "";
14361
+ for (const byte of bytes) out += byte.toString(16).padStart(2, "0");
14362
+ return out;
14363
+ }
14364
+ function embedded(bytes, offset) {
14365
+ const shifted = new Uint8Array(offset + bytes.length);
14366
+ shifted.set(bytes, offset);
14367
+ const encoded = base642(shifted);
14368
+ const first = Math.ceil(8 * offset / 6);
14369
+ const last = Math.floor(8 * (offset + bytes.length) / 6);
14370
+ return encoded.slice(first, last);
14371
+ }
14372
+ function unicode(value, upper) {
14373
+ let out = "";
14374
+ for (let i = 0; i < value.length; i++) {
14375
+ const unit = value.charCodeAt(i);
14376
+ if (unit === 34) out += '\\"';
14377
+ else if (unit === 92) out += "\\\\";
14378
+ else if (unit < 32 || unit > 126) {
14379
+ const code = unit.toString(16).padStart(4, "0");
14380
+ out += `\\u${upper ? code.toUpperCase() : code}`;
14381
+ } else out += value[i];
14382
+ }
14383
+ return out;
14384
+ }
14385
+ function percent(value) {
14386
+ let component;
14387
+ try {
14388
+ component = encodeURIComponent(value);
14389
+ } catch {
14390
+ return [];
14391
+ }
14392
+ const lower = component.replace(/%[0-9A-F]{2}/g, (escape) => escape.toLowerCase());
14393
+ const plus = component.replace(/%20/g, "+");
14394
+ let form = "";
14395
+ for (const byte of utf82(value)) {
14396
+ const char = String.fromCharCode(byte);
14397
+ if (/[A-Za-z0-9*\-._]/.test(char)) form += char;
14398
+ else if (byte === 32) form += "+";
14399
+ else form += `%${byte.toString(16).toUpperCase().padStart(2, "0")}`;
14400
+ }
14401
+ return [component, lower, plus, form];
14402
+ }
14403
+ function html(value, apostrophe) {
14404
+ return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, apostrophe);
14405
+ }
14406
+ function encodings(bytes) {
14407
+ const standard = [base642(bytes), base642(bytes, false)];
14408
+ for (const offset of [0, 1, 2]) {
14409
+ const run2 = embedded(bytes, offset);
14410
+ if (run2.length >= MIN_BASE64) standard.push(run2);
14411
+ }
14412
+ return [...standard, ...standard.map(urlSafe)];
14413
+ }
14414
+ function shapes(value) {
14415
+ const raw = utf82(value);
14416
+ const seen = /* @__PURE__ */ new Set([value]);
14417
+ const out = [];
14418
+ if (raw.length < FRAGMENT) out.push({ bytes: raw, form: "raw" });
14419
+ for (let offset = 0; raw.length >= FRAGMENT && offset + FRAGMENT <= raw.length; offset++) {
14420
+ out.push({ bytes: raw.subarray(offset, offset + FRAGMENT), form: "fragment", offset });
14421
+ }
14422
+ const add = (text, form) => {
14423
+ if (seen.has(text)) return;
14424
+ seen.add(text);
14425
+ out.push({ bytes: utf82(text), form });
14426
+ };
14427
+ const json5 = JSON.stringify(value).slice(1, -1);
14428
+ for (const text of [
14429
+ json5,
14430
+ json5.replace(/\//g, "\\/"),
14431
+ unicode(value, false),
14432
+ unicode(value, true)
14433
+ ]) {
14434
+ add(text, "json");
14435
+ }
14436
+ for (const text of percent(value)) add(text, "percent");
14437
+ for (const text of [html(value, "&#39;"), html(value, "&#x27;")]) add(text, "html");
14438
+ for (const text of encodings(raw)) add(text, "base64");
14439
+ add(hex2(raw), "hex");
14440
+ add(hex2(raw).toUpperCase(), "hex");
14441
+ return out;
14442
+ }
14443
+ function wrappable(form) {
14444
+ return form === "base64" || form === "hex";
14445
+ }
14446
+ var Automaton = class {
14447
+ edges = /* @__PURE__ */ new Map();
14448
+ fail = [0];
14449
+ depth = [0];
14450
+ children = [0];
14451
+ out = [[]];
14452
+ dict = [-1];
14453
+ lengths = [];
14454
+ add(bytes) {
14455
+ let node = 0;
14456
+ for (const byte of bytes) {
14457
+ const key = node * 256 + byte;
14458
+ let next2 = this.edges.get(key);
14459
+ if (next2 === void 0) {
14460
+ next2 = this.depth.length;
14461
+ this.edges.set(key, next2);
14462
+ this.fail.push(0);
14463
+ this.depth.push(this.depth[node] + 1);
14464
+ this.children.push(0);
14465
+ this.children[node] += 1;
14466
+ this.out.push([]);
14467
+ this.dict.push(-1);
14468
+ }
14469
+ node = next2;
14470
+ }
14471
+ const id2 = this.lengths.length;
14472
+ this.lengths.push(bytes.length);
14473
+ this.out[node].push(id2);
14474
+ return id2;
14475
+ }
14476
+ build() {
14477
+ const queue = [];
14478
+ const byNode = /* @__PURE__ */ new Map();
14479
+ for (const [key, child] of this.edges) {
14480
+ const parent = Math.floor(key / 256);
14481
+ const list = byNode.get(parent) ?? [];
14482
+ list.push([key % 256, child]);
14483
+ byNode.set(parent, list);
14484
+ }
14485
+ for (const [, child] of byNode.get(0) ?? []) queue.push(child);
14486
+ for (let head = 0; head < queue.length; head++) {
14487
+ const node = queue[head];
14488
+ const fallback = this.fail[node];
14489
+ this.dict[node] = this.out[fallback].length > 0 ? fallback : this.dict[fallback];
14490
+ for (const [byte, child] of byNode.get(node) ?? []) {
14491
+ let state = fallback;
14492
+ let target = this.edges.get(state * 256 + byte);
14493
+ while (target === void 0 && state > 0) {
14494
+ state = this.fail[state];
14495
+ target = this.edges.get(state * 256 + byte);
14496
+ }
14497
+ this.fail[child] = target ?? 0;
14498
+ queue.push(child);
14499
+ }
14500
+ }
14501
+ }
14502
+ step(state, byte) {
14503
+ let current = state;
14504
+ for (; ; ) {
14505
+ const next2 = this.edges.get(current * 256 + byte);
14506
+ if (next2 !== void 0) return next2;
14507
+ if (current === 0) return 0;
14508
+ current = this.fail[current];
14509
+ }
14510
+ }
14511
+ matches(state, visit) {
14512
+ for (let node = state; node > 0; node = this.dict[node]) {
14513
+ for (const id2 of this.out[node]) visit(id2);
14514
+ }
14515
+ }
14516
+ partials(state, length2, visit) {
14517
+ for (let node = state; node > 0; node = this.fail[node]) {
14518
+ if (this.children[node] > 0) visit(length2 - this.depth[node]);
14519
+ }
14520
+ }
14521
+ };
14522
+ var RANK = {
14523
+ raw: 0,
14524
+ fragment: 1,
14525
+ json: 2,
14526
+ percent: 3,
14527
+ html: 4,
14528
+ base64: 5,
14529
+ hex: 6,
14530
+ wrapped: 7
14531
+ };
14532
+ var CR2 = 13;
14533
+ var LF2 = 10;
14534
+ var EMPTY2 = new Uint8Array(0);
14535
+ function register(automaton, sources, ids, bytes, source) {
14536
+ const key = Array.from(bytes).join(",");
14537
+ let id2 = ids.get(key);
14538
+ if (id2 === void 0) {
14539
+ id2 = automaton.add(bytes);
14540
+ ids.set(key, id2);
14541
+ sources[id2] = [];
14542
+ }
14543
+ sources[id2].push(source);
14544
+ }
14545
+ function prepare(secrets) {
14546
+ const main = new Automaton();
14547
+ const wrap = new Automaton();
14548
+ const sources = [];
14549
+ const wrapSources = [];
14550
+ const ids = /* @__PURE__ */ new Map();
14551
+ const wrapIds = /* @__PURE__ */ new Map();
14552
+ const values = secrets.map((secret) => utf82(secret.value));
14553
+ secrets.forEach((secret, index) => {
14554
+ if (typeof secret.value !== "string" || values[index].length < MIN_VALUE) {
14555
+ throw new RangeError(`the value of ${secret.name} is shorter than ${MIN_VALUE} bytes`);
14556
+ }
14557
+ for (const shape of shapes(secret.value)) {
14558
+ const source = { secret: index, form: shape.form, offset: shape.offset };
14559
+ register(main, sources, ids, shape.bytes, source);
14560
+ if (wrappable(shape.form)) register(wrap, wrapSources, wrapIds, shape.bytes, source);
14561
+ }
14562
+ });
14563
+ main.build();
14564
+ wrap.build();
14565
+ const replacements = secrets.map((secret) => [
14566
+ utf82(secret.placeholder),
14567
+ utf82(`[redacted:${secret.name}]`)
14568
+ ]);
14569
+ return { secrets, values, main, wrap, sources, wrapSources, replacements };
14570
+ }
14571
+ function better(a, b) {
14572
+ if (!b) return true;
14573
+ if (a.end !== b.end) return a.end > b.end;
14574
+ if (a.rank !== b.rank) return a.rank < b.rank;
14575
+ return a.secret < b.secret;
14576
+ }
14577
+ function resolve(c, input, start2, end, source) {
14578
+ if (source.form !== "fragment") {
14579
+ return {
14580
+ start: start2,
14581
+ end,
14582
+ secret: source.secret,
14583
+ form: source.form,
14584
+ rank: RANK[source.form],
14585
+ growing: false
14586
+ };
14587
+ }
14588
+ const value = c.values[source.secret];
14589
+ let stop = end;
14590
+ let at = source.offset + FRAGMENT;
14591
+ while (stop < input.length && at < value.length && input[stop] === value[at]) {
14592
+ stop++;
14593
+ at++;
14594
+ }
14595
+ const form = source.offset === 0 && at === value.length ? "raw" : "fragment";
14596
+ const growing = stop === input.length && at < value.length;
14597
+ return { start: start2, end: stop, secret: source.secret, form, rank: RANK[form], growing };
14598
+ }
14599
+ function keep(best, candidate) {
14600
+ if (better(candidate, best.get(candidate.start))) best.set(candidate.start, candidate);
14601
+ }
14602
+ function scanMain(c, input, best, partials) {
14603
+ let state = 0;
14604
+ for (let i = 0; i < input.length; i++) {
14605
+ state = c.main.step(state, input[i]);
14606
+ c.main.matches(state, (id2) => {
14607
+ const start2 = i + 1 - c.main.lengths[id2];
14608
+ for (const source of c.sources[id2]) {
14609
+ const candidate = resolve(c, input, start2, i + 1, source);
14610
+ if (candidate.growing) partials.push(candidate.start);
14611
+ keep(best, candidate);
14612
+ }
14613
+ });
14614
+ }
14615
+ c.main.partials(state, input.length, (start2) => partials.push(start2));
14616
+ }
14617
+ function scanWrapped(c, input, best, partials) {
14618
+ const map = [];
14619
+ for (let i = 0; i < input.length; i++) if (input[i] !== CR2 && input[i] !== LF2) map.push(i);
14620
+ if (map.length === input.length) return;
14621
+ let state = 0;
14622
+ for (let v = 0; v < map.length; v++) {
14623
+ state = c.wrap.step(state, input[map[v]]);
14624
+ c.wrap.matches(state, (id2) => {
14625
+ const first = v + 1 - c.wrap.lengths[id2];
14626
+ const start2 = map[first];
14627
+ const end = map[v] + 1;
14628
+ const wrapped = end - start2 !== c.wrap.lengths[id2];
14629
+ for (const source of c.wrapSources[id2]) {
14630
+ const form = wrapped ? "wrapped" : source.form;
14631
+ keep(best, { start: start2, end, secret: source.secret, form, rank: RANK[form], growing: false });
14632
+ }
14633
+ });
14634
+ }
14635
+ c.wrap.partials(state, map.length, (start2) => partials.push(map[start2]));
14636
+ }
14637
+ function count(c, hits, candidate) {
14638
+ const name2 = c.secrets[candidate.secret].name;
14639
+ const key = `${name2}\0${candidate.form}`;
14640
+ const hit = hits.get(key) ?? { name: name2, form: candidate.form, count: 0 };
14641
+ hit.count += 1;
14642
+ hits.set(key, hit);
14643
+ }
14644
+ function concat5(parts2) {
14645
+ let length2 = 0;
14646
+ for (const part of parts2) length2 += part.length;
14647
+ const out = new Uint8Array(length2);
14648
+ let at = 0;
14649
+ for (const part of parts2) {
14650
+ out.set(part, at);
14651
+ at += part.length;
14652
+ }
14653
+ return out;
14654
+ }
14655
+ function pass(c, input, final) {
14656
+ const best = /* @__PURE__ */ new Map();
14657
+ const partials = [];
14658
+ scanMain(c, input, best, partials);
14659
+ scanWrapped(c, input, best, partials);
14660
+ const holds = final ? [] : [...new Set(partials)].sort((a, b) => a - b);
14661
+ const starts = [...best.keys()].sort((a, b) => a - b);
14662
+ const parts2 = [];
14663
+ const hits = /* @__PURE__ */ new Map();
14664
+ let pos = 0;
14665
+ let cut = input.length;
14666
+ let s = 0;
14667
+ let h = 0;
14668
+ for (; ; ) {
14669
+ while (s < starts.length && starts[s] < pos) s++;
14670
+ while (h < holds.length && holds[h] < pos) h++;
14671
+ const hold = h < holds.length ? holds[h] : Infinity;
14672
+ const next2 = s < starts.length ? starts[s] : Infinity;
14673
+ if (hold <= next2) {
14674
+ cut = Math.min(hold, input.length);
14675
+ break;
14676
+ }
14677
+ const candidate = best.get(next2);
14678
+ parts2.push(
14679
+ input.subarray(pos, next2),
14680
+ c.replacements[candidate.secret][candidate.form === "raw" ? 0 : 1]
14681
+ );
14682
+ count(c, hits, candidate);
14683
+ pos = candidate.end;
14684
+ }
14685
+ parts2.push(input.subarray(pos, cut));
14686
+ return { output: concat5(parts2), cut, hits };
14687
+ }
14688
+ function merge(into, from) {
14689
+ for (const [key, hit] of from) {
14690
+ const known = into.get(key);
14691
+ if (known) known.count += hit.count;
14692
+ else into.set(key, { ...hit });
14693
+ }
14694
+ }
14695
+ function compile(secrets, options = {}) {
14696
+ const c = prepare(secrets.map((secret) => ({ ...secret })));
14697
+ const decoder4 = new TextDecoder();
14698
+ const idleMs = options.idleMs ?? 250;
14699
+ const scrubBytes = (input) => {
14700
+ if (c.secrets.length === 0) return { bytes: input.slice(), hits: [] };
14701
+ const result = pass(c, input, true);
14702
+ return { bytes: result.output, hits: [...result.hits.values()] };
14703
+ };
14704
+ return {
14705
+ version: options.version ?? 0,
14706
+ idleMs,
14707
+ size: c.main.lengths.length,
14708
+ bytes: scrubBytes,
14709
+ text(input) {
14710
+ const { bytes, hits } = scrubBytes(utf82(input));
14711
+ return { text: decoder4.decode(bytes), hits };
14712
+ },
14713
+ stream() {
14714
+ let pending = EMPTY2;
14715
+ const hits = /* @__PURE__ */ new Map();
14716
+ const run2 = (final) => {
14717
+ if (c.secrets.length === 0 || pending.length === 0) {
14718
+ const out = pending;
14719
+ pending = EMPTY2;
14720
+ return out;
14721
+ }
14722
+ const result = pass(c, pending, final);
14723
+ merge(hits, result.hits);
14724
+ pending = pending.slice(result.cut);
14725
+ return result.output;
14726
+ };
14727
+ return {
14728
+ push(chunk2) {
14729
+ pending = concat5([pending, chunk2]);
14730
+ return run2(false);
14731
+ },
14732
+ idle() {
14733
+ return pending.length < FRAGMENT ? run2(true) : EMPTY2;
14734
+ },
14735
+ end() {
14736
+ return run2(true);
14737
+ },
14738
+ get hits() {
14739
+ return [...hits.values()];
14740
+ }
14741
+ };
14742
+ }
14743
+ };
14744
+ }
14745
+
14746
+ // src/kernel/scrub-file.ts
14747
+ var SCRUB_IDLE_MS = 50;
14748
+ var encoder5 = new TextEncoder();
14749
+ function scrubberOf(secrets) {
14750
+ const usable = secrets.filter((s) => encoder5.encode(s.value).length >= MIN_VALUE);
14751
+ return usable.length > 0 ? compile(usable, { idleMs: SCRUB_IDLE_MS }) : void 0;
14752
+ }
14753
+ async function writeAll2(file, bytes, signal) {
14754
+ const write = file.write;
14755
+ for (let at = 0; at < bytes.length; ) {
14756
+ at += await write.call(file, bytes.subarray(at), at === 0 ? signal : void 0);
14757
+ }
14758
+ }
14759
+ function bound(file, key) {
14760
+ const method = file[key];
14761
+ return typeof method === "function" ? { [key]: method.bind(file) } : {};
14762
+ }
14763
+ function scrubbed(inner, scrubber, idleMs = SCRUB_IDLE_MS) {
14764
+ const file = inner.file;
14765
+ const stream = scrubber.stream();
14766
+ let queue = Promise.resolve();
14767
+ let timer;
14768
+ let failed3;
14769
+ const raise = () => {
14770
+ if (failed3 === void 0) return;
14771
+ const err = failed3;
14772
+ failed3 = void 0;
14773
+ throw err;
14774
+ };
14775
+ const enqueue = (bytes, signal) => {
14776
+ const next2 = queue.then(() => bytes.length > 0 ? writeAll2(file, bytes, signal) : void 0);
14777
+ queue = next2.catch(() => void 0);
14778
+ return next2;
14779
+ };
14780
+ const release = () => {
14781
+ timer = void 0;
14782
+ enqueue(stream.idle()).catch((err) => {
14783
+ failed3 = err;
14784
+ });
14785
+ };
14786
+ return new OpenFile({
14787
+ ...bound(file, "read"),
14788
+ ...bound(file, "peek"),
14789
+ ...bound(file, "poll"),
14790
+ ...bound(file, "changed"),
14791
+ ...bound(file, "stat"),
14792
+ ...file.tty ? { tty: file.tty } : {},
14793
+ ...file.clipboard ? { clipboard: file.clipboard } : {},
14794
+ ...file.write ? {
14795
+ write: async (bytes, signal) => {
14796
+ if (timer !== void 0) clearTimeout(timer);
14797
+ raise();
14798
+ await enqueue(stream.push(bytes), signal);
14799
+ timer = setTimeout(release, idleMs);
14800
+ return bytes.length;
14801
+ }
14802
+ } : {},
14803
+ flush: async () => {
14804
+ await queue;
14805
+ raise();
14806
+ await file.flush?.();
14807
+ },
14808
+ close: async () => {
14809
+ if (timer !== void 0) clearTimeout(timer);
14810
+ let failure2;
14811
+ try {
14812
+ await enqueue(stream.end());
14813
+ raise();
14814
+ } catch (err) {
14815
+ failure2 = { err };
14816
+ }
14817
+ await inner.release();
14818
+ if (failure2) throw failure2.err;
14819
+ }
14820
+ });
14821
+ }
14822
+ function scrubbedAll(file, scrubbers) {
14823
+ return scrubbers.reduce((inner, scrubber) => scrubbed(inner, scrubber), file);
14824
+ }
14825
+ function stdioFiles(fds) {
14826
+ const files = /* @__PURE__ */ new Set();
14827
+ for (const fd of [1, 2]) {
14828
+ try {
14829
+ files.add(fds.get(fd));
14830
+ } catch {
14831
+ }
14832
+ }
14833
+ return files;
14834
+ }
14835
+ function scrubStdio(fds, scrubber) {
14836
+ const wrapped = /* @__PURE__ */ new Map();
14837
+ const stdio = stdioFiles(fds);
14838
+ for (const fd of fds.numbers()) {
14839
+ const original = fds.get(fd);
14840
+ if (!stdio.has(original) && !original.file.tty) continue;
14841
+ const known = wrapped.get(original);
14842
+ const flags2 = fds.statusFlags(fd);
14843
+ const wrapper = known ? known.retain() : scrubbed(original.retain(), scrubber);
14844
+ wrapped.set(original, wrapper);
14845
+ fds.installAt(fd, wrapper);
14846
+ if (flags2 !== void 0) fds.setStatusFlags(fd, flags2);
14847
+ }
14848
+ }
14849
+
14276
14850
  // src/kernel/sealed.ts
14277
14851
  var SEALED_MAX_BYTES = 64 * 1024;
14278
14852
  var SEALED_TIMEOUT_MS = 1e4;
@@ -14286,7 +14860,7 @@ var SEALED_OPS = /* @__PURE__ */ new Set([
14286
14860
  "cancel",
14287
14861
  "materialize"
14288
14862
  ]);
14289
- var encoder4 = new TextEncoder();
14863
+ var encoder6 = new TextEncoder();
14290
14864
  var decoder3 = new TextDecoder("utf-8", { fatal: true });
14291
14865
  function parseSealed(bytes) {
14292
14866
  try {
@@ -14302,11 +14876,16 @@ function parseSealed(bytes) {
14302
14876
  const req = parsed2;
14303
14877
  if (req.v !== 1 || typeof req.op !== "string" || !SEALED_OPS.has(req.op))
14304
14878
  throw new KernelError("EINVAL");
14879
+ if (req.op === "materialize" && !materializable(req)) throw new KernelError("EINVAL");
14305
14880
  return req;
14306
14881
  } finally {
14307
14882
  bytes.fill(0);
14308
14883
  }
14309
14884
  }
14885
+ function materializable(req) {
14886
+ if (req.shellGrants !== true && !isStrings(req.names)) return false;
14887
+ return isStrings(req.argv) && typeof req.path === "string" && typeof req.cwd === "string";
14888
+ }
14310
14889
  function errorReply(code, message3) {
14311
14890
  return { v: 1, error: { code, message: message3 } };
14312
14891
  }
@@ -14350,12 +14929,14 @@ var SealedChannel = class {
14350
14929
  const timer = setTimeout(() => control.abort("timeout"), this.broker.timeoutMs);
14351
14930
  const req = { ...fields, v: 1, op: fields.op, caller };
14352
14931
  const flight = { control, done: Promise.resolve() };
14353
- flight.done = this.answer(req, control.signal).then((reply) => {
14932
+ flight.done = this.answer(req, control.signal).then(async (reply) => {
14354
14933
  clearTimeout(timer);
14355
14934
  gone.removeEventListener("abort", withdraw);
14935
+ if (reply && req.op === "materialize")
14936
+ await this.broker.tickets.record(req, reply, caller.pid);
14356
14937
  if (this.inflight !== flight) return;
14357
14938
  this.inflight = void 0;
14358
- if (reply) this.reply = encoder4.encode(serialized(reply));
14939
+ if (reply) this.reply = encoder6.encode(serialized(reply));
14359
14940
  });
14360
14941
  this.inflight = flight;
14361
14942
  return length2;
@@ -14363,8 +14944,8 @@ var SealedChannel = class {
14363
14944
  async answer(req, signal) {
14364
14945
  const hook = this.broker.hook;
14365
14946
  if (!hook) return errorReply("ENOTCONN", "no vault is connected");
14366
- const stopped = new Promise((resolve) => {
14367
- signal.addEventListener("abort", () => resolve(void 0), { once: true });
14947
+ const stopped = new Promise((resolve2) => {
14948
+ signal.addEventListener("abort", () => resolve2(void 0), { once: true });
14368
14949
  });
14369
14950
  if (signal.aborted) return void 0;
14370
14951
  const asked = Promise.resolve().then(() => hook(req, { signal })).then(
@@ -14419,17 +15000,60 @@ var SealedChannel = class {
14419
15000
  this.reply = void 0;
14420
15001
  }
14421
15002
  };
15003
+ function swapOf(reply) {
15004
+ if (!isRecord(reply) || reply.error !== void 0) return void 0;
15005
+ const values = stringRecord(reply.values);
15006
+ const placeholders = stringRecord(reply.placeholders);
15007
+ return values && placeholders ? { values, placeholders } : void 0;
15008
+ }
14422
15009
  var SealedBroker = class {
14423
15010
  hook;
14424
15011
  users;
14425
15012
  timeoutMs;
14426
15013
  tagOf;
15014
+ tickets = new TicketBook();
15015
+ userOf = async () => void 0;
14427
15016
  constructor(hook, users, timeoutMs = SEALED_TIMEOUT_MS, tagOf = () => void 0) {
14428
15017
  this.hook = hook;
14429
15018
  this.users = users;
14430
15019
  this.timeoutMs = timeoutMs;
14431
15020
  this.tagOf = tagOf;
14432
15021
  }
15022
+ async stamp(ids, cred, tag) {
15023
+ const user = await this.userOf(cred.euid).catch(() => void 0);
15024
+ return {
15025
+ pid: ids.pid,
15026
+ ppid: ids.ppid,
15027
+ uid: cred.euid,
15028
+ gid: cred.egid,
15029
+ ...user !== void 0 ? { user } : {},
15030
+ groups: [...cred.groups],
15031
+ users: this.users,
15032
+ ...tag !== void 0 ? { tag } : {}
15033
+ };
15034
+ }
15035
+ async consume(fields) {
15036
+ const { hook } = this;
15037
+ if (!hook) return void 0;
15038
+ const control = new AbortController();
15039
+ const timer = setTimeout(() => control.abort("timeout"), this.timeoutMs);
15040
+ const stopped = new Promise((resolve2) => {
15041
+ control.signal.addEventListener("abort", () => resolve2(void 0), { once: true });
15042
+ });
15043
+ const req = {
15044
+ ...fields,
15045
+ v: 1,
15046
+ op: "materializeConsume",
15047
+ caller: fields.stamp
15048
+ };
15049
+ try {
15050
+ const asked = Promise.resolve().then(() => hook(req, { signal: control.signal })).then(swapOf, () => void 0);
15051
+ return await Promise.race([asked, stopped]);
15052
+ } finally {
15053
+ clearTimeout(timer);
15054
+ control.abort("done");
15055
+ }
15056
+ }
14433
15057
  open() {
14434
15058
  const channel = new SealedChannel(this);
14435
15059
  return new OpenFile({
@@ -14928,11 +15552,11 @@ function codeOf3(err) {
14928
15552
  }
14929
15553
  function wait(ms, signal) {
14930
15554
  if (signal.aborted) return Promise.resolve();
14931
- return new Promise((resolve) => {
15555
+ return new Promise((resolve2) => {
14932
15556
  const done4 = () => {
14933
15557
  clearTimeout(timer);
14934
15558
  signal.removeEventListener("abort", done4);
14935
- resolve();
15559
+ resolve2();
14936
15560
  };
14937
15561
  const timer = setTimeout(done4, ms);
14938
15562
  signal.addEventListener("abort", done4, { once: true });
@@ -15259,11 +15883,11 @@ async function resize(h, path, size) {
15259
15883
  }
15260
15884
  }
15261
15885
  function sleep(ms, signal) {
15262
- return new Promise((resolve) => {
15886
+ return new Promise((resolve2) => {
15263
15887
  const done4 = () => {
15264
15888
  clearTimeout(timer);
15265
15889
  signal.removeEventListener("abort", done4);
15266
- resolve();
15890
+ resolve2();
15267
15891
  };
15268
15892
  const timer = setTimeout(done4, ms);
15269
15893
  signal.addEventListener("abort", done4);
@@ -15346,7 +15970,7 @@ var PORT_DEAD_MS = 1e4;
15346
15970
  var PORT_LINGER_MS = 1e3;
15347
15971
  function timed(transport, ms) {
15348
15972
  const inflight = /* @__PURE__ */ new Set();
15349
- const guard2 = (name2, run2, late, expire) => new Promise((resolve, reject) => {
15973
+ const guard2 = (name2, run2, late, expire) => new Promise((resolve2, reject) => {
15350
15974
  let expired = false;
15351
15975
  const running = run2();
15352
15976
  inflight.add(running);
@@ -15363,7 +15987,7 @@ function timed(transport, ms) {
15363
15987
  (value) => {
15364
15988
  clearTimeout(timer);
15365
15989
  if (expired) late?.(value);
15366
- resolve(value);
15990
+ resolve2(value);
15367
15991
  },
15368
15992
  (err) => {
15369
15993
  clearTimeout(timer);
@@ -15498,7 +16122,7 @@ var PortTransport = class {
15498
16122
  ask(message3, bytes = 0, transfer = []) {
15499
16123
  const id2 = ++this.next;
15500
16124
  if (this.dead) return Promise.reject(fsError2("ENOTCONN", this.dead));
15501
- return new Promise((resolve, reject) => {
16125
+ return new Promise((resolve2, reject) => {
15502
16126
  const timer = setTimeout(
15503
16127
  () => {
15504
16128
  this.waiting.delete(id2);
@@ -15512,7 +16136,7 @@ var PortTransport = class {
15512
16136
  clearTimeout(timer);
15513
16137
  this.waiting.delete(id2);
15514
16138
  if (reply.error) reject(fsError2(reply.error.code ?? "EIO", reply.error.message ?? ""));
15515
- else resolve(reply);
16139
+ else resolve2(reply);
15516
16140
  });
15517
16141
  try {
15518
16142
  this.port.postMessage({ id: id2, ...message3 }, transfer);
@@ -15541,7 +16165,7 @@ var PortTransport = class {
15541
16165
  this.fail("the folder's watch ended");
15542
16166
  return Promise.resolve();
15543
16167
  }
15544
- return new Promise((resolve, reject) => {
16168
+ return new Promise((resolve2, reject) => {
15545
16169
  const finish = () => {
15546
16170
  this.waiting.delete(id2);
15547
16171
  signal.removeEventListener("abort", stop);
@@ -15552,7 +16176,7 @@ var PortTransport = class {
15552
16176
  this.port.postMessage({ id: id2, op: "unwatch" });
15553
16177
  } catch {
15554
16178
  }
15555
- resolve();
16179
+ resolve2();
15556
16180
  };
15557
16181
  this.watchBeat();
15558
16182
  this.waiting.set(id2, (reply) => {
@@ -15560,7 +16184,7 @@ var PortTransport = class {
15560
16184
  if (reply.event) return onEvent(reply.event);
15561
16185
  finish();
15562
16186
  if (reply.error) reject(fsError2(reply.error.code ?? "ENOTCONN", reply.error.message ?? ""));
15563
- else resolve();
16187
+ else resolve2();
15564
16188
  });
15565
16189
  signal.addEventListener("abort", stop, { once: true });
15566
16190
  try {
@@ -15673,10 +16297,10 @@ var ChunkedBytes = class {
15673
16297
  }
15674
16298
  truncate(size) {
15675
16299
  if (size < this.size) {
15676
- const keep = Math.ceil(size / CHUNK3);
15677
- this.chunks.length = Math.min(this.chunks.length, keep);
15678
- const tail = this.chunks[keep - 1];
15679
- const from = size - (keep - 1) * CHUNK3;
16300
+ const keep2 = Math.ceil(size / CHUNK3);
16301
+ this.chunks.length = Math.min(this.chunks.length, keep2);
16302
+ const tail = this.chunks[keep2 - 1];
16303
+ const from = size - (keep2 - 1) * CHUNK3;
15680
16304
  if (tail && from < tail.length) tail.fill(0, from);
15681
16305
  }
15682
16306
  this.size = size;
@@ -15921,8 +16545,8 @@ function importedMemory(bytes) {
15921
16545
  at = end;
15922
16546
  continue;
15923
16547
  }
15924
- const count = u32();
15925
- for (let i = 0; i < count; i++) {
16548
+ const count2 = u32();
16549
+ for (let i = 0; i < count2; i++) {
15926
16550
  const module = name2();
15927
16551
  const field3 = name2();
15928
16552
  const kind = bytes[at++];
@@ -16351,7 +16975,7 @@ ${lines2}
16351
16975
  const withdraw = () => control.abort("withdrawn");
16352
16976
  requester.addEventListener("abort", withdraw, { once: true });
16353
16977
  const aborted2 = new Promise(
16354
- (resolve) => control.signal.addEventListener("abort", () => resolve("aborted"), { once: true })
16978
+ (resolve2) => control.signal.addEventListener("abort", () => resolve2("aborted"), { once: true })
16355
16979
  );
16356
16980
  try {
16357
16981
  const answered2 = Promise.resolve().then(() => approve(req, { signal: control.signal })).catch(() => "deny");
@@ -16477,7 +17101,7 @@ var LAYOUT = [
16477
17101
  ];
16478
17102
  var LOAD_SAMPLE_MS = 5e3;
16479
17103
  var LOAD_WINDOWS_MS = [6e4, 3e5, 9e5];
16480
- var encoder5 = new TextEncoder();
17104
+ var encoder7 = new TextEncoder();
16481
17105
  var USERS_MODES = ["off", "report", "enforce"];
16482
17106
  function usersMode(mode = "off") {
16483
17107
  if (USERS_MODES.includes(mode)) return mode;
@@ -16508,6 +17132,30 @@ function shebang(head) {
16508
17132
  if (head[0] !== 35 || head[1] !== 33) return void 0;
16509
17133
  return new TextDecoder().decode(head.subarray(0, SHEBANG_MAX)).slice(2).split("\n")[0].trim().split(/[ \t]+/);
16510
17134
  }
17135
+ async function rootOnly(fs, path) {
17136
+ const names = chain(path);
17137
+ for (const [i, at] of names.entries()) {
17138
+ const st = await fs.lstat(at).catch(() => void 0);
17139
+ const kind = i === names.length - 1 ? st?.isFile : st?.isDirectory;
17140
+ if (!kind || st?.uid !== 0 || (st.mode & 18) !== 0) return false;
17141
+ }
17142
+ return true;
17143
+ }
17144
+ function plainEnv(words2) {
17145
+ const next2 = words2[1];
17146
+ if (baseName(words2[0] ?? "") !== "env" || next2 === void 0) return false;
17147
+ return next2 === "-S" || !next2.startsWith("-") && !next2.includes("=");
17148
+ }
17149
+ function shebangCommand(words2) {
17150
+ if (!plainEnv(words2)) {
17151
+ const arg2 = words2.slice(1).join(" ");
17152
+ return { interp: words2[0], args: arg2 ? [arg2] : [] };
17153
+ }
17154
+ const split2 = words2[1] === "-S";
17155
+ const [interp, ...rest2] = words2.slice(split2 ? 2 : 1);
17156
+ const arg = rest2.join(" ");
17157
+ return { interp, args: split2 ? rest2 : arg ? [arg] : [] };
17158
+ }
16511
17159
  function interpreter(head) {
16512
17160
  const words2 = shebang(head);
16513
17161
  if (!words2) return "node";
@@ -16561,7 +17209,7 @@ function childHandle(handle) {
16561
17209
  onState: (listener) => handle.onState(listener)
16562
17210
  };
16563
17211
  }
16564
- function concat5(chunks) {
17212
+ function concat6(chunks) {
16565
17213
  const out = new Uint8Array(chunks.reduce((n, chunk2) => n + chunk2.length, 0));
16566
17214
  let offset = 0;
16567
17215
  for (const chunk2 of chunks) {
@@ -16647,6 +17295,7 @@ var Launcher = class {
16647
17295
  usersMode;
16648
17296
  dac;
16649
17297
  sealed;
17298
+ scrubs = /* @__PURE__ */ new Map();
16650
17299
  clipboard;
16651
17300
  rootFs;
16652
17301
  fileWatches;
@@ -16670,6 +17319,8 @@ var Launcher = class {
16670
17319
  void 0,
16671
17320
  (pid) => this.tagOf(pid)
16672
17321
  );
17322
+ this.sealed.tickets.normalise = (path) => physicalPathAsync(this.base, path);
17323
+ this.sealed.userOf = async (uid) => (await this.users.lookup(uid))?.name;
16673
17324
  if (this.owners) options.fs.trackOwners?.();
16674
17325
  this.mounts = new MountTable({
16675
17326
  open: (type, spec) => this.driver(type, spec),
@@ -16918,13 +17569,12 @@ var Launcher = class {
16918
17569
  const binfmt = isWasm(head) ? void 0 : binfmtOf(await this.interpreters(scope), script);
16919
17570
  const words2 = shebang(head) ?? (binfmt ? [binfmt] : void 0);
16920
17571
  if (!words2) return void 0;
16921
- if (baseName(words2[0]) === "env") words2.shift();
16922
- const [interp, ...rest2] = words2;
16923
- const arg = rest2.join(" ");
16924
- const passed = [...arg ? [arg] : [], command ? script : file, ...argv.slice(1)];
16925
- const found = interp ? await this.resolve(interp, interp, cwd, scope) : void 0;
17572
+ const { interp, args } = shebangCommand(words2);
17573
+ const passed = [...args, command ? script : file, ...argv.slice(1)];
17574
+ if (!interp) return void 0;
17575
+ const found = await this.resolve(interp, interp, cwd, scope);
16926
17576
  if (!found) {
16927
- if (!interp || depth >= MAX_INTERPRETERS || !await this.scriptCommand(interp, cwd, scope)) {
17577
+ if (depth >= MAX_INTERPRETERS || !await this.scriptCommand(interp, cwd, scope)) {
16928
17578
  return void 0;
16929
17579
  }
16930
17580
  const inner = await this.interpreted(interp, [interp, ...passed], cwd, scope, depth + 1);
@@ -16964,6 +17614,99 @@ var Launcher = class {
16964
17614
  await need(g, "exec", this.fs.resolvePath(req.cwd, file), want);
16965
17615
  }
16966
17616
  }
17617
+ async checkedPlan(req, { ppid, cred, scope }, fds) {
17618
+ const planned = await this.plan(req.file, req.argv, req.cwd, scope, req.argv0);
17619
+ try {
17620
+ await this.mayExec(cred, { ...req, pid: ppid }, planned);
17621
+ } catch (err) {
17622
+ await fds.closeAll();
17623
+ throw err.code === "EACCES" ? new SpawnError("EACCES") : err;
17624
+ }
17625
+ if (planned) return planned;
17626
+ await fds.closeAll();
17627
+ throw new SpawnError(await this.unrunnable(req.file, req.cwd, scope));
17628
+ }
17629
+ async ticketFile(req, fds) {
17630
+ if (req.file.startsWith("/")) return physicalPathAsync(this.base, req.file);
17631
+ await fds.closeAll();
17632
+ throw new SpawnError("EACCES");
17633
+ }
17634
+ takeTicket(req) {
17635
+ if (!(TICKET_ENV in req.env)) return void 0;
17636
+ return this.sealed.tickets.take(req.env[TICKET_ENV] ?? "") ?? null;
17637
+ }
17638
+ async redeemed(req, who, planned, fds) {
17639
+ if (who.booked === void 0) return { env: req.env };
17640
+ try {
17641
+ const redeemed = await this.redeem(req, who, planned);
17642
+ if (redeemed.scrub) scrubStdio(fds, redeemed.scrub);
17643
+ return redeemed;
17644
+ } catch {
17645
+ await fds.closeAll();
17646
+ throw new SpawnError("EACCES");
17647
+ }
17648
+ }
17649
+ async redeem(req, { ppid, cred, scope, booked }, planned) {
17650
+ const { [TICKET_ENV]: ticket = "", ...env } = req.env;
17651
+ const caller = this.jobs.shown(ppid);
17652
+ const named = typeof req.argv0 === "string" && !planned.script && !planned.target.fixed;
17653
+ const argv = named ? [req.argv0, ...req.argv.slice(1)] : req.argv;
17654
+ const exact = booked?.pid === caller && req.file === booked.path && await physicalPathAsync(this.base, req.cwd) === booked.cwd && await argvDigest(argv) === booked.argv;
17655
+ if (!exact) throw new SpawnError("EACCES");
17656
+ const { requested: path, requestedCwd: cwd, path: resolved2 } = booked;
17657
+ const pid = this.nextPid++;
17658
+ const ids = { pid: req.exec ? caller : pid, ppid: caller };
17659
+ const stamp = await this.sealed.stamp(ids, cred, this.tagOf(ppid));
17660
+ const interpreters = await this.interpreterChain(planned, booked.cwd, scope);
17661
+ const trusted = this.usersMode === "enforce" && await this.trustedFiles(planned, req.file, booked.cwd, scope);
17662
+ const swap = await this.sealed.consume({
17663
+ ticket,
17664
+ stamp,
17665
+ path,
17666
+ resolved: resolved2,
17667
+ argv,
17668
+ cwd,
17669
+ interpreters,
17670
+ trusted
17671
+ });
17672
+ if (!swap) throw new SpawnError("EACCES");
17673
+ const secrets = [];
17674
+ for (const [name2, placeholder] of Object.entries(swap.placeholders)) {
17675
+ const value = swap.values[name2];
17676
+ if (value === void 0 || env[name2] !== placeholder) continue;
17677
+ env[name2] = value;
17678
+ secrets.push({ name: name2, value, placeholder });
17679
+ }
17680
+ const scrub = scrubberOf(secrets);
17681
+ return { env, pid, cwd: booked.cwd, ...scrub ? { scrub } : {} };
17682
+ }
17683
+ async interpreterChain(planned, cwd, scope) {
17684
+ const out = [];
17685
+ for (const entry of planned.via ?? []) {
17686
+ if (entry.includes("/")) {
17687
+ out.push(await physicalPathAsync(this.base, this.fs.resolvePath(cwd, entry)));
17688
+ continue;
17689
+ }
17690
+ const script = (await this.scriptCommand(entry, cwd, scope))?.script;
17691
+ out.push(
17692
+ await physicalPathAsync(this.base, script ?? await this.commandFile(entry, cwd, scope))
17693
+ );
17694
+ }
17695
+ return out;
17696
+ }
17697
+ async commandFile(name2, cwd, scope) {
17698
+ const scoped = await this.resolve(name2, name2, cwd, scope);
17699
+ const system = scope === "" ? scoped : await this.resolve(name2, name2, cwd, "");
17700
+ if (!scoped || system?.glue === scoped.glue) return `/usr/bin/${name2}`;
17701
+ return scoped.glue;
17702
+ }
17703
+ async trustedFiles(planned, file, cwd, scope) {
17704
+ const files = await this.backingOf(planned, file, cwd, scope);
17705
+ for (const at of files) {
17706
+ if (!await rootOnly(this.base, await physicalPathAsync(this.base, at))) return false;
17707
+ }
17708
+ return true;
17709
+ }
16967
17710
  async grantedCwd(caller, cwd) {
16968
17711
  const real = await physicalPathAsync(this.base, cwd).catch(() => void 0);
16969
17712
  return real === cwd && await this.sudoer.reachable(caller, cwd);
@@ -16982,13 +17725,15 @@ var Launcher = class {
16982
17725
  }
16983
17726
  async backing(file, cwd) {
16984
17727
  const planned = await this.plan(file, [file], cwd, "");
16985
- if (!planned) return void 0;
17728
+ return planned && this.backingOf(planned, file, cwd, "");
17729
+ }
17730
+ async backingOf(planned, file, cwd, scope) {
16986
17731
  const { glue, wasm, imports } = planned.target;
16987
17732
  const files = [glue, wasm, ...imports ? [imports] : []];
16988
17733
  const scripts = [];
16989
17734
  for (const name2 of [file, ...planned.via ?? []]) {
16990
17735
  if (name2.includes("/") && !COMMAND2.test(name2)) scripts.push(this.fs.resolvePath(cwd, name2));
16991
- const script = (await this.scriptCommand(name2, cwd, ""))?.script;
17736
+ const script = (await this.scriptCommand(name2, cwd, scope))?.script;
16992
17737
  if (script) scripts.push(script);
16993
17738
  }
16994
17739
  files.push(...scripts, ...await this.binfmtManifests(scripts));
@@ -17117,6 +17862,7 @@ var Launcher = class {
17117
17862
  const seen = { ...req.env, HOSTNAME: this.hostname, cwd };
17118
17863
  const env = { ...expandDefaults(target.env, seen), ...req.env };
17119
17864
  for (const key of target.unset ?? []) delete env[key];
17865
+ delete env[TICKET_ENV];
17120
17866
  env.HOSTNAME = this.hostname;
17121
17867
  let program;
17122
17868
  try {
@@ -17132,16 +17878,23 @@ var Launcher = class {
17132
17878
  groupSession(pgid) {
17133
17879
  return this.jobs.sessionOf(pgid);
17134
17880
  }
17881
+ treeScrubs(pid, req) {
17882
+ const inherited2 = req.ppid !== void 0 ? this.scrubs.get(req.ppid) : void 0;
17883
+ const scrubs = req.scrub ? [...inherited2 ?? [], req.scrub] : inherited2;
17884
+ if (scrubs) this.scrubs.set(pid, scrubs);
17885
+ return scrubs;
17886
+ }
17135
17887
  start(req) {
17136
17888
  this.sampling();
17137
17889
  if (req.pgid !== void 0 && this.jobs.sessionOf(req.pgid) === void 0) {
17138
17890
  throw new SpawnError("ESRCH");
17139
17891
  }
17140
- const pid = this.nextPid++;
17892
+ const pid = req.pid ?? this.nextPid++;
17893
+ const scrubs = this.treeScrubs(pid, req);
17141
17894
  const stack = this.stackFor(req.tag);
17142
17895
  const terminal = req.fds.stdioTerminal();
17143
17896
  const decided = req.decided ?? Promise.resolve(true);
17144
- const count = (byParent) => {
17897
+ const count2 = (byParent) => {
17145
17898
  this.identities.asked++;
17146
17899
  if (!byParent) this.identities.timedOut++;
17147
17900
  };
@@ -17149,7 +17902,7 @@ var Launcher = class {
17149
17902
  const handle = spawnWasmProcess({
17150
17903
  pid,
17151
17904
  identity: async () => {
17152
- await (asked ??= decided.then(count));
17905
+ await (asked ??= decided.then(count2));
17153
17906
  return this.identityOf(pid);
17154
17907
  },
17155
17908
  onSyscall: (call) => {
@@ -17163,6 +17916,7 @@ var Launcher = class {
17163
17916
  ...this.owners && req.program.abi === "wasi" ? { fresh: (path, umask) => this.freshModules.add(path, umask, pid) } : {},
17164
17917
  ...this.owners ? { owners: true } : {},
17165
17918
  sealed: this.sealed,
17919
+ ...scrubs ? { ttyFilter: (file) => scrubbedAll(file, scrubs) } : {},
17166
17920
  clipboard: this.clipboard,
17167
17921
  ...this.dac ? { dac: this.dac } : {},
17168
17922
  program: req.program,
@@ -17229,6 +17983,7 @@ var Launcher = class {
17229
17983
  if (spent) addTimes(this.imageTimes, this.jobs.shown(pid), spent);
17230
17984
  this.stopped.delete(pid);
17231
17985
  this.processes.delete(pid);
17986
+ this.scrubs.delete(pid);
17232
17987
  if (this.processes.size === 0) {
17233
17988
  clearInterval(this.sampler);
17234
17989
  this.sampler = void 0;
@@ -17400,6 +18155,7 @@ var Launcher = class {
17400
18155
  }
17401
18156
  spawner(ppid, report) {
17402
18157
  return async (req, fds, grant) => {
18158
+ const booked = this.takeTicket(req);
17403
18159
  if (grant && !await this.grantedCwd(grant.caller, req.cwd)) {
17404
18160
  await fds.closeAll();
17405
18161
  throw new SpawnError("EACCES");
@@ -17411,23 +18167,20 @@ var Launcher = class {
17411
18167
  }
17412
18168
  const cred = grant ? grant.cred : this.credOf(ppid);
17413
18169
  const scope = grant ? "" : await this.scopeOf(cred.euid);
17414
- const planned = await this.plan(req.file, req.argv, req.cwd, scope, req.argv0);
17415
- try {
17416
- await this.mayExec(cred, { ...req, pid: ppid }, planned);
17417
- } catch (err) {
17418
- await fds.closeAll();
17419
- throw err.code === "EACCES" ? new SpawnError("EACCES") : err;
17420
- }
17421
- if (!planned) {
17422
- await fds.closeAll();
17423
- throw new SpawnError(await this.unrunnable(req.file, req.cwd, scope));
17424
- }
18170
+ const file = booked === void 0 ? req.file : await this.ticketFile(req, fds);
18171
+ const planned = await this.checkedPlan({ ...req, file }, { ppid, cred, scope }, fds);
18172
+ const redeemed = await this.redeemed(
18173
+ { ...req, file },
18174
+ { ppid, cred, scope, booked },
18175
+ planned,
18176
+ fds
18177
+ );
17425
18178
  const exec = req.exec ? { exec: true } : {};
17426
18179
  const deciding = req.exec ? void 0 : this.undecided(ppid);
17427
18180
  const handle = await this.launch(planned, {
17428
18181
  ...deciding ? { decided: deciding.promise } : {},
17429
- env: req.env,
17430
18182
  cwd: req.cwd,
18183
+ ...redeemed,
17431
18184
  fds,
17432
18185
  report,
17433
18186
  ppid,
@@ -17480,11 +18233,11 @@ var Launcher = class {
17480
18233
  if (!waiting) return;
17481
18234
  this.deciding.delete(ppid);
17482
18235
  setTimeout(() => {
17483
- for (const resolve of waiting) resolve(true);
18236
+ for (const resolve2 of waiting) resolve2(true);
17484
18237
  }, 0);
17485
18238
  }
17486
18239
  forker(ppid, parent) {
17487
- const { exec: _exec, pgid: _pgid, group: _group, ...image } = parent;
18240
+ const { exec: _exec, pgid: _pgid, group: _group, pid: _pid, scrub: _scrub, ...image } = parent;
17488
18241
  return async (state, fds) => childHandle(
17489
18242
  this.start({
17490
18243
  ...image,
@@ -17861,7 +18614,14 @@ var Launcher = class {
17861
18614
  );
17862
18615
  }
17863
18616
  environment(cwd, extra, account) {
17864
- return { ...this.env, ...userEnv(account, this.pnpmHome), PWD: cwd, ...extra };
18617
+ const env = {
18618
+ ...this.env,
18619
+ ...userEnv(account, this.pnpmHome),
18620
+ PWD: cwd,
18621
+ ...extra
18622
+ };
18623
+ delete env[TICKET_ENV];
18624
+ return env;
17865
18625
  }
17866
18626
  async account(user) {
17867
18627
  if (typeof user === "object") return user;
@@ -17957,7 +18717,7 @@ var Launcher = class {
17957
18717
  },
17958
18718
  account
17959
18719
  );
17960
- const report = (message3) => options.onData(encoder5.encode(`${message3}\r
18720
+ const report = (message3) => options.onData(encoder7.encode(`${message3}\r
17961
18721
  `));
17962
18722
  const handle = await this.launch(planned, {
17963
18723
  env,
@@ -17988,18 +18748,18 @@ var Launcher = class {
17988
18748
  const env = this.environment(cwd, options.env, account);
17989
18749
  const out = [];
17990
18750
  const err = [];
17991
- const keep = options.collect !== false;
18751
+ const keep2 = options.collect !== false;
17992
18752
  const collect = (chunks, tee) => (bytes) => {
17993
- if (keep) chunks.push(bytes);
18753
+ if (keep2) chunks.push(bytes);
17994
18754
  tee?.(bytes);
17995
18755
  };
17996
18756
  const stdout = collect(out, options.onStdout);
17997
18757
  const stderr = collect(err, options.onStderr);
17998
- const report = (message3) => stderr(encoder5.encode(`${message3}
18758
+ const report = (message3) => stderr(encoder7.encode(`${message3}
17999
18759
  `));
18000
18760
  if (!planned) {
18001
18761
  report(`${file}: command not found`);
18002
- return { status: NOT_FOUND, stdout: concat5(out), stderr: concat5(err) };
18762
+ return { status: NOT_FOUND, stdout: concat6(out), stderr: concat6(err) };
18003
18763
  }
18004
18764
  const fds = new FdTable();
18005
18765
  fds.installAt(0, options.stdin ? bytesSource(options.stdin) : deviceFile("null"));
@@ -18017,7 +18777,7 @@ var Launcher = class {
18017
18777
  options.onStarted?.(handle.pid);
18018
18778
  const status = await handle.exited;
18019
18779
  const signal = handle.termsig();
18020
- return { status, ...signal ? { signal } : {}, stdout: concat5(out), stderr: concat5(err) };
18780
+ return { status, ...signal ? { signal } : {}, stdout: concat6(out), stderr: concat6(err) };
18021
18781
  }
18022
18782
  };
18023
18783
 
@@ -18118,14 +18878,14 @@ function dial(l, req) {
18118
18878
  function sudoApprovals(port) {
18119
18879
  const waiting = /* @__PURE__ */ new Map();
18120
18880
  return {
18121
- ask: (req, { signal }) => new Promise((resolve) => {
18122
- waiting.set(req.id, resolve);
18881
+ ask: (req, { signal }) => new Promise((resolve2) => {
18882
+ waiting.set(req.id, resolve2);
18123
18883
  signal.addEventListener(
18124
18884
  "abort",
18125
18885
  () => {
18126
18886
  waiting.delete(req.id);
18127
18887
  port.postMessage({ sudoAbort: { id: req.id, reason: String(signal.reason) } });
18128
- resolve("deny");
18888
+ resolve2("deny");
18129
18889
  },
18130
18890
  { once: true }
18131
18891
  );
@@ -18209,9 +18969,9 @@ function hostProtect(init, lookup) {
18209
18969
  function policyAsker(port) {
18210
18970
  const policies = /* @__PURE__ */ new Map();
18211
18971
  let nextPolicy = 0;
18212
- const askPolicy = (req) => new Promise((resolve) => {
18972
+ const askPolicy = (req) => new Promise((resolve2) => {
18213
18973
  const id2 = ++nextPolicy;
18214
- policies.set(id2, resolve);
18974
+ policies.set(id2, resolve2);
18215
18975
  port.postMessage({ mountPolicy: { id: id2, req } });
18216
18976
  });
18217
18977
  return {
@@ -18239,10 +18999,10 @@ function serveKernel(port, deps) {
18239
18999
  const locks = deps.locks === null ? void 0 : deps.locks ?? locksOf();
18240
19000
  let holding;
18241
19001
  function holdLock(locks2) {
18242
- holding ??= new Promise((resolve) => {
19002
+ holding ??= new Promise((resolve2) => {
18243
19003
  const name2 = `slicc-kernel:${crypto.randomUUID()}`;
18244
19004
  void locks2.request(name2, () => {
18245
- resolve(name2);
19005
+ resolve2(name2);
18246
19006
  return new Promise(() => {
18247
19007
  });
18248
19008
  });