@bluehawks/cli 1.0.2 → 1.0.4

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 (49) hide show
  1. package/.bluehawks/history.json +11 -0
  2. package/dist/config/constants.d.ts +1 -1
  3. package/dist/config/constants.js +1 -1
  4. package/dist/core/agents/orchestrator.d.ts +2 -0
  5. package/dist/core/agents/orchestrator.d.ts.map +1 -1
  6. package/dist/core/agents/orchestrator.js +30 -1
  7. package/dist/core/agents/orchestrator.js.map +1 -1
  8. package/dist/core/api/client.d.ts +5 -1
  9. package/dist/core/api/client.d.ts.map +1 -1
  10. package/dist/core/api/client.js +10 -0
  11. package/dist/core/api/client.js.map +1 -1
  12. package/dist/core/api/types.d.ts +19 -0
  13. package/dist/core/api/types.d.ts.map +1 -1
  14. package/dist/core/api/types.js.map +1 -1
  15. package/dist/core/memory/index.d.ts +4 -0
  16. package/dist/core/memory/index.d.ts.map +1 -0
  17. package/dist/core/memory/index.js +4 -0
  18. package/dist/core/memory/index.js.map +1 -0
  19. package/dist/core/memory/manager.d.ts +29 -0
  20. package/dist/core/memory/manager.d.ts.map +1 -0
  21. package/dist/core/memory/manager.js +106 -0
  22. package/dist/core/memory/manager.js.map +1 -0
  23. package/dist/core/memory/storage.d.ts +15 -0
  24. package/dist/core/memory/storage.d.ts.map +1 -0
  25. package/dist/core/memory/storage.js +77 -0
  26. package/dist/core/memory/storage.js.map +1 -0
  27. package/dist/core/memory/types.d.ts +20 -0
  28. package/dist/core/memory/types.d.ts.map +1 -0
  29. package/dist/core/memory/types.js +2 -0
  30. package/dist/core/memory/types.js.map +1 -0
  31. package/dist/core/tools/definitions/index.d.ts +1 -0
  32. package/dist/core/tools/definitions/index.d.ts.map +1 -1
  33. package/dist/core/tools/definitions/index.js +3 -0
  34. package/dist/core/tools/definitions/index.js.map +1 -1
  35. package/dist/core/tools/definitions/memory.d.ts +2 -0
  36. package/dist/core/tools/definitions/memory.d.ts.map +1 -0
  37. package/dist/core/tools/definitions/memory.js +155 -0
  38. package/dist/core/tools/definitions/memory.js.map +1 -0
  39. package/package.json +3 -1
  40. package/src/config/constants.ts +1 -1
  41. package/src/core/agents/orchestrator.ts +33 -2
  42. package/src/core/api/client.ts +17 -0
  43. package/src/core/api/types.ts +23 -0
  44. package/src/core/memory/index.ts +3 -0
  45. package/src/core/memory/manager.ts +120 -0
  46. package/src/core/memory/storage.ts +90 -0
  47. package/src/core/memory/types.ts +22 -0
  48. package/src/core/tools/definitions/index.ts +3 -0
  49. package/src/core/tools/definitions/memory.ts +171 -0
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/core/tools/definitions/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAE5C,MAAM,UAAU,gBAAgB;IAC5B,iBAAiB,EAAE,CAAC;IACpB,kBAAkB,EAAE,CAAC;IACrB,mBAAmB,EAAE,CAAC;IACtB,gBAAgB,EAAE,CAAC;IACnB,gBAAgB,EAAE,CAAC;AACvB,CAAC;AAED,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/core/tools/definitions/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAElD,MAAM,UAAU,gBAAgB;IAC5B,iBAAiB,EAAE,CAAC;IACpB,kBAAkB,EAAE,CAAC;IACrB,mBAAmB,EAAE,CAAC;IACtB,gBAAgB,EAAE,CAAC;IACnB,gBAAgB,EAAE,CAAC;IACnB,mBAAmB,EAAE,CAAC;AAC1B,CAAC;AAED,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function registerMemoryTools(): void;
2
+ //# sourceMappingURL=memory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../../../src/core/tools/definitions/memory.ts"],"names":[],"mappings":"AAqKA,wBAAgB,mBAAmB,IAAI,IAAI,CAK1C"}
@@ -0,0 +1,155 @@
1
+ import { toolRegistry } from '../registry.js';
2
+ import { memoryManager } from '../../memory/index.js';
3
+ // Remember Tool
4
+ const rememberTool = {
5
+ name: 'remember',
6
+ safeToAutoRun: true,
7
+ definition: {
8
+ type: 'function',
9
+ function: {
10
+ name: 'remember',
11
+ description: 'Store a piece of information, preference, or concept in long-term memory. Use this to remember user choices, project guidelines, or important facts.',
12
+ parameters: {
13
+ type: 'object',
14
+ properties: {
15
+ content: {
16
+ type: 'string',
17
+ description: 'The information to remember.',
18
+ },
19
+ type: {
20
+ type: 'string',
21
+ enum: ['preference', 'mistake', 'knowledge', 'task_context'],
22
+ description: 'The type of memory. Default is knowledge.',
23
+ },
24
+ tags: {
25
+ type: 'array',
26
+ items: { type: 'string' },
27
+ description: 'Tags to categorize this memory.',
28
+ },
29
+ },
30
+ required: ['content'],
31
+ },
32
+ },
33
+ },
34
+ async execute(args) {
35
+ const content = args.content;
36
+ const type = args.type || 'knowledge';
37
+ const tags = args.tags || [];
38
+ const memory = await memoryManager.remember(content, type, { tags });
39
+ return `Remembered: "${content}" (ID: ${memory.id})`;
40
+ },
41
+ };
42
+ // Recall Tool
43
+ const recallTool = {
44
+ name: 'recall',
45
+ safeToAutoRun: true,
46
+ definition: {
47
+ type: 'function',
48
+ function: {
49
+ name: 'recall',
50
+ description: 'Search long-term memory for relevant information. Use this to find past decisions, user preferences, or project guidelines.',
51
+ parameters: {
52
+ type: 'object',
53
+ properties: {
54
+ query: {
55
+ type: 'string',
56
+ description: 'The search query to find relevant memories.',
57
+ },
58
+ limit: {
59
+ type: 'number',
60
+ description: 'Maximum number of results to return. Default is 5.',
61
+ },
62
+ },
63
+ required: ['query'],
64
+ },
65
+ },
66
+ },
67
+ async execute(args) {
68
+ const query = args.query;
69
+ const limit = args.limit || 5;
70
+ const results = await memoryManager.search(query, limit);
71
+ if (results.length === 0) {
72
+ return 'No relevant memories found.';
73
+ }
74
+ return results
75
+ .map((m) => `[${m.type.toUpperCase()}] ${m.content} (Similarity: ${(m.similarity * 100).toFixed(1)}%)`)
76
+ .join('\n');
77
+ },
78
+ };
79
+ // Forget Tool
80
+ const forgetTool = {
81
+ name: 'forget',
82
+ safeToAutoRun: false, // Deletion is unsafe
83
+ definition: {
84
+ type: 'function',
85
+ function: {
86
+ name: 'forget',
87
+ description: 'Delete a memory by its ID.',
88
+ parameters: {
89
+ type: 'object',
90
+ properties: {
91
+ id: {
92
+ type: 'string',
93
+ description: 'The ID of the memory to delete.',
94
+ },
95
+ },
96
+ required: ['id'],
97
+ },
98
+ },
99
+ },
100
+ async execute(args) {
101
+ const id = args.id;
102
+ await memoryManager.forget(id);
103
+ return `Forgot memory with ID: ${id}`;
104
+ },
105
+ };
106
+ // Learn Mistake Tool
107
+ const learnMistakeTool = {
108
+ name: 'learn_mistake',
109
+ safeToAutoRun: true, // Learning is safe
110
+ definition: {
111
+ type: 'function',
112
+ function: {
113
+ name: 'learn_mistake',
114
+ description: 'Record a mistake and its solution to avoid repeating it in the future.',
115
+ parameters: {
116
+ type: 'object',
117
+ properties: {
118
+ error: {
119
+ type: 'string',
120
+ description: 'The error or mistake that occurred.',
121
+ },
122
+ fix: {
123
+ type: 'string',
124
+ description: 'The solution or lesson learned.',
125
+ },
126
+ context: {
127
+ type: 'string',
128
+ description: 'Optional context (e.g., file path, command).',
129
+ },
130
+ },
131
+ required: ['error', 'fix'],
132
+ },
133
+ },
134
+ },
135
+ async execute(args) {
136
+ const error = args.error;
137
+ const fix = args.fix;
138
+ const context = args.context;
139
+ const content = `Mistake: ${error}\nSolution: ${fix}${context ? `\nContext: ${context}` : ''}`;
140
+ const memory = await memoryManager.remember(content, 'mistake', {
141
+ originalError: error,
142
+ fix,
143
+ context,
144
+ });
145
+ return `Recorded mistake and solution (ID: ${memory.id}). I will remember this to avoid it in the future.`;
146
+ },
147
+ };
148
+ // Register all memory tools
149
+ export function registerMemoryTools() {
150
+ toolRegistry.register(rememberTool);
151
+ toolRegistry.register(recallTool);
152
+ toolRegistry.register(forgetTool);
153
+ toolRegistry.register(learnMistakeTool);
154
+ }
155
+ //# sourceMappingURL=memory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory.js","sourceRoot":"","sources":["../../../../src/core/tools/definitions/memory.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bluehawks/cli",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "A production-ready multi-agent AI CLI assistant",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -35,6 +35,7 @@
35
35
  "node": ">=20.0.0"
36
36
  },
37
37
  "dependencies": {
38
+ "better-sqlite3": "^12.6.2",
38
39
  "chalk": "^5.3.0",
39
40
  "commander": "^12.1.0",
40
41
  "eventsource-parser": "^3.0.0",
@@ -50,6 +51,7 @@
50
51
  "zod": "^3.24.1"
51
52
  },
52
53
  "devDependencies": {
54
+ "@types/better-sqlite3": "^7.6.13",
53
55
  "@types/node": "^22.10.5",
54
56
  "@types/react": "^18.3.18",
55
57
  "@typescript-eslint/eslint-plugin": "^8.19.1",
@@ -8,7 +8,7 @@ export const DEFAULT_MODEL = 'Qwen/Qwen3-0.6B';
8
8
 
9
9
  // CLI Metadata
10
10
  export const CLI_NAME = 'bluehawks';
11
- export const CLI_VERSION = '1.0.2';
11
+ export const CLI_VERSION = '1.0.4';
12
12
  export const CLI_DESCRIPTION = 'A production-ready multi-agent AI CLI assistant';
13
13
 
14
14
  // Configuration Paths
@@ -9,6 +9,7 @@ import { Agent, type AgentResponse } from './agent.js';
9
9
  import { CONTEXT_FILE } from '../../config/constants.js';
10
10
  import * as fs from 'node:fs/promises';
11
11
  import * as path from 'node:path';
12
+ import { memoryManager } from '../memory/index.js'; // Corrected path
12
13
 
13
14
  export interface SubAgentConfig {
14
15
  name: string;
@@ -58,6 +59,7 @@ export class Orchestrator {
58
59
  private customSystemPrompt?: string;
59
60
  private appendSystemPrompt?: string;
60
61
  private contextContent: string = '';
62
+ private rootStructure: string = '';
61
63
  private subAgents: Map<string, SubAgentConfig> = new Map();
62
64
 
63
65
  constructor(options: OrchestratorOptions) {
@@ -112,6 +114,8 @@ export class Orchestrator {
112
114
  async initialize(): Promise<void> {
113
115
  // Load context file if it exists
114
116
  await this.loadContextFile();
117
+ // Load root directory structure
118
+ await this.loadRootStructure();
115
119
  }
116
120
 
117
121
  private async loadContextFile(): Promise<void> {
@@ -123,6 +127,19 @@ export class Orchestrator {
123
127
  }
124
128
  }
125
129
 
130
+ private async loadRootStructure(): Promise<void> {
131
+ try {
132
+ const entries = await fs.readdir(this.projectPath, { withFileTypes: true });
133
+ const list = entries
134
+ .filter(e => !e.name.startsWith('.') && e.name !== 'node_modules' && e.name !== 'dist')
135
+ .map(e => `${e.isDirectory() ? '📂' : '📄'} ${e.name}`)
136
+ .join('\n');
137
+ this.rootStructure = list;
138
+ } catch {
139
+ this.rootStructure = '';
140
+ }
141
+ }
142
+
126
143
  private buildSystemPrompt(): string {
127
144
  // Use custom system prompt if provided, otherwise default
128
145
  let prompt = this.customSystemPrompt || DEFAULT_SYSTEM_PROMPT;
@@ -132,6 +149,10 @@ export class Orchestrator {
132
149
  prompt += `\n\n${this.appendSystemPrompt}`;
133
150
  }
134
151
 
152
+ if (this.rootStructure) {
153
+ prompt += `\n\n## Current Directory Structure\n${this.rootStructure}\n\nUse this context to understand the project structure and answer questions about the codebase. If the user asks about specific files, use read_file to examine them.`;
154
+ }
155
+
135
156
  if (this.contextContent) {
136
157
  prompt += `\n\n## Project Context (from ${CONTEXT_FILE})\n\n${this.contextContent}`;
137
158
  }
@@ -158,17 +179,27 @@ Before making any changes, first:
158
179
  onToolEnd?: (name: string, result: string) => void;
159
180
  }
160
181
  ): Promise<AgentResponse> {
182
+ // Retrieve relevant memories
183
+ const memories = await memoryManager.search(userMessage, 5);
184
+ let systemPrompt = this.buildSystemPrompt();
185
+
186
+ if (memories.length > 0) {
187
+ const memoryContext = memories
188
+ .map(m => `- [${m.type.toUpperCase()}] ${m.content}`)
189
+ .join('\n');
190
+ systemPrompt += `\n\n## Long-Term Memory (Relevant Context)\n${memoryContext}\n\nUse this information to guide your decisions and avoid past mistakes.`;
191
+ }
192
+
161
193
  const mainAgent = new Agent(
162
194
  {
163
195
  name: 'main',
164
- systemPrompt: this.buildSystemPrompt(),
196
+ systemPrompt,
165
197
  maxIterations: this.maxTurns,
166
198
  },
167
199
  this.apiClient,
168
200
  this.toolExecutor
169
201
  );
170
202
 
171
-
172
203
  return mainAgent.run(
173
204
  userMessage,
174
205
  callbacks?.onChunk,
@@ -22,6 +22,8 @@ import {
22
22
  type ToolDefinition,
23
23
  type ToolResult,
24
24
  type StreamDelta,
25
+ type EmbeddingRequest,
26
+ type EmbeddingResponse,
25
27
  APIError,
26
28
  } from './types.js';
27
29
 
@@ -42,6 +44,21 @@ export class APIClient {
42
44
  this.timeout = options.timeout || DEFAULT_TIMEOUT_MS;
43
45
  }
44
46
 
47
+ /**
48
+ * Create embeddings for the given input
49
+ */
50
+ async createEmbeddings(
51
+ input: string | string[],
52
+ model?: string
53
+ ): Promise<EmbeddingResponse> {
54
+ const body: EmbeddingRequest = {
55
+ model: model || 'text-embedding-3-small',
56
+ input,
57
+ };
58
+
59
+ return this.makeRequest<EmbeddingResponse>('/embeddings', body);
60
+ }
61
+
45
62
  /**
46
63
  * Create a chat completion (non-streaming)
47
64
  */
@@ -136,6 +136,29 @@ export interface APIClientOptions {
136
136
  export type StreamCallback = (chunk: string) => void;
137
137
  export type ToolCallCallback = (toolCalls: ToolCall[]) => void;
138
138
 
139
+ // Embedding Types
140
+ export interface EmbeddingRequest {
141
+ model: string;
142
+ input: string | string[];
143
+ user?: string;
144
+ }
145
+
146
+ export interface EmbeddingResponse {
147
+ object: 'list';
148
+ data: EmbeddingObject[];
149
+ model: string;
150
+ usage: {
151
+ prompt_tokens: number;
152
+ total_tokens: number;
153
+ };
154
+ }
155
+
156
+ export interface EmbeddingObject {
157
+ object: 'embedding';
158
+ index: number;
159
+ embedding: number[];
160
+ }
161
+
139
162
  // API Error
140
163
  export class APIError extends Error {
141
164
  constructor(
@@ -0,0 +1,3 @@
1
+ export * from './types.js';
2
+ export * from './storage.js';
3
+ export * from './manager.js';
@@ -0,0 +1,120 @@
1
+ import { apiClient } from '../api/client.js';
2
+ import { memoryStorage } from './storage.js';
3
+ import type { Memory, MemoryType, SearchResult } from './types.js';
4
+ import * as crypto from 'crypto';
5
+
6
+ export class MemoryManager {
7
+ private static instance: MemoryManager;
8
+
9
+ private constructor() { }
10
+
11
+ static getInstance(): MemoryManager {
12
+ if (!MemoryManager.instance) {
13
+ MemoryManager.instance = new MemoryManager();
14
+ }
15
+ return MemoryManager.instance;
16
+ }
17
+
18
+ /**
19
+ * Store a new memory
20
+ */
21
+ async remember(content: string, type: MemoryType = 'knowledge', metadata: Record<string, any> = {}): Promise<Memory> {
22
+ // Generate embedding
23
+ let embedding: number[] = [];
24
+ try {
25
+ const response = await apiClient.createEmbeddings(content);
26
+ if (response.data && response.data.length > 0) {
27
+ embedding = response.data[0].embedding;
28
+ }
29
+ } catch (error) {
30
+ console.error('Failed to generate embedding for memory:', error);
31
+ // We still save the memory without embedding, it just won't be searchable by vector
32
+ }
33
+
34
+ const memory: Memory = {
35
+ id: crypto.randomUUID(),
36
+ content,
37
+ type,
38
+ metadata,
39
+ embedding,
40
+ created_at: Date.now(),
41
+ updated_at: Date.now(),
42
+ };
43
+
44
+ await memoryStorage.save(memory);
45
+ return memory;
46
+ }
47
+
48
+ /**
49
+ * Search memories by semantic similarity
50
+ */
51
+ async search(query: string, limit: number = 5, minSimilarity: number = 0.7): Promise<SearchResult[]> {
52
+ // Generate query embedding
53
+ let queryEmbedding: number[] = [];
54
+ try {
55
+ const response = await apiClient.createEmbeddings(query);
56
+ if (response.data && response.data.length > 0) {
57
+ queryEmbedding = response.data[0].embedding;
58
+ }
59
+ } catch (error) {
60
+ console.error('Failed to generate embedding for search query:', error);
61
+ // Fallback to keyword search? For now just return empty if vector search fails
62
+ return [];
63
+ }
64
+
65
+ const allMemories = await memoryStorage.getAll();
66
+
67
+ // Calculate similarity for each memory
68
+ const results: SearchResult[] = allMemories
69
+ .filter(m => m.embedding && m.embedding.length > 0)
70
+ .map(memory => {
71
+ const similarity = this.cosineSimilarity(queryEmbedding, memory.embedding!);
72
+ return { ...memory, similarity };
73
+ })
74
+ .filter(r => r.similarity >= minSimilarity)
75
+ .sort((a, b) => b.similarity - a.similarity) // Descending
76
+ .slice(0, limit);
77
+
78
+ return results;
79
+ }
80
+
81
+ /**
82
+ * Retrieve a memory by ID
83
+ */
84
+ async get(id: string): Promise<Memory | null> {
85
+ return memoryStorage.get(id);
86
+ }
87
+
88
+ /**
89
+ * Delete a memory
90
+ */
91
+ async forget(id: string): Promise<void> {
92
+ await memoryStorage.delete(id);
93
+ }
94
+
95
+ /**
96
+ * Clear all memories (useful for testing or reset)
97
+ */
98
+ async clear(): Promise<void> {
99
+ await memoryStorage.clear();
100
+ }
101
+
102
+ private cosineSimilarity(vecA: number[], vecB: number[]): number {
103
+ if (vecA.length !== vecB.length) return 0;
104
+
105
+ let dotProduct = 0;
106
+ let normA = 0;
107
+ let normB = 0;
108
+
109
+ for (let i = 0; i < vecA.length; i++) {
110
+ dotProduct += vecA[i] * vecB[i];
111
+ normA += vecA[i] * vecA[i];
112
+ normB += vecB[i] * vecB[i];
113
+ }
114
+
115
+ if (normA === 0 || normB === 0) return 0;
116
+ return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
117
+ }
118
+ }
119
+
120
+ export const memoryManager = MemoryManager.getInstance();
@@ -0,0 +1,90 @@
1
+ import Database from 'better-sqlite3';
2
+ import * as path from 'path';
3
+ import * as os from 'os';
4
+ import * as fs from 'fs';
5
+ import { CONFIG_DIR_NAME } from '../../config/constants.js';
6
+ import type { Memory, MemoryType } from './types.js';
7
+
8
+ export class MemoryStorage {
9
+ private db: Database.Database;
10
+ private dbPath: string;
11
+
12
+ constructor() {
13
+ const homeDir = os.homedir();
14
+ const configDir = path.join(homeDir, CONFIG_DIR_NAME);
15
+
16
+ // Ensure directory exists
17
+ if (!fs.existsSync(configDir)) {
18
+ fs.mkdirSync(configDir, { recursive: true });
19
+ }
20
+
21
+ this.dbPath = path.join(configDir, 'memory.db');
22
+ this.db = new Database(this.dbPath);
23
+ this.initialize();
24
+ }
25
+
26
+ private initialize(): void {
27
+ this.db.exec(`
28
+ CREATE TABLE IF NOT EXISTS memories (
29
+ id TEXT PRIMARY KEY,
30
+ content TEXT NOT NULL,
31
+ type TEXT NOT NULL,
32
+ metadata TEXT,
33
+ embedding TEXT,
34
+ created_at INTEGER NOT NULL,
35
+ updated_at INTEGER NOT NULL
36
+ );
37
+ CREATE INDEX IF NOT EXISTS idx_memories_type ON memories(type);
38
+ `);
39
+ }
40
+
41
+ async save(memory: Memory): Promise<void> {
42
+ const stmt = this.db.prepare(`
43
+ INSERT OR REPLACE INTO memories (id, content, type, metadata, embedding, created_at, updated_at)
44
+ VALUES (@id, @content, @type, @metadata, @embedding, @created_at, @updated_at)
45
+ `);
46
+
47
+ stmt.run({
48
+ ...memory,
49
+ metadata: JSON.stringify(memory.metadata || {}),
50
+ embedding: JSON.stringify(memory.embedding || []),
51
+ });
52
+ }
53
+
54
+ async get(id: string): Promise<Memory | null> {
55
+ const stmt = this.db.prepare('SELECT * FROM memories WHERE id = ?');
56
+ const row = stmt.get(id) as any;
57
+
58
+ if (!row) return null;
59
+ return this.mapRowToMemory(row);
60
+ }
61
+
62
+ async getAll(): Promise<Memory[]> {
63
+ const stmt = this.db.prepare('SELECT * FROM memories');
64
+ const rows = stmt.all() as any[];
65
+ return rows.map(r => this.mapRowToMemory(r));
66
+ }
67
+
68
+ async delete(id: string): Promise<void> {
69
+ const stmt = this.db.prepare('DELETE FROM memories WHERE id = ?');
70
+ stmt.run(id);
71
+ }
72
+
73
+ async clear(): Promise<void> {
74
+ this.db.exec('DELETE FROM memories');
75
+ }
76
+
77
+ private mapRowToMemory(row: any): Memory {
78
+ return {
79
+ id: row.id,
80
+ content: row.content,
81
+ type: row.type as MemoryType,
82
+ metadata: JSON.parse(row.metadata),
83
+ embedding: JSON.parse(row.embedding),
84
+ created_at: row.created_at,
85
+ updated_at: row.updated_at,
86
+ };
87
+ }
88
+ }
89
+
90
+ export const memoryStorage = new MemoryStorage();
@@ -0,0 +1,22 @@
1
+ export interface Memory {
2
+ id: string;
3
+ content: string;
4
+ type: MemoryType;
5
+ metadata?: Record<string, any>;
6
+ embedding?: number[];
7
+ created_at: number;
8
+ updated_at: number;
9
+ }
10
+
11
+ export type MemoryType = 'preference' | 'mistake' | 'knowledge' | 'task_context';
12
+
13
+ export interface MemoryMetadata {
14
+ source?: string;
15
+ confidence?: number;
16
+ tags?: string[];
17
+ [key: string]: any;
18
+ }
19
+
20
+ export interface SearchResult extends Memory {
21
+ similarity: number;
22
+ }
@@ -8,6 +8,7 @@ import { registerShellTools } from './shell.js';
8
8
  import { registerSearchTools } from './search.js';
9
9
  import { registerGitTools } from './git.js';
10
10
  import { registerWebTools } from './web.js';
11
+ import { registerMemoryTools } from './memory.js';
11
12
 
12
13
  export function registerAllTools(): void {
13
14
  registerFileTools();
@@ -15,6 +16,7 @@ export function registerAllTools(): void {
15
16
  registerSearchTools();
16
17
  registerGitTools();
17
18
  registerWebTools();
19
+ registerMemoryTools();
18
20
  }
19
21
 
20
22
  export * from './file.js';
@@ -22,3 +24,4 @@ export * from './shell.js';
22
24
  export * from './search.js';
23
25
  export * from './git.js';
24
26
  export * from './web.js';
27
+ export * from './memory.js';