@zhanguym/chatroom 1.0.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/LICENSE +202 -0
- package/README.md +52 -0
- package/assets/chatroom.svg +15 -0
- package/chatroom.config.example.json +24 -0
- package/dist/app/application.d.ts +20 -0
- package/dist/app/application.js +75 -0
- package/dist/app/event-bus.d.ts +25 -0
- package/dist/app/event-bus.js +11 -0
- package/dist/app/external-access-registry.d.ts +17 -0
- package/dist/app/external-access-registry.js +41 -0
- package/dist/app/lifecycle.d.ts +14 -0
- package/dist/app/lifecycle.js +130 -0
- package/dist/auth/auth-service.d.ts +88 -0
- package/dist/auth/auth-service.js +221 -0
- package/dist/auth/ingress-policy.d.ts +23 -0
- package/dist/auth/ingress-policy.js +61 -0
- package/dist/auth/passkey-service.d.ts +39 -0
- package/dist/auth/passkey-service.js +145 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +10 -0
- package/dist/cli/run-cli.d.ts +1 -0
- package/dist/cli/run-cli.js +41 -0
- package/dist/config/load-config.d.ts +7 -0
- package/dist/config/load-config.js +197 -0
- package/dist/config/platform-paths.d.ts +7 -0
- package/dist/config/platform-paths.js +34 -0
- package/dist/config/types.d.ts +24 -0
- package/dist/config/types.js +1 -0
- package/dist/core/auth/passkey-repository.d.ts +18 -0
- package/dist/core/auth/passkey-repository.js +1 -0
- package/dist/core/auth/repository.d.ts +36 -0
- package/dist/core/auth/repository.js +1 -0
- package/dist/core/auth/session-repository.d.ts +6 -0
- package/dist/core/auth/session-repository.js +1 -0
- package/dist/core/errors/chatroom-error.d.ts +9 -0
- package/dist/core/errors/chatroom-error.js +31 -0
- package/dist/core/logging/types.d.ts +31 -0
- package/dist/core/logging/types.js +1 -0
- package/dist/core/operations/bounded-value.d.ts +6 -0
- package/dist/core/operations/bounded-value.js +57 -0
- package/dist/core/operations/redactor.d.ts +4 -0
- package/dist/core/operations/redactor.js +69 -0
- package/dist/core/operations/repository.d.ts +18 -0
- package/dist/core/operations/repository.js +1 -0
- package/dist/core/operations/types.d.ts +28 -0
- package/dist/core/operations/types.js +8 -0
- package/dist/core/runtime/child-environment.d.ts +1 -0
- package/dist/core/runtime/child-environment.js +39 -0
- package/dist/core/runtime/command-runner.d.ts +16 -0
- package/dist/core/runtime/command-runner.js +48 -0
- package/dist/core/runtime/identity.d.ts +2 -0
- package/dist/core/runtime/identity.js +9 -0
- package/dist/infrastructure/database/app-database.d.ts +6 -0
- package/dist/infrastructure/database/app-database.js +22 -0
- package/dist/infrastructure/database/mcp-tool-settings-repository.d.ts +8 -0
- package/dist/infrastructure/database/mcp-tool-settings-repository.js +22 -0
- package/dist/infrastructure/database/oauth-repository.d.ts +20 -0
- package/dist/infrastructure/database/oauth-repository.js +140 -0
- package/dist/infrastructure/database/operation-repository.d.ts +16 -0
- package/dist/infrastructure/database/operation-repository.js +120 -0
- package/dist/infrastructure/database/passkey-repository.d.ts +11 -0
- package/dist/infrastructure/database/passkey-repository.js +57 -0
- package/dist/infrastructure/database/schema.d.ts +1 -0
- package/dist/infrastructure/database/schema.js +90 -0
- package/dist/infrastructure/database/web-session-repository.d.ts +10 -0
- package/dist/infrastructure/database/web-session-repository.js +26 -0
- package/dist/infrastructure/http/http-server.d.ts +28 -0
- package/dist/infrastructure/http/http-server.js +146 -0
- package/dist/infrastructure/http/ingress-middleware.d.ts +6 -0
- package/dist/infrastructure/http/ingress-middleware.js +58 -0
- package/dist/infrastructure/logging/file-log-store.d.ts +9 -0
- package/dist/infrastructure/logging/file-log-store.js +173 -0
- package/dist/infrastructure/logging/system-log.d.ts +22 -0
- package/dist/infrastructure/logging/system-log.js +117 -0
- package/dist/mcp/server/create-mcp-server.d.ts +3 -0
- package/dist/mcp/server/create-mcp-server.js +16 -0
- package/dist/mcp/server/plugin-mcp-registrar.d.ts +31 -0
- package/dist/mcp/server/plugin-mcp-registrar.js +70 -0
- package/dist/mcp/server/request-context.d.ts +3 -0
- package/dist/mcp/server/request-context.js +8 -0
- package/dist/mcp/server/tool-control.d.ts +31 -0
- package/dist/mcp/server/tool-control.js +76 -0
- package/dist/mcp/server/tool-support.d.ts +44 -0
- package/dist/mcp/server/tool-support.js +72 -0
- package/dist/native/linux/chatroom-computer-helper +0 -0
- package/dist/native/macos/ChatRoomComputerHelper.app/Contents/Info.plist +14 -0
- package/dist/native/macos/ChatRoomComputerHelper.app/Contents/MacOS/chatroom-computer-helper +0 -0
- package/dist/native/macos/ChatRoomComputerHelper.app/Contents/_CodeSignature/CodeResources +115 -0
- package/dist/native/windows/chatroom-computer-helper.exe +0 -0
- package/dist/operations/operation-log.d.ts +24 -0
- package/dist/operations/operation-log.js +98 -0
- package/dist/plugins/cloud/api-client.d.ts +50 -0
- package/dist/plugins/cloud/api-client.js +112 -0
- package/dist/plugins/cloud/controller.d.ts +58 -0
- package/dist/plugins/cloud/controller.js +425 -0
- package/dist/plugins/cloud/device-proof.d.ts +9 -0
- package/dist/plugins/cloud/device-proof.js +17 -0
- package/dist/plugins/cloud/plugin.d.ts +4 -0
- package/dist/plugins/cloud/plugin.js +17 -0
- package/dist/plugins/cloud/state-store.d.ts +7 -0
- package/dist/plugins/cloud/state-store.js +79 -0
- package/dist/plugins/cloud/tunnel-client.d.ts +84 -0
- package/dist/plugins/cloud/tunnel-client.js +427 -0
- package/dist/plugins/cloud/types.d.ts +72 -0
- package/dist/plugins/cloud/types.js +60 -0
- package/dist/plugins/computer/audit.d.ts +34 -0
- package/dist/plugins/computer/audit.js +42 -0
- package/dist/plugins/computer/computer-native-backend.d.ts +11 -0
- package/dist/plugins/computer/computer-native-backend.js +58 -0
- package/dist/plugins/computer/computer-native-host.d.ts +30 -0
- package/dist/plugins/computer/computer-native-host.js +411 -0
- package/dist/plugins/computer/computer-protocol.d.ts +22 -0
- package/dist/plugins/computer/computer-protocol.js +74 -0
- package/dist/plugins/computer/computer-schemas.d.ts +285 -0
- package/dist/plugins/computer/computer-schemas.js +152 -0
- package/dist/plugins/computer/computer-service.d.ts +29 -0
- package/dist/plugins/computer/computer-service.js +117 -0
- package/dist/plugins/computer/computer-settings-repository.d.ts +8 -0
- package/dist/plugins/computer/computer-settings-repository.js +41 -0
- package/dist/plugins/computer/mcp.d.ts +3 -0
- package/dist/plugins/computer/mcp.js +126 -0
- package/dist/plugins/computer/plugin.d.ts +4 -0
- package/dist/plugins/computer/plugin.js +29 -0
- package/dist/plugins/computer/types.d.ts +174 -0
- package/dist/plugins/computer/types.js +1 -0
- package/dist/plugins/git/git-service.d.ts +30 -0
- package/dist/plugins/git/git-service.js +428 -0
- package/dist/plugins/git/plugin.d.ts +4 -0
- package/dist/plugins/git/plugin.js +12 -0
- package/dist/plugins/git/types.d.ts +32 -0
- package/dist/plugins/git/types.js +1 -0
- package/dist/plugins/plugin-manager.d.ts +11 -0
- package/dist/plugins/plugin-manager.js +63 -0
- package/dist/plugins/process/backend.d.ts +18 -0
- package/dist/plugins/process/backend.js +1 -0
- package/dist/plugins/process/head-tail-buffer.d.ts +17 -0
- package/dist/plugins/process/head-tail-buffer.js +49 -0
- package/dist/plugins/process/infrastructure/pipe-process-backend.d.ts +8 -0
- package/dist/plugins/process/infrastructure/pipe-process-backend.js +71 -0
- package/dist/plugins/process/infrastructure/pty-process-backend.d.ts +8 -0
- package/dist/plugins/process/infrastructure/pty-process-backend.js +51 -0
- package/dist/plugins/process/mcp.d.ts +3 -0
- package/dist/plugins/process/mcp.js +58 -0
- package/dist/plugins/process/plugin.d.ts +4 -0
- package/dist/plugins/process/plugin.js +25 -0
- package/dist/plugins/process/process-supervisor.d.ts +39 -0
- package/dist/plugins/process/process-supervisor.js +244 -0
- package/dist/plugins/process/types.d.ts +30 -0
- package/dist/plugins/process/types.js +1 -0
- package/dist/plugins/types.d.ts +35 -0
- package/dist/plugins/types.js +17 -0
- package/dist/plugins/web/api-types.d.ts +56 -0
- package/dist/plugins/web/api-types.js +1 -0
- package/dist/plugins/web/http/api-router.d.ts +13 -0
- package/dist/plugins/web/http/api-router.js +47 -0
- package/dist/plugins/web/http/auth-api-router.d.ts +8 -0
- package/dist/plugins/web/http/auth-api-router.js +123 -0
- package/dist/plugins/web/http/cloud-api-router.d.ts +4 -0
- package/dist/plugins/web/http/cloud-api-router.js +29 -0
- package/dist/plugins/web/http/computer-api-router.d.ts +5 -0
- package/dist/plugins/web/http/computer-api-router.js +69 -0
- package/dist/plugins/web/http/git-api-router.d.ts +3 -0
- package/dist/plugins/web/http/git-api-router.js +85 -0
- package/dist/plugins/web/http/logs-api-router.d.ts +3 -0
- package/dist/plugins/web/http/logs-api-router.js +49 -0
- package/dist/plugins/web/http/process-api-router.d.ts +3 -0
- package/dist/plugins/web/http/process-api-router.js +16 -0
- package/dist/plugins/web/http/runtime-api-router.d.ts +10 -0
- package/dist/plugins/web/http/runtime-api-router.js +34 -0
- package/dist/plugins/web/http/workspace-api-router.d.ts +3 -0
- package/dist/plugins/web/http/workspace-api-router.js +91 -0
- package/dist/plugins/web/plugin.d.ts +8 -0
- package/dist/plugins/web/plugin.js +17 -0
- package/dist/plugins/web/runtime.d.ts +18 -0
- package/dist/plugins/web/runtime.js +31 -0
- package/dist/plugins/workspace/mcp.d.ts +3 -0
- package/dist/plugins/workspace/mcp.js +24 -0
- package/dist/plugins/workspace/metadata.d.ts +6 -0
- package/dist/plugins/workspace/metadata.js +111 -0
- package/dist/plugins/workspace/plugin.d.ts +4 -0
- package/dist/plugins/workspace/plugin.js +22 -0
- package/dist/plugins/workspace/types.d.ts +23 -0
- package/dist/plugins/workspace/types.js +1 -0
- package/dist/plugins/workspace/workspace-fs.d.ts +28 -0
- package/dist/plugins/workspace/workspace-fs.js +200 -0
- package/dist/plugins/workspace/workspace-service.d.ts +15 -0
- package/dist/plugins/workspace/workspace-service.js +140 -0
- package/dist/presentation/http/http-utils.d.ts +9 -0
- package/dist/presentation/http/http-utils.js +89 -0
- package/dist/presentation/http/oauth-router.d.ts +5 -0
- package/dist/presentation/http/oauth-router.js +172 -0
- package/dist/web/assets/CloudView-CHjVbp-5.css +1 -0
- package/dist/web/assets/CloudView-CvX0dkgu.js +1 -0
- package/dist/web/assets/CodeViewer-CH1DEJge.css +1 -0
- package/dist/web/assets/CodeViewer.vue_vue_type_script_setup_true_lang-B5TxGkUW.js +3 -0
- package/dist/web/assets/ComputerView-91Z9Cefw.css +1 -0
- package/dist/web/assets/ComputerView-OOyEqWml.js +1 -0
- package/dist/web/assets/McpToolsView-BTnolyS6.css +1 -0
- package/dist/web/assets/McpToolsView-DjXWTKrZ.js +1 -0
- package/dist/web/assets/OperationsView-DqTY51Cr.js +4 -0
- package/dist/web/assets/ProcessesView-C13BykIa.js +4 -0
- package/dist/web/assets/StateChip.vue_vue_type_script_setup_true_lang-DyOhJmR6.js +1 -0
- package/dist/web/assets/SystemLogsView-Ci0u4BTb.js +1 -0
- package/dist/web/assets/VSelect-CAxEESw-.css +1 -0
- package/dist/web/assets/VSelect-DrRpKyYI.js +1 -0
- package/dist/web/assets/VSpacer-C3wAY3F0.js +1 -0
- package/dist/web/assets/VSpacer-DfbUir7X.css +1 -0
- package/dist/web/assets/VSwitch-Cos8PNSP.css +1 -0
- package/dist/web/assets/VSwitch-CxusR4iO.js +1 -0
- package/dist/web/assets/VTabs-DSWgbwhc.css +1 -0
- package/dist/web/assets/VTabs-qBcuuXh3.js +1 -0
- package/dist/web/assets/WorkspacesView-BzQ0aH74.css +1 -0
- package/dist/web/assets/WorkspacesView-CijIvfsp.js +2 -0
- package/dist/web/assets/_plugin-vue_export-helper-DlAUqK2U.js +1 -0
- package/dist/web/assets/chatroom-B5p-5n3y.svg +15 -0
- package/dist/web/assets/index-BDkarAkX.js +2 -0
- package/dist/web/assets/index-BegKQ3Yd.js +19 -0
- package/dist/web/assets/index-CkjqXRSj.css +1 -0
- package/dist/web/assets/syntax-highlight-B5ArnyrC.js +3 -0
- package/dist/web/assets/useOperationLabels-BDjzGDkT.js +1 -0
- package/dist/web/assets/utils-rtPwWNel.js +1 -0
- package/dist/web/index.html +19 -0
- package/package.json +125 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
export class PipeProcessBackend {
|
|
3
|
+
kind = "pipe";
|
|
4
|
+
async start(command, args, options) {
|
|
5
|
+
const child = spawn(command, args, {
|
|
6
|
+
cwd: options.cwd,
|
|
7
|
+
env: options.env,
|
|
8
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
9
|
+
detached: process.platform !== "win32",
|
|
10
|
+
windowsHide: true,
|
|
11
|
+
});
|
|
12
|
+
await new Promise((resolve, reject) => {
|
|
13
|
+
child.once("spawn", resolve);
|
|
14
|
+
child.once("error", reject);
|
|
15
|
+
});
|
|
16
|
+
return new PipeBackendProcess(child);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
class PipeBackendProcess {
|
|
20
|
+
child;
|
|
21
|
+
constructor(child) {
|
|
22
|
+
this.child = child;
|
|
23
|
+
}
|
|
24
|
+
get pid() {
|
|
25
|
+
return this.child.pid ?? null;
|
|
26
|
+
}
|
|
27
|
+
write(data) {
|
|
28
|
+
this.child.stdin.write(data);
|
|
29
|
+
}
|
|
30
|
+
kill(signal = "SIGTERM") {
|
|
31
|
+
if (!this.child.pid)
|
|
32
|
+
return;
|
|
33
|
+
if (process.platform === "win32") {
|
|
34
|
+
const args = ["/PID", String(this.child.pid), "/T"];
|
|
35
|
+
if (signal === "SIGKILL")
|
|
36
|
+
args.push("/F");
|
|
37
|
+
const killer = spawn("taskkill.exe", args, {
|
|
38
|
+
stdio: "ignore",
|
|
39
|
+
windowsHide: true,
|
|
40
|
+
});
|
|
41
|
+
let fellBack = false;
|
|
42
|
+
const fallback = () => {
|
|
43
|
+
if (fellBack)
|
|
44
|
+
return;
|
|
45
|
+
fellBack = true;
|
|
46
|
+
this.child.kill(signal);
|
|
47
|
+
};
|
|
48
|
+
killer.once("error", fallback);
|
|
49
|
+
killer.once("exit", (code) => {
|
|
50
|
+
if (code !== 0)
|
|
51
|
+
fallback();
|
|
52
|
+
});
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
try {
|
|
56
|
+
process.kill(-this.child.pid, signal);
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
this.child.kill(signal);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
onStdout(listener) {
|
|
63
|
+
this.child.stdout.on("data", listener);
|
|
64
|
+
}
|
|
65
|
+
onStderr(listener) {
|
|
66
|
+
this.child.stderr.on("data", listener);
|
|
67
|
+
}
|
|
68
|
+
onExit(listener) {
|
|
69
|
+
this.child.once("close", (code, signal) => listener({ exitCode: code, signal }));
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { BackendProcess, ProcessBackend } from "../backend.js";
|
|
2
|
+
export declare class PtyProcessBackend implements ProcessBackend {
|
|
3
|
+
readonly kind: "pty";
|
|
4
|
+
start(command: string, args: string[], options: {
|
|
5
|
+
cwd: string;
|
|
6
|
+
env: NodeJS.ProcessEnv;
|
|
7
|
+
}): Promise<BackendProcess>;
|
|
8
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { ChatRoomError } from "#core/errors/chatroom-error";
|
|
2
|
+
export class PtyProcessBackend {
|
|
3
|
+
kind = "pty";
|
|
4
|
+
async start(command, args, options) {
|
|
5
|
+
let pty;
|
|
6
|
+
try {
|
|
7
|
+
pty = (await import("node-pty"));
|
|
8
|
+
}
|
|
9
|
+
catch (error) {
|
|
10
|
+
throw new ChatRoomError("UNSUPPORTED", "PTY support is unavailable; install optional dependency node-pty", undefined, { cause: error });
|
|
11
|
+
}
|
|
12
|
+
const env = Object.fromEntries(Object.entries(options.env).filter((entry) => typeof entry[1] === "string"));
|
|
13
|
+
const processHandle = pty.spawn(command, args, {
|
|
14
|
+
name: env.TERM ?? "xterm-256color",
|
|
15
|
+
cols: 120,
|
|
16
|
+
rows: 30,
|
|
17
|
+
cwd: options.cwd,
|
|
18
|
+
env,
|
|
19
|
+
});
|
|
20
|
+
return new PtyBackendProcess(processHandle);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
class PtyBackendProcess {
|
|
24
|
+
processHandle;
|
|
25
|
+
constructor(processHandle) {
|
|
26
|
+
this.processHandle = processHandle;
|
|
27
|
+
}
|
|
28
|
+
get pid() {
|
|
29
|
+
return this.processHandle.pid;
|
|
30
|
+
}
|
|
31
|
+
write(data) {
|
|
32
|
+
this.processHandle.write(data);
|
|
33
|
+
}
|
|
34
|
+
kill(signal = "SIGTERM") {
|
|
35
|
+
if (process.platform === "win32") {
|
|
36
|
+
this.processHandle.kill();
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
this.processHandle.kill(signal);
|
|
40
|
+
}
|
|
41
|
+
onStdout(listener) {
|
|
42
|
+
this.processHandle.onData((data) => listener(Buffer.from(data)));
|
|
43
|
+
}
|
|
44
|
+
onStderr(_listener) { }
|
|
45
|
+
onExit(listener) {
|
|
46
|
+
this.processHandle.onExit((event) => listener({
|
|
47
|
+
exitCode: event.exitCode,
|
|
48
|
+
signal: event.signal ? String(event.signal) : null,
|
|
49
|
+
}));
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { closedRead, destructiveLocalMutation, openWorldMutation, processSnapshotSchema, } from "#mcp/server/tool-support";
|
|
3
|
+
export function registerProcessTools(mcp, processes) {
|
|
4
|
+
mcp.registerTool("process_start", {
|
|
5
|
+
title: "Start process",
|
|
6
|
+
description: "Start a supervised executable directly and return a ProcessId immediately. Prefer invoking the target executable without a shell. For compound shell commands, use bash -c rather than bash -lc unless login-shell semantics are explicitly required, because a login shell may replace the inherited PATH (for example, removing NVM-managed Node.js commands).",
|
|
7
|
+
inputSchema: z.object({
|
|
8
|
+
command: z.string().min(1),
|
|
9
|
+
args: z.array(z.string()).default([]),
|
|
10
|
+
cwd: z.string().default("."),
|
|
11
|
+
env: z.record(z.string(), z.string()).optional(),
|
|
12
|
+
pty: z.boolean().default(false),
|
|
13
|
+
timeoutMs: z.number().int().positive().optional(),
|
|
14
|
+
}),
|
|
15
|
+
outputSchema: processSnapshotSchema,
|
|
16
|
+
annotations: openWorldMutation,
|
|
17
|
+
action: "start",
|
|
18
|
+
}, (input, execution) => {
|
|
19
|
+
execution.deferCompletion();
|
|
20
|
+
return processes.start({
|
|
21
|
+
cwd: input.cwd,
|
|
22
|
+
command: input.command,
|
|
23
|
+
args: input.args,
|
|
24
|
+
...(input.env ? { env: input.env } : {}),
|
|
25
|
+
pty: input.pty,
|
|
26
|
+
...(input.timeoutMs === undefined
|
|
27
|
+
? {}
|
|
28
|
+
: { timeoutMs: input.timeoutMs }),
|
|
29
|
+
}, { source: "mcp", operationId: execution.operationId });
|
|
30
|
+
});
|
|
31
|
+
mcp.registerTool("process_read", {
|
|
32
|
+
title: "Read process",
|
|
33
|
+
description: "Read bounded stdout/stderr and current process state.",
|
|
34
|
+
inputSchema: z.object({ processId: z.string() }),
|
|
35
|
+
outputSchema: processSnapshotSchema,
|
|
36
|
+
annotations: closedRead,
|
|
37
|
+
action: "read",
|
|
38
|
+
}, (input) => processes.read(input.processId));
|
|
39
|
+
mcp.registerTool("process_write", {
|
|
40
|
+
title: "Write process stdin",
|
|
41
|
+
description: "Write to stdin of a running process.",
|
|
42
|
+
inputSchema: z.object({ processId: z.string(), data: z.string() }),
|
|
43
|
+
outputSchema: processSnapshotSchema,
|
|
44
|
+
annotations: openWorldMutation,
|
|
45
|
+
action: "write",
|
|
46
|
+
}, (input) => processes.write(input.processId, input.data));
|
|
47
|
+
mcp.registerTool("process_kill", {
|
|
48
|
+
title: "Stop process",
|
|
49
|
+
description: "Terminate or force-kill a supervised process.",
|
|
50
|
+
inputSchema: z.object({
|
|
51
|
+
processId: z.string(),
|
|
52
|
+
force: z.boolean().default(false),
|
|
53
|
+
}),
|
|
54
|
+
outputSchema: processSnapshotSchema,
|
|
55
|
+
annotations: destructiveLocalMutation,
|
|
56
|
+
action: (input) => (input.force ? "kill" : "terminate"),
|
|
57
|
+
}, (input) => processes.kill(input.processId, input.force));
|
|
58
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { InternalPlugin } from "#plugins/types";
|
|
2
|
+
import { ProcessSupervisor } from "./process-supervisor.js";
|
|
3
|
+
export declare const ProcessService: import("#plugins/types").ServiceToken<ProcessSupervisor>;
|
|
4
|
+
export declare function createProcessPlugin(): InternalPlugin;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { createServiceToken } from "#plugins/types";
|
|
2
|
+
import { PipeProcessBackend } from "./infrastructure/pipe-process-backend.js";
|
|
3
|
+
import { PtyProcessBackend } from "./infrastructure/pty-process-backend.js";
|
|
4
|
+
import { registerProcessTools } from "./mcp.js";
|
|
5
|
+
import { ProcessSupervisor } from "./process-supervisor.js";
|
|
6
|
+
export const ProcessService = createServiceToken("process");
|
|
7
|
+
export function createProcessPlugin() {
|
|
8
|
+
let service = null;
|
|
9
|
+
return {
|
|
10
|
+
id: "process",
|
|
11
|
+
activate(context) {
|
|
12
|
+
service = new ProcessSupervisor({ pipe: new PipeProcessBackend(), pty: new PtyProcessBackend() }, context.operations, context.events, context.config.process.maxOutputBytes, context.config.process.defaultTimeoutMs, context.config.process.maxCompletedProcesses);
|
|
13
|
+
context.services.provide(ProcessService, service);
|
|
14
|
+
},
|
|
15
|
+
registerMcp(mcp) {
|
|
16
|
+
if (!service)
|
|
17
|
+
throw new Error("Process plugin is not active");
|
|
18
|
+
registerProcessTools(mcp, service);
|
|
19
|
+
},
|
|
20
|
+
async deactivate() {
|
|
21
|
+
await service?.shutdown();
|
|
22
|
+
service = null;
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { ProcessId, ProcessSnapshot, ProcessStartRequest, ProcessSummary } from "./types.js";
|
|
2
|
+
import type { RuntimeEventBus } from "#app/event-bus";
|
|
3
|
+
import type { OperationLog } from "#operations/operation-log";
|
|
4
|
+
import type { OperationSource } from "#core/operations/types";
|
|
5
|
+
import type { ProcessBackend } from "./backend.js";
|
|
6
|
+
interface ProcessOperationContext {
|
|
7
|
+
source: OperationSource;
|
|
8
|
+
action?: string;
|
|
9
|
+
operationId?: string;
|
|
10
|
+
}
|
|
11
|
+
export declare class ProcessSupervisor {
|
|
12
|
+
private readonly backends;
|
|
13
|
+
private readonly operations;
|
|
14
|
+
private readonly eventBus;
|
|
15
|
+
private readonly maxOutputBytes;
|
|
16
|
+
private readonly defaultTimeoutMs;
|
|
17
|
+
private readonly maxCompletedProcesses;
|
|
18
|
+
private readonly processes;
|
|
19
|
+
private shuttingDown;
|
|
20
|
+
constructor(backends: {
|
|
21
|
+
pipe: ProcessBackend;
|
|
22
|
+
pty: ProcessBackend;
|
|
23
|
+
}, operations: OperationLog, eventBus: RuntimeEventBus, maxOutputBytes: number, defaultTimeoutMs: number, maxCompletedProcesses: number);
|
|
24
|
+
start(request: ProcessStartRequest, operationContext: ProcessOperationContext): Promise<ProcessSnapshot>;
|
|
25
|
+
read(processId: ProcessId): ProcessSnapshot;
|
|
26
|
+
list(): ProcessSnapshot[];
|
|
27
|
+
summaries(): ProcessSummary[];
|
|
28
|
+
write(processId: ProcessId, data: string): ProcessSnapshot;
|
|
29
|
+
kill(processId: ProcessId, force?: boolean): ProcessSnapshot;
|
|
30
|
+
shutdown(): Promise<void>;
|
|
31
|
+
private onOutput;
|
|
32
|
+
private onExit;
|
|
33
|
+
private trimCompletedProcesses;
|
|
34
|
+
private require;
|
|
35
|
+
private requireRunning;
|
|
36
|
+
private summaryOf;
|
|
37
|
+
private snapshotOf;
|
|
38
|
+
}
|
|
39
|
+
export {};
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { ChatRoomError } from "#core/errors/chatroom-error";
|
|
3
|
+
import { childEnvironment } from "#core/runtime/child-environment";
|
|
4
|
+
import { HeadTailBuffer } from "./head-tail-buffer.js";
|
|
5
|
+
export class ProcessSupervisor {
|
|
6
|
+
backends;
|
|
7
|
+
operations;
|
|
8
|
+
eventBus;
|
|
9
|
+
maxOutputBytes;
|
|
10
|
+
defaultTimeoutMs;
|
|
11
|
+
maxCompletedProcesses;
|
|
12
|
+
processes = new Map();
|
|
13
|
+
shuttingDown = false;
|
|
14
|
+
constructor(backends, operations, eventBus, maxOutputBytes, defaultTimeoutMs, maxCompletedProcesses) {
|
|
15
|
+
this.backends = backends;
|
|
16
|
+
this.operations = operations;
|
|
17
|
+
this.eventBus = eventBus;
|
|
18
|
+
this.maxOutputBytes = maxOutputBytes;
|
|
19
|
+
this.defaultTimeoutMs = defaultTimeoutMs;
|
|
20
|
+
this.maxCompletedProcesses = maxCompletedProcesses;
|
|
21
|
+
}
|
|
22
|
+
async start(request, operationContext) {
|
|
23
|
+
if (this.shuttingDown)
|
|
24
|
+
throw new ChatRoomError("CONFLICT", "Process supervisor is shutting down");
|
|
25
|
+
const processId = `proc_${randomUUID()}`;
|
|
26
|
+
const args = request.args ?? [];
|
|
27
|
+
const adoptedOperation = operationContext.operationId !== undefined;
|
|
28
|
+
const operationId = operationContext.operationId ??
|
|
29
|
+
this.operations.start({
|
|
30
|
+
pluginId: "process",
|
|
31
|
+
source: operationContext.source,
|
|
32
|
+
action: operationContext.action ?? "start",
|
|
33
|
+
processId,
|
|
34
|
+
input: {
|
|
35
|
+
command: request.command,
|
|
36
|
+
args,
|
|
37
|
+
cwd: request.cwd,
|
|
38
|
+
pty: request.pty ?? false,
|
|
39
|
+
timeoutMs: request.timeoutMs ?? this.defaultTimeoutMs,
|
|
40
|
+
env: request.env ?? {},
|
|
41
|
+
},
|
|
42
|
+
}).operationId;
|
|
43
|
+
if (adoptedOperation)
|
|
44
|
+
this.operations.associate(operationId, { processId });
|
|
45
|
+
let backend;
|
|
46
|
+
try {
|
|
47
|
+
backend = await (request.pty ? this.backends.pty : this.backends.pipe).start(request.command, args, {
|
|
48
|
+
cwd: request.cwd,
|
|
49
|
+
env: childEnvironment(request.env),
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
if (!adoptedOperation)
|
|
54
|
+
this.operations.finish(operationId, "error", null, error);
|
|
55
|
+
throw new ChatRoomError("PROCESS_FAILED", `Failed to start process: ${request.command}`, undefined, { cause: error });
|
|
56
|
+
}
|
|
57
|
+
let resolveSettled;
|
|
58
|
+
const settled = new Promise((resolve) => {
|
|
59
|
+
resolveSettled = resolve;
|
|
60
|
+
});
|
|
61
|
+
const managed = {
|
|
62
|
+
request: {
|
|
63
|
+
...request,
|
|
64
|
+
args: [...args],
|
|
65
|
+
...(request.env ? { env: { ...request.env } } : {}),
|
|
66
|
+
},
|
|
67
|
+
backend,
|
|
68
|
+
stdout: new HeadTailBuffer(this.maxOutputBytes),
|
|
69
|
+
stderr: new HeadTailBuffer(this.maxOutputBytes),
|
|
70
|
+
state: "running",
|
|
71
|
+
startedAt: new Date(),
|
|
72
|
+
finishedAt: null,
|
|
73
|
+
exitCode: null,
|
|
74
|
+
signal: null,
|
|
75
|
+
timeout: null,
|
|
76
|
+
forceTimeout: null,
|
|
77
|
+
outputEventTimer: null,
|
|
78
|
+
timedOut: false,
|
|
79
|
+
operationId,
|
|
80
|
+
settled,
|
|
81
|
+
resolveSettled,
|
|
82
|
+
};
|
|
83
|
+
this.processes.set(processId, managed);
|
|
84
|
+
backend.onStdout((chunk) => this.onOutput(processId, "stdout", chunk));
|
|
85
|
+
backend.onStderr((chunk) => this.onOutput(processId, "stderr", chunk));
|
|
86
|
+
backend.onExit((exit) => this.onExit(processId, exit.exitCode, exit.signal));
|
|
87
|
+
const timeoutMs = request.timeoutMs ?? this.defaultTimeoutMs;
|
|
88
|
+
if (timeoutMs > 0)
|
|
89
|
+
managed.timeout = setTimeout(() => {
|
|
90
|
+
if (managed.state !== "running")
|
|
91
|
+
return;
|
|
92
|
+
managed.timedOut = true;
|
|
93
|
+
managed.backend.kill("SIGTERM");
|
|
94
|
+
managed.forceTimeout = setTimeout(() => {
|
|
95
|
+
if (managed.state === "running")
|
|
96
|
+
managed.backend.kill("SIGKILL");
|
|
97
|
+
}, 2000).unref();
|
|
98
|
+
}, timeoutMs).unref();
|
|
99
|
+
const snapshot = this.snapshotOf(processId, managed);
|
|
100
|
+
this.eventBus.emit({ type: "process", process: snapshot });
|
|
101
|
+
return snapshot;
|
|
102
|
+
}
|
|
103
|
+
read(processId) {
|
|
104
|
+
const item = this.require(processId);
|
|
105
|
+
return this.snapshotOf(processId, item);
|
|
106
|
+
}
|
|
107
|
+
list() {
|
|
108
|
+
return [...this.processes.entries()]
|
|
109
|
+
.map(([id, item]) => this.snapshotOf(id, item))
|
|
110
|
+
.sort((a, b) => b.startedAt.localeCompare(a.startedAt));
|
|
111
|
+
}
|
|
112
|
+
summaries() {
|
|
113
|
+
return [...this.processes.entries()]
|
|
114
|
+
.map(([id, item]) => this.summaryOf(id, item))
|
|
115
|
+
.sort((a, b) => b.startedAt.localeCompare(a.startedAt));
|
|
116
|
+
}
|
|
117
|
+
write(processId, data) {
|
|
118
|
+
const item = this.requireRunning(processId);
|
|
119
|
+
item.backend.write(data);
|
|
120
|
+
return this.snapshotOf(processId, item);
|
|
121
|
+
}
|
|
122
|
+
kill(processId, force = false) {
|
|
123
|
+
const item = this.requireRunning(processId);
|
|
124
|
+
item.backend.kill(force ? "SIGKILL" : "SIGTERM");
|
|
125
|
+
return this.snapshotOf(processId, item);
|
|
126
|
+
}
|
|
127
|
+
async shutdown() {
|
|
128
|
+
this.shuttingDown = true;
|
|
129
|
+
const running = [...this.processes.entries()].filter(([, item]) => item.state === "running");
|
|
130
|
+
for (const [, item] of running)
|
|
131
|
+
item.backend.kill("SIGTERM");
|
|
132
|
+
await Promise.race([
|
|
133
|
+
Promise.allSettled(running.map(([, item]) => item.settled)),
|
|
134
|
+
new Promise((resolve) => setTimeout(resolve, 1500)),
|
|
135
|
+
]);
|
|
136
|
+
const survivors = running.filter(([, item]) => item.state === "running");
|
|
137
|
+
for (const [, item] of survivors)
|
|
138
|
+
item.backend.kill("SIGKILL");
|
|
139
|
+
if (survivors.length) {
|
|
140
|
+
await Promise.race([
|
|
141
|
+
Promise.allSettled(survivors.map(([, item]) => item.settled)),
|
|
142
|
+
new Promise((resolve) => setTimeout(resolve, 1500)),
|
|
143
|
+
]);
|
|
144
|
+
for (const [processId, item] of survivors)
|
|
145
|
+
if (item.state === "running")
|
|
146
|
+
this.onExit(processId, null, "SIGKILL");
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
onOutput(processId, stream, chunk) {
|
|
150
|
+
const item = this.processes.get(processId);
|
|
151
|
+
if (!item || item.state !== "running")
|
|
152
|
+
return;
|
|
153
|
+
(stream === "stdout" ? item.stdout : item.stderr).append(chunk);
|
|
154
|
+
if (!item.outputEventTimer) {
|
|
155
|
+
item.outputEventTimer = setTimeout(() => {
|
|
156
|
+
item.outputEventTimer = null;
|
|
157
|
+
if (item.state === "running")
|
|
158
|
+
this.eventBus.emit({ type: "process-output", processId });
|
|
159
|
+
}, 500).unref();
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
onExit(processId, exitCode, signal) {
|
|
163
|
+
const item = this.processes.get(processId);
|
|
164
|
+
if (!item || item.state !== "running")
|
|
165
|
+
return;
|
|
166
|
+
if (item.timeout)
|
|
167
|
+
clearTimeout(item.timeout);
|
|
168
|
+
if (item.forceTimeout)
|
|
169
|
+
clearTimeout(item.forceTimeout);
|
|
170
|
+
if (item.outputEventTimer)
|
|
171
|
+
clearTimeout(item.outputEventTimer);
|
|
172
|
+
item.finishedAt = new Date();
|
|
173
|
+
item.exitCode = exitCode;
|
|
174
|
+
item.signal = signal;
|
|
175
|
+
item.state = signal ? "killed" : exitCode === 0 ? "exited" : "failed";
|
|
176
|
+
const snapshot = this.snapshotOf(processId, item);
|
|
177
|
+
this.operations.finish(item.operationId, exitCode === 0 && !signal ? "success" : signal ? "cancelled" : "error", {
|
|
178
|
+
stdout: snapshot.stdout,
|
|
179
|
+
stderr: snapshot.stderr,
|
|
180
|
+
exitCode,
|
|
181
|
+
signal,
|
|
182
|
+
durationMs: snapshot.durationMs,
|
|
183
|
+
outputTruncated: snapshot.outputTruncated,
|
|
184
|
+
timedOut: snapshot.timedOut,
|
|
185
|
+
}, exitCode === 0 && !signal
|
|
186
|
+
? undefined
|
|
187
|
+
: { exitCode, signal, timedOut: snapshot.timedOut });
|
|
188
|
+
this.eventBus.emit({ type: "process", process: snapshot });
|
|
189
|
+
item.resolveSettled(snapshot);
|
|
190
|
+
this.trimCompletedProcesses();
|
|
191
|
+
}
|
|
192
|
+
trimCompletedProcesses() {
|
|
193
|
+
const completed = [...this.processes.entries()]
|
|
194
|
+
.filter(([, item]) => item.state !== "running")
|
|
195
|
+
.sort(([, a], [, b]) => b.startedAt.getTime() - a.startedAt.getTime());
|
|
196
|
+
for (const [processId] of completed.slice(this.maxCompletedProcesses)) {
|
|
197
|
+
this.processes.delete(processId);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
require(processId) {
|
|
201
|
+
const item = this.processes.get(processId);
|
|
202
|
+
if (!item)
|
|
203
|
+
throw new ChatRoomError("NOT_FOUND", `Unknown ProcessId: ${processId}`);
|
|
204
|
+
return item;
|
|
205
|
+
}
|
|
206
|
+
requireRunning(processId) {
|
|
207
|
+
const item = this.require(processId);
|
|
208
|
+
if (item.state !== "running")
|
|
209
|
+
throw new ChatRoomError("CONFLICT", `Process is not running: ${processId}`);
|
|
210
|
+
return item;
|
|
211
|
+
}
|
|
212
|
+
summaryOf(id, item) {
|
|
213
|
+
const finish = item.finishedAt?.getTime() ?? Date.now();
|
|
214
|
+
return {
|
|
215
|
+
processId: id,
|
|
216
|
+
command: item.request.command,
|
|
217
|
+
args: [...(item.request.args ?? [])],
|
|
218
|
+
state: item.state,
|
|
219
|
+
startedAt: item.startedAt.toISOString(),
|
|
220
|
+
durationMs: Math.max(0, finish - item.startedAt.getTime()),
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
snapshotOf(id, item) {
|
|
224
|
+
const stdout = item.stdout.snapshot(), stderr = item.stderr.snapshot(), finish = item.finishedAt?.getTime() ?? Date.now();
|
|
225
|
+
return {
|
|
226
|
+
processId: id,
|
|
227
|
+
command: item.request.command,
|
|
228
|
+
args: [...(item.request.args ?? [])],
|
|
229
|
+
cwd: item.request.cwd,
|
|
230
|
+
pid: item.backend.pid,
|
|
231
|
+
state: item.state,
|
|
232
|
+
startedAt: item.startedAt.toISOString(),
|
|
233
|
+
finishedAt: item.finishedAt?.toISOString() ?? null,
|
|
234
|
+
durationMs: Math.max(0, finish - item.startedAt.getTime()),
|
|
235
|
+
exitCode: item.exitCode,
|
|
236
|
+
signal: item.signal,
|
|
237
|
+
stdout: stdout.text,
|
|
238
|
+
stderr: stderr.text,
|
|
239
|
+
outputTruncated: stdout.outputTruncated || stderr.outputTruncated,
|
|
240
|
+
timedOut: item.timedOut,
|
|
241
|
+
operationId: item.operationId,
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
type ProcessState = "running" | "exited" | "killed" | "failed";
|
|
2
|
+
export type ProcessId = string;
|
|
3
|
+
export interface ProcessStartRequest {
|
|
4
|
+
cwd: string;
|
|
5
|
+
command: string;
|
|
6
|
+
args?: string[];
|
|
7
|
+
env?: Record<string, string>;
|
|
8
|
+
pty?: boolean;
|
|
9
|
+
timeoutMs?: number;
|
|
10
|
+
}
|
|
11
|
+
export interface ProcessSnapshot {
|
|
12
|
+
processId: ProcessId;
|
|
13
|
+
command: string;
|
|
14
|
+
args: string[];
|
|
15
|
+
cwd: string;
|
|
16
|
+
pid: number | null;
|
|
17
|
+
state: ProcessState;
|
|
18
|
+
startedAt: string;
|
|
19
|
+
finishedAt: string | null;
|
|
20
|
+
durationMs: number;
|
|
21
|
+
exitCode: number | null;
|
|
22
|
+
signal: string | null;
|
|
23
|
+
stdout: string;
|
|
24
|
+
stderr: string;
|
|
25
|
+
outputTruncated: boolean;
|
|
26
|
+
timedOut: boolean;
|
|
27
|
+
operationId: string;
|
|
28
|
+
}
|
|
29
|
+
export type ProcessSummary = Pick<ProcessSnapshot, "processId" | "command" | "args" | "state" | "startedAt" | "durationMs">;
|
|
30
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { ChatRoomConfig } from "#config/types";
|
|
2
|
+
import type { AppDatabase } from "#infrastructure/database/app-database";
|
|
3
|
+
import type { PluginMcpRegistrar } from "#mcp/server/plugin-mcp-registrar";
|
|
4
|
+
import type { OperationLog } from "#operations/operation-log";
|
|
5
|
+
import type { McpToolControl } from "#mcp/server/tool-control";
|
|
6
|
+
import type { RuntimeEventBus } from "#app/event-bus";
|
|
7
|
+
import type { ExternalAccessRegistry } from "#app/external-access-registry";
|
|
8
|
+
import type { LogWriter } from "#core/logging/types";
|
|
9
|
+
export interface ServiceToken<T> {
|
|
10
|
+
readonly key: symbol;
|
|
11
|
+
readonly name: string;
|
|
12
|
+
readonly __type?: T;
|
|
13
|
+
}
|
|
14
|
+
export declare function createServiceToken<T>(name: string): ServiceToken<T>;
|
|
15
|
+
export declare class ServiceRegistry {
|
|
16
|
+
private readonly values;
|
|
17
|
+
provide<T>(token: ServiceToken<T>, value: T): void;
|
|
18
|
+
require<T>(token: ServiceToken<T>): T;
|
|
19
|
+
}
|
|
20
|
+
export interface PluginContext {
|
|
21
|
+
config: ChatRoomConfig;
|
|
22
|
+
database: AppDatabase;
|
|
23
|
+
operations: OperationLog;
|
|
24
|
+
mcpTools: McpToolControl;
|
|
25
|
+
events: RuntimeEventBus;
|
|
26
|
+
externalAccess: ExternalAccessRegistry;
|
|
27
|
+
services: ServiceRegistry;
|
|
28
|
+
logs: LogWriter;
|
|
29
|
+
}
|
|
30
|
+
export interface InternalPlugin {
|
|
31
|
+
id: string;
|
|
32
|
+
activate(context: PluginContext): Promise<void> | void;
|
|
33
|
+
registerMcp?(mcp: PluginMcpRegistrar): void;
|
|
34
|
+
deactivate?(): Promise<void> | void;
|
|
35
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export function createServiceToken(name) {
|
|
2
|
+
return { key: Symbol(name), name };
|
|
3
|
+
}
|
|
4
|
+
export class ServiceRegistry {
|
|
5
|
+
values = new Map();
|
|
6
|
+
provide(token, value) {
|
|
7
|
+
if (this.values.has(token.key))
|
|
8
|
+
throw new Error(`Service already provided: ${token.name}`);
|
|
9
|
+
this.values.set(token.key, value);
|
|
10
|
+
}
|
|
11
|
+
require(token) {
|
|
12
|
+
const value = this.values.get(token.key);
|
|
13
|
+
if (value === undefined)
|
|
14
|
+
throw new Error(`Required service unavailable: ${token.name}`);
|
|
15
|
+
return value;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { Operation as DomainOperation } from "#core/operations/types";
|
|
2
|
+
import type { GitBranch, GitChange, GitCommit, GitDiff, GitStatus } from "#plugins/git/types";
|
|
3
|
+
import type { ProcessSnapshot, ProcessSummary } from "#plugins/process/types";
|
|
4
|
+
import type { McpToolSummary as DomainMcpToolSummary } from "#mcp/server/tool-control";
|
|
5
|
+
import type { CloudServiceId, CloudStatus as DomainCloudStatus } from "#plugins/cloud/types";
|
|
6
|
+
import type { ComputerDisplay, ComputerPermission, ComputerSnapshot, ComputerStatus } from "#plugins/computer/types";
|
|
7
|
+
import type { WorkspaceEntry, WorkspaceFile, WorkspaceInfo, WorkspaceSkill } from "#plugins/workspace/types";
|
|
8
|
+
export type { ComputerDisplay, ComputerPermission, ComputerStatus, GitBranch, GitChange, GitCommit, GitDiff, GitStatus, ProcessSnapshot, ProcessSummary, WorkspaceEntry, WorkspaceFile, WorkspaceInfo, WorkspaceSkill, };
|
|
9
|
+
export interface ComputerPreviewView {
|
|
10
|
+
snapshotId: string;
|
|
11
|
+
revision: number;
|
|
12
|
+
capturedAt: string | null;
|
|
13
|
+
display: ComputerDisplay | null;
|
|
14
|
+
activeApp: string | null;
|
|
15
|
+
activeWindow: string | null;
|
|
16
|
+
cursor: {
|
|
17
|
+
x: number;
|
|
18
|
+
y: number;
|
|
19
|
+
} | null;
|
|
20
|
+
elementCount: number;
|
|
21
|
+
screenshot: ComputerSnapshot["screenshot"] | null;
|
|
22
|
+
}
|
|
23
|
+
export type Operation = DomainOperation;
|
|
24
|
+
export interface AuthStatus {
|
|
25
|
+
authenticated: boolean;
|
|
26
|
+
passkeyAvailable: boolean;
|
|
27
|
+
passkeyRegistered: boolean;
|
|
28
|
+
}
|
|
29
|
+
export interface PasskeySummary {
|
|
30
|
+
id: string;
|
|
31
|
+
name: string;
|
|
32
|
+
lastUsedAt: string;
|
|
33
|
+
}
|
|
34
|
+
export interface RuntimeStatus {
|
|
35
|
+
version: string;
|
|
36
|
+
mcpRequests: number;
|
|
37
|
+
uptimeMinutes: number;
|
|
38
|
+
}
|
|
39
|
+
export interface UpdateStatus {
|
|
40
|
+
latestVersion: string | null;
|
|
41
|
+
updateAvailable: boolean;
|
|
42
|
+
releaseUrl: string | null;
|
|
43
|
+
}
|
|
44
|
+
export type McpToolSummary = DomainMcpToolSummary;
|
|
45
|
+
export type CloudService = CloudServiceId;
|
|
46
|
+
export type CloudStatus = DomainCloudStatus;
|
|
47
|
+
export interface WorkspaceFileContent {
|
|
48
|
+
content: string;
|
|
49
|
+
}
|
|
50
|
+
export interface CloudManagementSession {
|
|
51
|
+
url: string;
|
|
52
|
+
}
|
|
53
|
+
export interface CloudRestoreResult {
|
|
54
|
+
status: CloudStatus;
|
|
55
|
+
}
|
|
56
|
+
export type { LogLevel, LogPage, LogRecord } from "#core/logging/types";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Router } from "express";
|
|
2
|
+
import type { WebRuntime } from "#plugins/web/runtime";
|
|
3
|
+
import type { RuntimeEventBus } from "#app/event-bus";
|
|
4
|
+
import type { AuthService } from "#auth/auth-service";
|
|
5
|
+
import type { PasskeyService } from "#auth/passkey-service";
|
|
6
|
+
import type { IngressPolicy } from "#auth/ingress-policy";
|
|
7
|
+
import type { CloudController } from "#plugins/cloud/controller";
|
|
8
|
+
import type { LogService } from "#core/logging/types";
|
|
9
|
+
export declare function createApiRouter(application: WebRuntime, eventBus: RuntimeEventBus, auth: AuthService, passkeys: PasskeyService, ingress: IngressPolicy, cloud: CloudController, logs: LogService, runtimeStatus: () => {
|
|
10
|
+
version: string;
|
|
11
|
+
mcpRequests: number;
|
|
12
|
+
uptimeMinutes: number;
|
|
13
|
+
}): Router;
|