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/dist/bin.js
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import { render } from 'ink';
|
|
4
|
+
import React from 'react';
|
|
5
|
+
import { loginWithQr, saveSession, clearSession } from './auth.js';
|
|
6
|
+
import { openDb, getRecentMessages } from './db.js';
|
|
7
|
+
import { sendIpcRequest } from './ipc.js';
|
|
8
|
+
import { installService, uninstallService, isServiceRunning } from './daemon.js';
|
|
9
|
+
import { runService } from './service.js';
|
|
10
|
+
import { SESSION_PATH, DB_PATH, SOCKET_PATH, PID_PATH } from './paths.js';
|
|
11
|
+
import { DEFAULT_BASE_URL } from './api.js';
|
|
12
|
+
import { App } from './tui.js';
|
|
13
|
+
import fs from 'node:fs';
|
|
14
|
+
const IPC_TIMEOUT = 5_000;
|
|
15
|
+
const program = new Command();
|
|
16
|
+
program
|
|
17
|
+
.name('wxbot')
|
|
18
|
+
.description('wx bot cli — WeChat AI Bot dashboard')
|
|
19
|
+
.version('0.1.0');
|
|
20
|
+
// Default action: open TUI
|
|
21
|
+
program
|
|
22
|
+
.action(async () => {
|
|
23
|
+
let loginRequested = false;
|
|
24
|
+
const { waitUntilExit } = render(React.createElement(App, { onLoginRequested: () => { loginRequested = true; } }));
|
|
25
|
+
await waitUntilExit();
|
|
26
|
+
if (loginRequested) {
|
|
27
|
+
if (isServiceRunning()) {
|
|
28
|
+
console.log('正在停止已有服务...');
|
|
29
|
+
uninstallService();
|
|
30
|
+
}
|
|
31
|
+
try {
|
|
32
|
+
const session = await loginWithQr(DEFAULT_BASE_URL);
|
|
33
|
+
saveSession(SESSION_PATH, session);
|
|
34
|
+
console.log('正在安装系统服务...');
|
|
35
|
+
installService();
|
|
36
|
+
console.log('服务已启动,即将打开看板...');
|
|
37
|
+
await new Promise((r) => setTimeout(r, 1500));
|
|
38
|
+
const { waitUntilExit: waitAgain } = render(React.createElement(App));
|
|
39
|
+
await waitAgain();
|
|
40
|
+
}
|
|
41
|
+
catch (err) {
|
|
42
|
+
console.error(`登录失败: ${String(err)}`);
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
// wxbot login
|
|
48
|
+
program
|
|
49
|
+
.command('login')
|
|
50
|
+
.description('QR-code login, then install and start system service')
|
|
51
|
+
.option('--base-url <url>', 'iLink API base URL', DEFAULT_BASE_URL)
|
|
52
|
+
.action(async (opts) => {
|
|
53
|
+
// Stop existing service if running
|
|
54
|
+
if (isServiceRunning()) {
|
|
55
|
+
console.log('正在停止已有服务...');
|
|
56
|
+
uninstallService();
|
|
57
|
+
}
|
|
58
|
+
const session = await loginWithQr(opts.baseUrl);
|
|
59
|
+
saveSession(SESSION_PATH, session);
|
|
60
|
+
console.log('正在安装系统服务...');
|
|
61
|
+
installService();
|
|
62
|
+
console.log('✅ 服务已启动。运行 wxbot 打开看板。');
|
|
63
|
+
});
|
|
64
|
+
// wxbot logout
|
|
65
|
+
program
|
|
66
|
+
.command('logout')
|
|
67
|
+
.description('Stop service and clear session (preserves message history)')
|
|
68
|
+
.action(() => {
|
|
69
|
+
if (isServiceRunning()) {
|
|
70
|
+
uninstallService();
|
|
71
|
+
console.log('✅ 服务已停止。');
|
|
72
|
+
}
|
|
73
|
+
clearSession(SESSION_PATH);
|
|
74
|
+
try {
|
|
75
|
+
fs.unlinkSync(PID_PATH);
|
|
76
|
+
}
|
|
77
|
+
catch { /* ignore */ }
|
|
78
|
+
console.log('✅ 已登出(消息记录已保留)。');
|
|
79
|
+
});
|
|
80
|
+
// wxbot send
|
|
81
|
+
program
|
|
82
|
+
.command('send <text>')
|
|
83
|
+
.description('Send a message to the current active user')
|
|
84
|
+
.action(async (text) => {
|
|
85
|
+
try {
|
|
86
|
+
const resp = await sendIpcRequest(SOCKET_PATH, { type: 'send', text }, IPC_TIMEOUT);
|
|
87
|
+
if ('ok' in resp) {
|
|
88
|
+
if (resp.ok) {
|
|
89
|
+
const remaining = resp.remaining;
|
|
90
|
+
process.stdout.write('✉️ 已发送');
|
|
91
|
+
if (remaining <= 3) {
|
|
92
|
+
if (remaining === 1) {
|
|
93
|
+
process.stdout.write(` ⚠️ 消息额度还剩 1 条(已自动发送会话结束通知)`);
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
process.stdout.write(` ⚠️ 消息额度还剩 ${remaining} 条`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
process.stdout.write('\n');
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
const reasons = {
|
|
103
|
+
no_active_user: '服务未运行,请先执行 wxbot login',
|
|
104
|
+
session_exhausted: '当前会话已满,等待用户回复以开启新会话',
|
|
105
|
+
api_error: resp.message,
|
|
106
|
+
};
|
|
107
|
+
console.error(`❌ ${reasons[resp.reason] ?? resp.message}`);
|
|
108
|
+
process.exit(1);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
catch (err) {
|
|
113
|
+
const code = err.code;
|
|
114
|
+
if (code === 'ENOENT' || code === 'ECONNREFUSED') {
|
|
115
|
+
console.error('❌ 服务未运行,请先执行 wxbot login');
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
console.error('❌ 服务无响应,请检查 wxbot status');
|
|
119
|
+
}
|
|
120
|
+
process.exit(1);
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
// wxbot list
|
|
124
|
+
program
|
|
125
|
+
.command('list')
|
|
126
|
+
.description('Show recent messages')
|
|
127
|
+
.option('-n, --limit <n>', 'number of messages to show', '20')
|
|
128
|
+
.action((opts) => {
|
|
129
|
+
const db = openDb(DB_PATH, true);
|
|
130
|
+
const limit = parseInt(opts.limit, 10) || 20;
|
|
131
|
+
const rows = getRecentMessages(db, limit).reverse(); // oldest first
|
|
132
|
+
db.close();
|
|
133
|
+
if (rows.length === 0) {
|
|
134
|
+
console.log('(无消息记录)');
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
for (const row of rows) {
|
|
138
|
+
const time = new Date(row.created_at).toLocaleTimeString('zh-CN');
|
|
139
|
+
const dir = row.direction === 'in' ? `→ [${row.user_id}]` : `← [Bot] `;
|
|
140
|
+
console.log(`${time} ${dir} ${row.text}`);
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
// wxbot status
|
|
144
|
+
program
|
|
145
|
+
.command('status')
|
|
146
|
+
.description('Show service running status')
|
|
147
|
+
.action(async () => {
|
|
148
|
+
try {
|
|
149
|
+
const resp = await sendIpcRequest(SOCKET_PATH, { type: 'status' }, IPC_TIMEOUT);
|
|
150
|
+
const uptime = `${Math.floor(resp.uptime / 60)}m${resp.uptime % 60}s`;
|
|
151
|
+
console.log(`● 服务运行中`);
|
|
152
|
+
console.log(` PID: ${resp.pid}`);
|
|
153
|
+
console.log(` 账号: ${resp.accountId}`);
|
|
154
|
+
console.log(` 上次轮询: ${resp.lastPollAt}`);
|
|
155
|
+
console.log(` 活跃用户: ${resp.activeUser ?? '(无)'}`);
|
|
156
|
+
console.log(` 消息总数: ${resp.totalMessages}`);
|
|
157
|
+
console.log(` 运行时长: ${uptime}`);
|
|
158
|
+
if (resp.sessionExpired)
|
|
159
|
+
console.log(' ⚠️ 会话已过期,请重新登录');
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
// Fallback to PID file
|
|
163
|
+
try {
|
|
164
|
+
if (!fs.existsSync(PID_PATH)) {
|
|
165
|
+
console.log('○ 服务未运行');
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
const pid = fs.readFileSync(PID_PATH, 'utf-8').trim();
|
|
169
|
+
console.log(`● 服务运行中 (PID: ${pid}) (无法连接到 socket)`);
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
console.log('○ 服务未运行');
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
// wxbot _daemon — hidden command invoked by launchd/systemd
|
|
177
|
+
program
|
|
178
|
+
.command('_daemon', { hidden: true })
|
|
179
|
+
.action(async () => {
|
|
180
|
+
await runService();
|
|
181
|
+
});
|
|
182
|
+
program.parseAsync(process.argv).catch((err) => {
|
|
183
|
+
console.error(String(err));
|
|
184
|
+
process.exit(1);
|
|
185
|
+
});
|
|
186
|
+
//# sourceMappingURL=bin.js.map
|
package/dist/bin.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":"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"}
|
package/dist/daemon.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare function generatePlist(wxbotBin: string, nodeBin: string, logPath: string): string;
|
|
2
|
+
export declare function generateSystemdUnit(wxbotBin: string, logPath: string): string;
|
|
3
|
+
export declare function installService(): void;
|
|
4
|
+
export declare function uninstallService(): void;
|
|
5
|
+
export declare function isServiceRunning(): boolean;
|
|
6
|
+
//# sourceMappingURL=daemon.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../src/daemon.ts"],"names":[],"mappings":"AAUA,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAmBxF;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAc7E;AAID,wBAAgB,cAAc,IAAI,IAAI,CAoBrC;AAED,wBAAgB,gBAAgB,IAAI,IAAI,CAWvC;AAED,wBAAgB,gBAAgB,IAAI,OAAO,CAU1C"}
|
package/dist/daemon.js
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { execSync } from 'node:child_process';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { PID_PATH, LOG_PATH } from './paths.js';
|
|
6
|
+
const PLATFORM = process.platform;
|
|
7
|
+
// ---- Config generation (exported for testing) --------------------------------
|
|
8
|
+
export function generatePlist(wxbotBin, nodeBin, logPath) {
|
|
9
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
10
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
|
|
11
|
+
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
12
|
+
<plist version="1.0">
|
|
13
|
+
<dict>
|
|
14
|
+
<key>Label</key><string>com.wxbot.service</string>
|
|
15
|
+
<key>ProgramArguments</key>
|
|
16
|
+
<array>
|
|
17
|
+
<string>${nodeBin}</string>
|
|
18
|
+
<string>${wxbotBin}</string>
|
|
19
|
+
<string>_daemon</string>
|
|
20
|
+
</array>
|
|
21
|
+
<key>RunAtLoad</key><true/>
|
|
22
|
+
<key>KeepAlive</key><true/>
|
|
23
|
+
<key>StandardOutPath</key><string>${logPath}</string>
|
|
24
|
+
<key>StandardErrorPath</key><string>${logPath}</string>
|
|
25
|
+
</dict>
|
|
26
|
+
</plist>`;
|
|
27
|
+
}
|
|
28
|
+
export function generateSystemdUnit(wxbotBin, logPath) {
|
|
29
|
+
return `[Unit]
|
|
30
|
+
Description=wx bot cli service
|
|
31
|
+
After=network.target
|
|
32
|
+
|
|
33
|
+
[Service]
|
|
34
|
+
ExecStart=${wxbotBin} _daemon
|
|
35
|
+
Restart=on-failure
|
|
36
|
+
RestartSec=5s
|
|
37
|
+
StandardOutput=append:${logPath}
|
|
38
|
+
StandardError=append:${logPath}
|
|
39
|
+
|
|
40
|
+
[Install]
|
|
41
|
+
WantedBy=default.target`;
|
|
42
|
+
}
|
|
43
|
+
// ---- Install / uninstall ----------------------------------------------------
|
|
44
|
+
export function installService() {
|
|
45
|
+
const wxbotBin = process.argv[1]; // path to the compiled wxbot bin
|
|
46
|
+
const logPath = LOG_PATH;
|
|
47
|
+
if (PLATFORM === 'darwin') {
|
|
48
|
+
const plistDir = path.join(os.homedir(), 'Library', 'LaunchAgents');
|
|
49
|
+
const plistPath = path.join(plistDir, 'com.wxbot.service.plist');
|
|
50
|
+
fs.mkdirSync(plistDir, { recursive: true });
|
|
51
|
+
fs.writeFileSync(plistPath, generatePlist(wxbotBin, process.execPath, logPath));
|
|
52
|
+
execSync(`launchctl load "${plistPath}"`);
|
|
53
|
+
}
|
|
54
|
+
else if (PLATFORM === 'linux') {
|
|
55
|
+
const unitDir = path.join(os.homedir(), '.config', 'systemd', 'user');
|
|
56
|
+
const unitPath = path.join(unitDir, 'wxbot.service');
|
|
57
|
+
fs.mkdirSync(unitDir, { recursive: true });
|
|
58
|
+
fs.writeFileSync(unitPath, generateSystemdUnit(wxbotBin, logPath));
|
|
59
|
+
execSync('systemctl --user daemon-reload');
|
|
60
|
+
execSync('systemctl --user enable --now wxbot.service');
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
throw new Error(`Unsupported platform: ${PLATFORM}`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
export function uninstallService() {
|
|
67
|
+
if (PLATFORM === 'darwin') {
|
|
68
|
+
const plistPath = path.join(os.homedir(), 'Library', 'LaunchAgents', 'com.wxbot.service.plist');
|
|
69
|
+
try {
|
|
70
|
+
execSync(`launchctl unload "${plistPath}"`);
|
|
71
|
+
}
|
|
72
|
+
catch { /* ignore if not loaded */ }
|
|
73
|
+
try {
|
|
74
|
+
fs.unlinkSync(plistPath);
|
|
75
|
+
}
|
|
76
|
+
catch { /* ignore if missing */ }
|
|
77
|
+
}
|
|
78
|
+
else if (PLATFORM === 'linux') {
|
|
79
|
+
try {
|
|
80
|
+
execSync('systemctl --user disable --now wxbot.service');
|
|
81
|
+
}
|
|
82
|
+
catch { /* ignore */ }
|
|
83
|
+
const unitPath = path.join(os.homedir(), '.config', 'systemd', 'user', 'wxbot.service');
|
|
84
|
+
try {
|
|
85
|
+
fs.unlinkSync(unitPath);
|
|
86
|
+
}
|
|
87
|
+
catch { /* ignore */ }
|
|
88
|
+
try {
|
|
89
|
+
execSync('systemctl --user daemon-reload');
|
|
90
|
+
}
|
|
91
|
+
catch { /* ignore */ }
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
export function isServiceRunning() {
|
|
95
|
+
try {
|
|
96
|
+
if (!fs.existsSync(PID_PATH))
|
|
97
|
+
return false;
|
|
98
|
+
const pid = parseInt(fs.readFileSync(PID_PATH, 'utf-8').trim(), 10);
|
|
99
|
+
if (isNaN(pid))
|
|
100
|
+
return false;
|
|
101
|
+
process.kill(pid, 0); // throws if process doesn't exist
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=daemon.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon.js","sourceRoot":"","sources":["../src/daemon.ts"],"names":[],"mappings":"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"}
|
package/dist/db.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import Database from 'better-sqlite3';
|
|
2
|
+
import type { MessageRow } from './types.js';
|
|
3
|
+
export type DbInstance = InstanceType<typeof Database>;
|
|
4
|
+
export declare function openDb(filePath: string, readonly?: boolean): DbInstance;
|
|
5
|
+
type InsertParams = Omit<MessageRow, 'id' | 'created_at'>;
|
|
6
|
+
export declare function insertMessage(db: DbInstance, row: InsertParams): void;
|
|
7
|
+
export declare function getRecentMessages(db: DbInstance, limit: number): MessageRow[];
|
|
8
|
+
export declare function countMessages(db: DbInstance): number;
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=db.d.ts.map
|
package/dist/db.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../src/db.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AACtC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,MAAM,MAAM,UAAU,GAAG,YAAY,CAAC,OAAO,QAAQ,CAAC,CAAC;AAevD,wBAAgB,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,UAAQ,GAAG,UAAU,CAOrE;AAED,KAAK,YAAY,GAAG,IAAI,CAAC,UAAU,EAAE,IAAI,GAAG,YAAY,CAAC,CAAC;AAE1D,wBAAgB,aAAa,CAAC,EAAE,EAAE,UAAU,EAAE,GAAG,EAAE,YAAY,GAAG,IAAI,CAKrE;AAED,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,UAAU,EAAE,CAI7E;AAED,wBAAgB,aAAa,CAAC,EAAE,EAAE,UAAU,GAAG,MAAM,CAGpD"}
|
package/dist/db.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import Database from 'better-sqlite3';
|
|
2
|
+
const SCHEMA = `
|
|
3
|
+
CREATE TABLE IF NOT EXISTS messages (
|
|
4
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
5
|
+
ts TEXT NOT NULL,
|
|
6
|
+
direction TEXT NOT NULL,
|
|
7
|
+
user_id TEXT NOT NULL,
|
|
8
|
+
text TEXT NOT NULL,
|
|
9
|
+
context_token TEXT,
|
|
10
|
+
created_at INTEGER NOT NULL
|
|
11
|
+
);
|
|
12
|
+
CREATE INDEX IF NOT EXISTS idx_messages_created_at ON messages(created_at DESC);
|
|
13
|
+
`;
|
|
14
|
+
export function openDb(filePath, readonly = false) {
|
|
15
|
+
const db = new Database(filePath, { readonly });
|
|
16
|
+
if (!readonly) {
|
|
17
|
+
db.pragma('journal_mode = WAL');
|
|
18
|
+
db.exec(SCHEMA);
|
|
19
|
+
}
|
|
20
|
+
return db;
|
|
21
|
+
}
|
|
22
|
+
export function insertMessage(db, row) {
|
|
23
|
+
db.prepare(`INSERT INTO messages (ts, direction, user_id, text, context_token, created_at)
|
|
24
|
+
VALUES (@ts, @direction, @user_id, @text, @context_token, @created_at)`).run({ ...row, created_at: Date.now() });
|
|
25
|
+
}
|
|
26
|
+
export function getRecentMessages(db, limit) {
|
|
27
|
+
return db
|
|
28
|
+
.prepare('SELECT * FROM messages ORDER BY created_at DESC, id DESC LIMIT ?')
|
|
29
|
+
.all(limit);
|
|
30
|
+
}
|
|
31
|
+
export function countMessages(db) {
|
|
32
|
+
const row = db.prepare('SELECT COUNT(*) as n FROM messages').get();
|
|
33
|
+
return row.n;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=db.js.map
|
package/dist/db.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db.js","sourceRoot":"","sources":["../src/db.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAKtC,MAAM,MAAM,GAAG;;;;;;;;;;;CAWd,CAAC;AAEF,MAAM,UAAU,MAAM,CAAC,QAAgB,EAAE,QAAQ,GAAG,KAAK;IACvD,MAAM,EAAE,GAAG,IAAI,QAAQ,CAAC,QAAQ,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC;IAChD,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,EAAE,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;QAChC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAClB,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAID,MAAM,UAAU,aAAa,CAAC,EAAc,EAAE,GAAiB;IAC7D,EAAE,CAAC,OAAO,CACR;4EACwE,CACzE,CAAC,GAAG,CAAC,EAAE,GAAG,GAAG,EAAE,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,EAAc,EAAE,KAAa;IAC7D,OAAO,EAAE;SACN,OAAO,CAAC,kEAAkE,CAAC;SAC3E,GAAG,CAAC,KAAK,CAAiB,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,EAAc;IAC1C,MAAM,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,oCAAoC,CAAC,CAAC,GAAG,EAAmB,CAAC;IACpF,OAAO,GAAG,CAAC,CAAC,CAAC;AACf,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,eAAO,MAAM,OAAO,UAAU,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC"}
|
package/dist/ipc.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import net from 'node:net';
|
|
2
|
+
import type { IpcRequest, IpcResponse } from './types.js';
|
|
3
|
+
export declare function createIpcServer(socketPath: string, handler: (req: IpcRequest) => Promise<IpcResponse>): net.Server;
|
|
4
|
+
export declare function sendIpcRequest(socketPath: string, request: IpcRequest, timeoutMs: number): Promise<IpcResponse>;
|
|
5
|
+
//# sourceMappingURL=ipc.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ipc.d.ts","sourceRoot":"","sources":["../src/ipc.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,UAAU,CAAC;AAE3B,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE1D,wBAAgB,eAAe,CAC7B,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,CAAC,GAAG,EAAE,UAAU,KAAK,OAAO,CAAC,WAAW,CAAC,GACjD,GAAG,CAAC,MAAM,CA6BZ;AAED,wBAAgB,cAAc,CAC5B,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,UAAU,EACnB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,WAAW,CAAC,CAkCtB"}
|
package/dist/ipc.js
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import net from 'node:net';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
export function createIpcServer(socketPath, handler) {
|
|
4
|
+
// Clean up stale socket file before binding
|
|
5
|
+
try {
|
|
6
|
+
fs.unlinkSync(socketPath);
|
|
7
|
+
}
|
|
8
|
+
catch { /* ignore if not present */ }
|
|
9
|
+
const server = net.createServer((conn) => {
|
|
10
|
+
let buf = '';
|
|
11
|
+
conn.setEncoding('utf-8');
|
|
12
|
+
conn.on('data', (chunk) => {
|
|
13
|
+
buf += chunk;
|
|
14
|
+
const nl = buf.indexOf('\n');
|
|
15
|
+
if (nl === -1)
|
|
16
|
+
return;
|
|
17
|
+
const line = buf.slice(0, nl);
|
|
18
|
+
buf = buf.slice(nl + 1);
|
|
19
|
+
try {
|
|
20
|
+
const req = JSON.parse(line);
|
|
21
|
+
handler(req).then((resp) => {
|
|
22
|
+
conn.write(JSON.stringify(resp) + '\n');
|
|
23
|
+
conn.end();
|
|
24
|
+
}).catch((err) => {
|
|
25
|
+
conn.write(JSON.stringify({ ok: false, reason: 'api_error', message: String(err) }) + '\n');
|
|
26
|
+
conn.end();
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
conn.end();
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
return server;
|
|
35
|
+
}
|
|
36
|
+
export function sendIpcRequest(socketPath, request, timeoutMs) {
|
|
37
|
+
return new Promise((resolve, reject) => {
|
|
38
|
+
const timer = setTimeout(() => {
|
|
39
|
+
conn.destroy();
|
|
40
|
+
reject(new Error(`IPC timeout after ${timeoutMs}ms`));
|
|
41
|
+
}, timeoutMs);
|
|
42
|
+
const conn = net.createConnection(socketPath);
|
|
43
|
+
let buf = '';
|
|
44
|
+
conn.setEncoding('utf-8');
|
|
45
|
+
conn.on('connect', () => {
|
|
46
|
+
conn.write(JSON.stringify(request) + '\n');
|
|
47
|
+
});
|
|
48
|
+
conn.on('data', (chunk) => {
|
|
49
|
+
buf += chunk;
|
|
50
|
+
const nl = buf.indexOf('\n');
|
|
51
|
+
if (nl === -1)
|
|
52
|
+
return;
|
|
53
|
+
clearTimeout(timer);
|
|
54
|
+
try {
|
|
55
|
+
resolve(JSON.parse(buf.slice(0, nl)));
|
|
56
|
+
}
|
|
57
|
+
catch (e) {
|
|
58
|
+
reject(e);
|
|
59
|
+
}
|
|
60
|
+
conn.end();
|
|
61
|
+
});
|
|
62
|
+
conn.on('error', (err) => {
|
|
63
|
+
clearTimeout(timer);
|
|
64
|
+
reject(err);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=ipc.js.map
|
package/dist/ipc.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ipc.js","sourceRoot":"","sources":["../src/ipc.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,UAAU,CAAC;AAC3B,OAAO,EAAE,MAAM,SAAS,CAAC;AAGzB,MAAM,UAAU,eAAe,CAC7B,UAAkB,EAClB,OAAkD;IAElD,4CAA4C;IAC5C,IAAI,CAAC;QAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC,CAAC,2BAA2B,CAAC,CAAC;IAExE,MAAM,MAAM,GAAG,GAAG,CAAC,YAAY,CAAC,CAAC,IAAI,EAAE,EAAE;QACvC,IAAI,GAAG,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;QAC1B,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE;YACxB,GAAG,IAAI,KAAK,CAAC;YACb,MAAM,EAAE,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YAC7B,IAAI,EAAE,KAAK,CAAC,CAAC;gBAAE,OAAO;YACtB,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC9B,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;YACxB,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAe,CAAC;gBAC3C,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE;oBACzB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;oBACxC,IAAI,CAAC,GAAG,EAAE,CAAC;gBACb,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;oBACf,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC;oBAC5F,IAAI,CAAC,GAAG,EAAE,CAAC;gBACb,CAAC,CAAC,CAAC;YACL,CAAC;YAAC,MAAM,CAAC;gBACP,IAAI,CAAC,GAAG,EAAE,CAAC;YACb,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,cAAc,CAC5B,UAAkB,EAClB,OAAmB,EACnB,SAAiB;IAEjB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;YAC5B,IAAI,CAAC,OAAO,EAAE,CAAC;YACf,MAAM,CAAC,IAAI,KAAK,CAAC,qBAAqB,SAAS,IAAI,CAAC,CAAC,CAAC;QACxD,CAAC,EAAE,SAAS,CAAC,CAAC;QAEd,MAAM,IAAI,GAAG,GAAG,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC;QAC9C,IAAI,GAAG,GAAG,EAAE,CAAC;QAEb,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;QAE1B,IAAI,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE;YACtB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE;YACxB,GAAG,IAAI,KAAK,CAAC;YACb,MAAM,EAAE,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YAC7B,IAAI,EAAE,KAAK,CAAC,CAAC;gBAAE,OAAO;YACtB,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,IAAI,CAAC;gBACH,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAgB,CAAC,CAAC;YACvD,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,MAAM,CAAC,CAAC,CAAC,CAAC;YACZ,CAAC;YACD,IAAI,CAAC,GAAG,EAAE,CAAC;QACb,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YACvB,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,MAAM,CAAC,GAAG,CAAC,CAAC;QACd,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC"}
|
package/dist/paths.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare const DATA_DIR: string;
|
|
2
|
+
export declare const SESSION_PATH: string;
|
|
3
|
+
export declare const DB_PATH: string;
|
|
4
|
+
export declare const SOCKET_PATH: string;
|
|
5
|
+
export declare const PID_PATH: string;
|
|
6
|
+
export declare const LOG_PATH: string;
|
|
7
|
+
//# sourceMappingURL=paths.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,QAAQ,QAAoC,CAAC;AAC1D,eAAO,MAAM,YAAY,QAAsC,CAAC;AAChE,eAAO,MAAM,OAAO,QAAqC,CAAC;AAC1D,eAAO,MAAM,WAAW,QAAoC,CAAC;AAC7D,eAAO,MAAM,QAAQ,QAAqC,CAAC;AAC3D,eAAO,MAAM,QAAQ,QAA8E,CAAC"}
|
package/dist/paths.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import os from 'node:os';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
export const DATA_DIR = path.join(os.homedir(), '.wxbot');
|
|
4
|
+
export const SESSION_PATH = path.join(DATA_DIR, 'session.json');
|
|
5
|
+
export const DB_PATH = path.join(DATA_DIR, 'messages.db');
|
|
6
|
+
export const SOCKET_PATH = path.join(DATA_DIR, 'wxbot.sock');
|
|
7
|
+
export const PID_PATH = path.join(DATA_DIR, 'service.pid');
|
|
8
|
+
export const LOG_PATH = path.join(DATA_DIR, `service-${new Date().toISOString().slice(0, 10)}.log`);
|
|
9
|
+
//# sourceMappingURL=paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,MAAM,CAAC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,QAAQ,CAAC,CAAC;AAC1D,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC;AAChE,MAAM,CAAC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;AAC1D,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;AAC7D,MAAM,CAAC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;AAC3D,MAAM,CAAC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,WAAW,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { UserSession } from './types.js';
|
|
2
|
+
export type ServiceState = {
|
|
3
|
+
activeUser: string | null;
|
|
4
|
+
sessions: Map<string, UserSession>;
|
|
5
|
+
lastPollAt: string;
|
|
6
|
+
sessionExpired: boolean;
|
|
7
|
+
startedAt: number;
|
|
8
|
+
};
|
|
9
|
+
export declare function createUserSessionState(): ServiceState;
|
|
10
|
+
export declare function processInboundMessage(state: ServiceState, msg: {
|
|
11
|
+
fromUserId: string;
|
|
12
|
+
contextToken: string;
|
|
13
|
+
}): void;
|
|
14
|
+
export declare function recordOutboundSent(state: ServiceState, userId: string): number;
|
|
15
|
+
export declare function shouldAutoNotify(state: ServiceState, userId: string): boolean;
|
|
16
|
+
export declare function getEffectiveRemaining(state: ServiceState, userId: string): number;
|
|
17
|
+
export declare function runService(): Promise<void>;
|
|
18
|
+
//# sourceMappingURL=service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAA2B,WAAW,EAAE,MAAM,YAAY,CAAC;AAIvE,MAAM,MAAM,YAAY,GAAG;IACzB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,OAAO,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,wBAAgB,sBAAsB,IAAI,YAAY,CAQrD;AAED,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,YAAY,EACnB,GAAG,EAAE;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GAChD,IAAI,CAON;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAK9E;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAE7E;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAKjF;AAWD,wBAAsB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAkLhD"}
|