@takibeiy/moltbot_cn 2026.1.27-beta.1 → 2026.1.28

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.
Binary file
@@ -0,0 +1,15 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Moltbot Control</title>
7
+ <meta name="color-scheme" content="dark light" />
8
+ <link rel="icon" href="./favicon.ico" sizes="any" />
9
+ <script type="module" crossorigin src="./assets/index-CxUFDXFX.js"></script>
10
+ <link rel="stylesheet" crossorigin href="./assets/index-BAFzd9IE.css">
11
+ </head>
12
+ <body>
13
+ <moltbot-app></moltbot-app>
14
+ </body>
15
+ </html>
@@ -0,0 +1,19 @@
1
+ ---
2
+ name: boot-md
3
+ description: "Run BOOT.md on gateway startup"
4
+ homepage: https://docs.molt.bot/hooks#boot-md
5
+ metadata:
6
+ {
7
+ "moltbot":
8
+ {
9
+ "emoji": "🚀",
10
+ "events": ["gateway:startup"],
11
+ "requires": { "config": ["workspace.dir"] },
12
+ "install": [{ "id": "bundled", "kind": "bundled", "label": "Bundled with Moltbot" }],
13
+ },
14
+ }
15
+ ---
16
+
17
+ # Boot Checklist Hook
18
+
19
+ Runs `BOOT.md` every time the gateway starts, if the file exists in the workspace.
@@ -0,0 +1,122 @@
1
+ ---
2
+ name: command-logger
3
+ description: "Log all command events to a centralized audit file"
4
+ homepage: https://docs.molt.bot/hooks#command-logger
5
+ metadata:
6
+ {
7
+ "moltbot":
8
+ {
9
+ "emoji": "📝",
10
+ "events": ["command"],
11
+ "install": [{ "id": "bundled", "kind": "bundled", "label": "Bundled with Moltbot" }],
12
+ },
13
+ }
14
+ ---
15
+
16
+ # Command Logger Hook
17
+
18
+ Logs all command events (`/new`, `/reset`, `/stop`, etc.) to a centralized audit log file for debugging and monitoring purposes.
19
+
20
+ ## What It Does
21
+
22
+ Every time you issue a command to the agent:
23
+
24
+ 1. **Captures event details** - Command action, timestamp, session key, sender ID, source
25
+ 2. **Appends to log file** - Writes a JSON line to `~/.clawdbot/logs/commands.log`
26
+ 3. **Silent operation** - Runs in the background without user notifications
27
+
28
+ ## Output Format
29
+
30
+ Log entries are written in JSONL (JSON Lines) format:
31
+
32
+ ```json
33
+ {"timestamp":"2026-01-16T14:30:00.000Z","action":"new","sessionKey":"agent:main:main","senderId":"+1234567890","source":"telegram"}
34
+ {"timestamp":"2026-01-16T15:45:22.000Z","action":"stop","sessionKey":"agent:main:main","senderId":"user@example.com","source":"whatsapp"}
35
+ ```
36
+
37
+ ## Use Cases
38
+
39
+ - **Debugging**: Track when commands were issued and from which source
40
+ - **Auditing**: Monitor command usage across different channels
41
+ - **Analytics**: Analyze command patterns and frequency
42
+ - **Troubleshooting**: Investigate issues by reviewing command history
43
+
44
+ ## Log File Location
45
+
46
+ `~/.clawdbot/logs/commands.log`
47
+
48
+ ## Requirements
49
+
50
+ No requirements - this hook works out of the box on all platforms.
51
+
52
+ ## Configuration
53
+
54
+ No configuration needed. The hook automatically:
55
+
56
+ - Creates the log directory if it doesn't exist
57
+ - Appends to the log file (doesn't overwrite)
58
+ - Handles errors silently without disrupting command execution
59
+
60
+ ## Disabling
61
+
62
+ To disable this hook:
63
+
64
+ ```bash
65
+ moltbot hooks disable command-logger
66
+ ```
67
+
68
+ Or via config:
69
+
70
+ ```json
71
+ {
72
+ "hooks": {
73
+ "internal": {
74
+ "entries": {
75
+ "command-logger": { "enabled": false }
76
+ }
77
+ }
78
+ }
79
+ }
80
+ ```
81
+
82
+ ## Log Rotation
83
+
84
+ The hook does not automatically rotate logs. To manage log size, you can:
85
+
86
+ 1. **Manual rotation**:
87
+
88
+ ```bash
89
+ mv ~/.clawdbot/logs/commands.log ~/.clawdbot/logs/commands.log.old
90
+ ```
91
+
92
+ 2. **Use logrotate** (Linux):
93
+ Create `/etc/logrotate.d/moltbot`:
94
+ ```
95
+ /home/username/.clawdbot/logs/commands.log {
96
+ weekly
97
+ rotate 4
98
+ compress
99
+ missingok
100
+ notifempty
101
+ }
102
+ ```
103
+
104
+ ## Viewing Logs
105
+
106
+ View recent commands:
107
+
108
+ ```bash
109
+ tail -n 20 ~/.clawdbot/logs/commands.log
110
+ ```
111
+
112
+ Pretty-print with jq:
113
+
114
+ ```bash
115
+ cat ~/.clawdbot/logs/commands.log | jq .
116
+ ```
117
+
118
+ Filter by action:
119
+
120
+ ```bash
121
+ grep '"action":"new"' ~/.clawdbot/logs/commands.log | jq .
122
+ ```
@@ -0,0 +1,86 @@
1
+ ---
2
+ name: session-memory
3
+ description: "Save session context to memory when /new command is issued"
4
+ homepage: https://docs.molt.bot/hooks#session-memory
5
+ metadata:
6
+ {
7
+ "moltbot":
8
+ {
9
+ "emoji": "💾",
10
+ "events": ["command:new"],
11
+ "requires": { "config": ["workspace.dir"] },
12
+ "install": [{ "id": "bundled", "kind": "bundled", "label": "Bundled with Moltbot" }],
13
+ },
14
+ }
15
+ ---
16
+
17
+ # Session Memory Hook
18
+
19
+ Automatically saves session context to your workspace memory when you issue the `/new` command.
20
+
21
+ ## What It Does
22
+
23
+ When you run `/new` to start a fresh session:
24
+
25
+ 1. **Finds the previous session** - Uses the pre-reset session entry to locate the correct transcript
26
+ 2. **Extracts conversation** - Reads the last 15 lines of conversation from the session
27
+ 3. **Generates descriptive slug** - Uses LLM to create a meaningful filename slug based on conversation content
28
+ 4. **Saves to memory** - Creates a new file at `<workspace>/memory/YYYY-MM-DD-slug.md`
29
+ 5. **Sends confirmation** - Notifies you with the file path
30
+
31
+ ## Output Format
32
+
33
+ Memory files are created with the following format:
34
+
35
+ ```markdown
36
+ # Session: 2026-01-16 14:30:00 UTC
37
+
38
+ - **Session Key**: agent:main:main
39
+ - **Session ID**: abc123def456
40
+ - **Source**: telegram
41
+ ```
42
+
43
+ ## Filename Examples
44
+
45
+ The LLM generates descriptive slugs based on your conversation:
46
+
47
+ - `2026-01-16-vendor-pitch.md` - Discussion about vendor evaluation
48
+ - `2026-01-16-api-design.md` - API architecture planning
49
+ - `2026-01-16-bug-fix.md` - Debugging session
50
+ - `2026-01-16-1430.md` - Fallback timestamp if slug generation fails
51
+
52
+ ## Requirements
53
+
54
+ - **Config**: `workspace.dir` must be set (automatically configured during onboarding)
55
+
56
+ The hook uses your configured LLM provider to generate slugs, so it works with any provider (Anthropic, OpenAI, etc.).
57
+
58
+ ## Configuration
59
+
60
+ No additional configuration required. The hook automatically:
61
+
62
+ - Uses your workspace directory (`~/clawd` by default)
63
+ - Uses your configured LLM for slug generation
64
+ - Falls back to timestamp slugs if LLM is unavailable
65
+
66
+ ## Disabling
67
+
68
+ To disable this hook:
69
+
70
+ ```bash
71
+ moltbot hooks disable session-memory
72
+ ```
73
+
74
+ Or remove it from your config:
75
+
76
+ ```json
77
+ {
78
+ "hooks": {
79
+ "internal": {
80
+ "entries": {
81
+ "session-memory": { "enabled": false }
82
+ }
83
+ }
84
+ }
85
+ }
86
+ ```
@@ -0,0 +1,71 @@
1
+ ---
2
+ name: soul-evil
3
+ description: "Swap SOUL.md with SOUL_EVIL.md during a purge window or by random chance"
4
+ homepage: https://docs.molt.bot/hooks/soul-evil
5
+ metadata:
6
+ {
7
+ "moltbot":
8
+ {
9
+ "emoji": "😈",
10
+ "events": ["agent:bootstrap"],
11
+ "requires": { "config": ["hooks.internal.entries.soul-evil.enabled"] },
12
+ "install": [{ "id": "bundled", "kind": "bundled", "label": "Bundled with Moltbot" }],
13
+ },
14
+ }
15
+ ---
16
+
17
+ # SOUL Evil Hook
18
+
19
+ Replaces the injected `SOUL.md` content with `SOUL_EVIL.md` during a daily purge window or by random chance.
20
+
21
+ ## What It Does
22
+
23
+ When enabled and the trigger conditions match, the hook swaps the **injected** `SOUL.md` content before the system prompt is built. It does **not** modify files on disk.
24
+
25
+ ## Files
26
+
27
+ - `SOUL.md` — normal persona (always read)
28
+ - `SOUL_EVIL.md` — alternate persona (read only when triggered)
29
+
30
+ You can change the filename via hook config.
31
+
32
+ ## Configuration
33
+
34
+ Add this to your config (`~/.clawdbot/moltbot.json`):
35
+
36
+ ```json
37
+ {
38
+ "hooks": {
39
+ "internal": {
40
+ "enabled": true,
41
+ "entries": {
42
+ "soul-evil": {
43
+ "enabled": true,
44
+ "file": "SOUL_EVIL.md",
45
+ "chance": 0.1,
46
+ "purge": { "at": "21:00", "duration": "15m" }
47
+ }
48
+ }
49
+ }
50
+ }
51
+ }
52
+ ```
53
+
54
+ ### Options
55
+
56
+ - `file` (string): alternate SOUL filename (default: `SOUL_EVIL.md`)
57
+ - `chance` (number 0–1): random chance per run to swap in SOUL_EVIL
58
+ - `purge.at` (HH:mm): daily purge window start time (24h)
59
+ - `purge.duration` (duration): window length (e.g. `30s`, `10m`, `1h`)
60
+
61
+ **Precedence:** purge window wins over chance.
62
+
63
+ ## Requirements
64
+
65
+ - `hooks.internal.entries.soul-evil.enabled` must be set to `true`
66
+
67
+ ## Enable
68
+
69
+ ```bash
70
+ moltbot hooks enable soul-evil
71
+ ```
@@ -233,6 +233,13 @@ export class OneBotClient {
233
233
  this.state = "disconnected";
234
234
  this.ws = null;
235
235
 
236
+ // Clean up pending requests to prevent memory leak
237
+ for (const [echo, pending] of this.pendingRequests) {
238
+ clearTimeout(pending.timeoutId);
239
+ pending.reject(new Error(`Connection closed (code: ${code})`));
240
+ }
241
+ this.pendingRequests.clear();
242
+
236
243
  this.events.onDisconnect?.(code, reason.toString());
237
244
 
238
245
  // Auto-reconnect if enabled and not manually disconnected
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@takibeiy/moltbot_cn",
3
- "version": "2026.1.27-beta.1",
3
+ "version": "2026.1.28",
4
4
  "description": "Multi-channel AI assistant gateway (QQ, Telegram, WhatsApp, Discord, Slack)",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1,82 +0,0 @@
1
- /**
2
- * QQ Connection Test Script
3
- *
4
- * Tests connection to NapCat OneBot WebSocket server.
5
- * Run with: npx tsx extensions/qq/test-connection.ts
6
- */
7
-
8
- import WebSocket from "ws";
9
-
10
- const WS_URL = "ws://127.0.0.1:3001";
11
-
12
- console.log(`\n🔌 Connecting to NapCat at ${WS_URL}...\n`);
13
-
14
- const ws = new WebSocket(WS_URL);
15
-
16
- ws.on("open", () => {
17
- console.log("✅ Connected to NapCat!\n");
18
-
19
- // Request login info
20
- const request = {
21
- action: "get_login_info",
22
- params: {},
23
- echo: "test_login_info"
24
- };
25
-
26
- console.log("📤 Sending get_login_info request...");
27
- ws.send(JSON.stringify(request));
28
- });
29
-
30
- ws.on("message", (data) => {
31
- try {
32
- const message = JSON.parse(data.toString());
33
-
34
- // Check if it's our API response
35
- if (message.echo === "test_login_info") {
36
- if (message.status === "ok") {
37
- console.log("\n✅ Login info received:");
38
- console.log(` QQ号: ${message.data.user_id}`);
39
- console.log(` 昵称: ${message.data.nickname}`);
40
- } else {
41
- console.log("\n❌ API call failed:", message.message || message.wording);
42
- }
43
-
44
- // Close connection after getting info
45
- setTimeout(() => {
46
- console.log("\n👋 Closing connection...");
47
- ws.close();
48
- }, 500);
49
- return;
50
- }
51
-
52
- // It's an event
53
- if (message.post_type === "message") {
54
- const chatType = message.message_type === "group" ? "群聊" : "私聊";
55
- const sender = message.sender?.nickname || message.user_id;
56
- console.log(`\n📨 收到${chatType}消息 [${sender}]: ${message.raw_message?.slice(0, 50)}...`);
57
- } else if (message.post_type === "meta_event" && message.meta_event_type === "heartbeat") {
58
- console.log("💓 Heartbeat");
59
- } else if (message.post_type === "meta_event" && message.meta_event_type === "lifecycle") {
60
- console.log(`🔄 Lifecycle event: ${message.sub_type}`);
61
- }
62
- } catch (err) {
63
- console.log("⚠️ Failed to parse message:", data.toString().slice(0, 100));
64
- }
65
- });
66
-
67
- ws.on("error", (error) => {
68
- console.error("\n❌ Connection error:", error.message);
69
- console.log("\n提示: 请确保 NapCat 已启动且 WebSocket 服务器已配置在端口 3001");
70
- process.exit(1);
71
- });
72
-
73
- ws.on("close", (code, reason) => {
74
- console.log(`\n🔌 Connection closed (code: ${code})`);
75
- process.exit(0);
76
- });
77
-
78
- // Timeout after 10 seconds
79
- setTimeout(() => {
80
- console.log("\n⏱️ Timeout - closing connection");
81
- ws.close();
82
- }, 10000);
@@ -1,98 +0,0 @@
1
- /**
2
- * QQ Send Message Test
3
- *
4
- * Tests sending a message via OneBot API.
5
- * Usage: npx tsx extensions/qq/test-send.ts <target> <message>
6
- *
7
- * Examples:
8
- * npx tsx extensions/qq/test-send.ts 123456789 "Hello!"
9
- * npx tsx extensions/qq/test-send.ts group:740112783 "Hello group!"
10
- */
11
-
12
- import WebSocket from "ws";
13
-
14
- const WS_URL = "ws://127.0.0.1:3001";
15
-
16
- // Parse arguments
17
- const args = process.argv.slice(2);
18
- if (args.length < 2) {
19
- console.log("Usage: npx tsx extensions/qq/test-send.ts <target> <message>");
20
- console.log("");
21
- console.log("Examples:");
22
- console.log(' npx tsx extensions/qq/test-send.ts 123456789 "Hello!"');
23
- console.log(' npx tsx extensions/qq/test-send.ts group:740112783 "Hello group!"');
24
- process.exit(1);
25
- }
26
-
27
- const [target, ...messageParts] = args;
28
- const message = messageParts.join(" ");
29
-
30
- // Parse target
31
- const isGroup = target.startsWith("group:");
32
- const targetId = isGroup ? Number(target.slice(6)) : Number(target);
33
-
34
- if (Number.isNaN(targetId)) {
35
- console.error("❌ Invalid target ID:", target);
36
- process.exit(1);
37
- }
38
-
39
- console.log(`\n🔌 Connecting to NapCat at ${WS_URL}...`);
40
-
41
- const ws = new WebSocket(WS_URL);
42
-
43
- ws.on("open", () => {
44
- console.log("✅ Connected!\n");
45
-
46
- const action = isGroup ? "send_group_msg" : "send_private_msg";
47
- const params = isGroup
48
- ? { group_id: targetId, message: [{ type: "text", data: { text: message } }] }
49
- : { user_id: targetId, message: [{ type: "text", data: { text: message } }] };
50
-
51
- const request = {
52
- action,
53
- params,
54
- echo: "test_send"
55
- };
56
-
57
- console.log(`📤 Sending ${isGroup ? "group" : "private"} message to ${targetId}...`);
58
- console.log(` Content: "${message}"`);
59
- ws.send(JSON.stringify(request));
60
- });
61
-
62
- ws.on("message", (data) => {
63
- try {
64
- const response = JSON.parse(data.toString());
65
-
66
- if (response.echo === "test_send") {
67
- if (response.status === "ok") {
68
- console.log(`\n✅ Message sent successfully!`);
69
- console.log(` Message ID: ${response.data?.message_id}`);
70
- } else {
71
- console.log(`\n❌ Failed to send message:`);
72
- console.log(` Error: ${response.message || response.wording || "Unknown error"}`);
73
- console.log(` Retcode: ${response.retcode}`);
74
- }
75
-
76
- setTimeout(() => {
77
- ws.close();
78
- }, 500);
79
- }
80
- } catch {
81
- // Ignore parse errors
82
- }
83
- });
84
-
85
- ws.on("error", (error) => {
86
- console.error("\n❌ Connection error:", error.message);
87
- process.exit(1);
88
- });
89
-
90
- ws.on("close", () => {
91
- console.log("\n👋 Done!");
92
- process.exit(0);
93
- });
94
-
95
- setTimeout(() => {
96
- console.log("\n⏱️ Timeout");
97
- ws.close();
98
- }, 10000);