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.
@@ -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 existsSync11, readFileSync as readFileSync10 } from "node:fs";
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 join15 } from "node:path";
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 existsSync9, writeFileSync as writeFileSync2 } from "node:fs";
16
- import { tmpdir as tmpdir2 } from "node:os";
17
- import { dirname as dirname8, join as join12 } from "node:path";
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 join(homedir(), ".claude-codex-wechat", "config.json");
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 join2 } from "node:path";
265
+ import { basename, dirname, join as join3 } from "node:path";
166
266
  var FILE_MODE = 384;
167
267
  function tempPathFor(path) {
168
- return join2(dirname(path), `.${basename(path)}.${process.pid}.${randomBytes(6).toString("hex")}.tmp`);
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((resolve2) => {
182
- setTimeout(resolve2, ms);
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 = join2(dir, name);
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 join3 } from "node:path";
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 join3(env.HOME || homedir2(), ".claude");
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 = join3(resolveClaudeConfigDir(env), "projects");
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 = join3(projectsDir, String(entry.name));
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 = join3(projectDir, fileName);
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 = join3(resolveClaudeConfigDir(env), "projects");
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 = join3(projectsDir, String(entry.name), `${trimmed}.jsonl`);
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 = join3(resolveClaudeConfigDir(env), "history.jsonl");
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 = join3(resolveClaudeConfigDir(env), "sessions");
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 = join3(sessionsDir, String(entry.name));
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 = join3(resolveClaudeConfigDir(env), "history.jsonl");
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 = join3(resolveClaudeConfigDir(input.env), "history.jsonl");
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 join4 } from "node:path";
943
+ import { basename as basename3, join as join5 } from "node:path";
844
944
  function resolveCodexSessionsRoot(env = process.env) {
845
- return join4(env.CODEX_HOME || join4(env.HOME || homedir3(), ".codex"), "sessions");
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 = join4(currentDir, name);
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 = join4(currentDir, name);
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 = join4(env.CODEX_HOME || join4(env.HOME || homedir3(), ".codex"), "session_index.jsonl");
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 = join4(env.CODEX_HOME || join4(env.HOME || homedir3(), ".codex"), "state_5.sqlite");
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 join5 } from "node:path";
1112
+ import { dirname as dirname3, join as join6 } from "node:path";
1013
1113
  function resolveCodexIndexPath(env = process.env) {
1014
- return join5(env.CODEX_HOME || join5(env.HOME || homedir4(), ".codex"), "session_index.jsonl");
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 join6 } from "node:path";
1160
+ import { join as join7 } from "node:path";
1061
1161
  function resolveCodexStateDbPath(env = process.env) {
1062
- return join6(env.CODEX_HOME || join6(env.HOME || homedir5(), ".codex"), "state_5.sqlite");
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((resolve2) => setTimeout(resolve2, ms));
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((resolve2) => setTimeout(resolve2, client.pollIntervalMs));
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 join7, resolve } from "node:path";
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: join7(target, dirent.name), isDirectory: true })).filter((entry) => !entry.name.startsWith(".") || isOnKeepChain(entry.path)).sort((a, b) => a.name.localeCompare(b.name));
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 join8 } from "node:path";
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 = join8(mediaDir, `${idPrefix}_${i}${ext}`);
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((resolve2) => {
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", () => resolve2(false));
3151
- child.on("close", () => resolve2(output.includes("--append-system-prompt")));
3228
+ child.on("error", () => resolve3(false));
3229
+ child.on("close", () => resolve3(output.includes("--append-system-prompt")));
3152
3230
  } catch {
3153
- resolve2(false);
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((resolve2) => {
3244
+ return new Promise((resolve3) => {
3167
3245
  let settled = false;
3168
3246
  const timer = setTimeout(() => {
3169
3247
  if (!settled) {
3170
3248
  settled = true;
3171
- resolve2(IDLE_SENTINEL);
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
- resolve2(chunk);
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 resolve2 = resolveNext;
3406
- if (resolve2) {
3483
+ const resolve3 = resolveNext;
3484
+ if (resolve3) {
3407
3485
  resolveNext = null;
3408
- resolve2(chunk);
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((resolve2) => {
3445
- resolveNext = resolve2;
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((resolve2, reject) => {
3553
- this.pending.set(key, { resolve: resolve2, reject });
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 { dirname as dirname6, join as join10 } from "node:path";
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
- function buildCodexBridgeInstructions(input = {}) {
3657
- const apiBaseUrl = input.apiBaseUrl ?? defaultApiBaseUrl();
3658
- const douyinScript = input.douyinScriptPath ?? defaultDouyinScriptPath();
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
- "\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",
3661
- "",
3662
- "## \u73AF\u5883\u8BF4\u660E",
3663
- "- \u7528\u6237\u770B\u5230\u7684\u662F\u5FAE\u4FE1\u804A\u5929\u754C\u9762\uFF0C\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",
3664
- '- \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',
3665
- "",
3666
- "## \u53D1\u9001\u6587\u4EF6\u5230\u7528\u6237\u5FAE\u4FE1",
3667
- "\u7528 shell \u8C03\u7528\u6865\u63A5\u5C42\u7684\u53D1\u9001\u7AEF\u70B9\u5373\u53EF\uFF08kind \u53D6 image / video / audio / file\uFF09\uFF1A",
3668
- "```bash",
3669
- `curl -sS -X POST ${apiBaseUrl}/api/channel/send-media \\`,
3670
- " -H 'Content-Type: application/json' \\",
3671
- ` -d '{"kind":"video","filePath":"/absolute/path/to/file.mp4"}'`,
3672
- "```",
3673
- "- filePath \u5FC5\u987B\u662F\u7EDD\u5BF9\u8DEF\u5F84\u3002",
3674
- '- \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',
3675
- "",
3676
- "## \u6296\u97F3\u89C6\u9891\u4E0B\u8F7D",
3677
- "\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",
3678
- '- \u7ACB\u5373\u6267\u884C\u4E0B\u8F7D\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',
3679
- "```bash",
3680
- `node ${douyinScript} "<\u6296\u97F3\u94FE\u63A5\u6216\u6574\u6BB5\u5206\u4EAB\u6587\u6848>" --output /tmp`,
3681
- "```",
3682
- "- \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\u5230\u5FAE\u4FE1\u3002",
3683
- "- \u652F\u6301\u77ED\u94FE\u3001\u5B8C\u6574\u94FE\u63A5\u3001\u5206\u4EAB\u6587\u6848\u3001\u7EAF aweme_id\uFF0C\u53EF\u4EE5\u628A\u6574\u6BB5\u6587\u6848\u539F\u6837\u4F20\u8FDB\u53BB\u3002",
3684
- "- \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",
3685
- '- \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',
3686
- "",
3687
- "## \u884C\u4E3A\u51C6\u5219",
3688
- '- \u7528\u6237\u7684"\u6211"\u5C31\u662F\u4ED6\u7684\u5FAE\u4FE1\uFF0C"\u53D1\u7ED9\u6211"\u5C31\u662F\u53D1\u5230\u5FAE\u4FE1\u3002',
3689
- '- \u6267\u884C\u5B8C\u6210\u540E\u7B80\u77ED\u786E\u8BA4\uFF08\u5982"\u5DF2\u53D1\u9001"\uFF09\uFF0C\u4E0D\u9700\u8981\u5197\u957F\u89E3\u91CA\u3002',
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 join10(here2, "..", "mcp", "scripts", "douyin-download.mjs");
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((resolve2, reject) => {
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
- resolve2(IDLE_SENTINEL2);
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
- resolve2(value);
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((resolve2) => {
3839
- session.turnCompletedResolver = resolve2;
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((resolve2) => {
4052
- session.eventResolver = resolve2;
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((resolve2) => {
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
- resolve2({ ok: false, code: error.code ?? "ERROR", stdout, stderr: stderr || error.message });
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) resolve2({ ok: true, stdout, stderr });
4153
- else resolve2({ ok: false, code: code ?? "SIGNAL", stdout, stderr });
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((resolve2) => {
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
- resolve2({ ok: false, code: error.code ?? "ERROR", stdout, stderr: stderr || error.message });
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) resolve2({ ok: true, stdout, stderr });
4189
- else resolve2({ ok: false, code: code ?? "SIGNAL", stdout, stderr });
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 existsSync6, readFileSync as readFileSync5 } from "node:fs";
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 (!existsSync6(this.configPath)) return {};
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((resolve2) => {
4691
- abortGeneration = () => resolve2("aborted");
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 existsSync7, readFileSync as readFileSync6 } from "node:fs";
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 (!existsSync7(this.configPath)) return {};
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 existsSync8 } from "node:fs";
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 (!existsSync8(this.configPath)) return {};
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((resolve2, reject) => {
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
- resolve2(value);
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 join11 } from "node:path";
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(join11(here2, "..", "..", "package.json"), "utf8"));
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 ?? join12(mkdtempSync(join12(tmpdir2(), "claude-codex-wechat-")), "config.json");
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 = join12(dirname8(configPath), "mcp-media.json");
5634
+ const mcpConfigPath = join13(dirname8(configPath), "mcp-media.json");
5555
5635
  const serverDir = dirname8(fileURLToPath3(import.meta.url));
5556
- const mcpMediaServerTs = join12(serverDir, "..", "mcp", "mediaServer.ts");
5557
- const mcpMediaServerJs = join12(serverDir, "..", "mcp", "mediaServer.js");
5558
- const useTs = existsSync9(mcpMediaServerTs) && !existsSync9(mcpMediaServerJs);
5559
- const mcpCommand = useTs ? "tsx" : "node";
5560
- const mcpArgs = [useTs ? mcpMediaServerTs : mcpMediaServerJs];
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 ? join12(dirname8(configPath), "media") : void 0;
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 join13 } from "node:path";
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(join13(webRoot2, "index.html"), "utf8");
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 existsSync10, statSync, openSync as openSync2, closeSync as closeSync2, watchFile } from "node:fs";
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 homedir8 } from "node:os";
5973
- import { dirname as dirname9, join as join14 } from "node:path";
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 (!existsSync10(spec.plistPath)) return await readServiceStatus(context);
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 (!existsSync10(spec.unitPath)) return await readServiceStatus(context);
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 (existsSync10(spec.plistPath)) {
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 (existsSync10(spec.unitPath)) {
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 = existsSync10(spec.plistPath);
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 = existsSync10(spec.unitPath);
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 = join14(homedir8(), ".claude-codex-wechat");
6238
+ const stateDir = join15(homedir9(), ".claude-codex-wechat");
6151
6239
  return {
6152
6240
  label: "com.claude-codex-wechat",
6153
- plistPath: join14(homedir8(), "Library", "LaunchAgents", "com.claude-codex-wechat.plist"),
6241
+ plistPath: join15(homedir9(), "Library", "LaunchAgents", "com.claude-codex-wechat.plist"),
6154
6242
  programArgs: [context.nodePath ?? process.execPath, context.cliEntrypointPath, "__daemon"],
6155
- workingDirectory: homedir8(),
6156
- stdoutPath: join14(stateDir, "logs", "service.stdout.log"),
6157
- stderrPath: join14(stateDir, "logs", "service.stderr.log"),
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 = join14(homedir8(), ".claude-codex-wechat");
6250
+ const stateDir = join15(homedir9(), ".claude-codex-wechat");
6163
6251
  return {
6164
6252
  unitName: "claude-codex-wechat.service",
6165
- unitPath: join14(homedir8(), ".config", "systemd", "user", "claude-codex-wechat.service"),
6253
+ unitPath: join15(homedir9(), ".config", "systemd", "user", "claude-codex-wechat.service"),
6166
6254
  execStart: [context.nodePath ?? process.execPath, context.cliEntrypointPath, "__daemon"],
6167
- workingDirectory: homedir8(),
6168
- stdoutPath: join14(stateDir, "logs", "service.stdout.log"),
6169
- stderrPath: join14(stateDir, "logs", "service.stderr.log"),
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 = join14(homedir8(), ".claude-codex-wechat");
6262
+ const stateDir = join15(homedir9(), ".claude-codex-wechat");
6175
6263
  return {
6176
- pidPath: join14(stateDir, "service.pid"),
6264
+ pidPath: join15(stateDir, "service.pid"),
6177
6265
  command: [context.nodePath ?? process.execPath, context.cliEntrypointPath, "__daemon"],
6178
- workingDirectory: homedir8(),
6179
- stdoutPath: join14(stateDir, "logs", "service.stdout.log"),
6180
- stderrPath: join14(stateDir, "logs", "service.stderr.log"),
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 ?? homedir8()
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 (!existsSync10(pidPath)) return null;
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 (!existsSync10(path)) return "";
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) => existsSync10(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((resolve2, reject) => {
6374
- child.on("exit", () => resolve2());
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 = join15(here, "..", "web");
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 (!existsSync11(webRoot)) {
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 (!existsSync11(webRoot)) {
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", existsSync11(configPath) ? configPath : `\u7F3A\u5931 (${configPath})\uFF0C\u9996\u6B21 start \u65F6\u81EA\u52A8\u521B\u5EFA`);
6638
- report("\u524D\u7AEF\u4EA7\u7269", existsSync11(webRoot) ? webRoot : `\u7F3A\u5931 (${webRoot})`);
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 (existsSync11(configPath)) {
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 (!existsSync11(configPath)) return;
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 (!existsSync11(configPath)) {
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: existsSync11,
6779
+ exists: existsSync12,
6692
6780
  override: process.env.BRIDGE_CLI_ENTRYPOINT
6693
6781
  }),
6694
6782
  nodePath: process.execPath,