claude-codex-wechat 0.1.56 → 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.
- package/dist/mcp/mediaServer.js +72 -43
- package/dist/server/cli.js +227 -168
- package/package.json +1 -1
package/dist/mcp/mediaServer.js
CHANGED
|
@@ -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
|
-
|
|
11
|
-
|
|
12
|
-
|
|
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({
|
|
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 {
|
|
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
|
-
|
|
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
|
-
//
|
|
123
|
+
// 源码布局:src/mcp/tools -> src/mcp/scripts
|
|
105
124
|
join(baseDir, "..", "scripts", "douyin-download.mjs"),
|
|
106
|
-
//
|
|
125
|
+
// 打包布局:dist/mcp/mediaServer.js -> dist/mcp/scripts
|
|
107
126
|
join(baseDir, "scripts", "douyin-download.mjs"),
|
|
108
|
-
//
|
|
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
|
-
//
|
|
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
|
|
118
|
-
|
|
119
|
-
|
|
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
|
-
|
|
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",
|
|
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 || !
|
|
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);
|
package/dist/server/cli.js
CHANGED
|
@@ -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
|
|
6
|
+
import { existsSync as existsSync12, readFileSync as readFileSync10 } from "node:fs";
|
|
7
7
|
import { promisify as promisify2 } from "node:util";
|
|
8
|
-
import { dirname as dirname10, join as
|
|
8
|
+
import { dirname as dirname10, join as join16 } from "node:path";
|
|
9
9
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
10
10
|
|
|
11
11
|
// src/daemon/bootstrap.ts
|
|
12
12
|
import { networkInterfaces } from "node:os";
|
|
13
13
|
|
|
14
14
|
// src/daemon/server.ts
|
|
15
|
-
import { mkdtempSync, existsSync as
|
|
16
|
-
import { tmpdir as
|
|
17
|
-
import { dirname as dirname8, join as
|
|
15
|
+
import { mkdtempSync, existsSync as existsSync10, writeFileSync as writeFileSync2 } from "node:fs";
|
|
16
|
+
import { tmpdir as tmpdir3 } from "node:os";
|
|
17
|
+
import { dirname as dirname8, isAbsolute, join as join13 } from "node:path";
|
|
18
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((
|
|
182
|
-
setTimeout(
|
|
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((
|
|
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((
|
|
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((
|
|
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", () =>
|
|
3151
|
-
child.on("close", () =>
|
|
3201
|
+
child.on("error", () => resolve3(false));
|
|
3202
|
+
child.on("close", () => resolve3(output.includes("--append-system-prompt")));
|
|
3152
3203
|
} catch {
|
|
3153
|
-
|
|
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((
|
|
3217
|
+
return new Promise((resolve3) => {
|
|
3167
3218
|
let settled = false;
|
|
3168
3219
|
const timer = setTimeout(() => {
|
|
3169
3220
|
if (!settled) {
|
|
3170
3221
|
settled = true;
|
|
3171
|
-
|
|
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
|
-
|
|
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
|
|
3406
|
-
if (
|
|
3456
|
+
const resolve3 = resolveNext;
|
|
3457
|
+
if (resolve3) {
|
|
3407
3458
|
resolveNext = null;
|
|
3408
|
-
|
|
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((
|
|
3445
|
-
resolveNext =
|
|
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((
|
|
3553
|
-
this.pending.set(key, { resolve:
|
|
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 {
|
|
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
|
-
|
|
3657
|
-
|
|
3658
|
-
|
|
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
|
-
|
|
3661
|
-
"",
|
|
3662
|
-
|
|
3663
|
-
"
|
|
3664
|
-
|
|
3665
|
-
"",
|
|
3666
|
-
|
|
3667
|
-
"
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
"
|
|
3671
|
-
|
|
3672
|
-
|
|
3673
|
-
|
|
3674
|
-
|
|
3675
|
-
|
|
3676
|
-
|
|
3677
|
-
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
|
|
3682
|
-
|
|
3683
|
-
|
|
3684
|
-
|
|
3685
|
-
|
|
3686
|
-
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
'- \u4F60\u751F\u6210\u4E86\u6587\u4EF6\uFF08\u56FE\u8868\u3001\u4EE3\u7801\u3001\u6587\u6863\u7B49\uFF09\u540E\uFF0C\u7528\u6237\u8BF4"\u53D1\u7ED9\u6211"\u5C31\u76F4\u63A5\u6309\u4E0A\u9762\u7684\u65B9\u5F0F\u53D1\u9001\u3002'
|
|
3691
|
-
].join("\n");
|
|
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
|
|
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((
|
|
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
|
-
|
|
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
|
-
|
|
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((
|
|
3839
|
-
session.turnCompletedResolver =
|
|
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((
|
|
4052
|
-
session.eventResolver =
|
|
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((
|
|
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
|
-
|
|
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)
|
|
4153
|
-
else
|
|
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((
|
|
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
|
-
|
|
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)
|
|
4189
|
-
else
|
|
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
|
|
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 (!
|
|
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((
|
|
4691
|
-
abortGeneration = () =>
|
|
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
|
|
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 (!
|
|
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
|
|
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 (!
|
|
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((
|
|
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
|
-
|
|
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
|
|
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(
|
|
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 ??
|
|
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 =
|
|
5607
|
+
const mcpConfigPath = join13(dirname8(configPath), "mcp-media.json");
|
|
5555
5608
|
const serverDir = dirname8(fileURLToPath3(import.meta.url));
|
|
5556
|
-
const mcpMediaServerTs =
|
|
5557
|
-
const mcpMediaServerJs =
|
|
5558
|
-
const useTs =
|
|
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 ?
|
|
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
|
|
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(
|
|
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
|
|
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
|
|
5973
|
-
import { dirname as dirname9, join as
|
|
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 (!
|
|
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 (!
|
|
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 (
|
|
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 (
|
|
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 =
|
|
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 =
|
|
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 =
|
|
6209
|
+
const stateDir = join15(homedir9(), ".claude-codex-wechat");
|
|
6151
6210
|
return {
|
|
6152
6211
|
label: "com.claude-codex-wechat",
|
|
6153
|
-
plistPath:
|
|
6212
|
+
plistPath: join15(homedir9(), "Library", "LaunchAgents", "com.claude-codex-wechat.plist"),
|
|
6154
6213
|
programArgs: [context.nodePath ?? process.execPath, context.cliEntrypointPath, "__daemon"],
|
|
6155
|
-
workingDirectory:
|
|
6156
|
-
stdoutPath:
|
|
6157
|
-
stderrPath:
|
|
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 =
|
|
6221
|
+
const stateDir = join15(homedir9(), ".claude-codex-wechat");
|
|
6163
6222
|
return {
|
|
6164
6223
|
unitName: "claude-codex-wechat.service",
|
|
6165
|
-
unitPath:
|
|
6224
|
+
unitPath: join15(homedir9(), ".config", "systemd", "user", "claude-codex-wechat.service"),
|
|
6166
6225
|
execStart: [context.nodePath ?? process.execPath, context.cliEntrypointPath, "__daemon"],
|
|
6167
|
-
workingDirectory:
|
|
6168
|
-
stdoutPath:
|
|
6169
|
-
stderrPath:
|
|
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 =
|
|
6233
|
+
const stateDir = join15(homedir9(), ".claude-codex-wechat");
|
|
6175
6234
|
return {
|
|
6176
|
-
pidPath:
|
|
6235
|
+
pidPath: join15(stateDir, "service.pid"),
|
|
6177
6236
|
command: [context.nodePath ?? process.execPath, context.cliEntrypointPath, "__daemon"],
|
|
6178
|
-
workingDirectory:
|
|
6179
|
-
stdoutPath:
|
|
6180
|
-
stderrPath:
|
|
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 ??
|
|
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 (!
|
|
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 (!
|
|
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) =>
|
|
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((
|
|
6374
|
-
child.on("exit", () =>
|
|
6432
|
+
await new Promise((resolve3, reject) => {
|
|
6433
|
+
child.on("exit", () => resolve3());
|
|
6375
6434
|
child.on("error", reject);
|
|
6376
6435
|
});
|
|
6377
6436
|
return;
|
|
@@ -6484,7 +6543,7 @@ function globalNodeModulesCandidates(input, path) {
|
|
|
6484
6543
|
// src/cli.ts
|
|
6485
6544
|
var execFileAsync2 = promisify2(execFile2);
|
|
6486
6545
|
var here = dirname10(fileURLToPath4(import.meta.url));
|
|
6487
|
-
var webRoot =
|
|
6546
|
+
var webRoot = join16(here, "..", "web");
|
|
6488
6547
|
async function main() {
|
|
6489
6548
|
const command = process.argv[2];
|
|
6490
6549
|
switch (command) {
|
|
@@ -6536,7 +6595,7 @@ async function main() {
|
|
|
6536
6595
|
}
|
|
6537
6596
|
}
|
|
6538
6597
|
async function cmdStart() {
|
|
6539
|
-
if (!
|
|
6598
|
+
if (!existsSync12(webRoot)) {
|
|
6540
6599
|
console.error(`\u627E\u4E0D\u5230\u524D\u7AEF\u6784\u5EFA\u4EA7\u7269: ${webRoot}`);
|
|
6541
6600
|
console.error("\u8BF7\u91CD\u65B0\u5B89\u88C5\u5B8C\u6574\u7684 npm \u5305\u3002");
|
|
6542
6601
|
process.exitCode = 1;
|
|
@@ -6621,7 +6680,7 @@ async function cmdTail() {
|
|
|
6621
6680
|
await tailServiceLogs(createServiceContext());
|
|
6622
6681
|
}
|
|
6623
6682
|
async function cmdDaemon() {
|
|
6624
|
-
if (!
|
|
6683
|
+
if (!existsSync12(webRoot)) {
|
|
6625
6684
|
console.error(`\u627E\u4E0D\u5230\u524D\u7AEF\u6784\u5EFA\u4EA7\u7269: ${webRoot}`);
|
|
6626
6685
|
process.exitCode = 1;
|
|
6627
6686
|
return;
|
|
@@ -6634,14 +6693,14 @@ async function cmdDaemon() {
|
|
|
6634
6693
|
async function cmdDoctor() {
|
|
6635
6694
|
const configPath = process.env.BRIDGE_CONFIG ?? defaultConfigPath();
|
|
6636
6695
|
console.log("claude-codex-wechat doctor\n");
|
|
6637
|
-
report("\u914D\u7F6E\u6587\u4EF6",
|
|
6638
|
-
report("\u524D\u7AEF\u4EA7\u7269",
|
|
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})`);
|
|
6639
6698
|
const searchPath = resolveTerminalSearchPath();
|
|
6640
6699
|
const claude = await findExecutable("claude", searchPath);
|
|
6641
6700
|
report("claude \u53EF\u6267\u884C", claude ?? "\u672A\u627E\u5230\uFF0C\u9700\u5148\u5B89\u88C5\u5E76\u767B\u5F55 Claude Code");
|
|
6642
6701
|
const codex = await findExecutable("codex", searchPath);
|
|
6643
6702
|
report("codex \u53EF\u6267\u884C", codex ?? "\u672A\u627E\u5230\uFF08\u4EC5\u4F7F\u7528 Claude \u65F6\u53EF\u5FFD\u7565\uFF09");
|
|
6644
|
-
if (
|
|
6703
|
+
if (existsSync12(configPath)) {
|
|
6645
6704
|
const config = loadBridgeConfig(configPath);
|
|
6646
6705
|
const wechat = config.wechat;
|
|
6647
6706
|
report("\u5FAE\u4FE1\u542F\u7528", wechat?.enabled ? "\u662F" : "\u5426");
|
|
@@ -6652,7 +6711,7 @@ async function cmdDoctor() {
|
|
|
6652
6711
|
}
|
|
6653
6712
|
function printUpdateHint() {
|
|
6654
6713
|
const configPath = process.env.BRIDGE_CONFIG ?? defaultConfigPath();
|
|
6655
|
-
if (!
|
|
6714
|
+
if (!existsSync12(configPath)) return;
|
|
6656
6715
|
let update;
|
|
6657
6716
|
try {
|
|
6658
6717
|
update = loadBridgeConfig(configPath).update;
|
|
@@ -6670,7 +6729,7 @@ function printUpdateHint() {
|
|
|
6670
6729
|
}
|
|
6671
6730
|
function cmdPrintConfig() {
|
|
6672
6731
|
const configPath = process.env.BRIDGE_CONFIG ?? defaultConfigPath();
|
|
6673
|
-
if (!
|
|
6732
|
+
if (!existsSync12(configPath)) {
|
|
6674
6733
|
console.error(`\u914D\u7F6E\u4E0D\u5B58\u5728: ${configPath}\uFF08\u9996\u6B21 start \u540E\u81EA\u52A8\u751F\u6210\uFF09`);
|
|
6675
6734
|
process.exitCode = 1;
|
|
6676
6735
|
return;
|
|
@@ -6688,7 +6747,7 @@ function createServiceContext() {
|
|
|
6688
6747
|
currentPath: fileURLToPath4(import.meta.url),
|
|
6689
6748
|
execPath: process.execPath,
|
|
6690
6749
|
platform: process.platform,
|
|
6691
|
-
exists:
|
|
6750
|
+
exists: existsSync12,
|
|
6692
6751
|
override: process.env.BRIDGE_CLI_ENTRYPOINT
|
|
6693
6752
|
}),
|
|
6694
6753
|
nodePath: process.execPath,
|