@dev-anywhere/proxy 0.2.3 → 0.2.5
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/dist/{chunk-ZUWAB67J.js → chunk-IHUQNJF6.js} +7 -2
- package/dist/chunk-IHUQNJF6.js.map +1 -0
- package/dist/{chunk-NZZXBVO2.js → chunk-L6J5QCFH.js} +1 -1
- package/dist/chunk-L6J5QCFH.js.map +1 -0
- package/dist/{chunk-OBYEKZWC.js → chunk-Q7AQFYHG.js} +1 -1
- package/dist/chunk-Q7AQFYHG.js.map +1 -0
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/dist/serve.js +88 -217
- package/dist/serve.js.map +1 -1
- package/dist/session-worker.js +1 -1
- package/dist/{terminal-YGYIRO7H.js → terminal-THJIKZQG.js} +9 -16
- package/dist/terminal-THJIKZQG.js.map +1 -0
- package/package.json +3 -3
- package/dist/chunk-NZZXBVO2.js.map +0 -1
- package/dist/chunk-OBYEKZWC.js.map +0 -1
- package/dist/chunk-ZUWAB67J.js.map +0 -1
- package/dist/terminal-YGYIRO7H.js.map +0 -1
package/dist/serve.js
CHANGED
|
@@ -11,10 +11,10 @@ import {
|
|
|
11
11
|
decidePtySemanticTransition,
|
|
12
12
|
extractOscSequences,
|
|
13
13
|
extractOscSignals
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-Q7AQFYHG.js";
|
|
15
15
|
import {
|
|
16
16
|
spawnScript
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-IHUQNJF6.js";
|
|
18
18
|
import {
|
|
19
19
|
CLAUDE_PROVIDER,
|
|
20
20
|
CODEX_PROVIDER,
|
|
@@ -35,7 +35,7 @@ import {
|
|
|
35
35
|
serializeControl,
|
|
36
36
|
serializeIpc,
|
|
37
37
|
serializeWorkerMsg
|
|
38
|
-
} from "./chunk-
|
|
38
|
+
} from "./chunk-L6J5QCFH.js";
|
|
39
39
|
import {
|
|
40
40
|
buildProviderEnv,
|
|
41
41
|
loadConfig,
|
|
@@ -968,7 +968,7 @@ function extractConversationText(msg) {
|
|
|
968
968
|
return null;
|
|
969
969
|
}
|
|
970
970
|
async function extractTitleAndCwd(filePath) {
|
|
971
|
-
return new Promise((
|
|
971
|
+
return new Promise((resolve3) => {
|
|
972
972
|
const rl = createInterface({
|
|
973
973
|
input: createReadStream(filePath, { encoding: "utf-8" }),
|
|
974
974
|
crlfDelay: Infinity
|
|
@@ -996,10 +996,10 @@ async function extractTitleAndCwd(filePath) {
|
|
|
996
996
|
}
|
|
997
997
|
});
|
|
998
998
|
rl.on("close", () => {
|
|
999
|
-
if (!resolved)
|
|
1000
|
-
else
|
|
999
|
+
if (!resolved) resolve3({ title, cwd });
|
|
1000
|
+
else resolve3({ title, cwd });
|
|
1001
1001
|
});
|
|
1002
|
-
rl.on("error", () =>
|
|
1002
|
+
rl.on("error", () => resolve3({ title, cwd }));
|
|
1003
1003
|
});
|
|
1004
1004
|
}
|
|
1005
1005
|
async function collectJsonlFiles(root) {
|
|
@@ -1021,7 +1021,7 @@ async function collectJsonlFiles(root) {
|
|
|
1021
1021
|
return files;
|
|
1022
1022
|
}
|
|
1023
1023
|
async function extractCodexTitleAndCwd(filePath) {
|
|
1024
|
-
return new Promise((
|
|
1024
|
+
return new Promise((resolve3) => {
|
|
1025
1025
|
const rl = createInterface({
|
|
1026
1026
|
input: createReadStream(filePath, { encoding: "utf-8" }),
|
|
1027
1027
|
crlfDelay: Infinity
|
|
@@ -1045,8 +1045,8 @@ async function extractCodexTitleAndCwd(filePath) {
|
|
|
1045
1045
|
} catch {
|
|
1046
1046
|
}
|
|
1047
1047
|
});
|
|
1048
|
-
rl.on("close", () =>
|
|
1049
|
-
rl.on("error", () =>
|
|
1048
|
+
rl.on("close", () => resolve3({ id, title, cwd }));
|
|
1049
|
+
rl.on("error", () => resolve3({ id, title, cwd }));
|
|
1050
1050
|
});
|
|
1051
1051
|
}
|
|
1052
1052
|
function extractCodexUserText(payload) {
|
|
@@ -1598,7 +1598,7 @@ var WorkerRegistry = class {
|
|
|
1598
1598
|
}
|
|
1599
1599
|
args.push("--");
|
|
1600
1600
|
const providerEnv = this.deps.getProviderEnv();
|
|
1601
|
-
const child = spawnScript(
|
|
1601
|
+
const child = spawnScript("session-worker", args, {
|
|
1602
1602
|
logger: serviceLogger,
|
|
1603
1603
|
env: options?.hook ? { ...providerEnv, DEV_ANYWHERE_HOOK_TOKEN: options.hook.token } : providerEnv
|
|
1604
1604
|
});
|
|
@@ -1611,7 +1611,7 @@ var WorkerRegistry = class {
|
|
|
1611
1611
|
return workerPid;
|
|
1612
1612
|
}
|
|
1613
1613
|
connect(sessionId, sockPath) {
|
|
1614
|
-
return new Promise((
|
|
1614
|
+
return new Promise((resolve3) => {
|
|
1615
1615
|
const sock = connect(sockPath);
|
|
1616
1616
|
sock.on("connect", () => {
|
|
1617
1617
|
this.sockets.set(sessionId, sock);
|
|
@@ -1627,9 +1627,9 @@ var WorkerRegistry = class {
|
|
|
1627
1627
|
);
|
|
1628
1628
|
sock.on("close", () => this.onDisconnect(sessionId));
|
|
1629
1629
|
sock.on("error", () => this.onDisconnect(sessionId));
|
|
1630
|
-
|
|
1630
|
+
resolve3(sock);
|
|
1631
1631
|
});
|
|
1632
|
-
sock.on("error", () =>
|
|
1632
|
+
sock.on("error", () => resolve3(null));
|
|
1633
1633
|
});
|
|
1634
1634
|
}
|
|
1635
1635
|
// 枚举 DATA_DIR 下所有 session 目录,尝试连接存活的 worker.sock;失败则清理 stale socket。
|
|
@@ -1959,9 +1959,11 @@ function terminateSessionByOwnership(deps, sessionId) {
|
|
|
1959
1959
|
}
|
|
1960
1960
|
|
|
1961
1961
|
// src/serve/clipboard-image-upload.ts
|
|
1962
|
-
import {
|
|
1963
|
-
import {
|
|
1962
|
+
import { mkdirSync, writeFileSync } from "fs";
|
|
1963
|
+
import { tmpdir } from "os";
|
|
1964
|
+
import { join as join5 } from "path";
|
|
1964
1965
|
import { nanoid as nanoid3 } from "nanoid";
|
|
1966
|
+
var DEFAULT_DATA_DIR = join5(tmpdir(), "dev-anywhere");
|
|
1965
1967
|
var MAX_CLIPBOARD_IMAGE_BYTES = 10 * 1024 * 1024;
|
|
1966
1968
|
var MAX_CLIPBOARD_IMAGE_BASE64_LENGTH = Math.ceil(MAX_CLIPBOARD_IMAGE_BYTES / 3) * 4;
|
|
1967
1969
|
var IMAGE_EXTENSIONS = /* @__PURE__ */ new Map([
|
|
@@ -1970,10 +1972,6 @@ var IMAGE_EXTENSIONS = /* @__PURE__ */ new Map([
|
|
|
1970
1972
|
["image/webp", "webp"],
|
|
1971
1973
|
["image/gif", "gif"]
|
|
1972
1974
|
]);
|
|
1973
|
-
function formatTimestamp(ms) {
|
|
1974
|
-
const [date, time = "000000"] = new Date(ms).toISOString().replace(/\.\d{3}Z$/, "").split("T");
|
|
1975
|
-
return `${date.replace(/-/g, "")}-${time.replace(/:/g, "")}`;
|
|
1976
|
-
}
|
|
1977
1975
|
function normalizeBase64(input) {
|
|
1978
1976
|
return input.replace(/^data:[^;]+;base64,/i, "").replace(/\s/g, "");
|
|
1979
1977
|
}
|
|
@@ -1992,54 +1990,6 @@ function decodeBase64Image(dataBase64) {
|
|
|
1992
1990
|
}
|
|
1993
1991
|
return buffer;
|
|
1994
1992
|
}
|
|
1995
|
-
function resolveChildDir(rootPath, ...segments) {
|
|
1996
|
-
const root = resolve(rootPath);
|
|
1997
|
-
const uploadDir = resolve(root, ...segments);
|
|
1998
|
-
const relativePath = relative(root, uploadDir);
|
|
1999
|
-
if (!relativePath || relativePath.startsWith("..") || isAbsolute2(relativePath)) {
|
|
2000
|
-
throw new Error("\u4F1A\u8BDD\u8DEF\u5F84\u65E0\u6548");
|
|
2001
|
-
}
|
|
2002
|
-
return uploadDir;
|
|
2003
|
-
}
|
|
2004
|
-
function resolveSessionClipboardDir(dataDir, sessionId) {
|
|
2005
|
-
return resolveChildDir(dataDir, sessionId, "clipboard");
|
|
2006
|
-
}
|
|
2007
|
-
function normalizeGitignoreLine(line) {
|
|
2008
|
-
return line.trim().replace(/^\/+/, "").replace(/\/+$/, "");
|
|
2009
|
-
}
|
|
2010
|
-
function ensureProjectClipboardIgnored(cwd) {
|
|
2011
|
-
const gitignorePath = join5(cwd, ".gitignore");
|
|
2012
|
-
if (!existsSync4(gitignorePath)) return;
|
|
2013
|
-
try {
|
|
2014
|
-
const current = readFileSync4(gitignorePath, "utf-8");
|
|
2015
|
-
const alreadyIgnored = current.split(/\r?\n/).some((line) => normalizeGitignoreLine(line) === ".dev-anywhere");
|
|
2016
|
-
if (alreadyIgnored) return;
|
|
2017
|
-
const separator = current.length > 0 && !current.endsWith("\n") ? "\n" : "";
|
|
2018
|
-
writeFileSync(gitignorePath, `${current}${separator}.dev-anywhere/
|
|
2019
|
-
`);
|
|
2020
|
-
} catch {
|
|
2021
|
-
}
|
|
2022
|
-
}
|
|
2023
|
-
function trySaveProjectClipboardImage(options) {
|
|
2024
|
-
if (!options.cwd) return null;
|
|
2025
|
-
try {
|
|
2026
|
-
const cwd = resolve(options.cwd);
|
|
2027
|
-
if (!statSync(cwd).isDirectory()) return null;
|
|
2028
|
-
const clipboardRoot = resolve(cwd, ".dev-anywhere", "clipboard");
|
|
2029
|
-
const uploadDir = resolveChildDir(clipboardRoot, options.sessionId);
|
|
2030
|
-
const path = join5(uploadDir, options.fileName);
|
|
2031
|
-
mkdirSync(uploadDir, { recursive: true });
|
|
2032
|
-
writeFileSync(path, options.buffer, { mode: 384 });
|
|
2033
|
-
ensureProjectClipboardIgnored(cwd);
|
|
2034
|
-
return { success: true, path: relative(cwd, path) };
|
|
2035
|
-
} catch (err) {
|
|
2036
|
-
serviceLogger.warn(
|
|
2037
|
-
{ sessionId: options.sessionId, cwd: options.cwd, error: String(err) },
|
|
2038
|
-
"Project clipboard image write failed; falling back to data dir"
|
|
2039
|
-
);
|
|
2040
|
-
return null;
|
|
2041
|
-
}
|
|
2042
|
-
}
|
|
2043
1993
|
function saveClipboardImageUpload(request, options = {}) {
|
|
2044
1994
|
const extension = IMAGE_EXTENSIONS.get(request.mimeType);
|
|
2045
1995
|
if (!extension) {
|
|
@@ -2051,20 +2001,11 @@ function saveClipboardImageUpload(request, options = {}) {
|
|
|
2051
2001
|
}
|
|
2052
2002
|
try {
|
|
2053
2003
|
const buffer = decodeBase64Image(request.dataBase64);
|
|
2054
|
-
const now = options.now ?? Date.now;
|
|
2055
2004
|
const suffix = options.randomSuffix?.() ?? nanoid3(6);
|
|
2056
|
-
const fileName = `
|
|
2057
|
-
const
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
fileName,
|
|
2061
|
-
buffer
|
|
2062
|
-
});
|
|
2063
|
-
if (projectResult) return projectResult;
|
|
2064
|
-
const dataDir = options.dataDir ?? DATA_DIR;
|
|
2065
|
-
const uploadDir = resolveSessionClipboardDir(dataDir, request.sessionId);
|
|
2066
|
-
const path = join5(uploadDir, fileName);
|
|
2067
|
-
mkdirSync(uploadDir, { recursive: true });
|
|
2005
|
+
const fileName = `paste-${suffix}.${extension}`;
|
|
2006
|
+
const dataDir = options.dataDir ?? DEFAULT_DATA_DIR;
|
|
2007
|
+
const path = join5(dataDir, fileName);
|
|
2008
|
+
mkdirSync(dataDir, { recursive: true });
|
|
2068
2009
|
writeFileSync(path, buffer, { mode: 384 });
|
|
2069
2010
|
return { success: true, path };
|
|
2070
2011
|
} catch (err) {
|
|
@@ -2077,8 +2018,8 @@ function saveClipboardImageUpload(request, options = {}) {
|
|
|
2077
2018
|
}
|
|
2078
2019
|
|
|
2079
2020
|
// src/serve/file-download.ts
|
|
2080
|
-
import { readFileSync as
|
|
2081
|
-
import { extname, isAbsolute as
|
|
2021
|
+
import { readFileSync as readFileSync4, realpathSync, statSync } from "fs";
|
|
2022
|
+
import { extname, isAbsolute as isAbsolute2, resolve } from "path";
|
|
2082
2023
|
var MAX_FILE_DOWNLOAD_BYTES = 100 * 1024 * 1024;
|
|
2083
2024
|
var EXT_MIME_MAP = {
|
|
2084
2025
|
".png": "image/png",
|
|
@@ -2113,7 +2054,7 @@ function guessMimeType(filePath) {
|
|
|
2113
2054
|
return EXT_MIME_MAP[ext] ?? "application/octet-stream";
|
|
2114
2055
|
}
|
|
2115
2056
|
function resolveDownloadPath(rawPath, cwd) {
|
|
2116
|
-
const candidate =
|
|
2057
|
+
const candidate = isAbsolute2(rawPath) ? resolve(rawPath) : resolve(cwd, rawPath);
|
|
2117
2058
|
return realpathSync(candidate);
|
|
2118
2059
|
}
|
|
2119
2060
|
function errorCode(err) {
|
|
@@ -2125,7 +2066,7 @@ function errorCode(err) {
|
|
|
2125
2066
|
function loadFileDownload(request, options) {
|
|
2126
2067
|
try {
|
|
2127
2068
|
const resolvedPath = resolveDownloadPath(request.path, options.cwd);
|
|
2128
|
-
const stat2 =
|
|
2069
|
+
const stat2 = statSync(resolvedPath);
|
|
2129
2070
|
if (!stat2.isFile()) {
|
|
2130
2071
|
return {
|
|
2131
2072
|
success: false,
|
|
@@ -2145,7 +2086,7 @@ function loadFileDownload(request, options) {
|
|
|
2145
2086
|
errorCode: ControlErrorCode.UNKNOWN
|
|
2146
2087
|
};
|
|
2147
2088
|
}
|
|
2148
|
-
const buffer =
|
|
2089
|
+
const buffer = readFileSync4(resolvedPath);
|
|
2149
2090
|
return {
|
|
2150
2091
|
success: true,
|
|
2151
2092
|
sessionId: request.sessionId,
|
|
@@ -2166,12 +2107,14 @@ function loadFileDownload(request, options) {
|
|
|
2166
2107
|
}
|
|
2167
2108
|
|
|
2168
2109
|
// src/serve/file-upload.ts
|
|
2169
|
-
import {
|
|
2170
|
-
import {
|
|
2110
|
+
import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
2111
|
+
import { tmpdir as tmpdir2 } from "os";
|
|
2112
|
+
import { extname as extname2, join as join6 } from "path";
|
|
2171
2113
|
import { nanoid as nanoid4 } from "nanoid";
|
|
2114
|
+
var DEFAULT_DATA_DIR2 = join6(tmpdir2(), "dev-anywhere");
|
|
2172
2115
|
var MAX_FILE_UPLOAD_BYTES = 100 * 1024 * 1024;
|
|
2173
2116
|
var MAX_FILE_UPLOAD_BASE64_LENGTH = Math.ceil(MAX_FILE_UPLOAD_BYTES / 3) * 4;
|
|
2174
|
-
var
|
|
2117
|
+
var SAFE_EXT_RE = /^[A-Za-z0-9]{1,6}$/;
|
|
2175
2118
|
function normalizeBase642(input) {
|
|
2176
2119
|
return input.replace(/^data:[^;]+;base64,/i, "").replace(/\s/g, "");
|
|
2177
2120
|
}
|
|
@@ -2190,76 +2133,18 @@ function decodeBase64File(dataBase64) {
|
|
|
2190
2133
|
}
|
|
2191
2134
|
return buffer;
|
|
2192
2135
|
}
|
|
2193
|
-
function
|
|
2194
|
-
const
|
|
2195
|
-
|
|
2196
|
-
const extMatch = base.match(/\.([A-Za-z0-9]{1,6})$/);
|
|
2197
|
-
const ext = extMatch ? `.${extMatch[1]}` : "";
|
|
2198
|
-
return `${fallbackPrefix}-${suffix}${ext}`;
|
|
2199
|
-
}
|
|
2200
|
-
function resolveChildDir2(rootPath, ...segments) {
|
|
2201
|
-
const root = resolve3(rootPath);
|
|
2202
|
-
const target = resolve3(root, ...segments);
|
|
2203
|
-
const rel = relative2(root, target);
|
|
2204
|
-
if (!rel || rel.startsWith("..") || isAbsolute4(rel)) {
|
|
2205
|
-
throw new Error("\u4F1A\u8BDD\u8DEF\u5F84\u65E0\u6548");
|
|
2206
|
-
}
|
|
2207
|
-
return target;
|
|
2208
|
-
}
|
|
2209
|
-
function normalizeGitignoreLine2(line) {
|
|
2210
|
-
return line.trim().replace(/^\/+/, "").replace(/\/+$/, "");
|
|
2211
|
-
}
|
|
2212
|
-
function ensureProjectUploadIgnored(cwd) {
|
|
2213
|
-
const gitignorePath = join6(cwd, ".gitignore");
|
|
2214
|
-
if (!existsSync5(gitignorePath)) return;
|
|
2215
|
-
try {
|
|
2216
|
-
const current = readFileSync6(gitignorePath, "utf-8");
|
|
2217
|
-
const alreadyIgnored = current.split(/\r?\n/).some((line) => normalizeGitignoreLine2(line) === ".dev-anywhere");
|
|
2218
|
-
if (alreadyIgnored) return;
|
|
2219
|
-
const separator = current.length > 0 && !current.endsWith("\n") ? "\n" : "";
|
|
2220
|
-
writeFileSync2(gitignorePath, `${current}${separator}.dev-anywhere/
|
|
2221
|
-
`);
|
|
2222
|
-
} catch {
|
|
2223
|
-
}
|
|
2224
|
-
}
|
|
2225
|
-
function trySaveProjectUpload(options) {
|
|
2226
|
-
if (!options.cwd) return null;
|
|
2227
|
-
try {
|
|
2228
|
-
const cwd = resolve3(options.cwd);
|
|
2229
|
-
if (!statSync3(cwd).isDirectory()) return null;
|
|
2230
|
-
const uploadsRoot = resolve3(cwd, ".dev-anywhere", "uploads");
|
|
2231
|
-
const uploadDir = resolveChildDir2(uploadsRoot, options.sessionId);
|
|
2232
|
-
const path = join6(uploadDir, options.fileName);
|
|
2233
|
-
mkdirSync2(uploadDir, { recursive: true });
|
|
2234
|
-
writeFileSync2(path, options.buffer, { mode: 384 });
|
|
2235
|
-
ensureProjectUploadIgnored(cwd);
|
|
2236
|
-
return { success: true, path: relative2(cwd, path) };
|
|
2237
|
-
} catch (err) {
|
|
2238
|
-
serviceLogger.warn(
|
|
2239
|
-
{ sessionId: options.sessionId, cwd: options.cwd, error: String(err) },
|
|
2240
|
-
"Project upload write failed; falling back to data dir"
|
|
2241
|
-
);
|
|
2242
|
-
return null;
|
|
2243
|
-
}
|
|
2136
|
+
function safeExtension(fileName) {
|
|
2137
|
+
const raw = extname2(fileName).slice(1).toLowerCase();
|
|
2138
|
+
return SAFE_EXT_RE.test(raw) ? `.${raw}` : "";
|
|
2244
2139
|
}
|
|
2245
2140
|
async function saveFileUpload(request, options = {}) {
|
|
2246
2141
|
try {
|
|
2247
2142
|
const buffer = decodeBase64File(request.dataBase64);
|
|
2248
|
-
const now = options.now ?? Date.now;
|
|
2249
2143
|
const suffix = options.randomSuffix?.() ?? nanoid4(6);
|
|
2250
|
-
const
|
|
2251
|
-
const
|
|
2252
|
-
const
|
|
2253
|
-
|
|
2254
|
-
sessionId: request.sessionId,
|
|
2255
|
-
fileName,
|
|
2256
|
-
buffer
|
|
2257
|
-
});
|
|
2258
|
-
if (projectResult) return projectResult;
|
|
2259
|
-
const dataDir = options.dataDir ?? DATA_DIR;
|
|
2260
|
-
const uploadDir = resolveChildDir2(dataDir, request.sessionId, "uploads");
|
|
2261
|
-
const path = join6(uploadDir, fileName);
|
|
2262
|
-
mkdirSync2(uploadDir, { recursive: true });
|
|
2144
|
+
const fileName = `up-${suffix}${safeExtension(request.fileName)}`;
|
|
2145
|
+
const dataDir = options.dataDir ?? DEFAULT_DATA_DIR2;
|
|
2146
|
+
const path = join6(dataDir, fileName);
|
|
2147
|
+
mkdirSync2(dataDir, { recursive: true });
|
|
2263
2148
|
writeFileSync2(path, buffer, { mode: 384 });
|
|
2264
2149
|
return { success: true, path };
|
|
2265
2150
|
} catch (err) {
|
|
@@ -2272,16 +2157,16 @@ async function saveFileUpload(request, options = {}) {
|
|
|
2272
2157
|
}
|
|
2273
2158
|
|
|
2274
2159
|
// src/serve/image-preview.ts
|
|
2275
|
-
import { readFileSync as
|
|
2276
|
-
import { tmpdir } from "os";
|
|
2277
|
-
import { isAbsolute as
|
|
2160
|
+
import { readFileSync as readFileSync5, realpathSync as realpathSync2, statSync as statSync2 } from "fs";
|
|
2161
|
+
import { tmpdir as tmpdir3 } from "os";
|
|
2162
|
+
import { isAbsolute as isAbsolute3, relative, resolve as resolve2 } from "path";
|
|
2278
2163
|
var MAX_IMAGE_PREVIEW_BYTES = 10 * 1024 * 1024;
|
|
2279
2164
|
function isInsideRoot(realFilePath, realRootPath) {
|
|
2280
|
-
const rel =
|
|
2281
|
-
return rel === "" || !rel.startsWith("..") && !
|
|
2165
|
+
const rel = relative(realRootPath, realFilePath);
|
|
2166
|
+
return rel === "" || !rel.startsWith("..") && !isAbsolute3(rel);
|
|
2282
2167
|
}
|
|
2283
2168
|
function allowedRoots(options) {
|
|
2284
|
-
return [options.cwd, options.tmpDir ??
|
|
2169
|
+
return [options.cwd, options.tmpDir ?? tmpdir3(), ...options.previewRoots ?? []].map((root) => root.trim()).filter(Boolean).flatMap((root) => {
|
|
2285
2170
|
try {
|
|
2286
2171
|
return [realpathSync2(root)];
|
|
2287
2172
|
} catch {
|
|
@@ -2290,7 +2175,7 @@ function allowedRoots(options) {
|
|
|
2290
2175
|
});
|
|
2291
2176
|
}
|
|
2292
2177
|
function resolvePreviewPath(rawPath, options) {
|
|
2293
|
-
const candidate =
|
|
2178
|
+
const candidate = isAbsolute3(rawPath) ? resolve2(rawPath) : resolve2(options.cwd, rawPath);
|
|
2294
2179
|
const realCandidate = realpathSync2(candidate);
|
|
2295
2180
|
if (!allowedRoots(options).some((root) => isInsideRoot(realCandidate, root))) {
|
|
2296
2181
|
throw Object.assign(new Error("\u56FE\u7247\u8DEF\u5F84\u4E0D\u5728\u5141\u8BB8\u9884\u89C8\u7684\u76EE\u5F55\u5185"), {
|
|
@@ -2323,7 +2208,7 @@ function errorCode2(err) {
|
|
|
2323
2208
|
function loadImagePreview(request, options) {
|
|
2324
2209
|
try {
|
|
2325
2210
|
const resolvedPath = resolvePreviewPath(request.path, options);
|
|
2326
|
-
const stat2 =
|
|
2211
|
+
const stat2 = statSync2(resolvedPath);
|
|
2327
2212
|
if (!stat2.isFile()) {
|
|
2328
2213
|
return {
|
|
2329
2214
|
success: false,
|
|
@@ -2343,7 +2228,7 @@ function loadImagePreview(request, options) {
|
|
|
2343
2228
|
errorCode: ControlErrorCode.UNKNOWN
|
|
2344
2229
|
};
|
|
2345
2230
|
}
|
|
2346
|
-
const buffer =
|
|
2231
|
+
const buffer = readFileSync5(resolvedPath);
|
|
2347
2232
|
const mimeType = detectImageMime(buffer);
|
|
2348
2233
|
if (!mimeType) {
|
|
2349
2234
|
return {
|
|
@@ -2444,8 +2329,7 @@ var RelayInputHandlers = class {
|
|
|
2444
2329
|
onClipboardImageUpload(msg) {
|
|
2445
2330
|
const { sessionId, requestId } = msg;
|
|
2446
2331
|
if (!sessionId) return;
|
|
2447
|
-
|
|
2448
|
-
if (!session) {
|
|
2332
|
+
if (!this.deps.sessionManager.getSession(sessionId)) {
|
|
2449
2333
|
this.deps.relayConnection.sendRaw(
|
|
2450
2334
|
serializeControl({
|
|
2451
2335
|
type: "clipboard_image_upload_response",
|
|
@@ -2459,17 +2343,12 @@ var RelayInputHandlers = class {
|
|
|
2459
2343
|
serviceLogger.warn({ sessionId }, "Clipboard image upload rejected: session not found");
|
|
2460
2344
|
return;
|
|
2461
2345
|
}
|
|
2462
|
-
const result = saveClipboardImageUpload(
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
},
|
|
2469
|
-
{
|
|
2470
|
-
cwd: session.cwd
|
|
2471
|
-
}
|
|
2472
|
-
);
|
|
2346
|
+
const result = saveClipboardImageUpload({
|
|
2347
|
+
sessionId,
|
|
2348
|
+
mimeType: msg.mimeType,
|
|
2349
|
+
dataBase64: msg.dataBase64,
|
|
2350
|
+
fileName: msg.fileName
|
|
2351
|
+
});
|
|
2473
2352
|
this.deps.relayConnection.sendRaw(
|
|
2474
2353
|
serializeControl({
|
|
2475
2354
|
type: "clipboard_image_upload_response",
|
|
@@ -2550,10 +2429,7 @@ var RelayInputHandlers = class {
|
|
|
2550
2429
|
})
|
|
2551
2430
|
);
|
|
2552
2431
|
if (result.success) {
|
|
2553
|
-
serviceLogger.info(
|
|
2554
|
-
{ sessionId, path, size: result.size },
|
|
2555
|
-
"File download handled"
|
|
2556
|
-
);
|
|
2432
|
+
serviceLogger.info({ sessionId, path, size: result.size }, "File download handled");
|
|
2557
2433
|
} else {
|
|
2558
2434
|
serviceLogger.warn(
|
|
2559
2435
|
{ sessionId, path, errorCode: result.errorCode, error: result.error },
|
|
@@ -2564,8 +2440,7 @@ var RelayInputHandlers = class {
|
|
|
2564
2440
|
async onFileUploadRequest(msg) {
|
|
2565
2441
|
const { sessionId, requestId, mimeType, dataBase64, fileName } = msg;
|
|
2566
2442
|
if (!sessionId) return;
|
|
2567
|
-
|
|
2568
|
-
if (!session) {
|
|
2443
|
+
if (!this.deps.sessionManager.getSession(sessionId)) {
|
|
2569
2444
|
this.deps.relayConnection.sendRaw(
|
|
2570
2445
|
serializeControl({
|
|
2571
2446
|
type: "file_upload_response",
|
|
@@ -2579,10 +2454,7 @@ var RelayInputHandlers = class {
|
|
|
2579
2454
|
serviceLogger.warn({ sessionId }, "File upload rejected: session not found");
|
|
2580
2455
|
return;
|
|
2581
2456
|
}
|
|
2582
|
-
const result = await saveFileUpload(
|
|
2583
|
-
{ sessionId, mimeType, dataBase64, fileName },
|
|
2584
|
-
{ cwd: session.cwd }
|
|
2585
|
-
);
|
|
2457
|
+
const result = await saveFileUpload({ sessionId, mimeType, dataBase64, fileName });
|
|
2586
2458
|
this.deps.relayConnection.sendRaw(
|
|
2587
2459
|
serializeControl({
|
|
2588
2460
|
type: "file_upload_response",
|
|
@@ -2793,14 +2665,14 @@ var RelayPermissionHandlers = class {
|
|
|
2793
2665
|
|
|
2794
2666
|
// src/serve/relay-resource-handlers.ts
|
|
2795
2667
|
import { homedir as homedir4 } from "os";
|
|
2796
|
-
import { accessSync, constants, statSync as
|
|
2668
|
+
import { accessSync, constants, statSync as statSync3 } from "fs";
|
|
2797
2669
|
function errorMessage(err) {
|
|
2798
2670
|
return err instanceof Error ? err.message : String(err);
|
|
2799
2671
|
}
|
|
2800
2672
|
function validateExecutablePath(path) {
|
|
2801
2673
|
const normalized = path.trim();
|
|
2802
2674
|
if (!normalized.startsWith("/")) throw new Error("CLI \u8DEF\u5F84\u5FC5\u987B\u662F\u7EDD\u5BF9\u8DEF\u5F84");
|
|
2803
|
-
const stat2 =
|
|
2675
|
+
const stat2 = statSync3(normalized);
|
|
2804
2676
|
if (!stat2.isFile()) throw new Error("CLI \u8DEF\u5F84\u4E0D\u662F\u53EF\u6267\u884C\u6587\u4EF6");
|
|
2805
2677
|
accessSync(normalized, constants.X_OK);
|
|
2806
2678
|
return normalized;
|
|
@@ -2908,8 +2780,8 @@ var RelayResourceHandlers = class {
|
|
|
2908
2780
|
};
|
|
2909
2781
|
|
|
2910
2782
|
// src/serve/relay-session-create-handler.ts
|
|
2911
|
-
import { rmSync, statSync as
|
|
2912
|
-
import { isAbsolute as
|
|
2783
|
+
import { rmSync, statSync as statSync4 } from "fs";
|
|
2784
|
+
import { isAbsolute as isAbsolute4 } from "path";
|
|
2913
2785
|
import { nanoid as nanoid5 } from "nanoid";
|
|
2914
2786
|
|
|
2915
2787
|
// src/serve/hosted-pty-registry.ts
|
|
@@ -3161,11 +3033,11 @@ function validateSessionCwd(cwd) {
|
|
|
3161
3033
|
return { message: "\u8BF7\u8F93\u5165\u5DE5\u4F5C\u76EE\u5F55", code: ControlErrorCode.INVALID_PATH };
|
|
3162
3034
|
}
|
|
3163
3035
|
const trimmed = cwd.trim();
|
|
3164
|
-
if (!
|
|
3036
|
+
if (!isAbsolute4(trimmed)) {
|
|
3165
3037
|
return { message: "\u5DE5\u4F5C\u76EE\u5F55\u5FC5\u987B\u662F\u7EDD\u5BF9\u8DEF\u5F84", code: ControlErrorCode.INVALID_PATH };
|
|
3166
3038
|
}
|
|
3167
3039
|
try {
|
|
3168
|
-
const stat2 =
|
|
3040
|
+
const stat2 = statSync4(trimmed);
|
|
3169
3041
|
return stat2.isDirectory() ? null : { message: "\u5DE5\u4F5C\u76EE\u5F55\u4E0D\u662F\u76EE\u5F55", code: ControlErrorCode.PATH_NOT_DIRECTORY };
|
|
3170
3042
|
} catch (err) {
|
|
3171
3043
|
return {
|
|
@@ -3584,9 +3456,7 @@ var RelayRouter = class {
|
|
|
3584
3456
|
if (sid) {
|
|
3585
3457
|
const status = this.deps.agentStatusRegistry.get(sid);
|
|
3586
3458
|
const statuses2 = status && this.deps.sessionManager.getSession(sid) ? [{ sessionId: sid, payload: status }] : [];
|
|
3587
|
-
this.deps.relaySend(
|
|
3588
|
-
serializeControl({ type: "agent_status_response", requestId, statuses: statuses2 })
|
|
3589
|
-
);
|
|
3459
|
+
this.deps.relaySend(serializeControl({ type: "agent_status_response", requestId, statuses: statuses2 }));
|
|
3590
3460
|
serviceLogger.info({ sessionId: sid, count: statuses2.length }, "Agent status snapshot sent");
|
|
3591
3461
|
return;
|
|
3592
3462
|
}
|
|
@@ -3595,9 +3465,7 @@ var RelayRouter = class {
|
|
|
3595
3465
|
if (!this.deps.sessionManager.getSession(sessionId)) continue;
|
|
3596
3466
|
statuses.push({ sessionId, payload: status });
|
|
3597
3467
|
}
|
|
3598
|
-
this.deps.relaySend(
|
|
3599
|
-
serializeControl({ type: "agent_status_response", requestId, statuses })
|
|
3600
|
-
);
|
|
3468
|
+
this.deps.relaySend(serializeControl({ type: "agent_status_response", requestId, statuses }));
|
|
3601
3469
|
serviceLogger.info({ count: statuses.length }, "Agent status snapshot sent");
|
|
3602
3470
|
}
|
|
3603
3471
|
onSessionTerminate(msg) {
|
|
@@ -3762,11 +3630,11 @@ var PermissionBroker = class {
|
|
|
3762
3630
|
if (this.pending.has(request.requestId)) {
|
|
3763
3631
|
return Promise.resolve(DUPLICATE_DECISION);
|
|
3764
3632
|
}
|
|
3765
|
-
return new Promise((
|
|
3633
|
+
return new Promise((resolve3) => {
|
|
3766
3634
|
this.pending.set(request.requestId, {
|
|
3767
3635
|
...request,
|
|
3768
3636
|
source: "hook",
|
|
3769
|
-
resolve:
|
|
3637
|
+
resolve: resolve3,
|
|
3770
3638
|
createdAt: Date.now()
|
|
3771
3639
|
});
|
|
3772
3640
|
});
|
|
@@ -4142,14 +4010,14 @@ function createEventBridge(deps) {
|
|
|
4142
4010
|
|
|
4143
4011
|
// src/serve/service-files.ts
|
|
4144
4012
|
import { execSync } from "child_process";
|
|
4145
|
-
import { existsSync as
|
|
4013
|
+
import { existsSync as existsSync4, readFileSync as readFileSync6, unlinkSync as unlinkSync2 } from "fs";
|
|
4146
4014
|
import { hostname } from "os";
|
|
4147
4015
|
import { connect as connect2 } from "net";
|
|
4148
4016
|
function tryConnectSocket(sockPath) {
|
|
4149
|
-
return new Promise((
|
|
4017
|
+
return new Promise((resolve3) => {
|
|
4150
4018
|
const s = connect2(sockPath);
|
|
4151
|
-
s.on("connect", () =>
|
|
4152
|
-
s.on("error", () =>
|
|
4019
|
+
s.on("connect", () => resolve3(s));
|
|
4020
|
+
s.on("error", () => resolve3(null));
|
|
4153
4021
|
});
|
|
4154
4022
|
}
|
|
4155
4023
|
function isProcessAlive(pid) {
|
|
@@ -4161,7 +4029,7 @@ function isProcessAlive(pid) {
|
|
|
4161
4029
|
}
|
|
4162
4030
|
}
|
|
4163
4031
|
async function cleanupStaleResources() {
|
|
4164
|
-
if (
|
|
4032
|
+
if (existsSync4(SOCK_PATH)) {
|
|
4165
4033
|
const existing = await tryConnectSocket(SOCK_PATH);
|
|
4166
4034
|
if (existing) {
|
|
4167
4035
|
existing.destroy();
|
|
@@ -4174,8 +4042,8 @@ async function cleanupStaleResources() {
|
|
|
4174
4042
|
unlinkSync2(SOCK_PATH);
|
|
4175
4043
|
serviceLogger.info("Removed stale socket file");
|
|
4176
4044
|
}
|
|
4177
|
-
if (
|
|
4178
|
-
const pidStr =
|
|
4045
|
+
if (existsSync4(PID_PATH)) {
|
|
4046
|
+
const pidStr = readFileSync6(PID_PATH, "utf-8").trim();
|
|
4179
4047
|
const pid = parseInt(pidStr, 10);
|
|
4180
4048
|
if (!isNaN(pid) && isProcessAlive(pid)) {
|
|
4181
4049
|
const msg = `Another service is already running with PID ${pid}`;
|
|
@@ -4507,7 +4375,7 @@ function handleTerminalConnection(socket, deps) {
|
|
|
4507
4375
|
|
|
4508
4376
|
// src/serve/hook-registry.ts
|
|
4509
4377
|
import { createHash, randomBytes } from "crypto";
|
|
4510
|
-
import { existsSync as
|
|
4378
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as readFileSync7, renameSync, writeFileSync as writeFileSync3 } from "fs";
|
|
4511
4379
|
import { dirname } from "path";
|
|
4512
4380
|
import { z } from "zod";
|
|
4513
4381
|
var PersistedHookSessionBindingSchema = z.object({
|
|
@@ -4568,10 +4436,10 @@ var HookRegistry = class {
|
|
|
4568
4436
|
}
|
|
4569
4437
|
}
|
|
4570
4438
|
load() {
|
|
4571
|
-
if (!this.persistPath || !
|
|
4439
|
+
if (!this.persistPath || !existsSync5(this.persistPath)) return;
|
|
4572
4440
|
try {
|
|
4573
4441
|
const parsed = PersistedHookRegistrySchema.parse(
|
|
4574
|
-
JSON.parse(
|
|
4442
|
+
JSON.parse(readFileSync7(this.persistPath, "utf8"))
|
|
4575
4443
|
);
|
|
4576
4444
|
this.bindingsBySession.clear();
|
|
4577
4445
|
for (const binding of parsed.bindings) {
|
|
@@ -4635,7 +4503,7 @@ var HookServer = class {
|
|
|
4635
4503
|
this.writeJson(res, 500, { error: "internal_error" });
|
|
4636
4504
|
});
|
|
4637
4505
|
});
|
|
4638
|
-
return new Promise((
|
|
4506
|
+
return new Promise((resolve3, reject) => {
|
|
4639
4507
|
const onError = (err) => {
|
|
4640
4508
|
this.server?.off("listening", onListening);
|
|
4641
4509
|
reject(err);
|
|
@@ -4643,7 +4511,7 @@ var HookServer = class {
|
|
|
4643
4511
|
const onListening = () => {
|
|
4644
4512
|
this.server?.off("error", onError);
|
|
4645
4513
|
serviceLogger.info({ host: this.host, port: this.options.port }, "Hook server listening");
|
|
4646
|
-
|
|
4514
|
+
resolve3();
|
|
4647
4515
|
};
|
|
4648
4516
|
this.server.once("error", onError);
|
|
4649
4517
|
this.server.once("listening", onListening);
|
|
@@ -4654,8 +4522,8 @@ var HookServer = class {
|
|
|
4654
4522
|
if (!this.server) return Promise.resolve();
|
|
4655
4523
|
const server = this.server;
|
|
4656
4524
|
this.server = null;
|
|
4657
|
-
return new Promise((
|
|
4658
|
-
server.close((err) => err ? reject(err) :
|
|
4525
|
+
return new Promise((resolve3, reject) => {
|
|
4526
|
+
server.close((err) => err ? reject(err) : resolve3());
|
|
4659
4527
|
});
|
|
4660
4528
|
}
|
|
4661
4529
|
getListeningPort() {
|
|
@@ -4769,7 +4637,7 @@ var HookServer = class {
|
|
|
4769
4637
|
this.writeJson(res, 200, payload);
|
|
4770
4638
|
}
|
|
4771
4639
|
readBody(req) {
|
|
4772
|
-
return new Promise((
|
|
4640
|
+
return new Promise((resolve3, reject) => {
|
|
4773
4641
|
let body = "";
|
|
4774
4642
|
let size = 0;
|
|
4775
4643
|
req.setEncoding("utf8");
|
|
@@ -4782,7 +4650,7 @@ var HookServer = class {
|
|
|
4782
4650
|
}
|
|
4783
4651
|
body += chunk;
|
|
4784
4652
|
});
|
|
4785
|
-
req.on("end", () =>
|
|
4653
|
+
req.on("end", () => resolve3(body));
|
|
4786
4654
|
req.on("error", reject);
|
|
4787
4655
|
});
|
|
4788
4656
|
}
|
|
@@ -5089,7 +4957,10 @@ async function startService(options) {
|
|
|
5089
4957
|
relayConnection.on("connected", () => {
|
|
5090
4958
|
void controlHandlers.reinitializeOnReconnect().catch((err) => {
|
|
5091
4959
|
serviceLogger.error(
|
|
5092
|
-
{
|
|
4960
|
+
{
|
|
4961
|
+
error: err instanceof Error ? err.message : String(err),
|
|
4962
|
+
stack: err instanceof Error ? err.stack : void 0
|
|
4963
|
+
},
|
|
5093
4964
|
"reinitializeOnReconnect failed: client may see stale state until next manual sync"
|
|
5094
4965
|
);
|
|
5095
4966
|
});
|