openclaw-mem 1.0.3 → 1.2.1

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/setup.js ADDED
@@ -0,0 +1,114 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * OpenClaw-Mem Setup Script
4
+ *
5
+ * Prompts for DeepSeek API key and saves configuration
6
+ */
7
+
8
+ import readline from 'readline';
9
+ import fs from 'fs';
10
+ import path from 'path';
11
+ import os from 'os';
12
+
13
+ const CONFIG_DIR = path.join(os.homedir(), '.openclaw-mem');
14
+ const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
15
+
16
+ const rl = readline.createInterface({
17
+ input: process.stdin,
18
+ output: process.stdout
19
+ });
20
+
21
+ function question(prompt) {
22
+ return new Promise((resolve) => {
23
+ rl.question(prompt, resolve);
24
+ });
25
+ }
26
+
27
+ async function setup() {
28
+ console.log('\n');
29
+ console.log('╔════════════════════════════════════════════════════════════╗');
30
+ console.log('║ 🧠 OpenClaw-Mem Setup ║');
31
+ console.log('╚════════════════════════════════════════════════════════════╝');
32
+ console.log('\n');
33
+
34
+ // Ensure config directory exists
35
+ if (!fs.existsSync(CONFIG_DIR)) {
36
+ fs.mkdirSync(CONFIG_DIR, { recursive: true });
37
+ }
38
+
39
+ // Load existing config
40
+ let config = {};
41
+ if (fs.existsSync(CONFIG_FILE)) {
42
+ try {
43
+ config = JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf-8'));
44
+ } catch (e) {
45
+ config = {};
46
+ }
47
+ }
48
+
49
+ // Check if already configured
50
+ const existingKey = process.env.DEEPSEEK_API_KEY || config.deepseekApiKey;
51
+ if (existingKey) {
52
+ const maskedKey = existingKey.slice(0, 8) + '...' + existingKey.slice(-4);
53
+ console.log(`✓ DeepSeek API Key already configured: ${maskedKey}`);
54
+
55
+ const reconfigure = await question('\nDo you want to reconfigure? (y/N): ');
56
+ if (reconfigure.toLowerCase() !== 'y') {
57
+ console.log('\nSetup complete! OpenClaw-Mem is ready to use.\n');
58
+ rl.close();
59
+ return;
60
+ }
61
+ }
62
+
63
+ console.log('DeepSeek API is used for AI-powered session summarization.');
64
+ console.log('Get your API key at: https://platform.deepseek.com/\n');
65
+ console.log('(Press Enter to skip if you don\'t have one yet)\n');
66
+
67
+ const apiKey = await question('Enter your DeepSeek API Key: ');
68
+
69
+ if (apiKey.trim()) {
70
+ config.deepseekApiKey = apiKey.trim();
71
+
72
+ // Save to config file
73
+ fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
74
+ console.log(`\n✓ API Key saved to ${CONFIG_FILE}`);
75
+
76
+ // Suggest adding to shell profile
77
+ console.log('\n📝 To use the API key, add this to your shell profile (~/.bashrc or ~/.zshrc):');
78
+ console.log(`\n export DEEPSEEK_API_KEY="${apiKey.trim()}"\n`);
79
+
80
+ // Ask if user wants to auto-add
81
+ const autoAdd = await question('Add to ~/.zshrc automatically? (y/N): ');
82
+ if (autoAdd.toLowerCase() === 'y') {
83
+ const zshrc = path.join(os.homedir(), '.zshrc');
84
+ const exportLine = `\n# OpenClaw-Mem DeepSeek API\nexport DEEPSEEK_API_KEY="${apiKey.trim()}"\n`;
85
+
86
+ try {
87
+ fs.appendFileSync(zshrc, exportLine);
88
+ console.log('\n✓ Added to ~/.zshrc');
89
+ console.log(' Run `source ~/.zshrc` or restart your terminal to apply.\n');
90
+ } catch (e) {
91
+ console.log(`\n⚠ Could not write to ~/.zshrc: ${e.message}`);
92
+ console.log(' Please add the export line manually.\n');
93
+ }
94
+ }
95
+ } else {
96
+ console.log('\n⚠ No API key provided. AI summarization will be disabled.');
97
+ console.log(' You can run `npx openclaw-mem-setup` later to configure.\n');
98
+ }
99
+
100
+ // Additional configuration
101
+ console.log('─'.repeat(60));
102
+ console.log('\n📁 Data storage location: ~/.openclaw-mem/');
103
+ console.log('📊 Database: ~/.openclaw-mem/memory.db');
104
+ console.log('🔌 HTTP API port: 18790');
105
+ console.log('\n✓ Setup complete! OpenClaw-Mem is ready to use.\n');
106
+
107
+ rl.close();
108
+ }
109
+
110
+ // Run setup
111
+ setup().catch(err => {
112
+ console.error('Setup failed:', err.message);
113
+ process.exit(1);
114
+ });
package/sync-recent.js ADDED
@@ -0,0 +1,63 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Sync recent messages from OpenClaw session files to database
4
+ */
5
+
6
+ import fs from 'node:fs';
7
+ import path from 'node:path';
8
+ import os from 'node:os';
9
+ import Database from 'better-sqlite3';
10
+
11
+ const SESSION_FILE = path.join(os.homedir(), '.openclaw/agents/main/sessions/b99a8d14-5b71-4f2d-8fb1-25b48cf4aa68.jsonl');
12
+ const DB_PATH = path.join(os.homedir(), '.openclaw-mem/memory.db');
13
+
14
+ const db = new Database(DB_PATH);
15
+ const insert = db.prepare(`
16
+ INSERT INTO observations (session_id, timestamp, tool_name, tool_input, tool_response, summary, concepts, tokens_discovery, tokens_read)
17
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
18
+ `);
19
+
20
+ const content = fs.readFileSync(SESSION_FILE, 'utf-8');
21
+ const lines = content.trim().split('\n').slice(-30); // Last 30 lines
22
+
23
+ let saved = 0;
24
+ for (const line of lines) {
25
+ try {
26
+ const entry = JSON.parse(line);
27
+ if (entry.type === 'message' && entry.message) {
28
+ const role = entry.message.role;
29
+ let text = '';
30
+ if (Array.isArray(entry.message.content)) {
31
+ text = entry.message.content.map(c => c.text || c).join(' ');
32
+ } else {
33
+ text = entry.message.content || '';
34
+ }
35
+
36
+ if (!text.trim()) continue;
37
+
38
+ const toolName = role === 'user' ? 'UserMessage' : 'AssistantMessage';
39
+ const summary = text.slice(0, 100) + (text.length > 100 ? '...' : '');
40
+
41
+ try {
42
+ insert.run(
43
+ 'live-sync',
44
+ entry.timestamp || new Date().toISOString(),
45
+ toolName,
46
+ JSON.stringify({ role }),
47
+ JSON.stringify({ content: text.slice(0, 2000) }),
48
+ summary,
49
+ text.slice(0, 500),
50
+ Math.ceil(text.length / 4),
51
+ Math.ceil(summary.length / 4)
52
+ );
53
+ saved++;
54
+ console.log(`✓ [${role}] ${text.slice(0, 50)}...`);
55
+ } catch (e) {
56
+ // Skip duplicates
57
+ }
58
+ }
59
+ } catch (e) {}
60
+ }
61
+
62
+ console.log(`\n已同步 ${saved} 条消息`);
63
+ db.close();
package/README_CN.md DELETED
@@ -1,184 +0,0 @@
1
- # OpenClaw-Mem 🧠
2
-
3
- > 为你的 OpenClaw AI 代理提供持久长期记忆
4
-
5
- [![npm version](https://badge.fury.io/js/openclaw-mem.svg)](https://www.npmjs.com/package/openclaw-mem)
6
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
-
8
- [English](README.md) | 中文
9
-
10
- OpenClaw-Mem 自动捕获你的对话并使其可搜索,让你的 AI 助手能够记住跨会话讨论的内容。
11
-
12
- ## ✨ 功能特性
13
-
14
- - **🔄 自动记忆捕获** - 对话自动保存
15
- - **🔍 全文搜索** - 搜索你的整个对话历史
16
- - **📊 渐进式披露** - 分层上下文,高效使用 token
17
- - **🎯 话题检测** - 自动按话题索引讨论内容
18
- - **💾 本地存储** - 所有数据保存在你的机器上(SQLite)
19
- - **⚡ 零配置** - 开箱即用
20
-
21
- ## 🚀 快速开始
22
-
23
- ```bash
24
- # 一键安装和设置!
25
- npx openclaw-mem init
26
-
27
- # 重启 OpenClaw 网关
28
- openclaw gateway restart
29
- ```
30
-
31
- 就这样!开始聊天,你的对话将被记住。
32
-
33
- ## 📖 使用方法
34
-
35
- ### 在聊天中回忆记忆
36
-
37
- 询问你的 AI 助手:
38
- - "我们之前讨论过什么?"
39
- - "上次我们在做什么?"
40
- - "提醒我关于认证问题的事"
41
-
42
- ### CLI 命令
43
-
44
- ```bash
45
- # 查看记忆状态
46
- npx openclaw-mem status
47
-
48
- # 搜索记忆
49
- npx openclaw-mem search "认证"
50
- npx openclaw-mem search "AI 记忆"
51
-
52
- # 卸载(保留数据库)
53
- npx openclaw-mem uninstall
54
- ```
55
-
56
- ## 🏗️ 工作原理
57
-
58
- ```
59
- +-------------+ +------------------+ +------------+
60
- | Telegram | --> | OpenClaw Gateway | --> | AI Agent |
61
- +-------------+ +------------------+ +------------+
62
- | |
63
- v v
64
- +--------------+ +------------+
65
- | openclaw-mem | | Read Tool |
66
- | hook | +------------+
67
- +--------------+ |
68
- | v
69
- +-------------------+----------------------+
70
- | |
71
- v v
72
- +---------------+ +------------------+
73
- | SQLite DB | | SESSION-MEMORY.md|
74
- | (持久存储) | | (注入上下文) |
75
- +---------------+ +------------------+
76
- ```
77
-
78
- ### 事件流程
79
-
80
- 1. **`gateway:startup`** - 初始化记忆数据库
81
- 2. **`agent:bootstrap`** - 向新会话注入历史上下文
82
- 3. **`command:new`** - 开始新对话时保存会话摘要
83
-
84
- ### 渐进式披露
85
-
86
- 为优化 token 使用,记忆按层级组织:
87
-
88
- | 层级 | 内容 | Token 消耗 |
89
- |------|------|-----------|
90
- | 索引 | 所有观察的紧凑表格 | 低 |
91
- | 话题 | 关键讨论摘要 | 中 |
92
- | 详情 | 完整内容(按需) | 高 |
93
-
94
- ## 📁 文件位置
95
-
96
- | 文件 | 位置 | 用途 |
97
- |------|------|------|
98
- | 数据库 | `~/.openclaw-mem/memory.db` | 持久存储 |
99
- | Hook | `~/.openclaw/hooks/openclaw-mem/` | 事件处理器 |
100
- | 记忆上下文 | `~/.openclaw/workspace/SESSION-MEMORY.md` | 注入的上下文 |
101
-
102
- ## ⚙️ 配置
103
-
104
- ### 自定义 MEMORY.md
105
-
106
- 在 `~/.openclaw/workspace/MEMORY.md` 中添加你的偏好:
107
-
108
- ```markdown
109
- ## 用户偏好
110
- - 沟通风格:技术性且简洁
111
- - 语言:中文
112
-
113
- ## 长期上下文
114
- - 正在做:AI 记忆系统
115
- - 兴趣:机器学习、分布式系统
116
-
117
- ## 当前关注
118
- - 当前项目:构建聊天应用
119
- ```
120
-
121
- ### 动态话题检测
122
-
123
- 系统自动从你的实际对话中提取话题:
124
- - 频繁提及的概念会被自动检测
125
- - 没有硬编码关键词 - 一切来自你的数据
126
- - 话题随你的讨论内容变化
127
-
128
- ## 🔧 故障排除
129
-
130
- ### 记忆没有被回忆?
131
-
132
- 1. **重启网关:**
133
- ```bash
134
- openclaw gateway restart
135
- ```
136
-
137
- 2. **检查 hook 是否安装:**
138
- ```bash
139
- ls ~/.openclaw/hooks/openclaw-mem/
140
- ```
141
-
142
- 3. **验证数据库有内容:**
143
- ```bash
144
- npx openclaw-mem status
145
- ```
146
-
147
- ### 搜索找不到结果?
148
-
149
- - 尝试更简单的搜索词
150
- - 检查拼写错误
151
- - 使用实际对话中的关键词
152
-
153
- ### 数据库问题?
154
-
155
- ```bash
156
- # 重置数据库(⚠️ 删除所有记忆)
157
- rm ~/.openclaw-mem/memory.db
158
- openclaw gateway restart
159
- ```
160
-
161
- ## 🤝 贡献
162
-
163
- 欢迎贡献!请随时提交 Pull Request。
164
-
165
- 1. Fork 仓库
166
- 2. 创建你的功能分支 (`git checkout -b feature/amazing-feature`)
167
- 3. 提交更改 (`git commit -m 'Add amazing feature'`)
168
- 4. 推送到分支 (`git push origin feature/amazing-feature`)
169
- 5. 打开 Pull Request
170
-
171
- ## 📄 许可证
172
-
173
- MIT 许可证 - 详见 [LICENSE](LICENSE)
174
-
175
- ## 🙏 致谢
176
-
177
- - 灵感来自 [claude-mem](https://github.com/anthropics/claude-mem)
178
- - 为 [OpenClaw](https://openclaw.ai) 构建
179
-
180
- ---
181
-
182
- <p align="center">
183
- 用 ❤️ 为 AI 社区制作
184
- </p>
@@ -1,117 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * OpenClaw-Mem CLI
4
- *
5
- * Usage:
6
- * npx openclaw-mem init - Install hook to OpenClaw
7
- * npx openclaw-mem status - Show memory statistics
8
- * npx openclaw-mem search - Search memory
9
- * npx openclaw-mem uninstall - Remove hook
10
- */
11
-
12
- import { fileURLToPath } from 'node:url';
13
- import path from 'node:path';
14
- import fs from 'node:fs';
15
-
16
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
17
- const args = process.argv.slice(2);
18
- const command = args[0];
19
-
20
- // Colors for terminal output
21
- const c = {
22
- reset: '\x1b[0m',
23
- green: '\x1b[32m',
24
- red: '\x1b[31m',
25
- yellow: '\x1b[33m',
26
- blue: '\x1b[34m',
27
- cyan: '\x1b[36m',
28
- bold: '\x1b[1m',
29
- dim: '\x1b[2m'
30
- };
31
-
32
- function log(msg, color = 'reset') {
33
- console.log(`${c[color]}${msg}${c.reset}`);
34
- }
35
-
36
- function printBanner() {
37
- console.log(`
38
- ${c.cyan}╔══════════════════════════════════════════════════════════╗
39
- ║ ║
40
- ║ ${c.bold}OpenClaw-Mem${c.reset}${c.cyan} - Persistent Memory for OpenClaw ║
41
- ║ ║
42
- ╚══════════════════════════════════════════════════════════╝${c.reset}
43
- `);
44
- }
45
-
46
- function printUsage() {
47
- console.log(`
48
- ${c.bold}Usage:${c.reset}
49
- npx openclaw-mem <command>
50
-
51
- ${c.bold}Commands:${c.reset}
52
- ${c.green}init${c.reset} Install openclaw-mem hook to your OpenClaw setup
53
- ${c.green}status${c.reset} Show memory database statistics
54
- ${c.green}search${c.reset} Search your memory (e.g., npx openclaw-mem search "topic")
55
- ${c.green}uninstall${c.reset} Remove openclaw-mem from OpenClaw
56
- ${c.green}help${c.reset} Show this help message
57
-
58
- ${c.bold}Examples:${c.reset}
59
- ${c.dim}# First time setup${c.reset}
60
- npx openclaw-mem init
61
-
62
- ${c.dim}# Check what's stored${c.reset}
63
- npx openclaw-mem status
64
-
65
- ${c.dim}# Search for conversations about AI${c.reset}
66
- npx openclaw-mem search "AI memory"
67
-
68
- ${c.bold}Learn more:${c.reset}
69
- https://github.com/anthropics/openclaw-mem
70
- `);
71
- }
72
-
73
- async function main() {
74
- if (!command || command === 'help' || command === '--help' || command === '-h') {
75
- printBanner();
76
- printUsage();
77
- process.exit(0);
78
- }
79
-
80
- switch (command) {
81
- case 'init': {
82
- const { init } = await import('../scripts/init.js');
83
- await init();
84
- break;
85
- }
86
- case 'status': {
87
- const { status } = await import('../scripts/commands.js');
88
- await status();
89
- break;
90
- }
91
- case 'search': {
92
- const query = args.slice(1).join(' ');
93
- if (!query) {
94
- log('Error: Please provide a search query', 'red');
95
- log('Usage: npx openclaw-mem search "your query"', 'dim');
96
- process.exit(1);
97
- }
98
- const { search } = await import('../scripts/commands.js');
99
- await search(query);
100
- break;
101
- }
102
- case 'uninstall': {
103
- const { uninstall } = await import('../scripts/init.js');
104
- await uninstall();
105
- break;
106
- }
107
- default:
108
- log(`Unknown command: ${command}`, 'red');
109
- printUsage();
110
- process.exit(1);
111
- }
112
- }
113
-
114
- main().catch(err => {
115
- log(`Error: ${err.message}`, 'red');
116
- process.exit(1);
117
- });