@ai-ecoverse/slicc-kernel 1.74.0 → 1.75.1
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 +15 -1
- package/dist/index.js +56 -8
- package/dist/index.js.map +4 -4
- package/dist/kernel-worker.js +345 -36
- package/dist/kernel-worker.js.map +4 -4
- package/dist/node-process-worker.js +183 -34
- package/dist/node-process-worker.js.map +3 -3
- package/dist/node.js +323 -47
- package/dist/node.js.map +4 -4
- package/dist/process-worker.js +183 -34
- package/dist/process-worker.js.map +3 -3
- package/package.json +1 -1
package/dist/node.js
CHANGED
|
@@ -736,9 +736,11 @@ var KernelPipe = class {
|
|
|
736
736
|
// src/kernel/fd-table.ts
|
|
737
737
|
var KernelError = class extends Error {
|
|
738
738
|
code;
|
|
739
|
-
|
|
739
|
+
detail;
|
|
740
|
+
constructor(code, detail) {
|
|
740
741
|
super(code);
|
|
741
742
|
this.code = code;
|
|
743
|
+
if (detail !== void 0) this.detail = detail;
|
|
742
744
|
}
|
|
743
745
|
};
|
|
744
746
|
function pollFile(file) {
|
|
@@ -881,6 +883,7 @@ function kernelFdKind(file) {
|
|
|
881
883
|
if (file.heldMeta && "device" in file.heldMeta) return "device";
|
|
882
884
|
if (file.tty) return "tty";
|
|
883
885
|
if (file.sealed) return "sealed";
|
|
886
|
+
if (file.clipboard) return "clipboard";
|
|
884
887
|
return file.seek ? "file" : "stream";
|
|
885
888
|
}
|
|
886
889
|
var FdTable = class _FdTable {
|
|
@@ -3425,6 +3428,7 @@ async function positioned(handle, op) {
|
|
|
3425
3428
|
function isHandle(child) {
|
|
3426
3429
|
return "kind" in child;
|
|
3427
3430
|
}
|
|
3431
|
+
var FILE_TIMES_MS = 100;
|
|
3428
3432
|
var OpfsFs = class {
|
|
3429
3433
|
root;
|
|
3430
3434
|
meta;
|
|
@@ -3695,8 +3699,50 @@ var OpfsFs = class {
|
|
|
3695
3699
|
const fallback = directory || EXECUTABLE.test(path) ? 493 : 420;
|
|
3696
3700
|
return (directory ? S_IFDIR : S_IFREG) | (meta?.mode ?? fallback);
|
|
3697
3701
|
}
|
|
3702
|
+
id = crypto.randomUUID();
|
|
3698
3703
|
dirTimes = /* @__PURE__ */ new Map();
|
|
3699
3704
|
dirDirty = /* @__PURE__ */ new Set();
|
|
3705
|
+
fileTimes = /* @__PURE__ */ new Map();
|
|
3706
|
+
written(target) {
|
|
3707
|
+
this.committed(target);
|
|
3708
|
+
if (!this.ranged) return;
|
|
3709
|
+
this.fileTimes.set(target, Date.now());
|
|
3710
|
+
this.scheduleFileTimes();
|
|
3711
|
+
}
|
|
3712
|
+
scheduleFileTimes() {
|
|
3713
|
+
if (this.flushing.file || this.fileTimes.size === 0) return;
|
|
3714
|
+
this.flushing.file = setTimeout(() => {
|
|
3715
|
+
void this.flushFileTimes().catch(() => void 0).finally(() => {
|
|
3716
|
+
this.flushing.file = void 0;
|
|
3717
|
+
this.scheduleFileTimes();
|
|
3718
|
+
});
|
|
3719
|
+
}, FILE_TIMES_MS);
|
|
3720
|
+
this.flushing.file.unref?.();
|
|
3721
|
+
}
|
|
3722
|
+
async flushFileTimes() {
|
|
3723
|
+
for (const [path, ms] of [...this.fileTimes]) {
|
|
3724
|
+
const mtimeFor = await this.modified(path).catch(() => 0);
|
|
3725
|
+
await this.meta.update(
|
|
3726
|
+
path,
|
|
3727
|
+
(entry) => this.fileTimes.get(path) !== ms || this.explicitWins(entry, ms) ? entry : { ...entry, path, mtimeMs: ms, mtimeFor, ctimeMs: ms }
|
|
3728
|
+
);
|
|
3729
|
+
if (this.fileTimes.get(path) === ms) this.fileTimes.delete(path);
|
|
3730
|
+
}
|
|
3731
|
+
}
|
|
3732
|
+
timesOf(path) {
|
|
3733
|
+
return this.dirTimes.get(path) ?? this.fileTimes.get(path);
|
|
3734
|
+
}
|
|
3735
|
+
explicitWins(entry, ms) {
|
|
3736
|
+
if (entry?.timesAt === void 0 || entry.timesBy === this.id) return false;
|
|
3737
|
+
return entry.timesAt >= ms;
|
|
3738
|
+
}
|
|
3739
|
+
movePending(from, to) {
|
|
3740
|
+
for (const [path, ms] of [...this.fileTimes]) {
|
|
3741
|
+
if (!within2(path, from)) continue;
|
|
3742
|
+
this.fileTimes.delete(path);
|
|
3743
|
+
if (to !== void 0) this.fileTimes.set(to + path.slice(from.length), ms);
|
|
3744
|
+
}
|
|
3745
|
+
}
|
|
3700
3746
|
flushing = {};
|
|
3701
3747
|
touch(...dirs) {
|
|
3702
3748
|
const now = Date.now();
|
|
@@ -3720,11 +3766,10 @@ var OpfsFs = class {
|
|
|
3720
3766
|
if (this.dirTimes.get(path) === ms) this.dirTimes.delete(path);
|
|
3721
3767
|
}
|
|
3722
3768
|
}
|
|
3723
|
-
async statOf(path, handle, meta) {
|
|
3769
|
+
async statOf(path, handle, meta, touched) {
|
|
3724
3770
|
const directory = handle.kind === "directory";
|
|
3725
3771
|
const file = directory ? void 0 : await handle.getFile();
|
|
3726
3772
|
const modified = file?.lastModified ?? 0;
|
|
3727
|
-
const touched = directory ? this.dirTimes.get(path) : void 0;
|
|
3728
3773
|
const kept = meta?.mtimeMs !== void 0 && meta.mtimeFor === modified ? meta.mtimeMs : modified;
|
|
3729
3774
|
const mtime = touched ?? kept;
|
|
3730
3775
|
return {
|
|
@@ -3756,13 +3801,14 @@ var OpfsFs = class {
|
|
|
3756
3801
|
}
|
|
3757
3802
|
async describe(found) {
|
|
3758
3803
|
if (found.link) return this.owned(this.linkStat(found.link), found.path, found.link);
|
|
3804
|
+
const touched = this.timesOf(found.path);
|
|
3759
3805
|
if (!this.owners) {
|
|
3760
3806
|
const [meta2] = await this.meta.get([found.path]);
|
|
3761
|
-
return this.statOf(found.path, found.handle, meta2);
|
|
3807
|
+
return this.statOf(found.path, found.handle, meta2, touched);
|
|
3762
3808
|
}
|
|
3763
3809
|
const entries = await this.meta.get(chain(found.path));
|
|
3764
3810
|
const meta = entries.pop();
|
|
3765
|
-
const stat = await this.statOf(found.path, found.handle, meta);
|
|
3811
|
+
const stat = await this.statOf(found.path, found.handle, meta, touched);
|
|
3766
3812
|
return { ...stat, ...ownOf(meta) ?? inherit(entries) };
|
|
3767
3813
|
}
|
|
3768
3814
|
async stat(path) {
|
|
@@ -3819,13 +3865,14 @@ var OpfsFs = class {
|
|
|
3819
3865
|
async pwrite(path, offset, bytes) {
|
|
3820
3866
|
const [handle, , target] = await this.fileFor(path);
|
|
3821
3867
|
await this.retrying(path, () => positioned(handle, (io) => io.write(offset, bytes)), true);
|
|
3822
|
-
this.
|
|
3868
|
+
this.written(target);
|
|
3823
3869
|
}
|
|
3824
3870
|
async truncate(path, size) {
|
|
3825
3871
|
const handle = await this.existing(path, true);
|
|
3826
|
-
const
|
|
3872
|
+
const resolve = this.ranged || this.remote?.watched();
|
|
3873
|
+
const target = resolve ? (await this.locate(path, true)).path : path;
|
|
3827
3874
|
await this.retrying(path, () => positioned(handle, (io) => io.truncate(size)), true);
|
|
3828
|
-
this.
|
|
3875
|
+
this.written(target);
|
|
3829
3876
|
}
|
|
3830
3877
|
async writeSession(path, truncate) {
|
|
3831
3878
|
const [handle, , target] = await this.fileFor(path);
|
|
@@ -3915,13 +3962,16 @@ var OpfsFs = class {
|
|
|
3915
3962
|
async readdirStat(path) {
|
|
3916
3963
|
const [dir, children2] = await this.listing(path);
|
|
3917
3964
|
const base = dir === "/" ? "" : dir;
|
|
3965
|
+
const touched = children2.map(([name2]) => this.timesOf(`${base}/${name2}`));
|
|
3918
3966
|
const metas = await this.meta.get(children2.map(([name2]) => `${base}/${name2}`));
|
|
3919
3967
|
const handed2 = this.owners ? await this.handedTo(dir) : void 0;
|
|
3920
3968
|
const owned4 = (stat, entry) => handed2 ? { ...stat, ...ownOf(entry) ?? handed2 } : stat;
|
|
3921
3969
|
return Promise.all(
|
|
3922
3970
|
children2.map(async ([name2, child], i) => {
|
|
3923
3971
|
if (!isHandle(child)) return [name2, owned4(this.linkStat(child), child)];
|
|
3924
|
-
const stat = await this.statOf(`${base}/${name2}`, child, metas[i]).catch(
|
|
3972
|
+
const stat = await this.statOf(`${base}/${name2}`, child, metas[i], touched[i]).catch(
|
|
3973
|
+
() => null
|
|
3974
|
+
);
|
|
3925
3975
|
return [name2, stat && owned4(stat, metas[i])];
|
|
3926
3976
|
})
|
|
3927
3977
|
);
|
|
@@ -3979,6 +4029,7 @@ var OpfsFs = class {
|
|
|
3979
4029
|
throw translate(err, path);
|
|
3980
4030
|
}
|
|
3981
4031
|
this.changed(found.path);
|
|
4032
|
+
this.movePending(found.path);
|
|
3982
4033
|
}
|
|
3983
4034
|
await this.meta.remove([found.path]);
|
|
3984
4035
|
this.touch(parentOf4(found.path));
|
|
@@ -4042,6 +4093,7 @@ var OpfsFs = class {
|
|
|
4042
4093
|
const moved2 = await this.place(source.handle, dir, staging);
|
|
4043
4094
|
if (swap) await this.rm(destination, { recursive: true });
|
|
4044
4095
|
await this.meta.move(source.path, destination, carry);
|
|
4096
|
+
this.movePending(source.path, destination);
|
|
4045
4097
|
if (!moved2) await this.rm(source.path, { recursive: true });
|
|
4046
4098
|
let copied = !moved2;
|
|
4047
4099
|
if (swap) {
|
|
@@ -4163,6 +4215,7 @@ var OpfsFs = class {
|
|
|
4163
4215
|
const handle = found.handle;
|
|
4164
4216
|
const file = handle.kind === "file" ? await handle.getFile() : void 0;
|
|
4165
4217
|
this.dirTimes.delete(found.path);
|
|
4218
|
+
this.fileTimes.delete(found.path);
|
|
4166
4219
|
const ctimeMs = Date.now();
|
|
4167
4220
|
await this.meta.update(found.path, (entry) => ({
|
|
4168
4221
|
...entry,
|
|
@@ -4171,7 +4224,8 @@ var OpfsFs = class {
|
|
|
4171
4224
|
mtimeMs: mtime.getTime(),
|
|
4172
4225
|
mtimeFor: file?.lastModified ?? 0,
|
|
4173
4226
|
ctimeMs,
|
|
4174
|
-
timesAt: ctimeMs
|
|
4227
|
+
timesAt: ctimeMs,
|
|
4228
|
+
timesBy: this.id
|
|
4175
4229
|
}));
|
|
4176
4230
|
}
|
|
4177
4231
|
async reconcile() {
|
|
@@ -6070,6 +6124,173 @@ var ChildTable = class {
|
|
|
6070
6124
|
}
|
|
6071
6125
|
};
|
|
6072
6126
|
|
|
6127
|
+
// src/kernel/clipboard.ts
|
|
6128
|
+
var CLIPBOARD_MAX_BYTES = 1024 * 1024;
|
|
6129
|
+
var CLIPBOARD_TIMEOUT_MS = 1e4;
|
|
6130
|
+
var encoder = new TextEncoder();
|
|
6131
|
+
var decoder = new TextDecoder("utf-8", { fatal: true });
|
|
6132
|
+
var READY = { readable: true, writable: true, hangup: false };
|
|
6133
|
+
function lineOf(err) {
|
|
6134
|
+
const text = err instanceof Error ? err.message : String(err);
|
|
6135
|
+
return (text.split("\n")[0] ?? "").slice(0, 200);
|
|
6136
|
+
}
|
|
6137
|
+
function clipboardFailure(err) {
|
|
6138
|
+
if (err instanceof KernelError) return err;
|
|
6139
|
+
const name2 = err?.name;
|
|
6140
|
+
return new KernelError(name2 === "NotAllowedError" ? "EACCES" : "EIO", lineOf(err));
|
|
6141
|
+
}
|
|
6142
|
+
function joined2(chunks2, size) {
|
|
6143
|
+
if (chunks2.length === 1) return chunks2[0];
|
|
6144
|
+
const out = new Uint8Array(size);
|
|
6145
|
+
let at = 0;
|
|
6146
|
+
for (const chunk2 of chunks2) {
|
|
6147
|
+
out.set(chunk2, at);
|
|
6148
|
+
at += chunk2.length;
|
|
6149
|
+
}
|
|
6150
|
+
return out;
|
|
6151
|
+
}
|
|
6152
|
+
async function interruptible(work, signal) {
|
|
6153
|
+
if (!signal) return work;
|
|
6154
|
+
if (signal.aborted) throw new KernelError("EINTR");
|
|
6155
|
+
let stop = () => {
|
|
6156
|
+
};
|
|
6157
|
+
const interrupted2 = new Promise((_, reject) => {
|
|
6158
|
+
stop = () => reject(new KernelError("EINTR"));
|
|
6159
|
+
signal.addEventListener("abort", stop, { once: true });
|
|
6160
|
+
});
|
|
6161
|
+
try {
|
|
6162
|
+
return await Promise.race([work, interrupted2]);
|
|
6163
|
+
} finally {
|
|
6164
|
+
signal.removeEventListener("abort", stop);
|
|
6165
|
+
}
|
|
6166
|
+
}
|
|
6167
|
+
var ClipboardChannel = class {
|
|
6168
|
+
stamp;
|
|
6169
|
+
access;
|
|
6170
|
+
broker;
|
|
6171
|
+
snapshot;
|
|
6172
|
+
taken;
|
|
6173
|
+
offset = 0;
|
|
6174
|
+
chunks = [];
|
|
6175
|
+
size = 0;
|
|
6176
|
+
wrote = false;
|
|
6177
|
+
failed = false;
|
|
6178
|
+
constructor(broker, access2, stamp) {
|
|
6179
|
+
this.broker = broker;
|
|
6180
|
+
this.access = access2;
|
|
6181
|
+
this.stamp = stamp;
|
|
6182
|
+
}
|
|
6183
|
+
get unread() {
|
|
6184
|
+
return this.taken === void 0 && this.snapshot === void 0;
|
|
6185
|
+
}
|
|
6186
|
+
get settled() {
|
|
6187
|
+
return this.taken !== void 0;
|
|
6188
|
+
}
|
|
6189
|
+
async read(max, signal) {
|
|
6190
|
+
if (this.access === "write") throw new KernelError("EBADF");
|
|
6191
|
+
if (!this.taken) {
|
|
6192
|
+
if (!this.snapshot) {
|
|
6193
|
+
const stamp = this.stamp;
|
|
6194
|
+
const asked = this.broker.ask(async (hook) => {
|
|
6195
|
+
const text = await hook.read(stamp);
|
|
6196
|
+
if (typeof text !== "string") throw new KernelError("EIO", "the clipboard gave no text");
|
|
6197
|
+
return encoder.encode(text);
|
|
6198
|
+
});
|
|
6199
|
+
this.snapshot = asked;
|
|
6200
|
+
asked.then(
|
|
6201
|
+
(bytes) => {
|
|
6202
|
+
if (this.snapshot === asked) this.taken = bytes;
|
|
6203
|
+
},
|
|
6204
|
+
() => {
|
|
6205
|
+
if (this.snapshot === asked) this.snapshot = void 0;
|
|
6206
|
+
}
|
|
6207
|
+
);
|
|
6208
|
+
}
|
|
6209
|
+
this.taken = await interruptible(this.snapshot, signal);
|
|
6210
|
+
}
|
|
6211
|
+
const out = this.taken.subarray(this.offset, this.offset + max);
|
|
6212
|
+
this.offset += out.length;
|
|
6213
|
+
return out;
|
|
6214
|
+
}
|
|
6215
|
+
write(bytes) {
|
|
6216
|
+
if (this.access === "read") throw new KernelError("EBADF");
|
|
6217
|
+
this.wrote = true;
|
|
6218
|
+
if (this.failed) throw new KernelError("EFBIG");
|
|
6219
|
+
if (this.size + bytes.length > CLIPBOARD_MAX_BYTES) {
|
|
6220
|
+
this.failed = true;
|
|
6221
|
+
this.chunks = [];
|
|
6222
|
+
this.size = 0;
|
|
6223
|
+
throw new KernelError("EFBIG");
|
|
6224
|
+
}
|
|
6225
|
+
if (bytes.length > 0) this.chunks.push(bytes.slice());
|
|
6226
|
+
this.size += bytes.length;
|
|
6227
|
+
return bytes.length;
|
|
6228
|
+
}
|
|
6229
|
+
poll() {
|
|
6230
|
+
return READY;
|
|
6231
|
+
}
|
|
6232
|
+
async close() {
|
|
6233
|
+
this.snapshot = void 0;
|
|
6234
|
+
this.taken = void 0;
|
|
6235
|
+
const commits = this.access === "write" || this.access === "both" && this.wrote;
|
|
6236
|
+
if (!commits || this.failed) return;
|
|
6237
|
+
const bytes = joined2(this.chunks, this.size);
|
|
6238
|
+
this.chunks = [];
|
|
6239
|
+
this.size = 0;
|
|
6240
|
+
let text;
|
|
6241
|
+
try {
|
|
6242
|
+
text = decoder.decode(bytes);
|
|
6243
|
+
} catch {
|
|
6244
|
+
throw new KernelError("EILSEQ", "the text is not valid UTF-8");
|
|
6245
|
+
}
|
|
6246
|
+
const stamp = this.stamp;
|
|
6247
|
+
await this.broker.ask(async (hook) => {
|
|
6248
|
+
await hook.write(text, stamp);
|
|
6249
|
+
});
|
|
6250
|
+
}
|
|
6251
|
+
};
|
|
6252
|
+
var ClipboardBroker = class {
|
|
6253
|
+
hook;
|
|
6254
|
+
users;
|
|
6255
|
+
timeoutMs;
|
|
6256
|
+
tagOf;
|
|
6257
|
+
constructor(hook, users, timeoutMs = CLIPBOARD_TIMEOUT_MS, tagOf = () => void 0) {
|
|
6258
|
+
this.hook = hook;
|
|
6259
|
+
this.users = users;
|
|
6260
|
+
this.timeoutMs = timeoutMs;
|
|
6261
|
+
this.tagOf = tagOf;
|
|
6262
|
+
}
|
|
6263
|
+
async ask(work) {
|
|
6264
|
+
const hook = this.hook;
|
|
6265
|
+
if (!hook) throw new KernelError("ENOTSUP", "no clipboard in this embedder");
|
|
6266
|
+
let timer;
|
|
6267
|
+
const late = new Promise((_, reject) => {
|
|
6268
|
+
timer = setTimeout(
|
|
6269
|
+
() => reject(new KernelError("EIO", "clipboard timed out")),
|
|
6270
|
+
this.timeoutMs
|
|
6271
|
+
);
|
|
6272
|
+
});
|
|
6273
|
+
const asked = Promise.resolve().then(() => work(hook)).catch((err) => {
|
|
6274
|
+
throw clipboardFailure(err);
|
|
6275
|
+
});
|
|
6276
|
+
try {
|
|
6277
|
+
return await Promise.race([asked, late]);
|
|
6278
|
+
} finally {
|
|
6279
|
+
clearTimeout(timer);
|
|
6280
|
+
}
|
|
6281
|
+
}
|
|
6282
|
+
open(access2, stamp) {
|
|
6283
|
+
const channel = new ClipboardChannel(this, access2, stamp);
|
|
6284
|
+
return new OpenFile({
|
|
6285
|
+
read: (max, signal) => channel.read(max, signal),
|
|
6286
|
+
write: async (bytes) => channel.write(bytes),
|
|
6287
|
+
poll: () => channel.poll(),
|
|
6288
|
+
close: () => channel.close(),
|
|
6289
|
+
clipboard: channel
|
|
6290
|
+
});
|
|
6291
|
+
}
|
|
6292
|
+
};
|
|
6293
|
+
|
|
6073
6294
|
// src/mount/protocol.ts
|
|
6074
6295
|
var DRIVER_PROTOCOL = [1, 2];
|
|
6075
6296
|
function driverVersionError(theirs) {
|
|
@@ -7607,20 +7828,20 @@ var SAB_DEFAULT_WINDOW_BYTES = 1024 * 1024;
|
|
|
7607
7828
|
var SAB_MIN_BYTES = SAB_HEADER_BYTES + 4096;
|
|
7608
7829
|
var SYNC_SAB_REQ_MSG = "sync-sab-req";
|
|
7609
7830
|
var SYNC_SAB_NEXT_MSG = "sync-sab-next";
|
|
7610
|
-
var
|
|
7611
|
-
var
|
|
7831
|
+
var encoder2 = new TextEncoder();
|
|
7832
|
+
var decoder2 = new TextDecoder();
|
|
7612
7833
|
function encodeSabResult(result) {
|
|
7613
7834
|
if (!result.ok) {
|
|
7614
7835
|
return {
|
|
7615
7836
|
status: SAB_STATUS_ERRNO,
|
|
7616
|
-
payload:
|
|
7837
|
+
payload: encoder2.encode(JSON.stringify({ errno: result.errno, message: result.message }))
|
|
7617
7838
|
};
|
|
7618
7839
|
}
|
|
7619
7840
|
switch (result.kind) {
|
|
7620
7841
|
case "bytes":
|
|
7621
7842
|
return { status: SAB_STATUS_BYTES, payload: result.bytes };
|
|
7622
7843
|
case "json":
|
|
7623
|
-
return { status: SAB_STATUS_JSON, payload:
|
|
7844
|
+
return { status: SAB_STATUS_JSON, payload: encoder2.encode(JSON.stringify(result.json)) };
|
|
7624
7845
|
default:
|
|
7625
7846
|
return { status: SAB_STATUS_VOID, payload: new Uint8Array(0) };
|
|
7626
7847
|
}
|
|
@@ -10442,7 +10663,7 @@ function defaultTermios() {
|
|
|
10442
10663
|
c_cc: cCc
|
|
10443
10664
|
};
|
|
10444
10665
|
}
|
|
10445
|
-
var
|
|
10666
|
+
var encoder3 = new TextEncoder();
|
|
10446
10667
|
function isContinuation(byte) {
|
|
10447
10668
|
return (byte & 192) === 128;
|
|
10448
10669
|
}
|
|
@@ -10564,7 +10785,7 @@ var KernelTty = class {
|
|
|
10564
10785
|
this.line.push(byte);
|
|
10565
10786
|
this.readable.push(Uint8Array.from(this.line));
|
|
10566
10787
|
this.line = [];
|
|
10567
|
-
if (echo) this.output(
|
|
10788
|
+
if (echo) this.output(encoder3.encode("\n"));
|
|
10568
10789
|
} else {
|
|
10569
10790
|
this.line.push(byte);
|
|
10570
10791
|
if (echo) this.echo(byte);
|
|
@@ -10589,7 +10810,7 @@ var KernelTty = class {
|
|
|
10589
10810
|
const utf82 = (this.termios.c_iflag & IUTF8) !== 0;
|
|
10590
10811
|
const cells = utf82 ? dropped2.filter((b) => !isContinuation(b)).length : dropped2.length;
|
|
10591
10812
|
if (cells > 0 && this.termios.c_lflag & ECHO) {
|
|
10592
|
-
this.output(
|
|
10813
|
+
this.output(encoder3.encode("\b \b".repeat(cells)), false);
|
|
10593
10814
|
}
|
|
10594
10815
|
}
|
|
10595
10816
|
echo(byte) {
|
|
@@ -11078,7 +11299,7 @@ async function socketSyscall(req, proc) {
|
|
|
11078
11299
|
dialing?.catch(() => void 0);
|
|
11079
11300
|
throw new KernelError("EINPROGRESS");
|
|
11080
11301
|
}
|
|
11081
|
-
if (dialing !== void 0) await
|
|
11302
|
+
if (dialing !== void 0) await interruptible2(dialing, proc.blocking());
|
|
11082
11303
|
return ok();
|
|
11083
11304
|
}
|
|
11084
11305
|
case "sock-shutdown":
|
|
@@ -11102,7 +11323,7 @@ async function socketSyscall(req, proc) {
|
|
|
11102
11323
|
}
|
|
11103
11324
|
}
|
|
11104
11325
|
}
|
|
11105
|
-
function
|
|
11326
|
+
function interruptible2(dialing, signal) {
|
|
11106
11327
|
return new Promise((resolve, reject) => {
|
|
11107
11328
|
const abort = () => reject(new KernelError("EINTR"));
|
|
11108
11329
|
signal.addEventListener("abort", abort, { once: true });
|
|
@@ -11769,6 +11990,7 @@ var SYSCALL_OPS = /* @__PURE__ */ new Set([
|
|
|
11769
11990
|
"fd-tty-names",
|
|
11770
11991
|
"fd-tty-owner",
|
|
11771
11992
|
"fd-open-sealed",
|
|
11993
|
+
"fd-open-clipboard",
|
|
11772
11994
|
"tty-get",
|
|
11773
11995
|
"tty-set",
|
|
11774
11996
|
"tty-winsz",
|
|
@@ -12011,7 +12233,7 @@ var WasmProcess = class {
|
|
|
12011
12233
|
return await this.procSyscall(req, cancelled);
|
|
12012
12234
|
} catch (e) {
|
|
12013
12235
|
if (e instanceof KernelError || e instanceof SpawnError) {
|
|
12014
|
-
return { ok: false, errno: e.code, message: e.code };
|
|
12236
|
+
return { ok: false, errno: e.code, message: e.detail ?? e.code };
|
|
12015
12237
|
}
|
|
12016
12238
|
const code = e?.code;
|
|
12017
12239
|
if (typeof code === "string" && /^E[A-Z]+$/.test(code)) {
|
|
@@ -12054,6 +12276,7 @@ var WasmProcess = class {
|
|
|
12054
12276
|
const read = req.peek ? file.peek : file.read;
|
|
12055
12277
|
if (!read) throw new KernelError(req.peek && file.read ? "EOPNOTSUPP" : "EBADF");
|
|
12056
12278
|
if (file.tty) this.checkForeground(file.tty);
|
|
12279
|
+
if (file.clipboard) return this.readClipboard(file.clipboard, req, cancelled);
|
|
12057
12280
|
if (req.max <= 0) return new Uint8Array(0);
|
|
12058
12281
|
if (file instanceof KernelSocket && file.unconnected) throw new KernelError("ENOTCONN");
|
|
12059
12282
|
const ready2 = pollFile(file).readable;
|
|
@@ -12061,6 +12284,13 @@ var WasmProcess = class {
|
|
|
12061
12284
|
const signal = ready2 ? this.interrupt.signal : this.blockingSignal(cancelled);
|
|
12062
12285
|
return read.call(file, Math.max(0, Math.min(req.max, MAX_READ)), signal);
|
|
12063
12286
|
}
|
|
12287
|
+
async readClipboard(channel, req, cancelled) {
|
|
12288
|
+
if (channel.access === "write") throw new KernelError("EBADF");
|
|
12289
|
+
if (req.max <= 0) return new Uint8Array(0);
|
|
12290
|
+
if (channel.unread) channel.stamp = await this.clipboardStamp();
|
|
12291
|
+
const signal = channel.settled ? this.interrupt.signal : this.blockingSignal(cancelled);
|
|
12292
|
+
return channel.read(Math.min(req.max, MAX_READ), signal);
|
|
12293
|
+
}
|
|
12064
12294
|
async write(fd, body, nonblock = false, cancelled) {
|
|
12065
12295
|
const file = this.fds.get(fd).file;
|
|
12066
12296
|
if (file.sealed) return file.sealed.send(body, await this.sealedCaller(), this.gone.signal);
|
|
@@ -12164,6 +12394,36 @@ var WasmProcess = class {
|
|
|
12164
12394
|
if (!broker) throw new KernelError("ENOENT");
|
|
12165
12395
|
return this.fds.install(broker.open(), 3);
|
|
12166
12396
|
}
|
|
12397
|
+
async openClipboard(flags2) {
|
|
12398
|
+
const broker = this.options.clipboard;
|
|
12399
|
+
if (!broker) throw new KernelError("ENOENT");
|
|
12400
|
+
const mode = flags2 & WRITE_ACCESS;
|
|
12401
|
+
const access2 = mode === 0 ? "read" : mode === 1 ? "write" : "both";
|
|
12402
|
+
return this.fds.install(broker.open(access2, await this.clipboardStamp()), 3);
|
|
12403
|
+
}
|
|
12404
|
+
async clipboardStamp() {
|
|
12405
|
+
const shown = await this.options.identity?.();
|
|
12406
|
+
const broker = this.options.clipboard;
|
|
12407
|
+
const tag = broker.tagOf(this.pid);
|
|
12408
|
+
return {
|
|
12409
|
+
pid: shown?.pid ?? this.pid,
|
|
12410
|
+
uid: this.cred.euid,
|
|
12411
|
+
gid: this.cred.egid,
|
|
12412
|
+
users: broker.users,
|
|
12413
|
+
...tag !== void 0 ? { tag } : {}
|
|
12414
|
+
};
|
|
12415
|
+
}
|
|
12416
|
+
async stampClipboards() {
|
|
12417
|
+
if (!this.options.clipboard) return;
|
|
12418
|
+
const open = this.fds.numbers().filter((fd) => this.fds.get(fd).file.clipboard);
|
|
12419
|
+
if (open.length === 0) return;
|
|
12420
|
+
const stamp = await this.clipboardStamp().catch(() => void 0);
|
|
12421
|
+
if (!stamp) return;
|
|
12422
|
+
for (const fd of open) {
|
|
12423
|
+
const channel = this.fds.get(fd).file.clipboard;
|
|
12424
|
+
if (channel) channel.stamp = stamp;
|
|
12425
|
+
}
|
|
12426
|
+
}
|
|
12167
12427
|
async sealedCaller() {
|
|
12168
12428
|
const shown = await this.options.identity?.();
|
|
12169
12429
|
const broker = this.options.sealed;
|
|
@@ -12238,10 +12498,13 @@ var WasmProcess = class {
|
|
|
12238
12498
|
kind: "json",
|
|
12239
12499
|
json: await this.write(req.fd, req.body, req.nonblock, cancelled)
|
|
12240
12500
|
};
|
|
12241
|
-
case "fd-close":
|
|
12501
|
+
case "fd-close": {
|
|
12242
12502
|
this.options.locks?.closed(this.pid, req.fd);
|
|
12503
|
+
const channel = this.fds.get(req.fd).file.clipboard;
|
|
12504
|
+
if (channel) channel.stamp = await this.clipboardStamp();
|
|
12243
12505
|
await Promise.resolve(this.fds.close(req.fd));
|
|
12244
12506
|
return { ok: true, kind: "void" };
|
|
12507
|
+
}
|
|
12245
12508
|
case "fd-pipe": {
|
|
12246
12509
|
const pipe = openPipe();
|
|
12247
12510
|
const read = this.fds.install(pipe.read, 3);
|
|
@@ -12299,6 +12562,8 @@ var WasmProcess = class {
|
|
|
12299
12562
|
return { ok: true, kind: "json", json: this.options.jobs?.terminalNames() ?? [] };
|
|
12300
12563
|
case "fd-open-sealed":
|
|
12301
12564
|
return { ok: true, kind: "json", json: this.openSealed() };
|
|
12565
|
+
case "fd-open-clipboard":
|
|
12566
|
+
return { ok: true, kind: "json", json: await this.openClipboard(req.flags) };
|
|
12302
12567
|
case "fd-tty-owner":
|
|
12303
12568
|
return { ok: true, kind: "json", json: this.terminalByName(req.name).owner ?? null };
|
|
12304
12569
|
case "fd-select": {
|
|
@@ -12750,6 +13015,7 @@ var WasmProcess = class {
|
|
|
12750
13015
|
this.options.locks?.release(this.pid);
|
|
12751
13016
|
this.asyncOps.close();
|
|
12752
13017
|
for (const pid of this.children.pids()) this.options.onReap?.(pid);
|
|
13018
|
+
await this.stampClipboards();
|
|
12753
13019
|
await this.fds.closeAll();
|
|
12754
13020
|
if (!this.options.nodes) this.options.openFiles?.delete(this.nodes);
|
|
12755
13021
|
await this.options.http?.closeAll();
|
|
@@ -12932,6 +13198,7 @@ function processOptions(opts, header4, hooks, created3) {
|
|
|
12932
13198
|
...inherited(opts),
|
|
12933
13199
|
...opts.owners ? { owners: true } : {},
|
|
12934
13200
|
...opts.sealed ? { sealed: opts.sealed } : {},
|
|
13201
|
+
...opts.clipboard ? { clipboard: opts.clipboard } : {},
|
|
12935
13202
|
...opts.readonlyAt ? { readonlyAt: opts.readonlyAt } : {},
|
|
12936
13203
|
...opts.dac ? { guard: { dac: opts.dac, fs: opts.fs, created: created3 } } : {},
|
|
12937
13204
|
...opts.identity ? { identity: opts.identity } : {},
|
|
@@ -13436,14 +13703,14 @@ var SEALED_OPS = /* @__PURE__ */ new Set([
|
|
|
13436
13703
|
"cancel",
|
|
13437
13704
|
"materialize"
|
|
13438
13705
|
]);
|
|
13439
|
-
var
|
|
13440
|
-
var
|
|
13706
|
+
var encoder4 = new TextEncoder();
|
|
13707
|
+
var decoder3 = new TextDecoder("utf-8", { fatal: true });
|
|
13441
13708
|
function parseSealed(bytes) {
|
|
13442
13709
|
try {
|
|
13443
13710
|
if (bytes.length > SEALED_MAX_BYTES) throw new KernelError("EMSGSIZE");
|
|
13444
13711
|
let parsed2;
|
|
13445
13712
|
try {
|
|
13446
|
-
parsed2 = JSON.parse(
|
|
13713
|
+
parsed2 = JSON.parse(decoder3.decode(bytes));
|
|
13447
13714
|
} catch {
|
|
13448
13715
|
throw new KernelError("EINVAL");
|
|
13449
13716
|
}
|
|
@@ -13469,13 +13736,13 @@ function serialized(reply) {
|
|
|
13469
13736
|
const text = JSON.stringify(reply);
|
|
13470
13737
|
plain = text === void 0 ? void 0 : JSON.parse(text);
|
|
13471
13738
|
} catch (err) {
|
|
13472
|
-
return JSON.stringify(errorReply("EIO",
|
|
13739
|
+
return JSON.stringify(errorReply("EIO", lineOf2(err)));
|
|
13473
13740
|
}
|
|
13474
13741
|
if (!isRecord(plain)) return JSON.stringify(errorReply("EIO", "the vault gave no reply"));
|
|
13475
13742
|
const { v: _, ...rest2 } = plain;
|
|
13476
13743
|
return JSON.stringify({ v: 1, ...rest2 });
|
|
13477
13744
|
}
|
|
13478
|
-
function
|
|
13745
|
+
function lineOf2(err) {
|
|
13479
13746
|
const text = err instanceof Error ? err.message : String(err);
|
|
13480
13747
|
return (text.split("\n")[0] ?? "").slice(0, 200);
|
|
13481
13748
|
}
|
|
@@ -13505,7 +13772,7 @@ var SealedChannel = class {
|
|
|
13505
13772
|
gone.removeEventListener("abort", withdraw);
|
|
13506
13773
|
if (this.inflight !== flight) return;
|
|
13507
13774
|
this.inflight = void 0;
|
|
13508
|
-
if (reply) this.reply =
|
|
13775
|
+
if (reply) this.reply = encoder4.encode(serialized(reply));
|
|
13509
13776
|
});
|
|
13510
13777
|
this.inflight = flight;
|
|
13511
13778
|
return length2;
|
|
@@ -13519,7 +13786,7 @@ var SealedChannel = class {
|
|
|
13519
13786
|
if (signal.aborted) return void 0;
|
|
13520
13787
|
const asked = Promise.resolve().then(() => hook(req, { signal })).then(
|
|
13521
13788
|
(reply2) => isRecord(reply2) ? reply2 : errorReply("EIO", "the vault gave no reply"),
|
|
13522
|
-
(err) => errorReply("EIO",
|
|
13789
|
+
(err) => errorReply("EIO", lineOf2(err))
|
|
13523
13790
|
);
|
|
13524
13791
|
const reply = await Promise.race([asked, stopped]);
|
|
13525
13792
|
if (!signal.aborted) return reply;
|
|
@@ -14242,13 +14509,13 @@ var HostfsClient = class {
|
|
|
14242
14509
|
const response = await this.send("/api/hostfs/watch", { method: "POST", signal });
|
|
14243
14510
|
onOpen();
|
|
14244
14511
|
const reader = response.body.getReader();
|
|
14245
|
-
const
|
|
14512
|
+
const decoder4 = new TextDecoder();
|
|
14246
14513
|
let buffered = "";
|
|
14247
14514
|
try {
|
|
14248
14515
|
for (; ; ) {
|
|
14249
14516
|
const { done: done4, value } = await reader.read();
|
|
14250
14517
|
if (done4) return;
|
|
14251
|
-
buffered +=
|
|
14518
|
+
buffered += decoder4.decode(value, { stream: true });
|
|
14252
14519
|
let end = buffered.indexOf("\n");
|
|
14253
14520
|
while (end >= 0) {
|
|
14254
14521
|
const line = buffered.slice(0, end).trim();
|
|
@@ -15730,7 +15997,7 @@ var LAYOUT = [
|
|
|
15730
15997
|
];
|
|
15731
15998
|
var LOAD_SAMPLE_MS = 5e3;
|
|
15732
15999
|
var LOAD_WINDOWS_MS = [6e4, 3e5, 9e5];
|
|
15733
|
-
var
|
|
16000
|
+
var encoder5 = new TextEncoder();
|
|
15734
16001
|
var USERS_MODES = ["off", "report", "enforce"];
|
|
15735
16002
|
function usersMode(mode = "off") {
|
|
15736
16003
|
if (USERS_MODES.includes(mode)) return mode;
|
|
@@ -15887,6 +16154,7 @@ var Launcher = class {
|
|
|
15887
16154
|
usersMode;
|
|
15888
16155
|
dac;
|
|
15889
16156
|
sealed;
|
|
16157
|
+
clipboard;
|
|
15890
16158
|
rootFs;
|
|
15891
16159
|
fileWatches;
|
|
15892
16160
|
nextPid = 1e3;
|
|
@@ -15897,6 +16165,12 @@ var Launcher = class {
|
|
|
15897
16165
|
this.rootFs = options.fs;
|
|
15898
16166
|
this.dac = this.usersMode === "off" ? void 0 : new Dac(this.usersMode, options.onDenial);
|
|
15899
16167
|
if (this.dac) this.dac.tagOf = (pid) => this.tagOf(pid);
|
|
16168
|
+
this.clipboard = new ClipboardBroker(
|
|
16169
|
+
options.clipboard,
|
|
16170
|
+
this.usersMode,
|
|
16171
|
+
void 0,
|
|
16172
|
+
(pid) => this.tagOf(pid)
|
|
16173
|
+
);
|
|
15900
16174
|
this.sealed = new SealedBroker(
|
|
15901
16175
|
options.sealed,
|
|
15902
16176
|
this.usersMode,
|
|
@@ -16313,6 +16587,7 @@ var Launcher = class {
|
|
|
16313
16587
|
cred: req.cred,
|
|
16314
16588
|
...this.owners ? { owners: true } : {},
|
|
16315
16589
|
sealed: this.sealed,
|
|
16590
|
+
clipboard: this.clipboard,
|
|
16316
16591
|
...this.dac ? { dac: this.dac } : {},
|
|
16317
16592
|
program: req.program,
|
|
16318
16593
|
argv0: req.argv0,
|
|
@@ -17073,7 +17348,7 @@ var Launcher = class {
|
|
|
17073
17348
|
},
|
|
17074
17349
|
account
|
|
17075
17350
|
);
|
|
17076
|
-
const report = (message3) => options.onData(
|
|
17351
|
+
const report = (message3) => options.onData(encoder5.encode(`${message3}\r
|
|
17077
17352
|
`));
|
|
17078
17353
|
const handle = await this.launch(planned, {
|
|
17079
17354
|
env,
|
|
@@ -17110,7 +17385,7 @@ var Launcher = class {
|
|
|
17110
17385
|
};
|
|
17111
17386
|
const stdout = collect(out, options.onStdout);
|
|
17112
17387
|
const stderr = collect(err, options.onStderr);
|
|
17113
|
-
const report = (message3) => stderr(
|
|
17388
|
+
const report = (message3) => stderr(encoder5.encode(`${message3}
|
|
17114
17389
|
`));
|
|
17115
17390
|
if (!planned) {
|
|
17116
17391
|
report(`${file}: command not found`);
|
|
@@ -17647,7 +17922,7 @@ function dialStream(port, onClose) {
|
|
|
17647
17922
|
|
|
17648
17923
|
// src/client/loopback-fetch.ts
|
|
17649
17924
|
var OWN_HEADERS = /* @__PURE__ */ new Set(["host", "connection", "content-length", "transfer-encoding"]);
|
|
17650
|
-
var
|
|
17925
|
+
var encoder6 = new TextEncoder();
|
|
17651
17926
|
var latin12 = new TextDecoder("latin1");
|
|
17652
17927
|
var ByteSource = class {
|
|
17653
17928
|
buffered = new Uint8Array(0);
|
|
@@ -17658,14 +17933,14 @@ var ByteSource = class {
|
|
|
17658
17933
|
async more() {
|
|
17659
17934
|
const { done: done4, value } = await this.reader.read();
|
|
17660
17935
|
if (done4) return false;
|
|
17661
|
-
const
|
|
17662
|
-
|
|
17663
|
-
|
|
17664
|
-
this.buffered =
|
|
17936
|
+
const joined3 = new Uint8Array(this.buffered.length + value.length);
|
|
17937
|
+
joined3.set(this.buffered);
|
|
17938
|
+
joined3.set(value, this.buffered.length);
|
|
17939
|
+
this.buffered = joined3;
|
|
17665
17940
|
return true;
|
|
17666
17941
|
}
|
|
17667
17942
|
async until(marker) {
|
|
17668
|
-
const needle =
|
|
17943
|
+
const needle = encoder6.encode(marker);
|
|
17669
17944
|
for (; ; ) {
|
|
17670
17945
|
const at = indexOf(this.buffered, needle);
|
|
17671
17946
|
if (at >= 0) return this.take(at + needle.length);
|
|
@@ -17773,7 +18048,7 @@ async function requestBytes(request) {
|
|
|
17773
18048
|
});
|
|
17774
18049
|
if (body) lines2.push(`Content-Length: ${body.length}`);
|
|
17775
18050
|
lines2.push("Connection: close", "", "");
|
|
17776
|
-
const head =
|
|
18051
|
+
const head = encoder6.encode(lines2.join("\r\n"));
|
|
17777
18052
|
const out = new Uint8Array(head.length + (body?.length ?? 0));
|
|
17778
18053
|
out.set(head);
|
|
17779
18054
|
if (body) out.set(body, head.length);
|
|
@@ -17827,8 +18102,8 @@ var KernelCallError = class extends Error {
|
|
|
17827
18102
|
this.code = code;
|
|
17828
18103
|
}
|
|
17829
18104
|
};
|
|
17830
|
-
var
|
|
17831
|
-
var bytesOf2 = (data) => typeof data === "string" ?
|
|
18105
|
+
var encoder7 = new TextEncoder();
|
|
18106
|
+
var bytesOf2 = (data) => typeof data === "string" ? encoder7.encode(data) : data;
|
|
17832
18107
|
var UNAVAILABLE = {
|
|
17833
18108
|
manualRedirects: false,
|
|
17834
18109
|
encodedBodies: false,
|
|
@@ -18246,8 +18521,8 @@ function nodeWorker(file, live, closed) {
|
|
|
18246
18521
|
}
|
|
18247
18522
|
function textOf(on) {
|
|
18248
18523
|
if (!on) return void 0;
|
|
18249
|
-
const
|
|
18250
|
-
return (bytes) => on(
|
|
18524
|
+
const decoder4 = new TextDecoder();
|
|
18525
|
+
return (bytes) => on(decoder4.decode(bytes, { stream: true }));
|
|
18251
18526
|
}
|
|
18252
18527
|
async function createNodeKernel(options = {}) {
|
|
18253
18528
|
const root = options.root ?? memoryRoot();
|
|
@@ -18282,6 +18557,7 @@ async function createNodeKernel(options = {}) {
|
|
|
18282
18557
|
...options.onDenial ? { onDenial: options.onDenial } : {},
|
|
18283
18558
|
...options.protect ? { protect: options.protect } : {},
|
|
18284
18559
|
...options.sealed ? { sealed: options.sealed } : {},
|
|
18560
|
+
...options.clipboard ? { clipboard: options.clipboard } : {},
|
|
18285
18561
|
...options.approve ? { approve: options.approve } : {}
|
|
18286
18562
|
});
|
|
18287
18563
|
await launcher.prepare();
|
|
@@ -18290,7 +18566,7 @@ async function createNodeKernel(options = {}) {
|
|
|
18290
18566
|
pending.add(reject);
|
|
18291
18567
|
work().then(resolve, reject).finally(() => pending.delete(reject));
|
|
18292
18568
|
});
|
|
18293
|
-
const
|
|
18569
|
+
const decoder4 = new TextDecoder();
|
|
18294
18570
|
return {
|
|
18295
18571
|
root,
|
|
18296
18572
|
async run(argv, opts = {}) {
|
|
@@ -18307,8 +18583,8 @@ async function createNodeKernel(options = {}) {
|
|
|
18307
18583
|
);
|
|
18308
18584
|
return {
|
|
18309
18585
|
status: result.status,
|
|
18310
|
-
stdout:
|
|
18311
|
-
stderr:
|
|
18586
|
+
stdout: decoder4.decode(result.stdout),
|
|
18587
|
+
stderr: decoder4.decode(result.stderr)
|
|
18312
18588
|
};
|
|
18313
18589
|
},
|
|
18314
18590
|
async openTerminal(argv, opts = {}) {
|