@ai-ecoverse/slicc-kernel 1.85.0 → 1.86.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 +14 -8
- package/dist/index.js +1 -0
- package/dist/index.js.map +2 -2
- package/dist/kernel-worker.js +97 -20
- package/dist/kernel-worker.js.map +2 -2
- package/dist/meta.js +384 -0
- package/dist/meta.js.map +7 -0
- package/dist/node-process-worker.js +69 -15
- package/dist/node-process-worker.js.map +3 -3
- package/dist/node.js +74 -20
- package/dist/node.js.map +2 -2
- package/dist/process-worker.js +69 -15
- package/dist/process-worker.js.map +3 -3
- package/package.json +3 -2
package/dist/kernel-worker.js
CHANGED
|
@@ -97,6 +97,9 @@ var MemoryMeta = class {
|
|
|
97
97
|
async get(paths) {
|
|
98
98
|
return paths.map((path) => this.entries.get(path));
|
|
99
99
|
}
|
|
100
|
+
async fresh(path) {
|
|
101
|
+
return this.entries.get(path);
|
|
102
|
+
}
|
|
100
103
|
async update(path, change) {
|
|
101
104
|
this.set(path, change(this.entries.get(path)));
|
|
102
105
|
}
|
|
@@ -193,6 +196,16 @@ var IndexedDbMeta = class {
|
|
|
193
196
|
}
|
|
194
197
|
return paths.map((path) => this.cache.get(path) ?? void 0);
|
|
195
198
|
}
|
|
199
|
+
async fresh(path) {
|
|
200
|
+
const [transaction, store] = this.transaction("readonly");
|
|
201
|
+
const request2 = store.get(path);
|
|
202
|
+
let entry;
|
|
203
|
+
request2.onsuccess = () => {
|
|
204
|
+
entry = request2.result ?? void 0;
|
|
205
|
+
};
|
|
206
|
+
await settle(transaction, () => void 0);
|
|
207
|
+
return entry;
|
|
208
|
+
}
|
|
196
209
|
async update(path, change) {
|
|
197
210
|
this.settleRemoves();
|
|
198
211
|
const [transaction, store] = this.transaction("readwrite");
|
|
@@ -207,6 +220,19 @@ var IndexedDbMeta = class {
|
|
|
207
220
|
this.changed({ paths: [path] });
|
|
208
221
|
this.cache.set(path, next2 ?? null);
|
|
209
222
|
}
|
|
223
|
+
async updateMany(changes) {
|
|
224
|
+
const [transaction, store] = this.transaction("readwrite");
|
|
225
|
+
for (const { path, change } of changes) {
|
|
226
|
+
const request2 = store.get(path);
|
|
227
|
+
request2.onsuccess = () => store.put(change(request2.result));
|
|
228
|
+
}
|
|
229
|
+
await settle(transaction, () => void 0);
|
|
230
|
+
this.changed({ paths: changes.map(({ path }) => path) });
|
|
231
|
+
}
|
|
232
|
+
close() {
|
|
233
|
+
this.channel.close();
|
|
234
|
+
this.db.close();
|
|
235
|
+
}
|
|
210
236
|
async move(from, to, root) {
|
|
211
237
|
this.settleRemoves();
|
|
212
238
|
const [transaction, store] = this.transaction("readwrite");
|
|
@@ -326,6 +352,12 @@ async function lutimesOf(fs, path, atime, mtime) {
|
|
|
326
352
|
function mayLink(fs, path) {
|
|
327
353
|
return fs.links?.(path) ?? true;
|
|
328
354
|
}
|
|
355
|
+
function modeOption(mode) {
|
|
356
|
+
if (!Number.isInteger(mode) || mode < 0 || mode > 4095) {
|
|
357
|
+
throw fsError("EINVAL", `not a mode: ${String(mode)}`);
|
|
358
|
+
}
|
|
359
|
+
return mode;
|
|
360
|
+
}
|
|
329
361
|
function fsError(code, path) {
|
|
330
362
|
return Object.assign(new Error(`${code}: ${path}`), { code });
|
|
331
363
|
}
|
|
@@ -857,7 +889,8 @@ function sidecar(meta) {
|
|
|
857
889
|
const guarded2 = (op) => (...args) => meta[op].apply(meta, args).catch((err) => {
|
|
858
890
|
throw translate(err, pathOf(args), "sidecar", false);
|
|
859
891
|
});
|
|
860
|
-
const
|
|
892
|
+
const names = meta.fresh ? [...META_OPS, "fresh"] : META_OPS;
|
|
893
|
+
const ops = Object.fromEntries(names.map((op) => [op, guarded2(op)]));
|
|
861
894
|
if (meta.absent) ops.absent = meta.absent.bind(meta);
|
|
862
895
|
const { removeFile } = meta;
|
|
863
896
|
if (removeFile)
|
|
@@ -985,6 +1018,24 @@ var OpfsFs = class {
|
|
|
985
1018
|
committed(target) {
|
|
986
1019
|
if (this.remote?.watched()) this.remote.wrote(target);
|
|
987
1020
|
}
|
|
1021
|
+
counted = [];
|
|
1022
|
+
async stamp(path) {
|
|
1023
|
+
const entry = this.meta.fresh ? await this.meta.fresh(path) : (await this.meta.get([path]))[0];
|
|
1024
|
+
return String(entry?.writes ?? 0);
|
|
1025
|
+
}
|
|
1026
|
+
async counting(target) {
|
|
1027
|
+
if (!isProtected(this.counted, target)) return;
|
|
1028
|
+
await this.meta.update(target, (entry) => ({
|
|
1029
|
+
...entry,
|
|
1030
|
+
path: target,
|
|
1031
|
+
writes: (entry?.writes ?? 0) + 1
|
|
1032
|
+
}));
|
|
1033
|
+
}
|
|
1034
|
+
async recounting(handle, target) {
|
|
1035
|
+
if (this.counted.length === 0) return;
|
|
1036
|
+
const where = await this.root.resolve(handle).catch(() => null);
|
|
1037
|
+
await this.counting(where ? `/${where.join("/")}` : target);
|
|
1038
|
+
}
|
|
988
1039
|
resolvePath(base, path) {
|
|
989
1040
|
return resolvePath(base, path);
|
|
990
1041
|
}
|
|
@@ -1043,6 +1094,7 @@ var OpfsFs = class {
|
|
|
1043
1094
|
guarded = [];
|
|
1044
1095
|
protect(prefixes2) {
|
|
1045
1096
|
this.guarded = prefixes2;
|
|
1097
|
+
this.counted = prefixes2;
|
|
1046
1098
|
}
|
|
1047
1099
|
unguarded() {
|
|
1048
1100
|
return Object.create(this, { guarded: { value: [] } });
|
|
@@ -1379,9 +1431,10 @@ var OpfsFs = class {
|
|
|
1379
1431
|
return this.retrying(
|
|
1380
1432
|
path,
|
|
1381
1433
|
async () => {
|
|
1434
|
+
const stamp = await this.stamp(path);
|
|
1382
1435
|
const file = await handle.getFile();
|
|
1383
1436
|
const bytes = new Uint8Array(await file.arrayBuffer());
|
|
1384
|
-
return { bytes, version: `${file.lastModified}:${file.size}` };
|
|
1437
|
+
return { bytes, version: `${file.lastModified}:${file.size}:${stamp}` };
|
|
1385
1438
|
},
|
|
1386
1439
|
false
|
|
1387
1440
|
);
|
|
@@ -1391,8 +1444,9 @@ var OpfsFs = class {
|
|
|
1391
1444
|
return this.retrying(
|
|
1392
1445
|
path,
|
|
1393
1446
|
async () => {
|
|
1447
|
+
const stamp = await this.stamp(path);
|
|
1394
1448
|
const file = await handle.getFile();
|
|
1395
|
-
return `${file.lastModified}:${file.size}`;
|
|
1449
|
+
return `${file.lastModified}:${file.size}:${stamp}`;
|
|
1396
1450
|
},
|
|
1397
1451
|
false
|
|
1398
1452
|
);
|
|
@@ -1407,14 +1461,24 @@ var OpfsFs = class {
|
|
|
1407
1461
|
}
|
|
1408
1462
|
async pwrite(path, offset, bytes) {
|
|
1409
1463
|
const [handle, , target] = await this.fileFor(path);
|
|
1410
|
-
await this.
|
|
1464
|
+
await this.counting(target);
|
|
1465
|
+
try {
|
|
1466
|
+
await this.retrying(path, () => positioned(handle, (io) => io.write(offset, bytes)), true);
|
|
1467
|
+
} finally {
|
|
1468
|
+
await this.recounting(handle, target);
|
|
1469
|
+
}
|
|
1411
1470
|
this.written(target);
|
|
1412
1471
|
}
|
|
1413
1472
|
async truncate(path, size) {
|
|
1414
1473
|
const handle = await this.existing(path, true);
|
|
1415
1474
|
const resolve2 = this.ranged || this.remote?.watched();
|
|
1416
|
-
const target = resolve2 ? (await this.locate(path, true)).path : path;
|
|
1417
|
-
await this.
|
|
1475
|
+
const target = resolve2 || this.counted.length > 0 ? (await this.locate(path, true)).path : path;
|
|
1476
|
+
await this.counting(target);
|
|
1477
|
+
try {
|
|
1478
|
+
await this.retrying(path, () => positioned(handle, (io) => io.truncate(size)), true);
|
|
1479
|
+
} finally {
|
|
1480
|
+
await this.recounting(handle, target);
|
|
1481
|
+
}
|
|
1418
1482
|
this.written(target);
|
|
1419
1483
|
}
|
|
1420
1484
|
async writeSession(path, truncate) {
|
|
@@ -2339,7 +2403,9 @@ function id(value) {
|
|
|
2339
2403
|
return value;
|
|
2340
2404
|
}
|
|
2341
2405
|
function changeCred(cur, change) {
|
|
2342
|
-
if (typeof change !== "object" || change === null
|
|
2406
|
+
if (typeof change !== "object" || change === null || Array.isArray(change)) {
|
|
2407
|
+
throw fsError("EINVAL", "not a change");
|
|
2408
|
+
}
|
|
2343
2409
|
const privileged = cur.euid === 0;
|
|
2344
2410
|
const next2 = copyCred(cur);
|
|
2345
2411
|
for (const keys of [UIDS, GIDS]) {
|
|
@@ -11843,7 +11909,7 @@ function ptySyscall(req, ctx) {
|
|
|
11843
11909
|
const pair = ctx.ptys.get(req.n);
|
|
11844
11910
|
ttyOpenable(ctx.guard, pair.slave);
|
|
11845
11911
|
const slave = pair.openSlave();
|
|
11846
|
-
const fd = ctx.fds.install(ctx.
|
|
11912
|
+
const fd = ctx.fds.install(ctx.outputFilter?.(slave) ?? slave, 3);
|
|
11847
11913
|
if (!req.noctty) ctx.jobs?.acquireTerminal(ctx.pid, pair.slave);
|
|
11848
11914
|
return json4(fd);
|
|
11849
11915
|
}
|
|
@@ -13009,8 +13075,8 @@ var WasmProcess = class {
|
|
|
13009
13075
|
const { ptys, jobs } = this.options;
|
|
13010
13076
|
const owner = this.options.owners ? this.ttyOwner() : void 0;
|
|
13011
13077
|
const guard2 = this.guarded();
|
|
13012
|
-
const {
|
|
13013
|
-
const ctx = { pid: this.pid, fds: this.fds, ptys, jobs, guard: guard2, owner,
|
|
13078
|
+
const { outputFilter } = this.options;
|
|
13079
|
+
const ctx = { pid: this.pid, fds: this.fds, ptys, jobs, guard: guard2, owner, outputFilter };
|
|
13014
13080
|
return ptySyscall(req, ctx);
|
|
13015
13081
|
}
|
|
13016
13082
|
return await this.procSyscall(req, cancelled);
|
|
@@ -13187,7 +13253,7 @@ var WasmProcess = class {
|
|
|
13187
13253
|
if (!tty) throw new KernelError("ENXIO");
|
|
13188
13254
|
if (name2 !== void 0) ttyOpenable(this.guarded(), tty);
|
|
13189
13255
|
const file = tty.file();
|
|
13190
|
-
return this.fds.install(this.options.
|
|
13256
|
+
return this.fds.install(this.options.outputFilter?.(file) ?? file, 3);
|
|
13191
13257
|
}
|
|
13192
13258
|
openSealed() {
|
|
13193
13259
|
const broker = this.options.sealed;
|
|
@@ -13199,7 +13265,8 @@ var WasmProcess = class {
|
|
|
13199
13265
|
if (!broker) throw new KernelError("ENOENT");
|
|
13200
13266
|
const mode = flags2 & WRITE_ACCESS;
|
|
13201
13267
|
const access2 = mode === 0 ? "read" : mode === 1 ? "write" : "both";
|
|
13202
|
-
|
|
13268
|
+
const file = broker.open(access2, await this.clipboardStamp());
|
|
13269
|
+
return this.fds.install(this.options.outputFilter?.(file) ?? file, 3);
|
|
13203
13270
|
}
|
|
13204
13271
|
async clipboardStamp() {
|
|
13205
13272
|
const shown = await this.options.identity?.();
|
|
@@ -13998,7 +14065,7 @@ function processOptions(opts, header3, hooks, created3) {
|
|
|
13998
14065
|
...inherited(opts),
|
|
13999
14066
|
...opts.owners ? { owners: true } : {},
|
|
14000
14067
|
...opts.sealed ? { sealed: opts.sealed } : {},
|
|
14001
|
-
...opts.
|
|
14068
|
+
...opts.outputFilter ? { outputFilter: opts.outputFilter } : {},
|
|
14002
14069
|
...opts.clipboard ? { clipboard: opts.clipboard, ...clipboardName(opts) } : {},
|
|
14003
14070
|
...opts.readonlyAt ? { readonlyAt: opts.readonlyAt } : {},
|
|
14004
14071
|
...opts.dac ? { guard: { dac: opts.dac, fs: opts.fs, created: created3 } } : {},
|
|
@@ -15000,7 +15067,7 @@ function scrubStdio(fds, scrubber) {
|
|
|
15000
15067
|
const stdio = stdioFiles(fds);
|
|
15001
15068
|
for (const fd of fds.numbers()) {
|
|
15002
15069
|
const original = fds.get(fd);
|
|
15003
|
-
if (!stdio.has(original) && !original.file.tty) continue;
|
|
15070
|
+
if (!stdio.has(original) && !original.file.tty && !original.file.clipboard) continue;
|
|
15004
15071
|
const known = wrapped.get(original);
|
|
15005
15072
|
const flags2 = fds.statusFlags(fd);
|
|
15006
15073
|
const wrapper = known ? known.retain() : scrubbed(original.retain(), scrubber);
|
|
@@ -18079,7 +18146,7 @@ var Launcher = class {
|
|
|
18079
18146
|
...this.owners && req.program.abi === "wasi" ? { fresh: (path, umask) => this.freshModules.add(path, umask, pid) } : {},
|
|
18080
18147
|
...this.owners ? { owners: true } : {},
|
|
18081
18148
|
sealed: this.sealed,
|
|
18082
|
-
...scrubs ? {
|
|
18149
|
+
...scrubs ? { outputFilter: (file) => scrubbedAll(file, scrubs) } : {},
|
|
18083
18150
|
clipboard: this.clipboard,
|
|
18084
18151
|
...this.dac ? { dac: this.dac } : {},
|
|
18085
18152
|
program: req.program,
|
|
@@ -18612,17 +18679,21 @@ var Launcher = class {
|
|
|
18612
18679
|
const real = await this.realLayoutPath("/tmp");
|
|
18613
18680
|
const st = real === void 0 ? void 0 : await this.base.lstat(real).catch(() => void 0);
|
|
18614
18681
|
if (real !== void 0 && st?.isDirectory && this.base.hasOwner && !await this.base.hasOwner(real)) {
|
|
18682
|
+
const names = await this.base.readdir(real).catch(() => void 0);
|
|
18615
18683
|
let removed = 0;
|
|
18616
|
-
|
|
18684
|
+
let left = names === void 0 ? 1 : 0;
|
|
18685
|
+
for (const name2 of names ?? []) {
|
|
18617
18686
|
const path = joinName(real, name2);
|
|
18618
|
-
if (await this.base.hasOwner(path)
|
|
18619
|
-
const failed3 = await this.base.rm(path, { recursive: true, force: true }).catch(String);
|
|
18687
|
+
if (await this.base.hasOwner(path)) continue;
|
|
18688
|
+
const failed3 = this.inUse(path) ? "busy" : await this.base.rm(path, { recursive: true, force: true }).catch(String);
|
|
18620
18689
|
if (failed3 === void 0) removed++;
|
|
18690
|
+
else left++;
|
|
18621
18691
|
}
|
|
18622
18692
|
if (removed > 0) {
|
|
18623
18693
|
console.warn(`slicc-kernel users: removed ${removed} entries from /tmp that had no owner`);
|
|
18624
18694
|
}
|
|
18625
|
-
|
|
18695
|
+
if (left === 0)
|
|
18696
|
+
await this.base.chown?.(real, { uid: 0, gid: 0, mode: 1023, follow: false });
|
|
18626
18697
|
}
|
|
18627
18698
|
if (st?.isDirectory) await this.base.chmod(real, 1023);
|
|
18628
18699
|
}
|
|
@@ -19075,7 +19146,12 @@ var USERS_OPS = /* @__PURE__ */ new Set([
|
|
|
19075
19146
|
"groups-add-member",
|
|
19076
19147
|
"groups-remove-member"
|
|
19077
19148
|
]);
|
|
19078
|
-
var ATTEST_OPS = /* @__PURE__ */ new Set([
|
|
19149
|
+
var ATTEST_OPS = /* @__PURE__ */ new Set([
|
|
19150
|
+
"attest",
|
|
19151
|
+
"watch-files",
|
|
19152
|
+
"unwatch-files",
|
|
19153
|
+
"chmod"
|
|
19154
|
+
]);
|
|
19079
19155
|
function isAttestRequest(req) {
|
|
19080
19156
|
return ATTEST_OPS.has(req.op);
|
|
19081
19157
|
}
|
|
@@ -19091,6 +19167,7 @@ function attestOps(port) {
|
|
|
19091
19167
|
const watches = /* @__PURE__ */ new Map();
|
|
19092
19168
|
return async (l, req) => {
|
|
19093
19169
|
if (req.op === "attest") return l.attest(req.path);
|
|
19170
|
+
if (req.op === "chmod") return l.fs.chmod(req.path, modeOption(req.mode)).then(() => true);
|
|
19094
19171
|
if (req.op === "unwatch-files") {
|
|
19095
19172
|
watches.get(req.watch)?.();
|
|
19096
19173
|
return watches.delete(req.watch);
|