@cjhyy/code-shell-server 0.9.8 → 0.9.10
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 +85 -23
- package/dist/bin/code-shell-project-runtime.d.ts +2 -0
- package/dist/bin/code-shell-project-runtime.js +8 -0
- package/dist/desktop-web/http-api.d.ts +43 -0
- package/dist/desktop-web/http-api.js +376 -0
- package/dist/hub/approval-lease.d.ts +30 -0
- package/dist/hub/approval-lease.js +89 -0
- package/dist/hub/auth-http.d.ts +23 -0
- package/dist/hub/auth-http.js +259 -0
- package/dist/hub/auth-store.d.ts +52 -0
- package/dist/hub/auth-store.js +316 -0
- package/dist/hub/configuration.d.ts +64 -0
- package/dist/hub/configuration.js +555 -0
- package/dist/hub/files.d.ts +9 -0
- package/dist/hub/files.js +278 -0
- package/dist/hub/mcp-configuration.d.ts +51 -0
- package/dist/hub/mcp-configuration.js +558 -0
- package/dist/hub/mcp-probe.d.ts +24 -0
- package/dist/hub/mcp-probe.js +392 -0
- package/dist/hub/model-probe.d.ts +20 -0
- package/dist/hub/model-probe.js +193 -0
- package/dist/hub/outbound-transport.d.ts +36 -0
- package/dist/hub/outbound-transport.js +122 -0
- package/dist/hub/run-replay.d.ts +42 -0
- package/dist/hub/run-replay.js +89 -0
- package/dist/hub/session-management.d.ts +36 -0
- package/dist/hub/session-management.js +405 -0
- package/dist/hub/skills-management.d.ts +43 -0
- package/dist/hub/skills-management.js +487 -0
- package/dist/hub/uploads.d.ts +22 -0
- package/dist/hub/uploads.js +241 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.desktop-web.d.ts +2 -0
- package/dist/index.desktop-web.js +2 -0
- package/dist/index.js +3 -0
- package/dist/index.links.d.ts +6 -0
- package/dist/index.links.js +6 -0
- package/dist/index.panels.d.ts +9 -0
- package/dist/index.panels.js +8 -0
- package/dist/index.serve.d.ts +1 -0
- package/dist/index.serve.js +1 -0
- package/dist/index.storage.d.ts +2 -0
- package/dist/index.storage.js +2 -0
- package/dist/links/catalog.d.ts +10 -0
- package/dist/links/catalog.js +41 -0
- package/dist/links/device-oauth.d.ts +52 -0
- package/dist/links/device-oauth.js +255 -0
- package/dist/links/http.d.ts +34 -0
- package/dist/links/http.js +144 -0
- package/dist/links/service.d.ts +54 -0
- package/dist/links/service.js +578 -0
- package/dist/links/types.d.ts +6 -0
- package/dist/links/types.js +1 -0
- package/dist/mobile-remote/mobile-client-event-validator.js +5 -2
- package/dist/mobile-remote/pending-approvals.js +2 -0
- package/dist/mobile-remote/remote-host-manager.d.ts +8 -0
- package/dist/mobile-remote/remote-host-manager.js +90 -15
- package/dist/mobile-remote/room-manager.js +17 -5
- package/dist/panels/agent-task-host.d.ts +32 -0
- package/dist/panels/agent-task-host.js +457 -0
- package/dist/panels/agent-task-models.d.ts +27 -0
- package/dist/panels/agent-task-models.js +51 -0
- package/dist/panels/agent-task-service.d.ts +105 -0
- package/dist/panels/agent-task-service.js +283 -0
- package/dist/panels/http.d.ts +34 -0
- package/dist/panels/http.js +37 -0
- package/dist/panels/hub-binding.d.ts +12 -0
- package/dist/panels/hub-binding.js +174 -0
- package/dist/panels/management-http.d.ts +29 -0
- package/dist/panels/management-http.js +119 -0
- package/dist/panels/management.d.ts +39 -0
- package/dist/panels/management.js +494 -0
- package/dist/panels/process-files.d.ts +14 -0
- package/dist/panels/process-files.js +299 -0
- package/dist/panels/process-service.d.ts +96 -0
- package/dist/panels/process-service.js +501 -0
- package/dist/panels/runtime-services.d.ts +24 -0
- package/dist/panels/runtime-services.js +462 -0
- package/dist/panels/runtime.d.ts +51 -0
- package/dist/panels/runtime.js +1063 -0
- package/dist/panels/storage-store.d.ts +9 -0
- package/dist/panels/storage-store.js +154 -0
- package/dist/panels/types.d.ts +52 -0
- package/dist/panels/types.js +1 -0
- package/dist/project-runtime/control-server.d.ts +19 -0
- package/dist/project-runtime/control-server.js +300 -0
- package/dist/project-runtime/docker-provider.d.ts +33 -0
- package/dist/project-runtime/docker-provider.js +487 -0
- package/dist/project-runtime/lock.d.ts +6 -0
- package/dist/project-runtime/lock.js +43 -0
- package/dist/project-runtime/managed-entry.d.ts +10 -0
- package/dist/project-runtime/managed-entry.js +113 -0
- package/dist/project-runtime/manager.d.ts +40 -0
- package/dist/project-runtime/manager.js +249 -0
- package/dist/project-runtime/proxy.d.ts +22 -0
- package/dist/project-runtime/proxy.js +706 -0
- package/dist/project-runtime/registry.d.ts +54 -0
- package/dist/project-runtime/registry.js +286 -0
- package/dist/project-runtime/types.d.ts +43 -0
- package/dist/project-runtime/types.js +1 -0
- package/dist/serve/cli.d.ts +5 -0
- package/dist/serve/cli.js +82 -23
- package/dist/serve/headless-server.d.ts +11 -0
- package/dist/serve/headless-server.js +737 -83
- package/dist/session-titles-store.d.ts +17 -0
- package/dist/session-titles-store.js +174 -0
- package/dist/sessions-service.d.ts +2 -0
- package/dist/sessions-service.js +8 -0
- package/dist/static-files.js +1 -0
- package/dist/worker-bridge-core.js +17 -6
- package/package.json +19 -5
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
import { constants } from "node:fs";
|
|
2
|
+
import { lstat, open, opendir, realpath } from "node:fs/promises";
|
|
3
|
+
import { extname, isAbsolute, join, resolve } from "node:path";
|
|
4
|
+
import { Readable } from "node:stream";
|
|
5
|
+
import { pipeline } from "node:stream/promises";
|
|
6
|
+
const MAX_DOWNLOAD_BYTES = 2 * 1024 * 1024 * 1024;
|
|
7
|
+
const MAX_ENTRIES = 200;
|
|
8
|
+
const MAX_EXAMINED = 4096;
|
|
9
|
+
const DOWNLOAD_EXTENSIONS = new Set([
|
|
10
|
+
".mp4",
|
|
11
|
+
".m4v",
|
|
12
|
+
".mkv",
|
|
13
|
+
".mov",
|
|
14
|
+
".webm",
|
|
15
|
+
".avi",
|
|
16
|
+
".mpeg",
|
|
17
|
+
".mpg",
|
|
18
|
+
".ts",
|
|
19
|
+
".mp3",
|
|
20
|
+
".m4a",
|
|
21
|
+
".aac",
|
|
22
|
+
".wav",
|
|
23
|
+
".flac",
|
|
24
|
+
".ogg",
|
|
25
|
+
".opus",
|
|
26
|
+
".aiff",
|
|
27
|
+
".png",
|
|
28
|
+
".jpg",
|
|
29
|
+
".jpeg",
|
|
30
|
+
".gif",
|
|
31
|
+
".webp",
|
|
32
|
+
".avif",
|
|
33
|
+
".svg",
|
|
34
|
+
".bmp",
|
|
35
|
+
".tif",
|
|
36
|
+
".tiff",
|
|
37
|
+
".pdf",
|
|
38
|
+
".docx",
|
|
39
|
+
".xlsx",
|
|
40
|
+
".pptx",
|
|
41
|
+
".odt",
|
|
42
|
+
".ods",
|
|
43
|
+
".odp",
|
|
44
|
+
".txt",
|
|
45
|
+
".md",
|
|
46
|
+
".csv",
|
|
47
|
+
".tsv",
|
|
48
|
+
".json",
|
|
49
|
+
".html",
|
|
50
|
+
".srt",
|
|
51
|
+
".vtt",
|
|
52
|
+
".ass",
|
|
53
|
+
".zip",
|
|
54
|
+
".tar",
|
|
55
|
+
".gz",
|
|
56
|
+
".7z",
|
|
57
|
+
".rar",
|
|
58
|
+
]);
|
|
59
|
+
class DirectoryError extends Error {
|
|
60
|
+
status;
|
|
61
|
+
constructor(status, message) {
|
|
62
|
+
super(message);
|
|
63
|
+
this.status = status;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
function fail(status, message) {
|
|
67
|
+
throw new DirectoryError(status, message);
|
|
68
|
+
}
|
|
69
|
+
function sameFile(a, b) {
|
|
70
|
+
return a.dev === b.dev && a.ino === b.ino;
|
|
71
|
+
}
|
|
72
|
+
function escaped(value) {
|
|
73
|
+
return value.replace(/[&<>"']/g, (character) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" })[character]);
|
|
74
|
+
}
|
|
75
|
+
function safeBasename(name) {
|
|
76
|
+
return (Boolean(name) &&
|
|
77
|
+
name.length <= 240 &&
|
|
78
|
+
!name.startsWith(".") &&
|
|
79
|
+
!/[\\/\u0000-\u001f\u007f:]/u.test(name) &&
|
|
80
|
+
!/[. ]$/u.test(name) &&
|
|
81
|
+
!/^(CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])(?:\.|$)/iu.test(name));
|
|
82
|
+
}
|
|
83
|
+
function downloadable(name) {
|
|
84
|
+
return (safeBasename(name) &&
|
|
85
|
+
DOWNLOAD_EXTENSIONS.has(extname(name).toLowerCase()) &&
|
|
86
|
+
!/(?:^|[\s._-])(?:credentials?|cookies?|tokens?|secrets?|auth|oauth|accounts?|passwords?|sessions?|id_rsa|id_ed25519|id_ecdsa)(?:[\s._-]|$)/iu.test(name));
|
|
87
|
+
}
|
|
88
|
+
function disposition(name) {
|
|
89
|
+
const suffix = extname(name).replace(/[^.A-Za-z0-9]/g, "");
|
|
90
|
+
const encoded = encodeURIComponent(name).replace(/[!'()*]/g, (value) => `%${value.charCodeAt(0).toString(16).toUpperCase()}`);
|
|
91
|
+
return `attachment; filename="download${suffix}"; filename*=UTF-8''${encoded}`;
|
|
92
|
+
}
|
|
93
|
+
/** Authenticated read-only exports from one granted directory; no recursive paths. */
|
|
94
|
+
export async function handlePanelProcessDirectory(request, response, options) {
|
|
95
|
+
let directory;
|
|
96
|
+
let file;
|
|
97
|
+
const authorize = async () => {
|
|
98
|
+
let allowed = false;
|
|
99
|
+
try {
|
|
100
|
+
allowed = await options.isAuthorized();
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
/* fail closed */
|
|
104
|
+
}
|
|
105
|
+
if (!allowed)
|
|
106
|
+
fail(403, "下载授权已失效,请重新打开面板目录。");
|
|
107
|
+
if (response.destroyed || request.aborted)
|
|
108
|
+
throw new Error("Download connection closed");
|
|
109
|
+
};
|
|
110
|
+
try {
|
|
111
|
+
await authorize();
|
|
112
|
+
if (!["GET", "HEAD"].includes(request.method ?? ""))
|
|
113
|
+
fail(405, "此目录只支持浏览和下载。");
|
|
114
|
+
if (!isAbsolute(options.root) ||
|
|
115
|
+
(options.linkPrefix !== undefined &&
|
|
116
|
+
options.linkPrefix !== "" &&
|
|
117
|
+
!/^\/p\/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/.test(options.linkPrefix)) ||
|
|
118
|
+
(options.workspace !== undefined && !isAbsolute(options.workspace)) ||
|
|
119
|
+
!/^\/api\/v1\/panels\/runtime\/[A-Za-z0-9_-]+\/directory\/[A-Za-z0-9_-]+$/.test(options.baseUrl))
|
|
120
|
+
fail(400, "下载目录配置无效。");
|
|
121
|
+
const url = new URL(request.url ?? "", "http://localhost");
|
|
122
|
+
if (url.pathname !== options.baseUrl ||
|
|
123
|
+
[...url.searchParams.keys()].some((key) => key !== "file" && key !== "workspace") ||
|
|
124
|
+
url.searchParams.getAll("file").length > 1 ||
|
|
125
|
+
url.searchParams.getAll("workspace").length > 1 ||
|
|
126
|
+
(url.searchParams.has("workspace") && url.searchParams.get("workspace") !== options.workspace))
|
|
127
|
+
fail(400, "下载参数无效。");
|
|
128
|
+
const name = url.searchParams.get("file");
|
|
129
|
+
if (name !== null && !safeBasename(name))
|
|
130
|
+
fail(400, "下载文件名无效。");
|
|
131
|
+
if (name !== null && !downloadable(name))
|
|
132
|
+
fail(404, "找不到可下载的文件。");
|
|
133
|
+
const root = resolve(options.root);
|
|
134
|
+
const before = await lstat(root);
|
|
135
|
+
await authorize();
|
|
136
|
+
if (!before.isDirectory() || before.isSymbolicLink())
|
|
137
|
+
fail(404, "下载目录不可用。");
|
|
138
|
+
const canonical = await realpath(root);
|
|
139
|
+
await authorize();
|
|
140
|
+
if (canonical !== root)
|
|
141
|
+
fail(404, "下载目录已经改变。");
|
|
142
|
+
directory = await open(root, constants.O_RDONLY | (constants.O_DIRECTORY ?? 0) | (constants.O_NOFOLLOW ?? 0));
|
|
143
|
+
await authorize();
|
|
144
|
+
const opened = await directory.stat();
|
|
145
|
+
await authorize();
|
|
146
|
+
if (!opened.isDirectory() || !sameFile(before, opened))
|
|
147
|
+
fail(404, "下载目录已经改变。");
|
|
148
|
+
const verifyDirectory = async () => {
|
|
149
|
+
const current = await lstat(root);
|
|
150
|
+
await authorize();
|
|
151
|
+
if (!current.isDirectory() || current.isSymbolicLink() || !sameFile(opened, current))
|
|
152
|
+
fail(404, "下载目录已经改变。");
|
|
153
|
+
};
|
|
154
|
+
if (name === null) {
|
|
155
|
+
const entries = [];
|
|
156
|
+
let examined = 0;
|
|
157
|
+
let truncated = false;
|
|
158
|
+
const listing = await opendir(root);
|
|
159
|
+
try {
|
|
160
|
+
await authorize();
|
|
161
|
+
for await (const entry of listing) {
|
|
162
|
+
await authorize();
|
|
163
|
+
if (++examined > MAX_EXAMINED) {
|
|
164
|
+
truncated = true;
|
|
165
|
+
break;
|
|
166
|
+
}
|
|
167
|
+
if (!entry.isFile() || !downloadable(entry.name))
|
|
168
|
+
continue;
|
|
169
|
+
const metadata = await lstat(join(root, entry.name)).catch(() => null);
|
|
170
|
+
await authorize();
|
|
171
|
+
if (!metadata ||
|
|
172
|
+
!metadata.isFile() ||
|
|
173
|
+
metadata.isSymbolicLink() ||
|
|
174
|
+
metadata.nlink !== 1 ||
|
|
175
|
+
metadata.size > MAX_DOWNLOAD_BYTES)
|
|
176
|
+
continue;
|
|
177
|
+
if (entries.length >= MAX_ENTRIES) {
|
|
178
|
+
truncated = true;
|
|
179
|
+
break;
|
|
180
|
+
}
|
|
181
|
+
entries.push({ name: entry.name, size: metadata.size });
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
finally {
|
|
185
|
+
try {
|
|
186
|
+
await listing.close();
|
|
187
|
+
}
|
|
188
|
+
catch {
|
|
189
|
+
/* Iteration already closed the directory. */
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
193
|
+
await verifyDirectory();
|
|
194
|
+
await authorize();
|
|
195
|
+
const rows = entries
|
|
196
|
+
.map((entry) => `<li><a href="${escaped((options.linkPrefix ?? "") + options.baseUrl + "?file=" + encodeURIComponent(entry.name) + (options.workspace === undefined ? "" : "&workspace=" + encodeURIComponent(options.workspace)))}">${escaped(entry.name)}</a><span>${entry.size.toLocaleString("en-US")} bytes</span></li>`)
|
|
197
|
+
.join("");
|
|
198
|
+
const html = `<!doctype html><html lang="zh-CN"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>面板下载文件</title><style>body{font:16px system-ui,sans-serif;max-width:880px;margin:48px auto;padding:0 24px;color:#1f2937;background:#f8fafc}h1{font-size:26px}p,span{color:#64748b}ul{list-style:none;padding:0}li{display:flex;gap:24px;justify-content:space-between;padding:16px 0;border-bottom:1px solid #e2e8f0}a{color:#1d4ed8;overflow-wrap:anywhere}span{font-size:13px;white-space:nowrap}</style><h1>面板下载文件</h1><p>点击文件保存到这台设备。这里只显示当前目录中的媒体与导出文件。</p>${rows ? `<ul>${rows}</ul>` : "<p>暂无可下载的文件。</p>"}${truncated ? "<p>文件较多,当前最多显示 200 项。</p>" : ""}</html>`;
|
|
199
|
+
response.writeHead(200, {
|
|
200
|
+
"Content-Type": "text/html; charset=utf-8",
|
|
201
|
+
"Content-Length": Buffer.byteLength(html),
|
|
202
|
+
"Content-Security-Policy": "default-src 'none'; style-src 'unsafe-inline'; base-uri 'none'; form-action 'none'; frame-ancestors 'none'",
|
|
203
|
+
"Cache-Control": "no-store",
|
|
204
|
+
"X-Content-Type-Options": "nosniff",
|
|
205
|
+
"Referrer-Policy": "no-referrer",
|
|
206
|
+
});
|
|
207
|
+
response.end(request.method === "HEAD" ? undefined : html);
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
const path = join(root, name);
|
|
211
|
+
const entry = await lstat(path);
|
|
212
|
+
await authorize();
|
|
213
|
+
if (!entry.isFile() || entry.isSymbolicLink() || entry.nlink !== 1)
|
|
214
|
+
fail(404, "找不到可下载的文件。");
|
|
215
|
+
const location = process.platform === "linux" ? `/proc/self/fd/${directory.fd}/${name}` : path;
|
|
216
|
+
file = await open(location, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0) | (constants.O_NONBLOCK ?? 0));
|
|
217
|
+
await authorize();
|
|
218
|
+
const metadata = await file.stat();
|
|
219
|
+
await authorize();
|
|
220
|
+
if (!metadata.isFile() || metadata.nlink !== 1 || !sameFile(entry, metadata))
|
|
221
|
+
fail(404, "下载文件已经改变。");
|
|
222
|
+
if (metadata.size > MAX_DOWNLOAD_BYTES)
|
|
223
|
+
fail(413, "下载文件超过 2 GiB。");
|
|
224
|
+
const current = await lstat(path);
|
|
225
|
+
await authorize();
|
|
226
|
+
if (current.isSymbolicLink() || !sameFile(metadata, current))
|
|
227
|
+
fail(404, "下载文件已经改变。");
|
|
228
|
+
await verifyDirectory();
|
|
229
|
+
await authorize();
|
|
230
|
+
response.writeHead(200, {
|
|
231
|
+
"Content-Type": "application/octet-stream",
|
|
232
|
+
"Content-Disposition": disposition(name),
|
|
233
|
+
"Content-Length": metadata.size,
|
|
234
|
+
"Content-Security-Policy": "default-src 'none'; sandbox",
|
|
235
|
+
"Cache-Control": "no-store",
|
|
236
|
+
"X-Content-Type-Options": "nosniff",
|
|
237
|
+
"Referrer-Policy": "no-referrer",
|
|
238
|
+
});
|
|
239
|
+
if (request.method === "HEAD" || metadata.size === 0) {
|
|
240
|
+
response.end();
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
const input = file.createReadStream({ autoClose: false, start: 0, end: metadata.size - 1 });
|
|
244
|
+
let checking = false;
|
|
245
|
+
const timer = setInterval(() => {
|
|
246
|
+
if (checking)
|
|
247
|
+
return;
|
|
248
|
+
checking = true;
|
|
249
|
+
void authorize()
|
|
250
|
+
.catch((cause) => {
|
|
251
|
+
input.destroy(cause);
|
|
252
|
+
response.destroy(cause);
|
|
253
|
+
})
|
|
254
|
+
.finally(() => {
|
|
255
|
+
checking = false;
|
|
256
|
+
});
|
|
257
|
+
}, 250);
|
|
258
|
+
timer.unref();
|
|
259
|
+
try {
|
|
260
|
+
await pipeline(Readable.from((async function* () {
|
|
261
|
+
for await (const chunk of input) {
|
|
262
|
+
await authorize();
|
|
263
|
+
yield chunk;
|
|
264
|
+
}
|
|
265
|
+
})(), { objectMode: false }), response);
|
|
266
|
+
}
|
|
267
|
+
finally {
|
|
268
|
+
clearInterval(timer);
|
|
269
|
+
input.destroy();
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
catch (cause) {
|
|
273
|
+
if (response.headersSent || response.destroyed) {
|
|
274
|
+
response.destroy();
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
const code = cause?.code;
|
|
278
|
+
const status = cause instanceof DirectoryError
|
|
279
|
+
? cause.status
|
|
280
|
+
: ["ENOENT", "ENOTDIR", "ELOOP", "EACCES"].includes(code ?? "")
|
|
281
|
+
? 404
|
|
282
|
+
: 500;
|
|
283
|
+
const message = cause instanceof DirectoryError
|
|
284
|
+
? cause.message
|
|
285
|
+
: status === 404
|
|
286
|
+
? "找不到可下载的文件。"
|
|
287
|
+
: "无法读取下载目录。";
|
|
288
|
+
response.writeHead(status, {
|
|
289
|
+
"Content-Type": "text/plain; charset=utf-8",
|
|
290
|
+
"Cache-Control": "no-store",
|
|
291
|
+
"X-Content-Type-Options": "nosniff",
|
|
292
|
+
});
|
|
293
|
+
response.end(request.method === "HEAD" ? undefined : message);
|
|
294
|
+
}
|
|
295
|
+
finally {
|
|
296
|
+
await file?.close().catch(() => { });
|
|
297
|
+
await directory?.close().catch(() => { });
|
|
298
|
+
}
|
|
299
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
export interface PanelProcessApprovalScope {
|
|
2
|
+
appId: string;
|
|
3
|
+
revision: string;
|
|
4
|
+
executablePath: string;
|
|
5
|
+
executableFingerprint: string;
|
|
6
|
+
}
|
|
7
|
+
export interface PanelProcessOwner {
|
|
8
|
+
guestId: number;
|
|
9
|
+
appId: string;
|
|
10
|
+
appTitle: string;
|
|
11
|
+
revision: string;
|
|
12
|
+
send(event: "process.output" | "process.exit", payload: Record<string, unknown>): void;
|
|
13
|
+
}
|
|
14
|
+
export interface PanelAppProcessServiceOptions {
|
|
15
|
+
env?: NodeJS.ProcessEnv;
|
|
16
|
+
platform?: NodeJS.Platform;
|
|
17
|
+
/** Host-owned executable directories (for example CodeShell's managed bin). */
|
|
18
|
+
extraPathDirectories?: () => readonly string[];
|
|
19
|
+
/** Rechecked after asynchronous work and immediately before admitting a process. */
|
|
20
|
+
isOwnerAuthorized?(owner: PanelProcessOwner): boolean | Promise<boolean>;
|
|
21
|
+
/**
|
|
22
|
+
* Desktop defaults to app-version approvals. Web uses guest to isolate each
|
|
23
|
+
* authenticated instance; guest approvals never use the app-wide durable hooks.
|
|
24
|
+
*/
|
|
25
|
+
approvalScope?: "app" | "guest";
|
|
26
|
+
confirmExecution(input: {
|
|
27
|
+
guestId: number;
|
|
28
|
+
appId: string;
|
|
29
|
+
appTitle: string;
|
|
30
|
+
executable: string;
|
|
31
|
+
executablePath: string;
|
|
32
|
+
}): Promise<boolean>;
|
|
33
|
+
isExecutionApproved?(scope: PanelProcessApprovalScope): Promise<boolean>;
|
|
34
|
+
rememberExecutionApproval?(scope: PanelProcessApprovalScope): Promise<void>;
|
|
35
|
+
}
|
|
36
|
+
export declare function panelProcessInfo(platform?: NodeJS.Platform, arch?: string, report?: unknown): {
|
|
37
|
+
platform: NodeJS.Platform;
|
|
38
|
+
arch: string;
|
|
39
|
+
libc?: "glibc" | "musl";
|
|
40
|
+
};
|
|
41
|
+
export declare function panelExecutableDirectories(managedBin: string, options?: {
|
|
42
|
+
platform?: NodeJS.Platform;
|
|
43
|
+
env?: NodeJS.ProcessEnv;
|
|
44
|
+
home?: string;
|
|
45
|
+
}): string[];
|
|
46
|
+
export declare function resolvePanelExecutable(name: string, options?: {
|
|
47
|
+
env?: NodeJS.ProcessEnv;
|
|
48
|
+
platform?: NodeJS.Platform;
|
|
49
|
+
extraPathDirectories?: readonly string[];
|
|
50
|
+
}): Promise<string | null>;
|
|
51
|
+
export declare class PanelAppProcessService {
|
|
52
|
+
private readonly options;
|
|
53
|
+
private readonly executables;
|
|
54
|
+
private readonly directories;
|
|
55
|
+
private readonly fileArguments;
|
|
56
|
+
private readonly processes;
|
|
57
|
+
private readonly approvedExecutables;
|
|
58
|
+
private readonly guestEpochs;
|
|
59
|
+
private readonly reservations;
|
|
60
|
+
private closed;
|
|
61
|
+
constructor(options: PanelAppProcessServiceOptions);
|
|
62
|
+
private epoch;
|
|
63
|
+
private assertLive;
|
|
64
|
+
private authorize;
|
|
65
|
+
findExecutable(owner: PanelProcessOwner, params: unknown): Promise<{
|
|
66
|
+
available: boolean;
|
|
67
|
+
name: string;
|
|
68
|
+
handle?: string;
|
|
69
|
+
}>;
|
|
70
|
+
grantDirectory(owner: PanelProcessOwner, path: string): Promise<{
|
|
71
|
+
handle: string;
|
|
72
|
+
path: string;
|
|
73
|
+
name: string;
|
|
74
|
+
}>;
|
|
75
|
+
executableName(owner: PanelProcessOwner, handle: unknown): string;
|
|
76
|
+
grantFileArgument(owner: PanelProcessOwner, input: {
|
|
77
|
+
executableHandle: unknown;
|
|
78
|
+
argumentName: unknown;
|
|
79
|
+
path: string;
|
|
80
|
+
cleanup?: () => void;
|
|
81
|
+
}): Promise<{
|
|
82
|
+
handle: string;
|
|
83
|
+
}>;
|
|
84
|
+
directoryPath(owner: PanelProcessOwner, handle: unknown): string;
|
|
85
|
+
start(owner: PanelProcessOwner, params: unknown): Promise<{
|
|
86
|
+
processId: string;
|
|
87
|
+
executable: string;
|
|
88
|
+
}>;
|
|
89
|
+
cancel(owner: PanelProcessOwner, params: unknown): {
|
|
90
|
+
cancelled: boolean;
|
|
91
|
+
};
|
|
92
|
+
revokeGuest(guestId: number): void;
|
|
93
|
+
/** Permanently shut down all guests, including operations awaiting approval. */
|
|
94
|
+
close(): void;
|
|
95
|
+
private terminate;
|
|
96
|
+
}
|