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
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Jun Han
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# WeChat ACP
|
|
2
|
+
|
|
3
|
+
Bridge WeChat direct messages to any ACP-compatible AI agent.
|
|
4
|
+
|
|
5
|
+
`wechat-acp` logs in with the WeChat iLink bot API, polls incoming 1:1 messages, forwards them to an ACP agent over stdio, and sends the agent reply back to WeChat.
|
|
6
|
+
|
|
7
|
+
<img src="./resources/screenshot.jpg" alt="wechat-acp screenshot" width="400" />
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- WeChat QR login with terminal QR rendering
|
|
12
|
+
- One ACP agent session per WeChat user
|
|
13
|
+
- Built-in ACP agent presets for common CLIs
|
|
14
|
+
- Custom raw agent command support
|
|
15
|
+
- Auto-allow permission requests from the agent
|
|
16
|
+
- Direct message only; group chats are ignored
|
|
17
|
+
- Background daemon mode
|
|
18
|
+
|
|
19
|
+
## Requirements
|
|
20
|
+
|
|
21
|
+
- Node.js 20+
|
|
22
|
+
- A WeChat environment that can use the iLink bot API
|
|
23
|
+
- An ACP-compatible agent available locally or through `npx`
|
|
24
|
+
|
|
25
|
+
## Quick Start
|
|
26
|
+
|
|
27
|
+
Start with a built-in agent preset:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npx wechat-acp --agent copilot
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Or use a raw custom command:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npx wechat-acp --agent "npx my-agent --acp"
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
On first run, the bridge will:
|
|
40
|
+
|
|
41
|
+
1. Start WeChat QR login
|
|
42
|
+
2. Render a QR code in the terminal
|
|
43
|
+
3. Save the login token under `~/.wechat-acp`
|
|
44
|
+
4. Begin polling direct messages
|
|
45
|
+
|
|
46
|
+
## Built-in Agent Presets
|
|
47
|
+
|
|
48
|
+
List the bundled presets:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
npx wechat-acp agents
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Current presets:
|
|
55
|
+
|
|
56
|
+
- `copilot`
|
|
57
|
+
- `claude`
|
|
58
|
+
- `gemini`
|
|
59
|
+
- `qwen`
|
|
60
|
+
- `codex`
|
|
61
|
+
- `opencode`
|
|
62
|
+
|
|
63
|
+
These presets resolve to concrete `command + args` pairs internally, so users do not need to type long `npx ...` commands.
|
|
64
|
+
|
|
65
|
+
## CLI Usage
|
|
66
|
+
|
|
67
|
+
```text
|
|
68
|
+
wechat-acp --agent <preset|command> [options]
|
|
69
|
+
wechat-acp agents
|
|
70
|
+
wechat-acp stop
|
|
71
|
+
wechat-acp status
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Options:
|
|
75
|
+
|
|
76
|
+
- `--agent <value>`: built-in preset name or raw agent command
|
|
77
|
+
- `--cwd <dir>`: working directory for the agent process
|
|
78
|
+
- `--login`: force QR re-login and replace the saved token
|
|
79
|
+
- `--daemon`: run in background after startup
|
|
80
|
+
- `--config <file>`: load JSON config file
|
|
81
|
+
- `--idle-timeout <minutes>`: session idle timeout, default `30`
|
|
82
|
+
- `--max-sessions <count>`: maximum concurrent user sessions, default `10`
|
|
83
|
+
- `-h, --help`: show help
|
|
84
|
+
|
|
85
|
+
Examples:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
npx wechat-acp --agent copilot
|
|
89
|
+
npx wechat-acp --agent claude --cwd D:\code\project
|
|
90
|
+
npx wechat-acp --agent "npx @github/copilot --acp"
|
|
91
|
+
npx wechat-acp --agent gemini --daemon
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Configuration File
|
|
95
|
+
|
|
96
|
+
You can provide a JSON config file with `--config`.
|
|
97
|
+
|
|
98
|
+
Example:
|
|
99
|
+
|
|
100
|
+
```json
|
|
101
|
+
{
|
|
102
|
+
"agent": {
|
|
103
|
+
"preset": "copilot",
|
|
104
|
+
"cwd": "D:/code/project"
|
|
105
|
+
},
|
|
106
|
+
"session": {
|
|
107
|
+
"idleTimeoutMs": 1800000,
|
|
108
|
+
"maxConcurrentUsers": 10
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
You can also override or add agent presets:
|
|
114
|
+
|
|
115
|
+
```json
|
|
116
|
+
{
|
|
117
|
+
"agent": {
|
|
118
|
+
"preset": "my-agent"
|
|
119
|
+
},
|
|
120
|
+
"agents": {
|
|
121
|
+
"my-agent": {
|
|
122
|
+
"label": "My Agent",
|
|
123
|
+
"description": "Internal team agent",
|
|
124
|
+
"command": "npx",
|
|
125
|
+
"args": ["my-agent-cli", "--acp"]
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Runtime Behavior
|
|
132
|
+
|
|
133
|
+
- Each WeChat user gets a dedicated ACP session and subprocess.
|
|
134
|
+
- Messages are processed serially per user.
|
|
135
|
+
- Replies are formatted for WeChat before sending.
|
|
136
|
+
- Typing indicators are sent when supported by the WeChat API.
|
|
137
|
+
- Sessions are cleaned up after inactivity.
|
|
138
|
+
|
|
139
|
+
## Storage
|
|
140
|
+
|
|
141
|
+
By default, runtime files are stored under:
|
|
142
|
+
|
|
143
|
+
```text
|
|
144
|
+
~/.wechat-acp
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
This directory is used for:
|
|
148
|
+
|
|
149
|
+
- saved login token
|
|
150
|
+
- daemon pid file
|
|
151
|
+
- daemon log file
|
|
152
|
+
- sync state
|
|
153
|
+
|
|
154
|
+
## Current Limitations
|
|
155
|
+
|
|
156
|
+
- Direct messages only; group chats are ignored
|
|
157
|
+
- MCP servers are not used
|
|
158
|
+
- Permission requests are auto-approved
|
|
159
|
+
- Agent communication is subprocess-only over stdio
|
|
160
|
+
- Some preset agents may require separate authentication before they can respond successfully
|
|
161
|
+
|
|
162
|
+
## Development
|
|
163
|
+
|
|
164
|
+
For local development:
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
npm install
|
|
168
|
+
npm run build
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Run the built CLI locally:
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
node dist/bin/wechat-acp.js --help
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Watch mode:
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
npm run dev
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## License
|
|
184
|
+
|
|
185
|
+
MIT
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* wechat-acp CLI entry point.
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* wechat-acp --agent "claude code"
|
|
7
|
+
* wechat-acp --agent "gemini" --cwd /path/to/project
|
|
8
|
+
* wechat-acp --agent "npx tsx ./agent.ts" --login
|
|
9
|
+
* wechat-acp --agent "claude code" --daemon
|
|
10
|
+
* wechat-acp stop
|
|
11
|
+
* wechat-acp status
|
|
12
|
+
*/
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=wechat-acp.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wechat-acp.d.ts","sourceRoot":"","sources":["../../bin/wechat-acp.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;GAUG"}
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* wechat-acp CLI entry point.
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* wechat-acp --agent "claude code"
|
|
7
|
+
* wechat-acp --agent "gemini" --cwd /path/to/project
|
|
8
|
+
* wechat-acp --agent "npx tsx ./agent.ts" --login
|
|
9
|
+
* wechat-acp --agent "claude code" --daemon
|
|
10
|
+
* wechat-acp stop
|
|
11
|
+
* wechat-acp status
|
|
12
|
+
*/
|
|
13
|
+
import fs from "node:fs";
|
|
14
|
+
import path from "node:path";
|
|
15
|
+
import { spawn } from "node:child_process";
|
|
16
|
+
import qrcodeTerminal from "qrcode-terminal";
|
|
17
|
+
import { WeChatAcpBridge } from "../src/bridge.js";
|
|
18
|
+
import { defaultConfig, listBuiltInAgents, resolveAgentSelection, } from "../src/config.js";
|
|
19
|
+
function usage() {
|
|
20
|
+
const presets = listBuiltInAgents()
|
|
21
|
+
.map(({ id }) => id)
|
|
22
|
+
.join(", ");
|
|
23
|
+
console.log(`
|
|
24
|
+
wechat-acp — Bridge WeChat to any ACP-compatible AI agent
|
|
25
|
+
|
|
26
|
+
Usage:
|
|
27
|
+
wechat-acp --agent <preset|command> [options]
|
|
28
|
+
wechat-acp agents List built-in agent presets
|
|
29
|
+
wechat-acp stop Stop a running daemon
|
|
30
|
+
wechat-acp status Check daemon status
|
|
31
|
+
|
|
32
|
+
Options:
|
|
33
|
+
--agent <value> Built-in preset name or raw agent command
|
|
34
|
+
Presets: ${presets}
|
|
35
|
+
Examples: "copilot", "claude", "npx tsx ./agent.ts"
|
|
36
|
+
--cwd <dir> Working directory for agent (default: current dir)
|
|
37
|
+
--login Force re-login (new QR code)
|
|
38
|
+
--daemon Run in background after login
|
|
39
|
+
--config <file> Config file path (JSON)
|
|
40
|
+
--idle-timeout <m> Session idle timeout in minutes (default: 30)
|
|
41
|
+
--max-sessions <n> Max concurrent user sessions (default: 10)
|
|
42
|
+
-v, --verbose Verbose logging
|
|
43
|
+
-h, --help Show this help
|
|
44
|
+
`);
|
|
45
|
+
}
|
|
46
|
+
function parseArgs(argv) {
|
|
47
|
+
const result = {
|
|
48
|
+
forceLogin: false,
|
|
49
|
+
daemon: false,
|
|
50
|
+
verbose: false,
|
|
51
|
+
help: false,
|
|
52
|
+
};
|
|
53
|
+
const args = argv.slice(2);
|
|
54
|
+
let i = 0;
|
|
55
|
+
// Check for subcommand
|
|
56
|
+
if (args[0] && !args[0].startsWith("-")) {
|
|
57
|
+
result.command = args[0];
|
|
58
|
+
i = 1;
|
|
59
|
+
}
|
|
60
|
+
while (i < args.length) {
|
|
61
|
+
const arg = args[i];
|
|
62
|
+
switch (arg) {
|
|
63
|
+
case "--agent":
|
|
64
|
+
result.agent = args[++i];
|
|
65
|
+
break;
|
|
66
|
+
case "--cwd":
|
|
67
|
+
result.cwd = args[++i];
|
|
68
|
+
break;
|
|
69
|
+
case "--login":
|
|
70
|
+
result.forceLogin = true;
|
|
71
|
+
break;
|
|
72
|
+
case "--daemon":
|
|
73
|
+
result.daemon = true;
|
|
74
|
+
break;
|
|
75
|
+
case "--config":
|
|
76
|
+
result.configFile = args[++i];
|
|
77
|
+
break;
|
|
78
|
+
case "--idle-timeout":
|
|
79
|
+
result.idleTimeout = parseInt(args[++i], 10);
|
|
80
|
+
break;
|
|
81
|
+
case "--max-sessions":
|
|
82
|
+
result.maxSessions = parseInt(args[++i], 10);
|
|
83
|
+
break;
|
|
84
|
+
case "-v":
|
|
85
|
+
case "--verbose":
|
|
86
|
+
result.verbose = true;
|
|
87
|
+
break;
|
|
88
|
+
case "-h":
|
|
89
|
+
case "--help":
|
|
90
|
+
result.help = true;
|
|
91
|
+
break;
|
|
92
|
+
default:
|
|
93
|
+
if (arg?.startsWith("-")) {
|
|
94
|
+
console.error(`Unknown option: ${arg}`);
|
|
95
|
+
process.exit(1);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
i++;
|
|
99
|
+
}
|
|
100
|
+
return result;
|
|
101
|
+
}
|
|
102
|
+
function loadConfigFile(filePath) {
|
|
103
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
104
|
+
return JSON.parse(content);
|
|
105
|
+
}
|
|
106
|
+
function handleAgents(config) {
|
|
107
|
+
console.log("Built-in ACP agent presets:\n");
|
|
108
|
+
for (const { id, preset } of listBuiltInAgents(config.agents)) {
|
|
109
|
+
const commandLine = [preset.command, ...preset.args].join(" ");
|
|
110
|
+
console.log(`${id.padEnd(10)} ${commandLine}`);
|
|
111
|
+
if (preset.description) {
|
|
112
|
+
console.log(` ${preset.description}`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
function handleStop(config) {
|
|
117
|
+
const pidFile = config.daemon.pidFile;
|
|
118
|
+
if (!fs.existsSync(pidFile)) {
|
|
119
|
+
console.log("No daemon running (no PID file found)");
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
const pid = parseInt(fs.readFileSync(pidFile, "utf-8").trim(), 10);
|
|
123
|
+
try {
|
|
124
|
+
process.kill(pid, "SIGTERM");
|
|
125
|
+
fs.unlinkSync(pidFile);
|
|
126
|
+
console.log(`Stopped daemon (PID ${pid})`);
|
|
127
|
+
}
|
|
128
|
+
catch (err) {
|
|
129
|
+
if (err.code === "ESRCH") {
|
|
130
|
+
fs.unlinkSync(pidFile);
|
|
131
|
+
console.log(`Daemon not running (stale PID ${pid}), cleaned up`);
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
console.error(`Failed to stop daemon: ${String(err)}`);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
function handleStatus(config) {
|
|
139
|
+
const pidFile = config.daemon.pidFile;
|
|
140
|
+
if (!fs.existsSync(pidFile)) {
|
|
141
|
+
console.log("Not running");
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
const pid = parseInt(fs.readFileSync(pidFile, "utf-8").trim(), 10);
|
|
145
|
+
try {
|
|
146
|
+
process.kill(pid, 0); // test if process exists
|
|
147
|
+
console.log(`Running (PID ${pid})`);
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
console.log(`Not running (stale PID ${pid})`);
|
|
151
|
+
fs.unlinkSync(pidFile);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
function daemonize(config) {
|
|
155
|
+
const logFile = config.daemon.logFile;
|
|
156
|
+
const pidFile = config.daemon.pidFile;
|
|
157
|
+
fs.mkdirSync(path.dirname(logFile), { recursive: true });
|
|
158
|
+
fs.mkdirSync(path.dirname(pidFile), { recursive: true });
|
|
159
|
+
const out = fs.openSync(logFile, "a");
|
|
160
|
+
const err = fs.openSync(logFile, "a");
|
|
161
|
+
// Re-run ourselves with --no-daemon (internal flag) as a detached process
|
|
162
|
+
const args = process.argv.slice(1).filter((a) => a !== "--daemon");
|
|
163
|
+
const child = spawn(process.execPath, args, {
|
|
164
|
+
detached: true,
|
|
165
|
+
stdio: ["ignore", out, err],
|
|
166
|
+
env: { ...process.env, WECHAT_ACP_DAEMON: "1" },
|
|
167
|
+
});
|
|
168
|
+
child.unref();
|
|
169
|
+
fs.writeFileSync(pidFile, String(child.pid), "utf-8");
|
|
170
|
+
console.log(`Daemon started (PID ${child.pid})`);
|
|
171
|
+
console.log(`Logs: ${logFile}`);
|
|
172
|
+
console.log(`PID file: ${pidFile}`);
|
|
173
|
+
process.exit(0);
|
|
174
|
+
}
|
|
175
|
+
function renderQrInTerminal(url) {
|
|
176
|
+
qrcodeTerminal.generate(url, { small: true }, (qr) => {
|
|
177
|
+
console.log(qr);
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
async function main() {
|
|
181
|
+
const args = parseArgs(process.argv);
|
|
182
|
+
if (args.help) {
|
|
183
|
+
usage();
|
|
184
|
+
process.exit(0);
|
|
185
|
+
}
|
|
186
|
+
const config = defaultConfig();
|
|
187
|
+
// Load config file if specified
|
|
188
|
+
if (args.configFile) {
|
|
189
|
+
const fileConfig = loadConfigFile(args.configFile);
|
|
190
|
+
Object.assign(config.wechat, fileConfig.wechat ?? {});
|
|
191
|
+
Object.assign(config.agent, fileConfig.agent ?? {});
|
|
192
|
+
Object.assign(config.agents, fileConfig.agents ?? {});
|
|
193
|
+
Object.assign(config.session, fileConfig.session ?? {});
|
|
194
|
+
Object.assign(config.daemon, fileConfig.daemon ?? {});
|
|
195
|
+
Object.assign(config.storage, fileConfig.storage ?? {});
|
|
196
|
+
}
|
|
197
|
+
// Handle subcommands
|
|
198
|
+
if (args.command === "agents") {
|
|
199
|
+
handleAgents(config);
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
if (args.command === "stop") {
|
|
203
|
+
handleStop(config);
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
if (args.command === "status") {
|
|
207
|
+
handleStatus(config);
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
const agentSelection = args.agent ?? config.agent.preset;
|
|
211
|
+
// Require preset or raw command
|
|
212
|
+
if (!agentSelection && !config.agent.command) {
|
|
213
|
+
console.error("Error: --agent is required\n");
|
|
214
|
+
usage();
|
|
215
|
+
process.exit(1);
|
|
216
|
+
}
|
|
217
|
+
if (agentSelection) {
|
|
218
|
+
const resolvedAgent = resolveAgentSelection(agentSelection, config.agents);
|
|
219
|
+
config.agent.preset = resolvedAgent.id;
|
|
220
|
+
config.agent.command = resolvedAgent.command;
|
|
221
|
+
config.agent.args = resolvedAgent.args;
|
|
222
|
+
if (resolvedAgent.env) {
|
|
223
|
+
config.agent.env = { ...(config.agent.env ?? {}), ...resolvedAgent.env };
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
if (args.cwd)
|
|
227
|
+
config.agent.cwd = path.resolve(args.cwd);
|
|
228
|
+
if (args.idleTimeout)
|
|
229
|
+
config.session.idleTimeoutMs = args.idleTimeout * 60_000;
|
|
230
|
+
if (args.maxSessions)
|
|
231
|
+
config.session.maxConcurrentUsers = args.maxSessions;
|
|
232
|
+
config.daemon.enabled = args.daemon;
|
|
233
|
+
// Handle daemon mode
|
|
234
|
+
if (args.daemon && !process.env.WECHAT_ACP_DAEMON) {
|
|
235
|
+
daemonize(config);
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
// Create and start bridge
|
|
239
|
+
const bridge = new WeChatAcpBridge(config, (msg) => {
|
|
240
|
+
const ts = new Date().toISOString().substring(11, 19);
|
|
241
|
+
console.log(`[${ts}] ${msg}`);
|
|
242
|
+
});
|
|
243
|
+
// Handle graceful shutdown
|
|
244
|
+
const shutdown = async () => {
|
|
245
|
+
await bridge.stop();
|
|
246
|
+
process.exit(0);
|
|
247
|
+
};
|
|
248
|
+
process.on("SIGINT", () => void shutdown());
|
|
249
|
+
process.on("SIGTERM", () => void shutdown());
|
|
250
|
+
try {
|
|
251
|
+
await bridge.start({
|
|
252
|
+
forceLogin: args.forceLogin,
|
|
253
|
+
renderQrUrl: renderQrInTerminal,
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
catch (err) {
|
|
257
|
+
if (err.message === "aborted") {
|
|
258
|
+
// Normal shutdown
|
|
259
|
+
}
|
|
260
|
+
else {
|
|
261
|
+
console.error(`Fatal: ${String(err)}`);
|
|
262
|
+
process.exit(1);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
main().catch((err) => {
|
|
267
|
+
console.error(`Fatal: ${String(err)}`);
|
|
268
|
+
process.exit(1);
|
|
269
|
+
});
|
|
270
|
+
//# sourceMappingURL=wechat-acp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wechat-acp.js","sourceRoot":"","sources":["../../bin/wechat-acp.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "wechat-acp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Bridge WeChat to any ACP-compatible AI agent",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"files": [
|
|
7
|
+
"dist/",
|
|
8
|
+
"README.md",
|
|
9
|
+
"package.json"
|
|
10
|
+
],
|
|
11
|
+
"bin": {
|
|
12
|
+
"wechat-acp": "./dist/bin/wechat-acp.js"
|
|
13
|
+
},
|
|
14
|
+
"main": "./dist/src/index.js",
|
|
15
|
+
"types": "./dist/src/index.d.ts",
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"import": "./dist/src/index.js",
|
|
19
|
+
"types": "./dist/src/index.d.ts"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "tsc",
|
|
24
|
+
"prepack": "npm run build",
|
|
25
|
+
"start": "node dist/bin/wechat-acp.js",
|
|
26
|
+
"dev": "tsc --watch"
|
|
27
|
+
},
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"@agentclientprotocol/sdk": "^0.16.1",
|
|
30
|
+
"qrcode-terminal": "^0.12.0"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@types/node": "^22.0.0",
|
|
34
|
+
"typescript": "^5.5.0"
|
|
35
|
+
},
|
|
36
|
+
"engines": {
|
|
37
|
+
"node": ">=20.0.0"
|
|
38
|
+
},
|
|
39
|
+
"repository": {
|
|
40
|
+
"type": "git",
|
|
41
|
+
"url": "git+https://github.com/formulahendry/wechat-acp.git"
|
|
42
|
+
},
|
|
43
|
+
"homepage": "https://github.com/formulahendry/wechat-acp#readme",
|
|
44
|
+
"bugs": {
|
|
45
|
+
"url": "https://github.com/formulahendry/wechat-acp/issues"
|
|
46
|
+
},
|
|
47
|
+
"license": "MIT",
|
|
48
|
+
"keywords": [
|
|
49
|
+
"wechat",
|
|
50
|
+
"acp",
|
|
51
|
+
"agent-client-protocol",
|
|
52
|
+
"ai-agent",
|
|
53
|
+
"bridge"
|
|
54
|
+
]
|
|
55
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Spawn and manage ACP agent subprocesses.
|
|
3
|
+
*/
|
|
4
|
+
import { type ChildProcess } from "node:child_process";
|
|
5
|
+
import * as acp from "@agentclientprotocol/sdk";
|
|
6
|
+
import type { WeChatAcpClient } from "./client.js";
|
|
7
|
+
export interface AgentProcessInfo {
|
|
8
|
+
process: ChildProcess;
|
|
9
|
+
connection: acp.ClientSideConnection;
|
|
10
|
+
sessionId: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function spawnAgent(params: {
|
|
13
|
+
command: string;
|
|
14
|
+
args: string[];
|
|
15
|
+
cwd: string;
|
|
16
|
+
env?: Record<string, string>;
|
|
17
|
+
client: WeChatAcpClient;
|
|
18
|
+
log: (msg: string) => void;
|
|
19
|
+
}): Promise<AgentProcessInfo>;
|
|
20
|
+
export declare function killAgent(proc: ChildProcess): void;
|
|
21
|
+
//# sourceMappingURL=agent-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-manager.d.ts","sourceRoot":"","sources":["../../../src/acp/agent-manager.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAS,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAE9D,OAAO,KAAK,GAAG,MAAM,0BAA0B,CAAC;AAEhD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,YAAY,CAAC;IACtB,UAAU,EAAE,GAAG,CAAC,oBAAoB,CAAC;IACrC,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wBAAsB,UAAU,CAAC,MAAM,EAAE;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,MAAM,EAAE,eAAe,CAAC;IACxB,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC5B,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAiE5B;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI,CAQlD"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Spawn and manage ACP agent subprocesses.
|
|
3
|
+
*/
|
|
4
|
+
import { spawn } from "node:child_process";
|
|
5
|
+
import { Writable, Readable } from "node:stream";
|
|
6
|
+
import * as acp from "@agentclientprotocol/sdk";
|
|
7
|
+
import packageJson from "../../package.json" with { type: "json" };
|
|
8
|
+
export async function spawnAgent(params) {
|
|
9
|
+
const { command, args, cwd, env, client, log } = params;
|
|
10
|
+
// On Windows, shell mode avoids EINVAL/ENOENT for command shims like npx/claude/gemini.
|
|
11
|
+
const useShell = process.platform === "win32";
|
|
12
|
+
log(`Spawning agent: ${command} ${args.join(" ")} (cwd: ${cwd}, shell=${useShell})`);
|
|
13
|
+
const proc = spawn(command, args, {
|
|
14
|
+
stdio: ["pipe", "pipe", "inherit"],
|
|
15
|
+
cwd,
|
|
16
|
+
env: { ...process.env, ...env },
|
|
17
|
+
shell: useShell,
|
|
18
|
+
});
|
|
19
|
+
proc.on("error", (err) => {
|
|
20
|
+
log(`Agent process error: ${String(err)}`);
|
|
21
|
+
});
|
|
22
|
+
proc.on("exit", (code, signal) => {
|
|
23
|
+
log(`Agent process exited: code=${code} signal=${signal}`);
|
|
24
|
+
});
|
|
25
|
+
if (!proc.stdin || !proc.stdout) {
|
|
26
|
+
proc.kill();
|
|
27
|
+
throw new Error("Failed to get agent process stdio");
|
|
28
|
+
}
|
|
29
|
+
const input = Writable.toWeb(proc.stdin);
|
|
30
|
+
const output = Readable.toWeb(proc.stdout);
|
|
31
|
+
const stream = acp.ndJsonStream(input, output);
|
|
32
|
+
const connection = new acp.ClientSideConnection(() => client, stream);
|
|
33
|
+
// Initialize
|
|
34
|
+
log("Initializing ACP connection...");
|
|
35
|
+
const initResult = await connection.initialize({
|
|
36
|
+
protocolVersion: acp.PROTOCOL_VERSION,
|
|
37
|
+
clientInfo: {
|
|
38
|
+
name: packageJson.name,
|
|
39
|
+
title: packageJson.name,
|
|
40
|
+
version: packageJson.version,
|
|
41
|
+
},
|
|
42
|
+
clientCapabilities: {
|
|
43
|
+
fs: {
|
|
44
|
+
readTextFile: true,
|
|
45
|
+
writeTextFile: true,
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
log(`ACP initialized (protocol v${initResult.protocolVersion})`);
|
|
50
|
+
// Create session
|
|
51
|
+
log("Creating ACP session...");
|
|
52
|
+
const sessionResult = await connection.newSession({
|
|
53
|
+
cwd,
|
|
54
|
+
mcpServers: [],
|
|
55
|
+
});
|
|
56
|
+
log(`ACP session created: ${sessionResult.sessionId}`);
|
|
57
|
+
return {
|
|
58
|
+
process: proc,
|
|
59
|
+
connection,
|
|
60
|
+
sessionId: sessionResult.sessionId,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
export function killAgent(proc) {
|
|
64
|
+
if (!proc.killed) {
|
|
65
|
+
proc.kill("SIGTERM");
|
|
66
|
+
// Force kill after 5s if still alive
|
|
67
|
+
setTimeout(() => {
|
|
68
|
+
if (!proc.killed)
|
|
69
|
+
proc.kill("SIGKILL");
|
|
70
|
+
}, 5_000).unref();
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=agent-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-manager.js","sourceRoot":"","sources":["../../../src/acp/agent-manager.ts"],"names":[],"mappings":"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"}
|