@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 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;
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@liangrk/claude-code-wechatbot",
3
- "version": "0.3.3",
3
+ "version": "0.3.4",
4
4
  "description": "Claude Code Channel plugin for WeChat — bridge WeChat messages into Claude Code sessions via the official ilink API",
5
5
  "type": "module",
6
6
  "bin": {