@ai-ecoverse/slicc-kernel 1.73.3 → 1.75.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 +16 -2
- package/dist/index.js +56 -8
- package/dist/index.js.map +4 -4
- package/dist/kernel-worker.js +320 -32
- package/dist/kernel-worker.js.map +4 -4
- package/dist/node-process-worker.js +198 -35
- package/dist/node-process-worker.js.map +3 -3
- package/dist/node.js +298 -43
- package/dist/node.js.map +4 -4
- package/dist/process-worker.js +198 -35
- package/dist/process-worker.js.map +3 -3
- package/package.json +2 -2
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 {
|
|
@@ -6070,6 +6073,173 @@ var ChildTable = class {
|
|
|
6070
6073
|
}
|
|
6071
6074
|
};
|
|
6072
6075
|
|
|
6076
|
+
// src/kernel/clipboard.ts
|
|
6077
|
+
var CLIPBOARD_MAX_BYTES = 1024 * 1024;
|
|
6078
|
+
var CLIPBOARD_TIMEOUT_MS = 1e4;
|
|
6079
|
+
var encoder = new TextEncoder();
|
|
6080
|
+
var decoder = new TextDecoder("utf-8", { fatal: true });
|
|
6081
|
+
var READY = { readable: true, writable: true, hangup: false };
|
|
6082
|
+
function lineOf(err) {
|
|
6083
|
+
const text = err instanceof Error ? err.message : String(err);
|
|
6084
|
+
return (text.split("\n")[0] ?? "").slice(0, 200);
|
|
6085
|
+
}
|
|
6086
|
+
function clipboardFailure(err) {
|
|
6087
|
+
if (err instanceof KernelError) return err;
|
|
6088
|
+
const name2 = err?.name;
|
|
6089
|
+
return new KernelError(name2 === "NotAllowedError" ? "EACCES" : "EIO", lineOf(err));
|
|
6090
|
+
}
|
|
6091
|
+
function joined2(chunks2, size) {
|
|
6092
|
+
if (chunks2.length === 1) return chunks2[0];
|
|
6093
|
+
const out = new Uint8Array(size);
|
|
6094
|
+
let at = 0;
|
|
6095
|
+
for (const chunk2 of chunks2) {
|
|
6096
|
+
out.set(chunk2, at);
|
|
6097
|
+
at += chunk2.length;
|
|
6098
|
+
}
|
|
6099
|
+
return out;
|
|
6100
|
+
}
|
|
6101
|
+
async function interruptible(work, signal) {
|
|
6102
|
+
if (!signal) return work;
|
|
6103
|
+
if (signal.aborted) throw new KernelError("EINTR");
|
|
6104
|
+
let stop = () => {
|
|
6105
|
+
};
|
|
6106
|
+
const interrupted2 = new Promise((_, reject) => {
|
|
6107
|
+
stop = () => reject(new KernelError("EINTR"));
|
|
6108
|
+
signal.addEventListener("abort", stop, { once: true });
|
|
6109
|
+
});
|
|
6110
|
+
try {
|
|
6111
|
+
return await Promise.race([work, interrupted2]);
|
|
6112
|
+
} finally {
|
|
6113
|
+
signal.removeEventListener("abort", stop);
|
|
6114
|
+
}
|
|
6115
|
+
}
|
|
6116
|
+
var ClipboardChannel = class {
|
|
6117
|
+
stamp;
|
|
6118
|
+
access;
|
|
6119
|
+
broker;
|
|
6120
|
+
snapshot;
|
|
6121
|
+
taken;
|
|
6122
|
+
offset = 0;
|
|
6123
|
+
chunks = [];
|
|
6124
|
+
size = 0;
|
|
6125
|
+
wrote = false;
|
|
6126
|
+
failed = false;
|
|
6127
|
+
constructor(broker, access2, stamp) {
|
|
6128
|
+
this.broker = broker;
|
|
6129
|
+
this.access = access2;
|
|
6130
|
+
this.stamp = stamp;
|
|
6131
|
+
}
|
|
6132
|
+
get unread() {
|
|
6133
|
+
return this.taken === void 0 && this.snapshot === void 0;
|
|
6134
|
+
}
|
|
6135
|
+
get settled() {
|
|
6136
|
+
return this.taken !== void 0;
|
|
6137
|
+
}
|
|
6138
|
+
async read(max, signal) {
|
|
6139
|
+
if (this.access === "write") throw new KernelError("EBADF");
|
|
6140
|
+
if (!this.taken) {
|
|
6141
|
+
if (!this.snapshot) {
|
|
6142
|
+
const stamp = this.stamp;
|
|
6143
|
+
const asked = this.broker.ask(async (hook) => {
|
|
6144
|
+
const text = await hook.read(stamp);
|
|
6145
|
+
if (typeof text !== "string") throw new KernelError("EIO", "the clipboard gave no text");
|
|
6146
|
+
return encoder.encode(text);
|
|
6147
|
+
});
|
|
6148
|
+
this.snapshot = asked;
|
|
6149
|
+
asked.then(
|
|
6150
|
+
(bytes) => {
|
|
6151
|
+
if (this.snapshot === asked) this.taken = bytes;
|
|
6152
|
+
},
|
|
6153
|
+
() => {
|
|
6154
|
+
if (this.snapshot === asked) this.snapshot = void 0;
|
|
6155
|
+
}
|
|
6156
|
+
);
|
|
6157
|
+
}
|
|
6158
|
+
this.taken = await interruptible(this.snapshot, signal);
|
|
6159
|
+
}
|
|
6160
|
+
const out = this.taken.subarray(this.offset, this.offset + max);
|
|
6161
|
+
this.offset += out.length;
|
|
6162
|
+
return out;
|
|
6163
|
+
}
|
|
6164
|
+
write(bytes) {
|
|
6165
|
+
if (this.access === "read") throw new KernelError("EBADF");
|
|
6166
|
+
this.wrote = true;
|
|
6167
|
+
if (this.failed) throw new KernelError("EFBIG");
|
|
6168
|
+
if (this.size + bytes.length > CLIPBOARD_MAX_BYTES) {
|
|
6169
|
+
this.failed = true;
|
|
6170
|
+
this.chunks = [];
|
|
6171
|
+
this.size = 0;
|
|
6172
|
+
throw new KernelError("EFBIG");
|
|
6173
|
+
}
|
|
6174
|
+
if (bytes.length > 0) this.chunks.push(bytes.slice());
|
|
6175
|
+
this.size += bytes.length;
|
|
6176
|
+
return bytes.length;
|
|
6177
|
+
}
|
|
6178
|
+
poll() {
|
|
6179
|
+
return READY;
|
|
6180
|
+
}
|
|
6181
|
+
async close() {
|
|
6182
|
+
this.snapshot = void 0;
|
|
6183
|
+
this.taken = void 0;
|
|
6184
|
+
const commits = this.access === "write" || this.access === "both" && this.wrote;
|
|
6185
|
+
if (!commits || this.failed) return;
|
|
6186
|
+
const bytes = joined2(this.chunks, this.size);
|
|
6187
|
+
this.chunks = [];
|
|
6188
|
+
this.size = 0;
|
|
6189
|
+
let text;
|
|
6190
|
+
try {
|
|
6191
|
+
text = decoder.decode(bytes);
|
|
6192
|
+
} catch {
|
|
6193
|
+
throw new KernelError("EILSEQ", "the text is not valid UTF-8");
|
|
6194
|
+
}
|
|
6195
|
+
const stamp = this.stamp;
|
|
6196
|
+
await this.broker.ask(async (hook) => {
|
|
6197
|
+
await hook.write(text, stamp);
|
|
6198
|
+
});
|
|
6199
|
+
}
|
|
6200
|
+
};
|
|
6201
|
+
var ClipboardBroker = class {
|
|
6202
|
+
hook;
|
|
6203
|
+
users;
|
|
6204
|
+
timeoutMs;
|
|
6205
|
+
tagOf;
|
|
6206
|
+
constructor(hook, users, timeoutMs = CLIPBOARD_TIMEOUT_MS, tagOf = () => void 0) {
|
|
6207
|
+
this.hook = hook;
|
|
6208
|
+
this.users = users;
|
|
6209
|
+
this.timeoutMs = timeoutMs;
|
|
6210
|
+
this.tagOf = tagOf;
|
|
6211
|
+
}
|
|
6212
|
+
async ask(work) {
|
|
6213
|
+
const hook = this.hook;
|
|
6214
|
+
if (!hook) throw new KernelError("ENOTSUP", "no clipboard in this embedder");
|
|
6215
|
+
let timer;
|
|
6216
|
+
const late = new Promise((_, reject) => {
|
|
6217
|
+
timer = setTimeout(
|
|
6218
|
+
() => reject(new KernelError("EIO", "clipboard timed out")),
|
|
6219
|
+
this.timeoutMs
|
|
6220
|
+
);
|
|
6221
|
+
});
|
|
6222
|
+
const asked = Promise.resolve().then(() => work(hook)).catch((err) => {
|
|
6223
|
+
throw clipboardFailure(err);
|
|
6224
|
+
});
|
|
6225
|
+
try {
|
|
6226
|
+
return await Promise.race([asked, late]);
|
|
6227
|
+
} finally {
|
|
6228
|
+
clearTimeout(timer);
|
|
6229
|
+
}
|
|
6230
|
+
}
|
|
6231
|
+
open(access2, stamp) {
|
|
6232
|
+
const channel = new ClipboardChannel(this, access2, stamp);
|
|
6233
|
+
return new OpenFile({
|
|
6234
|
+
read: (max, signal) => channel.read(max, signal),
|
|
6235
|
+
write: async (bytes) => channel.write(bytes),
|
|
6236
|
+
poll: () => channel.poll(),
|
|
6237
|
+
close: () => channel.close(),
|
|
6238
|
+
clipboard: channel
|
|
6239
|
+
});
|
|
6240
|
+
}
|
|
6241
|
+
};
|
|
6242
|
+
|
|
6073
6243
|
// src/mount/protocol.ts
|
|
6074
6244
|
var DRIVER_PROTOCOL = [1, 2];
|
|
6075
6245
|
function driverVersionError(theirs) {
|
|
@@ -7607,20 +7777,20 @@ var SAB_DEFAULT_WINDOW_BYTES = 1024 * 1024;
|
|
|
7607
7777
|
var SAB_MIN_BYTES = SAB_HEADER_BYTES + 4096;
|
|
7608
7778
|
var SYNC_SAB_REQ_MSG = "sync-sab-req";
|
|
7609
7779
|
var SYNC_SAB_NEXT_MSG = "sync-sab-next";
|
|
7610
|
-
var
|
|
7611
|
-
var
|
|
7780
|
+
var encoder2 = new TextEncoder();
|
|
7781
|
+
var decoder2 = new TextDecoder();
|
|
7612
7782
|
function encodeSabResult(result) {
|
|
7613
7783
|
if (!result.ok) {
|
|
7614
7784
|
return {
|
|
7615
7785
|
status: SAB_STATUS_ERRNO,
|
|
7616
|
-
payload:
|
|
7786
|
+
payload: encoder2.encode(JSON.stringify({ errno: result.errno, message: result.message }))
|
|
7617
7787
|
};
|
|
7618
7788
|
}
|
|
7619
7789
|
switch (result.kind) {
|
|
7620
7790
|
case "bytes":
|
|
7621
7791
|
return { status: SAB_STATUS_BYTES, payload: result.bytes };
|
|
7622
7792
|
case "json":
|
|
7623
|
-
return { status: SAB_STATUS_JSON, payload:
|
|
7793
|
+
return { status: SAB_STATUS_JSON, payload: encoder2.encode(JSON.stringify(result.json)) };
|
|
7624
7794
|
default:
|
|
7625
7795
|
return { status: SAB_STATUS_VOID, payload: new Uint8Array(0) };
|
|
7626
7796
|
}
|
|
@@ -10442,7 +10612,7 @@ function defaultTermios() {
|
|
|
10442
10612
|
c_cc: cCc
|
|
10443
10613
|
};
|
|
10444
10614
|
}
|
|
10445
|
-
var
|
|
10615
|
+
var encoder3 = new TextEncoder();
|
|
10446
10616
|
function isContinuation(byte) {
|
|
10447
10617
|
return (byte & 192) === 128;
|
|
10448
10618
|
}
|
|
@@ -10564,7 +10734,7 @@ var KernelTty = class {
|
|
|
10564
10734
|
this.line.push(byte);
|
|
10565
10735
|
this.readable.push(Uint8Array.from(this.line));
|
|
10566
10736
|
this.line = [];
|
|
10567
|
-
if (echo) this.output(
|
|
10737
|
+
if (echo) this.output(encoder3.encode("\n"));
|
|
10568
10738
|
} else {
|
|
10569
10739
|
this.line.push(byte);
|
|
10570
10740
|
if (echo) this.echo(byte);
|
|
@@ -10589,7 +10759,7 @@ var KernelTty = class {
|
|
|
10589
10759
|
const utf82 = (this.termios.c_iflag & IUTF8) !== 0;
|
|
10590
10760
|
const cells = utf82 ? dropped2.filter((b) => !isContinuation(b)).length : dropped2.length;
|
|
10591
10761
|
if (cells > 0 && this.termios.c_lflag & ECHO) {
|
|
10592
|
-
this.output(
|
|
10762
|
+
this.output(encoder3.encode("\b \b".repeat(cells)), false);
|
|
10593
10763
|
}
|
|
10594
10764
|
}
|
|
10595
10765
|
echo(byte) {
|
|
@@ -10939,7 +11109,14 @@ async function runChild(req, deps) {
|
|
|
10939
11109
|
];
|
|
10940
11110
|
try {
|
|
10941
11111
|
pid = await deps.children.spawn(
|
|
10942
|
-
{
|
|
11112
|
+
{
|
|
11113
|
+
file: req.file,
|
|
11114
|
+
argv: req.argv,
|
|
11115
|
+
env: req.env,
|
|
11116
|
+
cwd: req.cwd,
|
|
11117
|
+
...req.pgid !== void 0 ? { pgid: req.pgid } : {},
|
|
11118
|
+
...req.session ? { session: req.session } : {}
|
|
11119
|
+
},
|
|
10943
11120
|
stdio
|
|
10944
11121
|
);
|
|
10945
11122
|
} catch (e) {
|
|
@@ -11071,7 +11248,7 @@ async function socketSyscall(req, proc) {
|
|
|
11071
11248
|
dialing?.catch(() => void 0);
|
|
11072
11249
|
throw new KernelError("EINPROGRESS");
|
|
11073
11250
|
}
|
|
11074
|
-
if (dialing !== void 0) await
|
|
11251
|
+
if (dialing !== void 0) await interruptible2(dialing, proc.blocking());
|
|
11075
11252
|
return ok();
|
|
11076
11253
|
}
|
|
11077
11254
|
case "sock-shutdown":
|
|
@@ -11095,7 +11272,7 @@ async function socketSyscall(req, proc) {
|
|
|
11095
11272
|
}
|
|
11096
11273
|
}
|
|
11097
11274
|
}
|
|
11098
|
-
function
|
|
11275
|
+
function interruptible2(dialing, signal) {
|
|
11099
11276
|
return new Promise((resolve, reject) => {
|
|
11100
11277
|
const abort = () => reject(new KernelError("EINTR"));
|
|
11101
11278
|
signal.addEventListener("abort", abort, { once: true });
|
|
@@ -11762,6 +11939,7 @@ var SYSCALL_OPS = /* @__PURE__ */ new Set([
|
|
|
11762
11939
|
"fd-tty-names",
|
|
11763
11940
|
"fd-tty-owner",
|
|
11764
11941
|
"fd-open-sealed",
|
|
11942
|
+
"fd-open-clipboard",
|
|
11765
11943
|
"tty-get",
|
|
11766
11944
|
"tty-set",
|
|
11767
11945
|
"tty-winsz",
|
|
@@ -11892,8 +12070,9 @@ var WasmProcess = class {
|
|
|
11892
12070
|
return "deliver";
|
|
11893
12071
|
}
|
|
11894
12072
|
async spawn(req) {
|
|
11895
|
-
const { file, argv, env, cwd, stdio, inherit: inherit2, exec } = req;
|
|
11896
|
-
const
|
|
12073
|
+
const { file, argv, env, cwd, stdio, inherit: inherit2, exec, pgid, session } = req;
|
|
12074
|
+
const group = { ...pgid !== void 0 ? { pgid } : {}, ...session ? { session } : {} };
|
|
12075
|
+
const spawned = { file, argv, env, cwd, ...group, ...exec ? { exec } : {} };
|
|
11897
12076
|
const pid = await this.children.spawn(spawned, stdio, inherit2);
|
|
11898
12077
|
if (!exec) return pid;
|
|
11899
12078
|
if (this.killed) void Promise.allSettled([this.options.kill?.(pid, SIG.KILL)]);
|
|
@@ -12003,7 +12182,7 @@ var WasmProcess = class {
|
|
|
12003
12182
|
return await this.procSyscall(req, cancelled);
|
|
12004
12183
|
} catch (e) {
|
|
12005
12184
|
if (e instanceof KernelError || e instanceof SpawnError) {
|
|
12006
|
-
return { ok: false, errno: e.code, message: e.code };
|
|
12185
|
+
return { ok: false, errno: e.code, message: e.detail ?? e.code };
|
|
12007
12186
|
}
|
|
12008
12187
|
const code = e?.code;
|
|
12009
12188
|
if (typeof code === "string" && /^E[A-Z]+$/.test(code)) {
|
|
@@ -12046,6 +12225,7 @@ var WasmProcess = class {
|
|
|
12046
12225
|
const read = req.peek ? file.peek : file.read;
|
|
12047
12226
|
if (!read) throw new KernelError(req.peek && file.read ? "EOPNOTSUPP" : "EBADF");
|
|
12048
12227
|
if (file.tty) this.checkForeground(file.tty);
|
|
12228
|
+
if (file.clipboard) return this.readClipboard(file.clipboard, req, cancelled);
|
|
12049
12229
|
if (req.max <= 0) return new Uint8Array(0);
|
|
12050
12230
|
if (file instanceof KernelSocket && file.unconnected) throw new KernelError("ENOTCONN");
|
|
12051
12231
|
const ready2 = pollFile(file).readable;
|
|
@@ -12053,6 +12233,13 @@ var WasmProcess = class {
|
|
|
12053
12233
|
const signal = ready2 ? this.interrupt.signal : this.blockingSignal(cancelled);
|
|
12054
12234
|
return read.call(file, Math.max(0, Math.min(req.max, MAX_READ)), signal);
|
|
12055
12235
|
}
|
|
12236
|
+
async readClipboard(channel, req, cancelled) {
|
|
12237
|
+
if (channel.access === "write") throw new KernelError("EBADF");
|
|
12238
|
+
if (req.max <= 0) return new Uint8Array(0);
|
|
12239
|
+
if (channel.unread) channel.stamp = await this.clipboardStamp();
|
|
12240
|
+
const signal = channel.settled ? this.interrupt.signal : this.blockingSignal(cancelled);
|
|
12241
|
+
return channel.read(Math.min(req.max, MAX_READ), signal);
|
|
12242
|
+
}
|
|
12056
12243
|
async write(fd, body, nonblock = false, cancelled) {
|
|
12057
12244
|
const file = this.fds.get(fd).file;
|
|
12058
12245
|
if (file.sealed) return file.sealed.send(body, await this.sealedCaller(), this.gone.signal);
|
|
@@ -12156,6 +12343,36 @@ var WasmProcess = class {
|
|
|
12156
12343
|
if (!broker) throw new KernelError("ENOENT");
|
|
12157
12344
|
return this.fds.install(broker.open(), 3);
|
|
12158
12345
|
}
|
|
12346
|
+
async openClipboard(flags2) {
|
|
12347
|
+
const broker = this.options.clipboard;
|
|
12348
|
+
if (!broker) throw new KernelError("ENOENT");
|
|
12349
|
+
const mode = flags2 & WRITE_ACCESS;
|
|
12350
|
+
const access2 = mode === 0 ? "read" : mode === 1 ? "write" : "both";
|
|
12351
|
+
return this.fds.install(broker.open(access2, await this.clipboardStamp()), 3);
|
|
12352
|
+
}
|
|
12353
|
+
async clipboardStamp() {
|
|
12354
|
+
const shown = await this.options.identity?.();
|
|
12355
|
+
const broker = this.options.clipboard;
|
|
12356
|
+
const tag = broker.tagOf(this.pid);
|
|
12357
|
+
return {
|
|
12358
|
+
pid: shown?.pid ?? this.pid,
|
|
12359
|
+
uid: this.cred.euid,
|
|
12360
|
+
gid: this.cred.egid,
|
|
12361
|
+
users: broker.users,
|
|
12362
|
+
...tag !== void 0 ? { tag } : {}
|
|
12363
|
+
};
|
|
12364
|
+
}
|
|
12365
|
+
async stampClipboards() {
|
|
12366
|
+
if (!this.options.clipboard) return;
|
|
12367
|
+
const open = this.fds.numbers().filter((fd) => this.fds.get(fd).file.clipboard);
|
|
12368
|
+
if (open.length === 0) return;
|
|
12369
|
+
const stamp = await this.clipboardStamp().catch(() => void 0);
|
|
12370
|
+
if (!stamp) return;
|
|
12371
|
+
for (const fd of open) {
|
|
12372
|
+
const channel = this.fds.get(fd).file.clipboard;
|
|
12373
|
+
if (channel) channel.stamp = stamp;
|
|
12374
|
+
}
|
|
12375
|
+
}
|
|
12159
12376
|
async sealedCaller() {
|
|
12160
12377
|
const shown = await this.options.identity?.();
|
|
12161
12378
|
const broker = this.options.sealed;
|
|
@@ -12230,10 +12447,13 @@ var WasmProcess = class {
|
|
|
12230
12447
|
kind: "json",
|
|
12231
12448
|
json: await this.write(req.fd, req.body, req.nonblock, cancelled)
|
|
12232
12449
|
};
|
|
12233
|
-
case "fd-close":
|
|
12450
|
+
case "fd-close": {
|
|
12234
12451
|
this.options.locks?.closed(this.pid, req.fd);
|
|
12452
|
+
const channel = this.fds.get(req.fd).file.clipboard;
|
|
12453
|
+
if (channel) channel.stamp = await this.clipboardStamp();
|
|
12235
12454
|
await Promise.resolve(this.fds.close(req.fd));
|
|
12236
12455
|
return { ok: true, kind: "void" };
|
|
12456
|
+
}
|
|
12237
12457
|
case "fd-pipe": {
|
|
12238
12458
|
const pipe = openPipe();
|
|
12239
12459
|
const read = this.fds.install(pipe.read, 3);
|
|
@@ -12291,6 +12511,8 @@ var WasmProcess = class {
|
|
|
12291
12511
|
return { ok: true, kind: "json", json: this.options.jobs?.terminalNames() ?? [] };
|
|
12292
12512
|
case "fd-open-sealed":
|
|
12293
12513
|
return { ok: true, kind: "json", json: this.openSealed() };
|
|
12514
|
+
case "fd-open-clipboard":
|
|
12515
|
+
return { ok: true, kind: "json", json: await this.openClipboard(req.flags) };
|
|
12294
12516
|
case "fd-tty-owner":
|
|
12295
12517
|
return { ok: true, kind: "json", json: this.terminalByName(req.name).owner ?? null };
|
|
12296
12518
|
case "fd-select": {
|
|
@@ -12742,6 +12964,7 @@ var WasmProcess = class {
|
|
|
12742
12964
|
this.options.locks?.release(this.pid);
|
|
12743
12965
|
this.asyncOps.close();
|
|
12744
12966
|
for (const pid of this.children.pids()) this.options.onReap?.(pid);
|
|
12967
|
+
await this.stampClipboards();
|
|
12745
12968
|
await this.fds.closeAll();
|
|
12746
12969
|
if (!this.options.nodes) this.options.openFiles?.delete(this.nodes);
|
|
12747
12970
|
await this.options.http?.closeAll();
|
|
@@ -12924,6 +13147,7 @@ function processOptions(opts, header4, hooks, created3) {
|
|
|
12924
13147
|
...inherited(opts),
|
|
12925
13148
|
...opts.owners ? { owners: true } : {},
|
|
12926
13149
|
...opts.sealed ? { sealed: opts.sealed } : {},
|
|
13150
|
+
...opts.clipboard ? { clipboard: opts.clipboard } : {},
|
|
12927
13151
|
...opts.readonlyAt ? { readonlyAt: opts.readonlyAt } : {},
|
|
12928
13152
|
...opts.dac ? { guard: { dac: opts.dac, fs: opts.fs, created: created3 } } : {},
|
|
12929
13153
|
...opts.identity ? { identity: opts.identity } : {},
|
|
@@ -13187,6 +13411,9 @@ var JobTable = class {
|
|
|
13187
13411
|
member.pgid = pgid;
|
|
13188
13412
|
member.sid = sid;
|
|
13189
13413
|
}
|
|
13414
|
+
lead(pid) {
|
|
13415
|
+
this.member(pid).pgid = this.idOf(pid);
|
|
13416
|
+
}
|
|
13190
13417
|
pgidOf(pid) {
|
|
13191
13418
|
return this.members.get(pid)?.pgid;
|
|
13192
13419
|
}
|
|
@@ -13425,14 +13652,14 @@ var SEALED_OPS = /* @__PURE__ */ new Set([
|
|
|
13425
13652
|
"cancel",
|
|
13426
13653
|
"materialize"
|
|
13427
13654
|
]);
|
|
13428
|
-
var
|
|
13429
|
-
var
|
|
13655
|
+
var encoder4 = new TextEncoder();
|
|
13656
|
+
var decoder3 = new TextDecoder("utf-8", { fatal: true });
|
|
13430
13657
|
function parseSealed(bytes) {
|
|
13431
13658
|
try {
|
|
13432
13659
|
if (bytes.length > SEALED_MAX_BYTES) throw new KernelError("EMSGSIZE");
|
|
13433
13660
|
let parsed2;
|
|
13434
13661
|
try {
|
|
13435
|
-
parsed2 = JSON.parse(
|
|
13662
|
+
parsed2 = JSON.parse(decoder3.decode(bytes));
|
|
13436
13663
|
} catch {
|
|
13437
13664
|
throw new KernelError("EINVAL");
|
|
13438
13665
|
}
|
|
@@ -13458,13 +13685,13 @@ function serialized(reply) {
|
|
|
13458
13685
|
const text = JSON.stringify(reply);
|
|
13459
13686
|
plain = text === void 0 ? void 0 : JSON.parse(text);
|
|
13460
13687
|
} catch (err) {
|
|
13461
|
-
return JSON.stringify(errorReply("EIO",
|
|
13688
|
+
return JSON.stringify(errorReply("EIO", lineOf2(err)));
|
|
13462
13689
|
}
|
|
13463
13690
|
if (!isRecord(plain)) return JSON.stringify(errorReply("EIO", "the vault gave no reply"));
|
|
13464
13691
|
const { v: _, ...rest2 } = plain;
|
|
13465
13692
|
return JSON.stringify({ v: 1, ...rest2 });
|
|
13466
13693
|
}
|
|
13467
|
-
function
|
|
13694
|
+
function lineOf2(err) {
|
|
13468
13695
|
const text = err instanceof Error ? err.message : String(err);
|
|
13469
13696
|
return (text.split("\n")[0] ?? "").slice(0, 200);
|
|
13470
13697
|
}
|
|
@@ -13494,7 +13721,7 @@ var SealedChannel = class {
|
|
|
13494
13721
|
gone.removeEventListener("abort", withdraw);
|
|
13495
13722
|
if (this.inflight !== flight) return;
|
|
13496
13723
|
this.inflight = void 0;
|
|
13497
|
-
if (reply) this.reply =
|
|
13724
|
+
if (reply) this.reply = encoder4.encode(serialized(reply));
|
|
13498
13725
|
});
|
|
13499
13726
|
this.inflight = flight;
|
|
13500
13727
|
return length2;
|
|
@@ -13508,7 +13735,7 @@ var SealedChannel = class {
|
|
|
13508
13735
|
if (signal.aborted) return void 0;
|
|
13509
13736
|
const asked = Promise.resolve().then(() => hook(req, { signal })).then(
|
|
13510
13737
|
(reply2) => isRecord(reply2) ? reply2 : errorReply("EIO", "the vault gave no reply"),
|
|
13511
|
-
(err) => errorReply("EIO",
|
|
13738
|
+
(err) => errorReply("EIO", lineOf2(err))
|
|
13512
13739
|
);
|
|
13513
13740
|
const reply = await Promise.race([asked, stopped]);
|
|
13514
13741
|
if (!signal.aborted) return reply;
|
|
@@ -14231,13 +14458,13 @@ var HostfsClient = class {
|
|
|
14231
14458
|
const response = await this.send("/api/hostfs/watch", { method: "POST", signal });
|
|
14232
14459
|
onOpen();
|
|
14233
14460
|
const reader = response.body.getReader();
|
|
14234
|
-
const
|
|
14461
|
+
const decoder4 = new TextDecoder();
|
|
14235
14462
|
let buffered = "";
|
|
14236
14463
|
try {
|
|
14237
14464
|
for (; ; ) {
|
|
14238
14465
|
const { done: done4, value } = await reader.read();
|
|
14239
14466
|
if (done4) return;
|
|
14240
|
-
buffered +=
|
|
14467
|
+
buffered += decoder4.decode(value, { stream: true });
|
|
14241
14468
|
let end = buffered.indexOf("\n");
|
|
14242
14469
|
while (end >= 0) {
|
|
14243
14470
|
const line = buffered.slice(0, end).trim();
|
|
@@ -15719,7 +15946,7 @@ var LAYOUT = [
|
|
|
15719
15946
|
];
|
|
15720
15947
|
var LOAD_SAMPLE_MS = 5e3;
|
|
15721
15948
|
var LOAD_WINDOWS_MS = [6e4, 3e5, 9e5];
|
|
15722
|
-
var
|
|
15949
|
+
var encoder5 = new TextEncoder();
|
|
15723
15950
|
var USERS_MODES = ["off", "report", "enforce"];
|
|
15724
15951
|
function usersMode(mode = "off") {
|
|
15725
15952
|
if (USERS_MODES.includes(mode)) return mode;
|
|
@@ -15876,6 +16103,7 @@ var Launcher = class {
|
|
|
15876
16103
|
usersMode;
|
|
15877
16104
|
dac;
|
|
15878
16105
|
sealed;
|
|
16106
|
+
clipboard;
|
|
15879
16107
|
rootFs;
|
|
15880
16108
|
fileWatches;
|
|
15881
16109
|
nextPid = 1e3;
|
|
@@ -15886,6 +16114,12 @@ var Launcher = class {
|
|
|
15886
16114
|
this.rootFs = options.fs;
|
|
15887
16115
|
this.dac = this.usersMode === "off" ? void 0 : new Dac(this.usersMode, options.onDenial);
|
|
15888
16116
|
if (this.dac) this.dac.tagOf = (pid) => this.tagOf(pid);
|
|
16117
|
+
this.clipboard = new ClipboardBroker(
|
|
16118
|
+
options.clipboard,
|
|
16119
|
+
this.usersMode,
|
|
16120
|
+
void 0,
|
|
16121
|
+
(pid) => this.tagOf(pid)
|
|
16122
|
+
);
|
|
15889
16123
|
this.sealed = new SealedBroker(
|
|
15890
16124
|
options.sealed,
|
|
15891
16125
|
this.usersMode,
|
|
@@ -16275,7 +16509,7 @@ var Launcher = class {
|
|
|
16275
16509
|
start(req) {
|
|
16276
16510
|
this.sampling();
|
|
16277
16511
|
if (req.pgid !== void 0 && this.jobs.sessionOf(req.pgid) === void 0) {
|
|
16278
|
-
throw
|
|
16512
|
+
throw new SpawnError("ESRCH");
|
|
16279
16513
|
}
|
|
16280
16514
|
const pid = this.nextPid++;
|
|
16281
16515
|
const stack = this.stackFor(req.tag);
|
|
@@ -16302,6 +16536,7 @@ var Launcher = class {
|
|
|
16302
16536
|
cred: req.cred,
|
|
16303
16537
|
...this.owners ? { owners: true } : {},
|
|
16304
16538
|
sealed: this.sealed,
|
|
16539
|
+
clipboard: this.clipboard,
|
|
16305
16540
|
...this.dac ? { dac: this.dac } : {},
|
|
16306
16541
|
program: req.program,
|
|
16307
16542
|
argv0: req.argv0,
|
|
@@ -16350,6 +16585,8 @@ var Launcher = class {
|
|
|
16350
16585
|
this.jobs.add(pid, req.ppid, (sig) => handle.signal(sig), terminal);
|
|
16351
16586
|
if (req.exec && req.ppid !== void 0) this.jobs.exec(req.ppid, pid, true);
|
|
16352
16587
|
if (req.pgid !== void 0) this.jobs.join(pid, req.pgid);
|
|
16588
|
+
if (req.group === "lead") this.jobs.lead(pid);
|
|
16589
|
+
if (req.group === "session") this.jobs.setsid(pid);
|
|
16353
16590
|
this.described.set(pid, {
|
|
16354
16591
|
argv: [req.argv0, ...req.args],
|
|
16355
16592
|
tty: terminal?.name ?? null,
|
|
@@ -16511,6 +16748,11 @@ var Launcher = class {
|
|
|
16511
16748
|
await fds.closeAll();
|
|
16512
16749
|
throw new SpawnError("EACCES");
|
|
16513
16750
|
}
|
|
16751
|
+
const group = this.childGroup(ppid, req);
|
|
16752
|
+
if (typeof group === "string") {
|
|
16753
|
+
await fds.closeAll();
|
|
16754
|
+
throw new SpawnError(group);
|
|
16755
|
+
}
|
|
16514
16756
|
const cred = grant ? grant.cred : this.credOf(ppid);
|
|
16515
16757
|
const scope = grant ? "" : await this.scopeOf(cred.euid);
|
|
16516
16758
|
const planned = await this.plan(req.file, req.argv, req.cwd, scope);
|
|
@@ -16537,6 +16779,7 @@ var Launcher = class {
|
|
|
16537
16779
|
umask: this.umaskOf(ppid),
|
|
16538
16780
|
cred,
|
|
16539
16781
|
tag: this.tagOf(ppid),
|
|
16782
|
+
...group,
|
|
16540
16783
|
...exec
|
|
16541
16784
|
});
|
|
16542
16785
|
deciding?.attach();
|
|
@@ -16544,6 +16787,17 @@ var Launcher = class {
|
|
|
16544
16787
|
return childHandle(handle);
|
|
16545
16788
|
};
|
|
16546
16789
|
}
|
|
16790
|
+
childGroup(ppid, req) {
|
|
16791
|
+
const { pgid, session } = req;
|
|
16792
|
+
if (pgid === void 0 && session === void 0) return {};
|
|
16793
|
+
const valid2 = pgid === void 0 || Number.isInteger(pgid) && pgid >= 0;
|
|
16794
|
+
if (req.exec || !valid2 || session !== void 0 && session !== true) return "EINVAL";
|
|
16795
|
+
if (session) return pgid === void 0 ? { group: "session" } : "EINVAL";
|
|
16796
|
+
if (pgid === 0) return { group: "lead" };
|
|
16797
|
+
const sid = this.jobs.sessionOf(pgid);
|
|
16798
|
+
if (sid === void 0) return "ESRCH";
|
|
16799
|
+
return sid === this.jobs.sidOf(ppid) ? { pgid } : "EPERM";
|
|
16800
|
+
}
|
|
16547
16801
|
undecided(ppid) {
|
|
16548
16802
|
const decided = Promise.withResolvers();
|
|
16549
16803
|
return {
|
|
@@ -16574,7 +16828,7 @@ var Launcher = class {
|
|
|
16574
16828
|
}, 0);
|
|
16575
16829
|
}
|
|
16576
16830
|
forker(ppid, parent) {
|
|
16577
|
-
const { exec: _exec, ...image } = parent;
|
|
16831
|
+
const { exec: _exec, pgid: _pgid, group: _group, ...image } = parent;
|
|
16578
16832
|
return async (state, fds) => childHandle(
|
|
16579
16833
|
this.start({
|
|
16580
16834
|
...image,
|
|
@@ -17043,7 +17297,7 @@ var Launcher = class {
|
|
|
17043
17297
|
},
|
|
17044
17298
|
account
|
|
17045
17299
|
);
|
|
17046
|
-
const report = (message3) => options.onData(
|
|
17300
|
+
const report = (message3) => options.onData(encoder5.encode(`${message3}\r
|
|
17047
17301
|
`));
|
|
17048
17302
|
const handle = await this.launch(planned, {
|
|
17049
17303
|
env,
|
|
@@ -17080,7 +17334,7 @@ var Launcher = class {
|
|
|
17080
17334
|
};
|
|
17081
17335
|
const stdout = collect(out, options.onStdout);
|
|
17082
17336
|
const stderr = collect(err, options.onStderr);
|
|
17083
|
-
const report = (message3) => stderr(
|
|
17337
|
+
const report = (message3) => stderr(encoder5.encode(`${message3}
|
|
17084
17338
|
`));
|
|
17085
17339
|
if (!planned) {
|
|
17086
17340
|
report(`${file}: command not found`);
|
|
@@ -17617,7 +17871,7 @@ function dialStream(port, onClose) {
|
|
|
17617
17871
|
|
|
17618
17872
|
// src/client/loopback-fetch.ts
|
|
17619
17873
|
var OWN_HEADERS = /* @__PURE__ */ new Set(["host", "connection", "content-length", "transfer-encoding"]);
|
|
17620
|
-
var
|
|
17874
|
+
var encoder6 = new TextEncoder();
|
|
17621
17875
|
var latin12 = new TextDecoder("latin1");
|
|
17622
17876
|
var ByteSource = class {
|
|
17623
17877
|
buffered = new Uint8Array(0);
|
|
@@ -17628,14 +17882,14 @@ var ByteSource = class {
|
|
|
17628
17882
|
async more() {
|
|
17629
17883
|
const { done: done4, value } = await this.reader.read();
|
|
17630
17884
|
if (done4) return false;
|
|
17631
|
-
const
|
|
17632
|
-
|
|
17633
|
-
|
|
17634
|
-
this.buffered =
|
|
17885
|
+
const joined3 = new Uint8Array(this.buffered.length + value.length);
|
|
17886
|
+
joined3.set(this.buffered);
|
|
17887
|
+
joined3.set(value, this.buffered.length);
|
|
17888
|
+
this.buffered = joined3;
|
|
17635
17889
|
return true;
|
|
17636
17890
|
}
|
|
17637
17891
|
async until(marker) {
|
|
17638
|
-
const needle =
|
|
17892
|
+
const needle = encoder6.encode(marker);
|
|
17639
17893
|
for (; ; ) {
|
|
17640
17894
|
const at = indexOf(this.buffered, needle);
|
|
17641
17895
|
if (at >= 0) return this.take(at + needle.length);
|
|
@@ -17743,7 +17997,7 @@ async function requestBytes(request) {
|
|
|
17743
17997
|
});
|
|
17744
17998
|
if (body) lines2.push(`Content-Length: ${body.length}`);
|
|
17745
17999
|
lines2.push("Connection: close", "", "");
|
|
17746
|
-
const head =
|
|
18000
|
+
const head = encoder6.encode(lines2.join("\r\n"));
|
|
17747
18001
|
const out = new Uint8Array(head.length + (body?.length ?? 0));
|
|
17748
18002
|
out.set(head);
|
|
17749
18003
|
if (body) out.set(body, head.length);
|
|
@@ -17797,8 +18051,8 @@ var KernelCallError = class extends Error {
|
|
|
17797
18051
|
this.code = code;
|
|
17798
18052
|
}
|
|
17799
18053
|
};
|
|
17800
|
-
var
|
|
17801
|
-
var bytesOf2 = (data) => typeof data === "string" ?
|
|
18054
|
+
var encoder7 = new TextEncoder();
|
|
18055
|
+
var bytesOf2 = (data) => typeof data === "string" ? encoder7.encode(data) : data;
|
|
17802
18056
|
var UNAVAILABLE = {
|
|
17803
18057
|
manualRedirects: false,
|
|
17804
18058
|
encodedBodies: false,
|
|
@@ -18216,8 +18470,8 @@ function nodeWorker(file, live, closed) {
|
|
|
18216
18470
|
}
|
|
18217
18471
|
function textOf(on) {
|
|
18218
18472
|
if (!on) return void 0;
|
|
18219
|
-
const
|
|
18220
|
-
return (bytes) => on(
|
|
18473
|
+
const decoder4 = new TextDecoder();
|
|
18474
|
+
return (bytes) => on(decoder4.decode(bytes, { stream: true }));
|
|
18221
18475
|
}
|
|
18222
18476
|
async function createNodeKernel(options = {}) {
|
|
18223
18477
|
const root = options.root ?? memoryRoot();
|
|
@@ -18252,6 +18506,7 @@ async function createNodeKernel(options = {}) {
|
|
|
18252
18506
|
...options.onDenial ? { onDenial: options.onDenial } : {},
|
|
18253
18507
|
...options.protect ? { protect: options.protect } : {},
|
|
18254
18508
|
...options.sealed ? { sealed: options.sealed } : {},
|
|
18509
|
+
...options.clipboard ? { clipboard: options.clipboard } : {},
|
|
18255
18510
|
...options.approve ? { approve: options.approve } : {}
|
|
18256
18511
|
});
|
|
18257
18512
|
await launcher.prepare();
|
|
@@ -18260,7 +18515,7 @@ async function createNodeKernel(options = {}) {
|
|
|
18260
18515
|
pending.add(reject);
|
|
18261
18516
|
work().then(resolve, reject).finally(() => pending.delete(reject));
|
|
18262
18517
|
});
|
|
18263
|
-
const
|
|
18518
|
+
const decoder4 = new TextDecoder();
|
|
18264
18519
|
return {
|
|
18265
18520
|
root,
|
|
18266
18521
|
async run(argv, opts = {}) {
|
|
@@ -18277,8 +18532,8 @@ async function createNodeKernel(options = {}) {
|
|
|
18277
18532
|
);
|
|
18278
18533
|
return {
|
|
18279
18534
|
status: result.status,
|
|
18280
|
-
stdout:
|
|
18281
|
-
stderr:
|
|
18535
|
+
stdout: decoder4.decode(result.stdout),
|
|
18536
|
+
stderr: decoder4.decode(result.stderr)
|
|
18282
18537
|
};
|
|
18283
18538
|
},
|
|
18284
18539
|
async openTerminal(argv, opts = {}) {
|