@ai-ecoverse/slicc-kernel 1.9.0 → 1.11.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 +4 -1
- package/dist/index.js +35 -2
- package/dist/index.js.map +3 -3
- package/dist/kernel-worker.js +103 -3
- package/dist/kernel-worker.js.map +4 -4
- package/dist/node-process-worker.js +32 -9
- package/dist/node-process-worker.js.map +2 -2
- package/dist/node.js +137 -4
- package/dist/node.js.map +4 -4
- package/dist/process-worker.js +32 -9
- package/dist/process-worker.js.map +2 -2
- package/package.json +1 -1
package/dist/node.js
CHANGED
|
@@ -252,7 +252,7 @@ function serveTransport(peer, transport) {
|
|
|
252
252
|
}
|
|
253
253
|
|
|
254
254
|
// src/client/protocol.ts
|
|
255
|
-
var PROTOCOL = [1,
|
|
255
|
+
var PROTOCOL = [1, 1];
|
|
256
256
|
var FS_METHODS = [
|
|
257
257
|
"readFile",
|
|
258
258
|
"writeFile",
|
|
@@ -345,6 +345,7 @@ function serveClient(port, host) {
|
|
|
345
345
|
let state = "new";
|
|
346
346
|
const terminals = /* @__PURE__ */ new Map();
|
|
347
347
|
const groups = /* @__PURE__ */ new Set();
|
|
348
|
+
const watches = /* @__PURE__ */ new Map();
|
|
348
349
|
let net;
|
|
349
350
|
const ended = Promise.withResolvers();
|
|
350
351
|
const send = (message2, transfer = []) => {
|
|
@@ -356,6 +357,8 @@ function serveClient(port, host) {
|
|
|
356
357
|
send({ bye });
|
|
357
358
|
state = "closed";
|
|
358
359
|
net?.close();
|
|
360
|
+
for (const unwatch of watches.values()) unwatch();
|
|
361
|
+
watches.clear();
|
|
359
362
|
for (const session of terminals.values()) session.close();
|
|
360
363
|
terminals.clear();
|
|
361
364
|
const pids = [...groups];
|
|
@@ -449,6 +452,19 @@ function serveClient(port, host) {
|
|
|
449
452
|
throw new Error(`unknown file system call ${req.method}`);
|
|
450
453
|
}
|
|
451
454
|
return fsCall(l.fs, req.method, req.args);
|
|
455
|
+
case "watch": {
|
|
456
|
+
const unwatch = l.watchers.watch(
|
|
457
|
+
req.paths,
|
|
458
|
+
{ recursive: req.recursive },
|
|
459
|
+
(change) => send({ watch: req.id, change })
|
|
460
|
+
);
|
|
461
|
+
watches.set(req.id, unwatch);
|
|
462
|
+
return { result: req.id };
|
|
463
|
+
}
|
|
464
|
+
case "unwatch":
|
|
465
|
+
watches.get(req.watch)?.();
|
|
466
|
+
watches.delete(req.watch);
|
|
467
|
+
return { result: true };
|
|
452
468
|
case "detach":
|
|
453
469
|
return { result: true };
|
|
454
470
|
default:
|
|
@@ -1269,6 +1285,89 @@ function withCommandDirs(fs, names) {
|
|
|
1269
1285
|
};
|
|
1270
1286
|
}
|
|
1271
1287
|
|
|
1288
|
+
// src/fs/watch.ts
|
|
1289
|
+
var WATCH_BATCH_LIMIT = 1e3;
|
|
1290
|
+
var under2 = (path, dir) => dir === "/" || path.startsWith(`${dir}/`);
|
|
1291
|
+
var parentOf3 = (path) => path.slice(0, path.lastIndexOf("/")) || "/";
|
|
1292
|
+
function touches(watcher, changed) {
|
|
1293
|
+
return watcher.paths.some(
|
|
1294
|
+
(watched) => changed === watched || under2(watched, changed) || (watcher.recursive ? under2(changed, watched) : parentOf3(changed) === watched)
|
|
1295
|
+
);
|
|
1296
|
+
}
|
|
1297
|
+
var FsWatchers = class {
|
|
1298
|
+
watchers = /* @__PURE__ */ new Set();
|
|
1299
|
+
watch(paths, options, notify) {
|
|
1300
|
+
const watcher = {
|
|
1301
|
+
paths: paths.map(normalizePath),
|
|
1302
|
+
recursive: options.recursive === true,
|
|
1303
|
+
notify,
|
|
1304
|
+
pending: /* @__PURE__ */ new Set(),
|
|
1305
|
+
scheduled: false
|
|
1306
|
+
};
|
|
1307
|
+
this.watchers.add(watcher);
|
|
1308
|
+
return () => {
|
|
1309
|
+
this.watchers.delete(watcher);
|
|
1310
|
+
};
|
|
1311
|
+
}
|
|
1312
|
+
changed(...paths) {
|
|
1313
|
+
for (const watcher of this.watchers) {
|
|
1314
|
+
for (const path of paths) {
|
|
1315
|
+
const changed = normalizePath(path);
|
|
1316
|
+
if (touches(watcher, changed)) watcher.pending.add(changed);
|
|
1317
|
+
}
|
|
1318
|
+
if (watcher.pending.size === 0 || watcher.scheduled) continue;
|
|
1319
|
+
watcher.scheduled = true;
|
|
1320
|
+
setTimeout(() => this.flush(watcher), 0);
|
|
1321
|
+
}
|
|
1322
|
+
}
|
|
1323
|
+
flush(watcher) {
|
|
1324
|
+
watcher.scheduled = false;
|
|
1325
|
+
const paths = [...watcher.pending];
|
|
1326
|
+
watcher.pending.clear();
|
|
1327
|
+
if (!this.watchers.has(watcher)) return;
|
|
1328
|
+
watcher.notify(paths.length > WATCH_BATCH_LIMIT ? { overflow: true } : { paths });
|
|
1329
|
+
}
|
|
1330
|
+
wrap(fs) {
|
|
1331
|
+
const after = (run2, changed) => async (...args) => {
|
|
1332
|
+
try {
|
|
1333
|
+
await run2(...args);
|
|
1334
|
+
} finally {
|
|
1335
|
+
this.changed(...changed(...args));
|
|
1336
|
+
}
|
|
1337
|
+
};
|
|
1338
|
+
const overrides = {
|
|
1339
|
+
writeFile: after(fs.writeFile.bind(fs), (path) => [path]),
|
|
1340
|
+
mkdir: async (path, options) => {
|
|
1341
|
+
const created = [];
|
|
1342
|
+
if (options?.recursive) {
|
|
1343
|
+
const parts = normalizePath(path).split("/").filter(Boolean);
|
|
1344
|
+
for (let at = 1; at < parts.length; at++) {
|
|
1345
|
+
const ancestor = `/${parts.slice(0, at).join("/")}`;
|
|
1346
|
+
if (created.length > 0 || !await fs.exists(ancestor)) created.push(ancestor);
|
|
1347
|
+
}
|
|
1348
|
+
}
|
|
1349
|
+
try {
|
|
1350
|
+
await fs.mkdir(path, options);
|
|
1351
|
+
} finally {
|
|
1352
|
+
this.changed(...created, path);
|
|
1353
|
+
}
|
|
1354
|
+
},
|
|
1355
|
+
rm: after(fs.rm.bind(fs), (path) => [path]),
|
|
1356
|
+
rename: after(fs.rename.bind(fs), (from, to) => [from, to]),
|
|
1357
|
+
symlink: after(fs.symlink.bind(fs), (_target, path) => [path]),
|
|
1358
|
+
chmod: after(fs.chmod.bind(fs), (path) => [path]),
|
|
1359
|
+
utimes: after(fs.utimes.bind(fs), (path) => [path])
|
|
1360
|
+
};
|
|
1361
|
+
return new Proxy(fs, {
|
|
1362
|
+
get(target, key, receiver) {
|
|
1363
|
+
if (Object.hasOwn(overrides, key)) return overrides[key];
|
|
1364
|
+
const value = Reflect.get(target, key, receiver);
|
|
1365
|
+
return typeof value === "function" ? value.bind(target) : value;
|
|
1366
|
+
}
|
|
1367
|
+
});
|
|
1368
|
+
}
|
|
1369
|
+
};
|
|
1370
|
+
|
|
1272
1371
|
// src/kernel/pipe.ts
|
|
1273
1372
|
var PIPE_CAPACITY = 64 * 1024;
|
|
1274
1373
|
var PipeError = class extends Error {
|
|
@@ -5866,11 +5965,12 @@ var Launcher = class {
|
|
|
5866
5965
|
net = new LoopbackNet();
|
|
5867
5966
|
ca;
|
|
5868
5967
|
transport;
|
|
5968
|
+
watchers = new FsWatchers();
|
|
5869
5969
|
nextPid = 1e3;
|
|
5870
5970
|
boot = Date.now();
|
|
5871
5971
|
terminals = 0;
|
|
5872
5972
|
constructor(options) {
|
|
5873
|
-
this.base = options.fs;
|
|
5973
|
+
this.base = this.watchers.wrap(options.fs);
|
|
5874
5974
|
this.createWorker = options.createWorker;
|
|
5875
5975
|
this.modulesDir = options.modules ?? "/node_modules";
|
|
5876
5976
|
this.env = { ...networkEnv(), ...options.env };
|
|
@@ -5881,7 +5981,7 @@ var Launcher = class {
|
|
|
5881
5981
|
engine: kernelTlsEngine(packageTlsEngine(options.fs, this.modulesDir)),
|
|
5882
5982
|
ca: this.ca
|
|
5883
5983
|
});
|
|
5884
|
-
this.fs = withCommandDirs(
|
|
5984
|
+
this.fs = withCommandDirs(this.base, async () => new Set((await this.commands()).keys()));
|
|
5885
5985
|
}
|
|
5886
5986
|
commands() {
|
|
5887
5987
|
this.catalog ??= scanCommands(this.base, this.modulesDir);
|
|
@@ -6510,6 +6610,8 @@ var Channel = class {
|
|
|
6510
6610
|
remote;
|
|
6511
6611
|
failure;
|
|
6512
6612
|
pending = /* @__PURE__ */ new Map();
|
|
6613
|
+
watching = /* @__PURE__ */ new Map();
|
|
6614
|
+
protocol = PROTOCOL;
|
|
6513
6615
|
nextId = 0;
|
|
6514
6616
|
port;
|
|
6515
6617
|
release;
|
|
@@ -6549,6 +6651,10 @@ var Channel = class {
|
|
|
6549
6651
|
return this.request(call).done;
|
|
6550
6652
|
}
|
|
6551
6653
|
receive(data) {
|
|
6654
|
+
if (data.watch !== void 0) {
|
|
6655
|
+
this.watching.get(data.watch)?.(data.change);
|
|
6656
|
+
return;
|
|
6657
|
+
}
|
|
6552
6658
|
if (data.bye !== void 0) {
|
|
6553
6659
|
this.end(new KernelGoneError(data.bye));
|
|
6554
6660
|
return;
|
|
@@ -6661,7 +6767,33 @@ function fsOn(channel) {
|
|
|
6661
6767
|
realpath: (path) => fs("realpath", path),
|
|
6662
6768
|
symlink: (target, path) => done4("symlink", target, path),
|
|
6663
6769
|
readlink: (path) => fs("readlink", path),
|
|
6664
|
-
exists: (path) => fs("exists", path)
|
|
6770
|
+
exists: (path) => fs("exists", path),
|
|
6771
|
+
async watch(paths, options, onChange) {
|
|
6772
|
+
if (channel.protocol[1] < 1) {
|
|
6773
|
+
throw new KernelCallError(
|
|
6774
|
+
`this kernel speaks protocol ${channel.protocol.join(".")}, which has no watch`,
|
|
6775
|
+
"ENOSYS"
|
|
6776
|
+
);
|
|
6777
|
+
}
|
|
6778
|
+
const { id, done: done5 } = channel.request({
|
|
6779
|
+
op: "watch",
|
|
6780
|
+
paths,
|
|
6781
|
+
recursive: options.recursive === true
|
|
6782
|
+
});
|
|
6783
|
+
channel.watching.set(id, onChange);
|
|
6784
|
+
try {
|
|
6785
|
+
await done5;
|
|
6786
|
+
} catch (error) {
|
|
6787
|
+
channel.watching.delete(id);
|
|
6788
|
+
throw error;
|
|
6789
|
+
}
|
|
6790
|
+
return {
|
|
6791
|
+
close: () => {
|
|
6792
|
+
if (!channel.watching.delete(id)) return;
|
|
6793
|
+
void channel.call({ op: "unwatch", watch: id }).catch(() => void 0);
|
|
6794
|
+
}
|
|
6795
|
+
};
|
|
6796
|
+
}
|
|
6665
6797
|
};
|
|
6666
6798
|
}
|
|
6667
6799
|
async function greet(channel, lock, timeoutMs) {
|
|
@@ -6691,6 +6823,7 @@ async function attachKernel(port, options = {}) {
|
|
|
6691
6823
|
const own = await holdLock(locks);
|
|
6692
6824
|
const channel = new Channel(port, own.release);
|
|
6693
6825
|
const hello = await greet(channel, own.name, options.timeoutMs ?? 1e4);
|
|
6826
|
+
channel.protocol = hello.protocol;
|
|
6694
6827
|
if (hello.lock && locks) void locks.request(hello.lock, () => channel.end(new KernelGoneError()));
|
|
6695
6828
|
const transport = new RemoteTransport(
|
|
6696
6829
|
{ postMessage: (call) => channel.post(call) },
|