@unlinearity/cli-wechat-bridge 1.0.2 → 1.0.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.
@@ -13,6 +13,9 @@ export function parseCliArgs(argv) {
13
13
  const cliArgs = [];
14
14
  for (let i = 0; i < argv.length; i += 1) {
15
15
  const arg = argv[i];
16
+ if (!arg) {
17
+ continue;
18
+ }
16
19
  const next = argv[i + 1];
17
20
  if (arg === "--help" || arg === "-h") {
18
21
  process.stdout.write([
@@ -87,6 +87,9 @@ export function parseCliArgs(argv) {
87
87
  const cliArgs = [];
88
88
  for (let i = 0; i < argv.length; i += 1) {
89
89
  const arg = argv[i];
90
+ if (!arg) {
91
+ continue;
92
+ }
90
93
  const next = argv[i + 1];
91
94
  if (arg === "--help" || arg === "-h") {
92
95
  process.stdout.write([
@@ -173,7 +176,9 @@ async function stopExistingBridge(lock, requestedAdapter) {
173
176
  catch (error) {
174
177
  if (isPidAlive(pid)) {
175
178
  const message = error instanceof Error ? error.message : String(error);
176
- throw new Error(`Failed to stop existing bridge pid=${pid}: ${message}`);
179
+ throw new Error(`Failed to stop existing bridge pid=${pid}: ${message}`, {
180
+ cause: error,
181
+ });
177
182
  }
178
183
  }
179
184
  if (!(await waitForProcessExit(pid, 10_000))) {
@@ -16,6 +16,9 @@ function parseCliArgs(argv) {
16
16
  const cliArgs = [];
17
17
  for (let i = 0; i < argv.length; i += 1) {
18
18
  const arg = argv[i];
19
+ if (!arg) {
20
+ continue;
21
+ }
19
22
  const next = argv[i + 1];
20
23
  if (arg === "--help" || arg === "-h") {
21
24
  process.stdout.write([
@@ -199,6 +202,14 @@ export async function runLocalCompanion(options) {
199
202
  publishState();
200
203
  sendResponse(socket, message.id, true);
201
204
  break;
205
+ case "create_session":
206
+ if (!adapter.createSession) {
207
+ throw new Error(`/${adapter.getState().kind} does not support creating sessions from WeChat.`);
208
+ }
209
+ await adapter.createSession();
210
+ publishState();
211
+ sendResponse(socket, message.id, true);
212
+ break;
202
213
  case "interrupt":
203
214
  sendResponse(socket, message.id, true, await adapter.interrupt());
204
215
  break;
@@ -19,6 +19,12 @@ export class LegacyAdapterRuntime {
19
19
  async resumeSession(sessionId) {
20
20
  await this.adapter.resumeSession(sessionId);
21
21
  }
22
+ async createSession() {
23
+ if (!this.adapter.createSession) {
24
+ throw new Error(`/${this.adapter.getState().kind} does not support creating sessions from WeChat.`);
25
+ }
26
+ await this.adapter.createSession();
27
+ }
22
28
  async interrupt() {
23
29
  return await this.adapter.interrupt();
24
30
  }
@@ -37,7 +37,7 @@ export async function fetchLatestVersion() {
37
37
  }
38
38
  // 按版本号排序,返回最新的
39
39
  versionTags.sort((a, b) => compareVersions(b, a));
40
- return versionTags[0];
40
+ return versionTags[0] ?? null;
41
41
  }
42
42
  catch (error) {
43
43
  // 如果 git 命令失败,静默返回 null
@@ -88,6 +88,49 @@ function readJsonFile(filePath) {
88
88
  function isRecord(value) {
89
89
  return typeof value === "object" && value !== null;
90
90
  }
91
+ function readNumericResponseField(response, key) {
92
+ const value = response[key];
93
+ if (typeof value === "number" && Number.isFinite(value)) {
94
+ return value;
95
+ }
96
+ if (typeof value === "string" && value.trim()) {
97
+ const parsed = Number(value);
98
+ return Number.isFinite(parsed) ? parsed : undefined;
99
+ }
100
+ return undefined;
101
+ }
102
+ function readStringResponseField(response, key) {
103
+ const value = response[key];
104
+ return typeof value === "string" && value.trim() ? value.trim() : undefined;
105
+ }
106
+ export function assertWechatApiResponseOk(endpoint, raw) {
107
+ const trimmed = raw.trim();
108
+ if (!trimmed) {
109
+ return;
110
+ }
111
+ let response;
112
+ try {
113
+ response = JSON.parse(trimmed);
114
+ }
115
+ catch {
116
+ return;
117
+ }
118
+ if (!isRecord(response)) {
119
+ return;
120
+ }
121
+ const ret = readNumericResponseField(response, "ret");
122
+ const errcode = readNumericResponseField(response, "errcode");
123
+ const failed = (ret !== undefined && ret !== 0) ||
124
+ (errcode !== undefined && errcode !== 0);
125
+ if (!failed) {
126
+ return;
127
+ }
128
+ const errmsg = readStringResponseField(response, "errmsg") ??
129
+ readStringResponseField(response, "message") ??
130
+ readStringResponseField(response, "msg") ??
131
+ "";
132
+ throw new Error(`${endpoint} failed: ret=${ret} errcode=${errcode} errmsg=${errmsg}`);
133
+ }
91
134
  function describeErrorNode(value) {
92
135
  if (value instanceof Error) {
93
136
  const error = value;
@@ -587,7 +630,7 @@ export class WeChatTransport {
587
630
  if (rawMessage.context_token) {
588
631
  this.cacheContextToken(senderId, rawMessage.context_token);
589
632
  }
590
- const createdAtMs = rawMessage.create_time_ms;
633
+ const createdAtMs = rawMessage.create_time_ms ?? 0;
591
634
  if (typeof options.minCreatedAtMs === "number" &&
592
635
  (!Number.isFinite(createdAtMs) || createdAtMs < options.minCreatedAtMs)) {
593
636
  ignoredBacklogCount += 1;
@@ -736,7 +779,7 @@ export class WeChatTransport {
736
779
  ]);
737
780
  }
738
781
  async sendMessage(account, recipientId, contextToken, itemList) {
739
- await apiFetch({
782
+ const raw = await apiFetch({
740
783
  baseUrl: account.baseUrl,
741
784
  endpoint: "ilink/bot/sendmessage",
742
785
  body: JSON.stringify({
@@ -754,6 +797,7 @@ export class WeChatTransport {
754
797
  token: account.token,
755
798
  timeoutMs: SEND_TIMEOUT_MS,
756
799
  });
800
+ assertWechatApiResponseOk("sendmessage", raw);
757
801
  }
758
802
  async prepareUpload(account, recipientId, filePath, mediaType, label) {
759
803
  const stat = this.requireExistingFile(filePath);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unlinearity/cli-wechat-bridge",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "CLI WeChat Bridge for Codex, Claude Code, OpenCode, and PowerShell over WeChat",
5
5
  "type": "module",
6
6
  "files": [
@@ -50,6 +50,11 @@
50
50
  "clean": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\"",
51
51
  "build": "npm run clean && tsc -p tsconfig.build.json",
52
52
  "prepack": "npm run build",
53
+ "lint": "eslint bin src test",
54
+ "lint:fix": "eslint bin src test --fix",
55
+ "typecheck:src": "tsc -p tsconfig.typecheck.src.json --noEmit --pretty false",
56
+ "quality": "npm run lint && npm run typecheck:src && bun test test && npm run build",
57
+ "smoke:global": "node scripts/smoke-global-install.mjs",
53
58
  "setup": "node --no-warnings --experimental-strip-types src/wechat/setup.ts",
54
59
  "start": "node --no-warnings --experimental-strip-types src/wechat/wechat-channel.ts",
55
60
  "check": "node --no-warnings --experimental-strip-types src/wechat/wechat-channel.ts --check",
@@ -80,8 +85,11 @@
80
85
  "qrcode-terminal": "^0.12.0"
81
86
  },
82
87
  "devDependencies": {
88
+ "@eslint/js": "^10.0.1",
83
89
  "@types/bun": "latest",
84
- "typescript": "^6.0.2"
90
+ "eslint": "^10.3.0",
91
+ "typescript": "^6.0.2",
92
+ "typescript-eslint": "^8.59.3"
85
93
  },
86
94
  "engines": {
87
95
  "bun": ">=1.0.0",