@dev-anywhere/proxy 0.1.6 → 0.1.8
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-TX6HNHDB.js → chunk-2SBGSJLQ.js} +2 -2
- package/dist/{chunk-RFBTVZ2X.js → chunk-2XO3KLWW.js} +27 -338
- package/dist/chunk-2XO3KLWW.js.map +1 -0
- package/dist/chunk-BLWDLNT6.js +346 -0
- package/dist/chunk-BLWDLNT6.js.map +1 -0
- package/dist/chunk-GTTLWHIG.js +84 -0
- package/dist/chunk-GTTLWHIG.js.map +1 -0
- package/dist/{chunk-JGGDVMY5.js → chunk-ORZTFYXR.js} +2 -21
- package/dist/chunk-ORZTFYXR.js.map +1 -0
- package/dist/{chunk-ODK6N2NP.js → chunk-PDX6QFJ7.js} +2 -2
- package/dist/chunk-R4S6OFIZ.js +195 -0
- package/dist/chunk-R4S6OFIZ.js.map +1 -0
- package/dist/index.js +25 -13
- package/dist/index.js.map +1 -1
- package/dist/relay-token-KQPEQVP7.js +81 -0
- package/dist/relay-token-KQPEQVP7.js.map +1 -0
- package/dist/serve.js +54 -200
- package/dist/serve.js.map +1 -1
- package/dist/session-worker.js +3 -2
- package/dist/session-worker.js.map +1 -1
- package/dist/{terminal-ES6I5W32.js → terminal-4MDRBCL4.js} +13 -9
- package/dist/{terminal-ES6I5W32.js.map → terminal-4MDRBCL4.js.map} +1 -1
- package/package.json +3 -3
- package/dist/chunk-JGGDVMY5.js.map +0 -1
- package/dist/chunk-RFBTVZ2X.js.map +0 -1
- /package/dist/{chunk-TX6HNHDB.js.map → chunk-2SBGSJLQ.js.map} +0 -0
- /package/dist/{chunk-ODK6N2NP.js.map → chunk-PDX6QFJ7.js.map} +0 -0
package/dist/serve.js
CHANGED
|
@@ -5,16 +5,15 @@ import {
|
|
|
5
5
|
KnownContentBlockSchema,
|
|
6
6
|
SeqCounter,
|
|
7
7
|
StreamJsonEventSchema
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-PDX6QFJ7.js";
|
|
9
9
|
import {
|
|
10
10
|
createFSM,
|
|
11
11
|
defineFSM,
|
|
12
12
|
extractOscSequences,
|
|
13
13
|
extractOscSignals,
|
|
14
|
-
serviceLogger,
|
|
15
14
|
shouldReleaseApprovalWait,
|
|
16
15
|
stateAfterApprovalRelease
|
|
17
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-ORZTFYXR.js";
|
|
18
17
|
import {
|
|
19
18
|
spawnScript
|
|
20
19
|
} from "./chunk-ZUWAB67J.js";
|
|
@@ -24,7 +23,20 @@ import {
|
|
|
24
23
|
detectAgentCliStatus
|
|
25
24
|
} from "./chunk-6O6JTF24.js";
|
|
26
25
|
import {
|
|
27
|
-
|
|
26
|
+
createIpcReader,
|
|
27
|
+
createWorkerReader,
|
|
28
|
+
serializeIpc,
|
|
29
|
+
serializeWorkerMsg
|
|
30
|
+
} from "./chunk-BLWDLNT6.js";
|
|
31
|
+
import {
|
|
32
|
+
buildProviderEnv,
|
|
33
|
+
loadConfig,
|
|
34
|
+
saveAgentCliPath
|
|
35
|
+
} from "./chunk-R4S6OFIZ.js";
|
|
36
|
+
import {
|
|
37
|
+
serviceLogger
|
|
38
|
+
} from "./chunk-GTTLWHIG.js";
|
|
39
|
+
import {
|
|
28
40
|
ControlErrorCode,
|
|
29
41
|
DATA_DIR,
|
|
30
42
|
DEFAULT_PROXY_PROFILE,
|
|
@@ -38,19 +50,14 @@ import {
|
|
|
38
50
|
STOPPED_PATH,
|
|
39
51
|
SessionState,
|
|
40
52
|
buildMessage,
|
|
41
|
-
createIpcReader,
|
|
42
|
-
createWorkerReader,
|
|
43
|
-
defaultHookPortForProfile,
|
|
44
53
|
ensureProfileWorkspace,
|
|
45
|
-
serializeIpc,
|
|
46
|
-
serializeWorkerMsg,
|
|
47
54
|
sessionPaths,
|
|
48
55
|
tildify
|
|
49
|
-
} from "./chunk-
|
|
56
|
+
} from "./chunk-2XO3KLWW.js";
|
|
50
57
|
|
|
51
58
|
// src/serve.ts
|
|
52
59
|
import { createServer as createServer2 } from "net";
|
|
53
|
-
import { unlinkSync as unlinkSync3, writeFileSync as
|
|
60
|
+
import { unlinkSync as unlinkSync3, writeFileSync as writeFileSync5, chmodSync, rmSync as rmSync2 } from "fs";
|
|
54
61
|
|
|
55
62
|
// src/serve/session-manager.ts
|
|
56
63
|
import { mkdirSync, readFileSync, renameSync, writeFileSync, existsSync } from "fs";
|
|
@@ -614,162 +621,9 @@ var RelayConnection = class extends EventEmitter {
|
|
|
614
621
|
}
|
|
615
622
|
};
|
|
616
623
|
|
|
617
|
-
// src/common/config.ts
|
|
618
|
-
import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
619
|
-
import { dirname as dirname3, isAbsolute } from "path";
|
|
620
|
-
function parsePort(value, source) {
|
|
621
|
-
if (!value) return void 0;
|
|
622
|
-
const port = Number(value);
|
|
623
|
-
if (!Number.isInteger(port) || port < 1 || port > 65535) {
|
|
624
|
-
throw new Error(`Invalid ${source}: expected TCP port 1-65535`);
|
|
625
|
-
}
|
|
626
|
-
return port;
|
|
627
|
-
}
|
|
628
|
-
function isRecord(value) {
|
|
629
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
630
|
-
}
|
|
631
|
-
function validateConfigShape(value) {
|
|
632
|
-
if (!isRecord(value) || !isRecord(value.profiles) || !isRecord(value.relays)) {
|
|
633
|
-
throw new Error(`Invalid config shape in ${CONFIG_PATH}: expected "profiles" and "relays".`);
|
|
634
|
-
}
|
|
635
|
-
return value;
|
|
636
|
-
}
|
|
637
|
-
function readConfigFile() {
|
|
638
|
-
if (!existsSync3(CONFIG_PATH)) {
|
|
639
|
-
throw new Error(`Dev Anywhere config not found at ${CONFIG_PATH}. Run "dev-anywhere init".`);
|
|
640
|
-
}
|
|
641
|
-
return validateConfigShape(JSON.parse(readFileSync3(CONFIG_PATH, "utf-8")));
|
|
642
|
-
}
|
|
643
|
-
function agentCliField(provider) {
|
|
644
|
-
return provider === "claude" ? "claudeBin" : "codexBin";
|
|
645
|
-
}
|
|
646
|
-
function agentCliHistoryField(provider) {
|
|
647
|
-
return provider === "claude" ? "claudeBinHistory" : "codexBinHistory";
|
|
648
|
-
}
|
|
649
|
-
function validateAgentCliPath(path) {
|
|
650
|
-
const normalized = path.trim();
|
|
651
|
-
if (!normalized) throw new Error("\u8BF7\u8F93\u5165 CLI \u8DEF\u5F84");
|
|
652
|
-
if (!isAbsolute(normalized)) throw new Error("CLI \u8DEF\u5F84\u5FC5\u987B\u662F\u7EDD\u5BF9\u8DEF\u5F84");
|
|
653
|
-
return normalized;
|
|
654
|
-
}
|
|
655
|
-
function uniqueAbsolutePaths(paths) {
|
|
656
|
-
const seen = /* @__PURE__ */ new Set();
|
|
657
|
-
const result = [];
|
|
658
|
-
for (const path of paths) {
|
|
659
|
-
const normalized = path?.trim();
|
|
660
|
-
if (!normalized || !isAbsolute(normalized) || seen.has(normalized)) continue;
|
|
661
|
-
seen.add(normalized);
|
|
662
|
-
result.push(normalized);
|
|
663
|
-
}
|
|
664
|
-
return result;
|
|
665
|
-
}
|
|
666
|
-
function resolveRelayConfig(fromFile, requestedRelayName) {
|
|
667
|
-
const profile = fromFile.profiles[PROFILE_NAME];
|
|
668
|
-
if (!profile) {
|
|
669
|
-
const available = Object.keys(fromFile.profiles).sort();
|
|
670
|
-
throw new Error(
|
|
671
|
-
`Unknown profile "${PROFILE_NAME}". Available profiles: ${available.length > 0 ? available.join(", ") : "(none)"}`
|
|
672
|
-
);
|
|
673
|
-
}
|
|
674
|
-
const relayName = requestedRelayName?.trim() || profile.relay?.trim();
|
|
675
|
-
if (!relayName) {
|
|
676
|
-
throw new Error(`Profile "${PROFILE_NAME}" must specify a relay.`);
|
|
677
|
-
}
|
|
678
|
-
const relay = fromFile.relays[relayName];
|
|
679
|
-
if (!relay) {
|
|
680
|
-
const available = Object.keys(fromFile.relays).sort();
|
|
681
|
-
throw new Error(
|
|
682
|
-
`Unknown relay "${relayName}". Available relays: ${available.length > 0 ? available.join(", ") : "(none)"}`
|
|
683
|
-
);
|
|
684
|
-
}
|
|
685
|
-
return {
|
|
686
|
-
relayName,
|
|
687
|
-
relayNameSource: requestedRelayName?.trim() ? "cli" : "profile",
|
|
688
|
-
relay
|
|
689
|
-
};
|
|
690
|
-
}
|
|
691
|
-
function loadConfig(options) {
|
|
692
|
-
const fromFile = readConfigFile();
|
|
693
|
-
const agentCli = fromFile.agentCli ?? {};
|
|
694
|
-
const resolved = resolveRelayConfig(fromFile, options?.relayName);
|
|
695
|
-
const claudeBin = process.env.CLAUDE_BIN ?? agentCli.claudeBin;
|
|
696
|
-
const codexBin = process.env.CODEX_BIN ?? agentCli.codexBin;
|
|
697
|
-
const config = {
|
|
698
|
-
profileName: PROFILE_NAME,
|
|
699
|
-
relayName: resolved.relayName,
|
|
700
|
-
relayUrl: process.env.RELAY_URL ?? resolved.relay.url,
|
|
701
|
-
relayToken: process.env.RELAY_PROXY_TOKEN ?? resolved.relay.proxyToken,
|
|
702
|
-
hookPort: parsePort(process.env.DEV_ANYWHERE_HOOK_PORT, "DEV_ANYWHERE_HOOK_PORT") ?? defaultHookPortForProfile(PROFILE_NAME),
|
|
703
|
-
claudeBin,
|
|
704
|
-
codexBin,
|
|
705
|
-
previewRoots: uniqueAbsolutePaths(fromFile.previewRoots ?? []),
|
|
706
|
-
agentCliSuggestions: {
|
|
707
|
-
claude: uniqueAbsolutePaths([
|
|
708
|
-
process.env.CLAUDE_BIN,
|
|
709
|
-
agentCli.claudeBin,
|
|
710
|
-
...agentCli.claudeBinHistory ?? []
|
|
711
|
-
]),
|
|
712
|
-
codex: uniqueAbsolutePaths([
|
|
713
|
-
process.env.CODEX_BIN,
|
|
714
|
-
agentCli.codexBin,
|
|
715
|
-
...agentCli.codexBinHistory ?? []
|
|
716
|
-
])
|
|
717
|
-
},
|
|
718
|
-
sources: {
|
|
719
|
-
relayName: resolved.relayNameSource,
|
|
720
|
-
relayUrl: process.env.RELAY_URL ? "env" : resolved.relay.url ? "file" : "none",
|
|
721
|
-
relayToken: process.env.RELAY_PROXY_TOKEN ? "env" : resolved.relay.proxyToken ? "file" : "none",
|
|
722
|
-
hookPort: process.env.DEV_ANYWHERE_HOOK_PORT ? "env" : "default",
|
|
723
|
-
claudeBin: process.env.CLAUDE_BIN ? "env" : agentCli.claudeBin ? "file" : "none",
|
|
724
|
-
codexBin: process.env.CODEX_BIN ? "env" : agentCli.codexBin ? "file" : "none"
|
|
725
|
-
}
|
|
726
|
-
};
|
|
727
|
-
serviceLogger.info(
|
|
728
|
-
{
|
|
729
|
-
profile: config.profileName,
|
|
730
|
-
relayName: config.relayName,
|
|
731
|
-
relayNameSource: config.sources.relayName,
|
|
732
|
-
relayUrl: config.relayUrl ?? "(unset)",
|
|
733
|
-
relayUrlSource: config.sources.relayUrl,
|
|
734
|
-
relayTokenSource: config.sources.relayToken,
|
|
735
|
-
hookPort: config.hookPort,
|
|
736
|
-
hookPortSource: config.sources.hookPort,
|
|
737
|
-
claudeBinSource: config.sources.claudeBin,
|
|
738
|
-
codexBinSource: config.sources.codexBin
|
|
739
|
-
},
|
|
740
|
-
"Config loaded"
|
|
741
|
-
);
|
|
742
|
-
return config;
|
|
743
|
-
}
|
|
744
|
-
function buildProviderEnv(config, baseEnv = process.env) {
|
|
745
|
-
return {
|
|
746
|
-
...baseEnv,
|
|
747
|
-
...config.claudeBin ? { CLAUDE_BIN: config.claudeBin } : {},
|
|
748
|
-
...config.codexBin ? { CODEX_BIN: config.codexBin } : {}
|
|
749
|
-
};
|
|
750
|
-
}
|
|
751
|
-
function updateAgentCliConfig(config, provider, path) {
|
|
752
|
-
const field = agentCliField(provider);
|
|
753
|
-
const historyField = agentCliHistoryField(provider);
|
|
754
|
-
const history = uniqueAbsolutePaths([path, ...config[historyField] ?? []]).slice(0, 8);
|
|
755
|
-
return {
|
|
756
|
-
...config,
|
|
757
|
-
[field]: path,
|
|
758
|
-
[historyField]: history
|
|
759
|
-
};
|
|
760
|
-
}
|
|
761
|
-
function saveAgentCliPath(provider, path) {
|
|
762
|
-
const normalized = validateAgentCliPath(path);
|
|
763
|
-
const fromFile = readConfigFile();
|
|
764
|
-
fromFile.agentCli = updateAgentCliConfig(fromFile.agentCli ?? {}, provider, normalized);
|
|
765
|
-
mkdirSync3(dirname3(CONFIG_PATH), { recursive: true });
|
|
766
|
-
writeFileSync3(CONFIG_PATH, `${JSON.stringify(fromFile, null, 2)}
|
|
767
|
-
`, "utf-8");
|
|
768
|
-
}
|
|
769
|
-
|
|
770
624
|
// src/serve/handlers/control-messages.ts
|
|
771
625
|
import { readdir as readdir2, mkdir } from "fs/promises";
|
|
772
|
-
import { join as join4, isAbsolute
|
|
626
|
+
import { join as join4, isAbsolute, normalize } from "path";
|
|
773
627
|
|
|
774
628
|
// src/serve/session-history.ts
|
|
775
629
|
import { readdir, stat, access, open } from "fs/promises";
|
|
@@ -1181,7 +1035,7 @@ function extractCodexUserText(payload) {
|
|
|
1181
1035
|
}
|
|
1182
1036
|
|
|
1183
1037
|
// src/serve/command-discovery.ts
|
|
1184
|
-
import { readdirSync, readFileSync as
|
|
1038
|
+
import { readdirSync, readFileSync as readFileSync3 } from "fs";
|
|
1185
1039
|
import { homedir as homedir3 } from "os";
|
|
1186
1040
|
import { join as join3 } from "path";
|
|
1187
1041
|
var REPL_BUILTINS = [
|
|
@@ -1257,7 +1111,7 @@ function scanSkillsDir(dirPath, source) {
|
|
|
1257
1111
|
for (const name of entries) {
|
|
1258
1112
|
const skillPath = join3(dirPath, name, "SKILL.md");
|
|
1259
1113
|
try {
|
|
1260
|
-
const content =
|
|
1114
|
+
const content = readFileSync3(skillPath, "utf-8");
|
|
1261
1115
|
const parsed = parseSkillFrontmatter(content);
|
|
1262
1116
|
commands.push({
|
|
1263
1117
|
name: `/${parsed.name ?? name}`,
|
|
@@ -1281,7 +1135,7 @@ function scanCommandsDir(dirPath, source) {
|
|
|
1281
1135
|
for (const filename of entries) {
|
|
1282
1136
|
const cmdName = filename.replace(/\.md$/, "");
|
|
1283
1137
|
try {
|
|
1284
|
-
const content =
|
|
1138
|
+
const content = readFileSync3(join3(dirPath, filename), "utf-8");
|
|
1285
1139
|
const firstLine = content.split("\n")[0].trim();
|
|
1286
1140
|
commands.push({
|
|
1287
1141
|
name: `/${cmdName}`,
|
|
@@ -1360,7 +1214,7 @@ function classifyPathError(err) {
|
|
|
1360
1214
|
// src/serve/handlers/control-messages.ts
|
|
1361
1215
|
var COMMAND_REFRESH_MS = 6 * 60 * 60 * 1e3;
|
|
1362
1216
|
function isPathSafe(path) {
|
|
1363
|
-
if (!
|
|
1217
|
+
if (!isAbsolute(path)) return false;
|
|
1364
1218
|
const normalized = normalize(path);
|
|
1365
1219
|
if (normalized.includes("..")) return false;
|
|
1366
1220
|
return true;
|
|
@@ -1656,7 +1510,7 @@ function createControlMessageHandlers(send, sessionManager) {
|
|
|
1656
1510
|
|
|
1657
1511
|
// src/serve/worker-registry.ts
|
|
1658
1512
|
import { connect } from "net";
|
|
1659
|
-
import { unlinkSync, existsSync as
|
|
1513
|
+
import { unlinkSync, existsSync as existsSync3, readdirSync as readdirSync2 } from "fs";
|
|
1660
1514
|
var WorkerRegistry = class {
|
|
1661
1515
|
constructor(deps) {
|
|
1662
1516
|
this.deps = deps;
|
|
@@ -1741,12 +1595,12 @@ var WorkerRegistry = class {
|
|
|
1741
1595
|
}
|
|
1742
1596
|
// 枚举 DATA_DIR 下所有 session 目录,尝试连接存活的 worker.sock;失败则清理 stale socket。
|
|
1743
1597
|
async reconnectAll() {
|
|
1744
|
-
if (!
|
|
1598
|
+
if (!existsSync3(DATA_DIR)) return;
|
|
1745
1599
|
const dirs = readdirSync2(DATA_DIR, { withFileTypes: true }).filter((d) => d.isDirectory());
|
|
1746
1600
|
for (const dir of dirs) {
|
|
1747
1601
|
const sessionId = dir.name;
|
|
1748
1602
|
const paths = sessionPaths(sessionId);
|
|
1749
|
-
if (!
|
|
1603
|
+
if (!existsSync3(paths.workerSock)) continue;
|
|
1750
1604
|
const sock = await this.connect(sessionId, paths.workerSock);
|
|
1751
1605
|
if (sock) {
|
|
1752
1606
|
if (!this.deps.sessionManager.getSession(sessionId)) {
|
|
@@ -2061,8 +1915,8 @@ function terminateSessionByOwnership(deps, sessionId) {
|
|
|
2061
1915
|
}
|
|
2062
1916
|
|
|
2063
1917
|
// src/serve/clipboard-image-upload.ts
|
|
2064
|
-
import { existsSync as
|
|
2065
|
-
import { isAbsolute as
|
|
1918
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync4, statSync, writeFileSync as writeFileSync3 } from "fs";
|
|
1919
|
+
import { isAbsolute as isAbsolute2, join as join5, relative, resolve } from "path";
|
|
2066
1920
|
import { nanoid as nanoid3 } from "nanoid";
|
|
2067
1921
|
var MAX_CLIPBOARD_IMAGE_BYTES = 10 * 1024 * 1024;
|
|
2068
1922
|
var MAX_CLIPBOARD_IMAGE_BASE64_LENGTH = Math.ceil(MAX_CLIPBOARD_IMAGE_BYTES / 3) * 4;
|
|
@@ -2098,7 +1952,7 @@ function resolveChildDir(rootPath, ...segments) {
|
|
|
2098
1952
|
const root = resolve(rootPath);
|
|
2099
1953
|
const uploadDir = resolve(root, ...segments);
|
|
2100
1954
|
const relativePath = relative(root, uploadDir);
|
|
2101
|
-
if (!relativePath || relativePath.startsWith("..") ||
|
|
1955
|
+
if (!relativePath || relativePath.startsWith("..") || isAbsolute2(relativePath)) {
|
|
2102
1956
|
throw new Error("\u4F1A\u8BDD\u8DEF\u5F84\u65E0\u6548");
|
|
2103
1957
|
}
|
|
2104
1958
|
return uploadDir;
|
|
@@ -2111,13 +1965,13 @@ function normalizeGitignoreLine(line) {
|
|
|
2111
1965
|
}
|
|
2112
1966
|
function ensureProjectClipboardIgnored(cwd) {
|
|
2113
1967
|
const gitignorePath = join5(cwd, ".gitignore");
|
|
2114
|
-
if (!
|
|
1968
|
+
if (!existsSync4(gitignorePath)) return;
|
|
2115
1969
|
try {
|
|
2116
|
-
const current =
|
|
1970
|
+
const current = readFileSync4(gitignorePath, "utf-8");
|
|
2117
1971
|
const alreadyIgnored = current.split(/\r?\n/).some((line) => normalizeGitignoreLine(line) === ".dev-anywhere");
|
|
2118
1972
|
if (alreadyIgnored) return;
|
|
2119
1973
|
const separator = current.length > 0 && !current.endsWith("\n") ? "\n" : "";
|
|
2120
|
-
|
|
1974
|
+
writeFileSync3(gitignorePath, `${current}${separator}.dev-anywhere/
|
|
2121
1975
|
`);
|
|
2122
1976
|
} catch {
|
|
2123
1977
|
}
|
|
@@ -2130,8 +1984,8 @@ function trySaveProjectClipboardImage(options) {
|
|
|
2130
1984
|
const clipboardRoot = resolve(cwd, ".dev-anywhere", "clipboard");
|
|
2131
1985
|
const uploadDir = resolveChildDir(clipboardRoot, options.sessionId);
|
|
2132
1986
|
const path = join5(uploadDir, options.fileName);
|
|
2133
|
-
|
|
2134
|
-
|
|
1987
|
+
mkdirSync3(uploadDir, { recursive: true });
|
|
1988
|
+
writeFileSync3(path, options.buffer, { mode: 384 });
|
|
2135
1989
|
ensureProjectClipboardIgnored(cwd);
|
|
2136
1990
|
return { success: true, path: relative(cwd, path) };
|
|
2137
1991
|
} catch {
|
|
@@ -2163,8 +2017,8 @@ function saveClipboardImageUpload(request, options = {}) {
|
|
|
2163
2017
|
const dataDir = options.dataDir ?? DATA_DIR;
|
|
2164
2018
|
const uploadDir = resolveSessionClipboardDir(dataDir, request.sessionId);
|
|
2165
2019
|
const path = join5(uploadDir, fileName);
|
|
2166
|
-
|
|
2167
|
-
|
|
2020
|
+
mkdirSync3(uploadDir, { recursive: true });
|
|
2021
|
+
writeFileSync3(path, buffer, { mode: 384 });
|
|
2168
2022
|
return { success: true, path };
|
|
2169
2023
|
} catch (err) {
|
|
2170
2024
|
return {
|
|
@@ -2177,13 +2031,13 @@ function saveClipboardImageUpload(request, options = {}) {
|
|
|
2177
2031
|
}
|
|
2178
2032
|
|
|
2179
2033
|
// src/serve/image-preview.ts
|
|
2180
|
-
import { readFileSync as
|
|
2034
|
+
import { readFileSync as readFileSync5, realpathSync, statSync as statSync2 } from "fs";
|
|
2181
2035
|
import { tmpdir } from "os";
|
|
2182
|
-
import { isAbsolute as
|
|
2036
|
+
import { isAbsolute as isAbsolute3, relative as relative2, resolve as resolve2 } from "path";
|
|
2183
2037
|
var MAX_IMAGE_PREVIEW_BYTES = 10 * 1024 * 1024;
|
|
2184
2038
|
function isInsideRoot(realFilePath, realRootPath) {
|
|
2185
2039
|
const rel = relative2(realRootPath, realFilePath);
|
|
2186
|
-
return rel === "" || !rel.startsWith("..") && !
|
|
2040
|
+
return rel === "" || !rel.startsWith("..") && !isAbsolute3(rel);
|
|
2187
2041
|
}
|
|
2188
2042
|
function allowedRoots(options) {
|
|
2189
2043
|
return [options.cwd, options.tmpDir ?? tmpdir(), ...options.previewRoots ?? []].map((root) => root.trim()).filter(Boolean).flatMap((root) => {
|
|
@@ -2195,7 +2049,7 @@ function allowedRoots(options) {
|
|
|
2195
2049
|
});
|
|
2196
2050
|
}
|
|
2197
2051
|
function resolvePreviewPath(rawPath, options) {
|
|
2198
|
-
const candidate =
|
|
2052
|
+
const candidate = isAbsolute3(rawPath) ? resolve2(rawPath) : resolve2(options.cwd, rawPath);
|
|
2199
2053
|
const realCandidate = realpathSync(candidate);
|
|
2200
2054
|
if (!allowedRoots(options).some((root) => isInsideRoot(realCandidate, root))) {
|
|
2201
2055
|
throw Object.assign(new Error("\u56FE\u7247\u8DEF\u5F84\u4E0D\u5728\u5141\u8BB8\u9884\u89C8\u7684\u76EE\u5F55\u5185"), {
|
|
@@ -2248,7 +2102,7 @@ function loadImagePreview(request, options) {
|
|
|
2248
2102
|
errorCode: ControlErrorCode.UNKNOWN
|
|
2249
2103
|
};
|
|
2250
2104
|
}
|
|
2251
|
-
const buffer =
|
|
2105
|
+
const buffer = readFileSync5(resolvedPath);
|
|
2252
2106
|
const mimeType = detectImageMime(buffer);
|
|
2253
2107
|
if (!mimeType) {
|
|
2254
2108
|
return {
|
|
@@ -2745,7 +2599,7 @@ var RelayResourceHandlers = class {
|
|
|
2745
2599
|
|
|
2746
2600
|
// src/serve/relay-session-create-handler.ts
|
|
2747
2601
|
import { rmSync, statSync as statSync4 } from "fs";
|
|
2748
|
-
import { isAbsolute as
|
|
2602
|
+
import { isAbsolute as isAbsolute4 } from "path";
|
|
2749
2603
|
import { nanoid as nanoid4 } from "nanoid";
|
|
2750
2604
|
|
|
2751
2605
|
// src/serve/hosted-pty-registry.ts
|
|
@@ -3035,7 +2889,7 @@ function validateSessionCwd(cwd) {
|
|
|
3035
2889
|
return { message: "\u8BF7\u8F93\u5165\u5DE5\u4F5C\u76EE\u5F55", code: ControlErrorCode.INVALID_PATH };
|
|
3036
2890
|
}
|
|
3037
2891
|
const trimmed = cwd.trim();
|
|
3038
|
-
if (!
|
|
2892
|
+
if (!isAbsolute4(trimmed)) {
|
|
3039
2893
|
return { message: "\u5DE5\u4F5C\u76EE\u5F55\u5FC5\u987B\u662F\u7EDD\u5BF9\u8DEF\u5F84", code: ControlErrorCode.INVALID_PATH };
|
|
3040
2894
|
}
|
|
3041
2895
|
try {
|
|
@@ -3837,7 +3691,7 @@ function touchSessionActivity(sessionManager, relay, sessionId, now = Date.now()
|
|
|
3837
3691
|
|
|
3838
3692
|
// src/serve/service-files.ts
|
|
3839
3693
|
import { execSync } from "child_process";
|
|
3840
|
-
import { existsSync as
|
|
3694
|
+
import { existsSync as existsSync5, readFileSync as readFileSync6, unlinkSync as unlinkSync2 } from "fs";
|
|
3841
3695
|
import { hostname } from "os";
|
|
3842
3696
|
import { connect as connect2 } from "net";
|
|
3843
3697
|
function tryConnectSocket(sockPath) {
|
|
@@ -3856,7 +3710,7 @@ function isProcessAlive(pid) {
|
|
|
3856
3710
|
}
|
|
3857
3711
|
}
|
|
3858
3712
|
async function cleanupStaleResources() {
|
|
3859
|
-
if (
|
|
3713
|
+
if (existsSync5(SOCK_PATH)) {
|
|
3860
3714
|
const existing = await tryConnectSocket(SOCK_PATH);
|
|
3861
3715
|
if (existing) {
|
|
3862
3716
|
existing.destroy();
|
|
@@ -3868,8 +3722,8 @@ async function cleanupStaleResources() {
|
|
|
3868
3722
|
unlinkSync2(SOCK_PATH);
|
|
3869
3723
|
serviceLogger.info("Removed stale socket file");
|
|
3870
3724
|
}
|
|
3871
|
-
if (
|
|
3872
|
-
const pidStr =
|
|
3725
|
+
if (existsSync5(PID_PATH)) {
|
|
3726
|
+
const pidStr = readFileSync6(PID_PATH, "utf-8").trim();
|
|
3873
3727
|
const pid = parseInt(pidStr, 10);
|
|
3874
3728
|
if (!isNaN(pid) && isProcessAlive(pid)) {
|
|
3875
3729
|
const msg = `Another service is already running with PID ${pid}`;
|
|
@@ -4244,8 +4098,8 @@ function handleTerminalConnection(socket, deps) {
|
|
|
4244
4098
|
|
|
4245
4099
|
// src/serve/hook-registry.ts
|
|
4246
4100
|
import { createHash, randomBytes } from "crypto";
|
|
4247
|
-
import { existsSync as
|
|
4248
|
-
import { dirname as
|
|
4101
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync4, readFileSync as readFileSync7, renameSync as renameSync2, writeFileSync as writeFileSync4 } from "fs";
|
|
4102
|
+
import { dirname as dirname3 } from "path";
|
|
4249
4103
|
import { z } from "zod";
|
|
4250
4104
|
var PersistedHookSessionBindingSchema = z.object({
|
|
4251
4105
|
sessionId: z.string(),
|
|
@@ -4305,10 +4159,10 @@ var HookRegistry = class {
|
|
|
4305
4159
|
}
|
|
4306
4160
|
}
|
|
4307
4161
|
load() {
|
|
4308
|
-
if (!this.persistPath || !
|
|
4162
|
+
if (!this.persistPath || !existsSync6(this.persistPath)) return;
|
|
4309
4163
|
try {
|
|
4310
4164
|
const parsed = PersistedHookRegistrySchema.parse(
|
|
4311
|
-
JSON.parse(
|
|
4165
|
+
JSON.parse(readFileSync7(this.persistPath, "utf8"))
|
|
4312
4166
|
);
|
|
4313
4167
|
this.bindingsBySession.clear();
|
|
4314
4168
|
for (const binding of parsed.bindings) {
|
|
@@ -4324,9 +4178,9 @@ var HookRegistry = class {
|
|
|
4324
4178
|
save() {
|
|
4325
4179
|
if (!this.persistPath) return;
|
|
4326
4180
|
try {
|
|
4327
|
-
|
|
4181
|
+
mkdirSync4(dirname3(this.persistPath), { recursive: true });
|
|
4328
4182
|
const tmpPath = `${this.persistPath}.${process.pid}.${Date.now()}.tmp`;
|
|
4329
|
-
|
|
4183
|
+
writeFileSync4(
|
|
4330
4184
|
tmpPath,
|
|
4331
4185
|
JSON.stringify(
|
|
4332
4186
|
{
|
|
@@ -4842,7 +4696,7 @@ async function startService(options) {
|
|
|
4842
4696
|
});
|
|
4843
4697
|
});
|
|
4844
4698
|
server.listen(SOCK_PATH, () => {
|
|
4845
|
-
|
|
4699
|
+
writeFileSync5(PID_PATH, String(process.pid));
|
|
4846
4700
|
chmodSync(SOCK_PATH, 384);
|
|
4847
4701
|
serviceLogger.info({ pid: process.pid, sock: SOCK_PATH }, "Service started");
|
|
4848
4702
|
});
|