@dev-anywhere/proxy 0.2.4 → 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/serve.js +77 -202
- package/dist/serve.js.map +1 -1
- package/package.json +3 -3
package/dist/serve.js
CHANGED
|
@@ -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) {
|
|
@@ -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",
|
|
@@ -2561,8 +2440,7 @@ var RelayInputHandlers = class {
|
|
|
2561
2440
|
async onFileUploadRequest(msg) {
|
|
2562
2441
|
const { sessionId, requestId, mimeType, dataBase64, fileName } = msg;
|
|
2563
2442
|
if (!sessionId) return;
|
|
2564
|
-
|
|
2565
|
-
if (!session) {
|
|
2443
|
+
if (!this.deps.sessionManager.getSession(sessionId)) {
|
|
2566
2444
|
this.deps.relayConnection.sendRaw(
|
|
2567
2445
|
serializeControl({
|
|
2568
2446
|
type: "file_upload_response",
|
|
@@ -2576,10 +2454,7 @@ var RelayInputHandlers = class {
|
|
|
2576
2454
|
serviceLogger.warn({ sessionId }, "File upload rejected: session not found");
|
|
2577
2455
|
return;
|
|
2578
2456
|
}
|
|
2579
|
-
const result = await saveFileUpload(
|
|
2580
|
-
{ sessionId, mimeType, dataBase64, fileName },
|
|
2581
|
-
{ cwd: session.cwd }
|
|
2582
|
-
);
|
|
2457
|
+
const result = await saveFileUpload({ sessionId, mimeType, dataBase64, fileName });
|
|
2583
2458
|
this.deps.relayConnection.sendRaw(
|
|
2584
2459
|
serializeControl({
|
|
2585
2460
|
type: "file_upload_response",
|
|
@@ -2790,14 +2665,14 @@ var RelayPermissionHandlers = class {
|
|
|
2790
2665
|
|
|
2791
2666
|
// src/serve/relay-resource-handlers.ts
|
|
2792
2667
|
import { homedir as homedir4 } from "os";
|
|
2793
|
-
import { accessSync, constants, statSync as
|
|
2668
|
+
import { accessSync, constants, statSync as statSync3 } from "fs";
|
|
2794
2669
|
function errorMessage(err) {
|
|
2795
2670
|
return err instanceof Error ? err.message : String(err);
|
|
2796
2671
|
}
|
|
2797
2672
|
function validateExecutablePath(path) {
|
|
2798
2673
|
const normalized = path.trim();
|
|
2799
2674
|
if (!normalized.startsWith("/")) throw new Error("CLI \u8DEF\u5F84\u5FC5\u987B\u662F\u7EDD\u5BF9\u8DEF\u5F84");
|
|
2800
|
-
const stat2 =
|
|
2675
|
+
const stat2 = statSync3(normalized);
|
|
2801
2676
|
if (!stat2.isFile()) throw new Error("CLI \u8DEF\u5F84\u4E0D\u662F\u53EF\u6267\u884C\u6587\u4EF6");
|
|
2802
2677
|
accessSync(normalized, constants.X_OK);
|
|
2803
2678
|
return normalized;
|
|
@@ -2905,8 +2780,8 @@ var RelayResourceHandlers = class {
|
|
|
2905
2780
|
};
|
|
2906
2781
|
|
|
2907
2782
|
// src/serve/relay-session-create-handler.ts
|
|
2908
|
-
import { rmSync, statSync as
|
|
2909
|
-
import { isAbsolute as
|
|
2783
|
+
import { rmSync, statSync as statSync4 } from "fs";
|
|
2784
|
+
import { isAbsolute as isAbsolute4 } from "path";
|
|
2910
2785
|
import { nanoid as nanoid5 } from "nanoid";
|
|
2911
2786
|
|
|
2912
2787
|
// src/serve/hosted-pty-registry.ts
|
|
@@ -3158,11 +3033,11 @@ function validateSessionCwd(cwd) {
|
|
|
3158
3033
|
return { message: "\u8BF7\u8F93\u5165\u5DE5\u4F5C\u76EE\u5F55", code: ControlErrorCode.INVALID_PATH };
|
|
3159
3034
|
}
|
|
3160
3035
|
const trimmed = cwd.trim();
|
|
3161
|
-
if (!
|
|
3036
|
+
if (!isAbsolute4(trimmed)) {
|
|
3162
3037
|
return { message: "\u5DE5\u4F5C\u76EE\u5F55\u5FC5\u987B\u662F\u7EDD\u5BF9\u8DEF\u5F84", code: ControlErrorCode.INVALID_PATH };
|
|
3163
3038
|
}
|
|
3164
3039
|
try {
|
|
3165
|
-
const stat2 =
|
|
3040
|
+
const stat2 = statSync4(trimmed);
|
|
3166
3041
|
return stat2.isDirectory() ? null : { message: "\u5DE5\u4F5C\u76EE\u5F55\u4E0D\u662F\u76EE\u5F55", code: ControlErrorCode.PATH_NOT_DIRECTORY };
|
|
3167
3042
|
} catch (err) {
|
|
3168
3043
|
return {
|
|
@@ -3755,11 +3630,11 @@ var PermissionBroker = class {
|
|
|
3755
3630
|
if (this.pending.has(request.requestId)) {
|
|
3756
3631
|
return Promise.resolve(DUPLICATE_DECISION);
|
|
3757
3632
|
}
|
|
3758
|
-
return new Promise((
|
|
3633
|
+
return new Promise((resolve3) => {
|
|
3759
3634
|
this.pending.set(request.requestId, {
|
|
3760
3635
|
...request,
|
|
3761
3636
|
source: "hook",
|
|
3762
|
-
resolve:
|
|
3637
|
+
resolve: resolve3,
|
|
3763
3638
|
createdAt: Date.now()
|
|
3764
3639
|
});
|
|
3765
3640
|
});
|
|
@@ -4135,14 +4010,14 @@ function createEventBridge(deps) {
|
|
|
4135
4010
|
|
|
4136
4011
|
// src/serve/service-files.ts
|
|
4137
4012
|
import { execSync } from "child_process";
|
|
4138
|
-
import { existsSync as
|
|
4013
|
+
import { existsSync as existsSync4, readFileSync as readFileSync6, unlinkSync as unlinkSync2 } from "fs";
|
|
4139
4014
|
import { hostname } from "os";
|
|
4140
4015
|
import { connect as connect2 } from "net";
|
|
4141
4016
|
function tryConnectSocket(sockPath) {
|
|
4142
|
-
return new Promise((
|
|
4017
|
+
return new Promise((resolve3) => {
|
|
4143
4018
|
const s = connect2(sockPath);
|
|
4144
|
-
s.on("connect", () =>
|
|
4145
|
-
s.on("error", () =>
|
|
4019
|
+
s.on("connect", () => resolve3(s));
|
|
4020
|
+
s.on("error", () => resolve3(null));
|
|
4146
4021
|
});
|
|
4147
4022
|
}
|
|
4148
4023
|
function isProcessAlive(pid) {
|
|
@@ -4154,7 +4029,7 @@ function isProcessAlive(pid) {
|
|
|
4154
4029
|
}
|
|
4155
4030
|
}
|
|
4156
4031
|
async function cleanupStaleResources() {
|
|
4157
|
-
if (
|
|
4032
|
+
if (existsSync4(SOCK_PATH)) {
|
|
4158
4033
|
const existing = await tryConnectSocket(SOCK_PATH);
|
|
4159
4034
|
if (existing) {
|
|
4160
4035
|
existing.destroy();
|
|
@@ -4167,8 +4042,8 @@ async function cleanupStaleResources() {
|
|
|
4167
4042
|
unlinkSync2(SOCK_PATH);
|
|
4168
4043
|
serviceLogger.info("Removed stale socket file");
|
|
4169
4044
|
}
|
|
4170
|
-
if (
|
|
4171
|
-
const pidStr =
|
|
4045
|
+
if (existsSync4(PID_PATH)) {
|
|
4046
|
+
const pidStr = readFileSync6(PID_PATH, "utf-8").trim();
|
|
4172
4047
|
const pid = parseInt(pidStr, 10);
|
|
4173
4048
|
if (!isNaN(pid) && isProcessAlive(pid)) {
|
|
4174
4049
|
const msg = `Another service is already running with PID ${pid}`;
|
|
@@ -4500,7 +4375,7 @@ function handleTerminalConnection(socket, deps) {
|
|
|
4500
4375
|
|
|
4501
4376
|
// src/serve/hook-registry.ts
|
|
4502
4377
|
import { createHash, randomBytes } from "crypto";
|
|
4503
|
-
import { existsSync as
|
|
4378
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as readFileSync7, renameSync, writeFileSync as writeFileSync3 } from "fs";
|
|
4504
4379
|
import { dirname } from "path";
|
|
4505
4380
|
import { z } from "zod";
|
|
4506
4381
|
var PersistedHookSessionBindingSchema = z.object({
|
|
@@ -4561,10 +4436,10 @@ var HookRegistry = class {
|
|
|
4561
4436
|
}
|
|
4562
4437
|
}
|
|
4563
4438
|
load() {
|
|
4564
|
-
if (!this.persistPath || !
|
|
4439
|
+
if (!this.persistPath || !existsSync5(this.persistPath)) return;
|
|
4565
4440
|
try {
|
|
4566
4441
|
const parsed = PersistedHookRegistrySchema.parse(
|
|
4567
|
-
JSON.parse(
|
|
4442
|
+
JSON.parse(readFileSync7(this.persistPath, "utf8"))
|
|
4568
4443
|
);
|
|
4569
4444
|
this.bindingsBySession.clear();
|
|
4570
4445
|
for (const binding of parsed.bindings) {
|
|
@@ -4628,7 +4503,7 @@ var HookServer = class {
|
|
|
4628
4503
|
this.writeJson(res, 500, { error: "internal_error" });
|
|
4629
4504
|
});
|
|
4630
4505
|
});
|
|
4631
|
-
return new Promise((
|
|
4506
|
+
return new Promise((resolve3, reject) => {
|
|
4632
4507
|
const onError = (err) => {
|
|
4633
4508
|
this.server?.off("listening", onListening);
|
|
4634
4509
|
reject(err);
|
|
@@ -4636,7 +4511,7 @@ var HookServer = class {
|
|
|
4636
4511
|
const onListening = () => {
|
|
4637
4512
|
this.server?.off("error", onError);
|
|
4638
4513
|
serviceLogger.info({ host: this.host, port: this.options.port }, "Hook server listening");
|
|
4639
|
-
|
|
4514
|
+
resolve3();
|
|
4640
4515
|
};
|
|
4641
4516
|
this.server.once("error", onError);
|
|
4642
4517
|
this.server.once("listening", onListening);
|
|
@@ -4647,8 +4522,8 @@ var HookServer = class {
|
|
|
4647
4522
|
if (!this.server) return Promise.resolve();
|
|
4648
4523
|
const server = this.server;
|
|
4649
4524
|
this.server = null;
|
|
4650
|
-
return new Promise((
|
|
4651
|
-
server.close((err) => err ? reject(err) :
|
|
4525
|
+
return new Promise((resolve3, reject) => {
|
|
4526
|
+
server.close((err) => err ? reject(err) : resolve3());
|
|
4652
4527
|
});
|
|
4653
4528
|
}
|
|
4654
4529
|
getListeningPort() {
|
|
@@ -4762,7 +4637,7 @@ var HookServer = class {
|
|
|
4762
4637
|
this.writeJson(res, 200, payload);
|
|
4763
4638
|
}
|
|
4764
4639
|
readBody(req) {
|
|
4765
|
-
return new Promise((
|
|
4640
|
+
return new Promise((resolve3, reject) => {
|
|
4766
4641
|
let body = "";
|
|
4767
4642
|
let size = 0;
|
|
4768
4643
|
req.setEncoding("utf8");
|
|
@@ -4775,7 +4650,7 @@ var HookServer = class {
|
|
|
4775
4650
|
}
|
|
4776
4651
|
body += chunk;
|
|
4777
4652
|
});
|
|
4778
|
-
req.on("end", () =>
|
|
4653
|
+
req.on("end", () => resolve3(body));
|
|
4779
4654
|
req.on("error", reject);
|
|
4780
4655
|
});
|
|
4781
4656
|
}
|