claude-codex-wechat 0.1.56 → 0.1.58
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/mcp/mediaServer.js +79 -44
- package/dist/server/cli.js +362 -274
- package/package.json +1 -1
package/dist/server/cli.js
CHANGED
|
@@ -3,18 +3,118 @@ import { createRequire as __cjsCreateRequire } from 'node:module'; const require
|
|
|
3
3
|
|
|
4
4
|
// src/cli.ts
|
|
5
5
|
import { execFile as execFile2 } from "node:child_process";
|
|
6
|
-
import { existsSync as
|
|
6
|
+
import { existsSync as existsSync12, readFileSync as readFileSync10 } from "node:fs";
|
|
7
7
|
import { promisify as promisify2 } from "node:util";
|
|
8
|
-
import { dirname as dirname10, join as
|
|
8
|
+
import { dirname as dirname10, join as join16 } from "node:path";
|
|
9
9
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
10
10
|
|
|
11
11
|
// src/daemon/bootstrap.ts
|
|
12
12
|
import { networkInterfaces } from "node:os";
|
|
13
13
|
|
|
14
14
|
// src/daemon/server.ts
|
|
15
|
-
import { mkdtempSync, existsSync as
|
|
16
|
-
import { tmpdir as
|
|
17
|
-
import { dirname as dirname8, join as
|
|
15
|
+
import { mkdtempSync, existsSync as existsSync10, writeFileSync as writeFileSync2 } from "node:fs";
|
|
16
|
+
import { tmpdir as tmpdir3 } from "node:os";
|
|
17
|
+
import { dirname as dirname8, isAbsolute, join as join13 } from "node:path";
|
|
18
|
+
|
|
19
|
+
// src/daemon/mcpConfig.ts
|
|
20
|
+
import { createRequire } from "node:module";
|
|
21
|
+
|
|
22
|
+
// src/shared/platform.ts
|
|
23
|
+
import { access, constants } from "node:fs/promises";
|
|
24
|
+
import { delimiter, join } from "node:path";
|
|
25
|
+
import { tmpdir } from "node:os";
|
|
26
|
+
import { spawn } from "node:child_process";
|
|
27
|
+
var isWindows = process.platform === "win32";
|
|
28
|
+
async function isExecutableFile(candidate) {
|
|
29
|
+
try {
|
|
30
|
+
await access(candidate, isWindows ? constants.F_OK : constants.X_OK);
|
|
31
|
+
return true;
|
|
32
|
+
} catch {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function executableExtensions() {
|
|
37
|
+
if (!isWindows) return [""];
|
|
38
|
+
const pathext = process.env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD";
|
|
39
|
+
return ["", ...pathext.split(";").filter(Boolean)];
|
|
40
|
+
}
|
|
41
|
+
function isTemporaryShim(candidate) {
|
|
42
|
+
const tempDir = tmpdir();
|
|
43
|
+
return candidate.startsWith(tempDir);
|
|
44
|
+
}
|
|
45
|
+
async function findExecutable(command, pathEnv) {
|
|
46
|
+
const extensions = executableExtensions();
|
|
47
|
+
if (command.includes("/") || command.includes("\\")) {
|
|
48
|
+
for (const ext of extensions) {
|
|
49
|
+
if (await isExecutableFile(command + ext)) return command + ext;
|
|
50
|
+
}
|
|
51
|
+
return void 0;
|
|
52
|
+
}
|
|
53
|
+
const dirs = (pathEnv ?? "").split(delimiter).filter(Boolean);
|
|
54
|
+
let fallback;
|
|
55
|
+
for (const dir of dirs) {
|
|
56
|
+
for (const ext of extensions) {
|
|
57
|
+
const candidate = join(dir, command + ext);
|
|
58
|
+
if (await isExecutableFile(candidate)) {
|
|
59
|
+
if (isTemporaryShim(candidate)) {
|
|
60
|
+
fallback ??= candidate;
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
return candidate;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return fallback;
|
|
68
|
+
}
|
|
69
|
+
function terminateChild(child, signal = "SIGTERM") {
|
|
70
|
+
if (child.pid === void 0 || child.exitCode !== null || child.signalCode !== null) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
if (isWindows) {
|
|
74
|
+
try {
|
|
75
|
+
spawn("taskkill", ["/pid", String(child.pid), "/T", "/F"], { stdio: "ignore" });
|
|
76
|
+
return;
|
|
77
|
+
} catch {
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
try {
|
|
81
|
+
child.kill(signal);
|
|
82
|
+
} catch {
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
function defaultWorkspaceDir() {
|
|
86
|
+
return join(tmpdir(), "project");
|
|
87
|
+
}
|
|
88
|
+
function useShellForCli() {
|
|
89
|
+
return isWindows;
|
|
90
|
+
}
|
|
91
|
+
function statePath(filename) {
|
|
92
|
+
return join(tmpdir(), filename);
|
|
93
|
+
}
|
|
94
|
+
function nodeExecutable() {
|
|
95
|
+
return process.execPath;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// src/daemon/mcpConfig.ts
|
|
99
|
+
function buildMcpServerCommand(input) {
|
|
100
|
+
if (input.exists(input.jsEntry)) {
|
|
101
|
+
return { command: nodeExecutable(), args: [input.jsEntry] };
|
|
102
|
+
}
|
|
103
|
+
const tsxCli = (input.resolveTsxCli ?? defaultResolveTsxCli)();
|
|
104
|
+
if (tsxCli) {
|
|
105
|
+
return { command: nodeExecutable(), args: [tsxCli, input.tsEntry] };
|
|
106
|
+
}
|
|
107
|
+
return { command: "tsx", args: [input.tsEntry] };
|
|
108
|
+
}
|
|
109
|
+
function defaultResolveTsxCli() {
|
|
110
|
+
try {
|
|
111
|
+
return createRequire(import.meta.url).resolve("tsx/dist/cli.mjs");
|
|
112
|
+
} catch {
|
|
113
|
+
return void 0;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// src/daemon/server.ts
|
|
18
118
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
19
119
|
import Fastify from "fastify";
|
|
20
120
|
|
|
@@ -69,9 +169,9 @@ var WeixinDirectLoginClient = class {
|
|
|
69
169
|
// src/daemon/config.ts
|
|
70
170
|
import { existsSync, readFileSync } from "node:fs";
|
|
71
171
|
import { homedir } from "node:os";
|
|
72
|
-
import { join } from "node:path";
|
|
172
|
+
import { join as join2 } from "node:path";
|
|
73
173
|
function defaultConfigPath() {
|
|
74
|
-
return
|
|
174
|
+
return join2(homedir(), ".claude-codex-wechat", "config.json");
|
|
75
175
|
}
|
|
76
176
|
function loadBridgeConfig(path = process.env.BRIDGE_CONFIG ?? defaultConfigPath()) {
|
|
77
177
|
if (!existsSync(path)) return normalizeBridgeConfig({}, process.env, path);
|
|
@@ -162,10 +262,10 @@ import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:f
|
|
|
162
262
|
import { closeSync, fsyncSync, mkdirSync, openSync, renameSync, unlinkSync, writeSync } from "node:fs";
|
|
163
263
|
import { mkdir, open, readdir, rename, stat, unlink } from "node:fs/promises";
|
|
164
264
|
import { randomBytes } from "node:crypto";
|
|
165
|
-
import { basename, dirname, join as
|
|
265
|
+
import { basename, dirname, join as join3 } from "node:path";
|
|
166
266
|
var FILE_MODE = 384;
|
|
167
267
|
function tempPathFor(path) {
|
|
168
|
-
return
|
|
268
|
+
return join3(dirname(path), `.${basename(path)}.${process.pid}.${randomBytes(6).toString("hex")}.tmp`);
|
|
169
269
|
}
|
|
170
270
|
var RENAME_RETRY_CODES = /* @__PURE__ */ new Set(["EPERM", "EACCES", "EBUSY"]);
|
|
171
271
|
var MAX_RENAME_RETRIES = 10;
|
|
@@ -178,8 +278,8 @@ function sleepSync(ms) {
|
|
|
178
278
|
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
179
279
|
}
|
|
180
280
|
function sleep(ms) {
|
|
181
|
-
return new Promise((
|
|
182
|
-
setTimeout(
|
|
281
|
+
return new Promise((resolve3) => {
|
|
282
|
+
setTimeout(resolve3, ms);
|
|
183
283
|
});
|
|
184
284
|
}
|
|
185
285
|
function writeFileAtomicSync(path, data) {
|
|
@@ -247,7 +347,7 @@ async function cleanupStaleTempFiles(targetPath, maxAgeMs = 36e5) {
|
|
|
247
347
|
const now = Date.now();
|
|
248
348
|
await Promise.all(entries.map(async (name) => {
|
|
249
349
|
if (!name.startsWith(prefix) || !name.endsWith(".tmp")) return;
|
|
250
|
-
const full =
|
|
350
|
+
const full = join3(dir, name);
|
|
251
351
|
try {
|
|
252
352
|
const info = await stat(full);
|
|
253
353
|
if (now - info.mtimeMs >= maxAgeMs) await unlink(full);
|
|
@@ -501,7 +601,7 @@ var FileWeixinStateStore = class {
|
|
|
501
601
|
// src/providers/claude-code/nativeSessions.ts
|
|
502
602
|
import { appendFile, mkdir as mkdir2, readdir as readdir2, readFile as readFile2, stat as stat2, unlink as unlink2, writeFile } from "node:fs/promises";
|
|
503
603
|
import { homedir as homedir2 } from "node:os";
|
|
504
|
-
import { basename as basename2, dirname as dirname2, join as
|
|
604
|
+
import { basename as basename2, dirname as dirname2, join as join4 } from "node:path";
|
|
505
605
|
|
|
506
606
|
// src/session/sessionBridgeTag.ts
|
|
507
607
|
function buildSessionBridgeName(input) {
|
|
@@ -528,7 +628,7 @@ function parseSessionBridgeName(value) {
|
|
|
528
628
|
|
|
529
629
|
// src/providers/claude-code/nativeSessions.ts
|
|
530
630
|
function resolveClaudeConfigDir(env = process.env) {
|
|
531
|
-
return
|
|
631
|
+
return join4(env.HOME || homedir2(), ".claude");
|
|
532
632
|
}
|
|
533
633
|
async function prepareClaudeSessionForResume(input) {
|
|
534
634
|
const env = input.env ?? process.env;
|
|
@@ -544,20 +644,20 @@ async function prepareClaudeSessionForResume(input) {
|
|
|
544
644
|
return { ok: true, adoptedBackground: true };
|
|
545
645
|
}
|
|
546
646
|
async function listRecoverableClaudeSessions(env = process.env) {
|
|
547
|
-
const projectsDir =
|
|
647
|
+
const projectsDir = join4(resolveClaudeConfigDir(env), "projects");
|
|
548
648
|
const historyIndex = await readClaudeHistoryIndex(env);
|
|
549
649
|
const candidates = [];
|
|
550
650
|
try {
|
|
551
651
|
const projectEntries = await readdir2(projectsDir, { withFileTypes: true });
|
|
552
652
|
for (const entry of projectEntries) {
|
|
553
653
|
if (!entry.isDirectory() || entry.isSymbolicLink()) continue;
|
|
554
|
-
const projectDir =
|
|
654
|
+
const projectDir = join4(projectsDir, String(entry.name));
|
|
555
655
|
const sessionEntries = await readdir2(projectDir, { withFileTypes: true }).catch(() => []);
|
|
556
656
|
for (const sessionEntry of sessionEntries) {
|
|
557
657
|
if (!sessionEntry.isFile() || sessionEntry.isSymbolicLink()) continue;
|
|
558
658
|
const fileName = String(sessionEntry.name);
|
|
559
659
|
if (!fileName.endsWith(".jsonl")) continue;
|
|
560
|
-
const filePath =
|
|
660
|
+
const filePath = join4(projectDir, fileName);
|
|
561
661
|
const metadata = await stat2(filePath).catch(() => null);
|
|
562
662
|
const parsedMeta = await readClaudeSessionMetadata(filePath).catch(() => null);
|
|
563
663
|
const historyMeta = historyIndex.get(basename2(fileName, ".jsonl"));
|
|
@@ -583,12 +683,12 @@ async function listRecoverableClaudeSessions(env = process.env) {
|
|
|
583
683
|
async function findRecoverableClaudeSessionPath(sessionId, env = process.env) {
|
|
584
684
|
const trimmed = sessionId.trim();
|
|
585
685
|
if (!trimmed || trimmed.includes("/") || trimmed.includes("\\")) return null;
|
|
586
|
-
const projectsDir =
|
|
686
|
+
const projectsDir = join4(resolveClaudeConfigDir(env), "projects");
|
|
587
687
|
try {
|
|
588
688
|
const projectEntries = await readdir2(projectsDir, { withFileTypes: true });
|
|
589
689
|
for (const entry of projectEntries) {
|
|
590
690
|
if (!entry.isDirectory() || entry.isSymbolicLink()) continue;
|
|
591
|
-
const sessionPath =
|
|
691
|
+
const sessionPath = join4(projectsDir, String(entry.name), `${trimmed}.jsonl`);
|
|
592
692
|
try {
|
|
593
693
|
const metadata = await stat2(sessionPath);
|
|
594
694
|
if (metadata.isFile()) return sessionPath;
|
|
@@ -636,7 +736,7 @@ async function hasClaudeSessionBridgeMetadata(input) {
|
|
|
636
736
|
}
|
|
637
737
|
async function hasClaudeHistoryDisplay(input) {
|
|
638
738
|
const env = input.env ?? process.env;
|
|
639
|
-
const historyPath =
|
|
739
|
+
const historyPath = join4(resolveClaudeConfigDir(env), "history.jsonl");
|
|
640
740
|
try {
|
|
641
741
|
const content = await readFile2(historyPath, "utf8");
|
|
642
742
|
for (const line of content.split(/\r?\n/)) {
|
|
@@ -701,13 +801,13 @@ async function readClaudeSessionMetadata(filePath) {
|
|
|
701
801
|
return { aiTitle, lastPrompt, sessionName, cwd };
|
|
702
802
|
}
|
|
703
803
|
async function readClaudeRuntimeSessionIndex(env) {
|
|
704
|
-
const sessionsDir =
|
|
804
|
+
const sessionsDir = join4(resolveClaudeConfigDir(env), "sessions");
|
|
705
805
|
const index = /* @__PURE__ */ new Map();
|
|
706
806
|
try {
|
|
707
807
|
const entries = await readdir2(sessionsDir, { withFileTypes: true });
|
|
708
808
|
for (const entry of entries) {
|
|
709
809
|
if (!entry.isFile() || entry.isSymbolicLink() || !String(entry.name).endsWith(".json")) continue;
|
|
710
|
-
const path =
|
|
810
|
+
const path = join4(sessionsDir, String(entry.name));
|
|
711
811
|
try {
|
|
712
812
|
const raw = await readFile2(path, "utf8");
|
|
713
813
|
const record = JSON.parse(raw);
|
|
@@ -725,7 +825,7 @@ async function readClaudeRuntimeSessionIndex(env) {
|
|
|
725
825
|
return index;
|
|
726
826
|
}
|
|
727
827
|
async function readClaudeHistoryIndex(env) {
|
|
728
|
-
const historyPath =
|
|
828
|
+
const historyPath = join4(resolveClaudeConfigDir(env), "history.jsonl");
|
|
729
829
|
const index = /* @__PURE__ */ new Map();
|
|
730
830
|
try {
|
|
731
831
|
const content = await readFile2(historyPath, "utf8");
|
|
@@ -750,7 +850,7 @@ async function readClaudeHistoryIndex(env) {
|
|
|
750
850
|
return index;
|
|
751
851
|
}
|
|
752
852
|
async function upsertClaudeHistoryDisplay(input) {
|
|
753
|
-
const historyPath =
|
|
853
|
+
const historyPath = join4(resolveClaudeConfigDir(input.env), "history.jsonl");
|
|
754
854
|
const lines = [];
|
|
755
855
|
let replaced = false;
|
|
756
856
|
let changed = false;
|
|
@@ -840,9 +940,9 @@ import Database from "better-sqlite3";
|
|
|
840
940
|
import { readdir as readdir3, readFile as readFile3, stat as stat3 } from "node:fs/promises";
|
|
841
941
|
import { existsSync as existsSync4 } from "node:fs";
|
|
842
942
|
import { homedir as homedir3 } from "node:os";
|
|
843
|
-
import { basename as basename3, join as
|
|
943
|
+
import { basename as basename3, join as join5 } from "node:path";
|
|
844
944
|
function resolveCodexSessionsRoot(env = process.env) {
|
|
845
|
-
return
|
|
945
|
+
return join5(env.CODEX_HOME || join5(env.HOME || homedir3(), ".codex"), "sessions");
|
|
846
946
|
}
|
|
847
947
|
function isMatchingCodexRolloutFile(name) {
|
|
848
948
|
return name.startsWith("rollout-") && name.endsWith(".jsonl");
|
|
@@ -865,7 +965,7 @@ async function listRecoverableCodexSessions(env = process.env) {
|
|
|
865
965
|
for (const entry of entries) {
|
|
866
966
|
if (entry.isSymbolicLink()) continue;
|
|
867
967
|
const name = String(entry.name);
|
|
868
|
-
const path =
|
|
968
|
+
const path = join5(currentDir, name);
|
|
869
969
|
if (entry.isDirectory()) {
|
|
870
970
|
await walk(path, depth + 1);
|
|
871
971
|
continue;
|
|
@@ -901,7 +1001,7 @@ async function findRecoverableCodexSessionPath(sessionId, env = process.env) {
|
|
|
901
1001
|
for (const entry of entries) {
|
|
902
1002
|
if (entry.isSymbolicLink()) continue;
|
|
903
1003
|
const name = String(entry.name);
|
|
904
|
-
const path =
|
|
1004
|
+
const path = join5(currentDir, name);
|
|
905
1005
|
if (entry.isDirectory()) {
|
|
906
1006
|
const found = await walk(path, depth + 1);
|
|
907
1007
|
if (found) return found;
|
|
@@ -925,7 +1025,7 @@ async function getCodexNativeVersion(input) {
|
|
|
925
1025
|
};
|
|
926
1026
|
}
|
|
927
1027
|
async function readCodexSessionIndex(env) {
|
|
928
|
-
const indexPath =
|
|
1028
|
+
const indexPath = join5(env.CODEX_HOME || join5(env.HOME || homedir3(), ".codex"), "session_index.jsonl");
|
|
929
1029
|
const index = /* @__PURE__ */ new Map();
|
|
930
1030
|
try {
|
|
931
1031
|
const content = await readFile3(indexPath, "utf8");
|
|
@@ -948,7 +1048,7 @@ async function readCodexSessionIndex(env) {
|
|
|
948
1048
|
return index;
|
|
949
1049
|
}
|
|
950
1050
|
function readCodexThreadMetadata(env) {
|
|
951
|
-
const dbPath =
|
|
1051
|
+
const dbPath = join5(env.CODEX_HOME || join5(env.HOME || homedir3(), ".codex"), "state_5.sqlite");
|
|
952
1052
|
const metadata = /* @__PURE__ */ new Map();
|
|
953
1053
|
if (!existsSync4(dbPath)) return metadata;
|
|
954
1054
|
let db = null;
|
|
@@ -1009,9 +1109,9 @@ import { nanoid } from "nanoid";
|
|
|
1009
1109
|
// src/providers/codex/sessionIndex.ts
|
|
1010
1110
|
import { mkdir as mkdir3, readFile as readFile4, writeFile as writeFile2 } from "node:fs/promises";
|
|
1011
1111
|
import { homedir as homedir4 } from "node:os";
|
|
1012
|
-
import { dirname as dirname3, join as
|
|
1112
|
+
import { dirname as dirname3, join as join6 } from "node:path";
|
|
1013
1113
|
function resolveCodexIndexPath(env = process.env) {
|
|
1014
|
-
return
|
|
1114
|
+
return join6(env.CODEX_HOME || join6(env.HOME || homedir4(), ".codex"), "session_index.jsonl");
|
|
1015
1115
|
}
|
|
1016
1116
|
async function upsertCodexSessionIndexEntry(input, env = process.env) {
|
|
1017
1117
|
const indexPath = resolveCodexIndexPath(env);
|
|
@@ -1057,9 +1157,9 @@ import Database2 from "better-sqlite3";
|
|
|
1057
1157
|
import { existsSync as existsSync5 } from "node:fs";
|
|
1058
1158
|
import { readFile as readFile5, writeFile as writeFile3 } from "node:fs/promises";
|
|
1059
1159
|
import { homedir as homedir5 } from "node:os";
|
|
1060
|
-
import { join as
|
|
1160
|
+
import { join as join7 } from "node:path";
|
|
1061
1161
|
function resolveCodexStateDbPath(env = process.env) {
|
|
1062
|
-
return
|
|
1162
|
+
return join7(env.CODEX_HOME || join7(env.HOME || homedir5(), ".codex"), "state_5.sqlite");
|
|
1063
1163
|
}
|
|
1064
1164
|
async function syncCodexThreadForResume(input) {
|
|
1065
1165
|
const env = input.env ?? process.env;
|
|
@@ -1120,7 +1220,7 @@ async function syncCodexRolloutSessionMeta(rolloutPath) {
|
|
|
1120
1220
|
}
|
|
1121
1221
|
}
|
|
1122
1222
|
async function delay(ms) {
|
|
1123
|
-
await new Promise((
|
|
1223
|
+
await new Promise((resolve3) => setTimeout(resolve3, ms));
|
|
1124
1224
|
}
|
|
1125
1225
|
|
|
1126
1226
|
// src/session/providerAutoAttach.ts
|
|
@@ -1301,7 +1401,7 @@ function registerChannelAdminRoutes(input) {
|
|
|
1301
1401
|
|
|
1302
1402
|
`);
|
|
1303
1403
|
while (true) {
|
|
1304
|
-
await new Promise((
|
|
1404
|
+
await new Promise((resolve3) => setTimeout(resolve3, client.pollIntervalMs));
|
|
1305
1405
|
const status = await client.pollQrCodeStatus(qr.ticket);
|
|
1306
1406
|
if (status.status === "waiting") continue;
|
|
1307
1407
|
if (status.status === "scanned") {
|
|
@@ -1741,7 +1841,7 @@ function normalizeSettings(input, defaultWorkspace) {
|
|
|
1741
1841
|
// src/admin/fsBrowseRoutes.ts
|
|
1742
1842
|
import { readdir as readdir4 } from "node:fs/promises";
|
|
1743
1843
|
import { homedir as homedir7 } from "node:os";
|
|
1744
|
-
import { dirname as dirname4, join as
|
|
1844
|
+
import { dirname as dirname4, join as join8, resolve } from "node:path";
|
|
1745
1845
|
|
|
1746
1846
|
// src/shared/expandTilde.ts
|
|
1747
1847
|
import { homedir as homedir6 } from "node:os";
|
|
@@ -1767,7 +1867,7 @@ function registerFsBrowseRoutes(input) {
|
|
|
1767
1867
|
reply.code(400);
|
|
1768
1868
|
return { error: "cannot_read_directory", path: target };
|
|
1769
1869
|
}
|
|
1770
|
-
const entries = dirents.filter((dirent) => dirent.isDirectory()).map((dirent) => ({ name: dirent.name, path:
|
|
1870
|
+
const entries = dirents.filter((dirent) => dirent.isDirectory()).map((dirent) => ({ name: dirent.name, path: join8(target, dirent.name), isDirectory: true })).filter((entry) => !entry.name.startsWith(".") || isOnKeepChain(entry.path)).sort((a, b) => a.name.localeCompare(b.name));
|
|
1771
1871
|
const parent = dirname4(target);
|
|
1772
1872
|
const isRoot = parent === target;
|
|
1773
1873
|
const listing = {
|
|
@@ -2048,7 +2148,7 @@ var WeixinDirectApiClient = class {
|
|
|
2048
2148
|
|
|
2049
2149
|
// src/channels/weixin-direct/adapter.ts
|
|
2050
2150
|
import { setTimeout as delay2 } from "node:timers/promises";
|
|
2051
|
-
import { join as
|
|
2151
|
+
import { join as join9 } from "node:path";
|
|
2052
2152
|
|
|
2053
2153
|
// src/channels/weixin-direct/typingController.ts
|
|
2054
2154
|
var CONFIG_CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
@@ -2344,7 +2444,7 @@ var WeixinDirectAdapter = class _WeixinDirectAdapter {
|
|
|
2344
2444
|
continue;
|
|
2345
2445
|
}
|
|
2346
2446
|
const { ext, mimeType } = mediaExtAndMime(meta);
|
|
2347
|
-
const destPath =
|
|
2447
|
+
const destPath = join9(mediaDir, `${idPrefix}_${i}${ext}`);
|
|
2348
2448
|
const maxBytes = meta.kind === "video" ? VIDEO_MAX_BYTES : void 0;
|
|
2349
2449
|
const result = await downloader.download(meta.media ?? {}, { destPath, aeskeyOverride: meta.aeskey, maxBytes });
|
|
2350
2450
|
if (result.ok) {
|
|
@@ -2875,79 +2975,6 @@ function stamp(item) {
|
|
|
2875
2975
|
import { spawn as spawn3 } from "node:child_process";
|
|
2876
2976
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
2877
2977
|
|
|
2878
|
-
// src/shared/platform.ts
|
|
2879
|
-
import { access, constants } from "node:fs/promises";
|
|
2880
|
-
import { delimiter, join as join9 } from "node:path";
|
|
2881
|
-
import { tmpdir } from "node:os";
|
|
2882
|
-
import { spawn } from "node:child_process";
|
|
2883
|
-
var isWindows = process.platform === "win32";
|
|
2884
|
-
async function isExecutableFile(candidate) {
|
|
2885
|
-
try {
|
|
2886
|
-
await access(candidate, isWindows ? constants.F_OK : constants.X_OK);
|
|
2887
|
-
return true;
|
|
2888
|
-
} catch {
|
|
2889
|
-
return false;
|
|
2890
|
-
}
|
|
2891
|
-
}
|
|
2892
|
-
function executableExtensions() {
|
|
2893
|
-
if (!isWindows) return [""];
|
|
2894
|
-
const pathext = process.env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD";
|
|
2895
|
-
return ["", ...pathext.split(";").filter(Boolean)];
|
|
2896
|
-
}
|
|
2897
|
-
function isTemporaryShim(candidate) {
|
|
2898
|
-
const tempDir = tmpdir();
|
|
2899
|
-
return candidate.startsWith(tempDir);
|
|
2900
|
-
}
|
|
2901
|
-
async function findExecutable(command, pathEnv) {
|
|
2902
|
-
const extensions = executableExtensions();
|
|
2903
|
-
if (command.includes("/") || command.includes("\\")) {
|
|
2904
|
-
for (const ext of extensions) {
|
|
2905
|
-
if (await isExecutableFile(command + ext)) return command + ext;
|
|
2906
|
-
}
|
|
2907
|
-
return void 0;
|
|
2908
|
-
}
|
|
2909
|
-
const dirs = (pathEnv ?? "").split(delimiter).filter(Boolean);
|
|
2910
|
-
let fallback;
|
|
2911
|
-
for (const dir of dirs) {
|
|
2912
|
-
for (const ext of extensions) {
|
|
2913
|
-
const candidate = join9(dir, command + ext);
|
|
2914
|
-
if (await isExecutableFile(candidate)) {
|
|
2915
|
-
if (isTemporaryShim(candidate)) {
|
|
2916
|
-
fallback ??= candidate;
|
|
2917
|
-
continue;
|
|
2918
|
-
}
|
|
2919
|
-
return candidate;
|
|
2920
|
-
}
|
|
2921
|
-
}
|
|
2922
|
-
}
|
|
2923
|
-
return fallback;
|
|
2924
|
-
}
|
|
2925
|
-
function terminateChild(child, signal = "SIGTERM") {
|
|
2926
|
-
if (child.pid === void 0 || child.exitCode !== null || child.signalCode !== null) {
|
|
2927
|
-
return;
|
|
2928
|
-
}
|
|
2929
|
-
if (isWindows) {
|
|
2930
|
-
try {
|
|
2931
|
-
spawn("taskkill", ["/pid", String(child.pid), "/T", "/F"], { stdio: "ignore" });
|
|
2932
|
-
return;
|
|
2933
|
-
} catch {
|
|
2934
|
-
}
|
|
2935
|
-
}
|
|
2936
|
-
try {
|
|
2937
|
-
child.kill(signal);
|
|
2938
|
-
} catch {
|
|
2939
|
-
}
|
|
2940
|
-
}
|
|
2941
|
-
function defaultWorkspaceDir() {
|
|
2942
|
-
return join9(tmpdir(), "project");
|
|
2943
|
-
}
|
|
2944
|
-
function useShellForCli() {
|
|
2945
|
-
return isWindows;
|
|
2946
|
-
}
|
|
2947
|
-
function statePath(filename) {
|
|
2948
|
-
return join9(tmpdir(), filename);
|
|
2949
|
-
}
|
|
2950
|
-
|
|
2951
2978
|
// src/shared/loginShellEnv.ts
|
|
2952
2979
|
import { spawnSync } from "node:child_process";
|
|
2953
2980
|
import { delimiter as delimiter2 } from "node:path";
|
|
@@ -3091,41 +3118,92 @@ function mapChoiceReply(text, labels, multiSelect) {
|
|
|
3091
3118
|
return picked.length > 0 ? picked.join(", ") : null;
|
|
3092
3119
|
}
|
|
3093
3120
|
|
|
3121
|
+
// src/media/behavior.ts
|
|
3122
|
+
var BRIDGE_RULES = {
|
|
3123
|
+
sendMeansWeChat: '\u7528\u6237\u8BF4\u7684"\u53D1\u7ED9\u6211""\u53D1\u5230\u5FAE\u4FE1""\u53D1\u51FA\u6765""\u4F20\u7ED9\u6211"\uFF0C\u90FD\u662F\u6307\u628A\u6587\u4EF6\u53D1\u9001\u5230\u4ED6\u7684\u5FAE\u4FE1\u3002',
|
|
3124
|
+
douyinNoAsking: '\u770B\u5230\u6296\u97F3\u94FE\u63A5\u5C31\u7ACB\u5373\u4E0B\u8F7D\u5E76\u53D1\u9001\uFF0C\u4E0D\u8981\u53CD\u95EE\u7528\u6237"\u8981\u4E0B\u8F7D\u8FD8\u662F\u8981\u603B\u7ED3"\u2014\u2014\u4E0B\u8F7D\u5E76\u53D1\u9001\u5C31\u662F\u9ED8\u8BA4\u9884\u671F\u3002',
|
|
3125
|
+
ignoreThumbnail: "\u5206\u4EAB\u6D88\u606F\u5E38\u9644\u5E26\u5361\u7247\u7F29\u7565\u56FE\uFF0C\u52A0\u8F7D\u5931\u8D25\u65E0\u5173\u7D27\u8981\uFF0C\u76F4\u63A5\u5FFD\u7565\uFF0C\u4E0D\u8981\u56E0\u6B64\u6539\u804A\u56FE\u7247\u3002",
|
|
3126
|
+
retryOnce: '\u4E0B\u8F7D\u5931\u8D25\u5148\u539F\u6837\u91CD\u8BD5\u4E00\u6B21\uFF1B\u4ECD\u5931\u8D25\u5C31\u4E00\u53E5\u8BDD\u544A\u8BC9\u7528\u6237"\u6296\u97F3\u4E0B\u8F7D\u5931\u8D25\uFF1A<\u539F\u56E0>"\uFF0C\u4E0D\u8981\u5C94\u5F00\u8BDD\u9898\u3002',
|
|
3127
|
+
briefConfirm: '\u6267\u884C\u5B8C\u6210\u540E\u7B80\u77ED\u786E\u8BA4\uFF08\u5982"\u5DF2\u53D1\u9001"\uFF09\uFF0C\u4E0D\u9700\u8981\u5197\u957F\u89E3\u91CA\u3002',
|
|
3128
|
+
noInteractiveUI: "\u6CA1\u6709\u4EA4\u4E92\u5F0F\u5F39\u7A97\u6216\u6309\u94AE\uFF1B\u9700\u8981\u7528\u6237\u505A\u9009\u62E9\u65F6\u7528\u5E8F\u53F7\u5217\u8868\u3002"
|
|
3129
|
+
};
|
|
3130
|
+
var DOUYIN_INPUT_FORMS = "\u652F\u6301\u77ED\u94FE(v.douyin.com)\u3001\u5B8C\u6574\u94FE\u63A5\u3001\u5206\u4EAB\u6587\u6848\uFF08\u81EA\u52A8\u63D0\u53D6\uFF09\u3001\u7EAF aweme_id\u3002";
|
|
3131
|
+
function renderClaudeSystemPrompt() {
|
|
3132
|
+
return [
|
|
3133
|
+
"\u4F60\u6B63\u8FD0\u884C\u5728\u4E00\u4E2A\u5FAE\u4FE1\u6865\u63A5\u73AF\u5883\u4E2D\uFF0C\u7528\u6237\u901A\u8FC7\u5FAE\u4FE1\u4E0E\u4F60\u5BF9\u8BDD\u3002\u4F60\u5177\u5907\u5411\u7528\u6237\u5FAE\u4FE1\u76F4\u63A5\u53D1\u9001\u6587\u4EF6\u7684\u80FD\u529B\u3002",
|
|
3134
|
+
"",
|
|
3135
|
+
"## \u73AF\u5883\u8BF4\u660E",
|
|
3136
|
+
"- \u7528\u6237\u770B\u5230\u7684\u662F\u5FAE\u4FE1\u804A\u5929\u754C\u9762\u3002",
|
|
3137
|
+
`- ${BRIDGE_RULES.sendMeansWeChat}`,
|
|
3138
|
+
`- ${BRIDGE_RULES.noInteractiveUI}`,
|
|
3139
|
+
"- \u4E0D\u8981\u8C03\u7528 AskUserQuestion \u5DE5\u5177\uFF08\u6B64\u73AF\u5883\u65E0\u6CD5\u4EA4\u4E92\uFF09\u3002",
|
|
3140
|
+
"",
|
|
3141
|
+
"## \u53D1\u9001\u6587\u4EF6\u5230\u7528\u6237\u5FAE\u4FE1",
|
|
3142
|
+
"- \u56FE\u7247 \u2192 send_image",
|
|
3143
|
+
"- \u89C6\u9891 \u2192 send_video",
|
|
3144
|
+
"- \u97F3\u9891 \u2192 send_audio\uFF08\u4EE5\u6587\u4EF6\u9644\u4EF6\u5F62\u5F0F\u53D1\u9001\uFF09",
|
|
3145
|
+
"- \u5176\u4ED6\u6587\u4EF6\uFF08PDF/\u6587\u6863/\u4EE3\u7801/\u538B\u7F29\u5305\u7B49\uFF09\u2192 send_file",
|
|
3146
|
+
"",
|
|
3147
|
+
"## \u6296\u97F3\u89C6\u9891\u4E0B\u8F7D",
|
|
3148
|
+
`- ${BRIDGE_RULES.douyinNoAsking}`,
|
|
3149
|
+
"- \u7B2C\u4E00\u65F6\u95F4\u8C03\u7528 download_douyin\uFF0C\u5B83\u4F1A\u4E0B\u8F7D\u65E0\u6C34\u5370\u89C6\u9891\u5E76\u81EA\u52A8\u53D1\u9001\u5230\u7528\u6237\u5FAE\u4FE1\u3002",
|
|
3150
|
+
`- ${DOUYIN_INPUT_FORMS}`,
|
|
3151
|
+
`- ${BRIDGE_RULES.ignoreThumbnail}`,
|
|
3152
|
+
`- ${BRIDGE_RULES.retryOnce}`,
|
|
3153
|
+
"",
|
|
3154
|
+
"## \u884C\u4E3A\u51C6\u5219",
|
|
3155
|
+
'- \u7528\u6237\u7684"\u6211"\u5C31\u662F\u4ED6\u7684\u5FAE\u4FE1\u3002',
|
|
3156
|
+
`- ${BRIDGE_RULES.briefConfirm}`,
|
|
3157
|
+
"- \u5982\u679C\u53D1\u9001\u5931\u8D25\uFF0C\u544A\u77E5\u539F\u56E0\u5E76\u7ED9\u51FA\u6587\u4EF6\u672C\u5730\u8DEF\u5F84\uFF0C\u8BA9\u7528\u6237\u53EF\u624B\u52A8\u83B7\u53D6\u3002",
|
|
3158
|
+
'- \u5F53\u4F60\u751F\u6210\u4E86\u6587\u4EF6\uFF08\u56FE\u8868\u3001\u4EE3\u7801\u6587\u4EF6\u3001\u6587\u6863\u7B49\uFF09\uFF0C\u7528\u6237\u8BF4"\u53D1\u7ED9\u6211"\u65F6\u76F4\u63A5\u8C03\u7528\u5BF9\u5E94\u5DE5\u5177\u53D1\u9001\u3002'
|
|
3159
|
+
].join("\n");
|
|
3160
|
+
}
|
|
3161
|
+
function renderCodexInstructions(input) {
|
|
3162
|
+
const isWindows2 = input.platform === "win32";
|
|
3163
|
+
const curl = isWindows2 ? "curl.exe" : "curl";
|
|
3164
|
+
const shellTag = isWindows2 ? "powershell" : "bash";
|
|
3165
|
+
const tmpDir = input.tmpDir ?? (isWindows2 ? "%TEMP%" : "/tmp");
|
|
3166
|
+
const quote = (value) => `"${value}"`;
|
|
3167
|
+
return [
|
|
3168
|
+
"\u4F60\u6B63\u8FD0\u884C\u5728\u4E00\u4E2A\u5FAE\u4FE1\u6865\u63A5\u73AF\u5883\u4E2D\uFF0C\u7528\u6237\u901A\u8FC7\u5FAE\u4FE1\u4E0E\u4F60\u5BF9\u8BDD\u3002",
|
|
3169
|
+
"",
|
|
3170
|
+
"## \u73AF\u5883\u8BF4\u660E",
|
|
3171
|
+
`- \u7528\u6237\u770B\u5230\u7684\u662F\u5FAE\u4FE1\u804A\u5929\u754C\u9762\u3002${BRIDGE_RULES.noInteractiveUI}`,
|
|
3172
|
+
`- ${BRIDGE_RULES.sendMeansWeChat}`,
|
|
3173
|
+
"",
|
|
3174
|
+
"## \u53D1\u9001\u6587\u4EF6\u5230\u7528\u6237\u5FAE\u4FE1",
|
|
3175
|
+
"\u7528 shell \u8C03\u7528\u6865\u63A5\u5C42\u7684\u53D1\u9001\u7AEF\u70B9\u5373\u53EF\uFF08kind \u53D6 image / video / audio / file\uFF09\uFF1A",
|
|
3176
|
+
"```" + shellTag,
|
|
3177
|
+
// Windows 给单行:PowerShell 的续行符是反引号,POSIX 的反斜杠会被当成参数传进去。
|
|
3178
|
+
...isWindows2 ? [`${curl} -sS -X POST ${input.apiBaseUrl}/api/channel/send-media -H 'Content-Type: application/json' -d '{"kind":"video","filePath":"<\u7EDD\u5BF9\u8DEF\u5F84>"}'`] : [
|
|
3179
|
+
`${curl} -sS -X POST ${input.apiBaseUrl}/api/channel/send-media \\`,
|
|
3180
|
+
" -H 'Content-Type: application/json' \\",
|
|
3181
|
+
` -d '{"kind":"video","filePath":"<\u7EDD\u5BF9\u8DEF\u5F84>"}'`
|
|
3182
|
+
],
|
|
3183
|
+
"```",
|
|
3184
|
+
"- filePath \u5FC5\u987B\u662F\u7EDD\u5BF9\u8DEF\u5F84\uFF0C\u4E14\u6587\u4EF6\u5FC5\u987B\u771F\u5B9E\u5B58\u5728\u2014\u2014\u4E0D\u8981\u51ED\u7A7A\u6784\u9020\u8DEF\u5F84\u3002",
|
|
3185
|
+
'- \u8FD4\u56DE {"ok":true} \u5373\u53D1\u9001\u6210\u529F\uFF1B\u5931\u8D25\u65F6\u628A\u9519\u8BEF\u539F\u6587\u544A\u8BC9\u7528\u6237\uFF0C\u5E76\u7ED9\u51FA\u6587\u4EF6\u672C\u5730\u8DEF\u5F84\u3002',
|
|
3186
|
+
"",
|
|
3187
|
+
"## \u6296\u97F3\u89C6\u9891\u4E0B\u8F7D",
|
|
3188
|
+
"\u5F53\u7528\u6237\u53D1\u6765\u542B\u6296\u97F3\u94FE\u63A5\uFF08v.douyin.com\u3001douyin.com\uFF09\u7684\u6D88\u606F\u6216\u5206\u4EAB\u6587\u6848\u65F6\uFF1A",
|
|
3189
|
+
`- ${BRIDGE_RULES.douyinNoAsking}`,
|
|
3190
|
+
"```" + shellTag,
|
|
3191
|
+
`node ${quote(input.douyinScriptPath)} "<\u6296\u97F3\u94FE\u63A5\u6216\u6574\u6BB5\u5206\u4EAB\u6587\u6848>" --output ${quote(tmpDir)}`,
|
|
3192
|
+
"```",
|
|
3193
|
+
"- \u811A\u672C\u6210\u529F\u65F6\u8F93\u51FA `\u2705 \u5DF2\u4FDD\u5B58: <\u6587\u4EF6\u7EDD\u5BF9\u8DEF\u5F84>`\uFF1B\u53D6\u8BE5\u8DEF\u5F84\uFF0C\u6309\u4E0A\u9762\u7684\u65B9\u5F0F\u4EE5 kind=video \u53D1\u9001\u3002",
|
|
3194
|
+
`- ${DOUYIN_INPUT_FORMS}\u53EF\u4EE5\u628A\u6574\u6BB5\u6587\u6848\u539F\u6837\u4F20\u8FDB\u53BB\u3002`,
|
|
3195
|
+
`- ${BRIDGE_RULES.ignoreThumbnail}`,
|
|
3196
|
+
`- ${BRIDGE_RULES.retryOnce}`,
|
|
3197
|
+
"",
|
|
3198
|
+
"## \u884C\u4E3A\u51C6\u5219",
|
|
3199
|
+
'- \u7528\u6237\u7684"\u6211"\u5C31\u662F\u4ED6\u7684\u5FAE\u4FE1\u3002',
|
|
3200
|
+
`- ${BRIDGE_RULES.briefConfirm}`,
|
|
3201
|
+
'- \u4F60\u751F\u6210\u4E86\u6587\u4EF6\uFF08\u56FE\u8868\u3001\u4EE3\u7801\u3001\u6587\u6863\u7B49\uFF09\u540E\uFF0C\u7528\u6237\u8BF4"\u53D1\u7ED9\u6211"\u5C31\u6309\u4E0A\u9762\u7684\u65B9\u5F0F\u53D1\u9001\u3002'
|
|
3202
|
+
].join("\n");
|
|
3203
|
+
}
|
|
3204
|
+
|
|
3094
3205
|
// src/providers/claude-code/bridgeSystemPrompt.ts
|
|
3095
|
-
var BRIDGE_APPEND_SYSTEM_PROMPT =
|
|
3096
|
-
"\u4F60\u6B63\u8FD0\u884C\u5728\u4E00\u4E2A\u5FAE\u4FE1\u6865\u63A5\u73AF\u5883\u4E2D\uFF0C\u7528\u6237\u901A\u8FC7\u5FAE\u4FE1\u4E0E\u4F60\u5BF9\u8BDD\u3002\u4F60\u5177\u5907\u5411\u7528\u6237\u5FAE\u4FE1\u76F4\u63A5\u53D1\u9001\u6587\u4EF6\u7684\u80FD\u529B\u3002",
|
|
3097
|
-
"",
|
|
3098
|
-
"## \u73AF\u5883\u8BF4\u660E",
|
|
3099
|
-
"- \u4F60\u4E0E\u7528\u6237\u4E4B\u95F4\u901A\u8FC7\u5FAE\u4FE1\u8FDE\u63A5\uFF0C\u7528\u6237\u770B\u5230\u7684\u662F\u5FAE\u4FE1\u804A\u5929\u754C\u9762\u3002",
|
|
3100
|
-
'- \u7528\u6237\u8BF4\u7684"\u53D1\u7ED9\u6211""\u53D1\u5230\u5FAE\u4FE1""\u53D1\u51FA\u6765""\u4F20\u7ED9\u6211"\u7B49\u90FD\u662F\u6307\uFF1A\u901A\u8FC7 MCP \u5DE5\u5177\u628A\u6587\u4EF6\u53D1\u9001\u5230\u7528\u6237\u7684\u5FAE\u4FE1\u3002',
|
|
3101
|
-
"- \u6CA1\u6709\u4EA4\u4E92\u5F0F\u5F39\u7A97\u6216\u6309\u94AE\uFF0C\u9700\u8981\u7528\u6237\u505A\u9009\u62E9\u65F6\u7528\u5E8F\u53F7\u5217\u8868\u3002",
|
|
3102
|
-
"- \u4E0D\u8981\u8C03\u7528 AskUserQuestion \u5DE5\u5177\uFF08\u6B64\u73AF\u5883\u65E0\u6CD5\u4EA4\u4E92\uFF09\u3002",
|
|
3103
|
-
"",
|
|
3104
|
-
"## \u6838\u5FC3\u80FD\u529B",
|
|
3105
|
-
"",
|
|
3106
|
-
"### 1. \u53D1\u9001\u6587\u4EF6\u5230\u7528\u6237\u5FAE\u4FE1",
|
|
3107
|
-
'\u5F53\u7528\u6237\u8BF4"\u628AXX\u53D1\u7ED9\u6211""\u628A\u6587\u4EF6\u53D1\u51FA\u6765""\u53D1\u5230\u6211\u5FAE\u4FE1""\u751F\u6210\u4E00\u4E2AXX\u53D1\u7ED9\u6211"\u7B49\uFF0C',
|
|
3108
|
-
"\u90FD\u662F\u8981\u4F60\u901A\u8FC7 MCP \u5DE5\u5177\u53D1\u9001\u5230\u4ED6\u7684\u5FAE\u4FE1\uFF1A",
|
|
3109
|
-
"- \u56FE\u7247 \u2192 send_image",
|
|
3110
|
-
"- \u89C6\u9891 \u2192 send_video",
|
|
3111
|
-
"- \u97F3\u9891 \u2192 send_audio\uFF08\u4EE5\u6587\u4EF6\u9644\u4EF6\u5F62\u5F0F\u53D1\u9001\uFF09",
|
|
3112
|
-
"- \u5176\u4ED6\u6587\u4EF6\uFF08PDF/\u6587\u6863/\u4EE3\u7801/\u538B\u7F29\u5305\u7B49\uFF09\u2192 send_file",
|
|
3113
|
-
"",
|
|
3114
|
-
"### 2. \u6296\u97F3\u89C6\u9891\u4E0B\u8F7D",
|
|
3115
|
-
"\u5F53\u7528\u6237\u53D1\u6765\u5305\u542B\u6296\u97F3\u94FE\u63A5\uFF08v.douyin.com\u3001douyin.com\uFF09\u7684\u6D88\u606F\uFF0C\u6216\u8005\u5206\u4EAB\u6587\u6848\u4E2D\u542B\u6709\u6296\u97F3\u94FE\u63A5\u65F6\uFF1A",
|
|
3116
|
-
"- \u7B2C\u4E00\u65F6\u95F4\u8C03\u7528 download_douyin \u4E0B\u8F7D\u65E0\u6C34\u5370\u89C6\u9891\u5E76\u81EA\u52A8\u53D1\u9001\u5230\u7528\u6237\u5FAE\u4FE1",
|
|
3117
|
-
"- \u65E0\u9700\u8BE2\u95EE\u7528\u6237\u662F\u5426\u8981\u4E0B\u8F7D\uFF0C\u76F4\u63A5\u6267\u884C",
|
|
3118
|
-
"- \u652F\u6301\u77ED\u94FE\u3001\u5B8C\u6574\u94FE\u63A5\u3001\u5206\u4EAB\u6587\u6848\u3001\u7EAF aweme_id",
|
|
3119
|
-
"- \u6296\u97F3\u5206\u4EAB\u6D88\u606F\u5E38\u5E38\u9644\u5E26\u5361\u7247\u7F29\u7565\u56FE\uFF0C\u8FD9\u4E9B\u56FE\u7247\u9644\u4EF6\u5373\u4F7F\u52A0\u8F7D\u5931\u8D25\u4E5F\u65E0\u5173\u7D27\u8981\uFF0C\u76F4\u63A5\u5FFD\u7565\uFF0C\u4E0D\u8981\u56E0\u6B64\u8FFD\u95EE\u7528\u6237\u6216\u6539\u804A\u56FE\u7247\u2014\u2014\u4F60\u7684\u4EFB\u52A1\u53EA\u6709\u4E00\u4E2A\uFF1A\u4E0B\u8F7D\u5E76\u53D1\u9001\u89C6\u9891\u3002",
|
|
3120
|
-
'- \u5982\u679C download_douyin \u8FD4\u56DE\u5931\u8D25\uFF0C\u5148\u539F\u6837\u91CD\u8BD5\u4E00\u6B21\uFF1B\u4ECD\u5931\u8D25\u5C31\u4E00\u53E5\u8BDD\u660E\u786E\u544A\u8BC9\u7528\u6237"\u6296\u97F3\u4E0B\u8F7D\u5931\u8D25\uFF1A<\u539F\u56E0>"\uFF0C\u4E0D\u8981\u8F6C\u800C\u8BA8\u8BBA\u56FE\u7247\u6216\u5C94\u5F00\u8BDD\u9898\u3002',
|
|
3121
|
-
"",
|
|
3122
|
-
"## \u884C\u4E3A\u51C6\u5219",
|
|
3123
|
-
'- \u7528\u6237\u7684"\u6211"\u5C31\u662F\u4ED6\u7684\u5FAE\u4FE1\uFF0C"\u53D1\u7ED9\u6211"\u5C31\u662F\u53D1\u5230\u5FAE\u4FE1\u3002',
|
|
3124
|
-
"- \u8BC6\u522B\u5230\u6296\u97F3\u94FE\u63A5\u65F6\u7ACB\u5373\u4E0B\u8F7D\u5E76\u53D1\u9001\uFF0C\u4E0D\u8981\u8BE2\u95EE\u3002",
|
|
3125
|
-
'- \u6267\u884C\u5B8C\u6210\u540E\u7B80\u77ED\u786E\u8BA4\uFF08\u5982"\u5DF2\u53D1\u9001"\uFF09\uFF0C\u4E0D\u9700\u8981\u5197\u957F\u89E3\u91CA\u3002',
|
|
3126
|
-
"- \u5982\u679C\u53D1\u9001\u5931\u8D25\uFF0C\u544A\u77E5\u539F\u56E0\u5E76\u7ED9\u51FA\u6587\u4EF6\u672C\u5730\u8DEF\u5F84\uFF0C\u8BA9\u7528\u6237\u53EF\u624B\u52A8\u83B7\u53D6\u3002",
|
|
3127
|
-
'- \u5F53\u4F60\u751F\u6210\u4E86\u6587\u4EF6\uFF08\u56FE\u8868\u3001\u4EE3\u7801\u6587\u4EF6\u3001\u6587\u6863\u7B49\uFF09\uFF0C\u7528\u6237\u8BF4"\u53D1\u7ED9\u6211"\u65F6\u76F4\u63A5\u8C03\u7528\u5BF9\u5E94\u5DE5\u5177\u53D1\u9001\u3002'
|
|
3128
|
-
].join("\n");
|
|
3206
|
+
var BRIDGE_APPEND_SYSTEM_PROMPT = renderClaudeSystemPrompt();
|
|
3129
3207
|
|
|
3130
3208
|
// src/providers/claude-code/claudeCapabilities.ts
|
|
3131
3209
|
import { spawn as spawn2 } from "node:child_process";
|
|
@@ -3138,7 +3216,7 @@ var probeAppendSystemPromptSupport = (command) => {
|
|
|
3138
3216
|
return result;
|
|
3139
3217
|
};
|
|
3140
3218
|
function runHelpProbe(command) {
|
|
3141
|
-
return new Promise((
|
|
3219
|
+
return new Promise((resolve3) => {
|
|
3142
3220
|
try {
|
|
3143
3221
|
const child = spawn2(command, ["--help"], { stdio: ["ignore", "pipe", "pipe"], shell: useShellForCli() });
|
|
3144
3222
|
let output = "";
|
|
@@ -3147,10 +3225,10 @@ function runHelpProbe(command) {
|
|
|
3147
3225
|
};
|
|
3148
3226
|
child.stdout?.on("data", collect);
|
|
3149
3227
|
child.stderr?.on("data", collect);
|
|
3150
|
-
child.on("error", () =>
|
|
3151
|
-
child.on("close", () =>
|
|
3228
|
+
child.on("error", () => resolve3(false));
|
|
3229
|
+
child.on("close", () => resolve3(output.includes("--append-system-prompt")));
|
|
3152
3230
|
} catch {
|
|
3153
|
-
|
|
3231
|
+
resolve3(false);
|
|
3154
3232
|
}
|
|
3155
3233
|
});
|
|
3156
3234
|
}
|
|
@@ -3163,12 +3241,12 @@ function capTail(text, capBytes) {
|
|
|
3163
3241
|
}
|
|
3164
3242
|
function readWithIdleTimeout(handle, ms) {
|
|
3165
3243
|
if (!ms || ms <= 0) return handle.read();
|
|
3166
|
-
return new Promise((
|
|
3244
|
+
return new Promise((resolve3) => {
|
|
3167
3245
|
let settled = false;
|
|
3168
3246
|
const timer = setTimeout(() => {
|
|
3169
3247
|
if (!settled) {
|
|
3170
3248
|
settled = true;
|
|
3171
|
-
|
|
3249
|
+
resolve3(IDLE_SENTINEL);
|
|
3172
3250
|
}
|
|
3173
3251
|
}, ms);
|
|
3174
3252
|
timer.unref?.();
|
|
@@ -3176,7 +3254,7 @@ function readWithIdleTimeout(handle, ms) {
|
|
|
3176
3254
|
if (!settled) {
|
|
3177
3255
|
settled = true;
|
|
3178
3256
|
clearTimeout(timer);
|
|
3179
|
-
|
|
3257
|
+
resolve3(chunk);
|
|
3180
3258
|
}
|
|
3181
3259
|
});
|
|
3182
3260
|
});
|
|
@@ -3402,10 +3480,10 @@ function defaultClaudeStreamSpawner(call, opts = {}) {
|
|
|
3402
3480
|
const queue = [];
|
|
3403
3481
|
let resolveNext = null;
|
|
3404
3482
|
const push = (chunk) => {
|
|
3405
|
-
const
|
|
3406
|
-
if (
|
|
3483
|
+
const resolve3 = resolveNext;
|
|
3484
|
+
if (resolve3) {
|
|
3407
3485
|
resolveNext = null;
|
|
3408
|
-
|
|
3486
|
+
resolve3(chunk);
|
|
3409
3487
|
} else {
|
|
3410
3488
|
queue.push(chunk);
|
|
3411
3489
|
}
|
|
@@ -3441,8 +3519,8 @@ function defaultClaudeStreamSpawner(call, opts = {}) {
|
|
|
3441
3519
|
read() {
|
|
3442
3520
|
const next = queue.shift();
|
|
3443
3521
|
if (next) return Promise.resolve(next);
|
|
3444
|
-
return new Promise((
|
|
3445
|
-
resolveNext =
|
|
3522
|
+
return new Promise((resolve3) => {
|
|
3523
|
+
resolveNext = resolve3;
|
|
3446
3524
|
});
|
|
3447
3525
|
},
|
|
3448
3526
|
close() {
|
|
@@ -3549,8 +3627,8 @@ var CodexAppServerClient = class {
|
|
|
3549
3627
|
const id = this.nextId++;
|
|
3550
3628
|
const key = String(id);
|
|
3551
3629
|
const payload = { id, method, ...params !== void 0 ? { params } : {} };
|
|
3552
|
-
const response = new Promise((
|
|
3553
|
-
this.pending.set(key, { resolve:
|
|
3630
|
+
const response = new Promise((resolve3, reject) => {
|
|
3631
|
+
this.pending.set(key, { resolve: resolve3, reject });
|
|
3554
3632
|
});
|
|
3555
3633
|
this.child.stdin.write(`${JSON.stringify(payload)}
|
|
3556
3634
|
`);
|
|
@@ -3651,44 +3729,46 @@ var CodexAppServerClient = class {
|
|
|
3651
3729
|
};
|
|
3652
3730
|
|
|
3653
3731
|
// src/providers/codex/bridgeDeveloperInstructions.ts
|
|
3654
|
-
import {
|
|
3732
|
+
import { tmpdir as tmpdir2 } from "node:os";
|
|
3733
|
+
import { dirname as dirname6, join as join11 } from "node:path";
|
|
3655
3734
|
import { fileURLToPath } from "node:url";
|
|
3656
|
-
|
|
3657
|
-
|
|
3658
|
-
|
|
3735
|
+
|
|
3736
|
+
// src/media/scriptLocator.ts
|
|
3737
|
+
import { existsSync as existsSync6 } from "node:fs";
|
|
3738
|
+
import { homedir as homedir8 } from "node:os";
|
|
3739
|
+
import { join as join10, resolve as resolve2 } from "node:path";
|
|
3740
|
+
function douyinScriptCandidates(baseDir) {
|
|
3659
3741
|
return [
|
|
3660
|
-
|
|
3661
|
-
"",
|
|
3662
|
-
|
|
3663
|
-
"
|
|
3664
|
-
|
|
3665
|
-
"",
|
|
3666
|
-
|
|
3667
|
-
"
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
"
|
|
3671
|
-
|
|
3672
|
-
|
|
3673
|
-
|
|
3674
|
-
|
|
3675
|
-
|
|
3676
|
-
|
|
3677
|
-
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
|
|
3682
|
-
|
|
3683
|
-
|
|
3684
|
-
|
|
3685
|
-
|
|
3686
|
-
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
'- \u4F60\u751F\u6210\u4E86\u6587\u4EF6\uFF08\u56FE\u8868\u3001\u4EE3\u7801\u3001\u6587\u6863\u7B49\uFF09\u540E\uFF0C\u7528\u6237\u8BF4"\u53D1\u7ED9\u6211"\u5C31\u76F4\u63A5\u6309\u4E0A\u9762\u7684\u65B9\u5F0F\u53D1\u9001\u3002'
|
|
3691
|
-
].join("\n");
|
|
3742
|
+
// 源码布局:src/mcp/tools -> src/mcp/scripts
|
|
3743
|
+
join10(baseDir, "..", "scripts", "douyin-download.mjs"),
|
|
3744
|
+
// 打包布局:dist/mcp/mediaServer.js -> dist/mcp/scripts
|
|
3745
|
+
join10(baseDir, "scripts", "douyin-download.mjs"),
|
|
3746
|
+
// 同级包:dist/server -> dist/mcp/scripts(打包后 cli.js 与 mcp/ 平级)
|
|
3747
|
+
join10(baseDir, "..", "mcp", "scripts", "douyin-download.mjs"),
|
|
3748
|
+
// 深一层:src/providers/codex -> src/mcp/scripts
|
|
3749
|
+
join10(baseDir, "..", "..", "mcp", "scripts", "douyin-download.mjs"),
|
|
3750
|
+
// 用户 skills 目录(跨平台)
|
|
3751
|
+
join10(homedir8(), ".agents", "skills", "douyin-download", "scripts", "douyin-download.mjs"),
|
|
3752
|
+
join10(homedir8(), ".claude", "skills", "douyin-download", "scripts", "douyin-download.mjs")
|
|
3753
|
+
];
|
|
3754
|
+
}
|
|
3755
|
+
function locateDouyinScript(input) {
|
|
3756
|
+
const exists = input.exists ?? existsSync6;
|
|
3757
|
+
for (const candidate of douyinScriptCandidates(input.baseDir)) {
|
|
3758
|
+
const resolved = resolve2(candidate);
|
|
3759
|
+
if (exists(resolved)) return resolved;
|
|
3760
|
+
}
|
|
3761
|
+
return void 0;
|
|
3762
|
+
}
|
|
3763
|
+
|
|
3764
|
+
// src/providers/codex/bridgeDeveloperInstructions.ts
|
|
3765
|
+
function buildCodexBridgeInstructions(input = {}) {
|
|
3766
|
+
return renderCodexInstructions({
|
|
3767
|
+
platform: input.platform ?? process.platform,
|
|
3768
|
+
apiBaseUrl: input.apiBaseUrl ?? defaultApiBaseUrl(),
|
|
3769
|
+
douyinScriptPath: input.douyinScriptPath ?? defaultDouyinScriptPath(),
|
|
3770
|
+
tmpDir: input.tmpDir ?? tmpdir2()
|
|
3771
|
+
});
|
|
3692
3772
|
}
|
|
3693
3773
|
function defaultApiBaseUrl() {
|
|
3694
3774
|
const port = process.env.BRIDGE_PORT ?? "8787";
|
|
@@ -3696,19 +3776,19 @@ function defaultApiBaseUrl() {
|
|
|
3696
3776
|
}
|
|
3697
3777
|
function defaultDouyinScriptPath() {
|
|
3698
3778
|
const here2 = dirname6(fileURLToPath(import.meta.url));
|
|
3699
|
-
return
|
|
3779
|
+
return locateDouyinScript({ baseDir: here2 }) ?? join11(here2, "..", "mcp", "scripts", "douyin-download.mjs");
|
|
3700
3780
|
}
|
|
3701
3781
|
|
|
3702
3782
|
// src/providers/codex/codexInteractiveRunner.ts
|
|
3703
3783
|
var IDLE_SENTINEL2 = /* @__PURE__ */ Symbol("idle_timeout");
|
|
3704
3784
|
function withIdleTimeout(promise, ms) {
|
|
3705
3785
|
if (!ms || ms <= 0) return promise;
|
|
3706
|
-
return new Promise((
|
|
3786
|
+
return new Promise((resolve3, reject) => {
|
|
3707
3787
|
let settled = false;
|
|
3708
3788
|
const timer = setTimeout(() => {
|
|
3709
3789
|
if (!settled) {
|
|
3710
3790
|
settled = true;
|
|
3711
|
-
|
|
3791
|
+
resolve3(IDLE_SENTINEL2);
|
|
3712
3792
|
}
|
|
3713
3793
|
}, ms);
|
|
3714
3794
|
timer.unref?.();
|
|
@@ -3717,7 +3797,7 @@ function withIdleTimeout(promise, ms) {
|
|
|
3717
3797
|
if (settled) return;
|
|
3718
3798
|
settled = true;
|
|
3719
3799
|
clearTimeout(timer);
|
|
3720
|
-
|
|
3800
|
+
resolve3(value);
|
|
3721
3801
|
},
|
|
3722
3802
|
(error) => {
|
|
3723
3803
|
if (settled) return;
|
|
@@ -3835,8 +3915,8 @@ var CodexInteractiveRunner = class {
|
|
|
3835
3915
|
session.activeTurnId = void 0;
|
|
3836
3916
|
session.turnClosed = false;
|
|
3837
3917
|
session.emittedTextThisTurn = false;
|
|
3838
|
-
session.turnCompletedPromise = new Promise((
|
|
3839
|
-
session.turnCompletedResolver =
|
|
3918
|
+
session.turnCompletedPromise = new Promise((resolve3) => {
|
|
3919
|
+
session.turnCompletedResolver = resolve3;
|
|
3840
3920
|
});
|
|
3841
3921
|
if (session.threadId) {
|
|
3842
3922
|
const resumed = await withIdleTimeout(client.request("thread/resume", {
|
|
@@ -4048,8 +4128,8 @@ var CodexInteractiveRunner = class {
|
|
|
4048
4128
|
const next = session.pendingEvents.shift();
|
|
4049
4129
|
if (next) return next;
|
|
4050
4130
|
if (session.turnClosed) return null;
|
|
4051
|
-
await new Promise((
|
|
4052
|
-
session.eventResolver =
|
|
4131
|
+
await new Promise((resolve3) => {
|
|
4132
|
+
session.eventResolver = resolve3;
|
|
4053
4133
|
});
|
|
4054
4134
|
}
|
|
4055
4135
|
}
|
|
@@ -4135,7 +4215,7 @@ function createDefaultProviders(input = {}) {
|
|
|
4135
4215
|
// src/providers/claude-code/claudeDetection.ts
|
|
4136
4216
|
import { spawn as spawn5 } from "node:child_process";
|
|
4137
4217
|
async function defaultCommandRunner(command, args) {
|
|
4138
|
-
return await new Promise((
|
|
4218
|
+
return await new Promise((resolve3) => {
|
|
4139
4219
|
const child = spawn5(command, args, { stdio: ["ignore", "pipe", "pipe"], shell: useShellForCli() });
|
|
4140
4220
|
let stdout = "";
|
|
4141
4221
|
let stderr = "";
|
|
@@ -4146,11 +4226,11 @@ async function defaultCommandRunner(command, args) {
|
|
|
4146
4226
|
stderr += String(chunk);
|
|
4147
4227
|
});
|
|
4148
4228
|
child.on("error", (error) => {
|
|
4149
|
-
|
|
4229
|
+
resolve3({ ok: false, code: error.code ?? "ERROR", stdout, stderr: stderr || error.message });
|
|
4150
4230
|
});
|
|
4151
4231
|
child.on("close", (code) => {
|
|
4152
|
-
if (code === 0)
|
|
4153
|
-
else
|
|
4232
|
+
if (code === 0) resolve3({ ok: true, stdout, stderr });
|
|
4233
|
+
else resolve3({ ok: false, code: code ?? "SIGNAL", stdout, stderr });
|
|
4154
4234
|
});
|
|
4155
4235
|
});
|
|
4156
4236
|
}
|
|
@@ -4171,7 +4251,7 @@ ${result.stderr}`) };
|
|
|
4171
4251
|
// src/providers/codex/codexDetection.ts
|
|
4172
4252
|
import { spawn as spawn6 } from "node:child_process";
|
|
4173
4253
|
async function defaultCodexCommandRunner(command, args) {
|
|
4174
|
-
return await new Promise((
|
|
4254
|
+
return await new Promise((resolve3) => {
|
|
4175
4255
|
const child = spawn6(command, args, { stdio: ["ignore", "pipe", "pipe"], shell: useShellForCli() });
|
|
4176
4256
|
let stdout = "";
|
|
4177
4257
|
let stderr = "";
|
|
@@ -4182,11 +4262,11 @@ async function defaultCodexCommandRunner(command, args) {
|
|
|
4182
4262
|
stderr += String(chunk);
|
|
4183
4263
|
});
|
|
4184
4264
|
child.on("error", (error) => {
|
|
4185
|
-
|
|
4265
|
+
resolve3({ ok: false, code: error.code ?? "ERROR", stdout, stderr: stderr || error.message });
|
|
4186
4266
|
});
|
|
4187
4267
|
child.on("close", (code) => {
|
|
4188
|
-
if (code === 0)
|
|
4189
|
-
else
|
|
4268
|
+
if (code === 0) resolve3({ ok: true, stdout, stderr });
|
|
4269
|
+
else resolve3({ ok: false, code: code ?? "SIGNAL", stdout, stderr });
|
|
4190
4270
|
});
|
|
4191
4271
|
});
|
|
4192
4272
|
}
|
|
@@ -4323,7 +4403,7 @@ function buildBridgeCommandHelpMarkdown(input) {
|
|
|
4323
4403
|
}
|
|
4324
4404
|
|
|
4325
4405
|
// src/session/currentConversationStore.ts
|
|
4326
|
-
import { existsSync as
|
|
4406
|
+
import { existsSync as existsSync7, readFileSync as readFileSync5 } from "node:fs";
|
|
4327
4407
|
import { nanoid as nanoid2 } from "nanoid";
|
|
4328
4408
|
var CurrentConversationStore = class {
|
|
4329
4409
|
constructor(configPath, defaults) {
|
|
@@ -4382,7 +4462,7 @@ var CurrentConversationStore = class {
|
|
|
4382
4462
|
this.writeState(state);
|
|
4383
4463
|
}
|
|
4384
4464
|
readState() {
|
|
4385
|
-
if (!
|
|
4465
|
+
if (!existsSync7(this.configPath)) return {};
|
|
4386
4466
|
const raw = JSON.parse(readFileSync5(this.configPath, "utf8"));
|
|
4387
4467
|
return raw && typeof raw === "object" ? raw : {};
|
|
4388
4468
|
}
|
|
@@ -4687,8 +4767,8 @@ var MessageRouter = class _MessageRouter {
|
|
|
4687
4767
|
}
|
|
4688
4768
|
const genId = ++this.generationSeq;
|
|
4689
4769
|
let abortGeneration;
|
|
4690
|
-
const aborted = new Promise((
|
|
4691
|
-
abortGeneration = () =>
|
|
4770
|
+
const aborted = new Promise((resolve3) => {
|
|
4771
|
+
abortGeneration = () => resolve3("aborted");
|
|
4692
4772
|
});
|
|
4693
4773
|
this.activeGenerations.set(message.chatId, {
|
|
4694
4774
|
genId,
|
|
@@ -5059,7 +5139,7 @@ function composeInboundText(content) {
|
|
|
5059
5139
|
}
|
|
5060
5140
|
|
|
5061
5141
|
// src/storage/lastProviderSessionStore.ts
|
|
5062
|
-
import { existsSync as
|
|
5142
|
+
import { existsSync as existsSync8, readFileSync as readFileSync6 } from "node:fs";
|
|
5063
5143
|
var LastProviderSessionStore = class {
|
|
5064
5144
|
constructor(configPath) {
|
|
5065
5145
|
this.configPath = configPath;
|
|
@@ -5085,7 +5165,7 @@ var LastProviderSessionStore = class {
|
|
|
5085
5165
|
return this.readState().bridge?.lastProviderSessions ?? {};
|
|
5086
5166
|
}
|
|
5087
5167
|
readState() {
|
|
5088
|
-
if (!
|
|
5168
|
+
if (!existsSync8(this.configPath)) return {};
|
|
5089
5169
|
const raw = JSON.parse(readFileSync6(this.configPath, "utf8"));
|
|
5090
5170
|
return raw && typeof raw === "object" ? raw : {};
|
|
5091
5171
|
}
|
|
@@ -5096,7 +5176,7 @@ var LastProviderSessionStore = class {
|
|
|
5096
5176
|
};
|
|
5097
5177
|
|
|
5098
5178
|
// src/storage/runtimeUserStore.ts
|
|
5099
|
-
import { readFileSync as readFileSync7, existsSync as
|
|
5179
|
+
import { readFileSync as readFileSync7, existsSync as existsSync9 } from "node:fs";
|
|
5100
5180
|
import { nanoid as nanoid3 } from "nanoid";
|
|
5101
5181
|
var RuntimeUserStore = class {
|
|
5102
5182
|
constructor(configPath) {
|
|
@@ -5156,7 +5236,7 @@ var RuntimeUserStore = class {
|
|
|
5156
5236
|
return { ok: true };
|
|
5157
5237
|
}
|
|
5158
5238
|
readState() {
|
|
5159
|
-
if (!
|
|
5239
|
+
if (!existsSync9(this.configPath)) return {};
|
|
5160
5240
|
const raw = JSON.parse(readFileSync7(this.configPath, "utf8"));
|
|
5161
5241
|
return raw && typeof raw === "object" ? raw : {};
|
|
5162
5242
|
}
|
|
@@ -5250,12 +5330,12 @@ var RelayTunnelProvider = class {
|
|
|
5250
5330
|
};
|
|
5251
5331
|
const socket = this.options.createSocket(this.options.serverUrl);
|
|
5252
5332
|
this.socket = socket;
|
|
5253
|
-
return new Promise((
|
|
5333
|
+
return new Promise((resolve3, reject) => {
|
|
5254
5334
|
let settled = false;
|
|
5255
5335
|
const finishResolve = (value) => {
|
|
5256
5336
|
if (settled) return;
|
|
5257
5337
|
settled = true;
|
|
5258
|
-
|
|
5338
|
+
resolve3(value);
|
|
5259
5339
|
};
|
|
5260
5340
|
const finishReject = (error) => {
|
|
5261
5341
|
if (settled) return;
|
|
@@ -5490,12 +5570,12 @@ var RelayTunnelRouter = class {
|
|
|
5490
5570
|
|
|
5491
5571
|
// src/shared/version.ts
|
|
5492
5572
|
import { readFileSync as readFileSync8 } from "node:fs";
|
|
5493
|
-
import { dirname as dirname7, join as
|
|
5573
|
+
import { dirname as dirname7, join as join12 } from "node:path";
|
|
5494
5574
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
5495
5575
|
function readClientVersion() {
|
|
5496
5576
|
try {
|
|
5497
5577
|
const here2 = dirname7(fileURLToPath2(import.meta.url));
|
|
5498
|
-
const pkg = JSON.parse(readFileSync8(
|
|
5578
|
+
const pkg = JSON.parse(readFileSync8(join12(here2, "..", "..", "package.json"), "utf8"));
|
|
5499
5579
|
return typeof pkg.version === "string" && pkg.version ? pkg.version : "0.0.0";
|
|
5500
5580
|
} catch {
|
|
5501
5581
|
return "0.0.0";
|
|
@@ -5514,7 +5594,7 @@ function readUpdateStatusBestEffort(configPath) {
|
|
|
5514
5594
|
function createDaemonServer(options = {}) {
|
|
5515
5595
|
const app = Fastify({ logger: true });
|
|
5516
5596
|
const events = new BridgeEventHub();
|
|
5517
|
-
const configPath = options.configPath ?? process.env.BRIDGE_CONFIG ??
|
|
5597
|
+
const configPath = options.configPath ?? process.env.BRIDGE_CONFIG ?? join13(mkdtempSync(join13(tmpdir3(), "claude-codex-wechat-")), "config.json");
|
|
5518
5598
|
const persistedConfig = loadBridgeConfig(configPath);
|
|
5519
5599
|
const bridgeDefaults = {
|
|
5520
5600
|
defaultProvider: options.bridgeDefaults?.defaultProvider ?? persistedConfig.bridge?.defaultProvider ?? "claude-code",
|
|
@@ -5551,13 +5631,15 @@ function createDaemonServer(options = {}) {
|
|
|
5551
5631
|
const lastProviderSessions = new LastProviderSessionStore(configPath);
|
|
5552
5632
|
const sessionBindingMatch = /* @__PURE__ */ new Map();
|
|
5553
5633
|
const bridgePort = process.env.BRIDGE_PORT ?? "8787";
|
|
5554
|
-
const mcpConfigPath =
|
|
5634
|
+
const mcpConfigPath = join13(dirname8(configPath), "mcp-media.json");
|
|
5555
5635
|
const serverDir = dirname8(fileURLToPath3(import.meta.url));
|
|
5556
|
-
const mcpMediaServerTs =
|
|
5557
|
-
const mcpMediaServerJs =
|
|
5558
|
-
const
|
|
5559
|
-
|
|
5560
|
-
|
|
5636
|
+
const mcpMediaServerTs = join13(serverDir, "..", "mcp", "mediaServer.ts");
|
|
5637
|
+
const mcpMediaServerJs = join13(serverDir, "..", "mcp", "mediaServer.js");
|
|
5638
|
+
const { command: mcpCommand, args: mcpArgs } = buildMcpServerCommand({
|
|
5639
|
+
tsEntry: mcpMediaServerTs,
|
|
5640
|
+
jsEntry: mcpMediaServerJs,
|
|
5641
|
+
exists: existsSync10
|
|
5642
|
+
});
|
|
5561
5643
|
writeFileSync2(mcpConfigPath, JSON.stringify({
|
|
5562
5644
|
mcpServers: {
|
|
5563
5645
|
"wechat-media": {
|
|
@@ -5589,7 +5671,7 @@ function createDaemonServer(options = {}) {
|
|
|
5589
5671
|
});
|
|
5590
5672
|
}
|
|
5591
5673
|
const weixinStateStore = configPath ? new FileWeixinStateStore(configPath) : void 0;
|
|
5592
|
-
const weixinMediaDir = configPath ?
|
|
5674
|
+
const weixinMediaDir = configPath ? join13(dirname8(configPath), "media") : void 0;
|
|
5593
5675
|
const managedWechatChannel = options.channel ? null : new ManagedWeixinDirectAdapter(options.wechat, weixinStateStore, weixinMediaDir);
|
|
5594
5676
|
const channel = options.channel ?? managedWechatChannel;
|
|
5595
5677
|
const weixinOutboundGate = managedWechatChannel && weixinStateStore ? new WeixinOutboundGate({
|
|
@@ -5756,6 +5838,12 @@ function createDaemonServer(options = {}) {
|
|
|
5756
5838
|
if (!kind || !validKinds.includes(kind)) {
|
|
5757
5839
|
return reply.code(400).send({ ok: false, error: `kind must be one of: ${validKinds.join(", ")}` });
|
|
5758
5840
|
}
|
|
5841
|
+
if (!isAbsolute(filePath)) {
|
|
5842
|
+
return reply.code(400).send({ ok: false, error: `filePath must be an absolute path: ${filePath}` });
|
|
5843
|
+
}
|
|
5844
|
+
if (!existsSync10(filePath)) {
|
|
5845
|
+
return reply.code(400).send({ ok: false, error: `file not found: ${filePath}` });
|
|
5846
|
+
}
|
|
5759
5847
|
if (!channel) {
|
|
5760
5848
|
return reply.code(503).send({ ok: false, error: "channel not available" });
|
|
5761
5849
|
}
|
|
@@ -5947,7 +6035,7 @@ async function resolveProviderCommands(providers) {
|
|
|
5947
6035
|
|
|
5948
6036
|
// src/daemon/staticFrontend.ts
|
|
5949
6037
|
import { readFileSync as readFileSync9 } from "node:fs";
|
|
5950
|
-
import { join as
|
|
6038
|
+
import { join as join14 } from "node:path";
|
|
5951
6039
|
import fastifyStatic from "@fastify/static";
|
|
5952
6040
|
function attachStaticFrontend(webRoot2) {
|
|
5953
6041
|
return async (app) => {
|
|
@@ -5955,7 +6043,7 @@ function attachStaticFrontend(webRoot2) {
|
|
|
5955
6043
|
root: webRoot2,
|
|
5956
6044
|
wildcard: false
|
|
5957
6045
|
});
|
|
5958
|
-
const indexHtml = readFileSync9(
|
|
6046
|
+
const indexHtml = readFileSync9(join14(webRoot2, "index.html"), "utf8");
|
|
5959
6047
|
app.setNotFoundHandler((request, reply) => {
|
|
5960
6048
|
if (request.url.startsWith("/api")) {
|
|
5961
6049
|
reply.code(404).send({ error: "not_found" });
|
|
@@ -5967,10 +6055,10 @@ function attachStaticFrontend(webRoot2) {
|
|
|
5967
6055
|
}
|
|
5968
6056
|
|
|
5969
6057
|
// src/daemon/service.ts
|
|
5970
|
-
import { existsSync as
|
|
6058
|
+
import { existsSync as existsSync11, statSync, openSync as openSync2, closeSync as closeSync2, watchFile } from "node:fs";
|
|
5971
6059
|
import { mkdir as mkdir4, readFile as readFile6, rm as rm2, writeFile as writeFile4 } from "node:fs/promises";
|
|
5972
|
-
import { homedir as
|
|
5973
|
-
import { dirname as dirname9, join as
|
|
6060
|
+
import { homedir as homedir9 } from "node:os";
|
|
6061
|
+
import { dirname as dirname9, join as join15 } from "node:path";
|
|
5974
6062
|
import { createReadStream } from "node:fs";
|
|
5975
6063
|
import { execFile, spawn as spawn7 } from "node:child_process";
|
|
5976
6064
|
import { createInterface } from "node:readline";
|
|
@@ -6021,13 +6109,13 @@ async function startService(context) {
|
|
|
6021
6109
|
async function stopService(context) {
|
|
6022
6110
|
if (process.platform === "darwin") {
|
|
6023
6111
|
const spec = buildLaunchdSpec(context);
|
|
6024
|
-
if (!
|
|
6112
|
+
if (!existsSync11(spec.plistPath)) return await readServiceStatus(context);
|
|
6025
6113
|
await runLaunchctl(["bootout", `gui/${process.getuid?.() ?? 0}`, spec.plistPath]).catch(() => void 0);
|
|
6026
6114
|
return await readServiceStatus(context);
|
|
6027
6115
|
}
|
|
6028
6116
|
if (process.platform === "linux") {
|
|
6029
6117
|
const spec = buildSystemdUserSpec(context);
|
|
6030
|
-
if (!
|
|
6118
|
+
if (!existsSync11(spec.unitPath)) return await readServiceStatus(context);
|
|
6031
6119
|
await runSystemctl(["--user", "stop", spec.unitName]).catch(() => void 0);
|
|
6032
6120
|
return await readServiceStatus(context);
|
|
6033
6121
|
}
|
|
@@ -6045,7 +6133,7 @@ async function stopService(context) {
|
|
|
6045
6133
|
async function uninstallService(context) {
|
|
6046
6134
|
if (process.platform === "darwin") {
|
|
6047
6135
|
const spec = buildLaunchdSpec(context);
|
|
6048
|
-
if (
|
|
6136
|
+
if (existsSync11(spec.plistPath)) {
|
|
6049
6137
|
await runLaunchctl(["bootout", `gui/${process.getuid?.() ?? 0}`, spec.plistPath]).catch(() => void 0);
|
|
6050
6138
|
await rm2(spec.plistPath, { force: true });
|
|
6051
6139
|
}
|
|
@@ -6053,7 +6141,7 @@ async function uninstallService(context) {
|
|
|
6053
6141
|
}
|
|
6054
6142
|
if (process.platform === "linux") {
|
|
6055
6143
|
const spec = buildSystemdUserSpec(context);
|
|
6056
|
-
if (
|
|
6144
|
+
if (existsSync11(spec.unitPath)) {
|
|
6057
6145
|
await runSystemctl(["--user", "disable", "--now", spec.unitName]).catch(() => void 0);
|
|
6058
6146
|
await rm2(spec.unitPath, { force: true });
|
|
6059
6147
|
await runSystemctl(["--user", "daemon-reload"]).catch(() => void 0);
|
|
@@ -6103,7 +6191,7 @@ async function tailServiceLogs(context) {
|
|
|
6103
6191
|
async function readServiceStatus(context) {
|
|
6104
6192
|
if (process.platform === "darwin") {
|
|
6105
6193
|
const spec = buildLaunchdSpec(context);
|
|
6106
|
-
const installed =
|
|
6194
|
+
const installed = existsSync11(spec.plistPath);
|
|
6107
6195
|
const running = installed ? await runLaunchctl(["print", `gui/${process.getuid?.() ?? 0}/${spec.label}`]).then(() => true, () => false) : false;
|
|
6108
6196
|
return {
|
|
6109
6197
|
manager: "launchd",
|
|
@@ -6117,7 +6205,7 @@ async function readServiceStatus(context) {
|
|
|
6117
6205
|
}
|
|
6118
6206
|
if (process.platform === "linux") {
|
|
6119
6207
|
const spec = buildSystemdUserSpec(context);
|
|
6120
|
-
const installed =
|
|
6208
|
+
const installed = existsSync11(spec.unitPath);
|
|
6121
6209
|
const running = installed ? await runSystemctl(["--user", "is-active", "--quiet", spec.unitName]).then(() => true, () => false) : false;
|
|
6122
6210
|
return {
|
|
6123
6211
|
manager: "systemd-user",
|
|
@@ -6147,44 +6235,44 @@ async function readServiceStatus(context) {
|
|
|
6147
6235
|
throw new Error("service_status_not_supported_on_this_platform");
|
|
6148
6236
|
}
|
|
6149
6237
|
function buildLaunchdSpec(context) {
|
|
6150
|
-
const stateDir =
|
|
6238
|
+
const stateDir = join15(homedir9(), ".claude-codex-wechat");
|
|
6151
6239
|
return {
|
|
6152
6240
|
label: "com.claude-codex-wechat",
|
|
6153
|
-
plistPath:
|
|
6241
|
+
plistPath: join15(homedir9(), "Library", "LaunchAgents", "com.claude-codex-wechat.plist"),
|
|
6154
6242
|
programArgs: [context.nodePath ?? process.execPath, context.cliEntrypointPath, "__daemon"],
|
|
6155
|
-
workingDirectory:
|
|
6156
|
-
stdoutPath:
|
|
6157
|
-
stderrPath:
|
|
6243
|
+
workingDirectory: homedir9(),
|
|
6244
|
+
stdoutPath: join15(stateDir, "logs", "service.stdout.log"),
|
|
6245
|
+
stderrPath: join15(stateDir, "logs", "service.stderr.log"),
|
|
6158
6246
|
environment: buildServiceEnvironment(context)
|
|
6159
6247
|
};
|
|
6160
6248
|
}
|
|
6161
6249
|
function buildSystemdUserSpec(context) {
|
|
6162
|
-
const stateDir =
|
|
6250
|
+
const stateDir = join15(homedir9(), ".claude-codex-wechat");
|
|
6163
6251
|
return {
|
|
6164
6252
|
unitName: "claude-codex-wechat.service",
|
|
6165
|
-
unitPath:
|
|
6253
|
+
unitPath: join15(homedir9(), ".config", "systemd", "user", "claude-codex-wechat.service"),
|
|
6166
6254
|
execStart: [context.nodePath ?? process.execPath, context.cliEntrypointPath, "__daemon"],
|
|
6167
|
-
workingDirectory:
|
|
6168
|
-
stdoutPath:
|
|
6169
|
-
stderrPath:
|
|
6255
|
+
workingDirectory: homedir9(),
|
|
6256
|
+
stdoutPath: join15(stateDir, "logs", "service.stdout.log"),
|
|
6257
|
+
stderrPath: join15(stateDir, "logs", "service.stderr.log"),
|
|
6170
6258
|
environment: buildServiceEnvironment(context)
|
|
6171
6259
|
};
|
|
6172
6260
|
}
|
|
6173
6261
|
function buildProcessSpec(context) {
|
|
6174
|
-
const stateDir =
|
|
6262
|
+
const stateDir = join15(homedir9(), ".claude-codex-wechat");
|
|
6175
6263
|
return {
|
|
6176
|
-
pidPath:
|
|
6264
|
+
pidPath: join15(stateDir, "service.pid"),
|
|
6177
6265
|
command: [context.nodePath ?? process.execPath, context.cliEntrypointPath, "__daemon"],
|
|
6178
|
-
workingDirectory:
|
|
6179
|
-
stdoutPath:
|
|
6180
|
-
stderrPath:
|
|
6266
|
+
workingDirectory: homedir9(),
|
|
6267
|
+
stdoutPath: join15(stateDir, "logs", "service.stdout.log"),
|
|
6268
|
+
stderrPath: join15(stateDir, "logs", "service.stderr.log"),
|
|
6181
6269
|
environment: buildServiceEnvironment(context)
|
|
6182
6270
|
};
|
|
6183
6271
|
}
|
|
6184
6272
|
function buildServiceEnvironment(context) {
|
|
6185
6273
|
const env = {
|
|
6186
6274
|
PATH: process.env.PATH ?? "",
|
|
6187
|
-
HOME: process.env.HOME ??
|
|
6275
|
+
HOME: process.env.HOME ?? homedir9()
|
|
6188
6276
|
};
|
|
6189
6277
|
const configPath = context.configPath ?? process.env.BRIDGE_CONFIG;
|
|
6190
6278
|
const port = context.port ?? Number(process.env.BRIDGE_PORT ?? 8787);
|
|
@@ -6302,7 +6390,7 @@ function isProcessAlive(pid) {
|
|
|
6302
6390
|
}
|
|
6303
6391
|
}
|
|
6304
6392
|
async function readPidFile(pidPath) {
|
|
6305
|
-
if (!
|
|
6393
|
+
if (!existsSync11(pidPath)) return null;
|
|
6306
6394
|
try {
|
|
6307
6395
|
const raw = (await readFile6(pidPath, "utf8")).trim();
|
|
6308
6396
|
const pid = Number.parseInt(raw, 10);
|
|
@@ -6353,12 +6441,12 @@ async function spawnDetachedDaemon(spec) {
|
|
|
6353
6441
|
}
|
|
6354
6442
|
}
|
|
6355
6443
|
async function tailFile(path, lines) {
|
|
6356
|
-
if (!
|
|
6444
|
+
if (!existsSync11(path)) return "";
|
|
6357
6445
|
const content = await readFile6(path, "utf8");
|
|
6358
6446
|
return content.split(/\r?\n/).slice(-lines).join("\n").trim();
|
|
6359
6447
|
}
|
|
6360
6448
|
async function tailFiles(paths) {
|
|
6361
|
-
const existing = paths.filter((path) =>
|
|
6449
|
+
const existing = paths.filter((path) => existsSync11(path));
|
|
6362
6450
|
for (const path of existing) {
|
|
6363
6451
|
const tail = await tailFile(path, 200);
|
|
6364
6452
|
if (tail) process.stdout.write(`[${path}]
|
|
@@ -6370,8 +6458,8 @@ ${tail}
|
|
|
6370
6458
|
child.stdout.on("data", (chunk) => {
|
|
6371
6459
|
process.stdout.write(String(chunk));
|
|
6372
6460
|
});
|
|
6373
|
-
await new Promise((
|
|
6374
|
-
child.on("exit", () =>
|
|
6461
|
+
await new Promise((resolve3, reject) => {
|
|
6462
|
+
child.on("exit", () => resolve3());
|
|
6375
6463
|
child.on("error", reject);
|
|
6376
6464
|
});
|
|
6377
6465
|
return;
|
|
@@ -6484,7 +6572,7 @@ function globalNodeModulesCandidates(input, path) {
|
|
|
6484
6572
|
// src/cli.ts
|
|
6485
6573
|
var execFileAsync2 = promisify2(execFile2);
|
|
6486
6574
|
var here = dirname10(fileURLToPath4(import.meta.url));
|
|
6487
|
-
var webRoot =
|
|
6575
|
+
var webRoot = join16(here, "..", "web");
|
|
6488
6576
|
async function main() {
|
|
6489
6577
|
const command = process.argv[2];
|
|
6490
6578
|
switch (command) {
|
|
@@ -6536,7 +6624,7 @@ async function main() {
|
|
|
6536
6624
|
}
|
|
6537
6625
|
}
|
|
6538
6626
|
async function cmdStart() {
|
|
6539
|
-
if (!
|
|
6627
|
+
if (!existsSync12(webRoot)) {
|
|
6540
6628
|
console.error(`\u627E\u4E0D\u5230\u524D\u7AEF\u6784\u5EFA\u4EA7\u7269: ${webRoot}`);
|
|
6541
6629
|
console.error("\u8BF7\u91CD\u65B0\u5B89\u88C5\u5B8C\u6574\u7684 npm \u5305\u3002");
|
|
6542
6630
|
process.exitCode = 1;
|
|
@@ -6621,7 +6709,7 @@ async function cmdTail() {
|
|
|
6621
6709
|
await tailServiceLogs(createServiceContext());
|
|
6622
6710
|
}
|
|
6623
6711
|
async function cmdDaemon() {
|
|
6624
|
-
if (!
|
|
6712
|
+
if (!existsSync12(webRoot)) {
|
|
6625
6713
|
console.error(`\u627E\u4E0D\u5230\u524D\u7AEF\u6784\u5EFA\u4EA7\u7269: ${webRoot}`);
|
|
6626
6714
|
process.exitCode = 1;
|
|
6627
6715
|
return;
|
|
@@ -6634,14 +6722,14 @@ async function cmdDaemon() {
|
|
|
6634
6722
|
async function cmdDoctor() {
|
|
6635
6723
|
const configPath = process.env.BRIDGE_CONFIG ?? defaultConfigPath();
|
|
6636
6724
|
console.log("claude-codex-wechat doctor\n");
|
|
6637
|
-
report("\u914D\u7F6E\u6587\u4EF6",
|
|
6638
|
-
report("\u524D\u7AEF\u4EA7\u7269",
|
|
6725
|
+
report("\u914D\u7F6E\u6587\u4EF6", existsSync12(configPath) ? configPath : `\u7F3A\u5931 (${configPath})\uFF0C\u9996\u6B21 start \u65F6\u81EA\u52A8\u521B\u5EFA`);
|
|
6726
|
+
report("\u524D\u7AEF\u4EA7\u7269", existsSync12(webRoot) ? webRoot : `\u7F3A\u5931 (${webRoot})`);
|
|
6639
6727
|
const searchPath = resolveTerminalSearchPath();
|
|
6640
6728
|
const claude = await findExecutable("claude", searchPath);
|
|
6641
6729
|
report("claude \u53EF\u6267\u884C", claude ?? "\u672A\u627E\u5230\uFF0C\u9700\u5148\u5B89\u88C5\u5E76\u767B\u5F55 Claude Code");
|
|
6642
6730
|
const codex = await findExecutable("codex", searchPath);
|
|
6643
6731
|
report("codex \u53EF\u6267\u884C", codex ?? "\u672A\u627E\u5230\uFF08\u4EC5\u4F7F\u7528 Claude \u65F6\u53EF\u5FFD\u7565\uFF09");
|
|
6644
|
-
if (
|
|
6732
|
+
if (existsSync12(configPath)) {
|
|
6645
6733
|
const config = loadBridgeConfig(configPath);
|
|
6646
6734
|
const wechat = config.wechat;
|
|
6647
6735
|
report("\u5FAE\u4FE1\u542F\u7528", wechat?.enabled ? "\u662F" : "\u5426");
|
|
@@ -6652,7 +6740,7 @@ async function cmdDoctor() {
|
|
|
6652
6740
|
}
|
|
6653
6741
|
function printUpdateHint() {
|
|
6654
6742
|
const configPath = process.env.BRIDGE_CONFIG ?? defaultConfigPath();
|
|
6655
|
-
if (!
|
|
6743
|
+
if (!existsSync12(configPath)) return;
|
|
6656
6744
|
let update;
|
|
6657
6745
|
try {
|
|
6658
6746
|
update = loadBridgeConfig(configPath).update;
|
|
@@ -6670,7 +6758,7 @@ function printUpdateHint() {
|
|
|
6670
6758
|
}
|
|
6671
6759
|
function cmdPrintConfig() {
|
|
6672
6760
|
const configPath = process.env.BRIDGE_CONFIG ?? defaultConfigPath();
|
|
6673
|
-
if (!
|
|
6761
|
+
if (!existsSync12(configPath)) {
|
|
6674
6762
|
console.error(`\u914D\u7F6E\u4E0D\u5B58\u5728: ${configPath}\uFF08\u9996\u6B21 start \u540E\u81EA\u52A8\u751F\u6210\uFF09`);
|
|
6675
6763
|
process.exitCode = 1;
|
|
6676
6764
|
return;
|
|
@@ -6688,7 +6776,7 @@ function createServiceContext() {
|
|
|
6688
6776
|
currentPath: fileURLToPath4(import.meta.url),
|
|
6689
6777
|
execPath: process.execPath,
|
|
6690
6778
|
platform: process.platform,
|
|
6691
|
-
exists:
|
|
6779
|
+
exists: existsSync12,
|
|
6692
6780
|
override: process.env.BRIDGE_CLI_ENTRYPOINT
|
|
6693
6781
|
}),
|
|
6694
6782
|
nodePath: process.execPath,
|