wechat-acp 0.1.0
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 +21 -0
- package/README.md +185 -0
- package/dist/bin/wechat-acp.d.ts +14 -0
- package/dist/bin/wechat-acp.d.ts.map +1 -0
- package/dist/bin/wechat-acp.js +270 -0
- package/dist/bin/wechat-acp.js.map +1 -0
- package/dist/package.json +55 -0
- package/dist/src/acp/agent-manager.d.ts +21 -0
- package/dist/src/acp/agent-manager.d.ts.map +1 -0
- package/dist/src/acp/agent-manager.js +73 -0
- package/dist/src/acp/agent-manager.js.map +1 -0
- package/dist/src/acp/client.d.ts +28 -0
- package/dist/src/acp/client.d.ts.map +1 -0
- package/dist/src/acp/client.js +121 -0
- package/dist/src/acp/client.js.map +1 -0
- package/dist/src/acp/session.d.ts +51 -0
- package/dist/src/acp/session.d.ts.map +1 -0
- package/dist/src/acp/session.js +173 -0
- package/dist/src/acp/session.js.map +1 -0
- package/dist/src/adapter/inbound.d.ts +10 -0
- package/dist/src/adapter/inbound.d.ts.map +1 -0
- package/dist/src/adapter/inbound.js +146 -0
- package/dist/src/adapter/inbound.js.map +1 -0
- package/dist/src/adapter/outbound.d.ts +9 -0
- package/dist/src/adapter/outbound.d.ts.map +1 -0
- package/dist/src/adapter/outbound.js +25 -0
- package/dist/src/adapter/outbound.js.map +1 -0
- package/dist/src/bridge.d.ts +28 -0
- package/dist/src/bridge.d.ts.map +1 -0
- package/dist/src/bridge.js +171 -0
- package/dist/src/bridge.js.map +1 -0
- package/dist/src/config.d.ts +61 -0
- package/dist/src/config.d.ts.map +1 -0
- package/dist/src/config.js +114 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/index.d.ts +7 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +6 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/weixin/api.d.ts +50 -0
- package/dist/src/weixin/api.d.ts.map +1 -0
- package/dist/src/weixin/api.js +84 -0
- package/dist/src/weixin/api.js.map +1 -0
- package/dist/src/weixin/auth.d.ts +20 -0
- package/dist/src/weixin/auth.d.ts.map +1 -0
- package/dist/src/weixin/auth.js +84 -0
- package/dist/src/weixin/auth.js.map +1 -0
- package/dist/src/weixin/media.d.ts +23 -0
- package/dist/src/weixin/media.d.ts.map +1 -0
- package/dist/src/weixin/media.js +58 -0
- package/dist/src/weixin/media.js.map +1 -0
- package/dist/src/weixin/monitor.d.ts +16 -0
- package/dist/src/weixin/monitor.d.ts.map +1 -0
- package/dist/src/weixin/monitor.js +111 -0
- package/dist/src/weixin/monitor.js.map +1 -0
- package/dist/src/weixin/send.d.ts +14 -0
- package/dist/src/weixin/send.d.ts.map +1 -0
- package/dist/src/weixin/send.js +51 -0
- package/dist/src/weixin/send.js.map +1 -0
- package/dist/src/weixin/types.d.ts +148 -0
- package/dist/src/weixin/types.d.ts.map +1 -0
- package/dist/src/weixin/types.js +33 -0
- package/dist/src/weixin/types.js.map +1 -0
- package/package.json +55 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../../src/bridge.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAWH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAInD,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,eAAe,CAAyB;IAChD,OAAO,CAAC,cAAc,CAA+B;IACrD,OAAO,CAAC,SAAS,CAA0B;IAE3C,OAAO,CAAC,aAAa,CAA4D;IACjF,OAAO,CAAC,GAAG,CAAwB;gBAEvB,MAAM,EAAE,eAAe,EAAE,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI;IAK1D,KAAK,CAAC,IAAI,CAAC,EAAE;QACjB,UAAU,CAAC,EAAE,OAAO,CAAC;QACrB,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;KACrC,GAAG,OAAO,CAAC,IAAI,CAAC;IA+CX,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAO3B,OAAO,CAAC,aAAa;YAmBP,cAAc;YAcd,SAAS;YAaT,mBAAmB;YAmBnB,eAAe;IAyB7B,OAAO,CAAC,cAAc;CAcvB"}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WeChatAcpBridge — the main orchestrator.
|
|
3
|
+
*
|
|
4
|
+
* Connects WeChat's iLink long-poll to ACP agent subprocesses.
|
|
5
|
+
* One bridge = one WeChat bot account → many users → many agent sessions.
|
|
6
|
+
*/
|
|
7
|
+
import { login, loadToken } from "./weixin/auth.js";
|
|
8
|
+
import { startMonitor } from "./weixin/monitor.js";
|
|
9
|
+
import { sendTextMessage, splitText } from "./weixin/send.js";
|
|
10
|
+
import { sendTyping, getConfig } from "./weixin/api.js";
|
|
11
|
+
import { TypingStatus, MessageType } from "./weixin/types.js";
|
|
12
|
+
import { SessionManager } from "./acp/session.js";
|
|
13
|
+
import { weixinMessageToPrompt } from "./adapter/inbound.js";
|
|
14
|
+
import { formatForWeChat } from "./adapter/outbound.js";
|
|
15
|
+
const TEXT_CHUNK_LIMIT = 4000;
|
|
16
|
+
export class WeChatAcpBridge {
|
|
17
|
+
config;
|
|
18
|
+
abortController = new AbortController();
|
|
19
|
+
sessionManager = null;
|
|
20
|
+
tokenData = null;
|
|
21
|
+
// Per-user typing ticket cache
|
|
22
|
+
typingTickets = new Map();
|
|
23
|
+
log;
|
|
24
|
+
constructor(config, log) {
|
|
25
|
+
this.config = config;
|
|
26
|
+
this.log = log ?? ((msg) => console.log(`[wechat-acp] ${msg}`));
|
|
27
|
+
}
|
|
28
|
+
async start(opts) {
|
|
29
|
+
const { forceLogin, renderQrUrl } = opts ?? {};
|
|
30
|
+
// 1. Login or load token
|
|
31
|
+
if (!forceLogin) {
|
|
32
|
+
this.tokenData = loadToken(this.config.storage.dir);
|
|
33
|
+
}
|
|
34
|
+
if (!this.tokenData) {
|
|
35
|
+
this.tokenData = await login({
|
|
36
|
+
baseUrl: this.config.wechat.baseUrl,
|
|
37
|
+
botType: this.config.wechat.botType,
|
|
38
|
+
storageDir: this.config.storage.dir,
|
|
39
|
+
log: this.log,
|
|
40
|
+
renderQrUrl,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
this.log(`Loaded saved token (Bot: ${this.tokenData.accountId}, saved at ${this.tokenData.savedAt})`);
|
|
45
|
+
this.log(`Use --login to force re-login`);
|
|
46
|
+
}
|
|
47
|
+
// 2. Create SessionManager
|
|
48
|
+
this.sessionManager = new SessionManager({
|
|
49
|
+
agentCommand: this.config.agent.command,
|
|
50
|
+
agentArgs: this.config.agent.args,
|
|
51
|
+
agentCwd: this.config.agent.cwd,
|
|
52
|
+
agentEnv: this.config.agent.env,
|
|
53
|
+
idleTimeoutMs: this.config.session.idleTimeoutMs,
|
|
54
|
+
maxConcurrentUsers: this.config.session.maxConcurrentUsers,
|
|
55
|
+
log: this.log,
|
|
56
|
+
onReply: (userId, contextToken, text) => this.sendReply(userId, contextToken, text),
|
|
57
|
+
sendTyping: (userId, contextToken) => this.sendTypingIndicator(userId, contextToken),
|
|
58
|
+
});
|
|
59
|
+
this.sessionManager.start();
|
|
60
|
+
// 3. Start monitor loop
|
|
61
|
+
this.log("Starting message polling...");
|
|
62
|
+
await startMonitor({
|
|
63
|
+
baseUrl: this.tokenData.baseUrl,
|
|
64
|
+
token: this.tokenData.token,
|
|
65
|
+
storageDir: this.config.storage.dir,
|
|
66
|
+
abortSignal: this.abortController.signal,
|
|
67
|
+
log: this.log,
|
|
68
|
+
onMessage: (msg) => this.handleMessage(msg),
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
async stop() {
|
|
72
|
+
this.log("Stopping bridge...");
|
|
73
|
+
this.abortController.abort();
|
|
74
|
+
await this.sessionManager?.stop();
|
|
75
|
+
this.log("Bridge stopped");
|
|
76
|
+
}
|
|
77
|
+
handleMessage(msg) {
|
|
78
|
+
// Only process user messages (not bot's own messages)
|
|
79
|
+
if (msg.message_type !== MessageType.USER)
|
|
80
|
+
return;
|
|
81
|
+
// Skip group messages (v1: direct only)
|
|
82
|
+
if (msg.group_id)
|
|
83
|
+
return;
|
|
84
|
+
const userId = msg.from_user_id;
|
|
85
|
+
const contextToken = msg.context_token;
|
|
86
|
+
if (!userId || !contextToken)
|
|
87
|
+
return;
|
|
88
|
+
this.log(`Message from ${userId}: ${this.previewMessage(msg)}`);
|
|
89
|
+
// Convert and enqueue — fire-and-forget (don't block the poll loop)
|
|
90
|
+
this.enqueueMessage(msg, userId, contextToken).catch((err) => {
|
|
91
|
+
this.log(`Failed to enqueue message from ${userId}: ${String(err)}`);
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
async enqueueMessage(msg, userId, contextToken) {
|
|
95
|
+
const prompt = await weixinMessageToPrompt(msg, this.config.wechat.cdnBaseUrl, this.log);
|
|
96
|
+
await this.sessionManager.enqueue(userId, { prompt, contextToken });
|
|
97
|
+
}
|
|
98
|
+
async sendReply(userId, contextToken, text) {
|
|
99
|
+
const formatted = formatForWeChat(text);
|
|
100
|
+
const segments = splitText(formatted, TEXT_CHUNK_LIMIT);
|
|
101
|
+
for (const segment of segments) {
|
|
102
|
+
await sendTextMessage(userId, segment, {
|
|
103
|
+
baseUrl: this.tokenData.baseUrl,
|
|
104
|
+
token: this.tokenData.token,
|
|
105
|
+
contextToken,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
async sendTypingIndicator(userId, contextToken) {
|
|
110
|
+
try {
|
|
111
|
+
const ticket = await this.getTypingTicket(userId, contextToken);
|
|
112
|
+
if (!ticket)
|
|
113
|
+
return;
|
|
114
|
+
await sendTyping({
|
|
115
|
+
baseUrl: this.tokenData.baseUrl,
|
|
116
|
+
token: this.tokenData.token,
|
|
117
|
+
body: {
|
|
118
|
+
ilink_user_id: userId,
|
|
119
|
+
typing_ticket: ticket,
|
|
120
|
+
status: TypingStatus.TYPING,
|
|
121
|
+
},
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
// Typing is best-effort
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
async getTypingTicket(userId, contextToken) {
|
|
129
|
+
const cached = this.typingTickets.get(userId);
|
|
130
|
+
if (cached && cached.expiresAt > Date.now())
|
|
131
|
+
return cached.ticket;
|
|
132
|
+
try {
|
|
133
|
+
const resp = await getConfig({
|
|
134
|
+
baseUrl: this.tokenData.baseUrl,
|
|
135
|
+
token: this.tokenData.token,
|
|
136
|
+
ilinkUserId: userId,
|
|
137
|
+
contextToken,
|
|
138
|
+
});
|
|
139
|
+
if (resp.typing_ticket) {
|
|
140
|
+
this.typingTickets.set(userId, {
|
|
141
|
+
ticket: resp.typing_ticket,
|
|
142
|
+
expiresAt: Date.now() + 24 * 60 * 60_000, // 24h cache
|
|
143
|
+
});
|
|
144
|
+
return resp.typing_ticket;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
// Not critical
|
|
149
|
+
}
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
previewMessage(msg) {
|
|
153
|
+
const items = msg.item_list ?? [];
|
|
154
|
+
for (const item of items) {
|
|
155
|
+
if (item.type === 1 && item.text_item?.text) {
|
|
156
|
+
const text = item.text_item.text;
|
|
157
|
+
return text.length > 50 ? text.substring(0, 50) + "..." : text;
|
|
158
|
+
}
|
|
159
|
+
if (item.type === 2)
|
|
160
|
+
return "[image]";
|
|
161
|
+
if (item.type === 3)
|
|
162
|
+
return item.voice_item?.text ? `[voice] ${item.voice_item.text.substring(0, 30)}` : "[voice]";
|
|
163
|
+
if (item.type === 4)
|
|
164
|
+
return `[file] ${item.file_item?.file_name ?? ""}`;
|
|
165
|
+
if (item.type === 5)
|
|
166
|
+
return "[video]";
|
|
167
|
+
}
|
|
168
|
+
return "[empty]";
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
//# sourceMappingURL=bridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bridge.js","sourceRoot":"","sources":["../../src/bridge.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration types and defaults for wechat-acp.
|
|
3
|
+
*/
|
|
4
|
+
export interface AgentCommandConfig {
|
|
5
|
+
command: string;
|
|
6
|
+
args: string[];
|
|
7
|
+
env?: Record<string, string>;
|
|
8
|
+
}
|
|
9
|
+
export interface AgentPreset extends AgentCommandConfig {
|
|
10
|
+
label: string;
|
|
11
|
+
description?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface ResolvedAgentConfig extends AgentCommandConfig {
|
|
14
|
+
id?: string;
|
|
15
|
+
label?: string;
|
|
16
|
+
source: "preset" | "raw";
|
|
17
|
+
}
|
|
18
|
+
export declare const BUILT_IN_AGENTS: Record<string, AgentPreset>;
|
|
19
|
+
export interface WeChatAcpConfig {
|
|
20
|
+
wechat: {
|
|
21
|
+
baseUrl: string;
|
|
22
|
+
cdnBaseUrl: string;
|
|
23
|
+
botType: string;
|
|
24
|
+
};
|
|
25
|
+
agent: {
|
|
26
|
+
preset?: string;
|
|
27
|
+
command: string;
|
|
28
|
+
args: string[];
|
|
29
|
+
cwd: string;
|
|
30
|
+
env?: Record<string, string>;
|
|
31
|
+
};
|
|
32
|
+
agents: Record<string, AgentPreset>;
|
|
33
|
+
session: {
|
|
34
|
+
idleTimeoutMs: number;
|
|
35
|
+
maxConcurrentUsers: number;
|
|
36
|
+
};
|
|
37
|
+
daemon: {
|
|
38
|
+
enabled: boolean;
|
|
39
|
+
logFile: string;
|
|
40
|
+
pidFile: string;
|
|
41
|
+
};
|
|
42
|
+
storage: {
|
|
43
|
+
dir: string;
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
export declare function defaultStorageDir(): string;
|
|
47
|
+
export declare function defaultConfig(): WeChatAcpConfig;
|
|
48
|
+
/**
|
|
49
|
+
* Parse agent string like "claude code" or "npx tsx ./agent.ts"
|
|
50
|
+
* into { command, args }.
|
|
51
|
+
*/
|
|
52
|
+
export declare function parseAgentCommand(agentStr: string): {
|
|
53
|
+
command: string;
|
|
54
|
+
args: string[];
|
|
55
|
+
};
|
|
56
|
+
export declare function resolveAgentSelection(agentSelection: string, registry?: Record<string, AgentPreset>): ResolvedAgentConfig;
|
|
57
|
+
export declare function listBuiltInAgents(registry?: Record<string, AgentPreset>): Array<{
|
|
58
|
+
id: string;
|
|
59
|
+
preset: AgentPreset;
|
|
60
|
+
}>;
|
|
61
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B;AAED,MAAM,WAAW,WAAY,SAAQ,kBAAkB;IACrD,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,mBAAoB,SAAQ,kBAAkB;IAC7D,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,QAAQ,GAAG,KAAK,CAAC;CAC1B;AAED,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAqCvD,CAAC;AAEF,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE;QACN,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,EAAE,MAAM,CAAC;QACnB,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,KAAK,EAAE;QACL,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,EAAE,MAAM,EAAE,CAAC;QACf,GAAG,EAAE,MAAM,CAAC;QACZ,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KAC9B,CAAC;IACF,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACpC,OAAO,EAAE;QACP,aAAa,EAAE,MAAM,CAAC;QACtB,kBAAkB,EAAE,MAAM,CAAC;KAC5B,CAAC;IACF,MAAM,EAAE;QACN,OAAO,EAAE,OAAO,CAAC;QACjB,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,OAAO,EAAE;QACP,GAAG,EAAE,MAAM,CAAC;KACb,CAAC;CACH;AAED,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED,wBAAgB,aAAa,IAAI,eAAe,CA4B/C;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,CASvF;AAED,wBAAgB,qBAAqB,CACnC,cAAc,EAAE,MAAM,EACtB,QAAQ,GAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAmB,GACtD,mBAAmB,CAmBrB;AAED,wBAAgB,iBAAiB,CAC/B,QAAQ,GAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAmB,GACtD,KAAK,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,WAAW,CAAA;CAAE,CAAC,CAI5C"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration types and defaults for wechat-acp.
|
|
3
|
+
*/
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import os from "node:os";
|
|
6
|
+
export const BUILT_IN_AGENTS = {
|
|
7
|
+
copilot: {
|
|
8
|
+
label: "GitHub Copilot",
|
|
9
|
+
command: "npx",
|
|
10
|
+
args: ["@github/copilot", "--acp", "--yolo"],
|
|
11
|
+
description: "GitHub Copilot",
|
|
12
|
+
},
|
|
13
|
+
claude: {
|
|
14
|
+
label: "Claude Code",
|
|
15
|
+
command: "npx",
|
|
16
|
+
args: ["@zed-industries/claude-code-acp"],
|
|
17
|
+
description: "Claude Code ACP",
|
|
18
|
+
},
|
|
19
|
+
gemini: {
|
|
20
|
+
label: "Gemini CLI",
|
|
21
|
+
command: "npx",
|
|
22
|
+
args: ["@google/gemini-cli", "--experimental-acp"],
|
|
23
|
+
description: "Gemini CLI",
|
|
24
|
+
},
|
|
25
|
+
qwen: {
|
|
26
|
+
label: "Qwen Code",
|
|
27
|
+
command: "npx",
|
|
28
|
+
args: ["@qwen-code/qwen-code", "--acp", "--experimental-skills"],
|
|
29
|
+
description: "Qwen Code",
|
|
30
|
+
},
|
|
31
|
+
codex: {
|
|
32
|
+
label: "Codex CLI",
|
|
33
|
+
command: "npx",
|
|
34
|
+
args: ["@zed-industries/codex-acp"],
|
|
35
|
+
description: "Codex ACP",
|
|
36
|
+
},
|
|
37
|
+
opencode: {
|
|
38
|
+
label: "OpenCode",
|
|
39
|
+
command: "npx",
|
|
40
|
+
args: ["opencode-ai", "acp"],
|
|
41
|
+
description: "OpenCode",
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
export function defaultStorageDir() {
|
|
45
|
+
return path.join(os.homedir(), ".wechat-acp");
|
|
46
|
+
}
|
|
47
|
+
export function defaultConfig() {
|
|
48
|
+
const storageDir = defaultStorageDir();
|
|
49
|
+
return {
|
|
50
|
+
wechat: {
|
|
51
|
+
baseUrl: "https://ilinkai.weixin.qq.com",
|
|
52
|
+
cdnBaseUrl: "https://novac2c.cdn.weixin.qq.com/c2c",
|
|
53
|
+
botType: "3",
|
|
54
|
+
},
|
|
55
|
+
agent: {
|
|
56
|
+
preset: undefined,
|
|
57
|
+
command: "",
|
|
58
|
+
args: [],
|
|
59
|
+
cwd: process.cwd(),
|
|
60
|
+
},
|
|
61
|
+
agents: { ...BUILT_IN_AGENTS },
|
|
62
|
+
session: {
|
|
63
|
+
idleTimeoutMs: 30 * 60_000, // 30 minutes
|
|
64
|
+
maxConcurrentUsers: 10,
|
|
65
|
+
},
|
|
66
|
+
daemon: {
|
|
67
|
+
enabled: false,
|
|
68
|
+
logFile: path.join(storageDir, "wechat-acp.log"),
|
|
69
|
+
pidFile: path.join(storageDir, "daemon.pid"),
|
|
70
|
+
},
|
|
71
|
+
storage: {
|
|
72
|
+
dir: storageDir,
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Parse agent string like "claude code" or "npx tsx ./agent.ts"
|
|
78
|
+
* into { command, args }.
|
|
79
|
+
*/
|
|
80
|
+
export function parseAgentCommand(agentStr) {
|
|
81
|
+
const parts = agentStr.trim().split(/\s+/);
|
|
82
|
+
if (parts.length === 0 || !parts[0]) {
|
|
83
|
+
throw new Error("Agent command cannot be empty");
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
command: parts[0],
|
|
87
|
+
args: parts.slice(1),
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
export function resolveAgentSelection(agentSelection, registry = BUILT_IN_AGENTS) {
|
|
91
|
+
const preset = registry[agentSelection];
|
|
92
|
+
if (preset) {
|
|
93
|
+
return {
|
|
94
|
+
id: agentSelection,
|
|
95
|
+
label: preset.label,
|
|
96
|
+
command: preset.command,
|
|
97
|
+
args: [...preset.args],
|
|
98
|
+
env: preset.env ? { ...preset.env } : undefined,
|
|
99
|
+
source: "preset",
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
const parsed = parseAgentCommand(agentSelection);
|
|
103
|
+
return {
|
|
104
|
+
command: parsed.command,
|
|
105
|
+
args: parsed.args,
|
|
106
|
+
source: "raw",
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
export function listBuiltInAgents(registry = BUILT_IN_AGENTS) {
|
|
110
|
+
return Object.entries(registry)
|
|
111
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
112
|
+
.map(([id, preset]) => ({ id, preset }));
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* wechat-acp — public API
|
|
3
|
+
*/
|
|
4
|
+
export { WeChatAcpBridge } from "./bridge.js";
|
|
5
|
+
export type { AgentCommandConfig, AgentPreset, ResolvedAgentConfig, WeChatAcpConfig, } from "./config.js";
|
|
6
|
+
export { BUILT_IN_AGENTS, defaultConfig, listBuiltInAgents, parseAgentCommand, resolveAgentSelection, } from "./config.js";
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,YAAY,EACX,kBAAkB,EAClB,WAAW,EACX,mBAAmB,EACnB,eAAe,GACf,MAAM,aAAa,CAAC;AACrB,OAAO,EACN,eAAe,EACf,aAAa,EACb,iBAAiB,EACjB,iBAAiB,EACjB,qBAAqB,GACrB,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAO9C,OAAO,EACN,eAAe,EACf,aAAa,EACb,iBAAiB,EACjB,iBAAiB,EACjB,qBAAqB,GACrB,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WeChat iLink HTTP API client.
|
|
3
|
+
* Adapted from @tencent-weixin/openclaw-weixin api/api.ts
|
|
4
|
+
*/
|
|
5
|
+
import type { GetUpdatesResp, SendMessageReq, GetUploadUrlReq, GetUploadUrlResp, SendTypingReq, GetConfigResp } from "./types.js";
|
|
6
|
+
export declare function getUpdates(params: {
|
|
7
|
+
baseUrl: string;
|
|
8
|
+
token?: string;
|
|
9
|
+
get_updates_buf: string;
|
|
10
|
+
timeoutMs?: number;
|
|
11
|
+
}): Promise<GetUpdatesResp>;
|
|
12
|
+
export declare function sendMessage(params: {
|
|
13
|
+
baseUrl: string;
|
|
14
|
+
token?: string;
|
|
15
|
+
body: SendMessageReq;
|
|
16
|
+
}): Promise<void>;
|
|
17
|
+
export declare function getUploadUrl(params: {
|
|
18
|
+
baseUrl: string;
|
|
19
|
+
token?: string;
|
|
20
|
+
body: GetUploadUrlReq;
|
|
21
|
+
}): Promise<GetUploadUrlResp>;
|
|
22
|
+
export declare function getConfig(params: {
|
|
23
|
+
baseUrl: string;
|
|
24
|
+
token?: string;
|
|
25
|
+
ilinkUserId: string;
|
|
26
|
+
contextToken?: string;
|
|
27
|
+
}): Promise<GetConfigResp>;
|
|
28
|
+
export declare function sendTyping(params: {
|
|
29
|
+
baseUrl: string;
|
|
30
|
+
token?: string;
|
|
31
|
+
body: SendTypingReq;
|
|
32
|
+
}): Promise<void>;
|
|
33
|
+
export declare function getBotQrcode(params: {
|
|
34
|
+
baseUrl: string;
|
|
35
|
+
botType?: string;
|
|
36
|
+
}): Promise<{
|
|
37
|
+
qrcode: string;
|
|
38
|
+
qrcode_img_content: string;
|
|
39
|
+
}>;
|
|
40
|
+
export declare function getQrcodeStatus(params: {
|
|
41
|
+
baseUrl: string;
|
|
42
|
+
qrcode: string;
|
|
43
|
+
}): Promise<{
|
|
44
|
+
status: string;
|
|
45
|
+
bot_token?: string;
|
|
46
|
+
baseurl?: string;
|
|
47
|
+
ilink_bot_id?: string;
|
|
48
|
+
ilink_user_id?: string;
|
|
49
|
+
}>;
|
|
50
|
+
//# sourceMappingURL=api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../../src/weixin/api.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAEV,cAAc,EACd,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,aAAa,EACb,aAAa,EACd,MAAM,YAAY,CAAC;AAmEpB,wBAAsB,UAAU,CAAC,MAAM,EAAE;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC,cAAc,CAAC,CAQ1B;AAED,wBAAsB,WAAW,CAAC,MAAM,EAAE;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,cAAc,CAAC;CACtB,GAAG,OAAO,CAAC,IAAI,CAAC,CAEhB;AAED,wBAAsB,YAAY,CAAC,MAAM,EAAE;IACzC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,eAAe,CAAC;CACvB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAO5B;AAED,wBAAsB,SAAS,CAAC,MAAM,EAAE;IACtC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,GAAG,OAAO,CAAC,aAAa,CAAC,CAWzB;AAED,wBAAsB,UAAU,CAAC,MAAM,EAAE;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,aAAa,CAAC;CACrB,GAAG,OAAO,CAAC,IAAI,CAAC,CAQhB;AAED,wBAAsB,YAAY,CAAC,MAAM,EAAE;IACzC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,kBAAkB,EAAE,MAAM,CAAA;CAAE,CAAC,CAK1D;AAED,wBAAsB,eAAe,CAAC,MAAM,EAAE;IAC5C,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC;IACV,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC,CAKD"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WeChat iLink HTTP API client.
|
|
3
|
+
* Adapted from @tencent-weixin/openclaw-weixin api/api.ts
|
|
4
|
+
*/
|
|
5
|
+
import crypto from "node:crypto";
|
|
6
|
+
const CHANNEL_VERSION = "1.0.2";
|
|
7
|
+
function randomWechatUin() {
|
|
8
|
+
const uint32 = crypto.randomBytes(4).readUInt32BE(0);
|
|
9
|
+
return Buffer.from(String(uint32), "utf-8").toString("base64");
|
|
10
|
+
}
|
|
11
|
+
function buildHeaders(token) {
|
|
12
|
+
const headers = {
|
|
13
|
+
"Content-Type": "application/json",
|
|
14
|
+
AuthorizationType: "ilink_bot_token",
|
|
15
|
+
"X-WECHAT-UIN": randomWechatUin(),
|
|
16
|
+
};
|
|
17
|
+
if (token) {
|
|
18
|
+
headers["Authorization"] = `Bearer ${token}`;
|
|
19
|
+
}
|
|
20
|
+
return headers;
|
|
21
|
+
}
|
|
22
|
+
function buildBaseInfo() {
|
|
23
|
+
return { channel_version: CHANNEL_VERSION };
|
|
24
|
+
}
|
|
25
|
+
async function apiGet(baseUrl, path, token) {
|
|
26
|
+
const url = `${baseUrl.replace(/\/$/, "")}/${path}`;
|
|
27
|
+
const res = await fetch(url, { headers: buildHeaders(token) });
|
|
28
|
+
const text = await res.text();
|
|
29
|
+
if (!res.ok)
|
|
30
|
+
throw new Error(`HTTP ${res.status}: ${text}`);
|
|
31
|
+
return JSON.parse(text);
|
|
32
|
+
}
|
|
33
|
+
async function apiPost(baseUrl, endpoint, body, token, timeoutMs = 15_000) {
|
|
34
|
+
const url = `${baseUrl.replace(/\/$/, "")}/${endpoint}`;
|
|
35
|
+
const payload = { ...body, base_info: buildBaseInfo() };
|
|
36
|
+
const bodyStr = JSON.stringify(payload);
|
|
37
|
+
const controller = new AbortController();
|
|
38
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
39
|
+
try {
|
|
40
|
+
const res = await fetch(url, {
|
|
41
|
+
method: "POST",
|
|
42
|
+
headers: buildHeaders(token),
|
|
43
|
+
body: bodyStr,
|
|
44
|
+
signal: controller.signal,
|
|
45
|
+
});
|
|
46
|
+
clearTimeout(timer);
|
|
47
|
+
const text = await res.text();
|
|
48
|
+
if (!res.ok)
|
|
49
|
+
throw new Error(`HTTP ${res.status}: ${text}`);
|
|
50
|
+
return JSON.parse(text);
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
clearTimeout(timer);
|
|
54
|
+
if (err.name === "AbortError") {
|
|
55
|
+
return { ret: 0, msgs: [] };
|
|
56
|
+
}
|
|
57
|
+
throw err;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
export async function getUpdates(params) {
|
|
61
|
+
return apiPost(params.baseUrl, "ilink/bot/getupdates", { get_updates_buf: params.get_updates_buf }, params.token, params.timeoutMs ?? 38_000);
|
|
62
|
+
}
|
|
63
|
+
export async function sendMessage(params) {
|
|
64
|
+
await apiPost(params.baseUrl, "ilink/bot/sendmessage", params.body, params.token);
|
|
65
|
+
}
|
|
66
|
+
export async function getUploadUrl(params) {
|
|
67
|
+
return apiPost(params.baseUrl, "ilink/bot/getuploadurl", params.body, params.token);
|
|
68
|
+
}
|
|
69
|
+
export async function getConfig(params) {
|
|
70
|
+
return apiPost(params.baseUrl, "ilink/bot/getconfig", {
|
|
71
|
+
ilink_user_id: params.ilinkUserId,
|
|
72
|
+
...(params.contextToken ? { context_token: params.contextToken } : {}),
|
|
73
|
+
}, params.token, 10_000);
|
|
74
|
+
}
|
|
75
|
+
export async function sendTyping(params) {
|
|
76
|
+
await apiPost(params.baseUrl, "ilink/bot/sendtyping", params.body, params.token, 10_000);
|
|
77
|
+
}
|
|
78
|
+
export async function getBotQrcode(params) {
|
|
79
|
+
return apiGet(params.baseUrl, `ilink/bot/get_bot_qrcode?bot_type=${params.botType ?? "3"}`);
|
|
80
|
+
}
|
|
81
|
+
export async function getQrcodeStatus(params) {
|
|
82
|
+
return apiGet(params.baseUrl, `ilink/bot/get_qrcode_status?qrcode=${encodeURIComponent(params.qrcode)}`);
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../../src/weixin/api.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WeChat QR login flow + token persistence.
|
|
3
|
+
*/
|
|
4
|
+
export interface TokenData {
|
|
5
|
+
token: string;
|
|
6
|
+
baseUrl: string;
|
|
7
|
+
accountId: string;
|
|
8
|
+
userId: string;
|
|
9
|
+
savedAt: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function loadToken(storageDir: string): TokenData | null;
|
|
12
|
+
export declare function saveToken(storageDir: string, data: TokenData): void;
|
|
13
|
+
export declare function login(params: {
|
|
14
|
+
baseUrl: string;
|
|
15
|
+
botType?: string;
|
|
16
|
+
storageDir: string;
|
|
17
|
+
log: (msg: string) => void;
|
|
18
|
+
renderQrUrl?: (url: string) => void;
|
|
19
|
+
}): Promise<TokenData>;
|
|
20
|
+
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../src/weixin/auth.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAMD,wBAAgB,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAQ9D;AAED,wBAAgB,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,GAAG,IAAI,CAInE;AAED,wBAAsB,KAAK,CAAC,MAAM,EAAE;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3B,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CACrC,GAAG,OAAO,CAAC,SAAS,CAAC,CA+DrB"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WeChat QR login flow + token persistence.
|
|
3
|
+
*/
|
|
4
|
+
import fs from "node:fs";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import { getBotQrcode, getQrcodeStatus } from "./api.js";
|
|
7
|
+
function getTokenPath(storageDir) {
|
|
8
|
+
return path.join(storageDir, "token.json");
|
|
9
|
+
}
|
|
10
|
+
export function loadToken(storageDir) {
|
|
11
|
+
const tokenPath = getTokenPath(storageDir);
|
|
12
|
+
if (!fs.existsSync(tokenPath))
|
|
13
|
+
return null;
|
|
14
|
+
try {
|
|
15
|
+
return JSON.parse(fs.readFileSync(tokenPath, "utf-8"));
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export function saveToken(storageDir, data) {
|
|
22
|
+
fs.mkdirSync(storageDir, { recursive: true });
|
|
23
|
+
const tokenPath = getTokenPath(storageDir);
|
|
24
|
+
fs.writeFileSync(tokenPath, JSON.stringify(data, null, 2), "utf-8");
|
|
25
|
+
}
|
|
26
|
+
export async function login(params) {
|
|
27
|
+
const { baseUrl, botType, storageDir, log, renderQrUrl } = params;
|
|
28
|
+
log("Starting WeChat QR login...");
|
|
29
|
+
const qrResp = await getBotQrcode({ baseUrl, botType });
|
|
30
|
+
const qrcodeUrl = qrResp.qrcode_img_content;
|
|
31
|
+
log("Please scan the QR code with WeChat:");
|
|
32
|
+
if (renderQrUrl) {
|
|
33
|
+
renderQrUrl(qrcodeUrl);
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
log(`QR URL: ${qrcodeUrl}`);
|
|
37
|
+
}
|
|
38
|
+
const deadline = Date.now() + 5 * 60_000;
|
|
39
|
+
let currentQrcode = qrResp.qrcode;
|
|
40
|
+
let refreshCount = 0;
|
|
41
|
+
while (Date.now() < deadline) {
|
|
42
|
+
const statusResp = await getQrcodeStatus({ baseUrl, qrcode: currentQrcode });
|
|
43
|
+
switch (statusResp.status) {
|
|
44
|
+
case "wait":
|
|
45
|
+
break;
|
|
46
|
+
case "scaned":
|
|
47
|
+
log("QR scanned, please confirm in WeChat...");
|
|
48
|
+
break;
|
|
49
|
+
case "expired": {
|
|
50
|
+
refreshCount++;
|
|
51
|
+
if (refreshCount > 3) {
|
|
52
|
+
throw new Error("QR code expired multiple times, please retry");
|
|
53
|
+
}
|
|
54
|
+
log(`QR expired, refreshing (${refreshCount}/3)...`);
|
|
55
|
+
const newQr = await getBotQrcode({ baseUrl, botType });
|
|
56
|
+
currentQrcode = newQr.qrcode;
|
|
57
|
+
if (renderQrUrl) {
|
|
58
|
+
renderQrUrl(newQr.qrcode_img_content);
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
log(`New QR URL: ${newQr.qrcode_img_content}`);
|
|
62
|
+
}
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
case "confirmed": {
|
|
66
|
+
log("Login successful!");
|
|
67
|
+
const tokenData = {
|
|
68
|
+
token: statusResp.bot_token,
|
|
69
|
+
baseUrl: statusResp.baseurl || baseUrl,
|
|
70
|
+
accountId: statusResp.ilink_bot_id,
|
|
71
|
+
userId: statusResp.ilink_user_id,
|
|
72
|
+
savedAt: new Date().toISOString(),
|
|
73
|
+
};
|
|
74
|
+
saveToken(storageDir, tokenData);
|
|
75
|
+
log(`Bot ID: ${tokenData.accountId}`);
|
|
76
|
+
log(`Token saved to ${getTokenPath(storageDir)}`);
|
|
77
|
+
return tokenData;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
await new Promise((r) => setTimeout(r, 1500));
|
|
81
|
+
}
|
|
82
|
+
throw new Error("Login timeout (5 minutes)");
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=auth.js.map
|