@ai-ecoverse/slicc-kernel 1.13.0 → 1.15.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 +19 -2
- package/dist/index.js +28 -9
- package/dist/index.js.map +2 -2
- package/dist/kernel-worker.js +296 -29
- package/dist/kernel-worker.js.map +4 -4
- package/dist/node-process-worker.js +3 -0
- package/dist/node-process-worker.js.map +2 -2
- package/dist/node.js +256 -20
- package/dist/node.js.map +4 -4
- package/dist/process-worker.js +3 -0
- package/dist/process-worker.js.map +2 -2
- package/package.json +2 -1
package/dist/node.js
CHANGED
|
@@ -585,7 +585,8 @@ var ERRNO_BY_DOM_ERROR = {
|
|
|
585
585
|
TypeMismatchError: "ENOTDIR",
|
|
586
586
|
InvalidModificationError: "ENOTEMPTY",
|
|
587
587
|
NoModificationAllowedError: "EBUSY",
|
|
588
|
-
TypeError: "EINVAL"
|
|
588
|
+
TypeError: "EINVAL",
|
|
589
|
+
NotAllowedError: "EACCES"
|
|
589
590
|
};
|
|
590
591
|
function translate(err, path) {
|
|
591
592
|
if (typeof err?.code === "string") return err;
|
|
@@ -1168,9 +1169,28 @@ async function packages(fs, modules) {
|
|
|
1168
1169
|
}
|
|
1169
1170
|
return dirs;
|
|
1170
1171
|
}
|
|
1172
|
+
async function pnpmGlobalRoots(fs, home) {
|
|
1173
|
+
const roots = [];
|
|
1174
|
+
const global = `${home}/global`;
|
|
1175
|
+
for (const version of (await fs.readdir(global).catch(() => [])).sort()) {
|
|
1176
|
+
for (const group of (await fs.readdir(`${global}/${version}`).catch(() => [])).sort()) {
|
|
1177
|
+
const dir = `${global}/${version}/${group}`;
|
|
1178
|
+
const st = await fs.lstat(dir).catch(() => void 0);
|
|
1179
|
+
if (st?.isDirectory && await fs.exists(`${dir}/node_modules`))
|
|
1180
|
+
roots.push(`${dir}/node_modules`);
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1183
|
+
return roots;
|
|
1184
|
+
}
|
|
1185
|
+
async function packagesIn(fs, roots) {
|
|
1186
|
+
const dirs = [];
|
|
1187
|
+
for (const root of typeof roots === "string" ? [roots] : roots)
|
|
1188
|
+
dirs.push(...await packages(fs, root));
|
|
1189
|
+
return dirs;
|
|
1190
|
+
}
|
|
1171
1191
|
async function scanCommands(fs, modules) {
|
|
1172
1192
|
const found = /* @__PURE__ */ new Map();
|
|
1173
|
-
for (const pkg of await
|
|
1193
|
+
for (const pkg of await packagesIn(fs, modules)) {
|
|
1174
1194
|
let manifest;
|
|
1175
1195
|
try {
|
|
1176
1196
|
manifest = JSON.parse(await fs.readFile(`${pkg}/package.json`));
|
|
@@ -1189,7 +1209,7 @@ async function scanCommands(fs, modules) {
|
|
|
1189
1209
|
}
|
|
1190
1210
|
async function scanFilesystems(fs, modules) {
|
|
1191
1211
|
const found = /* @__PURE__ */ new Map();
|
|
1192
|
-
for (const pkg of await
|
|
1212
|
+
for (const pkg of await packagesIn(fs, modules)) {
|
|
1193
1213
|
let manifest;
|
|
1194
1214
|
try {
|
|
1195
1215
|
manifest = JSON.parse(await fs.readFile(`${pkg}/package.json`));
|
|
@@ -5891,6 +5911,157 @@ function serveFilesystem(port, handlers, capabilities = {}) {
|
|
|
5891
5911
|
return { invalidate: (paths) => reply({ invalidate: paths }) };
|
|
5892
5912
|
}
|
|
5893
5913
|
|
|
5914
|
+
// src/mount/fsa.ts
|
|
5915
|
+
var FSA_CAPABILITIES = { listingStats: true };
|
|
5916
|
+
var codeOf = (err) => err?.code;
|
|
5917
|
+
var denied = (err) => codeOf(err) === "EACCES" || err?.name === "NotAllowedError";
|
|
5918
|
+
function attrOf(st) {
|
|
5919
|
+
return {
|
|
5920
|
+
kind: st.isDirectory ? "directory" : st.isSymbolicLink ? "symlink" : "file",
|
|
5921
|
+
size: st.size,
|
|
5922
|
+
mtime: st.mtime.getTime(),
|
|
5923
|
+
mode: st.mode,
|
|
5924
|
+
ino: st.ino
|
|
5925
|
+
};
|
|
5926
|
+
}
|
|
5927
|
+
function kernelFsHandlers(fs) {
|
|
5928
|
+
const handles = /* @__PURE__ */ new Map();
|
|
5929
|
+
let nextFh = 0;
|
|
5930
|
+
const handle = (fh) => {
|
|
5931
|
+
const found = handles.get(fh);
|
|
5932
|
+
if (!found) throw fsError2("EBADF", `handle ${fh}`);
|
|
5933
|
+
return found;
|
|
5934
|
+
};
|
|
5935
|
+
async function existing(path) {
|
|
5936
|
+
try {
|
|
5937
|
+
return await fs.stat(path);
|
|
5938
|
+
} catch (err) {
|
|
5939
|
+
if (codeOf(err) === "ENOENT") return void 0;
|
|
5940
|
+
throw err;
|
|
5941
|
+
}
|
|
5942
|
+
}
|
|
5943
|
+
return {
|
|
5944
|
+
getattr: async (path) => attrOf(await fs.lstat(path)),
|
|
5945
|
+
readdir: async (path) => (await fs.readdirStat(path)).flatMap(([name2, st]) => {
|
|
5946
|
+
if (!st) return [];
|
|
5947
|
+
const attr = attrOf(st);
|
|
5948
|
+
return [{ name: name2, kind: attr.kind, attr }];
|
|
5949
|
+
}),
|
|
5950
|
+
async open(path, flags) {
|
|
5951
|
+
const st = await existing(path);
|
|
5952
|
+
if (st && flags.exclusive) throw fsError2("EEXIST", path);
|
|
5953
|
+
if (st?.isDirectory && flags.write) throw fsError2("EISDIR", path);
|
|
5954
|
+
if (!st && !flags.create) throw fsError2("ENOENT", path);
|
|
5955
|
+
const data = st && !flags.truncate ? await fs.readFileBuffer(path) : new Uint8Array(0);
|
|
5956
|
+
handles.set(++nextFh, { path, data, length: data.length, dirty: !st || flags.truncate });
|
|
5957
|
+
return nextFh;
|
|
5958
|
+
},
|
|
5959
|
+
async read(fh, offset, size) {
|
|
5960
|
+
const h = handle(fh);
|
|
5961
|
+
return h.data.slice(offset, Math.min(h.length, offset + size));
|
|
5962
|
+
},
|
|
5963
|
+
async write(fh, offset, bytes) {
|
|
5964
|
+
const h = handle(fh);
|
|
5965
|
+
const end = offset + bytes.length;
|
|
5966
|
+
if (end > h.data.length) {
|
|
5967
|
+
const grown = new Uint8Array(Math.max(end, h.data.length * 2));
|
|
5968
|
+
grown.set(h.data.subarray(0, h.length));
|
|
5969
|
+
h.data = grown;
|
|
5970
|
+
}
|
|
5971
|
+
h.data.set(bytes, offset);
|
|
5972
|
+
h.length = Math.max(h.length, end);
|
|
5973
|
+
h.dirty = true;
|
|
5974
|
+
},
|
|
5975
|
+
async release(fh) {
|
|
5976
|
+
const h = handle(fh);
|
|
5977
|
+
handles.delete(fh);
|
|
5978
|
+
if (h.dirty) await fs.writeFile(h.path, h.data.slice(0, h.length));
|
|
5979
|
+
},
|
|
5980
|
+
mkdir: (path) => fs.mkdir(path),
|
|
5981
|
+
async rmdir(path) {
|
|
5982
|
+
if (!(await fs.lstat(path)).isDirectory) throw fsError2("ENOTDIR", path);
|
|
5983
|
+
if ((await fs.readdir(path)).length > 0) throw fsError2("ENOTEMPTY", path);
|
|
5984
|
+
await fs.rm(path);
|
|
5985
|
+
},
|
|
5986
|
+
async unlink(path) {
|
|
5987
|
+
if ((await fs.lstat(path)).isDirectory) throw fsError2("EISDIR", path);
|
|
5988
|
+
await fs.rm(path);
|
|
5989
|
+
},
|
|
5990
|
+
rename: (from, to) => fs.rename(from, to),
|
|
5991
|
+
symlink: (target, path) => fs.symlink(target, path),
|
|
5992
|
+
readlink: (path) => fs.readlink(path),
|
|
5993
|
+
async setattr(path, change) {
|
|
5994
|
+
if (change.mode !== void 0) await fs.chmod(path, change.mode);
|
|
5995
|
+
if (change.mtime !== void 0) {
|
|
5996
|
+
await fs.utimes(path, new Date(change.mtime), new Date(change.mtime));
|
|
5997
|
+
}
|
|
5998
|
+
}
|
|
5999
|
+
};
|
|
6000
|
+
}
|
|
6001
|
+
var EMPTY_ROOT = { kind: "directory", size: 0, mtime: 0, mode: 16749 };
|
|
6002
|
+
function granted(handle) {
|
|
6003
|
+
if (!handle.queryPermission) return Promise.resolve(true);
|
|
6004
|
+
return handle.queryPermission({ mode: "readwrite" }).then(
|
|
6005
|
+
(state) => state === "granted",
|
|
6006
|
+
() => false
|
|
6007
|
+
);
|
|
6008
|
+
}
|
|
6009
|
+
function removableMedium(onLost, open = (handle) => new OpfsFs(handle)) {
|
|
6010
|
+
let current;
|
|
6011
|
+
const absent = () => fsError2("ENOMEDIUM", "No medium found");
|
|
6012
|
+
function wrap(pick) {
|
|
6013
|
+
return async (...args) => {
|
|
6014
|
+
const medium = current;
|
|
6015
|
+
if (!medium) throw absent();
|
|
6016
|
+
try {
|
|
6017
|
+
return await pick(medium.handlers)(...args);
|
|
6018
|
+
} catch (err) {
|
|
6019
|
+
if (!denied(err) || await granted(medium.handle)) throw err;
|
|
6020
|
+
if (current === medium) {
|
|
6021
|
+
current = void 0;
|
|
6022
|
+
onLost(medium.handle);
|
|
6023
|
+
}
|
|
6024
|
+
throw absent();
|
|
6025
|
+
}
|
|
6026
|
+
};
|
|
6027
|
+
}
|
|
6028
|
+
const getattr = wrap((h) => h.getattr);
|
|
6029
|
+
const readdir = wrap((h) => h.readdir);
|
|
6030
|
+
return {
|
|
6031
|
+
handlers: {
|
|
6032
|
+
getattr: (path) => current || path !== "/" ? getattr(path) : Promise.resolve(EMPTY_ROOT),
|
|
6033
|
+
readdir: (path) => current || path !== "/" ? readdir(path) : Promise.resolve([]),
|
|
6034
|
+
open: wrap((h) => h.open),
|
|
6035
|
+
read: wrap((h) => h.read),
|
|
6036
|
+
write: wrap((h) => h.write),
|
|
6037
|
+
release: wrap((h) => h.release),
|
|
6038
|
+
mkdir: wrap((h) => h.mkdir),
|
|
6039
|
+
rmdir: wrap((h) => h.rmdir),
|
|
6040
|
+
unlink: wrap((h) => h.unlink),
|
|
6041
|
+
rename: wrap((h) => h.rename),
|
|
6042
|
+
symlink: wrap((h) => h.symlink),
|
|
6043
|
+
readlink: wrap((h) => h.readlink),
|
|
6044
|
+
setattr: wrap((h) => h.setattr)
|
|
6045
|
+
},
|
|
6046
|
+
present: () => current !== void 0,
|
|
6047
|
+
insert(handle) {
|
|
6048
|
+
current = { handle, handlers: kernelFsHandlers(open(handle)) };
|
|
6049
|
+
},
|
|
6050
|
+
eject() {
|
|
6051
|
+
current = void 0;
|
|
6052
|
+
}
|
|
6053
|
+
};
|
|
6054
|
+
}
|
|
6055
|
+
|
|
6056
|
+
// src/mount/media.ts
|
|
6057
|
+
function memoryMedia() {
|
|
6058
|
+
const handles = /* @__PURE__ */ new Map();
|
|
6059
|
+
return {
|
|
6060
|
+
get: async (id) => handles.get(id),
|
|
6061
|
+
put: async (id, handle) => void handles.set(id, handle)
|
|
6062
|
+
};
|
|
6063
|
+
}
|
|
6064
|
+
|
|
5894
6065
|
// src/mount/connection.ts
|
|
5895
6066
|
var DRIVER_TIMEOUT_MS = 3e4;
|
|
5896
6067
|
function unref(timer) {
|
|
@@ -6034,14 +6205,16 @@ var MountTable = class {
|
|
|
6034
6205
|
this.deps = deps;
|
|
6035
6206
|
}
|
|
6036
6207
|
list() {
|
|
6037
|
-
return [...this.mounts.values()].map(
|
|
6038
|
-
type,
|
|
6039
|
-
|
|
6040
|
-
|
|
6041
|
-
|
|
6042
|
-
|
|
6043
|
-
|
|
6044
|
-
|
|
6208
|
+
return [...this.mounts.values()].map(
|
|
6209
|
+
({ type, source, target, options, state, error, present }) => ({
|
|
6210
|
+
type,
|
|
6211
|
+
source,
|
|
6212
|
+
target,
|
|
6213
|
+
options: { ...options },
|
|
6214
|
+
state: state === "ok" && present?.() === false ? "nomedium" : state,
|
|
6215
|
+
...error ? { error } : {}
|
|
6216
|
+
})
|
|
6217
|
+
);
|
|
6045
6218
|
}
|
|
6046
6219
|
locate(path) {
|
|
6047
6220
|
let best;
|
|
@@ -6112,7 +6285,8 @@ var MountTable = class {
|
|
|
6112
6285
|
maxFile: options.maxfile !== void 0 ? parseSize(options.maxfile) : caps.maxFile ?? 0,
|
|
6113
6286
|
attrs: /* @__PURE__ */ new Map(),
|
|
6114
6287
|
lists: /* @__PURE__ */ new Map(),
|
|
6115
|
-
dispose: () => opened2.dispose()
|
|
6288
|
+
dispose: () => opened2.dispose(),
|
|
6289
|
+
...opened2.present ? { present: opened2.present } : {}
|
|
6116
6290
|
};
|
|
6117
6291
|
mounted = mount;
|
|
6118
6292
|
this.mounts.set(target, mount);
|
|
@@ -6749,6 +6923,7 @@ function foreignImports(bytes) {
|
|
|
6749
6923
|
}
|
|
6750
6924
|
|
|
6751
6925
|
// src/launcher.ts
|
|
6926
|
+
var PNPM_HOME = "/home/.local/share/pnpm";
|
|
6752
6927
|
var COMMAND2 = /^\/(?:usr\/)?bin\/([^/]+)$/;
|
|
6753
6928
|
var PACKAGE_ROOT = /^(.*\/node_modules\/(?:@[^/]+\/)?[^/]+)\//;
|
|
6754
6929
|
var ENV_REFERENCE = /\$\{([A-Za-z_][A-Za-z0-9_]*)\}/g;
|
|
@@ -6838,8 +7013,13 @@ var Launcher = class {
|
|
|
6838
7013
|
ca;
|
|
6839
7014
|
transport;
|
|
6840
7015
|
watchers = new FsWatchers();
|
|
7016
|
+
pnpmHome;
|
|
6841
7017
|
mounts;
|
|
6842
7018
|
createDriverWorker;
|
|
7019
|
+
media;
|
|
7020
|
+
onMountPending;
|
|
7021
|
+
removable = /* @__PURE__ */ new Map();
|
|
7022
|
+
inserted = /* @__PURE__ */ new Map();
|
|
6843
7023
|
openFiles = /* @__PURE__ */ new Set();
|
|
6844
7024
|
held = /* @__PURE__ */ new Set();
|
|
6845
7025
|
nextPid = 1e3;
|
|
@@ -6854,6 +7034,9 @@ var Launcher = class {
|
|
|
6854
7034
|
this.base = this.watchers.wrap(this.mounts.wrap(options.fs));
|
|
6855
7035
|
this.createWorker = options.createWorker;
|
|
6856
7036
|
this.createDriverWorker = options.createDriverWorker;
|
|
7037
|
+
this.media = options.media ?? memoryMedia();
|
|
7038
|
+
this.onMountPending = options.onMountPending;
|
|
7039
|
+
this.pnpmHome = options.env?.PNPM_HOME ?? PNPM_HOME;
|
|
6857
7040
|
this.modulesDir = options.modules ?? "/node_modules";
|
|
6858
7041
|
this.env = { ...networkEnv(), ...options.env };
|
|
6859
7042
|
this.ca = kernelCa(options.caStore ?? memoryCaStore());
|
|
@@ -6864,11 +7047,17 @@ var Launcher = class {
|
|
|
6864
7047
|
ca: this.ca
|
|
6865
7048
|
});
|
|
6866
7049
|
this.fs = withCommandDirs(this.base, async () => new Set((await this.commands()).keys()));
|
|
7050
|
+
this.watchers.watch([this.modulesDir, this.pnpmHome], { recursive: true }, () => {
|
|
7051
|
+
this.catalog = void 0;
|
|
7052
|
+
});
|
|
6867
7053
|
}
|
|
6868
7054
|
commands() {
|
|
6869
|
-
this.catalog ??= scanCommands(this.base,
|
|
7055
|
+
this.catalog ??= this.roots().then((roots) => scanCommands(this.base, roots));
|
|
6870
7056
|
return this.catalog;
|
|
6871
7057
|
}
|
|
7058
|
+
async roots() {
|
|
7059
|
+
return [this.modulesDir, ...await pnpmGlobalRoots(this.base, this.pnpmHome)];
|
|
7060
|
+
}
|
|
6872
7061
|
async resolve(file, argv0, cwd) {
|
|
6873
7062
|
const name2 = COMMAND2.exec(file)?.[1] ?? (file.includes("/") ? void 0 : file);
|
|
6874
7063
|
if (name2 !== void 0) {
|
|
@@ -7110,7 +7299,8 @@ var Launcher = class {
|
|
|
7110
7299
|
if (sig !== 0) handle.signal(sig);
|
|
7111
7300
|
return true;
|
|
7112
7301
|
}
|
|
7113
|
-
async driver(type,
|
|
7302
|
+
async driver(type, spec) {
|
|
7303
|
+
if (type === "fsa") return this.fsaDriver(spec);
|
|
7114
7304
|
if (type === "tmpfs") {
|
|
7115
7305
|
const { port1, port2 } = new MessageChannel();
|
|
7116
7306
|
serveFilesystem(port2, tmpfs(), { symlinks: true, chmod: true, attrTtl: 0 });
|
|
@@ -7122,7 +7312,7 @@ var Launcher = class {
|
|
|
7122
7312
|
}
|
|
7123
7313
|
};
|
|
7124
7314
|
}
|
|
7125
|
-
const module = (await scanFilesystems(this.base, this.
|
|
7315
|
+
const module = (await scanFilesystems(this.base, await this.roots())).get(type);
|
|
7126
7316
|
if (!module) throw fsError("ENODEV", `unknown file system type ${type}`);
|
|
7127
7317
|
if (!this.createDriverWorker)
|
|
7128
7318
|
throw fsError("ENODEV", `this kernel cannot start ${type} drivers`);
|
|
@@ -7151,8 +7341,47 @@ var Launcher = class {
|
|
|
7151
7341
|
})
|
|
7152
7342
|
};
|
|
7153
7343
|
}
|
|
7344
|
+
async fsaDriver(spec) {
|
|
7345
|
+
const { target, source } = spec;
|
|
7346
|
+
const ask = (handle) => this.onMountPending?.({ target, source, ...handle ? { handle } : {} });
|
|
7347
|
+
const { port1, port2 } = new MessageChannel();
|
|
7348
|
+
const medium = removableMedium((handle) => {
|
|
7349
|
+
served.invalidate(true);
|
|
7350
|
+
ask(handle);
|
|
7351
|
+
});
|
|
7352
|
+
const served = serveFilesystem(port2, medium.handlers, FSA_CAPABILITIES);
|
|
7353
|
+
const id = source.slice("fsa:".length);
|
|
7354
|
+
this.removable.set(target, { id, medium, served });
|
|
7355
|
+
const stored = this.inserted.get(id) ?? await this.media.get(id);
|
|
7356
|
+
if (stored && await granted(stored)) medium.insert(stored);
|
|
7357
|
+
else ask(stored);
|
|
7358
|
+
return {
|
|
7359
|
+
port: port1,
|
|
7360
|
+
present: () => medium.present(),
|
|
7361
|
+
dispose: () => {
|
|
7362
|
+
this.removable.delete(target);
|
|
7363
|
+
port1.close();
|
|
7364
|
+
port2.close();
|
|
7365
|
+
}
|
|
7366
|
+
};
|
|
7367
|
+
}
|
|
7154
7368
|
mount(spec) {
|
|
7155
|
-
|
|
7369
|
+
if (spec.type !== "fsa" || spec.source.startsWith("fsa:"))
|
|
7370
|
+
return this.mounts.mount(spec, this.fs);
|
|
7371
|
+
return this.mounts.mount({ ...spec, source: `fsa:${crypto.randomUUID()}` }, this.fs);
|
|
7372
|
+
}
|
|
7373
|
+
async insert(target, handle, source) {
|
|
7374
|
+
const at = normalizePath(target);
|
|
7375
|
+
const slot = this.removable.get(at);
|
|
7376
|
+
if (!slot) throw fsError("EINVAL", `${at} is not a removable mount`);
|
|
7377
|
+
if (source !== void 0 && source !== `fsa:${slot.id}`) {
|
|
7378
|
+
throw fsError("EINVAL", `${at} is no longer the drive ${source}`);
|
|
7379
|
+
}
|
|
7380
|
+
if (!await granted(handle)) throw fsError("EACCES", `${at}: no permission for this folder`);
|
|
7381
|
+
this.inserted.set(slot.id, handle);
|
|
7382
|
+
await this.media.put(slot.id, handle);
|
|
7383
|
+
slot.medium.insert(handle);
|
|
7384
|
+
slot.served.invalidate(true);
|
|
7156
7385
|
}
|
|
7157
7386
|
umount(target) {
|
|
7158
7387
|
this.mounts.umount(target);
|
|
@@ -7162,7 +7391,14 @@ var Launcher = class {
|
|
|
7162
7391
|
await writeCaFile(this.base, this.ca).catch(() => void 0);
|
|
7163
7392
|
}
|
|
7164
7393
|
environment(cwd, extra) {
|
|
7165
|
-
return {
|
|
7394
|
+
return {
|
|
7395
|
+
PATH: `/usr/bin:/bin:${this.pnpmHome}/bin`,
|
|
7396
|
+
HOME: "/home",
|
|
7397
|
+
PNPM_HOME: this.pnpmHome,
|
|
7398
|
+
...this.env,
|
|
7399
|
+
PWD: cwd,
|
|
7400
|
+
...extra
|
|
7401
|
+
};
|
|
7166
7402
|
}
|
|
7167
7403
|
async starting(argv, dir) {
|
|
7168
7404
|
this.catalog = void 0;
|
|
@@ -7520,13 +7756,13 @@ async function holdLock(locks) {
|
|
|
7520
7756
|
if (!locks) return { release() {
|
|
7521
7757
|
} };
|
|
7522
7758
|
const name2 = `slicc-kernel-client:${crypto.randomUUID()}`;
|
|
7523
|
-
const
|
|
7759
|
+
const granted2 = Promise.withResolvers();
|
|
7524
7760
|
const held = Promise.withResolvers();
|
|
7525
7761
|
void locks.request(name2, () => {
|
|
7526
|
-
|
|
7762
|
+
granted2.resolve();
|
|
7527
7763
|
return held.promise;
|
|
7528
7764
|
});
|
|
7529
|
-
await
|
|
7765
|
+
await granted2.promise;
|
|
7530
7766
|
return { name: name2, release: () => held.resolve() };
|
|
7531
7767
|
}
|
|
7532
7768
|
function concat6(chunks2) {
|