cli-wechat-bridge 1.1.7 → 1.1.8
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/LICENSE.txt +661 -661
- package/README.md +448 -434
- package/bin/_run-entry.mjs +23 -5
- package/dist/bridge/adapter-control.js +58 -0
- package/dist/bridge/bridge-adapters.claude.js +29 -1
- package/dist/bridge/bridge-adapters.codex.js +112 -7
- package/dist/bridge/bridge-adapters.core.js +19 -1
- package/dist/bridge/bridge-adapters.opencode.js +150 -1
- package/dist/bridge/bridge-adapters.pi.js +39 -0
- package/dist/bridge/claude-native-controls.js +133 -0
- package/dist/bridge/native-terminal-control.js +253 -0
- package/dist/bridge/wechat-bridge.js +182 -113
- package/dist/companion/codex-remote-client.js +22 -2
- package/dist/companion/codex-visible-client-link.js +101 -0
- package/dist/companion/local-companion-start.js +7 -2
- package/dist/companion/local-companion.js +17 -0
- package/dist/companion/pi-tui-bridge-extension.js +56 -3
- package/dist/core/bridge-control.js +8 -0
- package/dist/core/conversation-routing.js +48 -0
- package/dist/daemon/wechat-daemon.js +120 -74
- package/dist/i18n/messages-en.js +1 -1
- package/dist/i18n/messages-zh.js +1 -1
- package/dist/runtime/legacy-adapter-runtime.js +15 -0
- package/dist/runtime/runtime-types.js +3 -0
- package/dist/utils/version-checker.js +11 -11
- package/dist/wechat/wechat-transport.js +96 -58
- package/package.json +108 -106
- package/scripts/ensure-node-pty-permissions.mjs +73 -73
|
@@ -332,6 +332,15 @@ async function apiFetch(params) {
|
|
|
332
332
|
const url = new URL(params.endpoint, base).toString();
|
|
333
333
|
const controller = new AbortController();
|
|
334
334
|
const timer = setTimeout(() => controller.abort(), params.timeoutMs);
|
|
335
|
+
const abortFromCaller = () => controller.abort(params.signal?.reason);
|
|
336
|
+
if (params.signal) {
|
|
337
|
+
if (params.signal.aborted) {
|
|
338
|
+
abortFromCaller();
|
|
339
|
+
}
|
|
340
|
+
else {
|
|
341
|
+
params.signal.addEventListener("abort", abortFromCaller, { once: true });
|
|
342
|
+
}
|
|
343
|
+
}
|
|
335
344
|
try {
|
|
336
345
|
const res = await fetch(url, {
|
|
337
346
|
method: "POST",
|
|
@@ -353,6 +362,9 @@ async function apiFetch(params) {
|
|
|
353
362
|
clearTimeout(timer);
|
|
354
363
|
throw err;
|
|
355
364
|
}
|
|
365
|
+
finally {
|
|
366
|
+
params.signal?.removeEventListener("abort", abortFromCaller);
|
|
367
|
+
}
|
|
356
368
|
}
|
|
357
369
|
function encryptAesEcb(plaintext, key) {
|
|
358
370
|
const cipher = createCipheriv("aes-128-ecb", key, null);
|
|
@@ -812,6 +824,8 @@ export class WeChatTransport {
|
|
|
812
824
|
recentMessageOrder = [];
|
|
813
825
|
contextTokenCache;
|
|
814
826
|
syncBuffer = "";
|
|
827
|
+
stopped = false;
|
|
828
|
+
activePollControllers = new Set();
|
|
815
829
|
constructor(logger) {
|
|
816
830
|
this.logger = logger;
|
|
817
831
|
migrateLegacyChannelFiles((message) => this.logger.log(message));
|
|
@@ -855,73 +869,96 @@ export class WeChatTransport {
|
|
|
855
869
|
? "Reset sync state and cleared cached context tokens."
|
|
856
870
|
: "Reset sync state.";
|
|
857
871
|
}
|
|
872
|
+
stop() {
|
|
873
|
+
if (this.stopped) {
|
|
874
|
+
return;
|
|
875
|
+
}
|
|
876
|
+
this.stopped = true;
|
|
877
|
+
for (const controller of this.activePollControllers) {
|
|
878
|
+
controller.abort();
|
|
879
|
+
}
|
|
880
|
+
this.activePollControllers.clear();
|
|
881
|
+
}
|
|
858
882
|
async pollMessages(options = {}) {
|
|
883
|
+
if (this.stopped) {
|
|
884
|
+
return { messages: [], ignoredBacklogCount: 0 };
|
|
885
|
+
}
|
|
859
886
|
const timeoutMs = options.timeoutMs ?? DEFAULT_LONG_POLL_TIMEOUT_MS;
|
|
860
887
|
const account = this.requireAccount();
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
this.
|
|
865
|
-
response
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
}
|
|
870
|
-
const isError = (response.ret !== undefined && response.ret !== 0) ||
|
|
871
|
-
(response.errcode !== undefined && response.errcode !== 0);
|
|
872
|
-
if (isError) {
|
|
873
|
-
throw new Error(`getUpdates failed: ret=${response.ret} errcode=${response.errcode} errmsg=${response.errmsg ?? ""}`);
|
|
874
|
-
}
|
|
875
|
-
if (response.get_updates_buf) {
|
|
876
|
-
this.syncBuffer = response.get_updates_buf;
|
|
877
|
-
this.saveSyncBuffer(this.syncBuffer);
|
|
878
|
-
}
|
|
879
|
-
const messages = [];
|
|
880
|
-
let ignoredBacklogCount = 0;
|
|
881
|
-
for (const rawMessage of response.msgs ?? []) {
|
|
882
|
-
if (rawMessage.message_type !== MSG_TYPE_USER) {
|
|
883
|
-
continue;
|
|
888
|
+
const controller = new AbortController();
|
|
889
|
+
this.activePollControllers.add(controller);
|
|
890
|
+
try {
|
|
891
|
+
let response = await this.getUpdates(account, timeoutMs, controller.signal);
|
|
892
|
+
if (isWechatSyncSessionTimeout(response) && this.syncBuffer && !this.stopped) {
|
|
893
|
+
this.logger.log("WeChat sync session timed out. Clearing local sync cursor and retrying once.");
|
|
894
|
+
this.clearSyncBuffer();
|
|
895
|
+
response = await this.getUpdates(account, timeoutMs, controller.signal);
|
|
884
896
|
}
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
continue;
|
|
897
|
+
if (this.stopped) {
|
|
898
|
+
return { messages: [], ignoredBacklogCount: 0 };
|
|
888
899
|
}
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
this.cacheContextToken(senderId, rawMessage.context_token);
|
|
900
|
+
if (isWechatSyncSessionTimeout(response)) {
|
|
901
|
+
throw new Error('WeChat session timed out. Run "wechat-setup" to log in again.');
|
|
892
902
|
}
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
if (typeof options.minCreatedAtMs === "number" &&
|
|
898
|
-
Number.isFinite(createdAtMs) &&
|
|
899
|
-
createdAtMs > 0 &&
|
|
900
|
-
createdAtMs < options.minCreatedAtMs) {
|
|
901
|
-
ignoredBacklogCount += 1;
|
|
902
|
-
continue;
|
|
903
|
+
const isError = (response.ret !== undefined && response.ret !== 0) ||
|
|
904
|
+
(response.errcode !== undefined && response.errcode !== 0);
|
|
905
|
+
if (isError) {
|
|
906
|
+
throw new Error(`getUpdates failed: ret=${response.ret} errcode=${response.errcode} errmsg=${response.errmsg ?? ""}`);
|
|
903
907
|
}
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
908
|
+
if (response.get_updates_buf) {
|
|
909
|
+
this.syncBuffer = response.get_updates_buf;
|
|
910
|
+
this.saveSyncBuffer(this.syncBuffer);
|
|
907
911
|
}
|
|
908
|
-
|
|
909
|
-
|
|
912
|
+
const messages = [];
|
|
913
|
+
let ignoredBacklogCount = 0;
|
|
914
|
+
for (const rawMessage of response.msgs ?? []) {
|
|
915
|
+
if (rawMessage.message_type !== MSG_TYPE_USER) {
|
|
916
|
+
continue;
|
|
917
|
+
}
|
|
918
|
+
const extracted = extractInboundMessageContent(rawMessage);
|
|
919
|
+
if (!extracted.text && extracted.attachments.length === 0) {
|
|
920
|
+
continue;
|
|
921
|
+
}
|
|
922
|
+
const senderId = rawMessage.from_user_id ?? "unknown";
|
|
923
|
+
if (rawMessage.context_token) {
|
|
924
|
+
this.cacheContextToken(senderId, rawMessage.context_token);
|
|
925
|
+
}
|
|
926
|
+
// Filter pre-start backlog BEFORE claiming/remembering the message so a
|
|
927
|
+
// skipped message is not permanently locked away from other processes.
|
|
928
|
+
// A missing create_time_ms is treated as fresh rather than dropped.
|
|
929
|
+
const createdAtMs = rawMessage.create_time_ms ?? 0;
|
|
930
|
+
if (typeof options.minCreatedAtMs === "number" &&
|
|
931
|
+
Number.isFinite(createdAtMs) &&
|
|
932
|
+
createdAtMs > 0 &&
|
|
933
|
+
createdAtMs < options.minCreatedAtMs) {
|
|
934
|
+
ignoredBacklogCount += 1;
|
|
935
|
+
continue;
|
|
936
|
+
}
|
|
937
|
+
const messageKey = buildMessageKey(rawMessage);
|
|
938
|
+
if (!this.rememberMessage(messageKey)) {
|
|
939
|
+
continue;
|
|
940
|
+
}
|
|
941
|
+
if (!tryClaimInboundMessage(buildScopedMessageClaimKey(account.accountId, messageKey))) {
|
|
942
|
+
continue;
|
|
943
|
+
}
|
|
944
|
+
const { attachments, failureLines } = await this.downloadInboundAttachments(extracted.attachments, rawMessage);
|
|
945
|
+
const text = appendInboundAttachmentFailureText(extracted.text, failureLines);
|
|
946
|
+
messages.push({
|
|
947
|
+
senderId,
|
|
948
|
+
sender: normalizeSender(senderId),
|
|
949
|
+
sessionId: rawMessage.session_id ?? "",
|
|
950
|
+
text,
|
|
951
|
+
attachments,
|
|
952
|
+
contextToken: rawMessage.context_token,
|
|
953
|
+
createdAt: formatTimestamp(rawMessage.create_time_ms),
|
|
954
|
+
createdAtMs,
|
|
955
|
+
});
|
|
910
956
|
}
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
sender: normalizeSender(senderId),
|
|
916
|
-
sessionId: rawMessage.session_id ?? "",
|
|
917
|
-
text,
|
|
918
|
-
attachments,
|
|
919
|
-
contextToken: rawMessage.context_token,
|
|
920
|
-
createdAt: formatTimestamp(rawMessage.create_time_ms),
|
|
921
|
-
createdAtMs,
|
|
922
|
-
});
|
|
957
|
+
return { messages, ignoredBacklogCount };
|
|
958
|
+
}
|
|
959
|
+
finally {
|
|
960
|
+
this.activePollControllers.delete(controller);
|
|
923
961
|
}
|
|
924
|
-
return { messages, ignoredBacklogCount };
|
|
925
962
|
}
|
|
926
963
|
async downloadInboundAttachments(descriptors, rawMessage) {
|
|
927
964
|
const attachments = [];
|
|
@@ -1166,7 +1203,7 @@ export class WeChatTransport {
|
|
|
1166
1203
|
}
|
|
1167
1204
|
return stat;
|
|
1168
1205
|
}
|
|
1169
|
-
async getUpdates(account, timeoutMs) {
|
|
1206
|
+
async getUpdates(account, timeoutMs, signal) {
|
|
1170
1207
|
try {
|
|
1171
1208
|
const raw = await apiFetch({
|
|
1172
1209
|
baseUrl: account.baseUrl,
|
|
@@ -1177,6 +1214,7 @@ export class WeChatTransport {
|
|
|
1177
1214
|
}),
|
|
1178
1215
|
token: account.token,
|
|
1179
1216
|
timeoutMs,
|
|
1217
|
+
signal,
|
|
1180
1218
|
});
|
|
1181
1219
|
return JSON.parse(raw);
|
|
1182
1220
|
}
|
package/package.json
CHANGED
|
@@ -1,46 +1,46 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "cli-wechat-bridge",
|
|
3
|
-
"version": "1.1.
|
|
1
|
+
{
|
|
2
|
+
"name": "cli-wechat-bridge",
|
|
3
|
+
"version": "1.1.8",
|
|
4
4
|
"description": "CLI bridge for Codex, Claude Code, OpenCode, and Pi over WeChat and WeCom",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"files": [
|
|
7
|
-
"bin/",
|
|
8
|
-
"dist/",
|
|
9
|
-
"scripts/ensure-node-pty-permissions.mjs",
|
|
10
|
-
"README.md",
|
|
11
|
-
"LICENSE.txt"
|
|
12
|
-
],
|
|
13
|
-
"keywords": [
|
|
5
|
+
"type": "module",
|
|
6
|
+
"files": [
|
|
7
|
+
"bin/",
|
|
8
|
+
"dist/",
|
|
9
|
+
"scripts/ensure-node-pty-permissions.mjs",
|
|
10
|
+
"README.md",
|
|
11
|
+
"LICENSE.txt"
|
|
12
|
+
],
|
|
13
|
+
"keywords": [
|
|
14
14
|
"wechat",
|
|
15
15
|
"wecom",
|
|
16
|
-
"cli",
|
|
17
|
-
"bridge",
|
|
18
|
-
"codex",
|
|
19
|
-
"claude",
|
|
20
|
-
"opencode",
|
|
21
|
-
"pi",
|
|
22
|
-
"terminal"
|
|
23
|
-
],
|
|
24
|
-
"author": "UNLINEARITY",
|
|
25
|
-
"license": "AGPL-3.0-or-later",
|
|
26
|
-
"repository": {
|
|
27
|
-
"type": "git",
|
|
28
|
-
"url": "git+https://github.com/UNLINEARITY/CLI-WeChat-Bridge.git"
|
|
29
|
-
},
|
|
30
|
-
"bugs": {
|
|
31
|
-
"url": "https://github.com/UNLINEARITY/CLI-WeChat-Bridge/issues"
|
|
32
|
-
},
|
|
33
|
-
"homepage": "https://github.com/UNLINEARITY/CLI-WeChat-Bridge#readme",
|
|
34
|
-
"publishConfig": {
|
|
35
|
-
"access": "public"
|
|
36
|
-
},
|
|
37
|
-
"bin": {
|
|
38
|
-
"wechat-codex": "bin/wechat-codex.mjs",
|
|
39
|
-
"wechat-claude": "bin/wechat-claude.mjs",
|
|
40
|
-
"wechat-opencode": "bin/wechat-opencode.mjs",
|
|
41
|
-
"wechat-pi": "bin/wechat-pi.mjs",
|
|
42
|
-
"wechat-daemon": "bin/wechat-daemon.mjs",
|
|
43
|
-
"wechat-setup": "bin/wechat-setup.mjs",
|
|
16
|
+
"cli",
|
|
17
|
+
"bridge",
|
|
18
|
+
"codex",
|
|
19
|
+
"claude",
|
|
20
|
+
"opencode",
|
|
21
|
+
"pi",
|
|
22
|
+
"terminal"
|
|
23
|
+
],
|
|
24
|
+
"author": "UNLINEARITY",
|
|
25
|
+
"license": "AGPL-3.0-or-later",
|
|
26
|
+
"repository": {
|
|
27
|
+
"type": "git",
|
|
28
|
+
"url": "git+https://github.com/UNLINEARITY/CLI-WeChat-Bridge.git"
|
|
29
|
+
},
|
|
30
|
+
"bugs": {
|
|
31
|
+
"url": "https://github.com/UNLINEARITY/CLI-WeChat-Bridge/issues"
|
|
32
|
+
},
|
|
33
|
+
"homepage": "https://github.com/UNLINEARITY/CLI-WeChat-Bridge#readme",
|
|
34
|
+
"publishConfig": {
|
|
35
|
+
"access": "public"
|
|
36
|
+
},
|
|
37
|
+
"bin": {
|
|
38
|
+
"wechat-codex": "bin/wechat-codex.mjs",
|
|
39
|
+
"wechat-claude": "bin/wechat-claude.mjs",
|
|
40
|
+
"wechat-opencode": "bin/wechat-opencode.mjs",
|
|
41
|
+
"wechat-pi": "bin/wechat-pi.mjs",
|
|
42
|
+
"wechat-daemon": "bin/wechat-daemon.mjs",
|
|
43
|
+
"wechat-setup": "bin/wechat-setup.mjs",
|
|
44
44
|
"wechat-check-update": "bin/wechat-check-update.mjs",
|
|
45
45
|
"wecom-codex": "bin/wecom-codex.mjs",
|
|
46
46
|
"wecom-claude": "bin/wecom-claude.mjs",
|
|
@@ -49,71 +49,73 @@
|
|
|
49
49
|
"wecom-daemon": "bin/wecom-daemon.mjs",
|
|
50
50
|
"wecom-setup": "bin/wecom-setup.mjs",
|
|
51
51
|
"wecom-check-update": "bin/wecom-check-update.mjs"
|
|
52
|
-
},
|
|
53
|
-
"scripts": {
|
|
54
|
-
"postinstall": "node scripts/ensure-node-pty-permissions.mjs",
|
|
55
|
-
"clean": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\"",
|
|
56
|
-
"build": "npm run clean && tsc -p tsconfig.build.json",
|
|
57
|
-
"prepack": "npm run build",
|
|
58
|
-
"lint": "eslint bin src test",
|
|
59
|
-
"lint:fix": "eslint bin src test --fix",
|
|
60
|
-
"typecheck:src": "tsc -p tsconfig.typecheck.src.json --noEmit --pretty false",
|
|
61
|
-
"quality": "npm run lint && npm run typecheck:src && bun test test && npm run build",
|
|
62
|
-
"smoke:global": "node scripts/smoke-global-install.mjs",
|
|
63
|
-
"
|
|
64
|
-
"
|
|
65
|
-
"
|
|
66
|
-
"
|
|
67
|
-
"
|
|
68
|
-
"
|
|
69
|
-
"
|
|
70
|
-
"codex
|
|
71
|
-
"codex:
|
|
72
|
-
"
|
|
73
|
-
"claude:
|
|
74
|
-
"
|
|
75
|
-
"bridge:
|
|
76
|
-
"opencode
|
|
77
|
-
"opencode:
|
|
78
|
-
"
|
|
79
|
-
"pi
|
|
80
|
-
"pi:
|
|
81
|
-
"
|
|
82
|
-
"
|
|
83
|
-
"test
|
|
84
|
-
"test:
|
|
52
|
+
},
|
|
53
|
+
"scripts": {
|
|
54
|
+
"postinstall": "node scripts/ensure-node-pty-permissions.mjs",
|
|
55
|
+
"clean": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\"",
|
|
56
|
+
"build": "npm run clean && tsc -p tsconfig.build.json",
|
|
57
|
+
"prepack": "npm run build",
|
|
58
|
+
"lint": "eslint bin src test",
|
|
59
|
+
"lint:fix": "eslint bin src test --fix",
|
|
60
|
+
"typecheck:src": "tsc -p tsconfig.typecheck.src.json --noEmit --pretty false",
|
|
61
|
+
"quality": "npm run lint && npm run typecheck:src && bun test test && npm run build",
|
|
62
|
+
"smoke:global": "node scripts/smoke-global-install.mjs",
|
|
63
|
+
"smoke:cli-compat": "node scripts/smoke-cli-compatibility.mjs",
|
|
64
|
+
"publish:dual": "node scripts/publish-dual.mjs",
|
|
65
|
+
"setup": "node --no-warnings --experimental-strip-types src/wechat/setup.ts",
|
|
66
|
+
"start": "node --no-warnings --experimental-strip-types src/wechat/wechat-channel.ts",
|
|
67
|
+
"check": "node --no-warnings --experimental-strip-types src/wechat/wechat-channel.ts --check",
|
|
68
|
+
"bridge": "node --no-warnings --experimental-strip-types src/bridge/wechat-bridge.ts",
|
|
69
|
+
"daemon": "node --no-warnings --experimental-strip-types src/daemon/wechat-daemon.ts",
|
|
70
|
+
"bridge:codex": "node --no-warnings --experimental-strip-types src/bridge/wechat-bridge.ts --adapter codex",
|
|
71
|
+
"codex:panel": "node --no-warnings --experimental-strip-types src/companion/codex-remote-client.ts",
|
|
72
|
+
"codex:start": "node --no-warnings --experimental-strip-types src/companion/local-companion-start.ts",
|
|
73
|
+
"claude:start": "node --no-warnings --experimental-strip-types src/companion/local-companion-start.ts --adapter claude",
|
|
74
|
+
"claude:companion": "node --no-warnings --experimental-strip-types src/companion/local-companion.ts --adapter claude",
|
|
75
|
+
"bridge:claude": "node --no-warnings --experimental-strip-types src/bridge/wechat-bridge.ts --adapter claude",
|
|
76
|
+
"bridge:opencode": "node --no-warnings --experimental-strip-types src/bridge/wechat-bridge.ts --adapter opencode",
|
|
77
|
+
"opencode:panel": "node --no-warnings --experimental-strip-types src/companion/local-companion.ts --adapter opencode",
|
|
78
|
+
"opencode:start": "node --no-warnings --experimental-strip-types src/companion/local-companion-start.ts --adapter opencode",
|
|
79
|
+
"bridge:pi": "node --no-warnings --experimental-strip-types src/bridge/wechat-bridge.ts --adapter pi",
|
|
80
|
+
"pi:companion": "node --no-warnings --experimental-strip-types src/companion/local-companion.ts --adapter pi",
|
|
81
|
+
"pi:start": "node --no-warnings --experimental-strip-types src/companion/local-companion-start.ts --adapter pi",
|
|
82
|
+
"bridge:bun": "bun src/bridge/wechat-bridge.ts",
|
|
83
|
+
"test": "bun test test",
|
|
84
|
+
"test:bridge": "bun test test/bridge",
|
|
85
|
+
"test:companion": "bun test test/companion",
|
|
85
86
|
"test:wechat": "bun test test/wechat",
|
|
86
87
|
"test:wecom": "bun test test/wecom",
|
|
87
|
-
"test:watch": "bun test --watch test"
|
|
88
|
-
},
|
|
89
|
-
"dependencies": {
|
|
90
|
-
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
91
|
-
"@opencode-ai/sdk": "^1.18.0",
|
|
92
|
-
"@wecom/aibot-node-sdk": "1.0.7",
|
|
93
|
-
"
|
|
94
|
-
"
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
"
|
|
99
|
-
"
|
|
100
|
-
"
|
|
101
|
-
"
|
|
102
|
-
"
|
|
103
|
-
"
|
|
104
|
-
"
|
|
105
|
-
"
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
"@
|
|
110
|
-
"@types/
|
|
111
|
-
"
|
|
112
|
-
"
|
|
113
|
-
"typescript
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
"
|
|
118
|
-
|
|
119
|
-
}
|
|
88
|
+
"test:watch": "bun test --watch test"
|
|
89
|
+
},
|
|
90
|
+
"dependencies": {
|
|
91
|
+
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
92
|
+
"@opencode-ai/sdk": "^1.18.0",
|
|
93
|
+
"@wecom/aibot-node-sdk": "1.0.7",
|
|
94
|
+
"@xterm/headless": "^6.0.0",
|
|
95
|
+
"node-pty": "^1.1.0",
|
|
96
|
+
"qrcode-terminal": "^0.12.0"
|
|
97
|
+
},
|
|
98
|
+
"overrides": {
|
|
99
|
+
"@hono/node-server": "2.1.1",
|
|
100
|
+
"body-parser": "2.3.0",
|
|
101
|
+
"brace-expansion": "5.0.9",
|
|
102
|
+
"express-rate-limit": "8.6.2",
|
|
103
|
+
"fast-uri": "3.1.5",
|
|
104
|
+
"hono": "4.13.3",
|
|
105
|
+
"ip-address": "10.5.0",
|
|
106
|
+
"path-to-regexp": "8.4.2",
|
|
107
|
+
"qs": "6.15.3"
|
|
108
|
+
},
|
|
109
|
+
"devDependencies": {
|
|
110
|
+
"@eslint/js": "^10.0.1",
|
|
111
|
+
"@types/bun": "latest",
|
|
112
|
+
"@types/node": "^24.12.4",
|
|
113
|
+
"eslint": "^10.3.0",
|
|
114
|
+
"typescript": "^6.0.2",
|
|
115
|
+
"typescript-eslint": "^8.59.3"
|
|
116
|
+
},
|
|
117
|
+
"engines": {
|
|
118
|
+
"bun": ">=1.0.0",
|
|
119
|
+
"node": ">=22.13.0"
|
|
120
|
+
}
|
|
121
|
+
}
|
|
@@ -1,73 +1,73 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
// Ensure the bundled node-pty `spawn-helper` is executable.
|
|
4
|
-
//
|
|
5
|
-
// node-pty ships its prebuilt `spawn-helper` binaries with mode 0644 (no exec
|
|
6
|
-
// bit) in the published tarball. On macOS/Linux that makes `posix_spawnp`
|
|
7
|
-
// fail when node-pty tries to fork a PTY, so the bridge silently drops to the
|
|
8
|
-
// non-PTY fallback. The Claude adapter relies on PTY interactive mode, so the
|
|
9
|
-
// fallback surfaces to users as:
|
|
10
|
-
//
|
|
11
|
-
// Error: Input must be provided ... when using --print
|
|
12
|
-
//
|
|
13
|
-
// Restoring the exec bit after install fixes PTY spawning. This runs on
|
|
14
|
-
// postinstall and is idempotent; it never fails the install.
|
|
15
|
-
|
|
16
|
-
import fs from "node:fs";
|
|
17
|
-
import path from "node:path";
|
|
18
|
-
import { createRequire } from "node:module";
|
|
19
|
-
|
|
20
|
-
if (process.platform === "win32") {
|
|
21
|
-
process.exit(0);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const require = createRequire(import.meta.url);
|
|
25
|
-
|
|
26
|
-
let nodePtyDir;
|
|
27
|
-
try {
|
|
28
|
-
nodePtyDir = path.dirname(require.resolve("node-pty/package.json"));
|
|
29
|
-
} catch {
|
|
30
|
-
// node-pty is optional in unsupported environments; nothing to fix.
|
|
31
|
-
process.exit(0);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const candidates = [
|
|
35
|
-
"prebuilds/darwin-arm64/spawn-helper",
|
|
36
|
-
"prebuilds/darwin-x64/spawn-helper",
|
|
37
|
-
"prebuilds/linux-x64/spawn-helper",
|
|
38
|
-
"prebuilds/linux-arm64/spawn-helper",
|
|
39
|
-
"build/Release/spawn-helper",
|
|
40
|
-
];
|
|
41
|
-
|
|
42
|
-
let fixed = 0;
|
|
43
|
-
for (const relative of candidates) {
|
|
44
|
-
const helperPath = path.join(nodePtyDir, relative);
|
|
45
|
-
let stats;
|
|
46
|
-
try {
|
|
47
|
-
stats = fs.statSync(helperPath);
|
|
48
|
-
} catch {
|
|
49
|
-
continue;
|
|
50
|
-
}
|
|
51
|
-
if (!stats.isFile()) {
|
|
52
|
-
continue;
|
|
53
|
-
}
|
|
54
|
-
if ((stats.mode & 0o111) !== 0) {
|
|
55
|
-
continue;
|
|
56
|
-
}
|
|
57
|
-
try {
|
|
58
|
-
fs.chmodSync(helperPath, stats.mode | 0o755);
|
|
59
|
-
fixed += 1;
|
|
60
|
-
} catch (error) {
|
|
61
|
-
console.warn(
|
|
62
|
-
`[cli-wechat-bridge] Could not make node-pty spawn-helper executable: ${helperPath}\n` +
|
|
63
|
-
` ${error instanceof Error ? error.message : String(error)}\n` +
|
|
64
|
-
" PTY mode may be unavailable; run --doctor for details.",
|
|
65
|
-
);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
if (fixed > 0) {
|
|
70
|
-
console.log(
|
|
71
|
-
`[cli-wechat-bridge] Restored executable bit on ${fixed} node-pty spawn-helper binary(ies).`,
|
|
72
|
-
);
|
|
73
|
-
}
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// Ensure the bundled node-pty `spawn-helper` is executable.
|
|
4
|
+
//
|
|
5
|
+
// node-pty ships its prebuilt `spawn-helper` binaries with mode 0644 (no exec
|
|
6
|
+
// bit) in the published tarball. On macOS/Linux that makes `posix_spawnp`
|
|
7
|
+
// fail when node-pty tries to fork a PTY, so the bridge silently drops to the
|
|
8
|
+
// non-PTY fallback. The Claude adapter relies on PTY interactive mode, so the
|
|
9
|
+
// fallback surfaces to users as:
|
|
10
|
+
//
|
|
11
|
+
// Error: Input must be provided ... when using --print
|
|
12
|
+
//
|
|
13
|
+
// Restoring the exec bit after install fixes PTY spawning. This runs on
|
|
14
|
+
// postinstall and is idempotent; it never fails the install.
|
|
15
|
+
|
|
16
|
+
import fs from "node:fs";
|
|
17
|
+
import path from "node:path";
|
|
18
|
+
import { createRequire } from "node:module";
|
|
19
|
+
|
|
20
|
+
if (process.platform === "win32") {
|
|
21
|
+
process.exit(0);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const require = createRequire(import.meta.url);
|
|
25
|
+
|
|
26
|
+
let nodePtyDir;
|
|
27
|
+
try {
|
|
28
|
+
nodePtyDir = path.dirname(require.resolve("node-pty/package.json"));
|
|
29
|
+
} catch {
|
|
30
|
+
// node-pty is optional in unsupported environments; nothing to fix.
|
|
31
|
+
process.exit(0);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const candidates = [
|
|
35
|
+
"prebuilds/darwin-arm64/spawn-helper",
|
|
36
|
+
"prebuilds/darwin-x64/spawn-helper",
|
|
37
|
+
"prebuilds/linux-x64/spawn-helper",
|
|
38
|
+
"prebuilds/linux-arm64/spawn-helper",
|
|
39
|
+
"build/Release/spawn-helper",
|
|
40
|
+
];
|
|
41
|
+
|
|
42
|
+
let fixed = 0;
|
|
43
|
+
for (const relative of candidates) {
|
|
44
|
+
const helperPath = path.join(nodePtyDir, relative);
|
|
45
|
+
let stats;
|
|
46
|
+
try {
|
|
47
|
+
stats = fs.statSync(helperPath);
|
|
48
|
+
} catch {
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
if (!stats.isFile()) {
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
if ((stats.mode & 0o111) !== 0) {
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
fs.chmodSync(helperPath, stats.mode | 0o755);
|
|
59
|
+
fixed += 1;
|
|
60
|
+
} catch (error) {
|
|
61
|
+
console.warn(
|
|
62
|
+
`[cli-wechat-bridge] Could not make node-pty spawn-helper executable: ${helperPath}\n` +
|
|
63
|
+
` ${error instanceof Error ? error.message : String(error)}\n` +
|
|
64
|
+
" PTY mode may be unavailable; run --doctor for details.",
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (fixed > 0) {
|
|
70
|
+
console.log(
|
|
71
|
+
`[cli-wechat-bridge] Restored executable bit on ${fixed} node-pty spawn-helper binary(ies).`,
|
|
72
|
+
);
|
|
73
|
+
}
|