-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcli.ts
More file actions
129 lines (115 loc) · 3.74 KB
/
cli.ts
File metadata and controls
129 lines (115 loc) · 3.74 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#!/usr/bin/env node
import { doQRLogin } from "./src/ilink/auth";
import { getUpdates, sendTextMessage } from "./src/ilink/client";
import { OpenCodeClient } from "./src/opencode/client";
import { Bridge } from "./src/bridge";
import {
loadCredentials,
ILINK_BASE_URL,
OPENCODE_BASE_URL,
log,
logError,
loadSessionId,
saveSessionId,
loadSyncBuf,
saveSyncBuf,
RETRY_DELAY_MS,
MAX_CONSECUTIVE_FAILURES,
BACKOFF_DELAY_MS,
} from "./src/config";
import { MSG_TYPE_USER } from "./src/ilink/types";
const args = process.argv.slice(2);
const command = args[0] ?? "start";
async function main() {
switch (command) {
case "setup": {
const account = await doQRLogin(ILINK_BASE_URL);
if (!account) {
logError("登录失败");
process.exit(1);
}
log("✅ 设置完成!运行 wxcode-bridge start 启动桥接");
break;
}
case "start": {
const oc = new OpenCodeClient(OPENCODE_BASE_URL);
if (!(await oc.isHealthy())) {
logError("OpenCode 未运行。请先执行: opencode serve --port 4096");
process.exit(1);
}
log("✅ OpenCode 已连接");
let account = loadCredentials();
if (!account) {
log("未找到微信凭据,启动扫码登录...");
account = await doQRLogin(ILINK_BASE_URL);
if (!account) {
logError("登录失败");
process.exit(1);
}
}
log(`✅ 微信已连接 (${account.accountId})`);
const bridge = new Bridge({
sendText: (toUserId, text, contextToken) =>
sendTextMessage(account!.baseUrl, account!.token, toUserId, text, contextToken),
sendPrompt: (sessionId, text) => oc.sendPrompt(sessionId, text),
isHealthy: () => oc.isHealthy(),
createSession: async () => {
const id = await oc.createSession();
saveSessionId(id);
return id;
},
});
const savedSessionId = loadSessionId();
if (savedSessionId) {
bridge.setSessionId(savedSessionId);
log(`📎 恢复会话: ${savedSessionId}`);
}
log("🚀 桥接已启动,在微信中发消息开始对话");
let syncBuf = loadSyncBuf();
let consecutiveFailures = 0;
while (true) {
try {
const response = await getUpdates(account.baseUrl, account.token, syncBuf);
if (response.get_updates_buf) {
syncBuf = response.get_updates_buf;
saveSyncBuf(syncBuf);
}
consecutiveFailures = 0;
const msgs = response.msgs ?? [];
for (const msg of msgs) {
if (msg.message_type === MSG_TYPE_USER) {
await bridge.handleIncomingMessage(msg);
}
}
} catch (error: any) {
consecutiveFailures++;
logError(`轮询失败 (${consecutiveFailures}/${MAX_CONSECUTIVE_FAILURES}): ${error?.message ?? error}`);
if (consecutiveFailures >= MAX_CONSECUTIVE_FAILURES) {
logError(`连续失败 ${MAX_CONSECUTIVE_FAILURES} 次,等待 ${BACKOFF_DELAY_MS / 1000}s 后重试`);
await new Promise((r) => setTimeout(r, BACKOFF_DELAY_MS));
consecutiveFailures = 0;
} else {
await new Promise((r) => setTimeout(r, RETRY_DELAY_MS));
}
}
}
break;
}
case "help":
default:
console.log(`
wxcode-bridge — 微信 ↔ OpenCode 桥接
用法:
wxcode-bridge setup 微信扫码登录
wxcode-bridge start 启动桥接(默认)
wxcode-bridge help 显示帮助
前提:
1. opencode serve --port 4096 (先启动 OpenCode)
2. iOS 微信 8.0.70+ 已开启 ClawBot 插件
`);
}
}
main().catch((err) => {
logError(`Fatal: ${String(err)}`);
process.exit(1);
});