claude-codex-wechat 0.1.56 → 0.1.58
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/mcp/mediaServer.js +79 -44
- package/dist/server/cli.js +362 -274
- package/package.json +1 -1
package/dist/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,57 +108,64 @@ 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/shared/platform.ts
|
|
146
|
+
var isWindows = process.platform === "win32";
|
|
147
|
+
function nodeExecutable() {
|
|
148
|
+
return process.execPath;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// src/mcp/tools/douyinDownload.ts
|
|
115
152
|
function findDouyinScript() {
|
|
116
153
|
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");
|
|
154
|
+
const found = locateDouyinScript({ baseDir: here });
|
|
155
|
+
if (!found) throw new Error("douyin-download \u811A\u672C\u672A\u627E\u5230");
|
|
156
|
+
return found;
|
|
123
157
|
}
|
|
124
158
|
function runScript(args) {
|
|
125
159
|
const script = findDouyinScript();
|
|
126
160
|
return new Promise((resolve2, reject) => {
|
|
127
|
-
execFile(
|
|
161
|
+
execFile(nodeExecutable(), [script, ...args], { timeout: 12e4 }, (err, stdout, stderr) => {
|
|
128
162
|
if (err) reject(new Error(stderr || err.message));
|
|
129
163
|
else resolve2({ stdout, stderr });
|
|
130
164
|
});
|
|
131
165
|
});
|
|
132
166
|
}
|
|
133
167
|
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";
|
|
168
|
+
return await sendMediaToWeChat({ kind, filePath, fileName: basename2(filePath) || "video.mp4" });
|
|
147
169
|
}
|
|
148
170
|
function registerDouyinTools(server2) {
|
|
149
171
|
server2.registerTool(
|
|
@@ -160,11 +182,11 @@ function registerDouyinTools(server2) {
|
|
|
160
182
|
try {
|
|
161
183
|
const args = [url];
|
|
162
184
|
if (outputDir) args.push("--output", outputDir);
|
|
163
|
-
else args.push("--output",
|
|
185
|
+
else args.push("--output", join2(homedir2(), "Downloads"));
|
|
164
186
|
const { stdout } = await runScript(args);
|
|
165
187
|
const pathMatch = stdout.match(/(?:已保存|保存到|saved to|文件路径)[::]\s*(.+?\.mp4)/i) || stdout.match(/(\/[^\s]+\.mp4)/);
|
|
166
188
|
const filePath = pathMatch?.[1]?.trim();
|
|
167
|
-
if (!filePath || !
|
|
189
|
+
if (!filePath || !existsSync2(filePath)) {
|
|
168
190
|
return { content: [{ type: "text", text: `\u4E0B\u8F7D\u5B8C\u6210\u4F46\u672A\u627E\u5230\u6587\u4EF6\u8DEF\u5F84\u3002\u811A\u672C\u8F93\u51FA:
|
|
169
191
|
${stdout}` }] };
|
|
170
192
|
}
|
|
@@ -186,6 +208,28 @@ ${stdout}` }] };
|
|
|
186
208
|
);
|
|
187
209
|
}
|
|
188
210
|
|
|
211
|
+
// src/media/behavior.ts
|
|
212
|
+
var BRIDGE_RULES = {
|
|
213
|
+
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',
|
|
214
|
+
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',
|
|
215
|
+
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",
|
|
216
|
+
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',
|
|
217
|
+
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',
|
|
218
|
+
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"
|
|
219
|
+
};
|
|
220
|
+
function renderMcpInstructions() {
|
|
221
|
+
return [
|
|
222
|
+
"\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",
|
|
223
|
+
BRIDGE_RULES.sendMeansWeChat,
|
|
224
|
+
"",
|
|
225
|
+
"\u5173\u952E\u884C\u4E3A\uFF1A",
|
|
226
|
+
`- ${BRIDGE_RULES.douyinNoAsking}\u7ACB\u5373\u8C03\u7528 download_douyin \u4E0B\u8F7D\u5E76\u53D1\u9001\u3002${BRIDGE_RULES.ignoreThumbnail}${BRIDGE_RULES.retryOnce}`,
|
|
227
|
+
'- \u7528\u6237\u8BF4"\u628AXX\u53D1\u7ED9\u6211"\u65F6\uFF0C\u6839\u636E\u6587\u4EF6\u7C7B\u578B\u8C03\u7528 send_image/send_video/send_file\u3002',
|
|
228
|
+
'- \u751F\u6210\u4E86\u6587\u4EF6\u540E\u7528\u6237\u8BF4"\u53D1\u7ED9\u6211"\uFF0C\u76F4\u63A5\u8C03\u7528\u5BF9\u5E94\u5DE5\u5177\u53D1\u9001\u3002',
|
|
229
|
+
`- ${BRIDGE_RULES.briefConfirm}`
|
|
230
|
+
].join("\n");
|
|
231
|
+
}
|
|
232
|
+
|
|
189
233
|
// src/mcp/mediaServer.ts
|
|
190
234
|
var server = new McpServer(
|
|
191
235
|
{
|
|
@@ -193,16 +237,7 @@ var server = new McpServer(
|
|
|
193
237
|
version: "1.0.0"
|
|
194
238
|
},
|
|
195
239
|
{
|
|
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")
|
|
240
|
+
instructions: renderMcpInstructions()
|
|
206
241
|
}
|
|
207
242
|
);
|
|
208
243
|
registerSendMediaTools(server);
|