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/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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":"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"}
@@ -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
@@ -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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * wx-bot-cli - WeChat AI Bot CLI and TUI dashboard
3
+ */
4
+ export declare const version = "0.1.0";
5
+ //# 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,eAAO,MAAM,OAAO,UAAU,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ /**
2
+ * wx-bot-cli - WeChat AI Bot CLI and TUI dashboard
3
+ */
4
+ export const version = '0.1.0';
5
+ //# sourceMappingURL=index.js.map
@@ -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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ipc.js","sourceRoot":"","sources":["../src/ipc.ts"],"names":[],"mappings":"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"}
@@ -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"}