wechat-to-anything 0.6.7 → 0.6.9

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.
@@ -5,7 +5,9 @@
5
5
  "Bash(find /Users/zxw/AITOOL/wechat-to-anything/examples -name *.mjs ! -path */node_modules/* -exec head -40 {})",
6
6
  "Bash(2)",
7
7
  "Bash(ls -la /Users/zxw/AITOOL/wechat-to-anything/examples/*/package.json)",
8
- "mcp__filesystem__read_text_file"
8
+ "mcp__filesystem__read_text_file",
9
+ "Bash(gh issue:*)",
10
+ "Bash(gh api:*)"
9
11
  ]
10
12
  }
11
13
  }
@@ -8,11 +8,12 @@
8
8
  * - cli://gemini → 内置 Gemini CLI 适配器
9
9
  */
10
10
 
11
- import { execFile, spawn } from "node:child_process";
11
+ import { execFile } from "node:child_process";
12
12
  import { writeFile, readFile, unlink, mkdir } from "node:fs/promises";
13
13
  import { join } from "node:path";
14
14
  import { tmpdir } from "node:os";
15
15
  import { randomBytes } from "node:crypto";
16
+ import crossSpawn from "cross-spawn";
16
17
 
17
18
  /**
18
19
  * 统一调用接口 — 根据 URL 自动选择适配器
@@ -37,8 +38,12 @@ export async function checkAgent(url) {
37
38
  const name = url.replace("cli://", "");
38
39
  const cmd = { codex: "codex", gemini: "gemini", claude: "claude", openclaw: "openclaw" }[name] || name;
39
40
  return new Promise((resolve, reject) => {
40
- execFile(cmd, ["--version"], { timeout: 5000 }, (err) => {
41
- if (err) reject(new Error(`${cmd} CLI 未安装(npm install -g ${{
41
+ const child = crossSpawn(cmd, ["--version"], { timeout: 5000 });
42
+ child.on("error", (err) => reject(new Error(`${cmd} CLI 未安装(npm install -g ${{
43
+ codex: "@openai/codex", gemini: "@google/gemini-cli", claude: "@anthropic-ai/claude-code", openclaw: "openclaw"
44
+ }[name] || cmd})`)));
45
+ child.on("close", (code) => {
46
+ if (code !== 0) reject(new Error(`${cmd} CLI 未安装(npm install -g ${{
42
47
  codex: "@openai/codex", gemini: "@google/gemini-cli", claude: "@anthropic-ai/claude-code", openclaw: "openclaw"
43
48
  }[name] || cmd})`));
44
49
  else resolve();
@@ -161,23 +166,26 @@ function runCodex(prompt, imagePaths = []) {
161
166
  for (const img of imagePaths) args.push("-i", img);
162
167
  args.push("--", prompt);
163
168
 
164
- execFile("codex", args, { timeout: 300_000, maxBuffer: 2 * 1024 * 1024, cwd: tmpdir() },
165
- async (err, stdout, stderr) => {
169
+ const child = crossSpawn("codex", args, { timeout: 300_000, cwd: tmpdir() });
170
+ let stdout = "", stderr = "";
171
+ child.stdout.on("data", (d) => (stdout += d));
172
+ child.stderr.on("data", (d) => (stderr += d));
173
+ child.on("close", async () => {
166
174
  try {
167
175
  const reply = await readFile(outFile, "utf-8").catch(() => "");
168
176
  await unlink(outFile).catch(() => {});
169
177
  if (reply.trim()) resolve(reply.trim());
170
178
  else if (stdout.trim()) resolve(stdout.trim());
171
- else if (err) reject(new Error((stderr || err.message).trim().slice(0, 300)));
172
- else resolve("(empty response)");
179
+ else reject(new Error((stderr || "empty response").trim().slice(0, 300)));
173
180
  } catch (e) { reject(e); }
174
181
  });
182
+ child.on("error", (err) => reject(err));
175
183
  });
176
184
  }
177
185
 
178
186
  function runGemini(prompt) {
179
187
  return new Promise((resolve, reject) => {
180
- const child = spawn("gemini", [], { cwd: tmpdir(), stdio: ["pipe", "pipe", "pipe"], timeout: 300_000 });
188
+ const child = crossSpawn("gemini", [], { cwd: tmpdir(), stdio: ["pipe", "pipe", "pipe"], timeout: 300_000 });
181
189
  let stdout = "", stderr = "";
182
190
  child.stdout.on("data", (d) => (stdout += d));
183
191
  child.stderr.on("data", (d) => (stderr += d));
@@ -194,7 +202,7 @@ function runGemini(prompt) {
194
202
 
195
203
  function runClaude(prompt) {
196
204
  return new Promise((resolve, reject) => {
197
- const child = spawn("claude", ["--print", prompt], {
205
+ const child = crossSpawn("claude", ["--print", prompt], {
198
206
  stdio: ["ignore", "pipe", "pipe"],
199
207
  timeout: 300_000,
200
208
  });
package/cli/bridge.mjs CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  loadCredentials, loginWithQR, getUpdates,
5
5
  sendMessage, sendImageByUrl, sendVideoByUrl,
6
6
  extractText, extractMedia,
7
- getConfig, sendTyping,
7
+ getConfig, sendTyping, buildHeaders, BASE_URL,
8
8
  } from "./weixin.mjs";
9
9
  import { downloadAndDecrypt, downloadMediaToFile, uploadToCdn } from "./cdn.mjs";
10
10
  import { callAgentAuto, checkAgent } from "./agent-adapter.mjs";
@@ -130,8 +130,6 @@ export async function start(agents, defaultAgent, { port = 9099 } = {}) {
130
130
  try {
131
131
  const { execFileSync } = await import("node:child_process");
132
132
  const { statSync, writeFileSync } = await import("node:fs");
133
- const { uploadToCdn } = await import("./cdn.mjs");
134
- const { buildHeaders, BASE_URL: baseUrl } = await import("./weixin.mjs");
135
133
 
136
134
  let audioFile = audioSrc;
137
135
  if (audioSrc.startsWith("http://") || audioSrc.startsWith("https://")) {
@@ -166,7 +164,7 @@ export async function start(agents, defaultAgent, { port = 9099 } = {}) {
166
164
  },
167
165
  base_info: {},
168
166
  });
169
- await fetch(`${baseUrl}/ilink/bot/sendmessage`, {
167
+ await fetch(`${BASE_URL}/ilink/bot/sendmessage`, {
170
168
  method: "POST", headers: buildHeaders(creds.token, body), body,
171
169
  });
172
170
  console.log(pc.green(`→ [语音] 已发送 (${durationMs}ms)`));
@@ -246,6 +244,7 @@ export async function start(agents, defaultAgent, { port = 9099 } = {}) {
246
244
  if (bodySize > 1_048_576) { // 1MB limit
247
245
  res.writeHead(413, { "Content-Type": "application/json" });
248
246
  res.end(JSON.stringify({ error: "body too large (max 1MB)" }));
247
+ req.destroy();
249
248
  return;
250
249
  }
251
250
  body += chunk;
package/cli/cdn.mjs CHANGED
@@ -80,7 +80,7 @@ export async function downloadMediaToFile(encryptQueryParam, aesKeyBase64, ext =
80
80
  */
81
81
  export async function uploadImageWithThumb(filePath, toUserId, token) {
82
82
  const { buildHeaders, BASE_URL } = await import("./weixin.mjs");
83
- const { execFileSync } = await import("child_process");
83
+ const { execFileSync } = await import("node:child_process");
84
84
 
85
85
  const plaintext = await readFile(filePath);
86
86
  const rawsize = plaintext.length;
@@ -183,7 +183,7 @@ export async function uploadImageWithThumb(filePath, toUserId, token) {
183
183
  */
184
184
  export async function uploadVideoWithThumb(filePath, toUserId, token) {
185
185
  const { buildHeaders, BASE_URL } = await import("./weixin.mjs");
186
- const { execFileSync } = await import("child_process");
186
+ const { execFileSync } = await import("node:child_process");
187
187
 
188
188
  const plaintext = await readFile(filePath);
189
189
  const rawsize = plaintext.length;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wechat-to-anything",
3
- "version": "0.6.7",
3
+ "version": "0.6.9",
4
4
  "description": "一条命令,把微信变成任何 AI Agent 的入口",
5
5
  "type": "module",
6
6
  "bin": {
@@ -33,6 +33,7 @@
33
33
  "node": ">=22"
34
34
  },
35
35
  "dependencies": {
36
+ "cross-spawn": "^7.0.6",
36
37
  "picocolors": "^1.1.0",
37
38
  "qrcode-terminal": "^0.12.0"
38
39
  }