@ai-ecoverse/slicc-kernel 1.54.2 → 1.54.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/node.js CHANGED
@@ -329,6 +329,32 @@ function bytesSource(data) {
329
329
  }
330
330
  });
331
331
  }
332
+ function memoryFile(data, path, position = 0) {
333
+ let offset = position;
334
+ return new OpenFile({
335
+ read: async (max) => {
336
+ const out = data.subarray(offset, offset + max);
337
+ offset += out.length;
338
+ return out;
339
+ },
340
+ pread: async (max, at) => data.subarray(at, at + max),
341
+ seek: async (by, whence) => {
342
+ const at = (whence === 1 ? offset : whence === 2 ? data.length : 0) + by;
343
+ if (at < 0) throw new KernelError("EINVAL");
344
+ offset = at;
345
+ return at;
346
+ },
347
+ pwrite: async () => {
348
+ throw new KernelError("EBADF");
349
+ },
350
+ resize: async () => {
351
+ throw new KernelError("EBADF");
352
+ },
353
+ stat: async () => ({ path, size: data.length }),
354
+ close: () => {
355
+ }
356
+ });
357
+ }
332
358
  function sinkFile(onData) {
333
359
  return new OpenFile({
334
360
  write: async (bytes) => {
@@ -5866,179 +5892,6 @@ function attachSyncSabResponder(port, sab, token, opts) {
5866
5892
  };
5867
5893
  }
5868
5894
 
5869
- // src/kernel/host-ops.ts
5870
- var HOST_OPS = [
5871
- "lock",
5872
- "unlock",
5873
- "async-submit",
5874
- "async-wait",
5875
- "async-take",
5876
- "async-resolve",
5877
- "async-hold",
5878
- "async-cancel",
5879
- "async-close"
5880
- ];
5881
- var json3 = (value) => ({ ok: true, kind: "json", json: value });
5882
- var done2 = { ok: true, kind: "void" };
5883
- var LockTable = class {
5884
- held = /* @__PURE__ */ new Map();
5885
- lock(pid, path, exclusive, fd) {
5886
- const holders = this.held.get(path) ?? /* @__PURE__ */ new Map();
5887
- for (const [other, h] of holders) if (other !== pid && (exclusive || h.exclusive)) return false;
5888
- const mine = holders.get(pid) ?? { exclusive, fds: /* @__PURE__ */ new Set() };
5889
- mine.exclusive = exclusive;
5890
- mine.fds.add(fd);
5891
- holders.set(pid, mine);
5892
- this.held.set(path, holders);
5893
- return true;
5894
- }
5895
- unlock(pid, path) {
5896
- const holders = this.held.get(path);
5897
- holders?.delete(pid);
5898
- if (holders?.size === 0) this.held.delete(path);
5899
- }
5900
- closed(pid, fd) {
5901
- for (const [path, holders] of [...this.held]) {
5902
- const mine = holders.get(pid);
5903
- if (mine?.fds.delete(fd) && mine.fds.size === 0) this.unlock(pid, path);
5904
- }
5905
- }
5906
- release(pid) {
5907
- for (const path of [...this.held.keys()]) this.unlock(pid, path);
5908
- }
5909
- };
5910
- var AsyncOps = class {
5911
- next = 1;
5912
- results = /* @__PURE__ */ new Map();
5913
- ready = [];
5914
- running = /* @__PURE__ */ new Map();
5915
- waiters = /* @__PURE__ */ new Set();
5916
- closed = false;
5917
- run;
5918
- onReady;
5919
- constructor(run2, onReady) {
5920
- this.run = run2;
5921
- this.onReady = onReady;
5922
- }
5923
- submit(req) {
5924
- const id2 = this.hold();
5925
- const running = new AbortController();
5926
- this.running.set(id2, running);
5927
- this.run(req, running.signal).then(
5928
- (result) => this.complete(id2, result),
5929
- (err) => this.complete(id2, { ok: false, errno: "EIO", message: String(err) })
5930
- );
5931
- return id2;
5932
- }
5933
- resolve(value) {
5934
- const id2 = this.hold();
5935
- this.complete(id2, json3(value));
5936
- return id2;
5937
- }
5938
- hold() {
5939
- const id2 = this.next++;
5940
- this.results.set(id2, void 0);
5941
- return id2;
5942
- }
5943
- take(id2) {
5944
- if (!this.results.has(id2)) throw new KernelError("EINVAL");
5945
- const result = this.results.get(id2);
5946
- if (!result) throw new KernelError("EAGAIN");
5947
- this.forget(id2);
5948
- return result;
5949
- }
5950
- cancel(id2) {
5951
- this.running.get(id2)?.abort();
5952
- this.forget(id2);
5953
- }
5954
- forget(id2) {
5955
- this.running.delete(id2);
5956
- this.results.delete(id2);
5957
- const at = this.ready.indexOf(id2);
5958
- if (at >= 0) this.ready.splice(at, 1);
5959
- }
5960
- async wait(timeoutMs, signal) {
5961
- for (; ; ) {
5962
- if (this.closed) return -1;
5963
- const id2 = this.ready.shift();
5964
- if (id2 !== void 0) return id2;
5965
- if (timeoutMs !== void 0 && timeoutMs <= 0) return 0;
5966
- const woke = await this.sleep(timeoutMs, signal);
5967
- if (!woke) return 0;
5968
- }
5969
- }
5970
- close() {
5971
- this.closed = true;
5972
- this.wake();
5973
- }
5974
- sleep(timeoutMs, signal) {
5975
- return new Promise((resolve, reject) => {
5976
- let timer;
5977
- const cleanup = () => {
5978
- clearTimeout(timer);
5979
- this.waiters.delete(wake);
5980
- signal.removeEventListener("abort", abort);
5981
- };
5982
- const wake = () => {
5983
- cleanup();
5984
- resolve(true);
5985
- };
5986
- const abort = () => {
5987
- cleanup();
5988
- reject(new KernelError("EINTR"));
5989
- };
5990
- this.waiters.add(wake);
5991
- signal.addEventListener("abort", abort, { once: true });
5992
- if (timeoutMs !== void 0) {
5993
- timer = setTimeout(() => {
5994
- cleanup();
5995
- resolve(false);
5996
- }, timeoutMs);
5997
- }
5998
- });
5999
- }
6000
- complete(id2, result) {
6001
- this.running.delete(id2);
6002
- if (!this.results.has(id2)) return;
6003
- this.results.set(id2, result);
6004
- this.ready.push(id2);
6005
- this.wake();
6006
- this.onReady?.();
6007
- }
6008
- wake() {
6009
- for (const wake of [...this.waiters]) wake();
6010
- }
6011
- };
6012
- async function hostSyscall(req, ctx) {
6013
- switch (req.op) {
6014
- case "lock":
6015
- if (!ctx.locks) throw new KernelError("ENOSYS");
6016
- if (!ctx.locks.lock(ctx.pid, req.path, req.exclusive, req.fd))
6017
- throw new KernelError("EAGAIN");
6018
- return done2;
6019
- case "unlock":
6020
- ctx.locks?.unlock(ctx.pid, req.path);
6021
- return done2;
6022
- case "async-submit":
6023
- if (!ctx.valid(req.req)) throw new KernelError("EINVAL");
6024
- return json3(ctx.ops.submit(req.req));
6025
- case "async-wait":
6026
- return json3(await ctx.ops.wait(req.timeoutMs, ctx.blocking()));
6027
- case "async-take":
6028
- return ctx.ops.take(req.id);
6029
- case "async-resolve":
6030
- return json3(ctx.ops.resolve(req.value));
6031
- case "async-hold":
6032
- return json3(ctx.ops.hold());
6033
- case "async-cancel":
6034
- ctx.ops.cancel(req.id);
6035
- return done2;
6036
- case "async-close":
6037
- ctx.ops.close();
6038
- return done2;
6039
- }
6040
- }
6041
-
6042
5895
  // src/kernel/net/loopback-names.ts
6043
5896
  var HOST_LOOPBACK = "host.slicc.internal";
6044
5897
  var HOST_LOOPBACK_ADDRESS = [10, 0, 2, 2];
@@ -6066,66 +5919,815 @@ function ownNames(hostname) {
6066
5919
  return [.../* @__PURE__ */ new Set([hostname.toLowerCase(), ...LIBC_HOSTNAMES])];
6067
5920
  }
6068
5921
 
6069
- // src/kernel/net/proxy-service.ts
6070
- var SEND_BUFFER2 = 1024 * 1024;
6071
- var TLS_HANDSHAKE = 22;
6072
- var TOKEN2 = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
6073
- var NO_WEBSOCKET2 = "WebSocket not supported by this transport (fetchTransport needs { webSocket: true })";
6074
- var REALM_PROXY_PORT = 3128;
6075
- var DEFAULT_LIMITS = {
6076
- maxConnections: 64,
6077
- maxHead: 64 * 1024,
6078
- idleMs: 12e4,
6079
- bodyBudget: 128 * 1024 * 1024,
6080
- closeWaitMs: 5e3
6081
- };
6082
- var HOP_BY_HOP = /* @__PURE__ */ new Set([
6083
- "connection",
6084
- "keep-alive",
6085
- "proxy-connection",
6086
- "proxy-authenticate",
6087
- "proxy-authorization",
6088
- "te",
6089
- "trailer",
6090
- "transfer-encoding",
6091
- "upgrade"
6092
- ]);
6093
- var REQUEST_OWN = /* @__PURE__ */ new Set(["host", "content-length", "expect"]);
6094
- var Budget = class {
6095
- free;
6096
- waiters = [];
6097
- constructor(free) {
6098
- this.free = free;
5922
+ // src/process/process-fds.ts
5923
+ var field2 = (text) => (text || "none").replace(/[\s\\]/g, (c) => `\\${c.charCodeAt(0).toString(8).padStart(3, "0")}`);
5924
+ function mountTable(mounts = []) {
5925
+ const root = globalThis.navigator?.storage ? "opfs" : "memory";
5926
+ const lines2 = [`${root} / ${root} rw 0 0`, "devfs /dev devfs rw 0 0", "proc /proc proc rw 0 0"];
5927
+ for (const m of mounts) {
5928
+ const options = Object.entries(m.options).map(([k, v]) => v === "" ? k : `${k}=${v}`);
5929
+ if (m.state !== "ok") options.push(m.state);
5930
+ const access = options.includes("ro") ? [] : ["rw"];
5931
+ lines2.push(
5932
+ `${field2(m.source)} ${field2(m.target)} ${m.type} ${[...access, ...options].join(",")} 0 0`
5933
+ );
6099
5934
  }
6100
- async acquire(n, signal) {
6101
- while (this.free < n) {
6102
- signal.throwIfAborted();
6103
- await new Promise((resolve) => {
6104
- const done4 = () => {
6105
- signal.removeEventListener("abort", done4);
6106
- resolve();
6107
- };
6108
- this.waiters.push(done4);
6109
- signal.addEventListener("abort", done4, { once: true });
6110
- });
6111
- }
6112
- this.free -= n;
5935
+ return `${lines2.join("\n")}
5936
+ `;
5937
+ }
5938
+
5939
+ // src/process/procfs.ts
5940
+ var HZ = 100;
5941
+ var KIB = 1024;
5942
+ var FALLBACK_MEMORY = 4 * KIB * KIB * KIB;
5943
+ var PID_FILES = ["cmdline", "comm", "stat", "statm", "status"];
5944
+ var SYSTEM_FILES = ["loadavg", "meminfo", "stat", "uptime"];
5945
+ function commOf(info) {
5946
+ const name2 = info.argv[0] ?? "";
5947
+ return name2.slice(name2.lastIndexOf("/") + 1).slice(0, 15);
5948
+ }
5949
+ function ttyNumber(tty) {
5950
+ const pts = tty && /^\/dev\/pts\/(\d+)$/.exec(tty);
5951
+ if (pts) return 136 << 8 | Number(pts[1]);
5952
+ const vt = tty && /^\/dev\/tty(\d+)$/.exec(tty);
5953
+ return vt ? 4 << 8 | Number(vt[1]) : 0;
5954
+ }
5955
+ function pages(bytes) {
5956
+ return Math.ceil(bytes / 4096);
5957
+ }
5958
+ function ticks(ms) {
5959
+ return Math.max(0, Math.floor(ms * HZ / 1e3));
5960
+ }
5961
+ function pidStat(info, boot) {
5962
+ const fields = [
5963
+ info.pid,
5964
+ `(${commOf(info)})`,
5965
+ info.state,
5966
+ info.ppid,
5967
+ info.pgid,
5968
+ info.sid,
5969
+ ttyNumber(info.tty),
5970
+ info.tty ? info.pgid : -1,
5971
+ 4194304,
5972
+ 0,
5973
+ 0,
5974
+ 0,
5975
+ 0,
5976
+ 0,
5977
+ 0,
5978
+ 0,
5979
+ 0,
5980
+ 20,
5981
+ 0,
5982
+ 1,
5983
+ 0,
5984
+ ticks(info.started - boot),
5985
+ info.memory,
5986
+ pages(info.memory),
5987
+ "18446744073709551615",
5988
+ ...Array(12).fill(0),
5989
+ 17,
5990
+ 0,
5991
+ 0,
5992
+ 0,
5993
+ 0,
5994
+ 0,
5995
+ 0,
5996
+ ...Array(7).fill(0),
5997
+ 0
5998
+ ];
5999
+ return `${fields.join(" ")}
6000
+ `;
6001
+ }
6002
+ var sigMask = (mask = 0) => (mask >>> 1).toString(16).padStart(16, "0");
6003
+ function pidStatus(info) {
6004
+ const state = info.state === "Z" ? "Z (zombie)" : "S (sleeping)";
6005
+ const c = info.cred ?? ROOT;
6006
+ const ids = (r, e, s) => `${r} ${e} ${s} ${e}`;
6007
+ return [
6008
+ `Name: ${commOf(info)}`,
6009
+ `Umask: ${(info.umask ?? 18).toString(8).padStart(4, "0")}`,
6010
+ `State: ${state}`,
6011
+ `Tgid: ${info.pid}`,
6012
+ "Ngid: 0",
6013
+ `Pid: ${info.pid}`,
6014
+ `PPid: ${info.ppid}`,
6015
+ "TracerPid: 0",
6016
+ `Uid: ${ids(c.ruid, c.euid, c.suid)}`,
6017
+ `Gid: ${ids(c.rgid, c.egid, c.sgid)}`,
6018
+ "FDSize: 64",
6019
+ `VmSize: ${Math.ceil(info.memory / KIB)} kB`,
6020
+ `VmRSS: ${Math.ceil(info.memory / KIB)} kB`,
6021
+ `Groups: ${c.groups.join(" ")}`,
6022
+ `NSpid: ${info.pid}`,
6023
+ `NSpgid: ${info.pgid}`,
6024
+ `NSsid: ${info.sid}`,
6025
+ "Threads: 1",
6026
+ "SigQ: 0/0",
6027
+ "SigPnd: 0000000000000000",
6028
+ "ShdPnd: 0000000000000000",
6029
+ "SigBlk: 0000000000000000",
6030
+ `SigIgn: ${sigMask(info.sigIgn)}`,
6031
+ `SigCgt: ${sigMask(info.sigCgt)}`,
6032
+ ""
6033
+ ].join("\n");
6034
+ }
6035
+ function pidFile(name2, info, boot) {
6036
+ if (name2 === "cmdline") return info.state === "Z" ? "" : `${info.argv.join("\0")}\0`;
6037
+ if (name2 === "comm") return `${commOf(info)}
6038
+ `;
6039
+ if (name2 === "stat") return pidStat(info, boot);
6040
+ if (name2 === "statm") {
6041
+ const p = pages(info.memory);
6042
+ return `${p} ${p} 0 0 0 ${p} 0
6043
+ `;
6113
6044
  }
6114
- release(n) {
6115
- this.free += n;
6116
- const waiters = this.waiters;
6117
- this.waiters = [];
6118
- for (const wake of waiters) wake();
6045
+ return pidStatus(info);
6046
+ }
6047
+ function memoryInfo(source, used = 0) {
6048
+ const total = source.deviceMemory ? source.deviceMemory * KIB * KIB * KIB : FALLBACK_MEMORY;
6049
+ const free = Math.max(0, total - used - (source.usedHeap ?? 0));
6050
+ const kb = (bytes) => `${Math.floor(bytes / KIB)} kB`;
6051
+ return [
6052
+ ["MemTotal", kb(total)],
6053
+ ["MemFree", kb(free)],
6054
+ ["MemAvailable", kb(free)],
6055
+ ["Buffers", kb(0)],
6056
+ ["Cached", kb(0)],
6057
+ ["SwapCached", kb(0)],
6058
+ ["Shmem", kb(0)],
6059
+ ["SReclaimable", kb(0)],
6060
+ ["SwapTotal", kb(0)],
6061
+ ["SwapFree", kb(0)]
6062
+ ].map(([key, value]) => `${`${key}:`.padEnd(16)}${value.padStart(12)}`).concat("").join("\n");
6063
+ }
6064
+ function systemFile(name2, listing, now, memory) {
6065
+ const up = Math.max(0, now - listing.boot) / 1e3;
6066
+ if (name2 === "uptime") return `${up.toFixed(2)} ${up.toFixed(2)}
6067
+ `;
6068
+ if (name2 === "meminfo") {
6069
+ return memoryInfo(
6070
+ memory,
6071
+ listing.processes.reduce((sum, p) => sum + p.memory, 0)
6072
+ );
6119
6073
  }
6120
- };
6121
- function canonicalHost2(host) {
6122
- const bare = host.includes(":") && !host.startsWith("[") ? `[${host}]` : host;
6123
- try {
6124
- return new URL(`http://${bare}/`).hostname;
6125
- } catch {
6126
- return void 0;
6074
+ const live = listing.processes.filter((p) => p.state !== "Z");
6075
+ if (name2 === "loadavg") {
6076
+ const last = Math.max(0, ...listing.processes.map((p) => p.pid));
6077
+ return `0.00 0.00 0.00 1/${live.length} ${last}
6078
+ `;
6127
6079
  }
6128
- }
6080
+ const idle = ticks(now - listing.boot);
6081
+ return [
6082
+ `cpu 0 0 0 ${idle} 0 0 0 0 0 0`,
6083
+ `cpu0 0 0 0 ${idle} 0 0 0 0 0 0`,
6084
+ "intr 0",
6085
+ "ctxt 0",
6086
+ `btime ${Math.floor(listing.boot / 1e3)}`,
6087
+ `processes ${listing.processes.length}`,
6088
+ "procs_running 1",
6089
+ "procs_blocked 0",
6090
+ ""
6091
+ ].join("\n");
6092
+ }
6093
+ function memorySource(scope = globalThis) {
6094
+ const nav = scope.navigator;
6095
+ const perf = scope.performance;
6096
+ const deviceMemory = nav?.deviceMemory;
6097
+ const used = perf?.memory?.usedJSHeapSize;
6098
+ return {
6099
+ ...typeof deviceMemory === "number" && deviceMemory > 0 ? { deviceMemory } : {},
6100
+ ...typeof used === "number" ? { usedHeap: used } : {}
6101
+ };
6102
+ }
6103
+
6104
+ // src/fs/pages.ts
6105
+ var PAGE = 64 * 1024;
6106
+ var READAHEAD = 1024 * 1024;
6107
+ var CLEAN_LIMIT = 4 * 1024 * 1024;
6108
+ var WRITEBACK = 8 * 1024 * 1024;
6109
+ var RUN = 1024 * 1024;
6110
+ var Pages = class {
6111
+ length;
6112
+ stored;
6113
+ shrink;
6114
+ pages = /* @__PURE__ */ new Map();
6115
+ dirty = /* @__PURE__ */ new Set();
6116
+ free = [];
6117
+ pinned = false;
6118
+ constructor(size) {
6119
+ this.length = size;
6120
+ this.stored = size;
6121
+ }
6122
+ get dirtyBytes() {
6123
+ return this.dirty.size * PAGE;
6124
+ }
6125
+ get changed() {
6126
+ return this.dirty.size > 0 || this.shrink !== void 0 || this.length !== this.stored;
6127
+ }
6128
+ missing(at, length2) {
6129
+ this.evict();
6130
+ const end = Math.min(this.stored, at + length2, this.length);
6131
+ const runs = [];
6132
+ for (let page = Math.floor(at / PAGE); page * PAGE < end; page++) {
6133
+ if (this.pages.has(page)) continue;
6134
+ const last2 = runs[runs.length - 1];
6135
+ if (last2 && last2[0] + last2[1] === page * PAGE) last2[1] += PAGE;
6136
+ else runs.push([page * PAGE, PAGE]);
6137
+ }
6138
+ const last = runs[runs.length - 1];
6139
+ if (last) last[1] = Math.max(last[1], Math.min(READAHEAD, this.stored - last[0]));
6140
+ return runs.map(([start2, n]) => [start2, Math.min(n, this.stored - start2)]);
6141
+ }
6142
+ partial(at, length2) {
6143
+ if (length2 === 0) return [];
6144
+ this.evict();
6145
+ const edges = /* @__PURE__ */ new Set([Math.floor(at / PAGE), Math.floor((at + length2 - 1) / PAGE)]);
6146
+ const runs = [];
6147
+ for (const page of edges) {
6148
+ const start2 = page * PAGE;
6149
+ const covered = at <= start2 && at + length2 >= start2 + PAGE;
6150
+ if (covered || this.pages.has(page) || start2 >= this.stored) continue;
6151
+ runs.push([start2, Math.min(PAGE, this.stored - start2)]);
6152
+ }
6153
+ return runs;
6154
+ }
6155
+ fill(start2, bytes) {
6156
+ for (let at = 0; at < bytes.length; at += PAGE) {
6157
+ const page = (start2 + at) / PAGE;
6158
+ if (this.pages.has(page)) continue;
6159
+ const part = bytes.subarray(at, Math.min(at + PAGE, bytes.length));
6160
+ const fresh = this.take(part.length);
6161
+ fresh.set(part);
6162
+ this.pages.set(page, fresh);
6163
+ }
6164
+ }
6165
+ read(at, length2) {
6166
+ const out = new Uint8Array(Math.max(0, Math.min(this.length, at + length2) - at));
6167
+ this.readInto(at, out);
6168
+ return out;
6169
+ }
6170
+ readInto(at, out) {
6171
+ const end = Math.min(this.length, at + out.length);
6172
+ for (let pos = at; pos < end; ) {
6173
+ const page = Math.floor(pos / PAGE);
6174
+ const from = pos - page * PAGE;
6175
+ const n = Math.min(PAGE - from, end - pos);
6176
+ const bytes = this.pages.get(page);
6177
+ if (bytes) out.set(bytes.subarray(from, from + n), pos - at);
6178
+ else out.fill(0, pos - at, pos - at + n);
6179
+ pos += n;
6180
+ }
6181
+ return Math.max(0, end - at);
6182
+ }
6183
+ write(at, bytes) {
6184
+ for (let done4 = 0; done4 < bytes.length; ) {
6185
+ const pos = at + done4;
6186
+ const page = Math.floor(pos / PAGE);
6187
+ const from = pos - page * PAGE;
6188
+ const n = Math.min(PAGE - from, bytes.length - done4);
6189
+ let target = this.pages.get(page);
6190
+ if (!target) {
6191
+ target = this.take(0);
6192
+ this.pages.set(page, target);
6193
+ }
6194
+ target.set(bytes.subarray(done4, done4 + n), from);
6195
+ this.dirty.add(page);
6196
+ done4 += n;
6197
+ }
6198
+ this.length = Math.max(this.length, at + bytes.length);
6199
+ }
6200
+ truncate(size) {
6201
+ if (size < this.stored) {
6202
+ this.stored = size;
6203
+ this.shrink = Math.min(this.shrink ?? size, size);
6204
+ }
6205
+ if (size < this.length) {
6206
+ const edge = Math.floor(size / PAGE);
6207
+ for (const page of [...this.pages.keys()]) {
6208
+ if (page > edge || page === edge && size === edge * PAGE) this.drop(page);
6209
+ }
6210
+ this.pages.get(edge)?.fill(0, size - edge * PAGE);
6211
+ }
6212
+ this.length = size;
6213
+ }
6214
+ plan() {
6215
+ const runs = [];
6216
+ const sorted = [...this.dirty].sort((a, b) => a - b);
6217
+ for (let i = 0; i < sorted.length; ) {
6218
+ let j = i + 1;
6219
+ const first = sorted[i];
6220
+ while (j < sorted.length && sorted[j] === first + (j - i) && sorted[j] * PAGE % RUN !== 0) {
6221
+ j++;
6222
+ }
6223
+ const start2 = first * PAGE;
6224
+ const end = Math.min(this.length, (first + (j - i)) * PAGE);
6225
+ const bytes = new Uint8Array(end - start2);
6226
+ for (let k = i; k < j; k++) {
6227
+ const page = this.pages.get(sorted[k]);
6228
+ bytes.set(page.subarray(0, Math.min(PAGE, end - (k - i) * PAGE - start2)), (k - i) * PAGE);
6229
+ }
6230
+ runs.push({ offset: start2, bytes });
6231
+ i = j;
6232
+ }
6233
+ const written2 = Math.max(this.stored, ...runs.map((r) => r.offset + r.bytes.length));
6234
+ return {
6235
+ ...this.shrink !== void 0 ? { shrink: this.shrink } : {},
6236
+ runs,
6237
+ ...this.length > written2 ? { extend: this.length } : {}
6238
+ };
6239
+ }
6240
+ flushed() {
6241
+ this.dirty.clear();
6242
+ this.shrink = void 0;
6243
+ this.stored = this.length;
6244
+ this.evict();
6245
+ }
6246
+ pin() {
6247
+ this.pinned = true;
6248
+ }
6249
+ reset(size) {
6250
+ if (this.pinned) return;
6251
+ for (const page of [...this.pages.keys()]) if (!this.dirty.has(page)) this.drop(page);
6252
+ if (this.changed) return;
6253
+ this.length = size;
6254
+ this.stored = size;
6255
+ }
6256
+ evict() {
6257
+ if (this.pinned) return;
6258
+ let clean = (this.pages.size - this.dirty.size) * PAGE;
6259
+ for (const page of this.pages.keys()) {
6260
+ if (clean <= CLEAN_LIMIT) return;
6261
+ if (this.dirty.has(page)) continue;
6262
+ this.drop(page);
6263
+ clean -= PAGE;
6264
+ }
6265
+ }
6266
+ take(used) {
6267
+ const page = this.free.pop();
6268
+ if (!page) return new Uint8Array(PAGE);
6269
+ page.fill(0, used);
6270
+ return page;
6271
+ }
6272
+ drop(page) {
6273
+ const bytes = this.pages.get(page);
6274
+ this.pages.delete(page);
6275
+ this.dirty.delete(page);
6276
+ if (this.free.length < CLEAN_LIMIT / PAGE) this.free.push(bytes);
6277
+ }
6278
+ };
6279
+
6280
+ // src/fs/ranged.ts
6281
+ var AsyncRangedFile = class {
6282
+ pages;
6283
+ io;
6284
+ pinned = false;
6285
+ version;
6286
+ path;
6287
+ constructor(io, path, size, version) {
6288
+ this.io = io;
6289
+ this.path = path;
6290
+ this.version = version;
6291
+ this.pages = new Pages(size);
6292
+ }
6293
+ size() {
6294
+ return this.pages.length;
6295
+ }
6296
+ async fetch(runs) {
6297
+ for (const [start2, n] of runs) {
6298
+ this.pages.fill(start2, await this.io.pread(this.path, start2, n, this.version));
6299
+ }
6300
+ }
6301
+ async read(at, length2) {
6302
+ await this.fetch(this.pages.missing(at, length2));
6303
+ return this.pages.read(at, length2);
6304
+ }
6305
+ async write(at, bytes) {
6306
+ await this.fetch(this.pages.partial(at, bytes.length));
6307
+ this.pages.write(at, bytes);
6308
+ if (!this.pinned && this.pages.dirtyBytes >= WRITEBACK) await this.flush();
6309
+ }
6310
+ truncate(size) {
6311
+ this.pages.truncate(size);
6312
+ }
6313
+ async flush() {
6314
+ if (this.pinned || !this.pages.changed) return;
6315
+ const plan = this.pages.plan();
6316
+ if (plan.shrink !== void 0) await this.io.truncate(this.path, plan.shrink);
6317
+ for (const run2 of plan.runs) await this.io.pwrite(this.path, run2.offset, run2.bytes, true);
6318
+ if (plan.extend !== void 0) await this.io.truncate(this.path, plan.extend);
6319
+ this.version = void 0;
6320
+ this.pages.flushed();
6321
+ }
6322
+ async pin() {
6323
+ this.pinned = true;
6324
+ this.pages.pin();
6325
+ await this.fetch(this.pages.missing(0, this.pages.length));
6326
+ }
6327
+ };
6328
+
6329
+ // src/process/wasi/wasi-files.ts
6330
+ function normalize(path) {
6331
+ const out = [];
6332
+ for (const seg of path.split("/")) {
6333
+ if (seg === "" || seg === ".") continue;
6334
+ if (seg === "..") out.pop();
6335
+ else out.push(seg);
6336
+ }
6337
+ return `/${out.join("/")}`;
6338
+ }
6339
+
6340
+ // src/process/wasi/wasi-procfs.ts
6341
+ var DIR_MODE = 16749;
6342
+ var FILE_MODE = 33060;
6343
+ var LINK_MODE = 41471;
6344
+ var PID_NAMES = PID_FILES;
6345
+ var SYSTEM_NAMES = SYSTEM_FILES;
6346
+ function inProc(path) {
6347
+ return path === "/proc" || path.startsWith("/proc/");
6348
+ }
6349
+ var ProcTree = class {
6350
+ source;
6351
+ pid;
6352
+ memory;
6353
+ constructor(source, pid, memory = memorySource()) {
6354
+ this.source = source;
6355
+ this.pid = pid;
6356
+ this.memory = memory;
6357
+ }
6358
+ listing() {
6359
+ return this.source.procList();
6360
+ }
6361
+ alive(pid) {
6362
+ return this.listing().processes.some((p) => p.pid === pid);
6363
+ }
6364
+ node(parts) {
6365
+ const [top, leaf, ...rest2] = parts;
6366
+ if (top === void 0) {
6367
+ return {
6368
+ kind: "dir",
6369
+ names: () => [
6370
+ ...SYSTEM_NAMES,
6371
+ "mounts",
6372
+ "self",
6373
+ ...this.listing().processes.map((p) => String(p.pid))
6374
+ ]
6375
+ };
6376
+ }
6377
+ if (top === "self") {
6378
+ return leaf === void 0 ? { kind: "link", target: String(this.pid) } : void 0;
6379
+ }
6380
+ if (leaf === void 0 && top === "mounts") {
6381
+ return { kind: "file", content: () => mountTable(this.source.mountList()) };
6382
+ }
6383
+ if (leaf === void 0 && SYSTEM_NAMES.includes(top)) {
6384
+ return {
6385
+ kind: "file",
6386
+ content: () => systemFile(top, this.listing(), Date.now(), this.memory)
6387
+ };
6388
+ }
6389
+ if (!/^[1-9]\d*$/.test(top) || rest2.length > 0 || !this.alive(Number(top))) return void 0;
6390
+ if (leaf === void 0) return { kind: "dir", names: () => [...PID_NAMES] };
6391
+ if (!PID_NAMES.includes(leaf)) return void 0;
6392
+ return {
6393
+ kind: "file",
6394
+ content: () => {
6395
+ const listing = this.listing();
6396
+ const info = listing.processes.find((p) => p.pid === Number(top));
6397
+ if (!info) throw syncError("ENOENT", `/proc/${top}/${leaf}`);
6398
+ return pidFile(leaf, info, listing.boot);
6399
+ }
6400
+ };
6401
+ }
6402
+ parts(path, follow2) {
6403
+ const parts = path.split("/").filter((p) => p !== "").slice(1);
6404
+ if (parts[0] === "self" && (follow2 || parts.length > 1)) parts[0] = String(this.pid);
6405
+ return parts;
6406
+ }
6407
+ find(path, follow2) {
6408
+ const node = this.node(this.parts(path, follow2));
6409
+ if (!node) throw syncError("ENOENT", path);
6410
+ return node;
6411
+ }
6412
+ stat(path, follow2 = true) {
6413
+ const node = this.find(path, follow2);
6414
+ const base = {
6415
+ isFile: false,
6416
+ isDirectory: false,
6417
+ size: 0,
6418
+ mtimeMs: Date.now(),
6419
+ readonly: true
6420
+ };
6421
+ if (node.kind === "dir") return { ...base, isDirectory: true, mode: DIR_MODE };
6422
+ if (node.kind === "link") {
6423
+ return { ...base, isSymbolicLink: true, mode: LINK_MODE, size: node.target.length };
6424
+ }
6425
+ return { ...base, isFile: true, mode: FILE_MODE, size: this.bytes(node).length };
6426
+ }
6427
+ bytes(node) {
6428
+ return new TextEncoder().encode(node.kind === "file" ? node.content() : "");
6429
+ }
6430
+ read(path) {
6431
+ const node = this.find(path, true);
6432
+ if (node.kind !== "file") throw syncError("EISDIR", path);
6433
+ return this.bytes(node);
6434
+ }
6435
+ readdir(path) {
6436
+ const node = this.find(path, true);
6437
+ if (node.kind !== "dir") throw syncError("ENOTDIR", path);
6438
+ return node.names();
6439
+ }
6440
+ readlink(path) {
6441
+ const node = this.find(path, false);
6442
+ if (node.kind !== "link") throw syncError("EINVAL", path);
6443
+ return node.target;
6444
+ }
6445
+ exists(path) {
6446
+ try {
6447
+ this.find(path, true);
6448
+ return true;
6449
+ } catch {
6450
+ return false;
6451
+ }
6452
+ }
6453
+ };
6454
+ var MAX_HOPS2 = 40;
6455
+ function* procWalk(path, follow2) {
6456
+ let done4 = [];
6457
+ let todo = path.split("/").filter((part) => part !== "");
6458
+ let hops = 0;
6459
+ while (todo.length > 0) {
6460
+ const part = todo.shift();
6461
+ if (part === ".") continue;
6462
+ if (part === "..") {
6463
+ done4.pop();
6464
+ continue;
6465
+ }
6466
+ const at = `/${[...done4, part].join("/")}`;
6467
+ const whole = normalize(`/${[...done4, part, ...todo].join("/")}`);
6468
+ if (inProc(at) && inProc(whole)) return whole;
6469
+ if (!follow2 && todo.length === 0) return void 0;
6470
+ const target = yield at;
6471
+ if (target === null) return void 0;
6472
+ if (target === void 0) done4.push(part);
6473
+ else {
6474
+ if (++hops > MAX_HOPS2) return void 0;
6475
+ if (target.startsWith("/")) done4 = [];
6476
+ todo = [...target.split("/").filter((part2) => part2 !== ""), ...todo];
6477
+ }
6478
+ }
6479
+ return void 0;
6480
+ }
6481
+ async function procAlias(fs, path, follow2) {
6482
+ const { readlink, lstat } = fs;
6483
+ if (!readlink || !lstat) return void 0;
6484
+ const physical = await lstat.call(fs, "/proc").then(
6485
+ () => true,
6486
+ () => false
6487
+ );
6488
+ if (!physical) return void 0;
6489
+ const walk = procWalk(path, follow2);
6490
+ let step = walk.next();
6491
+ while (!step.done) {
6492
+ const target = await readlink.call(fs, step.value).catch(() => void 0);
6493
+ step = walk.next(target);
6494
+ }
6495
+ return step.value;
6496
+ }
6497
+
6498
+ // src/kernel/host-ops.ts
6499
+ var HOST_OPS = [
6500
+ "lock",
6501
+ "unlock",
6502
+ "async-submit",
6503
+ "async-wait",
6504
+ "async-take",
6505
+ "async-resolve",
6506
+ "async-hold",
6507
+ "async-cancel",
6508
+ "async-close"
6509
+ ];
6510
+ var json3 = (value) => ({ ok: true, kind: "json", json: value });
6511
+ var done2 = { ok: true, kind: "void" };
6512
+ var LockTable = class {
6513
+ held = /* @__PURE__ */ new Map();
6514
+ lock(pid, path, exclusive, fd) {
6515
+ const holders = this.held.get(path) ?? /* @__PURE__ */ new Map();
6516
+ for (const [other, h] of holders) if (other !== pid && (exclusive || h.exclusive)) return false;
6517
+ const mine = holders.get(pid) ?? { exclusive, fds: /* @__PURE__ */ new Set() };
6518
+ mine.exclusive = exclusive;
6519
+ mine.fds.add(fd);
6520
+ holders.set(pid, mine);
6521
+ this.held.set(path, holders);
6522
+ return true;
6523
+ }
6524
+ unlock(pid, path) {
6525
+ const holders = this.held.get(path);
6526
+ holders?.delete(pid);
6527
+ if (holders?.size === 0) this.held.delete(path);
6528
+ }
6529
+ closed(pid, fd) {
6530
+ for (const [path, holders] of [...this.held]) {
6531
+ const mine = holders.get(pid);
6532
+ if (mine?.fds.delete(fd) && mine.fds.size === 0) this.unlock(pid, path);
6533
+ }
6534
+ }
6535
+ release(pid) {
6536
+ for (const path of [...this.held.keys()]) this.unlock(pid, path);
6537
+ }
6538
+ };
6539
+ var AsyncOps = class {
6540
+ next = 1;
6541
+ results = /* @__PURE__ */ new Map();
6542
+ ready = [];
6543
+ running = /* @__PURE__ */ new Map();
6544
+ waiters = /* @__PURE__ */ new Set();
6545
+ closed = false;
6546
+ run;
6547
+ onReady;
6548
+ constructor(run2, onReady) {
6549
+ this.run = run2;
6550
+ this.onReady = onReady;
6551
+ }
6552
+ submit(req) {
6553
+ const id2 = this.hold();
6554
+ const running = new AbortController();
6555
+ this.running.set(id2, running);
6556
+ this.run(req, running.signal).then(
6557
+ (result) => this.complete(id2, result),
6558
+ (err) => this.complete(id2, { ok: false, errno: "EIO", message: String(err) })
6559
+ );
6560
+ return id2;
6561
+ }
6562
+ resolve(value) {
6563
+ const id2 = this.hold();
6564
+ this.complete(id2, json3(value));
6565
+ return id2;
6566
+ }
6567
+ hold() {
6568
+ const id2 = this.next++;
6569
+ this.results.set(id2, void 0);
6570
+ return id2;
6571
+ }
6572
+ take(id2) {
6573
+ if (!this.results.has(id2)) throw new KernelError("EINVAL");
6574
+ const result = this.results.get(id2);
6575
+ if (!result) throw new KernelError("EAGAIN");
6576
+ this.forget(id2);
6577
+ return result;
6578
+ }
6579
+ cancel(id2) {
6580
+ this.running.get(id2)?.abort();
6581
+ this.forget(id2);
6582
+ }
6583
+ forget(id2) {
6584
+ this.running.delete(id2);
6585
+ this.results.delete(id2);
6586
+ const at = this.ready.indexOf(id2);
6587
+ if (at >= 0) this.ready.splice(at, 1);
6588
+ }
6589
+ async wait(timeoutMs, signal) {
6590
+ for (; ; ) {
6591
+ if (this.closed) return -1;
6592
+ const id2 = this.ready.shift();
6593
+ if (id2 !== void 0) return id2;
6594
+ if (timeoutMs !== void 0 && timeoutMs <= 0) return 0;
6595
+ const woke = await this.sleep(timeoutMs, signal);
6596
+ if (!woke) return 0;
6597
+ }
6598
+ }
6599
+ close() {
6600
+ this.closed = true;
6601
+ this.wake();
6602
+ }
6603
+ sleep(timeoutMs, signal) {
6604
+ return new Promise((resolve, reject) => {
6605
+ let timer;
6606
+ const cleanup = () => {
6607
+ clearTimeout(timer);
6608
+ this.waiters.delete(wake);
6609
+ signal.removeEventListener("abort", abort);
6610
+ };
6611
+ const wake = () => {
6612
+ cleanup();
6613
+ resolve(true);
6614
+ };
6615
+ const abort = () => {
6616
+ cleanup();
6617
+ reject(new KernelError("EINTR"));
6618
+ };
6619
+ this.waiters.add(wake);
6620
+ signal.addEventListener("abort", abort, { once: true });
6621
+ if (timeoutMs !== void 0) {
6622
+ timer = setTimeout(() => {
6623
+ cleanup();
6624
+ resolve(false);
6625
+ }, timeoutMs);
6626
+ }
6627
+ });
6628
+ }
6629
+ complete(id2, result) {
6630
+ this.running.delete(id2);
6631
+ if (!this.results.has(id2)) return;
6632
+ this.results.set(id2, result);
6633
+ this.ready.push(id2);
6634
+ this.wake();
6635
+ this.onReady?.();
6636
+ }
6637
+ wake() {
6638
+ for (const wake of [...this.waiters]) wake();
6639
+ }
6640
+ };
6641
+ async function hostSyscall(req, ctx) {
6642
+ switch (req.op) {
6643
+ case "lock":
6644
+ if (!ctx.locks) throw new KernelError("ENOSYS");
6645
+ if (!ctx.locks.lock(ctx.pid, req.path, req.exclusive, req.fd))
6646
+ throw new KernelError("EAGAIN");
6647
+ return done2;
6648
+ case "unlock":
6649
+ ctx.locks?.unlock(ctx.pid, req.path);
6650
+ return done2;
6651
+ case "async-submit":
6652
+ if (!ctx.valid(req.req)) throw new KernelError("EINVAL");
6653
+ return json3(ctx.ops.submit(req.req));
6654
+ case "async-wait":
6655
+ return json3(await ctx.ops.wait(req.timeoutMs, ctx.blocking()));
6656
+ case "async-take":
6657
+ return ctx.ops.take(req.id);
6658
+ case "async-resolve":
6659
+ return json3(ctx.ops.resolve(req.value));
6660
+ case "async-hold":
6661
+ return json3(ctx.ops.hold());
6662
+ case "async-cancel":
6663
+ ctx.ops.cancel(req.id);
6664
+ return done2;
6665
+ case "async-close":
6666
+ ctx.ops.close();
6667
+ return done2;
6668
+ }
6669
+ }
6670
+
6671
+ // src/kernel/net/proxy-service.ts
6672
+ var SEND_BUFFER2 = 1024 * 1024;
6673
+ var TLS_HANDSHAKE = 22;
6674
+ var TOKEN2 = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
6675
+ var NO_WEBSOCKET2 = "WebSocket not supported by this transport (fetchTransport needs { webSocket: true })";
6676
+ var REALM_PROXY_PORT = 3128;
6677
+ var DEFAULT_LIMITS = {
6678
+ maxConnections: 64,
6679
+ maxHead: 64 * 1024,
6680
+ idleMs: 12e4,
6681
+ bodyBudget: 128 * 1024 * 1024,
6682
+ closeWaitMs: 5e3
6683
+ };
6684
+ var HOP_BY_HOP = /* @__PURE__ */ new Set([
6685
+ "connection",
6686
+ "keep-alive",
6687
+ "proxy-connection",
6688
+ "proxy-authenticate",
6689
+ "proxy-authorization",
6690
+ "te",
6691
+ "trailer",
6692
+ "transfer-encoding",
6693
+ "upgrade"
6694
+ ]);
6695
+ var REQUEST_OWN = /* @__PURE__ */ new Set(["host", "content-length", "expect"]);
6696
+ var Budget = class {
6697
+ free;
6698
+ waiters = [];
6699
+ constructor(free) {
6700
+ this.free = free;
6701
+ }
6702
+ async acquire(n, signal) {
6703
+ while (this.free < n) {
6704
+ signal.throwIfAborted();
6705
+ await new Promise((resolve) => {
6706
+ const done4 = () => {
6707
+ signal.removeEventListener("abort", done4);
6708
+ resolve();
6709
+ };
6710
+ this.waiters.push(done4);
6711
+ signal.addEventListener("abort", done4, { once: true });
6712
+ });
6713
+ }
6714
+ this.free -= n;
6715
+ }
6716
+ release(n) {
6717
+ this.free += n;
6718
+ const waiters = this.waiters;
6719
+ this.waiters = [];
6720
+ for (const wake of waiters) wake();
6721
+ }
6722
+ };
6723
+ function canonicalHost2(host) {
6724
+ const bare = host.includes(":") && !host.startsWith("[") ? `[${host}]` : host;
6725
+ try {
6726
+ return new URL(`http://${bare}/`).hostname;
6727
+ } catch {
6728
+ return void 0;
6729
+ }
6730
+ }
6129
6731
  function localV4(a, b) {
6130
6732
  return a === 127 || a === 0 || a === 169 && b === 254;
6131
6733
  }
@@ -8372,231 +8974,6 @@ async function accept(proc, fd, nonblock) {
8372
8974
  return { fd: proc.fds.install(new OpenFile(socket), 3), peer: socket.peer };
8373
8975
  }
8374
8976
 
8375
- // src/fs/pages.ts
8376
- var PAGE = 64 * 1024;
8377
- var READAHEAD = 1024 * 1024;
8378
- var CLEAN_LIMIT = 4 * 1024 * 1024;
8379
- var WRITEBACK = 8 * 1024 * 1024;
8380
- var RUN = 1024 * 1024;
8381
- var Pages = class {
8382
- length;
8383
- stored;
8384
- shrink;
8385
- pages = /* @__PURE__ */ new Map();
8386
- dirty = /* @__PURE__ */ new Set();
8387
- free = [];
8388
- pinned = false;
8389
- constructor(size) {
8390
- this.length = size;
8391
- this.stored = size;
8392
- }
8393
- get dirtyBytes() {
8394
- return this.dirty.size * PAGE;
8395
- }
8396
- get changed() {
8397
- return this.dirty.size > 0 || this.shrink !== void 0 || this.length !== this.stored;
8398
- }
8399
- missing(at, length2) {
8400
- this.evict();
8401
- const end = Math.min(this.stored, at + length2, this.length);
8402
- const runs = [];
8403
- for (let page = Math.floor(at / PAGE); page * PAGE < end; page++) {
8404
- if (this.pages.has(page)) continue;
8405
- const last2 = runs[runs.length - 1];
8406
- if (last2 && last2[0] + last2[1] === page * PAGE) last2[1] += PAGE;
8407
- else runs.push([page * PAGE, PAGE]);
8408
- }
8409
- const last = runs[runs.length - 1];
8410
- if (last) last[1] = Math.max(last[1], Math.min(READAHEAD, this.stored - last[0]));
8411
- return runs.map(([start2, n]) => [start2, Math.min(n, this.stored - start2)]);
8412
- }
8413
- partial(at, length2) {
8414
- if (length2 === 0) return [];
8415
- this.evict();
8416
- const edges = /* @__PURE__ */ new Set([Math.floor(at / PAGE), Math.floor((at + length2 - 1) / PAGE)]);
8417
- const runs = [];
8418
- for (const page of edges) {
8419
- const start2 = page * PAGE;
8420
- const covered = at <= start2 && at + length2 >= start2 + PAGE;
8421
- if (covered || this.pages.has(page) || start2 >= this.stored) continue;
8422
- runs.push([start2, Math.min(PAGE, this.stored - start2)]);
8423
- }
8424
- return runs;
8425
- }
8426
- fill(start2, bytes) {
8427
- for (let at = 0; at < bytes.length; at += PAGE) {
8428
- const page = (start2 + at) / PAGE;
8429
- if (this.pages.has(page)) continue;
8430
- const part = bytes.subarray(at, Math.min(at + PAGE, bytes.length));
8431
- const fresh = this.take(part.length);
8432
- fresh.set(part);
8433
- this.pages.set(page, fresh);
8434
- }
8435
- }
8436
- read(at, length2) {
8437
- const out = new Uint8Array(Math.max(0, Math.min(this.length, at + length2) - at));
8438
- this.readInto(at, out);
8439
- return out;
8440
- }
8441
- readInto(at, out) {
8442
- const end = Math.min(this.length, at + out.length);
8443
- for (let pos = at; pos < end; ) {
8444
- const page = Math.floor(pos / PAGE);
8445
- const from = pos - page * PAGE;
8446
- const n = Math.min(PAGE - from, end - pos);
8447
- const bytes = this.pages.get(page);
8448
- if (bytes) out.set(bytes.subarray(from, from + n), pos - at);
8449
- else out.fill(0, pos - at, pos - at + n);
8450
- pos += n;
8451
- }
8452
- return Math.max(0, end - at);
8453
- }
8454
- write(at, bytes) {
8455
- for (let done4 = 0; done4 < bytes.length; ) {
8456
- const pos = at + done4;
8457
- const page = Math.floor(pos / PAGE);
8458
- const from = pos - page * PAGE;
8459
- const n = Math.min(PAGE - from, bytes.length - done4);
8460
- let target = this.pages.get(page);
8461
- if (!target) {
8462
- target = this.take(0);
8463
- this.pages.set(page, target);
8464
- }
8465
- target.set(bytes.subarray(done4, done4 + n), from);
8466
- this.dirty.add(page);
8467
- done4 += n;
8468
- }
8469
- this.length = Math.max(this.length, at + bytes.length);
8470
- }
8471
- truncate(size) {
8472
- if (size < this.stored) {
8473
- this.stored = size;
8474
- this.shrink = Math.min(this.shrink ?? size, size);
8475
- }
8476
- if (size < this.length) {
8477
- const edge = Math.floor(size / PAGE);
8478
- for (const page of [...this.pages.keys()]) {
8479
- if (page > edge || page === edge && size === edge * PAGE) this.drop(page);
8480
- }
8481
- this.pages.get(edge)?.fill(0, size - edge * PAGE);
8482
- }
8483
- this.length = size;
8484
- }
8485
- plan() {
8486
- const runs = [];
8487
- const sorted = [...this.dirty].sort((a, b) => a - b);
8488
- for (let i = 0; i < sorted.length; ) {
8489
- let j = i + 1;
8490
- const first = sorted[i];
8491
- while (j < sorted.length && sorted[j] === first + (j - i) && sorted[j] * PAGE % RUN !== 0) {
8492
- j++;
8493
- }
8494
- const start2 = first * PAGE;
8495
- const end = Math.min(this.length, (first + (j - i)) * PAGE);
8496
- const bytes = new Uint8Array(end - start2);
8497
- for (let k = i; k < j; k++) {
8498
- const page = this.pages.get(sorted[k]);
8499
- bytes.set(page.subarray(0, Math.min(PAGE, end - (k - i) * PAGE - start2)), (k - i) * PAGE);
8500
- }
8501
- runs.push({ offset: start2, bytes });
8502
- i = j;
8503
- }
8504
- const written2 = Math.max(this.stored, ...runs.map((r) => r.offset + r.bytes.length));
8505
- return {
8506
- ...this.shrink !== void 0 ? { shrink: this.shrink } : {},
8507
- runs,
8508
- ...this.length > written2 ? { extend: this.length } : {}
8509
- };
8510
- }
8511
- flushed() {
8512
- this.dirty.clear();
8513
- this.shrink = void 0;
8514
- this.stored = this.length;
8515
- this.evict();
8516
- }
8517
- pin() {
8518
- this.pinned = true;
8519
- }
8520
- reset(size) {
8521
- if (this.pinned) return;
8522
- for (const page of [...this.pages.keys()]) if (!this.dirty.has(page)) this.drop(page);
8523
- if (this.changed) return;
8524
- this.length = size;
8525
- this.stored = size;
8526
- }
8527
- evict() {
8528
- if (this.pinned) return;
8529
- let clean = (this.pages.size - this.dirty.size) * PAGE;
8530
- for (const page of this.pages.keys()) {
8531
- if (clean <= CLEAN_LIMIT) return;
8532
- if (this.dirty.has(page)) continue;
8533
- this.drop(page);
8534
- clean -= PAGE;
8535
- }
8536
- }
8537
- take(used) {
8538
- const page = this.free.pop();
8539
- if (!page) return new Uint8Array(PAGE);
8540
- page.fill(0, used);
8541
- return page;
8542
- }
8543
- drop(page) {
8544
- const bytes = this.pages.get(page);
8545
- this.pages.delete(page);
8546
- this.dirty.delete(page);
8547
- if (this.free.length < CLEAN_LIMIT / PAGE) this.free.push(bytes);
8548
- }
8549
- };
8550
-
8551
- // src/fs/ranged.ts
8552
- var AsyncRangedFile = class {
8553
- pages;
8554
- io;
8555
- pinned = false;
8556
- version;
8557
- path;
8558
- constructor(io, path, size, version) {
8559
- this.io = io;
8560
- this.path = path;
8561
- this.version = version;
8562
- this.pages = new Pages(size);
8563
- }
8564
- size() {
8565
- return this.pages.length;
8566
- }
8567
- async fetch(runs) {
8568
- for (const [start2, n] of runs) {
8569
- this.pages.fill(start2, await this.io.pread(this.path, start2, n, this.version));
8570
- }
8571
- }
8572
- async read(at, length2) {
8573
- await this.fetch(this.pages.missing(at, length2));
8574
- return this.pages.read(at, length2);
8575
- }
8576
- async write(at, bytes) {
8577
- await this.fetch(this.pages.partial(at, bytes.length));
8578
- this.pages.write(at, bytes);
8579
- if (!this.pinned && this.pages.dirtyBytes >= WRITEBACK) await this.flush();
8580
- }
8581
- truncate(size) {
8582
- this.pages.truncate(size);
8583
- }
8584
- async flush() {
8585
- if (this.pinned || !this.pages.changed) return;
8586
- const plan = this.pages.plan();
8587
- if (plan.shrink !== void 0) await this.io.truncate(this.path, plan.shrink);
8588
- for (const run2 of plan.runs) await this.io.pwrite(this.path, run2.offset, run2.bytes, true);
8589
- if (plan.extend !== void 0) await this.io.truncate(this.path, plan.extend);
8590
- this.version = void 0;
8591
- this.pages.flushed();
8592
- }
8593
- async pin() {
8594
- this.pinned = true;
8595
- this.pages.pin();
8596
- await this.fetch(this.pages.missing(0, this.pages.length));
8597
- }
8598
- };
8599
-
8600
8977
  // src/kernel/vfs-file.ts
8601
8978
  var O_ACCMODE = 3;
8602
8979
  var O_WRONLY = 1;
@@ -9236,6 +9613,7 @@ function isWasmSyscall(req) {
9236
9613
  return typeof op === "string" && SYSCALL_OPS.has(op);
9237
9614
  }
9238
9615
  var MAX_READ = 1024 * 1024;
9616
+ var WRITE_ACCESS = 3;
9239
9617
  var KEYBOARD = /* @__PURE__ */ new Set([SIG.INT, SIG.QUIT, SIG.TSTP]);
9240
9618
  var DEFAULT_UMASK = 18;
9241
9619
  var DYING = { ok: false, errno: "EINTR", message: "the process is being killed" };
@@ -9446,11 +9824,18 @@ var WasmProcess = class {
9446
9824
  );
9447
9825
  }
9448
9826
  async openVfs(req) {
9827
+ if (inProc(req.path)) return this.openProc(req, req.path);
9828
+ const alias = req.orphan ? void 0 : await procAlias(this.options.fs, req.path, !req.exclusive);
9829
+ if (alias !== void 0) return this.openProc(req, alias);
9449
9830
  await refuseReadonly(this.options.fs, req.path, req.flags, req);
9450
9831
  const fd = this.fds.install(heldFile(), 3);
9451
9832
  try {
9452
9833
  const nodes = this.nodes;
9453
9834
  const path = req.orphan ? req.path : req.exclusive ? await nodes.entryKey(req.path) : req.create ? await nodes.targetKey(req.path) : await this.keptOr(await nodes.targetKey(req.path), req.handle);
9835
+ if (inProc(path)) {
9836
+ this.fds.installAt(fd, await this.procFile(req, path));
9837
+ return fd;
9838
+ }
9454
9839
  const open = { ...req, path };
9455
9840
  if (req.exclusive) {
9456
9841
  await nodes.createExclusive(path);
@@ -9472,6 +9857,22 @@ var WasmProcess = class {
9472
9857
  }
9473
9858
  return fd;
9474
9859
  }
9860
+ async openProc(req, path) {
9861
+ return this.fds.install(await this.procFile(req, path), 3);
9862
+ }
9863
+ async procFile(req, path) {
9864
+ if (req.flags & WRITE_ACCESS || req.create || req.truncate || req.exclusive) {
9865
+ throw new KernelError("EROFS");
9866
+ }
9867
+ const tree = new ProcTree(
9868
+ {
9869
+ procList: () => this.options.processes?.() ?? { boot: 0, processes: [] },
9870
+ mountList: () => this.options.mounts?.() ?? []
9871
+ },
9872
+ (await this.options.identity?.())?.pid ?? this.pid
9873
+ );
9874
+ return memoryFile(tree.read(path), path, req.position);
9875
+ }
9475
9876
  openVfsFile(req) {
9476
9877
  return vfsFile(
9477
9878
  this.options.fs,
@@ -10974,8 +11375,8 @@ function umountCall(target, flags) {
10974
11375
  var FSTAB_PATH = "/etc/fstab";
10975
11376
  var FSTAB_RETRIES = [1e3, 4e3, 16e3];
10976
11377
  var FINAL = /* @__PURE__ */ new Set(["EINVAL", "EBUSY", "EPERM", "EACCES"]);
10977
- function unescape(field2) {
10978
- return field2.replace(
11378
+ function unescape(field3) {
11379
+ return field3.replace(
10979
11380
  /\\([0-7]{3})/g,
10980
11381
  (_, octal) => String.fromCharCode(Number.parseInt(octal, 8))
10981
11382
  );
@@ -11868,7 +12269,7 @@ function importedMemory(bytes) {
11868
12269
  const count = u32();
11869
12270
  for (let i = 0; i < count; i++) {
11870
12271
  const module = name2();
11871
- const field2 = name2();
12272
+ const field3 = name2();
11872
12273
  const kind = bytes[at++];
11873
12274
  if (kind === 0) u32();
11874
12275
  else if (kind === 1) {
@@ -11876,7 +12277,7 @@ function importedMemory(bytes) {
11876
12277
  limits();
11877
12278
  } else if (kind === 2) {
11878
12279
  const l = limits();
11879
- return { module, name: field2, ...l };
12280
+ return { module, name: field3, ...l };
11880
12281
  } else if (kind === 3) at += 2;
11881
12282
  else if (kind === 4) {
11882
12283
  at++;
@@ -11967,12 +12368,12 @@ function readImports(r, types) {
11967
12368
  const foreign = {};
11968
12369
  for (let i = r.u32(); i > 0; i--) {
11969
12370
  const module = r.name();
11970
- const field2 = r.name();
12371
+ const field3 = r.name();
11971
12372
  const kind = r.byte();
11972
12373
  if (kind !== 0) skipImport(r, kind);
11973
12374
  else {
11974
12375
  const type = types[r.u32()] ?? "other";
11975
- if (!RESERVED_NAMESPACES.has(module)) (foreign[module] ??= {})[field2] = type;
12376
+ if (!RESERVED_NAMESPACES.has(module)) (foreign[module] ??= {})[field3] = type;
11976
12377
  }
11977
12378
  }
11978
12379
  return foreign;