universal-memory-mcp 0.2.3 → 0.3.2

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.
Files changed (36) hide show
  1. package/dist/consolidate.d.ts +6 -0
  2. package/dist/consolidate.d.ts.map +1 -0
  3. package/dist/consolidate.js +291 -0
  4. package/dist/consolidate.js.map +1 -0
  5. package/dist/consolidation/deduplicator.d.ts +17 -0
  6. package/dist/consolidation/deduplicator.d.ts.map +1 -0
  7. package/dist/consolidation/deduplicator.js +158 -0
  8. package/dist/consolidation/deduplicator.js.map +1 -0
  9. package/dist/consolidation/extractor.d.ts +36 -0
  10. package/dist/consolidation/extractor.d.ts.map +1 -0
  11. package/dist/consolidation/extractor.js +310 -0
  12. package/dist/consolidation/extractor.js.map +1 -0
  13. package/dist/consolidation/index.d.ts +14 -0
  14. package/dist/consolidation/index.d.ts.map +1 -0
  15. package/dist/consolidation/index.js +14 -0
  16. package/dist/consolidation/index.js.map +1 -0
  17. package/dist/consolidation/scanner.d.ts +27 -0
  18. package/dist/consolidation/scanner.d.ts.map +1 -0
  19. package/dist/consolidation/scanner.js +122 -0
  20. package/dist/consolidation/scanner.js.map +1 -0
  21. package/dist/consolidation/summary-consolidator.d.ts +40 -0
  22. package/dist/consolidation/summary-consolidator.d.ts.map +1 -0
  23. package/dist/consolidation/summary-consolidator.js +342 -0
  24. package/dist/consolidation/summary-consolidator.js.map +1 -0
  25. package/dist/consolidation/updater.d.ts +9 -0
  26. package/dist/consolidation/updater.d.ts.map +1 -0
  27. package/dist/consolidation/updater.js +179 -0
  28. package/dist/consolidation/updater.js.map +1 -0
  29. package/dist/cron.d.ts +6 -0
  30. package/dist/cron.d.ts.map +1 -0
  31. package/dist/cron.js +200 -0
  32. package/dist/cron.js.map +1 -0
  33. package/package.json +5 -3
  34. package/scripts/postinstall.js +231 -6
  35. package/scripts/universal-memory-start-hook.mjs +136 -0
  36. package/scripts/universal-memory-stop-hook.mjs +261 -0
package/dist/cron.js ADDED
@@ -0,0 +1,200 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * universal-memory-cron - 定时任务管理 CLI
4
+ */
5
+ import { execSync, spawnSync } from 'node:child_process';
6
+ import { platform } from 'node:os';
7
+ function printHelp() {
8
+ console.log(`
9
+ universal-memory-cron - 管理长期记忆整理定时任务
10
+
11
+ 使用方法:
12
+ universal-memory-cron <command>
13
+
14
+ 命令:
15
+ install 安装定时任务(每天凌晨 2:00 运行)
16
+ uninstall 卸载定时任务
17
+ status 查看定时任务状态
18
+
19
+ 示例:
20
+ universal-memory-cron install
21
+ universal-memory-cron uninstall
22
+ universal-memory-cron status
23
+
24
+ 说明:
25
+ 此命令用于管理 universal-memory-consolidate 的定时任务。
26
+ 安装后,系统会每天凌晨 2:00 自动运行记忆整理。
27
+
28
+ 支持的系统:macOS, Linux
29
+ Windows 用户请使用 Task Scheduler 手动配置。
30
+ `);
31
+ }
32
+ function getCronJobLine() {
33
+ // 每天凌晨 2:00 运行,整理前一天的对话
34
+ return `0 2 * * * $(which universal-memory-consolidate) --days 1 >> ~/.ai_memory/consolidate.log 2>&1`;
35
+ }
36
+ function getCronMarker() {
37
+ return '# universal-memory-consolidate';
38
+ }
39
+ function installCron() {
40
+ const os = platform();
41
+ if (os === 'win32') {
42
+ console.log('❌ Windows 不支持自动安装 cron 任务');
43
+ console.log('\n请使用 Task Scheduler 手动配置:');
44
+ console.log(' 1. 打开 Task Scheduler');
45
+ console.log(' 2. 创建基本任务');
46
+ console.log(' 3. 触发器:每天 2:00');
47
+ console.log(' 4. 操作:运行 universal-memory-consolidate --days 1');
48
+ return;
49
+ }
50
+ // 检查是否已安装
51
+ try {
52
+ const currentCrontab = execSync('crontab -l 2>/dev/null', { encoding: 'utf-8' });
53
+ if (currentCrontab.includes(getCronMarker())) {
54
+ console.log('ℹ️ 定时任务已存在');
55
+ console.log('\n当前配置:');
56
+ const lines = currentCrontab.split('\n').filter(l => l.includes('universal-memory'));
57
+ lines.forEach(l => console.log(` ${l}`));
58
+ return;
59
+ }
60
+ }
61
+ catch {
62
+ // crontab 为空或不存在
63
+ }
64
+ // 安装新的 cron 任务
65
+ const marker = getCronMarker();
66
+ const cronJob = getCronJobLine();
67
+ const newEntry = `${marker}\n${cronJob}`;
68
+ try {
69
+ // 获取现有 crontab
70
+ let currentCrontab = '';
71
+ try {
72
+ currentCrontab = execSync('crontab -l 2>/dev/null', { encoding: 'utf-8' });
73
+ }
74
+ catch {
75
+ // crontab 为空
76
+ }
77
+ // 添加新任务
78
+ const newCrontab = currentCrontab.trim() + '\n' + newEntry + '\n';
79
+ // 写入 crontab
80
+ const result = spawnSync('crontab', ['-'], {
81
+ input: newCrontab,
82
+ encoding: 'utf-8',
83
+ });
84
+ if (result.status !== 0) {
85
+ throw new Error(result.stderr || 'Unknown error');
86
+ }
87
+ console.log('✅ 定时任务已安装');
88
+ console.log('\n配置详情:');
89
+ console.log(' 时间:每天凌晨 2:00');
90
+ console.log(' 命令:universal-memory-consolidate --days 1');
91
+ console.log(' 日志:~/.ai_memory/consolidate.log');
92
+ console.log('\n查看:crontab -l | grep universal-memory');
93
+ }
94
+ catch (error) {
95
+ console.error('❌ 安装失败:', error.message);
96
+ console.log('\n请尝试手动安装:');
97
+ console.log(' crontab -e');
98
+ console.log(` # 添加以下行:`);
99
+ console.log(` ${cronJob}`);
100
+ }
101
+ }
102
+ function uninstallCron() {
103
+ const os = platform();
104
+ if (os === 'win32') {
105
+ console.log('❌ Windows 请使用 Task Scheduler 手动删除任务');
106
+ return;
107
+ }
108
+ try {
109
+ const currentCrontab = execSync('crontab -l 2>/dev/null', { encoding: 'utf-8' });
110
+ if (!currentCrontab.includes('universal-memory')) {
111
+ console.log('ℹ️ 没有找到相关的定时任务');
112
+ return;
113
+ }
114
+ // 移除相关行
115
+ const newCrontab = currentCrontab
116
+ .split('\n')
117
+ .filter(line => !line.includes('universal-memory'))
118
+ .join('\n');
119
+ // 写入 crontab
120
+ const result = spawnSync('crontab', ['-'], {
121
+ input: newCrontab,
122
+ encoding: 'utf-8',
123
+ });
124
+ if (result.status !== 0) {
125
+ throw new Error(result.stderr || 'Unknown error');
126
+ }
127
+ console.log('✅ 定时任务已卸载');
128
+ }
129
+ catch (error) {
130
+ if (error.message.includes('no crontab')) {
131
+ console.log('ℹ️ 没有找到相关的定时任务');
132
+ }
133
+ else {
134
+ console.error('❌ 卸载失败:', error.message);
135
+ }
136
+ }
137
+ }
138
+ function showStatus() {
139
+ const os = platform();
140
+ if (os === 'win32') {
141
+ console.log('ℹ️ Windows 请使用 Task Scheduler 查看任务状态');
142
+ return;
143
+ }
144
+ try {
145
+ const currentCrontab = execSync('crontab -l 2>/dev/null', { encoding: 'utf-8' });
146
+ const lines = currentCrontab.split('\n').filter(l => l.includes('universal-memory') && !l.startsWith('#'));
147
+ if (lines.length === 0) {
148
+ console.log('ℹ️ 未安装定时任务');
149
+ console.log('\n运行以下命令安装:');
150
+ console.log(' universal-memory-cron install');
151
+ }
152
+ else {
153
+ console.log('✅ 定时任务已安装\n');
154
+ console.log('当前配置:');
155
+ lines.forEach(l => console.log(` ${l}`));
156
+ // 检查日志文件
157
+ try {
158
+ const logTail = execSync('tail -5 ~/.ai_memory/consolidate.log 2>/dev/null', { encoding: 'utf-8' });
159
+ if (logTail.trim()) {
160
+ console.log('\n最近日志:');
161
+ console.log(logTail);
162
+ }
163
+ }
164
+ catch {
165
+ console.log('\n暂无运行日志');
166
+ }
167
+ }
168
+ }
169
+ catch {
170
+ console.log('ℹ️ 未安装定时任务');
171
+ console.log('\n运行以下命令安装:');
172
+ console.log(' universal-memory-cron install');
173
+ }
174
+ }
175
+ function main() {
176
+ const args = process.argv.slice(2);
177
+ const command = args[0];
178
+ switch (command) {
179
+ case 'install':
180
+ installCron();
181
+ break;
182
+ case 'uninstall':
183
+ uninstallCron();
184
+ break;
185
+ case 'status':
186
+ showStatus();
187
+ break;
188
+ case '--help':
189
+ case '-h':
190
+ case undefined:
191
+ printHelp();
192
+ break;
193
+ default:
194
+ console.error(`未知命令: ${command}`);
195
+ console.log('运行 universal-memory-cron --help 查看帮助');
196
+ process.exit(1);
197
+ }
198
+ }
199
+ main();
200
+ //# sourceMappingURL=cron.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cron.js","sourceRoot":"","sources":["../src/cron.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,13 +1,15 @@
1
1
  {
2
2
  "name": "universal-memory-mcp",
3
- "version": "0.2.3",
3
+ "version": "0.3.2",
4
4
  "description": "MCP Server for persistent AI memory across sessions",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",
8
8
  "bin": {
9
9
  "universal-memory-mcp": "./dist/index.js",
10
- "universal-memory-record": "./dist/record.js"
10
+ "universal-memory-record": "./dist/record.js",
11
+ "universal-memory-consolidate": "./dist/consolidate.js",
12
+ "universal-memory-cron": "./dist/cron.js"
11
13
  },
12
14
  "exports": {
13
15
  ".": {
@@ -25,7 +27,7 @@
25
27
  },
26
28
  "dependencies": {
27
29
  "@modelcontextprotocol/sdk": "^1.0.0",
28
- "universal-memory-core": "^0.1.3"
30
+ "universal-memory-core": "^0.1.4"
29
31
  },
30
32
  "devDependencies": {
31
33
  "@types/node": "^20.11.0",
@@ -12,8 +12,10 @@ import fs from 'fs';
12
12
  import path from 'path';
13
13
  import os from 'os';
14
14
 
15
- const CLAUDE_SETTINGS_PATH = path.join(os.homedir(), '.claude', 'settings.json');
16
- const CLAUDE_SKILLS_PATH = path.join(os.homedir(), '.claude', 'skills');
15
+ const CLAUDE_DIR = path.join(os.homedir(), '.claude');
16
+ const CLAUDE_SETTINGS_PATH = path.join(CLAUDE_DIR, 'settings.json');
17
+ const CLAUDE_SKILLS_PATH = path.join(CLAUDE_DIR, 'skills');
18
+ const CLAUDE_HOOKS_PATH = path.join(CLAUDE_DIR, 'hooks');
17
19
 
18
20
  // MCP server configuration
19
21
  const MCP_CONFIG = {
@@ -155,6 +157,21 @@ memory_update_long_term({
155
157
  - Use project name when in project context
156
158
  `;
157
159
 
160
+ /**
161
+ * Check if Claude Code is installed
162
+ */
163
+ function checkClaudeCodeInstalled() {
164
+ if (!fs.existsSync(CLAUDE_DIR)) {
165
+ console.log('\n⚠️ Claude Code not detected!\n');
166
+ console.log('Please install Claude Code first:');
167
+ console.log(' https://code.claude.com/\n');
168
+ console.log('After installing Claude Code, run:');
169
+ console.log(' npm install -g universal-memory-mcp\n');
170
+ return false;
171
+ }
172
+ return true;
173
+ }
174
+
158
175
  /**
159
176
  * Read JSON file safely
160
177
  */
@@ -253,6 +270,184 @@ function installSkill() {
253
270
  return true;
254
271
  }
255
272
 
273
+ /**
274
+ * Install Stop hook script
275
+ */
276
+ function installStopHook() {
277
+ console.log('\n🪝 Installing Stop hook...');
278
+
279
+ const hookScriptPath = path.join(CLAUDE_HOOKS_PATH, 'universal-memory-stop-hook.mjs');
280
+
281
+ // Create hooks directory if not exists
282
+ if (!fs.existsSync(CLAUDE_HOOKS_PATH)) {
283
+ fs.mkdirSync(CLAUDE_HOOKS_PATH, { recursive: true });
284
+ console.log(' Created hooks directory');
285
+ }
286
+
287
+ // Get source script path (in the same directory as this postinstall script)
288
+ const sourceScript = new URL('universal-memory-stop-hook.mjs', import.meta.url).pathname;
289
+
290
+ // Check if hook already exists
291
+ if (fs.existsSync(hookScriptPath)) {
292
+ const existingContent = fs.readFileSync(hookScriptPath, 'utf-8');
293
+ const newContent = fs.readFileSync(sourceScript, 'utf-8');
294
+
295
+ if (existingContent === newContent) {
296
+ console.log(' Stop hook already installed (same version)');
297
+ return false;
298
+ }
299
+
300
+ // Backup existing hook
301
+ const backupPath = `${hookScriptPath}.backup.${Date.now()}`;
302
+ fs.copyFileSync(hookScriptPath, backupPath);
303
+ console.log(` Backed up existing hook to: ${backupPath}`);
304
+ }
305
+
306
+ fs.copyFileSync(sourceScript, hookScriptPath);
307
+ fs.chmodSync(hookScriptPath, 0o755); // Make executable
308
+ console.log(' Stop hook installed successfully');
309
+ return true;
310
+ }
311
+
312
+ /**
313
+ * Install SessionStart hook script
314
+ */
315
+ function installStartHook() {
316
+ console.log('\n🚀 Installing SessionStart hook...');
317
+
318
+ const hookScriptPath = path.join(CLAUDE_HOOKS_PATH, 'universal-memory-start-hook.mjs');
319
+
320
+ // Create hooks directory if not exists
321
+ if (!fs.existsSync(CLAUDE_HOOKS_PATH)) {
322
+ fs.mkdirSync(CLAUDE_HOOKS_PATH, { recursive: true });
323
+ console.log(' Created hooks directory');
324
+ }
325
+
326
+ // Get source script path (in the same directory as this postinstall script)
327
+ const sourceScript = new URL('universal-memory-start-hook.mjs', import.meta.url).pathname;
328
+
329
+ // Check if source exists
330
+ if (!fs.existsSync(sourceScript)) {
331
+ console.log(' Start hook source not found, skipping');
332
+ return false;
333
+ }
334
+
335
+ // Check if hook already exists
336
+ if (fs.existsSync(hookScriptPath)) {
337
+ const existingContent = fs.readFileSync(hookScriptPath, 'utf-8');
338
+ const newContent = fs.readFileSync(sourceScript, 'utf-8');
339
+
340
+ if (existingContent === newContent) {
341
+ console.log(' Start hook already installed (same version)');
342
+ return false;
343
+ }
344
+
345
+ // Backup existing hook
346
+ const backupPath = `${hookScriptPath}.backup.${Date.now()}`;
347
+ fs.copyFileSync(hookScriptPath, backupPath);
348
+ console.log(` Backed up existing hook to: ${backupPath}`);
349
+ }
350
+
351
+ fs.copyFileSync(sourceScript, hookScriptPath);
352
+ fs.chmodSync(hookScriptPath, 0o755); // Make executable
353
+ console.log(' Start hook installed successfully');
354
+ return true;
355
+ }
356
+
357
+ /**
358
+ * Configure Stop hook in Claude settings
359
+ */
360
+ function configureStopHook() {
361
+ console.log('\n⚙️ Configuring Stop hook...');
362
+
363
+ let settings = readJsonFile(CLAUDE_SETTINGS_PATH) || {};
364
+
365
+ // Initialize hooks if not exists
366
+ if (!settings.hooks) {
367
+ settings.hooks = {};
368
+ }
369
+
370
+ // Initialize Stop hook array if not exists
371
+ if (!settings.hooks.Stop) {
372
+ settings.hooks.Stop = [];
373
+ }
374
+
375
+ // Check if our hook is already configured
376
+ const hookScriptPath = path.join(os.homedir(), '.claude', 'hooks', 'universal-memory-stop-hook.mjs');
377
+ const hookCommand = `node ${hookScriptPath}`;
378
+ const alreadyConfigured = settings.hooks.Stop.some(entry =>
379
+ entry.hooks?.some(hook =>
380
+ hook.type === 'command' && hook.command.includes('universal-memory-stop-hook')
381
+ )
382
+ );
383
+
384
+ if (alreadyConfigured) {
385
+ console.log(' Stop hook already configured');
386
+ return false;
387
+ }
388
+
389
+ // Add Stop hook configuration
390
+ settings.hooks.Stop.push({
391
+ hooks: [
392
+ {
393
+ type: 'command',
394
+ command: hookCommand
395
+ }
396
+ ]
397
+ });
398
+
399
+ writeJsonFile(CLAUDE_SETTINGS_PATH, settings);
400
+ console.log(' Stop hook configured successfully');
401
+ return true;
402
+ }
403
+
404
+ /**
405
+ * Configure SessionStart hook in Claude settings
406
+ */
407
+ function configureStartHook() {
408
+ console.log('\n⚙️ Configuring SessionStart hook...');
409
+
410
+ let settings = readJsonFile(CLAUDE_SETTINGS_PATH) || {};
411
+
412
+ // Initialize hooks if not exists
413
+ if (!settings.hooks) {
414
+ settings.hooks = {};
415
+ }
416
+
417
+ // Initialize SessionStart hook array if not exists
418
+ if (!settings.hooks.SessionStart) {
419
+ settings.hooks.SessionStart = [];
420
+ }
421
+
422
+ // Check if our hook is already configured
423
+ const hookScriptPath = path.join(os.homedir(), '.claude', 'hooks', 'universal-memory-start-hook.mjs');
424
+ const hookCommand = `node ${hookScriptPath}`;
425
+ const alreadyConfigured = settings.hooks.SessionStart.some(entry =>
426
+ entry.hooks?.some(hook =>
427
+ hook.type === 'command' && hook.command.includes('universal-memory-start-hook')
428
+ )
429
+ );
430
+
431
+ if (alreadyConfigured) {
432
+ console.log(' SessionStart hook already configured');
433
+ return false;
434
+ }
435
+
436
+ // Add SessionStart hook configuration
437
+ settings.hooks.SessionStart.push({
438
+ hooks: [
439
+ {
440
+ type: 'command',
441
+ command: hookCommand
442
+ }
443
+ ]
444
+ });
445
+
446
+ writeJsonFile(CLAUDE_SETTINGS_PATH, settings);
447
+ console.log(' SessionStart hook configured successfully');
448
+ return true;
449
+ }
450
+
256
451
  /**
257
452
  * Main installation
258
453
  */
@@ -261,26 +456,48 @@ function main() {
261
456
  console.log('║ Universal Memory MCP - Setup ║');
262
457
  console.log('╚════════════════════════════════════════════════════════════╝');
263
458
 
459
+ // Check Claude Code installation
460
+ if (!checkClaudeCodeInstalled()) {
461
+ process.exit(0);
462
+ }
463
+
264
464
  let needsRestart = false;
265
465
 
266
466
  try {
267
- // Configure MCP server
467
+ // 1. Configure MCP server
268
468
  const mcpConfigured = configureMcpServer();
269
469
  if (mcpConfigured) needsRestart = true;
270
470
 
271
- // Install skill
471
+ // 2. Install skill
272
472
  const skillInstalled = installSkill();
273
473
  if (skillInstalled) needsRestart = true;
274
474
 
475
+ // 3. Install Stop hook script
476
+ const stopHookInstalled = installStopHook();
477
+ if (stopHookInstalled) needsRestart = true;
478
+
479
+ // 4. Configure Stop hook
480
+ const stopHookConfigured = configureStopHook();
481
+ if (stopHookConfigured) needsRestart = true;
482
+
483
+ // 5. Install SessionStart hook script
484
+ const startHookInstalled = installStartHook();
485
+ if (startHookInstalled) needsRestart = true;
486
+
487
+ // 6. Configure SessionStart hook
488
+ const startHookConfigured = configureStartHook();
489
+ if (startHookConfigured) needsRestart = true;
490
+
275
491
  // Summary
276
492
  console.log('\n' + '═'.repeat(60));
277
493
 
278
494
  if (needsRestart) {
279
495
  console.log('\n✅ Setup complete!\n');
280
- console.log('⚠️ IMPORTANT: Please restart Claude Code to enable the MCP server.\n');
496
+ console.log('⚠️ IMPORTANT: Please restart Claude Code to enable all features.\n');
281
497
  console.log('After restart, Claude will automatically:');
498
+ console.log(' • Recall your profile at session start (via SessionStart hook)');
282
499
  console.log(' • Search past conversations when you reference them');
283
- console.log(' • Record important conversations for future recall');
500
+ console.log(' • Record EVERY conversation automatically (via Stop hook)');
284
501
  console.log(' • Remember your preferences and decisions\n');
285
502
  } else {
286
503
  console.log('\n✅ Already configured! No changes needed.\n');
@@ -289,8 +506,16 @@ function main() {
289
506
  console.log('📁 Configuration locations:');
290
507
  console.log(` MCP config: ${CLAUDE_SETTINGS_PATH}`);
291
508
  console.log(` Skill: ${path.join(CLAUDE_SKILLS_PATH, 'memory-assistant', 'SKILL.md')}`);
509
+ console.log(` Stop hook: ${path.join(CLAUDE_HOOKS_PATH, 'universal-memory-stop-hook.mjs')}`);
510
+ console.log(` Start hook: ${path.join(CLAUDE_HOOKS_PATH, 'universal-memory-start-hook.mjs')}`);
292
511
  console.log(` Memory storage: ${path.join(os.homedir(), '.ai_memory')}\n`);
293
512
 
513
+ console.log('💡 可选:设置自动整理长期记忆');
514
+ console.log(' # 手动整理最近 7 天的对话');
515
+ console.log(' universal-memory-consolidate --days 7\n');
516
+ console.log(' # 完整整理(包含二次整合)');
517
+ console.log(' universal-memory-consolidate --days 7 --consolidate-summary\n');
518
+
294
519
  } catch (error) {
295
520
  console.error('\n❌ Setup failed:', error.message);
296
521
  console.error('\nPlease configure manually. See README for instructions.');
@@ -0,0 +1,136 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Universal Memory - SessionStart Hook
5
+ *
6
+ * 在会话开始时召回用户画像,注入到会话上下文中。
7
+ *
8
+ * 功能:
9
+ * 1. 读取 profile-summary.md(Level 2 整合摘要)
10
+ * 2. 如果不存在,回退到 profile.md(Level 1 原始条目)
11
+ * 3. 输出用户画像到 stdout,Claude Code 会将其作为系统上下文
12
+ */
13
+
14
+ import fs from 'node:fs';
15
+ import path from 'node:path';
16
+ import os from 'node:os';
17
+
18
+ // Enable debug logging via environment variable
19
+ const DEBUG = process.env.UNIVERSAL_MEMORY_DEBUG === '1';
20
+
21
+ function debugLog(message) {
22
+ if (DEBUG) {
23
+ fs.appendFileSync('/tmp/universal-memory-start-hook.log', `[${new Date().toISOString()}] ${message}\n`);
24
+ }
25
+ }
26
+
27
+ function getMemoryPath() {
28
+ return process.env.MEMORY_PATH || path.join(os.homedir(), '.ai_memory');
29
+ }
30
+
31
+ function readProfileSummary() {
32
+ const memoryPath = getMemoryPath();
33
+ const longTermDir = path.join(memoryPath, 'long_term');
34
+
35
+ // 优先读取 Level 2 整合摘要
36
+ const summaryPath = path.join(longTermDir, 'profile-summary.md');
37
+ if (fs.existsSync(summaryPath)) {
38
+ debugLog(`Reading profile summary from: ${summaryPath}`);
39
+ const content = fs.readFileSync(summaryPath, 'utf-8');
40
+ return { source: 'profile-summary.md', content };
41
+ }
42
+
43
+ // 回退到 Level 1 原始条目
44
+ const profilePath = path.join(longTermDir, 'profile.md');
45
+ if (fs.existsSync(profilePath)) {
46
+ debugLog(`Reading profile from: ${profilePath}`);
47
+ const content = fs.readFileSync(profilePath, 'utf-8');
48
+ return { source: 'profile.md', content };
49
+ }
50
+
51
+ debugLog('No profile found');
52
+ return null;
53
+ }
54
+
55
+ function readKnowledgeSummary() {
56
+ const memoryPath = getMemoryPath();
57
+ const longTermDir = path.join(memoryPath, 'long_term');
58
+
59
+ const summaryPath = path.join(longTermDir, 'knowledge-summary.md');
60
+ if (fs.existsSync(summaryPath)) {
61
+ debugLog(`Reading knowledge summary from: ${summaryPath}`);
62
+ const content = fs.readFileSync(summaryPath, 'utf-8');
63
+ return { source: 'knowledge-summary.md', content };
64
+ }
65
+
66
+ return null;
67
+ }
68
+
69
+ function formatOutput(profile, knowledge) {
70
+ const parts = [];
71
+
72
+ parts.push('<user-memory>');
73
+ parts.push('以下是从长期记忆中召回的用户信息,请在对话中参考:');
74
+ parts.push('');
75
+
76
+ if (profile) {
77
+ parts.push(`<!-- Source: ${profile.source} -->`);
78
+ parts.push(profile.content);
79
+ parts.push('');
80
+ }
81
+
82
+ // 知识库摘要可能太长,只包含前 2000 字符
83
+ if (knowledge) {
84
+ const truncated = knowledge.content.length > 2000
85
+ ? knowledge.content.substring(0, 2000) + '\n\n[... 更多内容请使用 memory_search 查询]'
86
+ : knowledge.content;
87
+ parts.push(`<!-- Source: ${knowledge.source} -->`);
88
+ parts.push(truncated);
89
+ parts.push('');
90
+ }
91
+
92
+ parts.push('</user-memory>');
93
+
94
+ return parts.join('\n');
95
+ }
96
+
97
+ function main() {
98
+ debugLog('Start hook triggered');
99
+
100
+ // 读取 stdin(Claude Code 会传入 hook 输入)
101
+ let hookInput = {};
102
+ try {
103
+ const raw = fs.readFileSync(0, 'utf8');
104
+ if (raw.trim()) {
105
+ hookInput = JSON.parse(raw);
106
+ debugLog(`Hook input: ${JSON.stringify(hookInput).substring(0, 200)}`);
107
+ }
108
+ } catch (err) {
109
+ debugLog(`Failed to parse hook input: ${err.message}`);
110
+ }
111
+
112
+ // 读取用户画像
113
+ const profile = readProfileSummary();
114
+
115
+ // 可选:读取知识库摘要(如果需要的话)
116
+ // const knowledge = readKnowledgeSummary();
117
+ const knowledge = null; // 暂时不包含知识库,避免上下文过长
118
+
119
+ if (!profile && !knowledge) {
120
+ debugLog('No memory to recall, exiting');
121
+ process.exit(0);
122
+ }
123
+
124
+ // 输出到 stdout
125
+ const output = formatOutput(profile, knowledge);
126
+ debugLog(`Output length: ${output.length} chars`);
127
+
128
+ // 输出 JSON 格式,包含要注入的内容
129
+ const result = {
130
+ result: output,
131
+ };
132
+
133
+ console.log(JSON.stringify(result));
134
+ }
135
+
136
+ main();