wx-bot-cli 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/README.en.md +175 -0
- package/README.md +177 -0
- package/dist/api.d.ts +27 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +100 -0
- package/dist/api.js.map +1 -0
- package/dist/auth.d.ts +6 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +95 -0
- package/dist/auth.js.map +1 -0
- package/dist/bin.d.ts +3 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +186 -0
- package/dist/bin.js.map +1 -0
- package/dist/daemon.d.ts +6 -0
- package/dist/daemon.d.ts.map +1 -0
- package/dist/daemon.js +108 -0
- package/dist/daemon.js.map +1 -0
- package/dist/db.d.ts +10 -0
- package/dist/db.d.ts.map +1 -0
- package/dist/db.js +35 -0
- package/dist/db.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/ipc.d.ts +5 -0
- package/dist/ipc.d.ts.map +1 -0
- package/dist/ipc.js +68 -0
- package/dist/ipc.js.map +1 -0
- package/dist/paths.d.ts +7 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +9 -0
- package/dist/paths.js.map +1 -0
- package/dist/service.d.ts +18 -0
- package/dist/service.d.ts.map +1 -0
- package/dist/service.js +207 -0
- package/dist/service.js.map +1 -0
- package/dist/tui.d.ts +6 -0
- package/dist/tui.d.ts.map +1 -0
- package/dist/tui.js +87 -0
- package/dist/tui.js.map +1 -0
- package/dist/types.d.ts +54 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/package.json +33 -0
package/README.en.md
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# wxbot — WeChat AI Bot CLI
|
|
2
|
+
|
|
3
|
+
A command-line bot tool for the WeChat iLink API. Features QR-code login, message sending and receiving, SQLite-backed message history, and an Ink terminal dashboard (TUI).
|
|
4
|
+
|
|
5
|
+
The background daemon is managed by **launchd** (macOS) or **systemd** (Linux) — auto-start on boot, auto-restart on crash.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- **QR-code login** — renders a QR code in the terminal; scan with WeChat to authorize
|
|
12
|
+
- **System service** — auto-registers as a launchd / systemd user service, no manual process management needed
|
|
13
|
+
- **Long-polling** — daemon continuously fetches new messages and writes them to SQLite (WAL mode)
|
|
14
|
+
- **Session quota** — up to 10 replies per context token; an automatic notice is sent on the 9th reply
|
|
15
|
+
- **Unix Socket IPC** — CLI and daemon communicate over a local socket with minimal latency
|
|
16
|
+
- **Ink TUI dashboard** — live message feed and service status, refreshed every 2 seconds
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Requirements
|
|
21
|
+
|
|
22
|
+
- Node.js >= 22
|
|
23
|
+
- macOS (launchd) or Linux (systemd)
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Installation
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npm install -g wx-bot-cli
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Or build from source:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
git clone https://github.com/yourname/wx-bot-cli.git
|
|
37
|
+
cd wx-bot-cli
|
|
38
|
+
npm install
|
|
39
|
+
npm run build
|
|
40
|
+
npm link
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Quick Start
|
|
46
|
+
|
|
47
|
+
**1. Log in**
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
wxbot login
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
A QR code is rendered in the terminal. Scan it with WeChat and confirm. Once authorized, the background service is installed and started automatically.
|
|
54
|
+
|
|
55
|
+
**2. Open the dashboard**
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
wxbot
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Shows the live message feed, active user, and service status.
|
|
62
|
+
|
|
63
|
+
**3. Send a message**
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
wxbot send "Hello! How can I help you?"
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Sends to the currently active user (the most recent person who messaged the bot).
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Command Reference
|
|
74
|
+
|
|
75
|
+
| Command | Description |
|
|
76
|
+
|---|---|
|
|
77
|
+
| `wxbot` | Open the TUI dashboard (default) |
|
|
78
|
+
| `wxbot login` | QR-code login; install and start system service |
|
|
79
|
+
| `wxbot logout` | Stop service and clear session (message history preserved) |
|
|
80
|
+
| `wxbot send <text>` | Send a message to the active user |
|
|
81
|
+
| `wxbot list [-n <count>]` | Show recent messages (default: 20) |
|
|
82
|
+
| `wxbot status` | Show service running status |
|
|
83
|
+
|
|
84
|
+
### wxbot list
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
wxbot list # last 20 messages
|
|
88
|
+
wxbot list -n 50 # last 50 messages
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### wxbot status — example output
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
● Service running
|
|
95
|
+
PID: 12345
|
|
96
|
+
Account: bot_abc123
|
|
97
|
+
Last poll: 2026-03-22T10:00:00.000Z
|
|
98
|
+
Active user: user_xyz
|
|
99
|
+
Total msgs: 128
|
|
100
|
+
Uptime: 15m30s
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## Session Quota
|
|
106
|
+
|
|
107
|
+
Each user message carries a `context_token` representing an independent conversation. Each conversation allows up to **10 bot replies**:
|
|
108
|
+
|
|
109
|
+
- After the 9th reply, the bot automatically sends a notice asking the user to reply to start a new conversation
|
|
110
|
+
- Once the quota is exhausted, the bot waits for the user's next message to reset
|
|
111
|
+
- `wxbot send` shows a warning when 3 or fewer replies remain
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## Data Files
|
|
116
|
+
|
|
117
|
+
All runtime files are stored under `~/.wxbot/`:
|
|
118
|
+
|
|
119
|
+
| Path | Purpose |
|
|
120
|
+
|---|---|
|
|
121
|
+
| `~/.wxbot/session.json` | Login session (chmod 600) |
|
|
122
|
+
| `~/.wxbot/messages.db` | Message database (SQLite WAL) |
|
|
123
|
+
| `~/.wxbot/wxbot.sock` | IPC Unix socket |
|
|
124
|
+
| `~/.wxbot/service.pid` | Daemon PID |
|
|
125
|
+
| `~/.wxbot/service-YYYY-MM-DD.log` | Daily service log |
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## Architecture
|
|
130
|
+
|
|
131
|
+
```
|
|
132
|
+
wxbot (CLI / TUI)
|
|
133
|
+
│
|
|
134
|
+
│ Unix Socket IPC (newline-delimited JSON)
|
|
135
|
+
│
|
|
136
|
+
wxbot _daemon (Daemon)
|
|
137
|
+
├── Long-polls ilink/bot/getupdates
|
|
138
|
+
├── Writes messages to SQLite (~/.wxbot/messages.db)
|
|
139
|
+
└── Tracks session state ServiceState (in-memory)
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Key Modules
|
|
143
|
+
|
|
144
|
+
| File | Responsibility |
|
|
145
|
+
|---|---|
|
|
146
|
+
| `bin.ts` | CLI entry point, Commander routing |
|
|
147
|
+
| `tui.tsx` | Ink TUI dashboard (React) |
|
|
148
|
+
| `service.ts` | Daemon main loop + IPC handler |
|
|
149
|
+
| `auth.ts` | QR-code login flow |
|
|
150
|
+
| `daemon.ts` | launchd plist / systemd unit generation |
|
|
151
|
+
| `ipc.ts` | Unix socket server + client |
|
|
152
|
+
| `api.ts` | iLink API HTTP wrappers |
|
|
153
|
+
| `db.ts` | SQLite operations (better-sqlite3) |
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## Development
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
npm run build # compile TypeScript to dist/
|
|
161
|
+
npm run typecheck # type-check without emitting files
|
|
162
|
+
npm test # run Vitest tests with coverage
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Run a single test file:
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
npx vitest run src/auth.test.ts
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## License
|
|
174
|
+
|
|
175
|
+
[MIT](LICENSE)
|
package/README.md
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# wxbot — 微信 AI Bot CLI
|
|
2
|
+
|
|
3
|
+
[English](README.en.md)
|
|
4
|
+
|
|
5
|
+
基于微信 iLink API 的命令行 Bot 工具,提供扫码登录、消息收发、SQLite 持久化存储,以及 Ink 终端看板(TUI)。
|
|
6
|
+
|
|
7
|
+
后台守护进程由 **launchd**(macOS)或 **systemd**(Linux)托管,开机自启、崩溃自恢复。
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## 功能特性
|
|
12
|
+
|
|
13
|
+
- **扫码登录** — 终端内渲染二维码,用微信扫描即可完成授权
|
|
14
|
+
- **系统服务** — 自动注册为 launchd / systemd 用户服务,无需手动守护
|
|
15
|
+
- **长轮询收消息** — 后台持续拉取新消息,写入 SQLite(WAL 模式)
|
|
16
|
+
- **会话额度管理** — 每个 context token 最多发送 10 条消息,第 9 条时自动发送提醒
|
|
17
|
+
- **Unix Socket IPC** — CLI 与 Daemon 通过本地 socket 通信,延迟极低
|
|
18
|
+
- **Ink TUI 看板** — 实时展示消息流与服务状态,每 2 秒刷新
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## 环境要求
|
|
23
|
+
|
|
24
|
+
- Node.js >= 22
|
|
25
|
+
- macOS(launchd)或 Linux(systemd)
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## 安装
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npm install -g wx-bot-cli
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
或从源码构建:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
git clone https://github.com/yourname/wx-bot-cli.git
|
|
39
|
+
cd wx-bot-cli
|
|
40
|
+
npm install
|
|
41
|
+
npm run build
|
|
42
|
+
npm link
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## 快速开始
|
|
48
|
+
|
|
49
|
+
**1. 登录**
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
wxbot login
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
终端会显示二维码,用微信扫码并确认授权。登录成功后,后台服务自动安装并启动。
|
|
56
|
+
|
|
57
|
+
**2. 打开看板**
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
wxbot
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
实时展示收到的消息、当前活跃用户及服务状态。
|
|
64
|
+
|
|
65
|
+
**3. 发送消息**
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
wxbot send "你好,有什么可以帮你?"
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
消息发送给当前活跃用户(最近一个给 Bot 发过消息的人)。
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## 命令参考
|
|
76
|
+
|
|
77
|
+
| 命令 | 说明 |
|
|
78
|
+
|---|---|
|
|
79
|
+
| `wxbot` | 打开 TUI 看板(默认行为) |
|
|
80
|
+
| `wxbot login` | 扫码登录,安装并启动系统服务 |
|
|
81
|
+
| `wxbot logout` | 停止服务,清除会话(消息记录保留) |
|
|
82
|
+
| `wxbot send <text>` | 向当前活跃用户发送消息 |
|
|
83
|
+
| `wxbot list [-n <数量>]` | 查看最近消息,默认显示 20 条 |
|
|
84
|
+
| `wxbot status` | 查看服务运行状态 |
|
|
85
|
+
|
|
86
|
+
### wxbot list
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
wxbot list # 最近 20 条
|
|
90
|
+
wxbot list -n 50 # 最近 50 条
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### wxbot status 输出示例
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
● 服务运行中
|
|
97
|
+
PID: 12345
|
|
98
|
+
账号: bot_abc123
|
|
99
|
+
上次轮询: 2026-03-22T10:00:00.000Z
|
|
100
|
+
活跃用户: user_xyz
|
|
101
|
+
消息总数: 128
|
|
102
|
+
运行时长: 15m30s
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## 会话额度机制
|
|
108
|
+
|
|
109
|
+
每当用户发送一条消息时,会产生一个新的 `context_token`,对应一个独立会话。每个会话最多可回复 **10 条消息**:
|
|
110
|
+
|
|
111
|
+
- 第 9 条发送完毕后,Bot 自动向用户发送一条提醒("请回复以开启新会话")
|
|
112
|
+
- 第 10 条额度耗尽后,需等待用户回复才能继续
|
|
113
|
+
- `wxbot send` 会在剩余额度 <= 3 时显示警告
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## 数据文件
|
|
118
|
+
|
|
119
|
+
所有运行时文件存放在 `~/.wxbot/`:
|
|
120
|
+
|
|
121
|
+
| 路径 | 用途 |
|
|
122
|
+
|---|---|
|
|
123
|
+
| `~/.wxbot/session.json` | 登录会话(chmod 600) |
|
|
124
|
+
| `~/.wxbot/messages.db` | 消息数据库(SQLite WAL) |
|
|
125
|
+
| `~/.wxbot/wxbot.sock` | IPC Unix Socket |
|
|
126
|
+
| `~/.wxbot/service.pid` | 守护进程 PID |
|
|
127
|
+
| `~/.wxbot/service-YYYY-MM-DD.log` | 当日运行日志 |
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## 架构
|
|
132
|
+
|
|
133
|
+
```
|
|
134
|
+
wxbot (CLI/TUI)
|
|
135
|
+
│
|
|
136
|
+
│ Unix Socket IPC (JSON-over-newline)
|
|
137
|
+
│
|
|
138
|
+
wxbot _daemon (Daemon)
|
|
139
|
+
├── 长轮询 ilink/bot/getupdates
|
|
140
|
+
├── 消息写入 SQLite (~/.wxbot/messages.db)
|
|
141
|
+
└── 会话状态 ServiceState (内存)
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### 核心模块
|
|
145
|
+
|
|
146
|
+
| 文件 | 职责 |
|
|
147
|
+
|---|---|
|
|
148
|
+
| `bin.ts` | CLI 入口,Commander 路由 |
|
|
149
|
+
| `tui.tsx` | Ink TUI 看板,React 组件 |
|
|
150
|
+
| `service.ts` | Daemon 主循环 + IPC 处理 |
|
|
151
|
+
| `auth.ts` | 扫码登录流程 |
|
|
152
|
+
| `daemon.ts` | launchd plist / systemd unit 生成与管理 |
|
|
153
|
+
| `ipc.ts` | Unix Socket 服务端 + 客户端 |
|
|
154
|
+
| `api.ts` | iLink API HTTP 封装 |
|
|
155
|
+
| `db.ts` | SQLite 操作(better-sqlite3) |
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## 开发
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
npm run build # TypeScript 编译到 dist/
|
|
163
|
+
npm run typecheck # 仅类型检查,不输出文件
|
|
164
|
+
npm test # Vitest 测试 + 覆盖率报告
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
单独运行某个测试文件:
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
npx vitest run src/auth.test.ts
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## 许可证
|
|
176
|
+
|
|
177
|
+
[MIT](LICENSE)
|
package/dist/api.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export declare const DEFAULT_BASE_URL = "https://ilinkai.weixin.qq.com";
|
|
2
|
+
export declare const BOT_TYPE = "3";
|
|
3
|
+
export declare const LONG_POLL_TIMEOUT_MS = 35000;
|
|
4
|
+
export declare const API_TIMEOUT_MS = 15000;
|
|
5
|
+
export declare function buildHeaders(token?: string): Record<string, string>;
|
|
6
|
+
export declare function apiPost(params: {
|
|
7
|
+
baseUrl: string;
|
|
8
|
+
endpoint: string;
|
|
9
|
+
body: unknown;
|
|
10
|
+
token?: string;
|
|
11
|
+
timeoutMs: number;
|
|
12
|
+
}): Promise<unknown>;
|
|
13
|
+
export declare function apiGet(params: {
|
|
14
|
+
baseUrl: string;
|
|
15
|
+
endpoint: string;
|
|
16
|
+
token?: string;
|
|
17
|
+
extraHeaders?: Record<string, string>;
|
|
18
|
+
timeoutMs: number;
|
|
19
|
+
}): Promise<unknown>;
|
|
20
|
+
export declare function sendTextMessage(params: {
|
|
21
|
+
baseUrl: string;
|
|
22
|
+
token: string;
|
|
23
|
+
toUserId: string;
|
|
24
|
+
text: string;
|
|
25
|
+
contextToken: string;
|
|
26
|
+
}): Promise<void>;
|
|
27
|
+
//# sourceMappingURL=api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,gBAAgB,kCAAkC,CAAC;AAChE,eAAO,MAAM,QAAQ,MAAM,CAAC;AAC5B,eAAO,MAAM,oBAAoB,QAAS,CAAC;AAC3C,eAAO,MAAM,cAAc,QAAS,CAAC;AAOrC,wBAAgB,YAAY,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAQnE;AAaD,wBAAsB,OAAO,CAAC,MAAM,EAAE;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG,OAAO,CAAC,OAAO,CAAC,CAoBnB;AAED,wBAAsB,MAAM,CAAC,MAAM,EAAE;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG,OAAO,CAAC,OAAO,CAAC,CAoBnB;AAED,wBAAsB,eAAe,CAAC,MAAM,EAAE;IAC5C,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;CACtB,GAAG,OAAO,CAAC,IAAI,CAAC,CAoBhB"}
|
package/dist/api.js
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import crypto from 'node:crypto';
|
|
2
|
+
export const DEFAULT_BASE_URL = 'https://ilinkai.weixin.qq.com';
|
|
3
|
+
export const BOT_TYPE = '3';
|
|
4
|
+
export const LONG_POLL_TIMEOUT_MS = 35_000;
|
|
5
|
+
export const API_TIMEOUT_MS = 15_000;
|
|
6
|
+
function randomWechatUin() {
|
|
7
|
+
const uint32 = crypto.randomBytes(4).readUInt32BE(0);
|
|
8
|
+
return Buffer.from(String(uint32), 'utf-8').toString('base64');
|
|
9
|
+
}
|
|
10
|
+
export function buildHeaders(token) {
|
|
11
|
+
const h = {
|
|
12
|
+
'Content-Type': 'application/json',
|
|
13
|
+
'AuthorizationType': 'ilink_bot_token',
|
|
14
|
+
'X-WECHAT-UIN': randomWechatUin(),
|
|
15
|
+
};
|
|
16
|
+
if (token?.trim())
|
|
17
|
+
h['Authorization'] = `Bearer ${token.trim()}`;
|
|
18
|
+
return h;
|
|
19
|
+
}
|
|
20
|
+
function ensureSlash(url) {
|
|
21
|
+
return url.endsWith('/') ? url : `${url}/`;
|
|
22
|
+
}
|
|
23
|
+
function isAbortError(err) {
|
|
24
|
+
if (!(err instanceof Error))
|
|
25
|
+
return false;
|
|
26
|
+
if (err.name === 'AbortError')
|
|
27
|
+
return true;
|
|
28
|
+
const cause = err.cause;
|
|
29
|
+
return cause?.name === 'AbortError' || false;
|
|
30
|
+
}
|
|
31
|
+
export async function apiPost(params) {
|
|
32
|
+
const url = new URL(params.endpoint, ensureSlash(params.baseUrl)).toString();
|
|
33
|
+
const bodyStr = JSON.stringify(params.body);
|
|
34
|
+
const ctrl = new AbortController();
|
|
35
|
+
const t = setTimeout(() => ctrl.abort(), params.timeoutMs);
|
|
36
|
+
try {
|
|
37
|
+
const res = await fetch(url, {
|
|
38
|
+
method: 'POST',
|
|
39
|
+
headers: { ...buildHeaders(params.token), 'Content-Length': String(Buffer.byteLength(bodyStr)) },
|
|
40
|
+
body: bodyStr,
|
|
41
|
+
signal: ctrl.signal,
|
|
42
|
+
});
|
|
43
|
+
clearTimeout(t);
|
|
44
|
+
const text = await res.text();
|
|
45
|
+
if (!res.ok)
|
|
46
|
+
throw new Error(`HTTP ${res.status}: ${text}`);
|
|
47
|
+
return JSON.parse(text);
|
|
48
|
+
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
clearTimeout(t);
|
|
51
|
+
throw err;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
export async function apiGet(params) {
|
|
55
|
+
const url = new URL(params.endpoint, ensureSlash(params.baseUrl)).toString();
|
|
56
|
+
const ctrl = new AbortController();
|
|
57
|
+
const t = setTimeout(() => ctrl.abort(), params.timeoutMs);
|
|
58
|
+
try {
|
|
59
|
+
const res = await fetch(url, {
|
|
60
|
+
method: 'GET',
|
|
61
|
+
headers: { ...buildHeaders(params.token), ...(params.extraHeaders ?? {}) },
|
|
62
|
+
signal: ctrl.signal,
|
|
63
|
+
});
|
|
64
|
+
clearTimeout(t);
|
|
65
|
+
if (res.status === 204 || res.headers.get('content-length') === '0')
|
|
66
|
+
return {};
|
|
67
|
+
const text = await res.text();
|
|
68
|
+
if (!res.ok)
|
|
69
|
+
throw new Error(`HTTP ${res.status}: ${text}`);
|
|
70
|
+
return JSON.parse(text);
|
|
71
|
+
}
|
|
72
|
+
catch (err) {
|
|
73
|
+
clearTimeout(t);
|
|
74
|
+
if (isAbortError(err))
|
|
75
|
+
return { status: 'wait' };
|
|
76
|
+
throw err;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
export async function sendTextMessage(params) {
|
|
80
|
+
const clientId = `wxbot:${Date.now()}-${crypto.randomBytes(4).toString('hex')}`;
|
|
81
|
+
await apiPost({
|
|
82
|
+
baseUrl: params.baseUrl,
|
|
83
|
+
endpoint: 'ilink/bot/sendmessage',
|
|
84
|
+
body: {
|
|
85
|
+
msg: {
|
|
86
|
+
from_user_id: '',
|
|
87
|
+
to_user_id: params.toUserId,
|
|
88
|
+
client_id: clientId,
|
|
89
|
+
message_type: 2,
|
|
90
|
+
message_state: 2,
|
|
91
|
+
item_list: [{ type: 1, text_item: { text: params.text } }],
|
|
92
|
+
context_token: params.contextToken,
|
|
93
|
+
},
|
|
94
|
+
base_info: { channel_version: 'standalone' },
|
|
95
|
+
},
|
|
96
|
+
token: params.token,
|
|
97
|
+
timeoutMs: API_TIMEOUT_MS,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=api.js.map
|
package/dist/api.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
|
package/dist/auth.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Session } from './types.js';
|
|
2
|
+
export declare function loadSession(sessionPath: string): Session | null;
|
|
3
|
+
export declare function saveSession(sessionPath: string, session: Session): void;
|
|
4
|
+
export declare function clearSession(sessionPath: string): void;
|
|
5
|
+
export declare function loginWithQr(baseUrl: string): Promise<Session>;
|
|
6
|
+
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,wBAAgB,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAO/D;AAED,wBAAgB,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAIvE;AAED,wBAAgB,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAEtD;AAED,wBAAsB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAmEnE"}
|
package/dist/auth.js
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
// @ts-ignore — no type declarations for qrcode-terminal
|
|
4
|
+
import qrterm from 'qrcode-terminal';
|
|
5
|
+
import { apiGet } from './api.js';
|
|
6
|
+
export function loadSession(sessionPath) {
|
|
7
|
+
try {
|
|
8
|
+
if (!fs.existsSync(sessionPath))
|
|
9
|
+
return null;
|
|
10
|
+
return JSON.parse(fs.readFileSync(sessionPath, 'utf-8'));
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export function saveSession(sessionPath, session) {
|
|
17
|
+
fs.mkdirSync(path.dirname(sessionPath), { recursive: true });
|
|
18
|
+
fs.writeFileSync(sessionPath, JSON.stringify(session, null, 2), 'utf-8');
|
|
19
|
+
try {
|
|
20
|
+
fs.chmodSync(sessionPath, 0o600);
|
|
21
|
+
}
|
|
22
|
+
catch { /* best-effort */ }
|
|
23
|
+
}
|
|
24
|
+
export function clearSession(sessionPath) {
|
|
25
|
+
try {
|
|
26
|
+
fs.unlinkSync(sessionPath);
|
|
27
|
+
}
|
|
28
|
+
catch { /* ignore */ }
|
|
29
|
+
}
|
|
30
|
+
export async function loginWithQr(baseUrl) {
|
|
31
|
+
process.stdout.write('正在获取二维码...\n');
|
|
32
|
+
const qrResp = await apiGet({
|
|
33
|
+
baseUrl,
|
|
34
|
+
endpoint: `ilink/bot/get_bot_qrcode?bot_type=3`,
|
|
35
|
+
timeoutMs: 10_000,
|
|
36
|
+
});
|
|
37
|
+
if (!qrResp.qrcode || !qrResp.qrcode_img_content) {
|
|
38
|
+
throw new Error(`获取二维码失败: ${JSON.stringify(qrResp)}`);
|
|
39
|
+
}
|
|
40
|
+
process.stdout.write('\n请用微信扫描以下二维码:\n\n');
|
|
41
|
+
qrterm.generate(qrResp.qrcode_img_content, { small: true });
|
|
42
|
+
process.stdout.write('等待扫码确认...\n\n');
|
|
43
|
+
const deadline = Date.now() + 5 * 60_000;
|
|
44
|
+
let qrcode = qrResp.qrcode;
|
|
45
|
+
let qrcodeImg = qrResp.qrcode_img_content;
|
|
46
|
+
let refreshCount = 0;
|
|
47
|
+
while (Date.now() < deadline) {
|
|
48
|
+
const statusResp = await apiGet({
|
|
49
|
+
baseUrl,
|
|
50
|
+
endpoint: `ilink/bot/get_qrcode_status?qrcode=${encodeURIComponent(qrcode)}`,
|
|
51
|
+
extraHeaders: { 'iLink-App-ClientVersion': '1' },
|
|
52
|
+
timeoutMs: 35_000,
|
|
53
|
+
});
|
|
54
|
+
const status = statusResp.status ?? 'wait';
|
|
55
|
+
if (status === 'scaned') {
|
|
56
|
+
process.stdout.write('\r👀 已扫码,请在微信中确认... \n');
|
|
57
|
+
}
|
|
58
|
+
else if (status === 'confirmed') {
|
|
59
|
+
if (!statusResp.ilink_bot_id)
|
|
60
|
+
throw new Error('登录成功但缺少 ilink_bot_id');
|
|
61
|
+
const session = {
|
|
62
|
+
token: statusResp.bot_token ?? '',
|
|
63
|
+
baseUrl: statusResp.baseurl || baseUrl,
|
|
64
|
+
accountId: statusResp.ilink_bot_id,
|
|
65
|
+
userId: statusResp.ilink_user_id,
|
|
66
|
+
savedAt: new Date().toISOString(),
|
|
67
|
+
};
|
|
68
|
+
process.stdout.write(`\n✅ 登录成功!accountId=${session.accountId}\n`);
|
|
69
|
+
return session;
|
|
70
|
+
}
|
|
71
|
+
else if (status === 'expired') {
|
|
72
|
+
refreshCount++;
|
|
73
|
+
if (refreshCount > 3)
|
|
74
|
+
throw new Error('二维码多次过期,请重新运行');
|
|
75
|
+
process.stdout.write(`\n⏳ 二维码已过期,正在刷新... (${refreshCount}/3)\n`);
|
|
76
|
+
const newQr = await apiGet({
|
|
77
|
+
baseUrl,
|
|
78
|
+
endpoint: `ilink/bot/get_bot_qrcode?bot_type=3`,
|
|
79
|
+
timeoutMs: 10_000,
|
|
80
|
+
});
|
|
81
|
+
if (!newQr.qrcode || !newQr.qrcode_img_content)
|
|
82
|
+
throw new Error('刷新二维码失败');
|
|
83
|
+
qrcode = newQr.qrcode;
|
|
84
|
+
qrcodeImg = newQr.qrcode_img_content;
|
|
85
|
+
process.stdout.write('\n新二维码已生成,请重新扫描:\n\n');
|
|
86
|
+
qrterm.generate(qrcodeImg, { small: true });
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
process.stdout.write('.');
|
|
90
|
+
}
|
|
91
|
+
await new Promise((r) => setTimeout(r, 1000));
|
|
92
|
+
}
|
|
93
|
+
throw new Error('登录超时,请重新运行');
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=auth.js.map
|
package/dist/auth.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
|
package/dist/bin.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":""}
|