@ai-ecoverse/slicc-kernel 1.54.8 → 1.55.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -4
- package/dist/index.js +40 -10
- package/dist/index.js.map +2 -2
- package/dist/kernel-worker.js +326 -76
- package/dist/kernel-worker.js.map +3 -3
- package/dist/node.js +366 -86
- package/dist/node.js.map +3 -3
- package/package.json +1 -1
package/dist/kernel-worker.js
CHANGED
|
@@ -661,7 +661,7 @@ var OpfsFs = class {
|
|
|
661
661
|
const parent = await this.locate(parentOf2(path), true);
|
|
662
662
|
if (parent.handle?.kind !== "directory") throw fsError("ENOTDIR", path);
|
|
663
663
|
await parent.handle.getDirectoryHandle(baseOf(path), { create: true });
|
|
664
|
-
this.touch(parent.path);
|
|
664
|
+
this.touch(parent.path, `${parent.path === "/" ? "" : parent.path}/${baseOf(path)}`);
|
|
665
665
|
}
|
|
666
666
|
async rm(path, options = {}) {
|
|
667
667
|
let found;
|
|
@@ -725,7 +725,7 @@ var OpfsFs = class {
|
|
|
725
725
|
const swap = targetStat?.isDirectory === true;
|
|
726
726
|
const staging = swap ? `.${name2}.${crypto.randomUUID()}` : name2;
|
|
727
727
|
this.forget(destination);
|
|
728
|
-
const
|
|
728
|
+
const timed2 = await this.explicitTimes(source.path);
|
|
729
729
|
const moved2 = await this.place(source.handle, dir, staging);
|
|
730
730
|
if (swap) await this.rm(destination, { recursive: true });
|
|
731
731
|
await this.meta.move(source.path, destination, carry);
|
|
@@ -737,7 +737,7 @@ var OpfsFs = class {
|
|
|
737
737
|
if (!placed) await dir.removeEntry(staging, { recursive: true });
|
|
738
738
|
copied ||= !placed;
|
|
739
739
|
}
|
|
740
|
-
if (copied) await this.restamp(destination,
|
|
740
|
+
if (copied) await this.restamp(destination, timed2);
|
|
741
741
|
this.changed(source.path, destination);
|
|
742
742
|
this.touch(parentOf2(source.path), parent.path);
|
|
743
743
|
}
|
|
@@ -746,16 +746,16 @@ var OpfsFs = class {
|
|
|
746
746
|
return handle.kind === "file" ? (await handle.getFile()).lastModified : 0;
|
|
747
747
|
}
|
|
748
748
|
async explicitTimes(path) {
|
|
749
|
-
const
|
|
749
|
+
const timed2 = [];
|
|
750
750
|
for (const entry of await this.meta.under(path)) {
|
|
751
751
|
if (entry.mtimeFor === void 0 || entry.link !== void 0) continue;
|
|
752
752
|
const current = await this.modified(entry.path).catch(() => void 0);
|
|
753
|
-
if (current === entry.mtimeFor)
|
|
753
|
+
if (current === entry.mtimeFor) timed2.push(entry.path.slice(path.length));
|
|
754
754
|
}
|
|
755
|
-
return
|
|
755
|
+
return timed2;
|
|
756
756
|
}
|
|
757
|
-
async restamp(path,
|
|
758
|
-
for (const rest2 of
|
|
757
|
+
async restamp(path, timed2) {
|
|
758
|
+
for (const rest2 of timed2) {
|
|
759
759
|
const mtimeFor = await this.modified(path + rest2);
|
|
760
760
|
await this.meta.update(path + rest2, (entry) => entry && { ...entry, mtimeFor });
|
|
761
761
|
}
|
|
@@ -2385,6 +2385,7 @@ var LAST_UID = 6e4;
|
|
|
2385
2385
|
var USERS_GROUP = "users";
|
|
2386
2386
|
var HOME_DIR = /^\/home\/[^/]+$/;
|
|
2387
2387
|
var SYSTEM_PNPM_HOME = "/usr/local/share/pnpm";
|
|
2388
|
+
var PNPM_CONFIG = "minimumReleaseAge: 1440\n";
|
|
2388
2389
|
var isId = (text) => text !== void 0 && /^\d+$/.test(text);
|
|
2389
2390
|
function lines(text) {
|
|
2390
2391
|
return text.split("\n").filter((line, i, all) => line !== "" || i < all.length - 1);
|
|
@@ -2440,6 +2441,7 @@ function userEnv(account, system) {
|
|
|
2440
2441
|
USER: account.name,
|
|
2441
2442
|
LOGNAME: account.name,
|
|
2442
2443
|
PNPM_HOME: pnpm,
|
|
2444
|
+
NPM_CONFIG_PREFIX: account.uid === 0 ? "/usr/local" : `${account.home}/.local`,
|
|
2443
2445
|
PATH: `${pnpm}/bin:/usr/local/bin:/usr/bin:/bin`
|
|
2444
2446
|
};
|
|
2445
2447
|
}
|
|
@@ -2464,6 +2466,18 @@ var UserDb = class {
|
|
|
2464
2466
|
group: parseGroup(await this.read(GROUP, DEFAULT_GROUP))
|
|
2465
2467
|
};
|
|
2466
2468
|
}
|
|
2469
|
+
async provision(row) {
|
|
2470
|
+
const pnpm = `${row.home}/.local/share/pnpm`;
|
|
2471
|
+
if (!await this.fs.exists(pnpm)) {
|
|
2472
|
+
await this.fs.mkdir(pnpm, { recursive: true });
|
|
2473
|
+
await this.fs.chmod(pnpm, row.name.startsWith("scoop-") ? 488 : 448);
|
|
2474
|
+
}
|
|
2475
|
+
const config = `${row.home}/.config/pnpm/config.yaml`;
|
|
2476
|
+
if (!await this.fs.exists(config)) {
|
|
2477
|
+
await this.fs.mkdir(`${row.home}/.config/pnpm`, { recursive: true });
|
|
2478
|
+
await this.fs.writeFile(config, PNPM_CONFIG);
|
|
2479
|
+
}
|
|
2480
|
+
}
|
|
2467
2481
|
async commit(passwd, group, then) {
|
|
2468
2482
|
const before = [await this.read(PASSWD, DEFAULT_PASSWD), await this.read(GROUP, DEFAULT_GROUP)];
|
|
2469
2483
|
try {
|
|
@@ -2537,6 +2551,7 @@ var UserDb = class {
|
|
|
2537
2551
|
const groups = parsed(group);
|
|
2538
2552
|
const found = users.find((r) => r.name === name2);
|
|
2539
2553
|
if (found) {
|
|
2554
|
+
if (found.uid >= FIRST_UID && found.uid <= LAST_UID) await this.provision(found);
|
|
2540
2555
|
remember();
|
|
2541
2556
|
return this.account(found, groups);
|
|
2542
2557
|
}
|
|
@@ -2555,6 +2570,7 @@ var UserDb = class {
|
|
|
2555
2570
|
const fresh = !await this.fs.exists(home);
|
|
2556
2571
|
await this.fs.mkdir(home, { recursive: true });
|
|
2557
2572
|
try {
|
|
2573
|
+
await this.provision(row);
|
|
2558
2574
|
await this.fs.mkdir("/etc", { recursive: true });
|
|
2559
2575
|
await this.commit(formatPasswd(passwd), formatGroup(group));
|
|
2560
2576
|
} catch (err) {
|
|
@@ -5558,17 +5574,22 @@ async function followLinks(fs, path) {
|
|
|
5558
5574
|
}
|
|
5559
5575
|
return current;
|
|
5560
5576
|
}
|
|
5561
|
-
function withCommandDirs(fs, names) {
|
|
5577
|
+
function withCommandDirs(fs, names, userDir = async () => void 0) {
|
|
5562
5578
|
async function children2(path) {
|
|
5563
5579
|
if (path === "/") return ["bin", "usr"];
|
|
5564
5580
|
if (path === "/usr") return ["bin"];
|
|
5565
5581
|
if (path === "/bin" || path === "/usr/bin") return [...await names()];
|
|
5566
|
-
|
|
5582
|
+
const own = await userDir(path);
|
|
5583
|
+
return own?.size ? [...own] : void 0;
|
|
5567
5584
|
}
|
|
5568
5585
|
async function virtual(path) {
|
|
5569
5586
|
if (path === "/usr" || path === "/bin" || path === "/usr/bin") return synthetic(true, path);
|
|
5570
5587
|
const name2 = COMMAND.exec(path)?.[1];
|
|
5571
|
-
|
|
5588
|
+
if (name2 !== void 0) return (await names()).has(name2) ? synthetic(false, path) : void 0;
|
|
5589
|
+
if ((await userDir(path))?.size) return synthetic(true, path);
|
|
5590
|
+
const slash = path.lastIndexOf("/");
|
|
5591
|
+
const own = await userDir(path.slice(0, slash));
|
|
5592
|
+
return own?.has(path.slice(slash + 1)) ? synthetic(false, path) : void 0;
|
|
5572
5593
|
}
|
|
5573
5594
|
async function linked(path) {
|
|
5574
5595
|
return await virtual(path) ?? virtual(await followLinks(fs, path));
|
|
@@ -11818,11 +11839,24 @@ var HostfsClient = class {
|
|
|
11818
11839
|
get maxIo() {
|
|
11819
11840
|
return this.capabilities.maxIo ?? HOSTFS_IO;
|
|
11820
11841
|
}
|
|
11821
|
-
|
|
11842
|
+
retired;
|
|
11843
|
+
stop = new AbortController();
|
|
11844
|
+
get gone() {
|
|
11845
|
+
return this.retired !== void 0;
|
|
11846
|
+
}
|
|
11847
|
+
retire(why) {
|
|
11848
|
+
this.retired ??= why;
|
|
11849
|
+
this.stop.abort();
|
|
11850
|
+
}
|
|
11851
|
+
async send(path, init, handle = false, retried = false, cleanup = false) {
|
|
11852
|
+
if (this.retired && !cleanup) throw fsError2("ENOTCONN", this.retired);
|
|
11853
|
+
const stop = cleanup ? void 0 : this.stop.signal;
|
|
11854
|
+
const signal = init.signal && stop ? AbortSignal.any([init.signal, stop]) : init.signal ?? stop;
|
|
11822
11855
|
let response;
|
|
11823
11856
|
try {
|
|
11824
11857
|
response = await this.fetch(`${this.grant.url}${path}`, {
|
|
11825
11858
|
...init,
|
|
11859
|
+
...signal ? { signal } : {},
|
|
11826
11860
|
credentials: "omit",
|
|
11827
11861
|
headers: {
|
|
11828
11862
|
...init.headers,
|
|
@@ -11859,6 +11893,20 @@ var HostfsClient = class {
|
|
|
11859
11893
|
);
|
|
11860
11894
|
return await response.json();
|
|
11861
11895
|
}
|
|
11896
|
+
async cleanup(op, body) {
|
|
11897
|
+
const response = await this.send(
|
|
11898
|
+
"/api/hostfs",
|
|
11899
|
+
{
|
|
11900
|
+
method: "POST",
|
|
11901
|
+
headers: { "Content-Type": "application/json" },
|
|
11902
|
+
body: JSON.stringify({ op, ...body })
|
|
11903
|
+
},
|
|
11904
|
+
true,
|
|
11905
|
+
false,
|
|
11906
|
+
true
|
|
11907
|
+
);
|
|
11908
|
+
await response.body?.cancel();
|
|
11909
|
+
}
|
|
11862
11910
|
async read(fh, offset, size, ifMatch) {
|
|
11863
11911
|
const response = await this.send(
|
|
11864
11912
|
"/api/hostfs",
|
|
@@ -11926,6 +11974,11 @@ function hostfsHandlers(current) {
|
|
|
11926
11974
|
return fresh(remote);
|
|
11927
11975
|
};
|
|
11928
11976
|
const call = (op, body = {}) => current().call(op, body);
|
|
11977
|
+
const settle3 = (client, restore) => client.call("setattr", restore).catch((err) => {
|
|
11978
|
+
if (!client.gone || !client.cleanup) throw err;
|
|
11979
|
+
void client.cleanup("setattr", restore).catch(() => {
|
|
11980
|
+
});
|
|
11981
|
+
});
|
|
11929
11982
|
async function writable(client, path, flags) {
|
|
11930
11983
|
const { ifMatch: _, ...asked } = flags;
|
|
11931
11984
|
const opening = () => client.call("open", { path: rel(path), ...asked });
|
|
@@ -11936,9 +11989,9 @@ function hostfsHandlers(current) {
|
|
|
11936
11989
|
const mode = (await client.call("stat", { path: rel(path) })).mode ?? 0;
|
|
11937
11990
|
if (mode & 128) throw err;
|
|
11938
11991
|
const restore = { path: rel(path), mode };
|
|
11939
|
-
await client.call("setattr", { path: rel(path), mode: mode | 128 })
|
|
11940
|
-
|
|
11941
|
-
|
|
11992
|
+
const opened2 = await client.call("setattr", { path: rel(path), mode: mode | 128 }).then(opening).catch(async (again) => {
|
|
11993
|
+
await settle3(client, restore).catch(() => {
|
|
11994
|
+
});
|
|
11942
11995
|
throw again;
|
|
11943
11996
|
});
|
|
11944
11997
|
return { opened: opened2, restore };
|
|
@@ -11993,7 +12046,7 @@ function hostfsHandlers(current) {
|
|
|
11993
12046
|
try {
|
|
11994
12047
|
await fresh(remote).client.call("release", { fh: remote.fh }, true);
|
|
11995
12048
|
} finally {
|
|
11996
|
-
if (remote.restore) await current()
|
|
12049
|
+
if (remote.restore) await settle3(current(), remote.restore);
|
|
11997
12050
|
}
|
|
11998
12051
|
},
|
|
11999
12052
|
mkdir: async (path) => void await call("mkdir", { path: rel(path) }),
|
|
@@ -12123,6 +12176,73 @@ function invalidation(event) {
|
|
|
12123
12176
|
return event.paths ?? true;
|
|
12124
12177
|
}
|
|
12125
12178
|
var PORT_REQUEST_MS = 6e4;
|
|
12179
|
+
var HOSTFS_CALL_MS = 2e4;
|
|
12180
|
+
var PORT_BEAT_MS = 1e3;
|
|
12181
|
+
var PORT_DEAD_MS = 1e4;
|
|
12182
|
+
var PORT_LINGER_MS = 1e3;
|
|
12183
|
+
function timed(transport, ms) {
|
|
12184
|
+
const inflight = /* @__PURE__ */ new Set();
|
|
12185
|
+
const guard = (name2, run2, late, expire) => new Promise((resolve, reject) => {
|
|
12186
|
+
let expired = false;
|
|
12187
|
+
const running = run2();
|
|
12188
|
+
inflight.add(running);
|
|
12189
|
+
const done4 = () => inflight.delete(running);
|
|
12190
|
+
running.then(done4, done4);
|
|
12191
|
+
const timer = setTimeout(() => {
|
|
12192
|
+
expired = true;
|
|
12193
|
+
const why = `the host folder did not answer ${name2} within ${ms} ms`;
|
|
12194
|
+
transport.retire?.(why);
|
|
12195
|
+
expire?.(running);
|
|
12196
|
+
reject(fsError2("ENOTCONN", why));
|
|
12197
|
+
}, ms);
|
|
12198
|
+
running.then(
|
|
12199
|
+
(value) => {
|
|
12200
|
+
clearTimeout(timer);
|
|
12201
|
+
if (expired) late?.(value);
|
|
12202
|
+
resolve(value);
|
|
12203
|
+
},
|
|
12204
|
+
(err) => {
|
|
12205
|
+
clearTimeout(timer);
|
|
12206
|
+
reject(err);
|
|
12207
|
+
}
|
|
12208
|
+
);
|
|
12209
|
+
});
|
|
12210
|
+
const cleanup = async (op, body, skip) => {
|
|
12211
|
+
await Promise.allSettled([...inflight].filter((work) => work !== skip));
|
|
12212
|
+
await transport.cleanup?.(op, body);
|
|
12213
|
+
};
|
|
12214
|
+
const release = (opened2) => {
|
|
12215
|
+
const fh = opened2?.fh;
|
|
12216
|
+
if (typeof fh === "number") void cleanup("release", { fh }).catch(() => {
|
|
12217
|
+
});
|
|
12218
|
+
};
|
|
12219
|
+
return {
|
|
12220
|
+
get capabilities() {
|
|
12221
|
+
return transport.capabilities;
|
|
12222
|
+
},
|
|
12223
|
+
get token() {
|
|
12224
|
+
return transport.token;
|
|
12225
|
+
},
|
|
12226
|
+
get maxIo() {
|
|
12227
|
+
return transport.maxIo;
|
|
12228
|
+
},
|
|
12229
|
+
get gone() {
|
|
12230
|
+
return transport.gone;
|
|
12231
|
+
},
|
|
12232
|
+
retire: (why) => transport.retire?.(why),
|
|
12233
|
+
...transport.cleanup ? { cleanup } : {},
|
|
12234
|
+
call: (op, body, handle) => guard(
|
|
12235
|
+
op,
|
|
12236
|
+
() => transport.call(op, body, handle),
|
|
12237
|
+
op === "open" ? release : void 0,
|
|
12238
|
+
op === "release" ? (running) => void cleanup("release", body ?? {}, running).catch(() => {
|
|
12239
|
+
}) : void 0
|
|
12240
|
+
),
|
|
12241
|
+
read: (fh, offset, size, ifMatch) => guard("read", () => transport.read(fh, offset, size, ifMatch)),
|
|
12242
|
+
write: (fh, offset, bytes) => guard("write", () => transport.write(fh, offset, bytes)),
|
|
12243
|
+
watch: (signal, onEvent, onOpen) => transport.watch(signal, onEvent, onOpen)
|
|
12244
|
+
};
|
|
12245
|
+
}
|
|
12126
12246
|
var PORT_MS_PER_MIB = 1e3;
|
|
12127
12247
|
var nextPortToken = 0;
|
|
12128
12248
|
var PortTransport = class {
|
|
@@ -12133,13 +12253,25 @@ var PortTransport = class {
|
|
|
12133
12253
|
waiting = /* @__PURE__ */ new Map();
|
|
12134
12254
|
next = 0;
|
|
12135
12255
|
dead;
|
|
12136
|
-
|
|
12256
|
+
beatMs;
|
|
12257
|
+
deadMs;
|
|
12258
|
+
lingerMs;
|
|
12259
|
+
beat;
|
|
12260
|
+
answers = false;
|
|
12261
|
+
pinged;
|
|
12262
|
+
constructor(grant, liveness = {}) {
|
|
12137
12263
|
this.port = grant.port;
|
|
12138
|
-
this.requestMs = requestMs;
|
|
12264
|
+
this.requestMs = liveness.requestMs ?? PORT_REQUEST_MS;
|
|
12265
|
+
this.beatMs = liveness.beatMs ?? PORT_BEAT_MS;
|
|
12266
|
+
this.deadMs = liveness.deadMs ?? PORT_DEAD_MS;
|
|
12267
|
+
this.lingerMs = liveness.lingerMs ?? PORT_LINGER_MS;
|
|
12139
12268
|
this.capabilities = grant.capabilities ?? {};
|
|
12140
12269
|
this.token = grant.token ?? `port-${++nextPortToken}`;
|
|
12141
12270
|
this.port.addEventListener("message", (event) => {
|
|
12142
|
-
|
|
12271
|
+
if (event.data?.pong) {
|
|
12272
|
+
this.answers = true;
|
|
12273
|
+
this.pinged = void 0;
|
|
12274
|
+
} else this.waiting.get(event.data?.id)?.(event.data);
|
|
12143
12275
|
});
|
|
12144
12276
|
this.port.addEventListener("close", () => this.fail("the folder's port closed"));
|
|
12145
12277
|
this.port.start();
|
|
@@ -12150,8 +12282,51 @@ var PortTransport = class {
|
|
|
12150
12282
|
get gone() {
|
|
12151
12283
|
return this.dead !== void 0;
|
|
12152
12284
|
}
|
|
12285
|
+
retire(why) {
|
|
12286
|
+
this.fail(why);
|
|
12287
|
+
}
|
|
12288
|
+
ping() {
|
|
12289
|
+
if (this.pinged !== void 0) return;
|
|
12290
|
+
this.pinged = Date.now();
|
|
12291
|
+
try {
|
|
12292
|
+
this.port.postMessage({ id: 0, op: "ping" });
|
|
12293
|
+
} catch {
|
|
12294
|
+
}
|
|
12295
|
+
}
|
|
12296
|
+
watchBeat() {
|
|
12297
|
+
if (this.beat || this.dead) return;
|
|
12298
|
+
this.ping();
|
|
12299
|
+
this.beat = setInterval(() => {
|
|
12300
|
+
if (this.waiting.size === 0) {
|
|
12301
|
+
clearInterval(this.beat);
|
|
12302
|
+
this.beat = void 0;
|
|
12303
|
+
return;
|
|
12304
|
+
}
|
|
12305
|
+
if (this.answers && this.pinged !== void 0 && Date.now() - this.pinged > this.deadMs) {
|
|
12306
|
+
this.fail("the folder's port stopped answering");
|
|
12307
|
+
return;
|
|
12308
|
+
}
|
|
12309
|
+
this.ping();
|
|
12310
|
+
}, this.beatMs);
|
|
12311
|
+
}
|
|
12312
|
+
async cleanup(op, body) {
|
|
12313
|
+
if (this.closed) throw fsError2("ENOTCONN", "the folder's port is closed");
|
|
12314
|
+
this.port.postMessage({ id: 0, op: "cleanup", name: op, body });
|
|
12315
|
+
}
|
|
12316
|
+
closed = false;
|
|
12153
12317
|
fail(why) {
|
|
12154
|
-
if (this.dead === void 0)
|
|
12318
|
+
if (this.dead === void 0) {
|
|
12319
|
+
setTimeout(() => {
|
|
12320
|
+
try {
|
|
12321
|
+
this.port.postMessage({ id: 0, op: "bye" });
|
|
12322
|
+
} catch {
|
|
12323
|
+
}
|
|
12324
|
+
this.closed = true;
|
|
12325
|
+
this.port.close();
|
|
12326
|
+
}, this.lingerMs);
|
|
12327
|
+
}
|
|
12328
|
+
clearInterval(this.beat);
|
|
12329
|
+
this.beat = void 0;
|
|
12155
12330
|
this.dead ??= why;
|
|
12156
12331
|
for (const settle3 of [...this.waiting.values()])
|
|
12157
12332
|
settle3({ id: 0, error: { code: "ENOTCONN", message: why } });
|
|
@@ -12168,6 +12343,7 @@ var PortTransport = class {
|
|
|
12168
12343
|
},
|
|
12169
12344
|
this.requestMs + Math.ceil(bytes / 1048576) * PORT_MS_PER_MIB
|
|
12170
12345
|
);
|
|
12346
|
+
this.watchBeat();
|
|
12171
12347
|
this.waiting.set(id2, (reply) => {
|
|
12172
12348
|
clearTimeout(timer);
|
|
12173
12349
|
this.waiting.delete(id2);
|
|
@@ -12214,6 +12390,7 @@ var PortTransport = class {
|
|
|
12214
12390
|
}
|
|
12215
12391
|
resolve();
|
|
12216
12392
|
};
|
|
12393
|
+
this.watchBeat();
|
|
12217
12394
|
this.waiting.set(id2, (reply) => {
|
|
12218
12395
|
if (reply.open) return onOpen();
|
|
12219
12396
|
if (reply.event) return onEvent(reply.event);
|
|
@@ -12231,10 +12408,10 @@ var PortTransport = class {
|
|
|
12231
12408
|
}).finally(() => this.fail("the folder's watch ended"));
|
|
12232
12409
|
}
|
|
12233
12410
|
};
|
|
12234
|
-
function grantConnect(hook, fetch2,
|
|
12411
|
+
function grantConnect(hook, fetch2, liveness = {}) {
|
|
12235
12412
|
return async (source, options) => {
|
|
12236
12413
|
const first = await hook(source, options);
|
|
12237
|
-
if ("port" in first) return new PortTransport(first,
|
|
12414
|
+
if ("port" in first) return new PortTransport(first, liveness);
|
|
12238
12415
|
const grant = async () => {
|
|
12239
12416
|
const again = await hook(source, options);
|
|
12240
12417
|
if ("port" in again)
|
|
@@ -12254,7 +12431,10 @@ async function openHostfs(spec, connect, timing = {}) {
|
|
|
12254
12431
|
const stop = new AbortController();
|
|
12255
12432
|
let active;
|
|
12256
12433
|
const handlers = hostfsHandlers(() => active);
|
|
12257
|
-
const ranged2 = () =>
|
|
12434
|
+
const ranged2 = () => ({
|
|
12435
|
+
...active?.capabilities.ranges === true ? { ranges: true } : {},
|
|
12436
|
+
...active ? { maxIo: Math.min(active.maxIo, HOSTFS_IO) } : {}
|
|
12437
|
+
});
|
|
12258
12438
|
const served = serveFilesystem(
|
|
12259
12439
|
port2,
|
|
12260
12440
|
{ ...slot.handlers, mount: ranged2 },
|
|
@@ -12270,7 +12450,7 @@ async function openHostfs(spec, connect, timing = {}) {
|
|
|
12270
12450
|
{
|
|
12271
12451
|
connect: () => connect(spec.source, { readonly: readonly2 }),
|
|
12272
12452
|
up(client) {
|
|
12273
|
-
active = client;
|
|
12453
|
+
active = timed(client, timing.callMs ?? HOSTFS_CALL_MS);
|
|
12274
12454
|
slot.insert(client, handlers);
|
|
12275
12455
|
served.invalidate(true);
|
|
12276
12456
|
},
|
|
@@ -12760,8 +12940,11 @@ var Launcher = class {
|
|
|
12760
12940
|
createWorker;
|
|
12761
12941
|
modulesDir;
|
|
12762
12942
|
env;
|
|
12763
|
-
|
|
12764
|
-
|
|
12943
|
+
catalogs = /* @__PURE__ */ new Map();
|
|
12944
|
+
ownCatalogs = /* @__PURE__ */ new Map();
|
|
12945
|
+
binfmts = /* @__PURE__ */ new Map();
|
|
12946
|
+
scopes;
|
|
12947
|
+
unwatchScopes = () => void 0;
|
|
12765
12948
|
warned = /* @__PURE__ */ new Set();
|
|
12766
12949
|
compiled = /* @__PURE__ */ new Map();
|
|
12767
12950
|
processes = /* @__PURE__ */ new Map();
|
|
@@ -12841,7 +13024,11 @@ var Launcher = class {
|
|
|
12841
13024
|
ca: this.ca
|
|
12842
13025
|
});
|
|
12843
13026
|
enableCdp(this.net, this.cdp);
|
|
12844
|
-
const fs = withCommandDirs(
|
|
13027
|
+
const fs = withCommandDirs(
|
|
13028
|
+
this.base,
|
|
13029
|
+
async () => new Set((await this.commands()).keys()),
|
|
13030
|
+
(dir) => this.userCommandDir(dir)
|
|
13031
|
+
);
|
|
12845
13032
|
this.nodes = new VfsNodes(fs, (path) => this.released(path));
|
|
12846
13033
|
this.nodes.keepsOnDisk = true;
|
|
12847
13034
|
this.openFiles.add(this.nodes);
|
|
@@ -12859,35 +13046,99 @@ var Launcher = class {
|
|
|
12859
13046
|
this.fs = this.unlinked.wrap(keepingOpen(fs, this.nodes));
|
|
12860
13047
|
this.users = new UserDb(this.fs);
|
|
12861
13048
|
void this.unlinked.sweep("/");
|
|
12862
|
-
this.watchers.watch(
|
|
12863
|
-
this.
|
|
12864
|
-
|
|
13049
|
+
this.watchers.watch(
|
|
13050
|
+
[this.modulesDir, this.pnpmHome],
|
|
13051
|
+
{ recursive: true },
|
|
13052
|
+
() => this.resetCatalogs()
|
|
13053
|
+
);
|
|
13054
|
+
this.watchers.watch([PASSWD], { recursive: false }, () => {
|
|
13055
|
+
this.scopes = void 0;
|
|
13056
|
+
this.resetCatalogs();
|
|
12865
13057
|
});
|
|
12866
13058
|
}
|
|
12867
13059
|
setRoutes(table) {
|
|
12868
13060
|
this.routes.set(table);
|
|
12869
13061
|
}
|
|
12870
|
-
commands() {
|
|
12871
|
-
|
|
12872
|
-
|
|
13062
|
+
commands(scope = "") {
|
|
13063
|
+
let found = this.catalogs.get(scope);
|
|
13064
|
+
if (!found) {
|
|
13065
|
+
found = this.roots(scope).then((roots) => scanCommands(this.base, roots));
|
|
13066
|
+
this.catalogs.set(scope, found);
|
|
13067
|
+
}
|
|
13068
|
+
return found;
|
|
12873
13069
|
}
|
|
12874
|
-
|
|
12875
|
-
|
|
12876
|
-
|
|
12877
|
-
|
|
12878
|
-
|
|
12879
|
-
|
|
12880
|
-
|
|
12881
|
-
|
|
12882
|
-
|
|
13070
|
+
ownCommands(scope) {
|
|
13071
|
+
let found = this.ownCatalogs.get(scope);
|
|
13072
|
+
if (!found) {
|
|
13073
|
+
found = pnpmGlobalRoots(this.base, scope).then((roots) => scanCommands(this.base, roots)).then((commands) => new Set(commands.keys()));
|
|
13074
|
+
this.ownCatalogs.set(scope, found);
|
|
13075
|
+
}
|
|
13076
|
+
return found;
|
|
13077
|
+
}
|
|
13078
|
+
interpreters(scope = "") {
|
|
13079
|
+
let found = this.binfmts.get(scope);
|
|
13080
|
+
if (!found) {
|
|
13081
|
+
found = this.roots(scope).then(
|
|
13082
|
+
(roots) => scanBinfmts(this.base, roots, (message3) => {
|
|
13083
|
+
if (this.warned.has(message3)) return;
|
|
13084
|
+
this.warned.add(message3);
|
|
13085
|
+
console.warn(message3);
|
|
13086
|
+
})
|
|
13087
|
+
);
|
|
13088
|
+
this.binfmts.set(scope, found);
|
|
13089
|
+
}
|
|
13090
|
+
return found;
|
|
12883
13091
|
}
|
|
12884
|
-
async roots() {
|
|
12885
|
-
|
|
13092
|
+
async roots(scope = "") {
|
|
13093
|
+
const system = [this.modulesDir, ...await pnpmGlobalRoots(this.base, this.pnpmHome)];
|
|
13094
|
+
return scope ? [...await pnpmGlobalRoots(this.base, scope), ...system] : system;
|
|
13095
|
+
}
|
|
13096
|
+
resetCatalogs() {
|
|
13097
|
+
this.catalogs.clear();
|
|
13098
|
+
this.ownCatalogs.clear();
|
|
13099
|
+
this.binfmts.clear();
|
|
13100
|
+
}
|
|
13101
|
+
userScopes() {
|
|
13102
|
+
this.scopes ??= this.users.list().then(
|
|
13103
|
+
(accounts) => {
|
|
13104
|
+
const users = accounts.filter((account) => account.uid !== 0);
|
|
13105
|
+
const homes = users.map((account) => pnpmHomeOf(account, this.pnpmHome));
|
|
13106
|
+
this.unwatchScopes();
|
|
13107
|
+
this.unwatchScopes = this.watchers.watch(
|
|
13108
|
+
homes,
|
|
13109
|
+
{ recursive: true },
|
|
13110
|
+
() => this.resetCatalogs()
|
|
13111
|
+
);
|
|
13112
|
+
return {
|
|
13113
|
+
byUid: new Map(users.map((account, i) => [account.uid, homes[i]])),
|
|
13114
|
+
byBin: new Map(homes.map((home) => [`${home}/bin`, home]))
|
|
13115
|
+
};
|
|
13116
|
+
},
|
|
13117
|
+
() => ({ byUid: /* @__PURE__ */ new Map(), byBin: /* @__PURE__ */ new Map() })
|
|
13118
|
+
);
|
|
13119
|
+
return this.scopes;
|
|
13120
|
+
}
|
|
13121
|
+
async userCommandDir(dir) {
|
|
13122
|
+
const scope = (await this.userScopes()).byBin.get(dir);
|
|
13123
|
+
return scope === void 0 ? void 0 : this.ownCommands(scope);
|
|
13124
|
+
}
|
|
13125
|
+
async scopeOf(uid) {
|
|
13126
|
+
return (await this.userScopes()).byUid.get(uid) ?? "";
|
|
13127
|
+
}
|
|
13128
|
+
async commandAt(file, scope) {
|
|
13129
|
+
const system = COMMAND2.exec(file)?.[1];
|
|
13130
|
+
if (system !== void 0) return (await this.commands()).get(system);
|
|
13131
|
+
if (!file.includes("/")) return (await this.commands(scope)).get(file);
|
|
13132
|
+
const slash = file.lastIndexOf("/");
|
|
13133
|
+
const owner = (await this.userScopes()).byBin.get(file.slice(0, slash));
|
|
13134
|
+
if (owner === void 0 || !(await this.ownCommands(owner)).has(file.slice(slash + 1))) {
|
|
13135
|
+
return void 0;
|
|
13136
|
+
}
|
|
13137
|
+
return (await this.commands(owner)).get(file.slice(slash + 1));
|
|
12886
13138
|
}
|
|
12887
|
-
async resolve(file, argv0, cwd) {
|
|
12888
|
-
|
|
12889
|
-
|
|
12890
|
-
const command = (await this.commands()).get(name2);
|
|
13139
|
+
async resolve(file, argv0, cwd, scope = "") {
|
|
13140
|
+
if (!file.includes("/") || COMMAND2.test(file)) {
|
|
13141
|
+
const command = await this.commandAt(file, scope);
|
|
12891
13142
|
return command && !command.script ? targetOf(command) : void 0;
|
|
12892
13143
|
}
|
|
12893
13144
|
const path = this.fs.resolvePath(cwd, file);
|
|
@@ -12898,6 +13149,8 @@ var Launcher = class {
|
|
|
12898
13149
|
const byPath = !COMMAND2.test(path) && (await this.commands()).get(linked)?.argv0Path === true;
|
|
12899
13150
|
return target && byPath ? { ...target, argv0: path } : target;
|
|
12900
13151
|
}
|
|
13152
|
+
const own = await this.commandAt(glue, scope);
|
|
13153
|
+
if (own) return own.script ? void 0 : targetOf(own);
|
|
12901
13154
|
const head = await this.head(glue);
|
|
12902
13155
|
if (!head) return void 0;
|
|
12903
13156
|
if (isWasm(head)) {
|
|
@@ -12920,45 +13173,45 @@ var Launcher = class {
|
|
|
12920
13173
|
return void 0;
|
|
12921
13174
|
}
|
|
12922
13175
|
}
|
|
12923
|
-
async scriptCommand(file) {
|
|
12924
|
-
const
|
|
12925
|
-
|
|
12926
|
-
const command =
|
|
13176
|
+
async scriptCommand(file, cwd, scope) {
|
|
13177
|
+
const direct = !file.includes("/") || COMMAND2.test(file);
|
|
13178
|
+
const at = direct ? file : await followLinks(this.base, this.fs.resolvePath(cwd, file));
|
|
13179
|
+
const command = await this.commandAt(at, scope);
|
|
12927
13180
|
return command?.script ? command : void 0;
|
|
12928
13181
|
}
|
|
12929
|
-
async interpreted(file, argv, cwd, depth = 0) {
|
|
12930
|
-
const command = await this.scriptCommand(file);
|
|
13182
|
+
async interpreted(file, argv, cwd, scope, depth = 0) {
|
|
13183
|
+
const command = await this.scriptCommand(file, cwd, scope);
|
|
12931
13184
|
const script = command?.script ?? this.fs.resolvePath(cwd, file);
|
|
12932
13185
|
const head = await this.head(script);
|
|
12933
13186
|
if (!head) return void 0;
|
|
12934
|
-
const binfmt = isWasm(head) ? void 0 : binfmtOf(await this.interpreters(), script);
|
|
13187
|
+
const binfmt = isWasm(head) ? void 0 : binfmtOf(await this.interpreters(scope), script);
|
|
12935
13188
|
const words = shebang(head) ?? (binfmt ? [binfmt] : void 0);
|
|
12936
13189
|
if (!words) return void 0;
|
|
12937
13190
|
if (baseName(words[0]) === "env") words.shift();
|
|
12938
13191
|
const [interp, ...rest2] = words;
|
|
12939
13192
|
const arg = rest2.join(" ");
|
|
12940
13193
|
const passed = [...arg ? [arg] : [], command ? script : file, ...argv.slice(1)];
|
|
12941
|
-
const found = interp ? await this.resolve(interp, interp, cwd) : void 0;
|
|
13194
|
+
const found = interp ? await this.resolve(interp, interp, cwd, scope) : void 0;
|
|
12942
13195
|
if (!found) {
|
|
12943
|
-
if (!interp || depth >= MAX_INTERPRETERS || !await this.scriptCommand(interp)) {
|
|
13196
|
+
if (!interp || depth >= MAX_INTERPRETERS || !await this.scriptCommand(interp, cwd, scope)) {
|
|
12944
13197
|
return void 0;
|
|
12945
13198
|
}
|
|
12946
|
-
const inner = await this.interpreted(interp, [interp, ...passed], cwd, depth + 1);
|
|
13199
|
+
const inner = await this.interpreted(interp, [interp, ...passed], cwd, scope, depth + 1);
|
|
12947
13200
|
return inner && { ...inner, target: withScriptEnv(inner.target, command) };
|
|
12948
13201
|
}
|
|
12949
13202
|
const target = withScriptEnv(found, command);
|
|
12950
13203
|
return { target, args: [...target.prefix ?? [], ...passed] };
|
|
12951
13204
|
}
|
|
12952
|
-
async plan(file, argv, cwd) {
|
|
12953
|
-
const direct = await this.resolve(file, argv[0] ?? file, cwd);
|
|
13205
|
+
async plan(file, argv, cwd, scope) {
|
|
13206
|
+
const direct = await this.resolve(file, argv[0] ?? file, cwd, scope);
|
|
12954
13207
|
if (direct) return { target: direct, args: [...direct.prefix ?? [], ...argv.slice(1)] };
|
|
12955
|
-
return this.interpreted(file, argv, cwd);
|
|
13208
|
+
return this.interpreted(file, argv, cwd, scope);
|
|
12956
13209
|
}
|
|
12957
|
-
async unrunnable(file, cwd) {
|
|
13210
|
+
async unrunnable(file, cwd, scope) {
|
|
12958
13211
|
const path = this.fs.resolvePath(cwd, file);
|
|
12959
13212
|
const head = await this.base.readFileBuffer(path).catch(() => null);
|
|
12960
13213
|
if (!head || head[0] === 35 && head[1] === 33) return "ENOENT";
|
|
12961
|
-
return binfmtOf(await this.interpreters(), path) ? "ENOENT" : "ENOEXEC";
|
|
13214
|
+
return binfmtOf(await this.interpreters(scope), path) ? "ENOENT" : "ENOEXEC";
|
|
12962
13215
|
}
|
|
12963
13216
|
module(path) {
|
|
12964
13217
|
return this.base.stat(path).then((st) => {
|
|
@@ -13168,10 +13421,11 @@ var Launcher = class {
|
|
|
13168
13421
|
}
|
|
13169
13422
|
spawner(ppid, report) {
|
|
13170
13423
|
return async (req, fds) => {
|
|
13171
|
-
const
|
|
13424
|
+
const scope = await this.scopeOf(this.credOf(ppid).euid);
|
|
13425
|
+
const planned = await this.plan(req.file, req.argv, req.cwd, scope);
|
|
13172
13426
|
if (!planned) {
|
|
13173
13427
|
await fds.closeAll();
|
|
13174
|
-
throw new SpawnError(await this.unrunnable(req.file, req.cwd));
|
|
13428
|
+
throw new SpawnError(await this.unrunnable(req.file, req.cwd, scope));
|
|
13175
13429
|
}
|
|
13176
13430
|
const exec = req.exec ? { exec: true } : {};
|
|
13177
13431
|
const deciding = req.exec ? void 0 : this.undecided(ppid);
|
|
@@ -13290,11 +13544,7 @@ var Launcher = class {
|
|
|
13290
13544
|
throw fsError("ENODEV", "this kernel has no hostfs hook (createKernel({ hostfs }))");
|
|
13291
13545
|
return openHostfs(
|
|
13292
13546
|
spec,
|
|
13293
|
-
grantConnect(
|
|
13294
|
-
hostfs,
|
|
13295
|
-
hostfsFetch ?? ((url, init) => fetch(url, init)),
|
|
13296
|
-
hostfsTiming?.requestMs
|
|
13297
|
-
),
|
|
13547
|
+
grantConnect(hostfs, hostfsFetch ?? ((url, init) => fetch(url, init)), hostfsTiming),
|
|
13298
13548
|
hostfsTiming
|
|
13299
13549
|
);
|
|
13300
13550
|
}
|
|
@@ -13477,18 +13727,18 @@ var Launcher = class {
|
|
|
13477
13727
|
...account.umask !== void 0 ? { umask: account.umask } : {}
|
|
13478
13728
|
};
|
|
13479
13729
|
}
|
|
13480
|
-
async starting(argv, dir) {
|
|
13481
|
-
this.
|
|
13482
|
-
|
|
13730
|
+
async starting(argv, dir, account) {
|
|
13731
|
+
this.resetCatalogs();
|
|
13732
|
+
const scope = account.uid === 0 ? "" : pnpmHomeOf(account, this.pnpmHome);
|
|
13483
13733
|
const start2 = dir ?? "/";
|
|
13484
13734
|
const cwd = await physicalPathAsync(this.base, start2.startsWith("/") ? start2 : `/${start2}`);
|
|
13485
13735
|
const [file = ""] = argv;
|
|
13486
13736
|
await this.base.mkdir(cwd, { recursive: true });
|
|
13487
|
-
return { cwd, file, planned: await this.plan(file, argv, cwd) };
|
|
13737
|
+
return { cwd, file, planned: await this.plan(file, argv, cwd, scope) };
|
|
13488
13738
|
}
|
|
13489
13739
|
async openTerminal(argv, options) {
|
|
13490
13740
|
const account = await this.account(options.user);
|
|
13491
|
-
const { cwd, file, planned } = await this.starting(argv, options.cwd);
|
|
13741
|
+
const { cwd, file, planned } = await this.starting(argv, options.cwd, account);
|
|
13492
13742
|
if (!planned) throw new Error(`${file}: command not found`);
|
|
13493
13743
|
let leader = 0;
|
|
13494
13744
|
const tty = new KernelTty(
|
|
@@ -13531,7 +13781,7 @@ var Launcher = class {
|
|
|
13531
13781
|
}
|
|
13532
13782
|
async run(argv, options = {}) {
|
|
13533
13783
|
const account = await this.account(options.user);
|
|
13534
|
-
const { cwd, file, planned } = await this.starting(argv, options.cwd);
|
|
13784
|
+
const { cwd, file, planned } = await this.starting(argv, options.cwd, account);
|
|
13535
13785
|
const env = this.environment(cwd, options.env, account);
|
|
13536
13786
|
const out = [];
|
|
13537
13787
|
const err = [];
|