@dev-anywhere/proxy 0.1.2 → 0.1.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 +4 -1
- package/dist/{chunk-TG7JPHE5.js → chunk-JGGDVMY5.js} +2 -2
- package/dist/{chunk-QXOARRC2.js → chunk-ODK6N2NP.js} +2 -2
- package/dist/{chunk-DFLQ3TFT.js → chunk-RFBTVZ2X.js} +16 -1
- package/dist/chunk-RFBTVZ2X.js.map +1 -0
- package/dist/{chunk-CDKXSDAV.js → chunk-TX6HNHDB.js} +2 -2
- package/dist/index.js +3 -3
- package/dist/serve.js +180 -36
- package/dist/serve.js.map +1 -1
- package/dist/session-worker.js +2 -2
- package/dist/{terminal-GIU6MXOR.js → terminal-ES6I5W32.js} +4 -4
- package/package.json +3 -3
- package/dist/chunk-DFLQ3TFT.js.map +0 -1
- /package/dist/{chunk-TG7JPHE5.js.map → chunk-JGGDVMY5.js.map} +0 -0
- /package/dist/{chunk-QXOARRC2.js.map → chunk-ODK6N2NP.js.map} +0 -0
- /package/dist/{chunk-CDKXSDAV.js.map → chunk-TX6HNHDB.js.map} +0 -0
- /package/dist/{terminal-GIU6MXOR.js.map → terminal-ES6I5W32.js.map} +0 -0
package/dist/serve.js
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
KnownContentBlockSchema,
|
|
6
6
|
SeqCounter,
|
|
7
7
|
StreamJsonEventSchema
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-ODK6N2NP.js";
|
|
9
9
|
import {
|
|
10
10
|
createFSM,
|
|
11
11
|
defineFSM,
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
serviceLogger,
|
|
15
15
|
shouldReleaseApprovalWait,
|
|
16
16
|
stateAfterApprovalRelease
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-JGGDVMY5.js";
|
|
18
18
|
import {
|
|
19
19
|
spawnScript
|
|
20
20
|
} from "./chunk-ZUWAB67J.js";
|
|
@@ -46,7 +46,7 @@ import {
|
|
|
46
46
|
serializeWorkerMsg,
|
|
47
47
|
sessionPaths,
|
|
48
48
|
tildify
|
|
49
|
-
} from "./chunk-
|
|
49
|
+
} from "./chunk-RFBTVZ2X.js";
|
|
50
50
|
|
|
51
51
|
// src/serve.ts
|
|
52
52
|
import { createServer as createServer2 } from "net";
|
|
@@ -702,6 +702,7 @@ function loadConfig(options) {
|
|
|
702
702
|
hookPort: parsePort(process.env.DEV_ANYWHERE_HOOK_PORT, "DEV_ANYWHERE_HOOK_PORT") ?? defaultHookPortForProfile(PROFILE_NAME),
|
|
703
703
|
claudeBin,
|
|
704
704
|
codexBin,
|
|
705
|
+
previewRoots: uniqueAbsolutePaths(fromFile.previewRoots ?? []),
|
|
705
706
|
agentCliSuggestions: {
|
|
706
707
|
claude: uniqueAbsolutePaths([
|
|
707
708
|
process.env.CLAUDE_BIN,
|
|
@@ -1083,7 +1084,7 @@ function extractConversationText(msg) {
|
|
|
1083
1084
|
return null;
|
|
1084
1085
|
}
|
|
1085
1086
|
async function extractTitleAndCwd(filePath) {
|
|
1086
|
-
return new Promise((
|
|
1087
|
+
return new Promise((resolve3) => {
|
|
1087
1088
|
const rl = createInterface({
|
|
1088
1089
|
input: createReadStream(filePath, { encoding: "utf-8" }),
|
|
1089
1090
|
crlfDelay: Infinity
|
|
@@ -1111,10 +1112,10 @@ async function extractTitleAndCwd(filePath) {
|
|
|
1111
1112
|
}
|
|
1112
1113
|
});
|
|
1113
1114
|
rl.on("close", () => {
|
|
1114
|
-
if (!resolved)
|
|
1115
|
-
else
|
|
1115
|
+
if (!resolved) resolve3({ title, cwd });
|
|
1116
|
+
else resolve3({ title, cwd });
|
|
1116
1117
|
});
|
|
1117
|
-
rl.on("error", () =>
|
|
1118
|
+
rl.on("error", () => resolve3({ title, cwd }));
|
|
1118
1119
|
});
|
|
1119
1120
|
}
|
|
1120
1121
|
async function collectJsonlFiles(root) {
|
|
@@ -1136,7 +1137,7 @@ async function collectJsonlFiles(root) {
|
|
|
1136
1137
|
return files;
|
|
1137
1138
|
}
|
|
1138
1139
|
async function extractCodexTitleAndCwd(filePath) {
|
|
1139
|
-
return new Promise((
|
|
1140
|
+
return new Promise((resolve3) => {
|
|
1140
1141
|
const rl = createInterface({
|
|
1141
1142
|
input: createReadStream(filePath, { encoding: "utf-8" }),
|
|
1142
1143
|
crlfDelay: Infinity
|
|
@@ -1160,8 +1161,8 @@ async function extractCodexTitleAndCwd(filePath) {
|
|
|
1160
1161
|
} catch {
|
|
1161
1162
|
}
|
|
1162
1163
|
});
|
|
1163
|
-
rl.on("close", () =>
|
|
1164
|
-
rl.on("error", () =>
|
|
1164
|
+
rl.on("close", () => resolve3({ id, title, cwd }));
|
|
1165
|
+
rl.on("error", () => resolve3({ id, title, cwd }));
|
|
1165
1166
|
});
|
|
1166
1167
|
}
|
|
1167
1168
|
function extractCodexUserText(payload) {
|
|
@@ -1726,16 +1727,16 @@ var WorkerRegistry = class {
|
|
|
1726
1727
|
return workerPid;
|
|
1727
1728
|
}
|
|
1728
1729
|
connect(sessionId, sockPath) {
|
|
1729
|
-
return new Promise((
|
|
1730
|
+
return new Promise((resolve3) => {
|
|
1730
1731
|
const sock = connect(sockPath);
|
|
1731
1732
|
sock.on("connect", () => {
|
|
1732
1733
|
this.sockets.set(sessionId, sock);
|
|
1733
1734
|
createWorkerReader(sock, (msg) => this.handleWorkerMessage(sessionId, msg));
|
|
1734
1735
|
sock.on("close", () => this.onDisconnect(sessionId));
|
|
1735
1736
|
sock.on("error", () => this.onDisconnect(sessionId));
|
|
1736
|
-
|
|
1737
|
+
resolve3(sock);
|
|
1737
1738
|
});
|
|
1738
|
-
sock.on("error", () =>
|
|
1739
|
+
sock.on("error", () => resolve3(null));
|
|
1739
1740
|
});
|
|
1740
1741
|
}
|
|
1741
1742
|
// 枚举 DATA_DIR 下所有 session 目录,尝试连接存活的 worker.sock;失败则清理 stale socket。
|
|
@@ -2175,6 +2176,108 @@ function saveClipboardImageUpload(request, options = {}) {
|
|
|
2175
2176
|
}
|
|
2176
2177
|
}
|
|
2177
2178
|
|
|
2179
|
+
// src/serve/image-preview.ts
|
|
2180
|
+
import { readFileSync as readFileSync6, realpathSync, statSync as statSync2 } from "fs";
|
|
2181
|
+
import { tmpdir } from "os";
|
|
2182
|
+
import { isAbsolute as isAbsolute4, relative as relative2, resolve as resolve2 } from "path";
|
|
2183
|
+
var MAX_IMAGE_PREVIEW_BYTES = 10 * 1024 * 1024;
|
|
2184
|
+
function isInsideRoot(realFilePath, realRootPath) {
|
|
2185
|
+
const rel = relative2(realRootPath, realFilePath);
|
|
2186
|
+
return rel === "" || !rel.startsWith("..") && !isAbsolute4(rel);
|
|
2187
|
+
}
|
|
2188
|
+
function allowedRoots(options) {
|
|
2189
|
+
return [options.cwd, options.tmpDir ?? tmpdir(), ...options.previewRoots ?? []].map((root) => root.trim()).filter(Boolean).flatMap((root) => {
|
|
2190
|
+
try {
|
|
2191
|
+
return [realpathSync(root)];
|
|
2192
|
+
} catch {
|
|
2193
|
+
return [];
|
|
2194
|
+
}
|
|
2195
|
+
});
|
|
2196
|
+
}
|
|
2197
|
+
function resolvePreviewPath(rawPath, options) {
|
|
2198
|
+
const candidate = isAbsolute4(rawPath) ? resolve2(rawPath) : resolve2(options.cwd, rawPath);
|
|
2199
|
+
const realCandidate = realpathSync(candidate);
|
|
2200
|
+
if (!allowedRoots(options).some((root) => isInsideRoot(realCandidate, root))) {
|
|
2201
|
+
throw Object.assign(new Error("\u56FE\u7247\u8DEF\u5F84\u4E0D\u5728\u5141\u8BB8\u9884\u89C8\u7684\u76EE\u5F55\u5185"), {
|
|
2202
|
+
errorCode: ControlErrorCode.INVALID_PATH
|
|
2203
|
+
});
|
|
2204
|
+
}
|
|
2205
|
+
return realCandidate;
|
|
2206
|
+
}
|
|
2207
|
+
function detectImageMime(buffer) {
|
|
2208
|
+
if (buffer.length >= 8 && buffer[0] === 137 && buffer[1] === 80 && buffer[2] === 78 && buffer[3] === 71 && buffer[4] === 13 && buffer[5] === 10 && buffer[6] === 26 && buffer[7] === 10) {
|
|
2209
|
+
return "image/png";
|
|
2210
|
+
}
|
|
2211
|
+
if (buffer.length >= 3 && buffer[0] === 255 && buffer[1] === 216 && buffer[2] === 255) {
|
|
2212
|
+
return "image/jpeg";
|
|
2213
|
+
}
|
|
2214
|
+
if (buffer.length >= 12 && buffer.subarray(0, 4).toString("ascii") === "RIFF" && buffer.subarray(8, 12).toString("ascii") === "WEBP") {
|
|
2215
|
+
return "image/webp";
|
|
2216
|
+
}
|
|
2217
|
+
if (buffer.length >= 6 && (buffer.subarray(0, 6).toString("ascii") === "GIF87a" || buffer.subarray(0, 6).toString("ascii") === "GIF89a")) {
|
|
2218
|
+
return "image/gif";
|
|
2219
|
+
}
|
|
2220
|
+
return void 0;
|
|
2221
|
+
}
|
|
2222
|
+
function errorCode(err) {
|
|
2223
|
+
if (err instanceof Error && "errorCode" in err && typeof err.errorCode === "string") {
|
|
2224
|
+
return err.errorCode;
|
|
2225
|
+
}
|
|
2226
|
+
return classifyPathError(err);
|
|
2227
|
+
}
|
|
2228
|
+
function loadImagePreview(request, options) {
|
|
2229
|
+
try {
|
|
2230
|
+
const resolvedPath = resolvePreviewPath(request.path, options);
|
|
2231
|
+
const stat2 = statSync2(resolvedPath);
|
|
2232
|
+
if (!stat2.isFile()) {
|
|
2233
|
+
return {
|
|
2234
|
+
success: false,
|
|
2235
|
+
sessionId: request.sessionId,
|
|
2236
|
+
path: request.path,
|
|
2237
|
+
error: "\u8DEF\u5F84\u4E0D\u662F\u56FE\u7247\u6587\u4EF6",
|
|
2238
|
+
errorCode: ControlErrorCode.INVALID_PATH
|
|
2239
|
+
};
|
|
2240
|
+
}
|
|
2241
|
+
const maxBytes = options.maxBytes ?? MAX_IMAGE_PREVIEW_BYTES;
|
|
2242
|
+
if (stat2.size > maxBytes) {
|
|
2243
|
+
return {
|
|
2244
|
+
success: false,
|
|
2245
|
+
sessionId: request.sessionId,
|
|
2246
|
+
path: request.path,
|
|
2247
|
+
error: "\u56FE\u7247\u8D85\u8FC7 10MB \u9650\u5236",
|
|
2248
|
+
errorCode: ControlErrorCode.UNKNOWN
|
|
2249
|
+
};
|
|
2250
|
+
}
|
|
2251
|
+
const buffer = readFileSync6(resolvedPath);
|
|
2252
|
+
const mimeType = detectImageMime(buffer);
|
|
2253
|
+
if (!mimeType) {
|
|
2254
|
+
return {
|
|
2255
|
+
success: false,
|
|
2256
|
+
sessionId: request.sessionId,
|
|
2257
|
+
path: request.path,
|
|
2258
|
+
error: "\u4E0D\u652F\u6301\u8FD9\u79CD\u56FE\u7247\u683C\u5F0F",
|
|
2259
|
+
errorCode: ControlErrorCode.UNKNOWN
|
|
2260
|
+
};
|
|
2261
|
+
}
|
|
2262
|
+
return {
|
|
2263
|
+
success: true,
|
|
2264
|
+
sessionId: request.sessionId,
|
|
2265
|
+
path: request.path,
|
|
2266
|
+
mimeType,
|
|
2267
|
+
dataBase64: buffer.toString("base64"),
|
|
2268
|
+
size: buffer.length
|
|
2269
|
+
};
|
|
2270
|
+
} catch (err) {
|
|
2271
|
+
return {
|
|
2272
|
+
success: false,
|
|
2273
|
+
sessionId: request.sessionId,
|
|
2274
|
+
path: request.path,
|
|
2275
|
+
error: err instanceof Error ? err.message : String(err),
|
|
2276
|
+
errorCode: errorCode(err)
|
|
2277
|
+
};
|
|
2278
|
+
}
|
|
2279
|
+
}
|
|
2280
|
+
|
|
2178
2281
|
// src/serve/pty-input.ts
|
|
2179
2282
|
function serializeRawPtyInput(sessionId, data) {
|
|
2180
2283
|
return serializeIpc({ type: "pty_input", sessionId, data });
|
|
@@ -2289,6 +2392,43 @@ var RelayInputHandlers = class {
|
|
|
2289
2392
|
);
|
|
2290
2393
|
serviceLogger.info({ sessionId, success: result.success }, "Clipboard image upload handled");
|
|
2291
2394
|
}
|
|
2395
|
+
onImagePreviewRequest(msg) {
|
|
2396
|
+
const sessionId = msg.sessionId;
|
|
2397
|
+
const requestId = msg.requestId;
|
|
2398
|
+
const path = msg.path;
|
|
2399
|
+
if (!sessionId || !path) return;
|
|
2400
|
+
const session = this.deps.sessionManager.getSession(sessionId);
|
|
2401
|
+
if (!session) {
|
|
2402
|
+
this.deps.relayConnection.sendRaw(
|
|
2403
|
+
JSON.stringify({
|
|
2404
|
+
type: "image_preview_response",
|
|
2405
|
+
requestId,
|
|
2406
|
+
sessionId,
|
|
2407
|
+
success: false,
|
|
2408
|
+
path,
|
|
2409
|
+
error: "\u4F1A\u8BDD\u4E0D\u5B58\u5728",
|
|
2410
|
+
errorCode: ControlErrorCode.SESSION_NOT_FOUND
|
|
2411
|
+
})
|
|
2412
|
+
);
|
|
2413
|
+
serviceLogger.warn({ sessionId }, "Image preview rejected: session not found");
|
|
2414
|
+
return;
|
|
2415
|
+
}
|
|
2416
|
+
const result = loadImagePreview(
|
|
2417
|
+
{ sessionId, path },
|
|
2418
|
+
{
|
|
2419
|
+
cwd: session.cwd,
|
|
2420
|
+
previewRoots: this.deps.previewRoots
|
|
2421
|
+
}
|
|
2422
|
+
);
|
|
2423
|
+
this.deps.relayConnection.sendRaw(
|
|
2424
|
+
JSON.stringify({
|
|
2425
|
+
type: "image_preview_response",
|
|
2426
|
+
requestId,
|
|
2427
|
+
...result
|
|
2428
|
+
})
|
|
2429
|
+
);
|
|
2430
|
+
serviceLogger.info({ sessionId, success: result.success }, "Image preview handled");
|
|
2431
|
+
}
|
|
2292
2432
|
};
|
|
2293
2433
|
|
|
2294
2434
|
// src/serve/relay-history-handlers.ts
|
|
@@ -2488,14 +2628,14 @@ var RelayPermissionHandlers = class {
|
|
|
2488
2628
|
|
|
2489
2629
|
// src/serve/relay-resource-handlers.ts
|
|
2490
2630
|
import { homedir as homedir4 } from "os";
|
|
2491
|
-
import { accessSync, constants, statSync as
|
|
2631
|
+
import { accessSync, constants, statSync as statSync3 } from "fs";
|
|
2492
2632
|
function errorMessage(err) {
|
|
2493
2633
|
return err instanceof Error ? err.message : String(err);
|
|
2494
2634
|
}
|
|
2495
2635
|
function validateExecutablePath(path) {
|
|
2496
2636
|
const normalized = path.trim();
|
|
2497
2637
|
if (!normalized.startsWith("/")) throw new Error("CLI \u8DEF\u5F84\u5FC5\u987B\u662F\u7EDD\u5BF9\u8DEF\u5F84");
|
|
2498
|
-
const stat2 =
|
|
2638
|
+
const stat2 = statSync3(normalized);
|
|
2499
2639
|
if (!stat2.isFile()) throw new Error("CLI \u8DEF\u5F84\u4E0D\u662F\u53EF\u6267\u884C\u6587\u4EF6");
|
|
2500
2640
|
accessSync(normalized, constants.X_OK);
|
|
2501
2641
|
return normalized;
|
|
@@ -2604,8 +2744,8 @@ var RelayResourceHandlers = class {
|
|
|
2604
2744
|
};
|
|
2605
2745
|
|
|
2606
2746
|
// src/serve/relay-session-create-handler.ts
|
|
2607
|
-
import { rmSync, statSync as
|
|
2608
|
-
import { isAbsolute as
|
|
2747
|
+
import { rmSync, statSync as statSync4 } from "fs";
|
|
2748
|
+
import { isAbsolute as isAbsolute5 } from "path";
|
|
2609
2749
|
import { nanoid as nanoid4 } from "nanoid";
|
|
2610
2750
|
|
|
2611
2751
|
// src/serve/hosted-pty-registry.ts
|
|
@@ -2895,11 +3035,11 @@ function validateSessionCwd(cwd) {
|
|
|
2895
3035
|
return { message: "\u8BF7\u8F93\u5165\u5DE5\u4F5C\u76EE\u5F55", code: ControlErrorCode.INVALID_PATH };
|
|
2896
3036
|
}
|
|
2897
3037
|
const trimmed = cwd.trim();
|
|
2898
|
-
if (!
|
|
3038
|
+
if (!isAbsolute5(trimmed)) {
|
|
2899
3039
|
return { message: "\u5DE5\u4F5C\u76EE\u5F55\u5FC5\u987B\u662F\u7EDD\u5BF9\u8DEF\u5F84", code: ControlErrorCode.INVALID_PATH };
|
|
2900
3040
|
}
|
|
2901
3041
|
try {
|
|
2902
|
-
const stat2 =
|
|
3042
|
+
const stat2 = statSync4(trimmed);
|
|
2903
3043
|
return stat2.isDirectory() ? null : { message: "\u5DE5\u4F5C\u76EE\u5F55\u4E0D\u662F\u76EE\u5F55", code: ControlErrorCode.PATH_NOT_DIRECTORY };
|
|
2904
3044
|
} catch (err) {
|
|
2905
3045
|
return {
|
|
@@ -3148,7 +3288,8 @@ var RelayRouter = class {
|
|
|
3148
3288
|
relayConnection: deps.relayConnection,
|
|
3149
3289
|
terminalSockets: deps.terminalSockets,
|
|
3150
3290
|
hostedPtyRegistry: deps.hostedPtyRegistry,
|
|
3151
|
-
jsonObserver: deps.jsonObserver
|
|
3291
|
+
jsonObserver: deps.jsonObserver,
|
|
3292
|
+
previewRoots: deps.getPreviewRoots?.()
|
|
3152
3293
|
});
|
|
3153
3294
|
this.resourceHandlers = new RelayResourceHandlers({
|
|
3154
3295
|
relaySend: deps.relaySend,
|
|
@@ -3206,6 +3347,7 @@ var RelayRouter = class {
|
|
|
3206
3347
|
user_input: (msg) => this.inputHandlers.onUserInput(msg),
|
|
3207
3348
|
remote_input_raw: (msg) => this.inputHandlers.onRemoteInputRaw(msg),
|
|
3208
3349
|
clipboard_image_upload: (msg) => this.inputHandlers.onClipboardImageUpload(msg),
|
|
3350
|
+
image_preview_request: (msg) => this.inputHandlers.onImagePreviewRequest(msg),
|
|
3209
3351
|
tool_approve: (msg) => this.permissionHandlers.onToolApprove(msg),
|
|
3210
3352
|
tool_deny: (msg) => this.permissionHandlers.onToolDeny(msg),
|
|
3211
3353
|
proxy_info_request: (msg) => this.resourceHandlers.onProxyInfoRequest(msg),
|
|
@@ -3396,11 +3538,11 @@ var PermissionBroker = class {
|
|
|
3396
3538
|
message: "Duplicate permission request id."
|
|
3397
3539
|
});
|
|
3398
3540
|
}
|
|
3399
|
-
return new Promise((
|
|
3541
|
+
return new Promise((resolve3) => {
|
|
3400
3542
|
this.pending.set(request.requestId, {
|
|
3401
3543
|
...request,
|
|
3402
3544
|
source: "hook",
|
|
3403
|
-
resolve:
|
|
3545
|
+
resolve: resolve3,
|
|
3404
3546
|
createdAt: Date.now()
|
|
3405
3547
|
});
|
|
3406
3548
|
});
|
|
@@ -3695,14 +3837,14 @@ function touchSessionActivity(sessionManager, relay, sessionId, now = Date.now()
|
|
|
3695
3837
|
|
|
3696
3838
|
// src/serve/service-files.ts
|
|
3697
3839
|
import { execSync } from "child_process";
|
|
3698
|
-
import { existsSync as existsSync6, readFileSync as
|
|
3840
|
+
import { existsSync as existsSync6, readFileSync as readFileSync7, unlinkSync as unlinkSync2 } from "fs";
|
|
3699
3841
|
import { hostname } from "os";
|
|
3700
3842
|
import { connect as connect2 } from "net";
|
|
3701
3843
|
function tryConnectSocket(sockPath) {
|
|
3702
|
-
return new Promise((
|
|
3844
|
+
return new Promise((resolve3) => {
|
|
3703
3845
|
const s = connect2(sockPath);
|
|
3704
|
-
s.on("connect", () =>
|
|
3705
|
-
s.on("error", () =>
|
|
3846
|
+
s.on("connect", () => resolve3(s));
|
|
3847
|
+
s.on("error", () => resolve3(null));
|
|
3706
3848
|
});
|
|
3707
3849
|
}
|
|
3708
3850
|
function isProcessAlive(pid) {
|
|
@@ -3727,7 +3869,7 @@ async function cleanupStaleResources() {
|
|
|
3727
3869
|
serviceLogger.info("Removed stale socket file");
|
|
3728
3870
|
}
|
|
3729
3871
|
if (existsSync6(PID_PATH)) {
|
|
3730
|
-
const pidStr =
|
|
3872
|
+
const pidStr = readFileSync7(PID_PATH, "utf-8").trim();
|
|
3731
3873
|
const pid = parseInt(pidStr, 10);
|
|
3732
3874
|
if (!isNaN(pid) && isProcessAlive(pid)) {
|
|
3733
3875
|
const msg = `Another service is already running with PID ${pid}`;
|
|
@@ -4102,7 +4244,7 @@ function handleTerminalConnection(socket, deps) {
|
|
|
4102
4244
|
|
|
4103
4245
|
// src/serve/hook-registry.ts
|
|
4104
4246
|
import { createHash, randomBytes } from "crypto";
|
|
4105
|
-
import { existsSync as existsSync7, mkdirSync as mkdirSync5, readFileSync as
|
|
4247
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync5, readFileSync as readFileSync8, renameSync as renameSync2, writeFileSync as writeFileSync5 } from "fs";
|
|
4106
4248
|
import { dirname as dirname4 } from "path";
|
|
4107
4249
|
import { z } from "zod";
|
|
4108
4250
|
var PersistedHookSessionBindingSchema = z.object({
|
|
@@ -4166,7 +4308,7 @@ var HookRegistry = class {
|
|
|
4166
4308
|
if (!this.persistPath || !existsSync7(this.persistPath)) return;
|
|
4167
4309
|
try {
|
|
4168
4310
|
const parsed = PersistedHookRegistrySchema.parse(
|
|
4169
|
-
JSON.parse(
|
|
4311
|
+
JSON.parse(readFileSync8(this.persistPath, "utf8"))
|
|
4170
4312
|
);
|
|
4171
4313
|
this.bindingsBySession.clear();
|
|
4172
4314
|
for (const binding of parsed.bindings) {
|
|
@@ -4236,7 +4378,7 @@ var HookServer = class {
|
|
|
4236
4378
|
this.writeJson(res, 500, { error: "internal_error" });
|
|
4237
4379
|
});
|
|
4238
4380
|
});
|
|
4239
|
-
return new Promise((
|
|
4381
|
+
return new Promise((resolve3, reject) => {
|
|
4240
4382
|
const onError = (err) => {
|
|
4241
4383
|
this.server?.off("listening", onListening);
|
|
4242
4384
|
reject(err);
|
|
@@ -4244,7 +4386,7 @@ var HookServer = class {
|
|
|
4244
4386
|
const onListening = () => {
|
|
4245
4387
|
this.server?.off("error", onError);
|
|
4246
4388
|
serviceLogger.info({ host: this.host, port: this.options.port }, "Hook server listening");
|
|
4247
|
-
|
|
4389
|
+
resolve3();
|
|
4248
4390
|
};
|
|
4249
4391
|
this.server.once("error", onError);
|
|
4250
4392
|
this.server.once("listening", onListening);
|
|
@@ -4255,8 +4397,8 @@ var HookServer = class {
|
|
|
4255
4397
|
if (!this.server) return Promise.resolve();
|
|
4256
4398
|
const server = this.server;
|
|
4257
4399
|
this.server = null;
|
|
4258
|
-
return new Promise((
|
|
4259
|
-
server.close((err) => err ? reject(err) :
|
|
4400
|
+
return new Promise((resolve3, reject) => {
|
|
4401
|
+
server.close((err) => err ? reject(err) : resolve3());
|
|
4260
4402
|
});
|
|
4261
4403
|
}
|
|
4262
4404
|
getListeningPort() {
|
|
@@ -4370,7 +4512,7 @@ var HookServer = class {
|
|
|
4370
4512
|
this.writeJson(res, 200, payload);
|
|
4371
4513
|
}
|
|
4372
4514
|
readBody(req) {
|
|
4373
|
-
return new Promise((
|
|
4515
|
+
return new Promise((resolve3, reject) => {
|
|
4374
4516
|
let body = "";
|
|
4375
4517
|
let size = 0;
|
|
4376
4518
|
req.setEncoding("utf8");
|
|
@@ -4383,7 +4525,7 @@ var HookServer = class {
|
|
|
4383
4525
|
}
|
|
4384
4526
|
body += chunk;
|
|
4385
4527
|
});
|
|
4386
|
-
req.on("end", () =>
|
|
4528
|
+
req.on("end", () => resolve3(body));
|
|
4387
4529
|
req.on("error", reject);
|
|
4388
4530
|
});
|
|
4389
4531
|
}
|
|
@@ -4531,6 +4673,7 @@ async function startService(options) {
|
|
|
4531
4673
|
let proxyConfig = loadConfig({ relayName: options?.relayName });
|
|
4532
4674
|
const getProviderEnv = () => buildProviderEnv(proxyConfig, process.env);
|
|
4533
4675
|
const getAgentCliSuggestions = () => proxyConfig.agentCliSuggestions;
|
|
4676
|
+
const getPreviewRoots = () => proxyConfig.previewRoots;
|
|
4534
4677
|
const setAgentCliPath = (provider, path) => {
|
|
4535
4678
|
const field = provider === "claude" ? "claudeBin" : "codexBin";
|
|
4536
4679
|
const existing = proxyConfig.agentCliSuggestions[provider] ?? [];
|
|
@@ -4658,7 +4801,8 @@ async function startService(options) {
|
|
|
4658
4801
|
agentStatusRegistry,
|
|
4659
4802
|
getProviderEnv,
|
|
4660
4803
|
getAgentCliSuggestions,
|
|
4661
|
-
setAgentCliPath
|
|
4804
|
+
setAgentCliPath,
|
|
4805
|
+
getPreviewRoots
|
|
4662
4806
|
});
|
|
4663
4807
|
relayConnection.on("message", (msg) => relayRouter.handle(msg));
|
|
4664
4808
|
relayConnection.on("connected", () => {
|