@n24q02m/mnemo-plugin 1.3.0 → 1.4.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.
Files changed (34) hide show
  1. package/bin/cli.mjs +147 -9
  2. package/build/src/core/memory-service.d.ts +63 -0
  3. package/build/src/core/memory-service.d.ts.map +1 -0
  4. package/build/src/core/memory-service.js +151 -0
  5. package/build/src/core/memory-service.js.map +1 -0
  6. package/build/src/hooks/auto-capture.d.ts +1 -0
  7. package/build/src/hooks/auto-capture.d.ts.map +1 -1
  8. package/build/src/hooks/auto-capture.js +17 -34
  9. package/build/src/hooks/auto-capture.js.map +1 -1
  10. package/build/src/hooks/compaction.d.ts +8 -0
  11. package/build/src/hooks/compaction.d.ts.map +1 -1
  12. package/build/src/hooks/compaction.js +7 -19
  13. package/build/src/hooks/compaction.js.map +1 -1
  14. package/build/src/hooks/system-prompt.d.ts +1 -2
  15. package/build/src/hooks/system-prompt.d.ts.map +1 -1
  16. package/build/src/hooks/system-prompt.js +12 -59
  17. package/build/src/hooks/system-prompt.js.map +1 -1
  18. package/build/src/index.d.ts +8 -7
  19. package/build/src/index.d.ts.map +1 -1
  20. package/build/src/index.js +6 -46
  21. package/build/src/index.js.map +1 -1
  22. package/build/src/platforms/omp/index.d.ts +24 -0
  23. package/build/src/platforms/omp/index.d.ts.map +1 -0
  24. package/build/src/platforms/omp/index.js +74 -0
  25. package/build/src/platforms/omp/index.js.map +1 -0
  26. package/build/src/platforms/opencode/index.d.ts +11 -0
  27. package/build/src/platforms/opencode/index.d.ts.map +1 -0
  28. package/build/src/platforms/opencode/index.js +50 -0
  29. package/build/src/platforms/opencode/index.js.map +1 -0
  30. package/build/src/tools/memory.d.ts.map +1 -1
  31. package/build/src/tools/memory.js +1 -6
  32. package/build/src/tools/memory.js.map +1 -1
  33. package/build/tsconfig.tsbuildinfo +1 -1
  34. package/package.json +5 -2
package/bin/cli.mjs CHANGED
@@ -5,14 +5,145 @@
5
5
  * Modes:
6
6
  * - No args: MCP stdio proxy (spawns uvx mnemo-mcp)
7
7
  * - hook <action>: Execute Claude Code lifecycle hooks
8
+ * - init [--spawn]: Query mnemo-mcp, write/update CLAUDE.md, optionally launch claude
8
9
  */
9
10
  import { spawn, execSync } from 'node:child_process';
11
+ import { writeFileSync, readFileSync, existsSync } from 'node:fs';
12
+ import { resolve } from 'node:path';
10
13
 
11
14
  const args = process.argv.slice(2);
12
15
  const isWindows = process.platform === 'win32';
13
16
 
17
+ // Shared: connect to mnemo-mcp and fetch all memories as markdown
18
+ async function fetchMemoriesMarkdown() {
19
+ const { Client } = await import('@modelcontextprotocol/sdk/client/index.js');
20
+ const { StdioClientTransport } = await import('@modelcontextprotocol/sdk/client/stdio.js');
21
+ const { CallToolResultSchema } = await import('@modelcontextprotocol/sdk/types.js');
22
+
23
+ const transport = new StdioClientTransport({
24
+ command: 'uvx',
25
+ args: ['mnemo-mcp'],
26
+ stderr: 'ignore',
27
+ env: { ...process.env, LOG_LEVEL: 'WARNING' }
28
+ });
29
+
30
+ const client = new Client(
31
+ { name: 'mnemo-plugin-cli', version: '0.0.0' },
32
+ { capabilities: {} }
33
+ );
34
+
35
+ await client.connect(transport);
36
+
37
+ // Fetch stats
38
+ const statsResult = await client.callTool(
39
+ { name: 'memory', arguments: { action: 'stats' } },
40
+ CallToolResultSchema
41
+ );
42
+ const statsText = statsResult.content.find(c => c.type === 'text')?.text;
43
+ const stats = statsText ? JSON.parse(statsText) : { total_memories: 0 };
44
+ const total = stats.total_memories ?? 0;
45
+
46
+ let md = '# Mnemo Memory\n\n';
47
+
48
+ if (total === 0) {
49
+ md += 'No memories stored yet.\n';
50
+ } else {
51
+ const listResult = await client.callTool(
52
+ { name: 'memory', arguments: { action: 'list', limit: 50 } },
53
+ CallToolResultSchema
54
+ );
55
+ const listText = listResult.content.find(c => c.type === 'text')?.text;
56
+ const listData = listText ? JSON.parse(listText) : { results: [] };
57
+ const results = listData.results ?? [];
58
+
59
+ md += '> Auto-generated by mnemo-plugin. ' + total + ' memories found.\n\n';
60
+
61
+ const grouped = {};
62
+ for (const mem of results) {
63
+ const cat = mem.category || 'general';
64
+ if (!grouped[cat]) grouped[cat] = [];
65
+ grouped[cat].push(mem);
66
+ }
67
+
68
+ for (const [category, mems] of Object.entries(grouped)) {
69
+ md += '## ' + category + '\n\n';
70
+ for (const mem of mems) {
71
+ const tags = mem.tags?.length ? ' *(' + mem.tags.join(', ') + ')*' : '';
72
+ md += '- ' + mem.content + tags + '\n';
73
+ }
74
+ md += '\n';
75
+ }
76
+ }
77
+
78
+ await transport.close();
79
+ return md;
80
+ }
81
+
82
+ // Shared: upsert mnemo memory section into CLAUDE.md
83
+ function upsertClaudeMd(markdown, outputPath) {
84
+ const BEGIN = '<!-- BEGIN MNEMO MEMORY -->';
85
+ const END = '<!-- END MNEMO MEMORY -->';
86
+ const directive = "System Directive: You have persistent memory via the 'mnemo' MCP server. Start every new session by running mnemo_search for this project. Save user constraints and preferences with mnemo_remember.";
87
+ const section = BEGIN + '\n' + directive + '\n\n' + markdown + END;
88
+
89
+ const existing = existsSync(outputPath) ? readFileSync(outputPath, 'utf8') : '';
90
+ let finalContent;
91
+
92
+ if (existing.includes(BEGIN)) {
93
+ const start = existing.indexOf(BEGIN);
94
+ const endIdx = existing.indexOf(END);
95
+ if (endIdx !== -1) {
96
+ finalContent = existing.slice(0, start) + section + existing.slice(endIdx + END.length);
97
+ } else {
98
+ finalContent = existing.slice(0, start) + section;
99
+ }
100
+ } else {
101
+ const sep = existing && !existing.endsWith('\n') ? '\n' : '';
102
+ finalContent = existing + sep + '\n' + section + '\n';
103
+ }
104
+
105
+ writeFileSync(outputPath, finalContent, 'utf8');
106
+ }
107
+
108
+ // Init subcommand: export memories to CLAUDE.md
109
+ if (args[0] === 'init') {
110
+ const shouldSpawn = args.includes('--spawn');
111
+ const outputPath = resolve(process.cwd(), 'CLAUDE.md');
112
+
113
+ console.error('[mnemo] Connecting to mnemo-mcp to export memories...');
114
+
115
+ try {
116
+ const markdown = await fetchMemoriesMarkdown();
117
+ upsertClaudeMd(markdown, outputPath);
118
+ console.error('[mnemo] Wrote ' + outputPath);
119
+
120
+ if (shouldSpawn) {
121
+ console.error('[mnemo] Spawning claude...');
122
+ const claude = spawn('claude', [], {
123
+ stdio: 'inherit',
124
+ shell: isWindows,
125
+ cwd: process.cwd()
126
+ });
127
+
128
+ claude.on('error', (err) => {
129
+ console.error('[mnemo] Failed to start claude:', err.message);
130
+ process.exit(1);
131
+ });
132
+
133
+ claude.on('exit', (code) => {
134
+ process.exit(code || 0);
135
+ });
136
+ } else {
137
+ process.exit(0);
138
+ }
139
+ } catch (err) {
140
+ console.error('[mnemo] Init failed:', err.message || err);
141
+ console.error('[mnemo] Make sure mnemo-mcp is available: uv tool install mnemo-mcp');
142
+ process.exit(1);
143
+ }
144
+ }
14
145
  // Hook subcommand
15
- if (args[0] === 'hook') {
146
+ else if (args[0] === 'hook') {
16
147
  const action = args[1];
17
148
  let input = '';
18
149
 
@@ -28,24 +159,31 @@ if (args[0] === 'hook') {
28
159
  const payload = input ? JSON.parse(input) : {};
29
160
 
30
161
  switch (action) {
31
- case 'session-start':
32
- // Health check: verify mnemo-mcp is accessible
162
+ case 'session-start': {
163
+ // Inject memories into CLAUDE.md and output summary to stdout
164
+ const outputPath = resolve(process.cwd(), 'CLAUDE.md');
33
165
  try {
34
- execSync('uvx mnemo-mcp --version', { stdio: 'pipe', timeout: 5000, shell: isWindows });
166
+ const markdown = await fetchMemoriesMarkdown();
167
+ upsertClaudeMd(markdown, outputPath);
168
+ console.error('[mnemo] Updated ' + outputPath + ' with latest memories');
169
+ // Output directive to stdout so Claude Code may inject into context
170
+ process.stdout.write("System Directive: You have persistent memory via the 'mnemo' MCP server. Use mnemo_search, mnemo_remember, mnemo_forget tools proactively.\n");
35
171
  process.exit(0);
36
- } catch {
37
- console.error('[mnemo] Warning: mnemo-mcp not available. Install with: uv tool install mnemo-mcp');
38
- process.exit(1); // Non-blocking warning
172
+ } catch (err) {
173
+ console.error('[mnemo] Warning: session-start failed:', err.message || err);
174
+ console.error('[mnemo] Make sure mnemo-mcp is available: uv tool install mnemo-mcp');
175
+ process.exit(0); // Non-fatal: allow session to continue
39
176
  }
40
177
  break;
178
+ }
41
179
 
42
180
  case 'stop':
43
- // No-op for now: Claude handles memory via MCP tools during session
181
+ // No-op: Claude handles memory via MCP tools during session
44
182
  process.exit(0);
45
183
  break;
46
184
 
47
185
  case 'pre-compact':
48
- // No-op for now: memories are already persisted in mnemo-mcp
186
+ // No-op: memories are already persisted in mnemo-mcp
49
187
  process.exit(0);
50
188
  break;
51
189
 
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Core Memory Service
3
+ *
4
+ * Platform-agnostic business logic for the mnemo memory system.
5
+ * Extracted from hooks to enable universal adapter architecture:
6
+ * budgeting, regex parsing, MCP communication orchestration.
7
+ *
8
+ * All platforms (OpenCode, OMP, Claude Code CLI) import from here
9
+ * to avoid duplicating logic across adapters.
10
+ */
11
+ import type { MnemoBridge } from '../bridge.js';
12
+ /** Memory item returned from mnemo-mcp search */
13
+ export interface MemoryResult {
14
+ id: string;
15
+ category: string;
16
+ content: string;
17
+ tags?: string[];
18
+ }
19
+ /** Maximum percentage of context window to use for memory injection */
20
+ export declare const BUDGET_PERCENT = 0.025;
21
+ /** Budget bounds in characters */
22
+ export declare const MIN_BUDGET = 600;
23
+ export declare const MAX_BUDGET = 8000;
24
+ /** Minimum idle time before processing buffer (60 seconds) */
25
+ export declare const IDLE_THRESHOLD = 60000;
26
+ /** Maximum content length to store per auto-capture */
27
+ export declare const MAX_CAPTURE_LENGTH = 500;
28
+ /** Regex to detect constraint-like user statements */
29
+ export declare const CONSTRAINT_REGEX: RegExp;
30
+ /** Self-awareness block always injected (tells agent about available memory tools) */
31
+ export declare const SELF_AWARENESS = "You have persistent memory via the Mnemo system. You can use:\n- mnemo_search: Search stored memories, facts, preferences, decisions\n- mnemo_remember: Permanently store new facts, rules, preferences\n- mnemo_forget: Delete outdated or incorrect memories\nProactively search memory when entering a new codebase or when the user asks about past decisions.";
32
+ /** Compaction preservation instruction (always included during context compaction) */
33
+ export declare const COMPACTION_INSTRUCTION = "When summarizing this session, explicitly preserve any user preferences, technical constraints, architectural decisions, or project rules that were discussed. These should be saved to persistent memory if not already stored.";
34
+ /** Extract project name from directory path (cross-platform) */
35
+ export declare function getProjectName(directory: string): string;
36
+ /** Compute injection budget based on model context limit */
37
+ export declare function computeBudget(contextLimit: number | undefined): number;
38
+ /** Truncate text to fit within character budget */
39
+ export declare function truncateToFit(text: string, budget: number): string;
40
+ /** Simple string hash for deduplication */
41
+ export declare function hashContent(content: string): string;
42
+ /**
43
+ * Build memory context injection string for system prompt.
44
+ * Searches memories by project name and formats within budget.
45
+ * Returns null if no memories found.
46
+ */
47
+ export declare function buildMemoryContext(bridge: MnemoBridge, projectName: string, budget: number): Promise<string | null>;
48
+ /**
49
+ * Capture constraint-like content and store in mnemo-mcp.
50
+ * Returns true if content was captured, false if skipped (no constraint detected).
51
+ */
52
+ export declare function captureConstraint(bridge: MnemoBridge, content: string, projectName: string): Promise<boolean>;
53
+ /**
54
+ * Fetch memories for compaction context preservation.
55
+ * Returns formatted memory string, or null if none found.
56
+ */
57
+ export declare function fetchCompactionMemories(bridge: MnemoBridge): Promise<string | null>;
58
+ /**
59
+ * Search all memories and format as markdown for .claude_memory.md export.
60
+ * Groups memories by category for readability.
61
+ */
62
+ export declare function exportMemoriesAsMarkdown(bridge: MnemoBridge): Promise<string>;
63
+ //# sourceMappingURL=memory-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory-service.d.ts","sourceRoot":"","sources":["../../../src/core/memory-service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAE/C,iDAAiD;AACjD,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAA;IACV,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;CAChB;AAED,uEAAuE;AACvE,eAAO,MAAM,cAAc,QAAQ,CAAA;AAEnC,kCAAkC;AAClC,eAAO,MAAM,UAAU,MAAM,CAAA;AAC7B,eAAO,MAAM,UAAU,OAAO,CAAA;AAE9B,8DAA8D;AAC9D,eAAO,MAAM,cAAc,QAAS,CAAA;AAEpC,uDAAuD;AACvD,eAAO,MAAM,kBAAkB,MAAM,CAAA;AAErC,sDAAsD;AACtD,eAAO,MAAM,gBAAgB,QAAqF,CAAA;AAElH,sFAAsF;AACtF,eAAO,MAAM,cAAc,uWAIwE,CAAA;AAEnG,sFAAsF;AACtF,eAAO,MAAM,sBAAsB,qOACiM,CAAA;AAEpO,gEAAgE;AAChE,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAIxD;AAED,4DAA4D;AAC5D,wBAAgB,aAAa,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAKtE;AAED,mDAAmD;AACnD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAGlE;AAED,2CAA2C;AAC3C,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAOnD;AAED;;;;GAIG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,WAAW,EACnB,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA6BxB;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAanH;AAED;;;GAGG;AACH,wBAAsB,uBAAuB,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAYzF;AAED;;;GAGG;AACH,wBAAsB,wBAAwB,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CA8BnF"}
@@ -0,0 +1,151 @@
1
+ /**
2
+ * Core Memory Service
3
+ *
4
+ * Platform-agnostic business logic for the mnemo memory system.
5
+ * Extracted from hooks to enable universal adapter architecture:
6
+ * budgeting, regex parsing, MCP communication orchestration.
7
+ *
8
+ * All platforms (OpenCode, OMP, Claude Code CLI) import from here
9
+ * to avoid duplicating logic across adapters.
10
+ */
11
+ /** Maximum percentage of context window to use for memory injection */
12
+ export const BUDGET_PERCENT = 0.025;
13
+ /** Budget bounds in characters */
14
+ export const MIN_BUDGET = 600;
15
+ export const MAX_BUDGET = 8000;
16
+ /** Minimum idle time before processing buffer (60 seconds) */
17
+ export const IDLE_THRESHOLD = 60_000;
18
+ /** Maximum content length to store per auto-capture */
19
+ export const MAX_CAPTURE_LENGTH = 500;
20
+ /** Regex to detect constraint-like user statements */
21
+ export const CONSTRAINT_REGEX = /\b(always|never|must|prefer|don't|do not|should not|make sure|ensure|require)\b/i;
22
+ /** Self-awareness block always injected (tells agent about available memory tools) */
23
+ export const SELF_AWARENESS = `You have persistent memory via the Mnemo system. You can use:
24
+ - mnemo_search: Search stored memories, facts, preferences, decisions
25
+ - mnemo_remember: Permanently store new facts, rules, preferences
26
+ - mnemo_forget: Delete outdated or incorrect memories
27
+ Proactively search memory when entering a new codebase or when the user asks about past decisions.`;
28
+ /** Compaction preservation instruction (always included during context compaction) */
29
+ export const COMPACTION_INSTRUCTION = 'When summarizing this session, explicitly preserve any user preferences, technical constraints, architectural decisions, or project rules that were discussed. These should be saved to persistent memory if not already stored.';
30
+ /** Extract project name from directory path (cross-platform) */
31
+ export function getProjectName(directory) {
32
+ const cleanDir = directory.replace(/\\/g, '/');
33
+ const parts = cleanDir.split('/');
34
+ return parts[parts.length - 1] || 'unknown';
35
+ }
36
+ /** Compute injection budget based on model context limit */
37
+ export function computeBudget(contextLimit) {
38
+ if (!contextLimit || contextLimit <= 0)
39
+ return MIN_BUDGET;
40
+ const budget = Math.floor(contextLimit * BUDGET_PERCENT * 4); // ~4 chars per token
41
+ return Math.max(MIN_BUDGET, Math.min(MAX_BUDGET, budget));
42
+ }
43
+ /** Truncate text to fit within character budget */
44
+ export function truncateToFit(text, budget) {
45
+ if (text.length <= budget)
46
+ return text;
47
+ return `${text.slice(0, budget - 3)}...`;
48
+ }
49
+ /** Simple string hash for deduplication */
50
+ export function hashContent(content) {
51
+ let hash = 0;
52
+ for (let i = 0; i < content.length; i++) {
53
+ const char = content.charCodeAt(i);
54
+ hash = ((hash << 5) - hash + char) | 0;
55
+ }
56
+ return hash.toString(36);
57
+ }
58
+ /**
59
+ * Build memory context injection string for system prompt.
60
+ * Searches memories by project name and formats within budget.
61
+ * Returns null if no memories found.
62
+ */
63
+ export async function buildMemoryContext(bridge, projectName, budget) {
64
+ const searchRes = await bridge.callTool('memory', {
65
+ action: 'search',
66
+ query: projectName,
67
+ limit: 10
68
+ });
69
+ if (!searchRes || !searchRes.count || searchRes.count === 0)
70
+ return null;
71
+ const results = searchRes.results;
72
+ let injection = `[Mnemo Context for "${projectName}"]\n`;
73
+ let usedBudget = injection.length;
74
+ for (const mem of results) {
75
+ const line = `- [${mem.category}] ${mem.content}\n`;
76
+ if (usedBudget + line.length > budget) {
77
+ // Try to fit a truncated version
78
+ const remaining = budget - usedBudget;
79
+ if (remaining > 20) {
80
+ injection += truncateToFit(line, remaining);
81
+ }
82
+ break;
83
+ }
84
+ injection += line;
85
+ usedBudget += line.length;
86
+ }
87
+ return injection;
88
+ }
89
+ /**
90
+ * Capture constraint-like content and store in mnemo-mcp.
91
+ * Returns true if content was captured, false if skipped (no constraint detected).
92
+ */
93
+ export async function captureConstraint(bridge, content, projectName) {
94
+ if (!CONSTRAINT_REGEX.test(content))
95
+ return false;
96
+ const trimmedContent = content.length > MAX_CAPTURE_LENGTH ? `${content.slice(0, MAX_CAPTURE_LENGTH)}...` : content;
97
+ await bridge.callTool('memory', {
98
+ action: 'add',
99
+ content: `[Auto-captured for ${projectName}]: ${trimmedContent}`,
100
+ category: 'auto-capture',
101
+ tags: [projectName, 'preference']
102
+ });
103
+ return true;
104
+ }
105
+ /**
106
+ * Fetch memories for compaction context preservation.
107
+ * Returns formatted memory string, or null if none found.
108
+ */
109
+ export async function fetchCompactionMemories(bridge) {
110
+ const statsRes = await bridge.callTool('memory', { action: 'stats' });
111
+ const totalMemories = statsRes?.total_memories ?? 0;
112
+ if (totalMemories === 0)
113
+ return null;
114
+ const listRes = await bridge.callTool('memory', { action: 'list', limit: 10 });
115
+ if (!listRes?.results?.length)
116
+ return null;
117
+ const memories = listRes.results.map((m) => `- [${m.category}] ${m.content}`).join('\n');
118
+ return `[Mnemo Persistent Memory - Preserve These]\nThe following facts and preferences are stored in persistent memory and must be preserved:\n${memories}`;
119
+ }
120
+ /**
121
+ * Search all memories and format as markdown for .claude_memory.md export.
122
+ * Groups memories by category for readability.
123
+ */
124
+ export async function exportMemoriesAsMarkdown(bridge) {
125
+ const statsRes = await bridge.callTool('memory', { action: 'stats' });
126
+ const total = statsRes?.total_memories ?? 0;
127
+ if (total === 0)
128
+ return '# Mnemo Memory\n\nNo memories stored yet.\n';
129
+ const listRes = await bridge.callTool('memory', { action: 'list', limit: 50 });
130
+ const results = (listRes?.results ?? []);
131
+ let md = '# Mnemo Memory\n\n';
132
+ md += `> Auto-generated by mnemo-plugin. ${total} memories found.\n\n`;
133
+ // Group by category
134
+ const grouped = new Map();
135
+ for (const mem of results) {
136
+ const cat = mem.category || 'general';
137
+ if (!grouped.has(cat))
138
+ grouped.set(cat, []);
139
+ grouped.get(cat).push(mem);
140
+ }
141
+ for (const [category, mems] of grouped) {
142
+ md += `## ${category}\n\n`;
143
+ for (const mem of mems) {
144
+ const tags = mem.tags?.length ? ` *(${mem.tags.join(', ')})*` : '';
145
+ md += `- ${mem.content}${tags}\n`;
146
+ }
147
+ md += '\n';
148
+ }
149
+ return md;
150
+ }
151
+ //# sourceMappingURL=memory-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory-service.js","sourceRoot":"","sources":["../../../src/core/memory-service.ts"],"names":[],"mappings":"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"}
@@ -6,6 +6,7 @@
6
6
  * constraints are stored as auto-captured rules in mnemo-mcp.
7
7
  *
8
8
  * Uses a content hash to prevent duplicate captures within the same session.
9
+ * Core detection + storage logic delegated to memory-service.
9
10
  */
10
11
  import type { Event } from '@opencode-ai/sdk';
11
12
  /** Chat message hook: buffer user text parts */
@@ -1 +1 @@
1
- {"version":3,"file":"auto-capture.d.ts","sourceRoot":"","sources":["../../../src/hooks/auto-capture.ts"],"names":[],"mappings":"AACA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AAsC7C,gDAAgD;AAChD,eAAO,MAAM,WAAW,GAAU,QAAQ,OAAO,EAAE,QAAQ;IAAE,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CAAE,kBAUtG,CAAA;AAED,iDAAiD;AACjD,eAAO,MAAM,eAAe,GAAU,OAAO;IAAE,KAAK,EAAE,KAAK,CAAA;CAAE,EAAE,WAAW,MAAM,kBAS/E,CAAA"}
1
+ {"version":3,"file":"auto-capture.d.ts","sourceRoot":"","sources":["../../../src/hooks/auto-capture.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AAc7C,gDAAgD;AAChD,eAAO,MAAM,WAAW,GAAU,QAAQ,OAAO,EAAE,QAAQ;IAAE,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CAAE,kBAUtG,CAAA;AAED,iDAAiD;AACjD,eAAO,MAAM,eAAe,GAAU,OAAO;IAAE,KAAK,EAAE,KAAK,CAAA;CAAE,EAAE,WAAW,MAAM,kBAS/E,CAAA"}
@@ -1,32 +1,22 @@
1
- import { logger } from '../logger.js';
1
+ /**
2
+ * Auto-Capture Hook
3
+ *
4
+ * Buffers user messages from chat and extracts constraint-like patterns
5
+ * (always/never/must/prefer/don't) when the session goes idle. Captured
6
+ * constraints are stored as auto-captured rules in mnemo-mcp.
7
+ *
8
+ * Uses a content hash to prevent duplicate captures within the same session.
9
+ * Core detection + storage logic delegated to memory-service.
10
+ */
2
11
  import { MnemoBridge } from '../bridge.js';
12
+ import { captureConstraint, getProjectName, hashContent, IDLE_THRESHOLD } from '../core/memory-service.js';
13
+ import { logger } from '../logger.js';
3
14
  /** Buffer of user message texts accumulated during the session */
4
15
  const sessionBuffer = [];
5
16
  /** Set of content hashes already captured this session (dedup) */
6
17
  const capturedHashes = new Set();
7
18
  /** Timestamp of last capture to enforce cooldown */
8
19
  let lastCaptureTime = 0;
9
- /** Minimum idle time before processing buffer (60 seconds) */
10
- const IDLE_THRESHOLD = 60_000;
11
- /** Maximum content length to store per auto-capture */
12
- const MAX_CAPTURE_LENGTH = 500;
13
- /** Regex to detect constraint-like user statements */
14
- const CONSTRAINT_REGEX = /\b(always|never|must|prefer|don't|do not|should not|make sure|ensure|require)\b/i;
15
- /** Simple string hash for deduplication */
16
- function hashContent(content) {
17
- let hash = 0;
18
- for (let i = 0; i < content.length; i++) {
19
- const char = content.charCodeAt(i);
20
- hash = ((hash << 5) - hash + char) | 0;
21
- }
22
- return hash.toString(36);
23
- }
24
- /** Extract project name from directory path */
25
- function getProjectName(directory) {
26
- const cleanDir = directory.replace(/\\/g, '/');
27
- const parts = cleanDir.split('/');
28
- return parts[parts.length - 1] || 'unknown';
29
- }
30
20
  /** Chat message hook: buffer user text parts */
31
21
  export const messageHook = async (_input, output) => {
32
22
  const userText = output.parts
@@ -60,22 +50,15 @@ async function processCapture(directory) {
60
50
  const projectName = getProjectName(directory);
61
51
  const content = sessionBuffer.join('\n');
62
52
  sessionBuffer.length = 0;
63
- // Only capture if content looks like a constraint/preference
64
- if (!CONSTRAINT_REGEX.test(content))
65
- return;
66
53
  // Dedup check
67
54
  const hash = hashContent(content);
68
55
  if (capturedHashes.has(hash))
69
56
  return;
70
- capturedHashes.add(hash);
71
- const trimmedContent = content.length > MAX_CAPTURE_LENGTH ? `${content.slice(0, MAX_CAPTURE_LENGTH)}...` : content;
72
- await bridge.callTool('memory', {
73
- action: 'add',
74
- content: `[Auto-captured for ${projectName}]: ${trimmedContent}`,
75
- category: 'auto-capture',
76
- tags: [projectName, 'preference']
77
- });
78
- logger.info(`[Mnemo] Auto-captured a new rule for ${projectName}`);
57
+ const captured = await captureConstraint(bridge, content, projectName);
58
+ if (captured) {
59
+ capturedHashes.add(hash);
60
+ logger.info(`[Mnemo] Auto-captured a new rule for ${projectName}`);
61
+ }
79
62
  }
80
63
  catch (error) {
81
64
  logger.error(`[Mnemo] Error in auto-capture: ${error}`);
@@ -1 +1 @@
1
- {"version":3,"file":"auto-capture.js","sourceRoot":"","sources":["../../../src/hooks/auto-capture.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"auto-capture.js","sourceRoot":"","sources":["../../../src/hooks/auto-capture.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC1C,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAA;AAC1G,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAErC,kEAAkE;AAClE,MAAM,aAAa,GAAa,EAAE,CAAA;AAElC,kEAAkE;AAClE,MAAM,cAAc,GAAG,IAAI,GAAG,EAAU,CAAA;AAExC,oDAAoD;AACpD,IAAI,eAAe,GAAG,CAAC,CAAA;AAEvB,gDAAgD;AAChD,MAAM,CAAC,MAAM,WAAW,GAAG,KAAK,EAAE,MAAe,EAAE,MAAoD,EAAE,EAAE;IACzG,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK;SAC1B,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,CAAC,IAAI,CAAC;SAC1C,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAc,CAAC;SAC5B,IAAI,CAAC,IAAI,CAAC;SACV,IAAI,EAAE,CAAA;IAET,IAAI,QAAQ,EAAE,CAAC;QACb,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;IAC9B,CAAC;AACH,CAAC,CAAA;AAED,iDAAiD;AACjD,MAAM,CAAC,MAAM,eAAe,GAAG,KAAK,EAAE,KAAuB,EAAE,SAAiB,EAAE,EAAE;IAClF,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,KAAK,cAAc;QAAE,OAAM;IAE/C,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;IACtB,IAAI,GAAG,GAAG,eAAe,IAAI,cAAc;QAAE,OAAM;IACnD,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC;QAAE,OAAM;IAEtC,MAAM,cAAc,CAAC,SAAS,CAAC,CAAA;IAC/B,eAAe,GAAG,GAAG,CAAA;AACvB,CAAC,CAAA;AAED,wEAAwE;AACxE,KAAK,UAAU,cAAc,CAAC,SAAiB;IAC7C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,WAAW,CAAC,WAAW,EAAE,CAAA;QAExC,uDAAuD;QACvD,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE;YAAE,OAAM;QAEjC,MAAM,WAAW,GAAG,cAAc,CAAC,SAAS,CAAC,CAAA;QAE7C,MAAM,OAAO,GAAG,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACxC,aAAa,CAAC,MAAM,GAAG,CAAC,CAAA;QAExB,cAAc;QACd,MAAM,IAAI,GAAG,WAAW,CAAC,OAAO,CAAC,CAAA;QACjC,IAAI,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,OAAM;QAEpC,MAAM,QAAQ,GAAG,MAAM,iBAAiB,CAAC,MAAM,EAAE,OAAO,EAAE,WAAW,CAAC,CAAA;QACtE,IAAI,QAAQ,EAAE,CAAC;YACb,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;YACxB,MAAM,CAAC,IAAI,CAAC,wCAAwC,WAAW,EAAE,CAAC,CAAA;QACpE,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,KAAK,CAAC,kCAAkC,KAAK,EAAE,CAAC,CAAA;IACzD,CAAC;AACH,CAAC"}
@@ -1,3 +1,11 @@
1
+ /**
2
+ * Compaction Hook
3
+ *
4
+ * When OpenCode compacts the session context window, this hook injects
5
+ * relevant memories into the compaction context so they survive the
6
+ * summarization process. This prevents memory loss across long sessions.
7
+ * Core fetch logic delegated to memory-service.
8
+ */
1
9
  export declare const compactionHook: (_input: {
2
10
  sessionID: string;
3
11
  }, output: {
@@ -1 +1 @@
1
- {"version":3,"file":"compaction.d.ts","sourceRoot":"","sources":["../../../src/hooks/compaction.ts"],"names":[],"mappings":"AAiBA,eAAO,MAAM,cAAc,GAAU,QAAQ;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,EAAE,QAAQ;IAAE,OAAO,EAAE,MAAM,EAAE,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,kBAqCjH,CAAA"}
1
+ {"version":3,"file":"compaction.d.ts","sourceRoot":"","sources":["../../../src/hooks/compaction.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,eAAO,MAAM,cAAc,GAAU,QAAQ;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,EAAE,QAAQ;IAAE,OAAO,EAAE,MAAM,EAAE,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,kBAcjH,CAAA"}
@@ -1,36 +1,24 @@
1
- import { logger } from '../logger.js';
2
1
  /**
3
2
  * Compaction Hook
4
3
  *
5
4
  * When OpenCode compacts the session context window, this hook injects
6
5
  * relevant memories into the compaction context so they survive the
7
6
  * summarization process. This prevents memory loss across long sessions.
7
+ * Core fetch logic delegated to memory-service.
8
8
  */
9
9
  import { MnemoBridge } from '../bridge.js';
10
+ import { COMPACTION_INSTRUCTION, fetchCompactionMemories } from '../core/memory-service.js';
11
+ import { logger } from '../logger.js';
10
12
  export const compactionHook = async (_input, output) => {
11
13
  try {
12
14
  const bridge = MnemoBridge.getInstance();
13
15
  // Skip if bridge is unavailable (circuit breaker open)
14
16
  if (!bridge.isAvailable())
15
17
  return;
16
- // Fetch recent/important memories to preserve during compaction
17
- const statsRes = await bridge.callTool('memory', {
18
- action: 'stats'
19
- });
20
- const totalMemories = statsRes?.total_memories ?? 0;
21
- if (totalMemories > 0) {
22
- // Load top memories to include in compaction context
23
- const listRes = await bridge.callTool('memory', {
24
- action: 'list',
25
- limit: 10
26
- });
27
- if (listRes?.results?.length > 0) {
28
- const memories = listRes.results.map((m) => `- [${m.category}] ${m.content}`).join('\n');
29
- output.context.push(`[Mnemo Persistent Memory - Preserve These]\nThe following facts and preferences are stored in persistent memory and must be preserved:\n${memories}`);
30
- }
31
- }
32
- // Always add instruction to preserve preferences during summarization
33
- output.context.push('When summarizing this session, explicitly preserve any user preferences, technical constraints, architectural decisions, or project rules that were discussed. These should be saved to persistent memory if not already stored.');
18
+ const memoryContext = await fetchCompactionMemories(bridge);
19
+ if (memoryContext)
20
+ output.context.push(memoryContext);
21
+ output.context.push(COMPACTION_INSTRUCTION);
34
22
  }
35
23
  catch (error) {
36
24
  logger.error(`[Mnemo] Error in compaction hook: ${error}`);
@@ -1 +1 @@
1
- {"version":3,"file":"compaction.js","sourceRoot":"","sources":["../../../src/hooks/compaction.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AACrC;;;;;;GAMG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAQ1C,MAAM,CAAC,MAAM,cAAc,GAAG,KAAK,EAAE,MAA6B,EAAE,MAA8C,EAAE,EAAE;IACpH,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,WAAW,CAAC,WAAW,EAAE,CAAA;QAExC,uDAAuD;QACvD,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE;YAAE,OAAM;QAEjC,gEAAgE;QAChE,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,QAAQ,EAAE;YAC/C,MAAM,EAAE,OAAO;SAChB,CAAC,CAAA;QAEF,MAAM,aAAa,GAAG,QAAQ,EAAE,cAAc,IAAI,CAAC,CAAA;QAEnD,IAAI,aAAa,GAAG,CAAC,EAAE,CAAC;YACtB,qDAAqD;YACrD,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,QAAQ,EAAE;gBAC9C,MAAM,EAAE,MAAM;gBACd,KAAK,EAAE,EAAE;aACV,CAAC,CAAA;YAEF,IAAI,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,CAAC,EAAE,CAAC;gBACjC,MAAM,QAAQ,GAAI,OAAO,CAAC,OAA0B,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;gBAE5G,MAAM,CAAC,OAAO,CAAC,IAAI,CACjB,2IAA2I,QAAQ,EAAE,CACtJ,CAAA;YACH,CAAC;QACH,CAAC;QAED,sEAAsE;QACtE,MAAM,CAAC,OAAO,CAAC,IAAI,CACjB,kOAAkO,CACnO,CAAA;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,KAAK,CAAC,qCAAqC,KAAK,EAAE,CAAC,CAAA;IAC5D,CAAC;AACH,CAAC,CAAA"}
1
+ {"version":3,"file":"compaction.js","sourceRoot":"","sources":["../../../src/hooks/compaction.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC1C,OAAO,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAA;AAC3F,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAErC,MAAM,CAAC,MAAM,cAAc,GAAG,KAAK,EAAE,MAA6B,EAAE,MAA8C,EAAE,EAAE;IACpH,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,WAAW,CAAC,WAAW,EAAE,CAAA;QAExC,uDAAuD;QACvD,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE;YAAE,OAAM;QAEjC,MAAM,aAAa,GAAG,MAAM,uBAAuB,CAAC,MAAM,CAAC,CAAA;QAC3D,IAAI,aAAa;YAAE,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC,CAAA;QAErD,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAA;IAC7C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,KAAK,CAAC,qCAAqC,KAAK,EAAE,CAAC,CAAA;IAC5D,CAAC;AACH,CAAC,CAAA"}
@@ -2,8 +2,7 @@
2
2
  * System Prompt Hook
3
3
  *
4
4
  * Injects relevant memories into the system prompt using adaptive budget
5
- * based on the model's context window. Inspired by minzique-plugin's
6
- * tiered priority injection system.
5
+ * based on the model's context window. Delegates core logic to memory-service.
7
6
  */
8
7
  import type { Model } from '@opencode-ai/sdk';
9
8
  export declare const systemPromptHook: (input: {
@@ -1 +1 @@
1
- {"version":3,"file":"system-prompt.d.ts","sourceRoot":"","sources":["../../../src/hooks/system-prompt.ts"],"names":[],"mappings":"AACA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AA+C7C,eAAO,MAAM,gBAAgB,GAC3B,OAAO;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,KAAK,CAAA;CAAE,EAC3C,QAAQ;IAAE,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,EAC5B,WAAW,MAAM,kBA+ClB,CAAA"}
1
+ {"version":3,"file":"system-prompt.d.ts","sourceRoot":"","sources":["../../../src/hooks/system-prompt.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AAK7C,eAAO,MAAM,gBAAgB,GAC3B,OAAO;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,KAAK,CAAA;CAAE,EAC3C,QAAQ;IAAE,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,EAC5B,WAAW,MAAM,kBAmBlB,CAAA"}