leduo-patrol 2.0.1 → 2.2.3
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 +27 -4
- package/dist/server/__tests__/access-key-prompt.test.js +80 -0
- package/dist/server/__tests__/acp-session.test.js +92 -0
- package/dist/server/__tests__/activity-monitor.test.js +13 -1
- package/dist/server/__tests__/claude-cli-session.test.js +17 -0
- package/dist/server/__tests__/pty-runtime.test.js +28 -0
- package/dist/server/__tests__/session-manager.test.js +215 -1
- package/dist/server/access-key-prompt.js +84 -0
- package/dist/server/acp-session.js +476 -0
- package/dist/server/activity-monitor.js +22 -7
- package/dist/server/claude-cli-session.js +57 -12
- package/dist/server/index.js +104 -21
- package/dist/server/launch-mode.js +4 -22
- package/dist/server/pty-runtime.js +28 -0
- package/dist/server/session-manager.js +1117 -121
- package/dist/server/shell-session.js +2 -0
- package/dist/server/startup-preferences.js +45 -0
- package/dist/web/assets/index-B-YXVUoQ.css +1 -0
- package/dist/web/assets/index-Bu0K7QgY.js +21 -0
- package/dist/web/index.html +2 -2
- package/package.json +3 -1
- package/vendor/claude-code-acp/node_modules/@agentclientprotocol/sdk/LICENSE +191 -0
- package/vendor/claude-code-acp/node_modules/@agentclientprotocol/sdk/README.md +53 -0
- package/vendor/claude-code-acp/node_modules/@agentclientprotocol/sdk/dist/acp.d.ts +823 -0
- package/vendor/claude-code-acp/node_modules/@agentclientprotocol/sdk/dist/acp.js +965 -0
- package/vendor/claude-code-acp/node_modules/@agentclientprotocol/sdk/dist/acp.js.map +1 -0
- package/vendor/claude-code-acp/node_modules/@agentclientprotocol/sdk/dist/acp.test.d.ts +1 -0
- package/vendor/claude-code-acp/node_modules/@agentclientprotocol/sdk/dist/acp.test.js +839 -0
- package/vendor/claude-code-acp/node_modules/@agentclientprotocol/sdk/dist/acp.test.js.map +1 -0
- package/vendor/claude-code-acp/node_modules/@agentclientprotocol/sdk/dist/examples/agent.d.ts +2 -0
- package/vendor/claude-code-acp/node_modules/@agentclientprotocol/sdk/dist/examples/agent.js +225 -0
- package/vendor/claude-code-acp/node_modules/@agentclientprotocol/sdk/dist/examples/agent.js.map +1 -0
- package/vendor/claude-code-acp/node_modules/@agentclientprotocol/sdk/dist/examples/client.d.ts +2 -0
- package/vendor/claude-code-acp/node_modules/@agentclientprotocol/sdk/dist/examples/client.js +130 -0
- package/vendor/claude-code-acp/node_modules/@agentclientprotocol/sdk/dist/examples/client.js.map +1 -0
- package/vendor/claude-code-acp/node_modules/@agentclientprotocol/sdk/dist/jsonrpc.d.ts +35 -0
- package/vendor/claude-code-acp/node_modules/@agentclientprotocol/sdk/dist/jsonrpc.js +5 -0
- package/vendor/claude-code-acp/node_modules/@agentclientprotocol/sdk/dist/jsonrpc.js.map +1 -0
- package/vendor/claude-code-acp/node_modules/@agentclientprotocol/sdk/dist/schema/index.d.ts +27 -0
- package/vendor/claude-code-acp/node_modules/@agentclientprotocol/sdk/dist/schema/index.js +28 -0
- package/vendor/claude-code-acp/node_modules/@agentclientprotocol/sdk/dist/schema/index.js.map +1 -0
- package/vendor/claude-code-acp/node_modules/@agentclientprotocol/sdk/dist/schema/types.gen.d.ts +2870 -0
- package/vendor/claude-code-acp/node_modules/@agentclientprotocol/sdk/dist/schema/types.gen.js +3 -0
- package/vendor/claude-code-acp/node_modules/@agentclientprotocol/sdk/dist/schema/types.gen.js.map +1 -0
- package/vendor/claude-code-acp/node_modules/@agentclientprotocol/sdk/dist/schema/zod.gen.d.ts +5333 -0
- package/vendor/claude-code-acp/node_modules/@agentclientprotocol/sdk/dist/schema/zod.gen.js +1554 -0
- package/vendor/claude-code-acp/node_modules/@agentclientprotocol/sdk/dist/schema/zod.gen.js.map +1 -0
- package/vendor/claude-code-acp/node_modules/@agentclientprotocol/sdk/dist/stream.d.ts +24 -0
- package/vendor/claude-code-acp/node_modules/@agentclientprotocol/sdk/dist/stream.js +64 -0
- package/vendor/claude-code-acp/node_modules/@agentclientprotocol/sdk/dist/stream.js.map +1 -0
- package/vendor/claude-code-acp/node_modules/@agentclientprotocol/sdk/package.json +66 -0
- package/vendor/claude-code-acp/node_modules/@agentclientprotocol/sdk/schema/schema.json +4125 -0
- package/vendor/claude-code-acp/node_modules/@types/node/LICENSE +21 -0
- package/vendor/claude-code-acp/node_modules/@types/node/README.md +15 -0
- package/vendor/claude-code-acp/node_modules/@types/node/assert/strict.d.ts +105 -0
- package/vendor/claude-code-acp/node_modules/@types/node/assert.d.ts +955 -0
- package/vendor/claude-code-acp/node_modules/@types/node/async_hooks.d.ts +623 -0
- package/vendor/claude-code-acp/node_modules/@types/node/buffer.buffer.d.ts +466 -0
- package/vendor/claude-code-acp/node_modules/@types/node/buffer.d.ts +1810 -0
- package/vendor/claude-code-acp/node_modules/@types/node/child_process.d.ts +1428 -0
- package/vendor/claude-code-acp/node_modules/@types/node/cluster.d.ts +486 -0
- package/vendor/claude-code-acp/node_modules/@types/node/compatibility/iterators.d.ts +21 -0
- package/vendor/claude-code-acp/node_modules/@types/node/console.d.ts +151 -0
- package/vendor/claude-code-acp/node_modules/@types/node/constants.d.ts +20 -0
- package/vendor/claude-code-acp/node_modules/@types/node/crypto.d.ts +4065 -0
- package/vendor/claude-code-acp/node_modules/@types/node/dgram.d.ts +564 -0
- package/vendor/claude-code-acp/node_modules/@types/node/diagnostics_channel.d.ts +576 -0
- package/vendor/claude-code-acp/node_modules/@types/node/dns/promises.d.ts +503 -0
- package/vendor/claude-code-acp/node_modules/@types/node/dns.d.ts +922 -0
- package/vendor/claude-code-acp/node_modules/@types/node/domain.d.ts +166 -0
- package/vendor/claude-code-acp/node_modules/@types/node/events.d.ts +1054 -0
- package/vendor/claude-code-acp/node_modules/@types/node/fs/promises.d.ts +1329 -0
- package/vendor/claude-code-acp/node_modules/@types/node/fs.d.ts +4676 -0
- package/vendor/claude-code-acp/node_modules/@types/node/globals.d.ts +150 -0
- package/vendor/claude-code-acp/node_modules/@types/node/globals.typedarray.d.ts +101 -0
- package/vendor/claude-code-acp/node_modules/@types/node/http.d.ts +2167 -0
- package/vendor/claude-code-acp/node_modules/@types/node/http2.d.ts +2480 -0
- package/vendor/claude-code-acp/node_modules/@types/node/https.d.ts +405 -0
- package/vendor/claude-code-acp/node_modules/@types/node/index.d.ts +115 -0
- package/vendor/claude-code-acp/node_modules/@types/node/inspector/promises.d.ts +41 -0
- package/vendor/claude-code-acp/node_modules/@types/node/inspector.d.ts +224 -0
- package/vendor/claude-code-acp/node_modules/@types/node/inspector.generated.d.ts +4226 -0
- package/vendor/claude-code-acp/node_modules/@types/node/module.d.ts +819 -0
- package/vendor/claude-code-acp/node_modules/@types/node/net.d.ts +933 -0
- package/vendor/claude-code-acp/node_modules/@types/node/os.d.ts +507 -0
- package/vendor/claude-code-acp/node_modules/@types/node/package.json +155 -0
- package/vendor/claude-code-acp/node_modules/@types/node/path/posix.d.ts +8 -0
- package/vendor/claude-code-acp/node_modules/@types/node/path/win32.d.ts +8 -0
- package/vendor/claude-code-acp/node_modules/@types/node/path.d.ts +187 -0
- package/vendor/claude-code-acp/node_modules/@types/node/perf_hooks.d.ts +643 -0
- package/vendor/claude-code-acp/node_modules/@types/node/process.d.ts +2161 -0
- package/vendor/claude-code-acp/node_modules/@types/node/punycode.d.ts +117 -0
- package/vendor/claude-code-acp/node_modules/@types/node/querystring.d.ts +152 -0
- package/vendor/claude-code-acp/node_modules/@types/node/quic.d.ts +910 -0
- package/vendor/claude-code-acp/node_modules/@types/node/readline/promises.d.ts +161 -0
- package/vendor/claude-code-acp/node_modules/@types/node/readline.d.ts +541 -0
- package/vendor/claude-code-acp/node_modules/@types/node/repl.d.ts +415 -0
- package/vendor/claude-code-acp/node_modules/@types/node/sea.d.ts +162 -0
- package/vendor/claude-code-acp/node_modules/@types/node/sqlite.d.ts +955 -0
- package/vendor/claude-code-acp/node_modules/@types/node/stream/consumers.d.ts +38 -0
- package/vendor/claude-code-acp/node_modules/@types/node/stream/promises.d.ts +211 -0
- package/vendor/claude-code-acp/node_modules/@types/node/stream/web.d.ts +296 -0
- package/vendor/claude-code-acp/node_modules/@types/node/stream.d.ts +1760 -0
- package/vendor/claude-code-acp/node_modules/@types/node/string_decoder.d.ts +67 -0
- package/vendor/claude-code-acp/node_modules/@types/node/test/reporters.d.ts +96 -0
- package/vendor/claude-code-acp/node_modules/@types/node/test.d.ts +2240 -0
- package/vendor/claude-code-acp/node_modules/@types/node/timers/promises.d.ts +108 -0
- package/vendor/claude-code-acp/node_modules/@types/node/timers.d.ts +159 -0
- package/vendor/claude-code-acp/node_modules/@types/node/tls.d.ts +1198 -0
- package/vendor/claude-code-acp/node_modules/@types/node/trace_events.d.ts +197 -0
- package/vendor/claude-code-acp/node_modules/@types/node/ts5.6/buffer.buffer.d.ts +462 -0
- package/vendor/claude-code-acp/node_modules/@types/node/ts5.6/compatibility/float16array.d.ts +71 -0
- package/vendor/claude-code-acp/node_modules/@types/node/ts5.6/globals.typedarray.d.ts +36 -0
- package/vendor/claude-code-acp/node_modules/@types/node/ts5.6/index.d.ts +117 -0
- package/vendor/claude-code-acp/node_modules/@types/node/ts5.7/compatibility/float16array.d.ts +72 -0
- package/vendor/claude-code-acp/node_modules/@types/node/ts5.7/index.d.ts +117 -0
- package/vendor/claude-code-acp/node_modules/@types/node/tty.d.ts +250 -0
- package/vendor/claude-code-acp/node_modules/@types/node/url.d.ts +519 -0
- package/vendor/claude-code-acp/node_modules/@types/node/util/types.d.ts +558 -0
- package/vendor/claude-code-acp/node_modules/@types/node/util.d.ts +1662 -0
- package/vendor/claude-code-acp/node_modules/@types/node/v8.d.ts +983 -0
- package/vendor/claude-code-acp/node_modules/@types/node/vm.d.ts +1208 -0
- package/vendor/claude-code-acp/node_modules/@types/node/wasi.d.ts +202 -0
- package/vendor/claude-code-acp/node_modules/@types/node/web-globals/abortcontroller.d.ts +59 -0
- package/vendor/claude-code-acp/node_modules/@types/node/web-globals/blob.d.ts +23 -0
- package/vendor/claude-code-acp/node_modules/@types/node/web-globals/console.d.ts +9 -0
- package/vendor/claude-code-acp/node_modules/@types/node/web-globals/crypto.d.ts +39 -0
- package/vendor/claude-code-acp/node_modules/@types/node/web-globals/domexception.d.ts +68 -0
- package/vendor/claude-code-acp/node_modules/@types/node/web-globals/encoding.d.ts +11 -0
- package/vendor/claude-code-acp/node_modules/@types/node/web-globals/events.d.ts +106 -0
- package/vendor/claude-code-acp/node_modules/@types/node/web-globals/fetch.d.ts +69 -0
- package/vendor/claude-code-acp/node_modules/@types/node/web-globals/importmeta.d.ts +13 -0
- package/vendor/claude-code-acp/node_modules/@types/node/web-globals/messaging.d.ts +23 -0
- package/vendor/claude-code-acp/node_modules/@types/node/web-globals/navigator.d.ts +25 -0
- package/vendor/claude-code-acp/node_modules/@types/node/web-globals/performance.d.ts +45 -0
- package/vendor/claude-code-acp/node_modules/@types/node/web-globals/storage.d.ts +24 -0
- package/vendor/claude-code-acp/node_modules/@types/node/web-globals/streams.d.ts +115 -0
- package/vendor/claude-code-acp/node_modules/@types/node/web-globals/timers.d.ts +44 -0
- package/vendor/claude-code-acp/node_modules/@types/node/web-globals/url.d.ts +24 -0
- package/vendor/claude-code-acp/node_modules/@types/node/worker_threads.d.ts +717 -0
- package/vendor/claude-code-acp/node_modules/@types/node/zlib.d.ts +618 -0
- package/vendor/claude-code-acp/node_modules/undici-types/LICENSE +21 -0
- package/vendor/claude-code-acp/node_modules/undici-types/README.md +6 -0
- package/vendor/claude-code-acp/node_modules/undici-types/agent.d.ts +32 -0
- package/vendor/claude-code-acp/node_modules/undici-types/api.d.ts +43 -0
- package/vendor/claude-code-acp/node_modules/undici-types/balanced-pool.d.ts +29 -0
- package/vendor/claude-code-acp/node_modules/undici-types/cache-interceptor.d.ts +172 -0
- package/vendor/claude-code-acp/node_modules/undici-types/cache.d.ts +36 -0
- package/vendor/claude-code-acp/node_modules/undici-types/client-stats.d.ts +15 -0
- package/vendor/claude-code-acp/node_modules/undici-types/client.d.ts +108 -0
- package/vendor/claude-code-acp/node_modules/undici-types/connector.d.ts +34 -0
- package/vendor/claude-code-acp/node_modules/undici-types/content-type.d.ts +21 -0
- package/vendor/claude-code-acp/node_modules/undici-types/cookies.d.ts +30 -0
- package/vendor/claude-code-acp/node_modules/undici-types/diagnostics-channel.d.ts +74 -0
- package/vendor/claude-code-acp/node_modules/undici-types/dispatcher.d.ts +276 -0
- package/vendor/claude-code-acp/node_modules/undici-types/env-http-proxy-agent.d.ts +22 -0
- package/vendor/claude-code-acp/node_modules/undici-types/errors.d.ts +161 -0
- package/vendor/claude-code-acp/node_modules/undici-types/eventsource.d.ts +66 -0
- package/vendor/claude-code-acp/node_modules/undici-types/fetch.d.ts +211 -0
- package/vendor/claude-code-acp/node_modules/undici-types/formdata.d.ts +108 -0
- package/vendor/claude-code-acp/node_modules/undici-types/global-dispatcher.d.ts +9 -0
- package/vendor/claude-code-acp/node_modules/undici-types/global-origin.d.ts +7 -0
- package/vendor/claude-code-acp/node_modules/undici-types/h2c-client.d.ts +73 -0
- package/vendor/claude-code-acp/node_modules/undici-types/handlers.d.ts +15 -0
- package/vendor/claude-code-acp/node_modules/undici-types/header.d.ts +160 -0
- package/vendor/claude-code-acp/node_modules/undici-types/index.d.ts +80 -0
- package/vendor/claude-code-acp/node_modules/undici-types/interceptors.d.ts +39 -0
- package/vendor/claude-code-acp/node_modules/undici-types/mock-agent.d.ts +68 -0
- package/vendor/claude-code-acp/node_modules/undici-types/mock-call-history.d.ts +111 -0
- package/vendor/claude-code-acp/node_modules/undici-types/mock-client.d.ts +27 -0
- package/vendor/claude-code-acp/node_modules/undici-types/mock-errors.d.ts +12 -0
- package/vendor/claude-code-acp/node_modules/undici-types/mock-interceptor.d.ts +94 -0
- package/vendor/claude-code-acp/node_modules/undici-types/mock-pool.d.ts +27 -0
- package/vendor/claude-code-acp/node_modules/undici-types/package.json +55 -0
- package/vendor/claude-code-acp/node_modules/undici-types/patch.d.ts +29 -0
- package/vendor/claude-code-acp/node_modules/undici-types/pool-stats.d.ts +19 -0
- package/vendor/claude-code-acp/node_modules/undici-types/pool.d.ts +41 -0
- package/vendor/claude-code-acp/node_modules/undici-types/proxy-agent.d.ts +29 -0
- package/vendor/claude-code-acp/node_modules/undici-types/readable.d.ts +68 -0
- package/vendor/claude-code-acp/node_modules/undici-types/retry-agent.d.ts +8 -0
- package/vendor/claude-code-acp/node_modules/undici-types/retry-handler.d.ts +125 -0
- package/vendor/claude-code-acp/node_modules/undici-types/snapshot-agent.d.ts +109 -0
- package/vendor/claude-code-acp/node_modules/undici-types/util.d.ts +18 -0
- package/vendor/claude-code-acp/node_modules/undici-types/utility.d.ts +7 -0
- package/vendor/claude-code-acp/node_modules/undici-types/webidl.d.ts +341 -0
- package/vendor/claude-code-acp/node_modules/undici-types/websocket.d.ts +186 -0
- package/dist/web/assets/index-B0sSFjwT.css +0 -1
- package/dist/web/assets/index-Cdb0JMLq.js +0 -13
package/dist/server/index.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import express from "express";
|
|
3
3
|
import { access, readdir } from "node:fs/promises";
|
|
4
4
|
import path from "node:path";
|
|
5
|
+
import { createRequire } from "node:module";
|
|
5
6
|
import { fileURLToPath } from "node:url";
|
|
6
7
|
import { createServer } from "node:http";
|
|
7
8
|
import { userInfo } from "node:os";
|
|
@@ -10,9 +11,10 @@ import { SessionManager } from "./session-manager.js";
|
|
|
10
11
|
import { formatError, resolveAllowedPath } from "./server-helpers.js";
|
|
11
12
|
import { ShellSession } from "./shell-session.js";
|
|
12
13
|
import { buildSingleFileDiff, buildWorkspaceDiffFilesSnapshot } from "./git-diff.js";
|
|
13
|
-
import { buildAccessCookie,
|
|
14
|
+
import { buildAccessCookie, hasAuthorizedAccessCookie, isAccessKeyAuthorized } from "./access-key.js";
|
|
14
15
|
import { findAvailablePort, pickPreferredLanIp } from "./network.js";
|
|
15
16
|
import { resolveBindMode } from "./launch-mode.js";
|
|
17
|
+
import { resolveAccessKey } from "./access-key-prompt.js";
|
|
16
18
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
17
19
|
const launchCwd = process.cwd();
|
|
18
20
|
const defaultWorkspacePath = process.env.LEDUO_PATROL_WORKSPACE_PATH ?? launchCwd;
|
|
@@ -34,8 +36,9 @@ const listenHost = bindMode === "local" ? "127.0.0.1" : "0.0.0.0";
|
|
|
34
36
|
const launchHost = bindMode === "local" ? "127.0.0.1" : pickPreferredLanIp();
|
|
35
37
|
const launchUser = userInfo().username;
|
|
36
38
|
const claudeBin = process.env.LEDUO_PATROL_CLAUDE_BIN?.trim() || undefined;
|
|
37
|
-
const
|
|
38
|
-
const
|
|
39
|
+
const agentBinPath = resolveAgentBinPath();
|
|
40
|
+
const accessKey = await resolveAccessKey();
|
|
41
|
+
const enableShell = parseBooleanFlag(process.env.LEDUO_ENABLE_SHELL, true);
|
|
39
42
|
const allowSkipPermissions = process.env.LEDUO_PATROL_ALLOW_SKIP_PERMISSIONS === "true";
|
|
40
43
|
const app = express();
|
|
41
44
|
const server = createServer(app);
|
|
@@ -43,6 +46,7 @@ const wss = new WebSocketServer({ server, path: "/ws" });
|
|
|
43
46
|
const sessionManager = new SessionManager({
|
|
44
47
|
allowedRoots,
|
|
45
48
|
claudeBin,
|
|
49
|
+
agentBinPath,
|
|
46
50
|
allowSkipPermissions,
|
|
47
51
|
});
|
|
48
52
|
await sessionManager.initialize();
|
|
@@ -86,11 +90,29 @@ app.get("/api/config", (_req, res) => {
|
|
|
86
90
|
launchHost,
|
|
87
91
|
launchUser,
|
|
88
92
|
allowSkipPermissions,
|
|
93
|
+
availableSessionEngines: sessionManager.getAvailableEngines(),
|
|
94
|
+
defaultSessionEngine: "cli",
|
|
89
95
|
});
|
|
90
96
|
});
|
|
91
97
|
app.get("/api/state", (_req, res) => {
|
|
92
98
|
res.json(sessionManager.getStateSnapshot());
|
|
93
99
|
});
|
|
100
|
+
app.get("/api/session-history", (req, res) => {
|
|
101
|
+
try {
|
|
102
|
+
const clientSessionId = typeof req.query.clientSessionId === "string" ? req.query.clientSessionId : "";
|
|
103
|
+
const before = Number(req.query.before ?? 0);
|
|
104
|
+
const limit = Number(req.query.limit ?? 120);
|
|
105
|
+
if (!clientSessionId) {
|
|
106
|
+
throw new Error("clientSessionId is required");
|
|
107
|
+
}
|
|
108
|
+
res.json(sessionManager.getSessionHistory(clientSessionId, before, limit));
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
res.status(400).json({
|
|
112
|
+
message: formatError(error),
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
});
|
|
94
116
|
app.get("/api/session-diff/files", async (req, res) => {
|
|
95
117
|
try {
|
|
96
118
|
const clientSessionId = typeof req.query.clientSessionId === "string" ? req.query.clientSessionId : "";
|
|
@@ -174,8 +196,17 @@ wss.on("connection", (socket, request) => {
|
|
|
174
196
|
socket.close(1008, "Unauthorized");
|
|
175
197
|
return;
|
|
176
198
|
}
|
|
177
|
-
const
|
|
178
|
-
|
|
199
|
+
const shellSessions = new Map();
|
|
200
|
+
const unsubscribe = sessionManager.subscribe((event) => {
|
|
201
|
+
if (event.type === "session_closed") {
|
|
202
|
+
const shellSession = shellSessions.get(event.payload.clientSessionId);
|
|
203
|
+
if (shellSession) {
|
|
204
|
+
shellSession.kill();
|
|
205
|
+
shellSessions.delete(event.payload.clientSessionId);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
sendEvent(socket, event);
|
|
209
|
+
});
|
|
179
210
|
socket.on("message", async (raw) => {
|
|
180
211
|
try {
|
|
181
212
|
const message = JSON.parse(String(raw));
|
|
@@ -187,7 +218,25 @@ wss.on("connection", (socket, request) => {
|
|
|
187
218
|
});
|
|
188
219
|
break;
|
|
189
220
|
case "create_session":
|
|
190
|
-
await sessionManager.createSession(message.payload.workspacePath, message.payload.title, message.payload.allowSkipPermissions);
|
|
221
|
+
await sessionManager.createSession(message.payload.workspacePath, message.payload.title, message.payload.allowSkipPermissions, message.payload.engine ?? "cli");
|
|
222
|
+
break;
|
|
223
|
+
case "switch_engine":
|
|
224
|
+
await sessionManager.switchEngine(message.payload.clientSessionId, message.payload.engine);
|
|
225
|
+
break;
|
|
226
|
+
case "prompt":
|
|
227
|
+
await sessionManager.prompt(message.payload.clientSessionId, message.payload.text, message.payload.modeId, message.payload.images);
|
|
228
|
+
break;
|
|
229
|
+
case "set_mode":
|
|
230
|
+
await sessionManager.setSessionMode(message.payload.clientSessionId, message.payload.modeId);
|
|
231
|
+
break;
|
|
232
|
+
case "cancel":
|
|
233
|
+
await sessionManager.cancel(message.payload.clientSessionId);
|
|
234
|
+
break;
|
|
235
|
+
case "permission":
|
|
236
|
+
await sessionManager.resolvePermission(message.payload.clientSessionId, message.payload.requestId, message.payload.optionId, message.payload.note);
|
|
237
|
+
break;
|
|
238
|
+
case "answer_question":
|
|
239
|
+
await sessionManager.answerQuestion(message.payload.clientSessionId, message.payload.questionId, message.payload.answer);
|
|
191
240
|
break;
|
|
192
241
|
case "close_session":
|
|
193
242
|
await sessionManager.closeSession(message.payload.clientSessionId);
|
|
@@ -215,40 +264,44 @@ wss.on("connection", (socket, request) => {
|
|
|
215
264
|
if (!enableShell) {
|
|
216
265
|
throw new Error("Shell feature is disabled. Set LEDUO_ENABLE_SHELL=true to enable it.");
|
|
217
266
|
}
|
|
218
|
-
|
|
219
|
-
|
|
267
|
+
const clientSessionId = message.payload.clientSessionId;
|
|
268
|
+
const existingShell = shellSessions.get(clientSessionId);
|
|
220
269
|
const cols = Math.max(2, message.payload.cols);
|
|
221
270
|
const rows = Math.max(2, message.payload.rows);
|
|
222
|
-
|
|
271
|
+
if (existingShell?.alive) {
|
|
272
|
+
existingShell.resize(cols, rows);
|
|
273
|
+
break;
|
|
274
|
+
}
|
|
275
|
+
const shellWorkspacePath = sessionManager.getSessionWorkspacePath(clientSessionId);
|
|
223
276
|
const newShell = new ShellSession(shellWorkspacePath, cols, rows);
|
|
224
|
-
|
|
277
|
+
shellSessions.set(clientSessionId, newShell);
|
|
225
278
|
newShell.on("output", (data) => {
|
|
226
279
|
if (socket.readyState === WebSocket.OPEN) {
|
|
227
|
-
socket.send(JSON.stringify({ type: "shell_output", payload: { data } }));
|
|
280
|
+
socket.send(JSON.stringify({ type: "shell_output", payload: { clientSessionId, data } }));
|
|
228
281
|
}
|
|
229
282
|
});
|
|
230
283
|
newShell.on("exit", (exitCode) => {
|
|
231
|
-
if (
|
|
232
|
-
|
|
284
|
+
if (shellSessions.get(clientSessionId) === newShell) {
|
|
285
|
+
shellSessions.delete(clientSessionId);
|
|
233
286
|
}
|
|
234
287
|
if (socket.readyState === WebSocket.OPEN) {
|
|
235
|
-
socket.send(JSON.stringify({ type: "shell_exited", payload: { exitCode } }));
|
|
288
|
+
socket.send(JSON.stringify({ type: "shell_exited", payload: { clientSessionId, exitCode } }));
|
|
236
289
|
}
|
|
237
290
|
});
|
|
238
291
|
break;
|
|
239
292
|
}
|
|
240
293
|
case "shell_input":
|
|
241
|
-
if (!
|
|
294
|
+
if (!shellSessions.get(message.payload.clientSessionId)?.alive) {
|
|
242
295
|
throw new Error("Shell is not running");
|
|
243
296
|
}
|
|
244
|
-
|
|
297
|
+
shellSessions.get(message.payload.clientSessionId)?.write(message.payload.data);
|
|
245
298
|
break;
|
|
246
299
|
case "shell_resize":
|
|
247
|
-
|
|
300
|
+
shellSessions.get(message.payload.clientSessionId)?.resize(message.payload.cols, message.payload.rows);
|
|
248
301
|
break;
|
|
249
302
|
case "shell_stop":
|
|
250
|
-
|
|
251
|
-
|
|
303
|
+
shellSessions.get(message.payload.clientSessionId)?.kill();
|
|
304
|
+
shellSessions.delete(message.payload.clientSessionId);
|
|
252
305
|
break;
|
|
253
306
|
}
|
|
254
307
|
}
|
|
@@ -261,8 +314,10 @@ wss.on("connection", (socket, request) => {
|
|
|
261
314
|
});
|
|
262
315
|
socket.on("close", () => {
|
|
263
316
|
unsubscribe();
|
|
264
|
-
shellSession
|
|
265
|
-
|
|
317
|
+
for (const shellSession of shellSessions.values()) {
|
|
318
|
+
shellSession.kill();
|
|
319
|
+
}
|
|
320
|
+
shellSessions.clear();
|
|
266
321
|
});
|
|
267
322
|
});
|
|
268
323
|
const listenPort = await findAvailablePort(requestedPort, listenHost);
|
|
@@ -286,6 +341,7 @@ else {
|
|
|
286
341
|
console.log("Web UI is unavailable on this start because bundled assets are missing.");
|
|
287
342
|
}
|
|
288
343
|
console.log(`Access URL: http://${displayHost}:${accessPort}/?key=${accessKey}`);
|
|
344
|
+
console.log(`Shell feature: ${enableShell ? "enabled" : "disabled"}`);
|
|
289
345
|
function sendEvent(socket, event) {
|
|
290
346
|
if (socket.readyState !== WebSocket.OPEN) {
|
|
291
347
|
return;
|
|
@@ -301,3 +357,30 @@ async function hasReadableFile(filePath) {
|
|
|
301
357
|
return false;
|
|
302
358
|
}
|
|
303
359
|
}
|
|
360
|
+
function parseBooleanFlag(rawValue, defaultValue) {
|
|
361
|
+
if (rawValue == null || rawValue.trim() === "") {
|
|
362
|
+
return defaultValue;
|
|
363
|
+
}
|
|
364
|
+
const normalized = rawValue.trim().toLowerCase();
|
|
365
|
+
if (["1", "true", "yes", "on"].includes(normalized)) {
|
|
366
|
+
return true;
|
|
367
|
+
}
|
|
368
|
+
if (["0", "false", "no", "off"].includes(normalized)) {
|
|
369
|
+
return false;
|
|
370
|
+
}
|
|
371
|
+
return defaultValue;
|
|
372
|
+
}
|
|
373
|
+
function resolveAgentBinPath() {
|
|
374
|
+
if (process.env.LEDUO_PATROL_AGENT_BIN?.trim()) {
|
|
375
|
+
return process.env.LEDUO_PATROL_AGENT_BIN.trim();
|
|
376
|
+
}
|
|
377
|
+
const require = createRequire(import.meta.url);
|
|
378
|
+
try {
|
|
379
|
+
const pkgPath = require.resolve("@zed-industries/claude-code-acp/package.json");
|
|
380
|
+
const pkgDir = path.dirname(pkgPath);
|
|
381
|
+
return path.join(pkgDir, "dist", "index.js");
|
|
382
|
+
}
|
|
383
|
+
catch {
|
|
384
|
+
return undefined;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
import os from "node:os";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { access, mkdir, readFile, writeFile } from "node:fs/promises";
|
|
4
1
|
import readline from "node:readline/promises";
|
|
2
|
+
import { loadStartupPreferences, saveStartupPreferences } from "./startup-preferences.js";
|
|
5
3
|
const DEFAULT_MODE = "server";
|
|
6
|
-
const PREFS_FILE_PATH = path.join(os.homedir(), ".leduo-patrol", "launch-preferences.json");
|
|
7
4
|
export async function resolveBindMode(options = {}) {
|
|
8
5
|
const argv = options.argv ?? process.argv.slice(2);
|
|
9
6
|
const stdin = options.stdin ?? process.stdin;
|
|
@@ -41,7 +38,7 @@ function parseBindMode(raw) {
|
|
|
41
38
|
}
|
|
42
39
|
return null;
|
|
43
40
|
}
|
|
44
|
-
function readOptionValue(argv, optionName) {
|
|
41
|
+
export function readOptionValue(argv, optionName) {
|
|
45
42
|
for (let i = 0; i < argv.length; i += 1) {
|
|
46
43
|
const arg = argv[i];
|
|
47
44
|
if (arg === optionName) {
|
|
@@ -77,12 +74,8 @@ async function promptShouldRemember(stdin, stdout) {
|
|
|
77
74
|
}
|
|
78
75
|
}
|
|
79
76
|
async function loadRememberedMode() {
|
|
80
|
-
if (!(await isReadable(PREFS_FILE_PATH))) {
|
|
81
|
-
return null;
|
|
82
|
-
}
|
|
83
77
|
try {
|
|
84
|
-
const
|
|
85
|
-
const parsed = JSON.parse(raw);
|
|
78
|
+
const parsed = (await loadStartupPreferences());
|
|
86
79
|
return parseBindMode(parsed.bindMode ?? "");
|
|
87
80
|
}
|
|
88
81
|
catch {
|
|
@@ -90,18 +83,7 @@ async function loadRememberedMode() {
|
|
|
90
83
|
}
|
|
91
84
|
}
|
|
92
85
|
async function saveRememberedMode(mode) {
|
|
93
|
-
await
|
|
94
|
-
const payload = { bindMode: mode };
|
|
95
|
-
await writeFile(PREFS_FILE_PATH, JSON.stringify(payload, null, 2), "utf8");
|
|
96
|
-
}
|
|
97
|
-
async function isReadable(filePath) {
|
|
98
|
-
try {
|
|
99
|
-
await access(filePath);
|
|
100
|
-
return true;
|
|
101
|
-
}
|
|
102
|
-
catch {
|
|
103
|
-
return false;
|
|
104
|
-
}
|
|
86
|
+
await saveStartupPreferences({ bindMode: mode });
|
|
105
87
|
}
|
|
106
88
|
export const launchModeTestables = {
|
|
107
89
|
parseBindMode,
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { chmodSync, existsSync, statSync } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { createRequire } from "node:module";
|
|
4
|
+
const require = createRequire(import.meta.url);
|
|
5
|
+
export function ensureNodePtySpawnHelperExecutable() {
|
|
6
|
+
if (process.platform !== "darwin") {
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
const helperPath = resolveNodePtySpawnHelperPath();
|
|
10
|
+
if (!helperPath) {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
ensureExecutableBit(helperPath);
|
|
14
|
+
}
|
|
15
|
+
export function resolveNodePtySpawnHelperPath() {
|
|
16
|
+
const packageJsonPath = require.resolve("node-pty/package.json");
|
|
17
|
+
const packageRoot = path.dirname(packageJsonPath);
|
|
18
|
+
const helperPath = path.join(packageRoot, "prebuilds", `${process.platform}-${process.arch}`, "spawn-helper");
|
|
19
|
+
return existsSync(helperPath) ? helperPath : null;
|
|
20
|
+
}
|
|
21
|
+
export function ensureExecutableBit(filePath) {
|
|
22
|
+
const stats = statSync(filePath);
|
|
23
|
+
if ((stats.mode & 0o111) === 0o111) {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
chmodSync(filePath, stats.mode | 0o755);
|
|
27
|
+
return true;
|
|
28
|
+
}
|