@liangrk/claude-code-wechatbot 0.3.3 → 0.3.4
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/cli.mjs +155 -1
- package/dist/wechat-channel.js +26 -1
- package/package.json +1 -1
package/cli.mjs
CHANGED
|
@@ -11,8 +11,9 @@
|
|
|
11
11
|
|
|
12
12
|
import { execSync, spawnSync } from "node:child_process";
|
|
13
13
|
import { existsSync, writeFileSync, readFileSync, renameSync } from "node:fs";
|
|
14
|
-
import { resolve, dirname } from "node:path";
|
|
14
|
+
import { resolve, dirname, join } from "node:path";
|
|
15
15
|
import { fileURLToPath } from "node:url";
|
|
16
|
+
import os from "node:os";
|
|
16
17
|
|
|
17
18
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
18
19
|
const DIST_DIR = resolve(__dirname, "dist");
|
|
@@ -46,6 +47,155 @@ function runScript(script, args = []) {
|
|
|
46
47
|
process.exit(result.status ?? 1);
|
|
47
48
|
}
|
|
48
49
|
|
|
50
|
+
function getCredentialsDir() {
|
|
51
|
+
return join(os.homedir(), ".claude", "channels", "wechat");
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function getCredentialsFile() {
|
|
55
|
+
return join(getCredentialsDir(), "account.json");
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async function status() {
|
|
59
|
+
const credFile = getCredentialsFile();
|
|
60
|
+
|
|
61
|
+
if (!existsSync(credFile)) {
|
|
62
|
+
console.log("Status: NOT CONFIGURED");
|
|
63
|
+
console.log("");
|
|
64
|
+
console.log("No account credentials found.");
|
|
65
|
+
console.log("Run: npx claude-code-wechat-channel setup");
|
|
66
|
+
process.exit(1);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
let account;
|
|
70
|
+
try {
|
|
71
|
+
account = JSON.parse(readFileSync(credFile, "utf-8"));
|
|
72
|
+
} catch {
|
|
73
|
+
console.log("Status: ERROR");
|
|
74
|
+
console.log("");
|
|
75
|
+
console.log("Failed to parse account.json. It may be corrupted.");
|
|
76
|
+
console.log(`File: ${credFile}`);
|
|
77
|
+
console.log("Fix: Remove the file and run setup again.");
|
|
78
|
+
process.exit(1);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
console.log("Account Information:");
|
|
82
|
+
console.log(` Bot ID: ${account.accountId ?? "N/A"}`);
|
|
83
|
+
console.log(` User ID: ${account.userId ?? "N/A"}`);
|
|
84
|
+
console.log(` Base URL: ${account.baseUrl ?? "N/A"}`);
|
|
85
|
+
console.log(` Token: ${account.token ? account.token.slice(0, 8) + "..." : "MISSING"}`);
|
|
86
|
+
|
|
87
|
+
if (account.savedAt) {
|
|
88
|
+
const ageMs = Date.now() - new Date(account.savedAt).getTime();
|
|
89
|
+
const ageHours = (ageMs / 3600_000).toFixed(1);
|
|
90
|
+
console.log(` Saved at: ${account.savedAt} (${ageHours}h ago)`);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (!account.token) {
|
|
94
|
+
console.log("");
|
|
95
|
+
console.log("Status: MISSING TOKEN");
|
|
96
|
+
console.log("The account.json is missing the bot_token.");
|
|
97
|
+
console.log("Fix: Run setup again: npx claude-code-wechat-channel setup");
|
|
98
|
+
process.exit(1);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Test API connectivity
|
|
102
|
+
console.log("");
|
|
103
|
+
console.log("Testing API connectivity...");
|
|
104
|
+
|
|
105
|
+
const body = JSON.stringify({
|
|
106
|
+
get_updates_buf: "",
|
|
107
|
+
base_info: { channel_version: "1.0.2" },
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
const base = (account.baseUrl || "https://ilinkai.weixin.qq.com").replace(/\/$/, "") + "/";
|
|
111
|
+
const url = base + "ilink/bot/getupdates";
|
|
112
|
+
|
|
113
|
+
const start = Date.now();
|
|
114
|
+
try {
|
|
115
|
+
const res = await fetch(url, {
|
|
116
|
+
method: "POST",
|
|
117
|
+
headers: {
|
|
118
|
+
"Content-Type": "application/json",
|
|
119
|
+
AuthorizationType: "ilink_bot_token",
|
|
120
|
+
Authorization: `Bearer ${account.token}`,
|
|
121
|
+
},
|
|
122
|
+
body,
|
|
123
|
+
signal: AbortSignal.timeout(15_000),
|
|
124
|
+
});
|
|
125
|
+
const latency = Date.now() - start;
|
|
126
|
+
const text = await res.text();
|
|
127
|
+
|
|
128
|
+
if (!res.ok) {
|
|
129
|
+
console.log(`Status: API ERROR (HTTP ${res.status}, ${latency}ms)`);
|
|
130
|
+
console.log(` Response: ${text.slice(0, 300)}`);
|
|
131
|
+
console.log("");
|
|
132
|
+
console.log("Possible causes:");
|
|
133
|
+
console.log(" - Bot token is invalid or expired");
|
|
134
|
+
console.log(" - Network/firewall blocking the request");
|
|
135
|
+
console.log("Fix: Run setup again: npx claude-code-wechat-channel setup");
|
|
136
|
+
process.exit(1);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
let resp;
|
|
140
|
+
try {
|
|
141
|
+
resp = JSON.parse(text);
|
|
142
|
+
} catch {
|
|
143
|
+
console.log(`Status: UNEXPECTED RESPONSE (${latency}ms)`);
|
|
144
|
+
console.log(` Response: ${text.slice(0, 300)}`);
|
|
145
|
+
process.exit(1);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const isErr =
|
|
149
|
+
(resp.ret !== undefined && resp.ret !== 0) ||
|
|
150
|
+
(resp.errcode !== undefined && resp.errcode !== 0);
|
|
151
|
+
|
|
152
|
+
if (isErr) {
|
|
153
|
+
if (resp.ret === -14 || resp.errcode === -14) {
|
|
154
|
+
console.log(`Status: SESSION EXPIRED (${latency}ms)`);
|
|
155
|
+
console.log(" The WeChat session has expired.");
|
|
156
|
+
console.log("");
|
|
157
|
+
console.log("Fix: Run setup to re-login: npx claude-code-wechat-channel setup");
|
|
158
|
+
process.exit(1);
|
|
159
|
+
}
|
|
160
|
+
console.log(`Status: API ERROR (${latency}ms)`);
|
|
161
|
+
console.log(` ret=${resp.ret} errcode=${resp.errcode} errmsg=${resp.errmsg ?? ""}`);
|
|
162
|
+
console.log("");
|
|
163
|
+
console.log("Possible causes:");
|
|
164
|
+
console.log(" - ClawBot is not activated in WeChat");
|
|
165
|
+
console.log(" - Bot token is invalid");
|
|
166
|
+
console.log("Fix: Run setup again: npx claude-code-wechat-channel setup");
|
|
167
|
+
process.exit(1);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
console.log(`Status: OK (${latency}ms)`);
|
|
171
|
+
console.log(" API is reachable and session is valid.");
|
|
172
|
+
console.log("");
|
|
173
|
+
console.log("The WeChat channel is ready to use.");
|
|
174
|
+
console.log("If messages aren't being received by Claude Code, check:");
|
|
175
|
+
console.log(" 1. Claude Code is running with MCP connected");
|
|
176
|
+
console.log(" 2. Messages are sent to the ClawBot in WeChat");
|
|
177
|
+
} catch (err) {
|
|
178
|
+
const elapsed = Date.now() - start;
|
|
179
|
+
if (err.name === "TimeoutError" || err.name === "AbortError") {
|
|
180
|
+
console.log(`Status: TIMEOUT (${elapsed}ms)`);
|
|
181
|
+
console.log(" The API request timed out.");
|
|
182
|
+
console.log("");
|
|
183
|
+
console.log("Possible causes:");
|
|
184
|
+
console.log(" - Network connectivity issues");
|
|
185
|
+
console.log(" - Firewall blocking access to ilinkai.weixin.qq.com");
|
|
186
|
+
} else {
|
|
187
|
+
console.log(`Status: NETWORK ERROR (${elapsed}ms)`);
|
|
188
|
+
console.log(` ${err.message}`);
|
|
189
|
+
console.log("");
|
|
190
|
+
console.log("Possible causes:");
|
|
191
|
+
console.log(" - No internet connection");
|
|
192
|
+
console.log(" - DNS resolution failure");
|
|
193
|
+
console.log(" - Firewall blocking the request");
|
|
194
|
+
}
|
|
195
|
+
process.exit(1);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
49
199
|
function install() {
|
|
50
200
|
const mcpConfig = {
|
|
51
201
|
mcpServers: {
|
|
@@ -97,6 +247,7 @@ function help() {
|
|
|
97
247
|
Commands:
|
|
98
248
|
setup WeChat QR login (scan to authenticate)
|
|
99
249
|
start Start the channel MCP server
|
|
250
|
+
status Check account and API connectivity
|
|
100
251
|
install Write .mcp.json to current directory
|
|
101
252
|
help Show this help message
|
|
102
253
|
`);
|
|
@@ -111,6 +262,9 @@ switch (command) {
|
|
|
111
262
|
case "start":
|
|
112
263
|
runScript("wechat-channel.js");
|
|
113
264
|
break;
|
|
265
|
+
case "status":
|
|
266
|
+
status();
|
|
267
|
+
break;
|
|
114
268
|
case "install":
|
|
115
269
|
install();
|
|
116
270
|
break;
|
package/dist/wechat-channel.js
CHANGED
|
@@ -21891,6 +21891,7 @@ import path from "node:path";
|
|
|
21891
21891
|
var DEFAULT_BASE_URL = "https://ilinkai.weixin.qq.com";
|
|
21892
21892
|
var BOT_TYPE = "3";
|
|
21893
21893
|
var LONG_POLL_TIMEOUT_MS = 35e3;
|
|
21894
|
+
var CHANNEL_VERSION = "1.0.2";
|
|
21894
21895
|
function getHomeDir() {
|
|
21895
21896
|
return os.homedir();
|
|
21896
21897
|
}
|
|
@@ -22009,7 +22010,6 @@ async function pollQRStatus(baseUrl, qrcode) {
|
|
|
22009
22010
|
|
|
22010
22011
|
// wechat-channel.ts
|
|
22011
22012
|
var CHANNEL_NAME = "wechat";
|
|
22012
|
-
var CHANNEL_VERSION = "0.1.0";
|
|
22013
22013
|
var MAX_CONSECUTIVE_FAILURES = 3;
|
|
22014
22014
|
var MAX_REPLY_LENGTH = 4096;
|
|
22015
22015
|
var MAX_SENDER_ID_LENGTH = 256;
|
|
@@ -22422,6 +22422,7 @@ async function startPolling(account) {
|
|
|
22422
22422
|
let getUpdatesBuf = "";
|
|
22423
22423
|
let consecutiveFailures = 0;
|
|
22424
22424
|
let longPollTimeout = LONG_POLL_TIMEOUT_MS;
|
|
22425
|
+
let emptyPollCount = 0;
|
|
22425
22426
|
const syncBufFile = getSyncBufFile();
|
|
22426
22427
|
try {
|
|
22427
22428
|
if (fs2.existsSync(syncBufFile)) {
|
|
@@ -22432,12 +22433,27 @@ async function startPolling(account) {
|
|
|
22432
22433
|
log(`\u52A0\u8F7D\u540C\u6B65\u72B6\u6001\u5931\u8D25: ${String(err)}`);
|
|
22433
22434
|
}
|
|
22434
22435
|
loadContextTokens();
|
|
22436
|
+
if (account.savedAt) {
|
|
22437
|
+
try {
|
|
22438
|
+
const ageMs = Date.now() - new Date(account.savedAt).getTime();
|
|
22439
|
+
const ageHours = Math.round(ageMs / 36e5);
|
|
22440
|
+
log(`\u51ED\u636E\u4FDD\u5B58\u4E8E ${account.savedAt}\uFF0C\u8DDD\u4ECA ${ageHours} \u5C0F\u65F6`);
|
|
22441
|
+
} catch {
|
|
22442
|
+
}
|
|
22443
|
+
}
|
|
22444
|
+
log(`channel_version: ${CHANNEL_VERSION}`);
|
|
22435
22445
|
log("\u5F00\u59CB\u76D1\u542C\u5FAE\u4FE1\u6D88\u606F...");
|
|
22436
22446
|
while (true) {
|
|
22437
22447
|
try {
|
|
22438
22448
|
const resp = await getUpdates(baseUrl, token, getUpdatesBuf, longPollTimeout);
|
|
22439
22449
|
const isError = resp.ret !== void 0 && resp.ret !== 0 || resp.errcode !== void 0 && resp.errcode !== 0;
|
|
22440
22450
|
if (isError) {
|
|
22451
|
+
if (resp.ret === -14 || resp.errcode === -14) {
|
|
22452
|
+
logError("\u4F1A\u8BDD\u5DF2\u8FC7\u671F (errcode -14)\uFF0C\u8BF7\u91CD\u65B0\u8FD0\u884C setup \u767B\u5F55");
|
|
22453
|
+
logError("1 \u5C0F\u65F6\u540E\u91CD\u8BD5...");
|
|
22454
|
+
await new Promise((r) => setTimeout(r, 36e5));
|
|
22455
|
+
continue;
|
|
22456
|
+
}
|
|
22441
22457
|
consecutiveFailures++;
|
|
22442
22458
|
logError(
|
|
22443
22459
|
`getUpdates \u5931\u8D25: ret=${resp.ret} errcode=${resp.errcode} errmsg=${resp.errmsg ?? ""}`
|
|
@@ -22454,7 +22470,16 @@ async function startPolling(account) {
|
|
|
22454
22470
|
if (resp.longpolling_timeout_ms && resp.longpolling_timeout_ms >= LONG_POLL_TIMEOUT_MIN_MS && resp.longpolling_timeout_ms <= LONG_POLL_TIMEOUT_MAX_MS) {
|
|
22455
22471
|
longPollTimeout = resp.longpolling_timeout_ms;
|
|
22456
22472
|
}
|
|
22473
|
+
const msgCount = resp.msgs?.length ?? 0;
|
|
22457
22474
|
await processMessages(resp.msgs);
|
|
22475
|
+
if (msgCount === 0) {
|
|
22476
|
+
emptyPollCount++;
|
|
22477
|
+
if (emptyPollCount % 10 === 0) {
|
|
22478
|
+
log(`\u5FC3\u8DF3: \u957F\u8F6E\u8BE2\u6B63\u5E38 (\u5DF2\u7A7A\u8F6E\u8BE2 ${emptyPollCount} \u6B21)`);
|
|
22479
|
+
}
|
|
22480
|
+
} else {
|
|
22481
|
+
emptyPollCount = 0;
|
|
22482
|
+
}
|
|
22458
22483
|
if (resp.get_updates_buf) {
|
|
22459
22484
|
getUpdatesBuf = resp.get_updates_buf;
|
|
22460
22485
|
try {
|
package/package.json
CHANGED