claude-codex-wechat 0.1.55 → 0.1.57

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.
@@ -7,12 +7,22 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
7
7
  // src/mcp/tools/sendMedia.ts
8
8
  import { basename } from "node:path";
9
9
  import { z } from "zod";
10
- var BRIDGE_API_URL = process.env.BRIDGE_API_URL || "http://localhost:8787";
11
- async function sendMedia(kind, filePath, fileName) {
12
- const response = await fetch(`${BRIDGE_API_URL}/api/channel/send-media`, {
10
+
11
+ // src/media/sendClient.ts
12
+ function defaultBridgeApiUrl() {
13
+ return process.env.BRIDGE_API_URL || "http://localhost:8787";
14
+ }
15
+ async function sendMediaToWeChat(input) {
16
+ const baseUrl = input.apiBaseUrl ?? defaultBridgeApiUrl();
17
+ const doFetch = input.fetchImpl ?? fetch;
18
+ const response = await doFetch(`${baseUrl}/api/channel/send-media`, {
13
19
  method: "POST",
14
20
  headers: { "content-type": "application/json" },
15
- body: JSON.stringify({ kind, filePath, fileName })
21
+ body: JSON.stringify({
22
+ kind: input.kind,
23
+ filePath: input.filePath,
24
+ ...input.fileName ? { fileName: input.fileName } : {}
25
+ })
16
26
  });
17
27
  if (!response.ok) {
18
28
  const text = await response.text();
@@ -24,6 +34,11 @@ async function sendMedia(kind, filePath, fileName) {
24
34
  }
25
35
  return "\u53D1\u9001\u6210\u529F";
26
36
  }
37
+
38
+ // src/mcp/tools/sendMedia.ts
39
+ async function sendMedia(kind, filePath, fileName) {
40
+ return await sendMediaToWeChat({ kind, filePath, fileName });
41
+ }
27
42
  function registerSendMediaTools(server2) {
28
43
  server2.registerTool(
29
44
  "send_image",
@@ -93,33 +108,46 @@ function registerSendMediaTools(server2) {
93
108
 
94
109
  // src/mcp/tools/douyinDownload.ts
95
110
  import { execFile } from "node:child_process";
96
- import { existsSync } from "node:fs";
97
- import { resolve, dirname, join, basename as basename2 } from "node:path";
98
- import { homedir } from "node:os";
111
+ import { existsSync as existsSync2 } from "node:fs";
112
+ import { dirname, join as join2, basename as basename2 } from "node:path";
113
+ import { homedir as homedir2 } from "node:os";
99
114
  import { fileURLToPath } from "node:url";
100
115
  import { z as z2 } from "zod";
101
- var BRIDGE_API_URL2 = process.env.BRIDGE_API_URL || "http://localhost:8787";
116
+
117
+ // src/media/scriptLocator.ts
118
+ import { existsSync } from "node:fs";
119
+ import { homedir } from "node:os";
120
+ import { join, resolve } from "node:path";
102
121
  function douyinScriptCandidates(baseDir) {
103
122
  return [
104
- // Source layout: src/mcp/tools -> src/mcp/scripts
123
+ // 源码布局:src/mcp/tools -> src/mcp/scripts
105
124
  join(baseDir, "..", "scripts", "douyin-download.mjs"),
106
- // Bundled layout: dist/mcp/mediaServer.js -> dist/mcp/scripts
125
+ // 打包布局:dist/mcp/mediaServer.js -> dist/mcp/scripts
107
126
  join(baseDir, "scripts", "douyin-download.mjs"),
108
- // Older/alternate dist layout fallback
127
+ // 同级包:dist/server -> dist/mcp/scripts(打包后 cli.js 与 mcp/ 平级)
128
+ join(baseDir, "..", "mcp", "scripts", "douyin-download.mjs"),
129
+ // 深一层:src/providers/codex -> src/mcp/scripts
109
130
  join(baseDir, "..", "..", "mcp", "scripts", "douyin-download.mjs"),
110
- // User skills locations (cross-platform)
131
+ // 用户 skills 目录(跨平台)
111
132
  join(homedir(), ".agents", "skills", "douyin-download", "scripts", "douyin-download.mjs"),
112
133
  join(homedir(), ".claude", "skills", "douyin-download", "scripts", "douyin-download.mjs")
113
134
  ];
114
135
  }
136
+ function locateDouyinScript(input) {
137
+ const exists = input.exists ?? existsSync;
138
+ for (const candidate of douyinScriptCandidates(input.baseDir)) {
139
+ const resolved = resolve(candidate);
140
+ if (exists(resolved)) return resolved;
141
+ }
142
+ return void 0;
143
+ }
144
+
145
+ // src/mcp/tools/douyinDownload.ts
115
146
  function findDouyinScript() {
116
147
  const here = dirname(fileURLToPath(import.meta.url));
117
- const candidates = douyinScriptCandidates(here);
118
- for (const p of candidates) {
119
- const resolved = resolve(p);
120
- if (existsSync(resolved)) return resolved;
121
- }
122
- throw new Error("douyin-download \u811A\u672C\u672A\u627E\u5230");
148
+ const found = locateDouyinScript({ baseDir: here });
149
+ if (!found) throw new Error("douyin-download \u811A\u672C\u672A\u627E\u5230");
150
+ return found;
123
151
  }
124
152
  function runScript(args) {
125
153
  const script = findDouyinScript();
@@ -131,19 +159,7 @@ function runScript(args) {
131
159
  });
132
160
  }
133
161
  async function sendToWechat(filePath, kind) {
134
- const fileName = basename2(filePath) || "video.mp4";
135
- const response = await fetch(`${BRIDGE_API_URL2}/api/channel/send-media`, {
136
- method: "POST",
137
- headers: { "content-type": "application/json" },
138
- body: JSON.stringify({ kind, filePath, fileName })
139
- });
140
- if (!response.ok) {
141
- const text = await response.text();
142
- throw new Error(`\u53D1\u9001\u5931\u8D25 (HTTP ${response.status}): ${text}`);
143
- }
144
- const result = await response.json();
145
- if (!result.ok) throw new Error(`\u53D1\u9001\u5931\u8D25: ${result.error ?? "\u672A\u77E5\u9519\u8BEF"}`);
146
- return "\u53D1\u9001\u6210\u529F";
162
+ return await sendMediaToWeChat({ kind, filePath, fileName: basename2(filePath) || "video.mp4" });
147
163
  }
148
164
  function registerDouyinTools(server2) {
149
165
  server2.registerTool(
@@ -160,11 +176,11 @@ function registerDouyinTools(server2) {
160
176
  try {
161
177
  const args = [url];
162
178
  if (outputDir) args.push("--output", outputDir);
163
- else args.push("--output", join(homedir(), "Downloads"));
179
+ else args.push("--output", join2(homedir2(), "Downloads"));
164
180
  const { stdout } = await runScript(args);
165
181
  const pathMatch = stdout.match(/(?:已保存|保存到|saved to|文件路径)[::]\s*(.+?\.mp4)/i) || stdout.match(/(\/[^\s]+\.mp4)/);
166
182
  const filePath = pathMatch?.[1]?.trim();
167
- if (!filePath || !existsSync(filePath)) {
183
+ if (!filePath || !existsSync2(filePath)) {
168
184
  return { content: [{ type: "text", text: `\u4E0B\u8F7D\u5B8C\u6210\u4F46\u672A\u627E\u5230\u6587\u4EF6\u8DEF\u5F84\u3002\u811A\u672C\u8F93\u51FA:
169
185
  ${stdout}` }] };
170
186
  }
@@ -186,6 +202,28 @@ ${stdout}` }] };
186
202
  );
187
203
  }
188
204
 
205
+ // src/media/behavior.ts
206
+ var BRIDGE_RULES = {
207
+ 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',
208
+ 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',
209
+ 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",
210
+ 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',
211
+ 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',
212
+ 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"
213
+ };
214
+ function renderMcpInstructions() {
215
+ return [
216
+ "\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",
217
+ BRIDGE_RULES.sendMeansWeChat,
218
+ "",
219
+ "\u5173\u952E\u884C\u4E3A\uFF1A",
220
+ `- ${BRIDGE_RULES.douyinNoAsking}\u7ACB\u5373\u8C03\u7528 download_douyin \u4E0B\u8F7D\u5E76\u53D1\u9001\u3002${BRIDGE_RULES.ignoreThumbnail}${BRIDGE_RULES.retryOnce}`,
221
+ '- \u7528\u6237\u8BF4"\u628AXX\u53D1\u7ED9\u6211"\u65F6\uFF0C\u6839\u636E\u6587\u4EF6\u7C7B\u578B\u8C03\u7528 send_image/send_video/send_file\u3002',
222
+ '- \u751F\u6210\u4E86\u6587\u4EF6\u540E\u7528\u6237\u8BF4"\u53D1\u7ED9\u6211"\uFF0C\u76F4\u63A5\u8C03\u7528\u5BF9\u5E94\u5DE5\u5177\u53D1\u9001\u3002',
223
+ `- ${BRIDGE_RULES.briefConfirm}`
224
+ ].join("\n");
225
+ }
226
+
189
227
  // src/mcp/mediaServer.ts
190
228
  var server = new McpServer(
191
229
  {
@@ -193,16 +231,7 @@ var server = new McpServer(
193
231
  version: "1.0.0"
194
232
  },
195
233
  {
196
- instructions: [
197
- "\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",
198
- '\u7528\u6237\u8BF4\u7684"\u53D1\u7ED9\u6211""\u53D1\u5230\u5FAE\u4FE1""\u53D1\u51FA\u6765""\u4F20\u7ED9\u6211"\u90FD\u662F\u6307\u901A\u8FC7\u672C\u670D\u52A1\u5668\u7684\u5DE5\u5177\u53D1\u9001\u6587\u4EF6\u5230\u7528\u6237\u5FAE\u4FE1\u3002',
199
- "",
200
- "\u5173\u952E\u884C\u4E3A\uFF1A",
201
- '- \u5F53\u7528\u6237\u53D1\u6765\u6296\u97F3\u94FE\u63A5\u6216\u5206\u4EAB\u6587\u6848\u65F6\uFF0C\u7ACB\u5373\u8C03\u7528 download_douyin \u4E0B\u8F7D\u5E76\u53D1\u9001\uFF0C\u65E0\u9700\u8BE2\u95EE\uFF1B\u5206\u4EAB\u81EA\u5E26\u7684\u7F29\u7565\u56FE\u9644\u4EF6\u5373\u4F7F\u5931\u8D25\u4E5F\u5FFD\u7565\uFF0C\u4E0D\u8981\u5C94\u5F00\u53BB\u804A\u56FE\u7247\u3002download_douyin \u5931\u8D25\u65F6\u5148\u91CD\u8BD5\u4E00\u6B21\uFF0C\u4ECD\u5931\u8D25\u5C31\u4E00\u53E5\u8BDD\u544A\u77E5\u7528\u6237"\u6296\u97F3\u4E0B\u8F7D\u5931\u8D25\uFF1A<\u539F\u56E0>"\u3002',
202
- '- \u5F53\u7528\u6237\u8BF4"\u628AXX\u53D1\u7ED9\u6211"\u65F6\uFF0C\u6839\u636E\u6587\u4EF6\u7C7B\u578B\u8C03\u7528 send_image/send_video/send_file\u3002',
203
- '- \u751F\u6210\u4E86\u6587\u4EF6\u540E\u7528\u6237\u8BF4"\u53D1\u7ED9\u6211"\uFF0C\u76F4\u63A5\u8C03\u7528\u5BF9\u5E94\u5DE5\u5177\u53D1\u9001\u3002',
204
- "- \u5B8C\u6210\u540E\u7B80\u77ED\u786E\u8BA4\u5373\u53EF\uFF0C\u4E0D\u9700\u8981\u5197\u957F\u89E3\u91CA\u3002"
205
- ].join("\n")
234
+ instructions: renderMcpInstructions()
206
235
  }
207
236
  );
208
237
  registerSendMediaTools(server);
@@ -3,18 +3,18 @@ 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
18
  import { fileURLToPath as fileURLToPath3 } from "node:url";
19
19
  import Fastify from "fastify";
20
20
 
@@ -178,8 +178,8 @@ function sleepSync(ms) {
178
178
  Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
179
179
  }
180
180
  function sleep(ms) {
181
- return new Promise((resolve2) => {
182
- setTimeout(resolve2, ms);
181
+ return new Promise((resolve3) => {
182
+ setTimeout(resolve3, ms);
183
183
  });
184
184
  }
185
185
  function writeFileAtomicSync(path, data) {
@@ -1120,7 +1120,7 @@ async function syncCodexRolloutSessionMeta(rolloutPath) {
1120
1120
  }
1121
1121
  }
1122
1122
  async function delay(ms) {
1123
- await new Promise((resolve2) => setTimeout(resolve2, ms));
1123
+ await new Promise((resolve3) => setTimeout(resolve3, ms));
1124
1124
  }
1125
1125
 
1126
1126
  // src/session/providerAutoAttach.ts
@@ -1301,7 +1301,7 @@ function registerChannelAdminRoutes(input) {
1301
1301
 
1302
1302
  `);
1303
1303
  while (true) {
1304
- await new Promise((resolve2) => setTimeout(resolve2, client.pollIntervalMs));
1304
+ await new Promise((resolve3) => setTimeout(resolve3, client.pollIntervalMs));
1305
1305
  const status = await client.pollQrCodeStatus(qr.ticket);
1306
1306
  if (status.status === "waiting") continue;
1307
1307
  if (status.status === "scanned") {
@@ -3091,41 +3091,92 @@ function mapChoiceReply(text, labels, multiSelect) {
3091
3091
  return picked.length > 0 ? picked.join(", ") : null;
3092
3092
  }
3093
3093
 
3094
+ // src/media/behavior.ts
3095
+ var BRIDGE_RULES = {
3096
+ 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',
3097
+ 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',
3098
+ 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",
3099
+ 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',
3100
+ 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',
3101
+ 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"
3102
+ };
3103
+ 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";
3104
+ function renderClaudeSystemPrompt() {
3105
+ return [
3106
+ "\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",
3107
+ "",
3108
+ "## \u73AF\u5883\u8BF4\u660E",
3109
+ "- \u7528\u6237\u770B\u5230\u7684\u662F\u5FAE\u4FE1\u804A\u5929\u754C\u9762\u3002",
3110
+ `- ${BRIDGE_RULES.sendMeansWeChat}`,
3111
+ `- ${BRIDGE_RULES.noInteractiveUI}`,
3112
+ "- \u4E0D\u8981\u8C03\u7528 AskUserQuestion \u5DE5\u5177\uFF08\u6B64\u73AF\u5883\u65E0\u6CD5\u4EA4\u4E92\uFF09\u3002",
3113
+ "",
3114
+ "## \u53D1\u9001\u6587\u4EF6\u5230\u7528\u6237\u5FAE\u4FE1",
3115
+ "- \u56FE\u7247 \u2192 send_image",
3116
+ "- \u89C6\u9891 \u2192 send_video",
3117
+ "- \u97F3\u9891 \u2192 send_audio\uFF08\u4EE5\u6587\u4EF6\u9644\u4EF6\u5F62\u5F0F\u53D1\u9001\uFF09",
3118
+ "- \u5176\u4ED6\u6587\u4EF6\uFF08PDF/\u6587\u6863/\u4EE3\u7801/\u538B\u7F29\u5305\u7B49\uFF09\u2192 send_file",
3119
+ "",
3120
+ "## \u6296\u97F3\u89C6\u9891\u4E0B\u8F7D",
3121
+ `- ${BRIDGE_RULES.douyinNoAsking}`,
3122
+ "- \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",
3123
+ `- ${DOUYIN_INPUT_FORMS}`,
3124
+ `- ${BRIDGE_RULES.ignoreThumbnail}`,
3125
+ `- ${BRIDGE_RULES.retryOnce}`,
3126
+ "",
3127
+ "## \u884C\u4E3A\u51C6\u5219",
3128
+ '- \u7528\u6237\u7684"\u6211"\u5C31\u662F\u4ED6\u7684\u5FAE\u4FE1\u3002',
3129
+ `- ${BRIDGE_RULES.briefConfirm}`,
3130
+ "- \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",
3131
+ '- \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'
3132
+ ].join("\n");
3133
+ }
3134
+ function renderCodexInstructions(input) {
3135
+ const isWindows2 = input.platform === "win32";
3136
+ const curl = isWindows2 ? "curl.exe" : "curl";
3137
+ const shellTag = isWindows2 ? "powershell" : "bash";
3138
+ const tmpDir = input.tmpDir ?? (isWindows2 ? "%TEMP%" : "/tmp");
3139
+ const quote = (value) => `"${value}"`;
3140
+ return [
3141
+ "\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",
3142
+ "",
3143
+ "## \u73AF\u5883\u8BF4\u660E",
3144
+ `- \u7528\u6237\u770B\u5230\u7684\u662F\u5FAE\u4FE1\u804A\u5929\u754C\u9762\u3002${BRIDGE_RULES.noInteractiveUI}`,
3145
+ `- ${BRIDGE_RULES.sendMeansWeChat}`,
3146
+ "",
3147
+ "## \u53D1\u9001\u6587\u4EF6\u5230\u7528\u6237\u5FAE\u4FE1",
3148
+ "\u7528 shell \u8C03\u7528\u6865\u63A5\u5C42\u7684\u53D1\u9001\u7AEF\u70B9\u5373\u53EF\uFF08kind \u53D6 image / video / audio / file\uFF09\uFF1A",
3149
+ "```" + shellTag,
3150
+ // Windows 给单行:PowerShell 的续行符是反引号,POSIX 的反斜杠会被当成参数传进去。
3151
+ ...isWindows2 ? [`${curl} -sS -X POST ${input.apiBaseUrl}/api/channel/send-media -H 'Content-Type: application/json' -d '{"kind":"video","filePath":"<\u7EDD\u5BF9\u8DEF\u5F84>"}'`] : [
3152
+ `${curl} -sS -X POST ${input.apiBaseUrl}/api/channel/send-media \\`,
3153
+ " -H 'Content-Type: application/json' \\",
3154
+ ` -d '{"kind":"video","filePath":"<\u7EDD\u5BF9\u8DEF\u5F84>"}'`
3155
+ ],
3156
+ "```",
3157
+ "- 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",
3158
+ '- \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',
3159
+ "",
3160
+ "## \u6296\u97F3\u89C6\u9891\u4E0B\u8F7D",
3161
+ "\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",
3162
+ `- ${BRIDGE_RULES.douyinNoAsking}`,
3163
+ "```" + shellTag,
3164
+ `node ${quote(input.douyinScriptPath)} "<\u6296\u97F3\u94FE\u63A5\u6216\u6574\u6BB5\u5206\u4EAB\u6587\u6848>" --output ${quote(tmpDir)}`,
3165
+ "```",
3166
+ "- \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",
3167
+ `- ${DOUYIN_INPUT_FORMS}\u53EF\u4EE5\u628A\u6574\u6BB5\u6587\u6848\u539F\u6837\u4F20\u8FDB\u53BB\u3002`,
3168
+ `- ${BRIDGE_RULES.ignoreThumbnail}`,
3169
+ `- ${BRIDGE_RULES.retryOnce}`,
3170
+ "",
3171
+ "## \u884C\u4E3A\u51C6\u5219",
3172
+ '- \u7528\u6237\u7684"\u6211"\u5C31\u662F\u4ED6\u7684\u5FAE\u4FE1\u3002',
3173
+ `- ${BRIDGE_RULES.briefConfirm}`,
3174
+ '- \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'
3175
+ ].join("\n");
3176
+ }
3177
+
3094
3178
  // 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");
3179
+ var BRIDGE_APPEND_SYSTEM_PROMPT = renderClaudeSystemPrompt();
3129
3180
 
3130
3181
  // src/providers/claude-code/claudeCapabilities.ts
3131
3182
  import { spawn as spawn2 } from "node:child_process";
@@ -3138,7 +3189,7 @@ var probeAppendSystemPromptSupport = (command) => {
3138
3189
  return result;
3139
3190
  };
3140
3191
  function runHelpProbe(command) {
3141
- return new Promise((resolve2) => {
3192
+ return new Promise((resolve3) => {
3142
3193
  try {
3143
3194
  const child = spawn2(command, ["--help"], { stdio: ["ignore", "pipe", "pipe"], shell: useShellForCli() });
3144
3195
  let output = "";
@@ -3147,10 +3198,10 @@ function runHelpProbe(command) {
3147
3198
  };
3148
3199
  child.stdout?.on("data", collect);
3149
3200
  child.stderr?.on("data", collect);
3150
- child.on("error", () => resolve2(false));
3151
- child.on("close", () => resolve2(output.includes("--append-system-prompt")));
3201
+ child.on("error", () => resolve3(false));
3202
+ child.on("close", () => resolve3(output.includes("--append-system-prompt")));
3152
3203
  } catch {
3153
- resolve2(false);
3204
+ resolve3(false);
3154
3205
  }
3155
3206
  });
3156
3207
  }
@@ -3163,12 +3214,12 @@ function capTail(text, capBytes) {
3163
3214
  }
3164
3215
  function readWithIdleTimeout(handle, ms) {
3165
3216
  if (!ms || ms <= 0) return handle.read();
3166
- return new Promise((resolve2) => {
3217
+ return new Promise((resolve3) => {
3167
3218
  let settled = false;
3168
3219
  const timer = setTimeout(() => {
3169
3220
  if (!settled) {
3170
3221
  settled = true;
3171
- resolve2(IDLE_SENTINEL);
3222
+ resolve3(IDLE_SENTINEL);
3172
3223
  }
3173
3224
  }, ms);
3174
3225
  timer.unref?.();
@@ -3176,7 +3227,7 @@ function readWithIdleTimeout(handle, ms) {
3176
3227
  if (!settled) {
3177
3228
  settled = true;
3178
3229
  clearTimeout(timer);
3179
- resolve2(chunk);
3230
+ resolve3(chunk);
3180
3231
  }
3181
3232
  });
3182
3233
  });
@@ -3402,10 +3453,10 @@ function defaultClaudeStreamSpawner(call, opts = {}) {
3402
3453
  const queue = [];
3403
3454
  let resolveNext = null;
3404
3455
  const push = (chunk) => {
3405
- const resolve2 = resolveNext;
3406
- if (resolve2) {
3456
+ const resolve3 = resolveNext;
3457
+ if (resolve3) {
3407
3458
  resolveNext = null;
3408
- resolve2(chunk);
3459
+ resolve3(chunk);
3409
3460
  } else {
3410
3461
  queue.push(chunk);
3411
3462
  }
@@ -3441,8 +3492,8 @@ function defaultClaudeStreamSpawner(call, opts = {}) {
3441
3492
  read() {
3442
3493
  const next = queue.shift();
3443
3494
  if (next) return Promise.resolve(next);
3444
- return new Promise((resolve2) => {
3445
- resolveNext = resolve2;
3495
+ return new Promise((resolve3) => {
3496
+ resolveNext = resolve3;
3446
3497
  });
3447
3498
  },
3448
3499
  close() {
@@ -3549,8 +3600,8 @@ var CodexAppServerClient = class {
3549
3600
  const id = this.nextId++;
3550
3601
  const key = String(id);
3551
3602
  const payload = { id, method, ...params !== void 0 ? { params } : {} };
3552
- const response = new Promise((resolve2, reject) => {
3553
- this.pending.set(key, { resolve: resolve2, reject });
3603
+ const response = new Promise((resolve3, reject) => {
3604
+ this.pending.set(key, { resolve: resolve3, reject });
3554
3605
  });
3555
3606
  this.child.stdin.write(`${JSON.stringify(payload)}
3556
3607
  `);
@@ -3651,44 +3702,46 @@ var CodexAppServerClient = class {
3651
3702
  };
3652
3703
 
3653
3704
  // src/providers/codex/bridgeDeveloperInstructions.ts
3654
- import { dirname as dirname6, join as join10 } from "node:path";
3705
+ import { tmpdir as tmpdir2 } from "node:os";
3706
+ import { dirname as dirname6, join as join11 } from "node:path";
3655
3707
  import { fileURLToPath } from "node:url";
3656
- function buildCodexBridgeInstructions(input = {}) {
3657
- const apiBaseUrl = input.apiBaseUrl ?? defaultApiBaseUrl();
3658
- const douyinScript = input.douyinScriptPath ?? defaultDouyinScriptPath();
3708
+
3709
+ // src/media/scriptLocator.ts
3710
+ import { existsSync as existsSync6 } from "node:fs";
3711
+ import { homedir as homedir8 } from "node:os";
3712
+ import { join as join10, resolve as resolve2 } from "node:path";
3713
+ function douyinScriptCandidates(baseDir) {
3659
3714
  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");
3715
+ // 源码布局:src/mcp/tools -> src/mcp/scripts
3716
+ join10(baseDir, "..", "scripts", "douyin-download.mjs"),
3717
+ // 打包布局:dist/mcp/mediaServer.js -> dist/mcp/scripts
3718
+ join10(baseDir, "scripts", "douyin-download.mjs"),
3719
+ // 同级包:dist/server -> dist/mcp/scripts(打包后 cli.js 与 mcp/ 平级)
3720
+ join10(baseDir, "..", "mcp", "scripts", "douyin-download.mjs"),
3721
+ // 深一层:src/providers/codex -> src/mcp/scripts
3722
+ join10(baseDir, "..", "..", "mcp", "scripts", "douyin-download.mjs"),
3723
+ // 用户 skills 目录(跨平台)
3724
+ join10(homedir8(), ".agents", "skills", "douyin-download", "scripts", "douyin-download.mjs"),
3725
+ join10(homedir8(), ".claude", "skills", "douyin-download", "scripts", "douyin-download.mjs")
3726
+ ];
3727
+ }
3728
+ function locateDouyinScript(input) {
3729
+ const exists = input.exists ?? existsSync6;
3730
+ for (const candidate of douyinScriptCandidates(input.baseDir)) {
3731
+ const resolved = resolve2(candidate);
3732
+ if (exists(resolved)) return resolved;
3733
+ }
3734
+ return void 0;
3735
+ }
3736
+
3737
+ // src/providers/codex/bridgeDeveloperInstructions.ts
3738
+ function buildCodexBridgeInstructions(input = {}) {
3739
+ return renderCodexInstructions({
3740
+ platform: input.platform ?? process.platform,
3741
+ apiBaseUrl: input.apiBaseUrl ?? defaultApiBaseUrl(),
3742
+ douyinScriptPath: input.douyinScriptPath ?? defaultDouyinScriptPath(),
3743
+ tmpDir: input.tmpDir ?? tmpdir2()
3744
+ });
3692
3745
  }
3693
3746
  function defaultApiBaseUrl() {
3694
3747
  const port = process.env.BRIDGE_PORT ?? "8787";
@@ -3696,19 +3749,19 @@ function defaultApiBaseUrl() {
3696
3749
  }
3697
3750
  function defaultDouyinScriptPath() {
3698
3751
  const here2 = dirname6(fileURLToPath(import.meta.url));
3699
- return join10(here2, "..", "mcp", "scripts", "douyin-download.mjs");
3752
+ return locateDouyinScript({ baseDir: here2 }) ?? join11(here2, "..", "mcp", "scripts", "douyin-download.mjs");
3700
3753
  }
3701
3754
 
3702
3755
  // src/providers/codex/codexInteractiveRunner.ts
3703
3756
  var IDLE_SENTINEL2 = /* @__PURE__ */ Symbol("idle_timeout");
3704
3757
  function withIdleTimeout(promise, ms) {
3705
3758
  if (!ms || ms <= 0) return promise;
3706
- return new Promise((resolve2, reject) => {
3759
+ return new Promise((resolve3, reject) => {
3707
3760
  let settled = false;
3708
3761
  const timer = setTimeout(() => {
3709
3762
  if (!settled) {
3710
3763
  settled = true;
3711
- resolve2(IDLE_SENTINEL2);
3764
+ resolve3(IDLE_SENTINEL2);
3712
3765
  }
3713
3766
  }, ms);
3714
3767
  timer.unref?.();
@@ -3717,7 +3770,7 @@ function withIdleTimeout(promise, ms) {
3717
3770
  if (settled) return;
3718
3771
  settled = true;
3719
3772
  clearTimeout(timer);
3720
- resolve2(value);
3773
+ resolve3(value);
3721
3774
  },
3722
3775
  (error) => {
3723
3776
  if (settled) return;
@@ -3835,8 +3888,8 @@ var CodexInteractiveRunner = class {
3835
3888
  session.activeTurnId = void 0;
3836
3889
  session.turnClosed = false;
3837
3890
  session.emittedTextThisTurn = false;
3838
- session.turnCompletedPromise = new Promise((resolve2) => {
3839
- session.turnCompletedResolver = resolve2;
3891
+ session.turnCompletedPromise = new Promise((resolve3) => {
3892
+ session.turnCompletedResolver = resolve3;
3840
3893
  });
3841
3894
  if (session.threadId) {
3842
3895
  const resumed = await withIdleTimeout(client.request("thread/resume", {
@@ -4048,8 +4101,8 @@ var CodexInteractiveRunner = class {
4048
4101
  const next = session.pendingEvents.shift();
4049
4102
  if (next) return next;
4050
4103
  if (session.turnClosed) return null;
4051
- await new Promise((resolve2) => {
4052
- session.eventResolver = resolve2;
4104
+ await new Promise((resolve3) => {
4105
+ session.eventResolver = resolve3;
4053
4106
  });
4054
4107
  }
4055
4108
  }
@@ -4135,7 +4188,7 @@ function createDefaultProviders(input = {}) {
4135
4188
  // src/providers/claude-code/claudeDetection.ts
4136
4189
  import { spawn as spawn5 } from "node:child_process";
4137
4190
  async function defaultCommandRunner(command, args) {
4138
- return await new Promise((resolve2) => {
4191
+ return await new Promise((resolve3) => {
4139
4192
  const child = spawn5(command, args, { stdio: ["ignore", "pipe", "pipe"], shell: useShellForCli() });
4140
4193
  let stdout = "";
4141
4194
  let stderr = "";
@@ -4146,11 +4199,11 @@ async function defaultCommandRunner(command, args) {
4146
4199
  stderr += String(chunk);
4147
4200
  });
4148
4201
  child.on("error", (error) => {
4149
- resolve2({ ok: false, code: error.code ?? "ERROR", stdout, stderr: stderr || error.message });
4202
+ resolve3({ ok: false, code: error.code ?? "ERROR", stdout, stderr: stderr || error.message });
4150
4203
  });
4151
4204
  child.on("close", (code) => {
4152
- if (code === 0) resolve2({ ok: true, stdout, stderr });
4153
- else resolve2({ ok: false, code: code ?? "SIGNAL", stdout, stderr });
4205
+ if (code === 0) resolve3({ ok: true, stdout, stderr });
4206
+ else resolve3({ ok: false, code: code ?? "SIGNAL", stdout, stderr });
4154
4207
  });
4155
4208
  });
4156
4209
  }
@@ -4171,7 +4224,7 @@ ${result.stderr}`) };
4171
4224
  // src/providers/codex/codexDetection.ts
4172
4225
  import { spawn as spawn6 } from "node:child_process";
4173
4226
  async function defaultCodexCommandRunner(command, args) {
4174
- return await new Promise((resolve2) => {
4227
+ return await new Promise((resolve3) => {
4175
4228
  const child = spawn6(command, args, { stdio: ["ignore", "pipe", "pipe"], shell: useShellForCli() });
4176
4229
  let stdout = "";
4177
4230
  let stderr = "";
@@ -4182,11 +4235,11 @@ async function defaultCodexCommandRunner(command, args) {
4182
4235
  stderr += String(chunk);
4183
4236
  });
4184
4237
  child.on("error", (error) => {
4185
- resolve2({ ok: false, code: error.code ?? "ERROR", stdout, stderr: stderr || error.message });
4238
+ resolve3({ ok: false, code: error.code ?? "ERROR", stdout, stderr: stderr || error.message });
4186
4239
  });
4187
4240
  child.on("close", (code) => {
4188
- if (code === 0) resolve2({ ok: true, stdout, stderr });
4189
- else resolve2({ ok: false, code: code ?? "SIGNAL", stdout, stderr });
4241
+ if (code === 0) resolve3({ ok: true, stdout, stderr });
4242
+ else resolve3({ ok: false, code: code ?? "SIGNAL", stdout, stderr });
4190
4243
  });
4191
4244
  });
4192
4245
  }
@@ -4323,7 +4376,7 @@ function buildBridgeCommandHelpMarkdown(input) {
4323
4376
  }
4324
4377
 
4325
4378
  // src/session/currentConversationStore.ts
4326
- import { existsSync as existsSync6, readFileSync as readFileSync5 } from "node:fs";
4379
+ import { existsSync as existsSync7, readFileSync as readFileSync5 } from "node:fs";
4327
4380
  import { nanoid as nanoid2 } from "nanoid";
4328
4381
  var CurrentConversationStore = class {
4329
4382
  constructor(configPath, defaults) {
@@ -4382,7 +4435,7 @@ var CurrentConversationStore = class {
4382
4435
  this.writeState(state);
4383
4436
  }
4384
4437
  readState() {
4385
- if (!existsSync6(this.configPath)) return {};
4438
+ if (!existsSync7(this.configPath)) return {};
4386
4439
  const raw = JSON.parse(readFileSync5(this.configPath, "utf8"));
4387
4440
  return raw && typeof raw === "object" ? raw : {};
4388
4441
  }
@@ -4687,8 +4740,8 @@ var MessageRouter = class _MessageRouter {
4687
4740
  }
4688
4741
  const genId = ++this.generationSeq;
4689
4742
  let abortGeneration;
4690
- const aborted = new Promise((resolve2) => {
4691
- abortGeneration = () => resolve2("aborted");
4743
+ const aborted = new Promise((resolve3) => {
4744
+ abortGeneration = () => resolve3("aborted");
4692
4745
  });
4693
4746
  this.activeGenerations.set(message.chatId, {
4694
4747
  genId,
@@ -5059,7 +5112,7 @@ function composeInboundText(content) {
5059
5112
  }
5060
5113
 
5061
5114
  // src/storage/lastProviderSessionStore.ts
5062
- import { existsSync as existsSync7, readFileSync as readFileSync6 } from "node:fs";
5115
+ import { existsSync as existsSync8, readFileSync as readFileSync6 } from "node:fs";
5063
5116
  var LastProviderSessionStore = class {
5064
5117
  constructor(configPath) {
5065
5118
  this.configPath = configPath;
@@ -5085,7 +5138,7 @@ var LastProviderSessionStore = class {
5085
5138
  return this.readState().bridge?.lastProviderSessions ?? {};
5086
5139
  }
5087
5140
  readState() {
5088
- if (!existsSync7(this.configPath)) return {};
5141
+ if (!existsSync8(this.configPath)) return {};
5089
5142
  const raw = JSON.parse(readFileSync6(this.configPath, "utf8"));
5090
5143
  return raw && typeof raw === "object" ? raw : {};
5091
5144
  }
@@ -5096,7 +5149,7 @@ var LastProviderSessionStore = class {
5096
5149
  };
5097
5150
 
5098
5151
  // src/storage/runtimeUserStore.ts
5099
- import { readFileSync as readFileSync7, existsSync as existsSync8 } from "node:fs";
5152
+ import { readFileSync as readFileSync7, existsSync as existsSync9 } from "node:fs";
5100
5153
  import { nanoid as nanoid3 } from "nanoid";
5101
5154
  var RuntimeUserStore = class {
5102
5155
  constructor(configPath) {
@@ -5156,7 +5209,7 @@ var RuntimeUserStore = class {
5156
5209
  return { ok: true };
5157
5210
  }
5158
5211
  readState() {
5159
- if (!existsSync8(this.configPath)) return {};
5212
+ if (!existsSync9(this.configPath)) return {};
5160
5213
  const raw = JSON.parse(readFileSync7(this.configPath, "utf8"));
5161
5214
  return raw && typeof raw === "object" ? raw : {};
5162
5215
  }
@@ -5250,12 +5303,12 @@ var RelayTunnelProvider = class {
5250
5303
  };
5251
5304
  const socket = this.options.createSocket(this.options.serverUrl);
5252
5305
  this.socket = socket;
5253
- return new Promise((resolve2, reject) => {
5306
+ return new Promise((resolve3, reject) => {
5254
5307
  let settled = false;
5255
5308
  const finishResolve = (value) => {
5256
5309
  if (settled) return;
5257
5310
  settled = true;
5258
- resolve2(value);
5311
+ resolve3(value);
5259
5312
  };
5260
5313
  const finishReject = (error) => {
5261
5314
  if (settled) return;
@@ -5490,12 +5543,12 @@ var RelayTunnelRouter = class {
5490
5543
 
5491
5544
  // src/shared/version.ts
5492
5545
  import { readFileSync as readFileSync8 } from "node:fs";
5493
- import { dirname as dirname7, join as join11 } from "node:path";
5546
+ import { dirname as dirname7, join as join12 } from "node:path";
5494
5547
  import { fileURLToPath as fileURLToPath2 } from "node:url";
5495
5548
  function readClientVersion() {
5496
5549
  try {
5497
5550
  const here2 = dirname7(fileURLToPath2(import.meta.url));
5498
- const pkg = JSON.parse(readFileSync8(join11(here2, "..", "..", "package.json"), "utf8"));
5551
+ const pkg = JSON.parse(readFileSync8(join12(here2, "..", "..", "package.json"), "utf8"));
5499
5552
  return typeof pkg.version === "string" && pkg.version ? pkg.version : "0.0.0";
5500
5553
  } catch {
5501
5554
  return "0.0.0";
@@ -5514,7 +5567,7 @@ function readUpdateStatusBestEffort(configPath) {
5514
5567
  function createDaemonServer(options = {}) {
5515
5568
  const app = Fastify({ logger: true });
5516
5569
  const events = new BridgeEventHub();
5517
- const configPath = options.configPath ?? process.env.BRIDGE_CONFIG ?? join12(mkdtempSync(join12(tmpdir2(), "claude-codex-wechat-")), "config.json");
5570
+ const configPath = options.configPath ?? process.env.BRIDGE_CONFIG ?? join13(mkdtempSync(join13(tmpdir3(), "claude-codex-wechat-")), "config.json");
5518
5571
  const persistedConfig = loadBridgeConfig(configPath);
5519
5572
  const bridgeDefaults = {
5520
5573
  defaultProvider: options.bridgeDefaults?.defaultProvider ?? persistedConfig.bridge?.defaultProvider ?? "claude-code",
@@ -5551,11 +5604,11 @@ function createDaemonServer(options = {}) {
5551
5604
  const lastProviderSessions = new LastProviderSessionStore(configPath);
5552
5605
  const sessionBindingMatch = /* @__PURE__ */ new Map();
5553
5606
  const bridgePort = process.env.BRIDGE_PORT ?? "8787";
5554
- const mcpConfigPath = join12(dirname8(configPath), "mcp-media.json");
5607
+ const mcpConfigPath = join13(dirname8(configPath), "mcp-media.json");
5555
5608
  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);
5609
+ const mcpMediaServerTs = join13(serverDir, "..", "mcp", "mediaServer.ts");
5610
+ const mcpMediaServerJs = join13(serverDir, "..", "mcp", "mediaServer.js");
5611
+ const useTs = existsSync10(mcpMediaServerTs) && !existsSync10(mcpMediaServerJs);
5559
5612
  const mcpCommand = useTs ? "tsx" : "node";
5560
5613
  const mcpArgs = [useTs ? mcpMediaServerTs : mcpMediaServerJs];
5561
5614
  writeFileSync2(mcpConfigPath, JSON.stringify({
@@ -5589,7 +5642,7 @@ function createDaemonServer(options = {}) {
5589
5642
  });
5590
5643
  }
5591
5644
  const weixinStateStore = configPath ? new FileWeixinStateStore(configPath) : void 0;
5592
- const weixinMediaDir = configPath ? join12(dirname8(configPath), "media") : void 0;
5645
+ const weixinMediaDir = configPath ? join13(dirname8(configPath), "media") : void 0;
5593
5646
  const managedWechatChannel = options.channel ? null : new ManagedWeixinDirectAdapter(options.wechat, weixinStateStore, weixinMediaDir);
5594
5647
  const channel = options.channel ?? managedWechatChannel;
5595
5648
  const weixinOutboundGate = managedWechatChannel && weixinStateStore ? new WeixinOutboundGate({
@@ -5756,6 +5809,12 @@ function createDaemonServer(options = {}) {
5756
5809
  if (!kind || !validKinds.includes(kind)) {
5757
5810
  return reply.code(400).send({ ok: false, error: `kind must be one of: ${validKinds.join(", ")}` });
5758
5811
  }
5812
+ if (!isAbsolute(filePath)) {
5813
+ return reply.code(400).send({ ok: false, error: `filePath must be an absolute path: ${filePath}` });
5814
+ }
5815
+ if (!existsSync10(filePath)) {
5816
+ return reply.code(400).send({ ok: false, error: `file not found: ${filePath}` });
5817
+ }
5759
5818
  if (!channel) {
5760
5819
  return reply.code(503).send({ ok: false, error: "channel not available" });
5761
5820
  }
@@ -5947,7 +6006,7 @@ async function resolveProviderCommands(providers) {
5947
6006
 
5948
6007
  // src/daemon/staticFrontend.ts
5949
6008
  import { readFileSync as readFileSync9 } from "node:fs";
5950
- import { join as join13 } from "node:path";
6009
+ import { join as join14 } from "node:path";
5951
6010
  import fastifyStatic from "@fastify/static";
5952
6011
  function attachStaticFrontend(webRoot2) {
5953
6012
  return async (app) => {
@@ -5955,7 +6014,7 @@ function attachStaticFrontend(webRoot2) {
5955
6014
  root: webRoot2,
5956
6015
  wildcard: false
5957
6016
  });
5958
- const indexHtml = readFileSync9(join13(webRoot2, "index.html"), "utf8");
6017
+ const indexHtml = readFileSync9(join14(webRoot2, "index.html"), "utf8");
5959
6018
  app.setNotFoundHandler((request, reply) => {
5960
6019
  if (request.url.startsWith("/api")) {
5961
6020
  reply.code(404).send({ error: "not_found" });
@@ -5967,10 +6026,10 @@ function attachStaticFrontend(webRoot2) {
5967
6026
  }
5968
6027
 
5969
6028
  // src/daemon/service.ts
5970
- import { existsSync as existsSync10, statSync, openSync as openSync2, closeSync as closeSync2, watchFile } from "node:fs";
6029
+ import { existsSync as existsSync11, statSync, openSync as openSync2, closeSync as closeSync2, watchFile } from "node:fs";
5971
6030
  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";
6031
+ import { homedir as homedir9 } from "node:os";
6032
+ import { dirname as dirname9, join as join15 } from "node:path";
5974
6033
  import { createReadStream } from "node:fs";
5975
6034
  import { execFile, spawn as spawn7 } from "node:child_process";
5976
6035
  import { createInterface } from "node:readline";
@@ -6021,13 +6080,13 @@ async function startService(context) {
6021
6080
  async function stopService(context) {
6022
6081
  if (process.platform === "darwin") {
6023
6082
  const spec = buildLaunchdSpec(context);
6024
- if (!existsSync10(spec.plistPath)) return await readServiceStatus(context);
6083
+ if (!existsSync11(spec.plistPath)) return await readServiceStatus(context);
6025
6084
  await runLaunchctl(["bootout", `gui/${process.getuid?.() ?? 0}`, spec.plistPath]).catch(() => void 0);
6026
6085
  return await readServiceStatus(context);
6027
6086
  }
6028
6087
  if (process.platform === "linux") {
6029
6088
  const spec = buildSystemdUserSpec(context);
6030
- if (!existsSync10(spec.unitPath)) return await readServiceStatus(context);
6089
+ if (!existsSync11(spec.unitPath)) return await readServiceStatus(context);
6031
6090
  await runSystemctl(["--user", "stop", spec.unitName]).catch(() => void 0);
6032
6091
  return await readServiceStatus(context);
6033
6092
  }
@@ -6045,7 +6104,7 @@ async function stopService(context) {
6045
6104
  async function uninstallService(context) {
6046
6105
  if (process.platform === "darwin") {
6047
6106
  const spec = buildLaunchdSpec(context);
6048
- if (existsSync10(spec.plistPath)) {
6107
+ if (existsSync11(spec.plistPath)) {
6049
6108
  await runLaunchctl(["bootout", `gui/${process.getuid?.() ?? 0}`, spec.plistPath]).catch(() => void 0);
6050
6109
  await rm2(spec.plistPath, { force: true });
6051
6110
  }
@@ -6053,7 +6112,7 @@ async function uninstallService(context) {
6053
6112
  }
6054
6113
  if (process.platform === "linux") {
6055
6114
  const spec = buildSystemdUserSpec(context);
6056
- if (existsSync10(spec.unitPath)) {
6115
+ if (existsSync11(spec.unitPath)) {
6057
6116
  await runSystemctl(["--user", "disable", "--now", spec.unitName]).catch(() => void 0);
6058
6117
  await rm2(spec.unitPath, { force: true });
6059
6118
  await runSystemctl(["--user", "daemon-reload"]).catch(() => void 0);
@@ -6103,7 +6162,7 @@ async function tailServiceLogs(context) {
6103
6162
  async function readServiceStatus(context) {
6104
6163
  if (process.platform === "darwin") {
6105
6164
  const spec = buildLaunchdSpec(context);
6106
- const installed = existsSync10(spec.plistPath);
6165
+ const installed = existsSync11(spec.plistPath);
6107
6166
  const running = installed ? await runLaunchctl(["print", `gui/${process.getuid?.() ?? 0}/${spec.label}`]).then(() => true, () => false) : false;
6108
6167
  return {
6109
6168
  manager: "launchd",
@@ -6117,7 +6176,7 @@ async function readServiceStatus(context) {
6117
6176
  }
6118
6177
  if (process.platform === "linux") {
6119
6178
  const spec = buildSystemdUserSpec(context);
6120
- const installed = existsSync10(spec.unitPath);
6179
+ const installed = existsSync11(spec.unitPath);
6121
6180
  const running = installed ? await runSystemctl(["--user", "is-active", "--quiet", spec.unitName]).then(() => true, () => false) : false;
6122
6181
  return {
6123
6182
  manager: "systemd-user",
@@ -6147,44 +6206,44 @@ async function readServiceStatus(context) {
6147
6206
  throw new Error("service_status_not_supported_on_this_platform");
6148
6207
  }
6149
6208
  function buildLaunchdSpec(context) {
6150
- const stateDir = join14(homedir8(), ".claude-codex-wechat");
6209
+ const stateDir = join15(homedir9(), ".claude-codex-wechat");
6151
6210
  return {
6152
6211
  label: "com.claude-codex-wechat",
6153
- plistPath: join14(homedir8(), "Library", "LaunchAgents", "com.claude-codex-wechat.plist"),
6212
+ plistPath: join15(homedir9(), "Library", "LaunchAgents", "com.claude-codex-wechat.plist"),
6154
6213
  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"),
6214
+ workingDirectory: homedir9(),
6215
+ stdoutPath: join15(stateDir, "logs", "service.stdout.log"),
6216
+ stderrPath: join15(stateDir, "logs", "service.stderr.log"),
6158
6217
  environment: buildServiceEnvironment(context)
6159
6218
  };
6160
6219
  }
6161
6220
  function buildSystemdUserSpec(context) {
6162
- const stateDir = join14(homedir8(), ".claude-codex-wechat");
6221
+ const stateDir = join15(homedir9(), ".claude-codex-wechat");
6163
6222
  return {
6164
6223
  unitName: "claude-codex-wechat.service",
6165
- unitPath: join14(homedir8(), ".config", "systemd", "user", "claude-codex-wechat.service"),
6224
+ unitPath: join15(homedir9(), ".config", "systemd", "user", "claude-codex-wechat.service"),
6166
6225
  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"),
6226
+ workingDirectory: homedir9(),
6227
+ stdoutPath: join15(stateDir, "logs", "service.stdout.log"),
6228
+ stderrPath: join15(stateDir, "logs", "service.stderr.log"),
6170
6229
  environment: buildServiceEnvironment(context)
6171
6230
  };
6172
6231
  }
6173
6232
  function buildProcessSpec(context) {
6174
- const stateDir = join14(homedir8(), ".claude-codex-wechat");
6233
+ const stateDir = join15(homedir9(), ".claude-codex-wechat");
6175
6234
  return {
6176
- pidPath: join14(stateDir, "service.pid"),
6235
+ pidPath: join15(stateDir, "service.pid"),
6177
6236
  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"),
6237
+ workingDirectory: homedir9(),
6238
+ stdoutPath: join15(stateDir, "logs", "service.stdout.log"),
6239
+ stderrPath: join15(stateDir, "logs", "service.stderr.log"),
6181
6240
  environment: buildServiceEnvironment(context)
6182
6241
  };
6183
6242
  }
6184
6243
  function buildServiceEnvironment(context) {
6185
6244
  const env = {
6186
6245
  PATH: process.env.PATH ?? "",
6187
- HOME: process.env.HOME ?? homedir8()
6246
+ HOME: process.env.HOME ?? homedir9()
6188
6247
  };
6189
6248
  const configPath = context.configPath ?? process.env.BRIDGE_CONFIG;
6190
6249
  const port = context.port ?? Number(process.env.BRIDGE_PORT ?? 8787);
@@ -6302,7 +6361,7 @@ function isProcessAlive(pid) {
6302
6361
  }
6303
6362
  }
6304
6363
  async function readPidFile(pidPath) {
6305
- if (!existsSync10(pidPath)) return null;
6364
+ if (!existsSync11(pidPath)) return null;
6306
6365
  try {
6307
6366
  const raw = (await readFile6(pidPath, "utf8")).trim();
6308
6367
  const pid = Number.parseInt(raw, 10);
@@ -6353,12 +6412,12 @@ async function spawnDetachedDaemon(spec) {
6353
6412
  }
6354
6413
  }
6355
6414
  async function tailFile(path, lines) {
6356
- if (!existsSync10(path)) return "";
6415
+ if (!existsSync11(path)) return "";
6357
6416
  const content = await readFile6(path, "utf8");
6358
6417
  return content.split(/\r?\n/).slice(-lines).join("\n").trim();
6359
6418
  }
6360
6419
  async function tailFiles(paths) {
6361
- const existing = paths.filter((path) => existsSync10(path));
6420
+ const existing = paths.filter((path) => existsSync11(path));
6362
6421
  for (const path of existing) {
6363
6422
  const tail = await tailFile(path, 200);
6364
6423
  if (tail) process.stdout.write(`[${path}]
@@ -6370,8 +6429,8 @@ ${tail}
6370
6429
  child.stdout.on("data", (chunk) => {
6371
6430
  process.stdout.write(String(chunk));
6372
6431
  });
6373
- await new Promise((resolve2, reject) => {
6374
- child.on("exit", () => resolve2());
6432
+ await new Promise((resolve3, reject) => {
6433
+ child.on("exit", () => resolve3());
6375
6434
  child.on("error", reject);
6376
6435
  });
6377
6436
  return;
@@ -6450,10 +6509,41 @@ async function performUpgrade(deps) {
6450
6509
  return { outcome: "upgraded", from: currentVersion, to: latest };
6451
6510
  }
6452
6511
 
6512
+ // src/daemon/entrypoint.ts
6513
+ import { posix, win32 } from "node:path";
6514
+ var PACKAGE_NAME = "claude-codex-wechat";
6515
+ var PACKAGE_ENTRY = ["dist", "server", "cli.js"];
6516
+ function resolveDaemonEntrypoint(input) {
6517
+ if (input.override) return input.override;
6518
+ const path = input.platform === "win32" ? win32 : posix;
6519
+ if (isInsideNodeModules(input.currentPath, path)) return input.currentPath;
6520
+ for (const root of globalNodeModulesCandidates(input, path)) {
6521
+ const candidate = path.join(root, PACKAGE_NAME, ...PACKAGE_ENTRY);
6522
+ if (input.exists(candidate)) return candidate;
6523
+ }
6524
+ return input.currentPath;
6525
+ }
6526
+ function isInsideNodeModules(target, path) {
6527
+ return target.split(path.sep).includes("node_modules");
6528
+ }
6529
+ function globalNodeModulesCandidates(input, path) {
6530
+ const nodeDir = path.dirname(input.execPath);
6531
+ const candidates = [...input.globalNodeModules ?? []];
6532
+ if (input.platform === "win32") {
6533
+ candidates.push(path.join(nodeDir, "node_modules"));
6534
+ return candidates;
6535
+ }
6536
+ candidates.push(path.join(nodeDir, "..", "lib", "node_modules"));
6537
+ candidates.push("/opt/homebrew/lib/node_modules");
6538
+ candidates.push("/usr/local/lib/node_modules");
6539
+ candidates.push("/usr/lib/node_modules");
6540
+ return candidates;
6541
+ }
6542
+
6453
6543
  // src/cli.ts
6454
6544
  var execFileAsync2 = promisify2(execFile2);
6455
6545
  var here = dirname10(fileURLToPath4(import.meta.url));
6456
- var webRoot = join15(here, "..", "web");
6546
+ var webRoot = join16(here, "..", "web");
6457
6547
  async function main() {
6458
6548
  const command = process.argv[2];
6459
6549
  switch (command) {
@@ -6505,7 +6595,7 @@ async function main() {
6505
6595
  }
6506
6596
  }
6507
6597
  async function cmdStart() {
6508
- if (!existsSync11(webRoot)) {
6598
+ if (!existsSync12(webRoot)) {
6509
6599
  console.error(`\u627E\u4E0D\u5230\u524D\u7AEF\u6784\u5EFA\u4EA7\u7269: ${webRoot}`);
6510
6600
  console.error("\u8BF7\u91CD\u65B0\u5B89\u88C5\u5B8C\u6574\u7684 npm \u5305\u3002");
6511
6601
  process.exitCode = 1;
@@ -6590,7 +6680,7 @@ async function cmdTail() {
6590
6680
  await tailServiceLogs(createServiceContext());
6591
6681
  }
6592
6682
  async function cmdDaemon() {
6593
- if (!existsSync11(webRoot)) {
6683
+ if (!existsSync12(webRoot)) {
6594
6684
  console.error(`\u627E\u4E0D\u5230\u524D\u7AEF\u6784\u5EFA\u4EA7\u7269: ${webRoot}`);
6595
6685
  process.exitCode = 1;
6596
6686
  return;
@@ -6603,14 +6693,14 @@ async function cmdDaemon() {
6603
6693
  async function cmdDoctor() {
6604
6694
  const configPath = process.env.BRIDGE_CONFIG ?? defaultConfigPath();
6605
6695
  console.log("claude-codex-wechat doctor\n");
6606
- report("\u914D\u7F6E\u6587\u4EF6", existsSync11(configPath) ? configPath : `\u7F3A\u5931 (${configPath})\uFF0C\u9996\u6B21 start \u65F6\u81EA\u52A8\u521B\u5EFA`);
6607
- report("\u524D\u7AEF\u4EA7\u7269", existsSync11(webRoot) ? webRoot : `\u7F3A\u5931 (${webRoot})`);
6696
+ report("\u914D\u7F6E\u6587\u4EF6", existsSync12(configPath) ? configPath : `\u7F3A\u5931 (${configPath})\uFF0C\u9996\u6B21 start \u65F6\u81EA\u52A8\u521B\u5EFA`);
6697
+ report("\u524D\u7AEF\u4EA7\u7269", existsSync12(webRoot) ? webRoot : `\u7F3A\u5931 (${webRoot})`);
6608
6698
  const searchPath = resolveTerminalSearchPath();
6609
6699
  const claude = await findExecutable("claude", searchPath);
6610
6700
  report("claude \u53EF\u6267\u884C", claude ?? "\u672A\u627E\u5230\uFF0C\u9700\u5148\u5B89\u88C5\u5E76\u767B\u5F55 Claude Code");
6611
6701
  const codex = await findExecutable("codex", searchPath);
6612
6702
  report("codex \u53EF\u6267\u884C", codex ?? "\u672A\u627E\u5230\uFF08\u4EC5\u4F7F\u7528 Claude \u65F6\u53EF\u5FFD\u7565\uFF09");
6613
- if (existsSync11(configPath)) {
6703
+ if (existsSync12(configPath)) {
6614
6704
  const config = loadBridgeConfig(configPath);
6615
6705
  const wechat = config.wechat;
6616
6706
  report("\u5FAE\u4FE1\u542F\u7528", wechat?.enabled ? "\u662F" : "\u5426");
@@ -6621,7 +6711,7 @@ async function cmdDoctor() {
6621
6711
  }
6622
6712
  function printUpdateHint() {
6623
6713
  const configPath = process.env.BRIDGE_CONFIG ?? defaultConfigPath();
6624
- if (!existsSync11(configPath)) return;
6714
+ if (!existsSync12(configPath)) return;
6625
6715
  let update;
6626
6716
  try {
6627
6717
  update = loadBridgeConfig(configPath).update;
@@ -6639,7 +6729,7 @@ function printUpdateHint() {
6639
6729
  }
6640
6730
  function cmdPrintConfig() {
6641
6731
  const configPath = process.env.BRIDGE_CONFIG ?? defaultConfigPath();
6642
- if (!existsSync11(configPath)) {
6732
+ if (!existsSync12(configPath)) {
6643
6733
  console.error(`\u914D\u7F6E\u4E0D\u5B58\u5728: ${configPath}\uFF08\u9996\u6B21 start \u540E\u81EA\u52A8\u751F\u6210\uFF09`);
6644
6734
  process.exitCode = 1;
6645
6735
  return;
@@ -6652,7 +6742,14 @@ async function cmdUninstall() {
6652
6742
  }
6653
6743
  function createServiceContext() {
6654
6744
  return {
6655
- cliEntrypointPath: fileURLToPath4(import.meta.url),
6745
+ // 服务配置长期存活,必须指向已安装的 npm 包而非当前源码目录。
6746
+ cliEntrypointPath: resolveDaemonEntrypoint({
6747
+ currentPath: fileURLToPath4(import.meta.url),
6748
+ execPath: process.execPath,
6749
+ platform: process.platform,
6750
+ exists: existsSync12,
6751
+ override: process.env.BRIDGE_CLI_ENTRYPOINT
6752
+ }),
6656
6753
  nodePath: process.execPath,
6657
6754
  configPath: process.env.BRIDGE_CONFIG ?? defaultConfigPath(),
6658
6755
  port: Number(process.env.BRIDGE_PORT ?? 8787)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-codex-wechat",
3
- "version": "0.1.55",
3
+ "version": "0.1.57",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "packageManager": "pnpm@11.5.0",