opencode-mem 2.2.0 → 2.3.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/README.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # OpenCode Memory
2
2
 
3
+ [![npm version](https://img.shields.io/npm/v/opencode-mem.svg)](https://www.npmjs.com/package/opencode-mem)
4
+ [![npm downloads](https://img.shields.io/npm/dm/opencode-mem.svg)](https://www.npmjs.com/package/opencode-mem)
5
+ [![license](https://img.shields.io/npm/l/opencode-mem.svg)](https://www.npmjs.com/package/opencode-mem)
6
+
3
7
  ![OpenCode Memory Banner](.github/banner.png)
4
8
 
5
9
  A persistent memory system for AI coding agents that enables long-term context retention across sessions using local vector database technology.
@@ -11,10 +15,9 @@ OpenCode Memory provides AI coding agents with the ability to remember and recal
11
15
  ## Key Features
12
16
 
13
17
  - **Local Vector Database**: SQLite-based storage with sqlite-vec extension
14
- - **Dual Memory Scopes**: Separate user-level and project-level memory contexts
18
+ - **Project Memory System**: Persistent storage for project-specific knowledge
19
+ - **User Profile System**: Automatic learning of preferences, patterns, and workflows
15
20
  - **Unified Timeline**: Browse memories and prompts together with linking support
16
- - **Prompt-Memory Linking**: Bidirectional links between prompts and generated memories
17
- - **User Profile System**: Structured learning with preferences, patterns, workflows, and skill assessment
18
21
  - **Web Interface**: Full-featured UI for memory management and search
19
22
  - **Auto-Capture System**: Intelligent prompt-based memory extraction
20
23
  - **Multi-Provider AI**: Support for OpenAI, Anthropic, and OpenAI-compatible APIs
@@ -38,6 +41,36 @@ Add the plugin to your OpenCode configuration:
38
41
 
39
42
  OpenCode will automatically download and install the plugin on next startup.
40
43
 
44
+ ### macOS Users - IMPORTANT
45
+
46
+ macOS ships with Apple's SQLite which **disables extension loading** for security reasons. You must install and configure Homebrew SQLite:
47
+
48
+ **Step 1: Install Homebrew SQLite**
49
+ ```bash
50
+ brew install sqlite
51
+ ```
52
+
53
+ **Step 2: Find the library path**
54
+ ```bash
55
+ brew --prefix sqlite
56
+ ```
57
+
58
+ **Step 3: Configure the path**
59
+
60
+ Edit `~/.config/opencode/opencode-mem.jsonc` and add:
61
+
62
+ ```jsonc
63
+ {
64
+ "customSqlitePath": "/opt/homebrew/opt/sqlite/lib/libsqlite3.dylib"
65
+ }
66
+ ```
67
+
68
+ **Common paths:**
69
+ - **Apple Silicon (M1/M2/M3)**: `/opt/homebrew/opt/sqlite/lib/libsqlite3.dylib`
70
+ - **Intel Mac**: `/usr/local/opt/sqlite/lib/libsqlite3.dylib`
71
+
72
+ The plugin will auto-detect these paths if not configured, but manual configuration is recommended for reliability.
73
+
41
74
  ### Install from Source
42
75
 
43
76
  ```bash
@@ -52,12 +85,18 @@ bun run build
52
85
  ### Basic Usage
53
86
 
54
87
  ```typescript
55
- memory({ mode: "add", content: "Project uses microservices", scope: "project" })
56
- memory({ mode: "search", query: "architecture decisions", scope: "project" })
88
+ // Add project memory
89
+ memory({ mode: "add", content: "Project uses microservices architecture" })
90
+
91
+ // Search memories
92
+ memory({ mode: "search", query: "architecture decisions" })
93
+
94
+ // View user profile
57
95
  memory({ mode: "profile" })
58
- ```
59
96
 
60
- **Note**: User-scoped `add` is deprecated in v2.2+. Use profile system instead.
97
+ // List recent memories
98
+ memory({ mode: "list", limit: 10 })
99
+ ```
61
100
 
62
101
  ### Web Interface
63
102
 
@@ -71,13 +110,14 @@ Access at `http://127.0.0.1:4747` to browse memories, view prompt-memory links,
71
110
 
72
111
  ![User Profile Viewer](.github/screenshot-user-profile.png)
73
112
 
74
- ### Configuration
113
+ ## Configuration
75
114
 
76
115
  Configuration file: `~/.config/opencode/opencode-mem.jsonc`
77
116
 
78
117
  ```jsonc
79
118
  {
80
119
  "storagePath": "~/.opencode-mem/data",
120
+ "customSqlitePath": "/opt/homebrew/opt/sqlite/lib/libsqlite3.dylib",
81
121
  "embeddingModel": "Xenova/nomic-embed-text-v1",
82
122
  "webServerEnabled": true,
83
123
  "webServerPort": 4747,
@@ -86,38 +126,48 @@ Configuration file: `~/.config/opencode/opencode-mem.jsonc`
86
126
  "memoryModel": "gpt-4",
87
127
  "memoryApiUrl": "https://api.openai.com/v1",
88
128
  "memoryApiKey": "sk-...",
89
- "userMemoryAnalysisInterval": 10,
90
- "userProfileMaxPreferences": 20,
91
- "userProfileMaxPatterns": 15,
92
- "userProfileMaxWorkflows": 10,
93
- "userProfileConfidenceDecayDays": 30,
94
- "userProfileChangelogRetentionCount": 5
129
+ "userProfileAnalysisInterval": 10,
130
+ "maxMemories": 10
95
131
  }
96
132
  ```
97
133
 
98
- ## Breaking Changes (v2.2)
134
+ See [Configuration Guide](https://github.com/tickernelz/opencode-mem/wiki/Configuration-Guide) for all options.
99
135
 
100
- **User-scoped memories deprecated in favor of structured user profiles:**
136
+ ## Breaking Changes (v2.3)
101
137
 
102
- - Removed: User-scoped `addMemory` (now returns error)
103
- - Changed: `memory({ mode: "profile" })` returns new structure (preferences/patterns/workflows/skillLevel)
104
- - Added: 5 new config options for profile management
105
- - New behavior: User learning creates/updates structured profile instead of individual memories
106
- - Migration: Existing user memories remain readable but new ones cannot be created
138
+ **User-scoped memories completely removed:**
107
139
 
108
- **Migration required**: Update code using `mode: "profile"` to handle new structure.
140
+ - **Removed**: `scope` parameter from all memory operations
141
+ - **Removed**: `maxProjectMemories` config (use `maxMemories` instead)
142
+ - **Renamed**: `userMemoryAnalysisInterval` → `userProfileAnalysisInterval`
143
+ - **Renamed**: `performUserMemoryLearning()` → `performUserProfileLearning()`
144
+ - **Changed**: All memories are now project-scoped by default
145
+ - **Changed**: User preferences managed exclusively through automatic profile system
109
146
 
110
- ## Breaking Changes (v2.0)
147
+ **Migration required:**
148
+ ```jsonc
149
+ // OLD
150
+ {
151
+ "userMemoryAnalysisInterval": 10,
152
+ "maxMemories": 5,
153
+ "maxProjectMemories": 10
154
+ }
111
155
 
112
- **Token-based auto-capture has been replaced with prompt-based system:**
156
+ // NEW
157
+ {
158
+ "userProfileAnalysisInterval": 10,
159
+ "maxMemories": 10
160
+ }
161
+ ```
113
162
 
114
- - Removed: `autoCaptureTokenThreshold`, `autoCaptureMinTokens`, `autoCaptureMaxMemories`, `autoCaptureSummaryMaxLength`, `autoCaptureContextWindow`
115
- - Added: `memoryProvider`, `userMemoryAnalysisInterval`, `autoCaptureMaxIterations`, `autoCaptureIterationTimeout`
116
- - New behavior: Triggers on session idle, analyzes last uncaptured prompt
117
- - Automatic skip logic for non-technical conversations
118
- - Prompt-memory linking with cascade delete support
163
+ Remove `scope` parameter from all `memory()` calls:
164
+ ```typescript
165
+ // OLD
166
+ memory({ mode: "add", content: "...", scope: "project" })
119
167
 
120
- **Migration required**: Remove deprecated config options and add new ones.
168
+ // NEW
169
+ memory({ mode: "add", content: "..." })
170
+ ```
121
171
 
122
172
  ## Documentation
123
173
 
@@ -126,88 +176,13 @@ For detailed documentation, see the [Wiki](https://github.com/tickernelz/opencod
126
176
  - [Installation Guide](https://github.com/tickernelz/opencode-mem/wiki/Installation-Guide)
127
177
  - [Quick Start](https://github.com/tickernelz/opencode-mem/wiki/Quick-Start)
128
178
  - [Configuration Guide](https://github.com/tickernelz/opencode-mem/wiki/Configuration-Guide)
129
- - [User Profile System](https://github.com/tickernelz/opencode-mem/wiki/User-Profile)
179
+ - [User Profile System](https://github.com/tickernelz/opencode-mem/wiki/User-Profile-System)
130
180
  - [Memory Operations](https://github.com/tickernelz/opencode-mem/wiki/Memory-Operations)
131
181
  - [Auto-Capture System](https://github.com/tickernelz/opencode-mem/wiki/Auto-Capture-System)
132
182
  - [Web Interface](https://github.com/tickernelz/opencode-mem/wiki/Web-Interface)
133
- - [Embedding Models](https://github.com/tickernelz/opencode-mem/wiki/Embedding-Models)
134
- - [Performance Tuning](https://github.com/tickernelz/opencode-mem/wiki/Performance-Tuning)
183
+ - [API Reference](https://github.com/tickernelz/opencode-mem/wiki/API-Reference)
135
184
  - [Troubleshooting](https://github.com/tickernelz/opencode-mem/wiki/Troubleshooting)
136
185
 
137
- ## Features Overview
138
-
139
- ### Memory Scopes
140
-
141
- - **User Scope**: Cross-project preferences, coding style, communication patterns
142
- - **Project Scope**: Architecture decisions, technology stack, implementation details
143
-
144
- ### Auto-Capture System
145
-
146
- Automatically extracts memories from conversations:
147
-
148
- 1. Triggers on session idle
149
- 2. Analyzes last uncaptured prompt and response
150
- 3. Links memory to source prompt
151
- 4. Skips non-technical conversations
152
-
153
- ### User Profile System
154
-
155
- Builds structured user profile from conversation history (default: every 10 prompts):
156
-
157
- - **Preferences**: Code style, communication style, tool preferences (with confidence scores)
158
- - **Patterns**: Recurring topics, problem domains, technical interests (with frequency tracking)
159
- - **Workflows**: Development sequences, habits, learning style
160
- - **Skill Level**: Overall and per-domain assessment
161
-
162
- Profile includes versioning, changelog, and confidence decay mechanism.
163
-
164
- ### Web Interface
165
-
166
- - Unified timeline of memories and prompts
167
- - User profile viewer with changelog
168
- - Visual prompt-memory link indicators
169
- - Cascade delete for linked items
170
- - Bulk operations
171
- - Search and filters
172
- - Maintenance tools (cleanup, deduplication)
173
-
174
- ## API Reference
175
-
176
- ### Memory Tool
177
-
178
- ```typescript
179
- memory({ mode: "add", content: "...", scope: "project" })
180
- memory({ mode: "search", query: "...", scope: "user|project" })
181
- memory({ mode: "list", scope: "user|project", limit: 10 })
182
- memory({ mode: "profile" })
183
- memory({ mode: "forget", memoryId: "..." })
184
- memory({ mode: "auto-capture-toggle" })
185
- memory({ mode: "auto-capture-stats" })
186
- memory({ mode: "capture-now" })
187
- ```
188
-
189
- **Note**: `scope: "user"` for `add` mode is deprecated in v2.2+.
190
-
191
- ### REST API
192
-
193
- **Memory & Prompt Management:**
194
- - `GET /api/memories?scope=project&includePrompts=true` - List memories/prompts
195
- - `POST /api/memories` - Create memory
196
- - `PUT /api/memories/:id` - Update memory
197
- - `DELETE /api/memories/:id?cascade=true` - Delete memory (and linked prompt)
198
- - `DELETE /api/prompts/:id?cascade=true` - Delete prompt (and linked memory)
199
- - `POST /api/search` - Vector search
200
-
201
- **User Profile:**
202
- - `GET /api/profile` - Get user profile
203
- - `GET /api/profile/changelog?limit=5` - Get profile changelog
204
- - `GET /api/profile/snapshot/:changelogId` - Get profile snapshot
205
- - `POST /api/profile/refresh` - Force profile refresh
206
-
207
- **Maintenance:**
208
- - `POST /api/cleanup` - Run cleanup
209
- - `POST /api/deduplicate` - Run deduplication
210
-
211
186
  ## Development
212
187
 
213
188
  ```bash
package/dist/config.d.ts CHANGED
@@ -1,12 +1,12 @@
1
1
  export declare const CONFIG: {
2
2
  storagePath: string;
3
+ customSqlitePath: string | undefined;
3
4
  embeddingModel: string;
4
5
  embeddingDimensions: number;
5
6
  embeddingApiUrl: string | undefined;
6
7
  embeddingApiKey: string | undefined;
7
8
  similarityThreshold: number;
8
9
  maxMemories: number;
9
- maxProjectMemories: number;
10
10
  maxProfileItems: number;
11
11
  injectProfile: boolean;
12
12
  containerTagPrefix: string;
@@ -27,7 +27,7 @@ export declare const CONFIG: {
27
27
  autoCleanupRetentionDays: number;
28
28
  deduplicationEnabled: boolean;
29
29
  deduplicationSimilarityThreshold: number;
30
- userMemoryAnalysisInterval: number;
30
+ userProfileAnalysisInterval: number;
31
31
  userProfileMaxPreferences: number;
32
32
  userProfileMaxPatterns: number;
33
33
  userProfileMaxWorkflows: number;
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AA2WA,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;oBAwBb,aAAa,GACb,kBAAkB,GAClB,WAAW;;;;;;;;;;;;;;;;;;;CAyBhB,CAAC;AAEF,wBAAgB,YAAY,IAAI,OAAO,CAEtC"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAyXA,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;oBAwBb,aAAa,GACb,kBAAkB,GAClB,WAAW;;;;;;;;;;;;;;;;;;;CAyBhB,CAAC;AAEF,wBAAgB,YAAY,IAAI,OAAO,CAEtC"}
package/dist/config.js CHANGED
@@ -37,8 +37,7 @@ const DEFAULTS = {
37
37
  embeddingModel: "Xenova/nomic-embed-text-v1",
38
38
  embeddingDimensions: 768,
39
39
  similarityThreshold: 0.6,
40
- maxMemories: 5,
41
- maxProjectMemories: 10,
40
+ maxMemories: 10,
42
41
  maxProfileItems: 5,
43
42
  injectProfile: true,
44
43
  containerTagPrefix: "opencode",
@@ -55,7 +54,7 @@ const DEFAULTS = {
55
54
  autoCleanupRetentionDays: 30,
56
55
  deduplicationEnabled: true,
57
56
  deduplicationSimilarityThreshold: 0.9,
58
- userMemoryAnalysisInterval: 10,
57
+ userProfileAnalysisInterval: 10,
59
58
  userProfileMaxPreferences: 20,
60
59
  userProfileMaxPatterns: 15,
61
60
  userProfileMaxWorkflows: 10,
@@ -102,6 +101,22 @@ const CONFIG_TEMPLATE = `{
102
101
  // Storage location for vector database
103
102
  "storagePath": "~/.opencode-mem/data",
104
103
 
104
+ // ============================================
105
+ // macOS SQLite Extension Loading (REQUIRED FOR macOS)
106
+ // ============================================
107
+
108
+ // macOS users MUST set this to use Homebrew SQLite instead of Apple's SQLite
109
+ // Apple's SQLite disables extension loading which breaks sqlite-vec
110
+ //
111
+ // Common paths:
112
+ // - Homebrew (Intel): "/usr/local/opt/sqlite/lib/libsqlite3.dylib"
113
+ // - Homebrew (Apple Silicon): "/opt/homebrew/opt/sqlite/lib/libsqlite3.dylib"
114
+ //
115
+ // To install: brew install sqlite
116
+ // To find path: brew --prefix sqlite
117
+ //
118
+ // "customSqlitePath": "/opt/homebrew/opt/sqlite/lib/libsqlite3.dylib",
119
+
105
120
  // ============================================
106
121
  // Embedding Model (for similarity search)
107
122
  // ============================================
@@ -205,18 +220,18 @@ const CONFIG_TEMPLATE = `{
205
220
 
206
221
  // Days to keep AI session history before cleanup
207
222
  "aiSessionRetentionDays": 7,
208
-
223
+
209
224
  // ============================================
210
- // User Memory Learning
225
+ // User Profile System
211
226
  // ============================================
212
-
227
+
213
228
  // Analyze user prompts every N prompts to build/update your user profile
214
229
  // When N uncaptured prompts accumulate, AI will analyze them to identify:
215
230
  // - User preferences (code style, communication style, tool preferences)
216
231
  // - User patterns (recurring topics, problem domains, technical interests)
217
232
  // - User workflows (development habits, sequences, learning style)
218
233
  // - Skill level (overall and per-domain assessment)
219
- "userMemoryAnalysisInterval": 10,
234
+ "userProfileAnalysisInterval": 10,
220
235
 
221
236
  // Maximum number of preferences to keep in user profile (sorted by confidence)
222
237
  // Preferences are things like "prefers code without comments", "likes concise responses"
@@ -244,13 +259,10 @@ const CONFIG_TEMPLATE = `{
244
259
 
245
260
  // Minimum similarity score (0-1) for memory search results
246
261
  "similarityThreshold": 0.6,
247
-
248
- // Maximum number of user-scoped memories to return in search
249
- "maxMemories": 5,
250
-
251
- // Maximum number of project-scoped memories to return in search
252
- "maxProjectMemories": 10,
253
-
262
+
263
+ // Maximum number of memories to return in search results
264
+ "maxMemories": 10,
265
+
254
266
  // ============================================
255
267
  // Advanced Settings
256
268
  // ============================================
@@ -297,6 +309,7 @@ function getEmbeddingDimensions(model) {
297
309
  }
298
310
  export const CONFIG = {
299
311
  storagePath: expandPath(fileConfig.storagePath ?? DEFAULTS.storagePath),
312
+ customSqlitePath: fileConfig.customSqlitePath ? expandPath(fileConfig.customSqlitePath) : undefined,
300
313
  embeddingModel: fileConfig.embeddingModel ?? DEFAULTS.embeddingModel,
301
314
  embeddingDimensions: fileConfig.embeddingDimensions ??
302
315
  getEmbeddingDimensions(fileConfig.embeddingModel ?? DEFAULTS.embeddingModel),
@@ -304,7 +317,6 @@ export const CONFIG = {
304
317
  embeddingApiKey: fileConfig.embeddingApiKey ?? process.env.OPENAI_API_KEY,
305
318
  similarityThreshold: fileConfig.similarityThreshold ?? DEFAULTS.similarityThreshold,
306
319
  maxMemories: fileConfig.maxMemories ?? DEFAULTS.maxMemories,
307
- maxProjectMemories: fileConfig.maxProjectMemories ?? DEFAULTS.maxProjectMemories,
308
320
  maxProfileItems: fileConfig.maxProfileItems ?? DEFAULTS.maxProfileItems,
309
321
  injectProfile: fileConfig.injectProfile ?? DEFAULTS.injectProfile,
310
322
  containerTagPrefix: fileConfig.containerTagPrefix ?? DEFAULTS.containerTagPrefix,
@@ -328,7 +340,7 @@ export const CONFIG = {
328
340
  autoCleanupRetentionDays: fileConfig.autoCleanupRetentionDays ?? DEFAULTS.autoCleanupRetentionDays,
329
341
  deduplicationEnabled: fileConfig.deduplicationEnabled ?? DEFAULTS.deduplicationEnabled,
330
342
  deduplicationSimilarityThreshold: fileConfig.deduplicationSimilarityThreshold ?? DEFAULTS.deduplicationSimilarityThreshold,
331
- userMemoryAnalysisInterval: fileConfig.userMemoryAnalysisInterval ?? DEFAULTS.userMemoryAnalysisInterval,
343
+ userProfileAnalysisInterval: fileConfig.userProfileAnalysisInterval ?? DEFAULTS.userProfileAnalysisInterval,
332
344
  userProfileMaxPreferences: fileConfig.userProfileMaxPreferences ?? DEFAULTS.userProfileMaxPreferences,
333
345
  userProfileMaxPatterns: fileConfig.userProfileMaxPatterns ?? DEFAULTS.userProfileMaxPatterns,
334
346
  userProfileMaxWorkflows: fileConfig.userProfileMaxWorkflows ?? DEFAULTS.userProfileMaxWorkflows,
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAe,MAAM,qBAAqB,CAAC;AAyC/D,eAAO,MAAM,iBAAiB,EAAE,MAulB/B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAe,MAAM,qBAAqB,CAAC;AA0C/D,eAAO,MAAM,iBAAiB,EAAE,MAyhB/B,CAAC"}
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import { formatContextForPrompt } from "./services/context.js";
4
4
  import { getTags } from "./services/tags.js";
5
5
  import { stripPrivateContent, isFullyPrivate } from "./services/privacy.js";
6
6
  import { performAutoCapture } from "./services/auto-capture.js";
7
- import { performUserMemoryLearning } from "./services/user-memory-learning.js";
7
+ import { performUserProfileLearning } from "./services/user-memory-learning.js";
8
8
  import { userPromptManager } from "./services/user-prompt/user-prompt-manager.js";
9
9
  import { startWebServer, WebServer } from "./services/web-server.js";
10
10
  import { isConfigured, CONFIG } from "./config.js";
@@ -16,10 +16,11 @@ const MEMORY_NUDGE_MESSAGE = `[MEMORY TRIGGER DETECTED]
16
16
  The user wants you to remember something. You MUST use the \`memory\` tool with \`mode: "add"\` to save this information.
17
17
 
18
18
  Extract the key information the user wants remembered and save it as a concise, searchable memory.
19
- - Use \`scope: "project"\` for project-specific preferences (e.g., "run lint with tests")
20
- - Use \`scope: "user"\` for cross-project preferences (e.g., "prefers concise responses")
19
+ - Use \`scope: "project"\` for project-specific knowledge (e.g., "run lint with tests", architecture decisions)
21
20
  - Choose an appropriate \`type\`: "preference", "project-config", "learned-pattern", etc.
22
21
 
22
+ Note: User preferences are automatically learned through the user profile system. Only store project-specific information.
23
+
23
24
  DO NOT skip this step. The user explicitly asked you to remember.`;
24
25
  function removeCodeBlocks(text) {
25
26
  return text.replace(CODE_BLOCK_PATTERN, "").replace(INLINE_CODE_PATTERN, "");
@@ -183,11 +184,7 @@ export const OpenCodeMemPlugin = async (ctx) => {
183
184
  return;
184
185
  }
185
186
  }
186
- const [userMemoriesResult, projectMemoriesListResult] = await Promise.all([
187
- memoryClient.searchMemories(userMessage, tags.user.tag),
188
- memoryClient.listMemories(tags.project.tag, CONFIG.maxProjectMemories),
189
- ]);
190
- const userMemories = userMemoriesResult.success ? userMemoriesResult : { results: [] };
187
+ const projectMemoriesListResult = await memoryClient.listMemories(tags.project.tag, CONFIG.maxMemories);
191
188
  const projectMemoriesList = projectMemoriesListResult.success
192
189
  ? projectMemoriesListResult
193
190
  : { memories: [] };
@@ -203,7 +200,7 @@ export const OpenCodeMemPlugin = async (ctx) => {
203
200
  timing: 0,
204
201
  };
205
202
  const userId = tags.user.userEmail || null;
206
- const memoryContext = formatContextForPrompt(userId, userMemories, projectMemories);
203
+ const memoryContext = formatContextForPrompt(userId, projectMemories);
207
204
  if (memoryContext) {
208
205
  const contextPart = {
209
206
  id: `memory-context-${Date.now()}`,
@@ -243,7 +240,6 @@ export const OpenCodeMemPlugin = async (ctx) => {
243
240
  content: tool.schema.string().optional(),
244
241
  query: tool.schema.string().optional(),
245
242
  type: tool.schema.string().optional(),
246
- scope: tool.schema.enum(["user", "project"]).optional(),
247
243
  memoryId: tool.schema.string().optional(),
248
244
  limit: tool.schema.number().optional(),
249
245
  },
@@ -271,28 +267,28 @@ export const OpenCodeMemPlugin = async (ctx) => {
271
267
  commands: [
272
268
  {
273
269
  command: "add",
274
- description: "Store a new memory",
275
- args: ["content", "type?", "scope?"],
270
+ description: "Store a new project memory",
271
+ args: ["content", "type?"],
276
272
  },
277
273
  {
278
274
  command: "search",
279
- description: "Search memories",
280
- args: ["query", "scope?"],
275
+ description: "Search project memories",
276
+ args: ["query"],
281
277
  },
282
278
  {
283
279
  command: "profile",
284
- description: "View user profile",
285
- args: ["query?"],
280
+ description: "View user profile (preferences, patterns, workflows)",
281
+ args: [],
286
282
  },
287
283
  {
288
284
  command: "list",
289
- description: "List recent memories",
290
- args: ["scope?", "limit?"],
285
+ description: "List recent project memories",
286
+ args: ["limit?"],
291
287
  },
292
288
  {
293
289
  command: "forget",
294
- description: "Remove a memory",
295
- args: ["memoryId", "scope?"],
290
+ description: "Remove a project memory",
291
+ args: ["memoryId"],
296
292
  },
297
293
  {
298
294
  command: "capture-now",
@@ -300,10 +296,7 @@ export const OpenCodeMemPlugin = async (ctx) => {
300
296
  args: [],
301
297
  },
302
298
  ],
303
- scopes: {
304
- user: "Cross-project user behaviors, preferences, patterns, requests",
305
- project: "Project-specific knowledge, decisions, architecture, context",
306
- },
299
+ note: "User preferences are automatically learned through the user profile system. Only project-specific memories can be added manually.",
307
300
  typeGuidance: "Choose appropriate type: preference, architecture, workflow, bug-fix, configuration, pattern, request, context, etc. Be specific and descriptive with categories.",
308
301
  });
309
302
  }
@@ -321,8 +314,7 @@ export const OpenCodeMemPlugin = async (ctx) => {
321
314
  error: "Cannot store fully private content",
322
315
  });
323
316
  }
324
- const scope = args.scope || "project";
325
- const tagInfo = scope === "user" ? tags.user : tags.project;
317
+ const tagInfo = tags.project;
326
318
  const result = await memoryClient.addMemory(sanitizedContent, tagInfo.tag, {
327
319
  type: args.type,
328
320
  displayName: tagInfo.displayName,
@@ -340,9 +332,8 @@ export const OpenCodeMemPlugin = async (ctx) => {
340
332
  }
341
333
  return JSON.stringify({
342
334
  success: true,
343
- message: `Memory added to ${scope} scope`,
335
+ message: `Memory added to project`,
344
336
  id: result.id,
345
- scope,
346
337
  type: args.type,
347
338
  });
348
339
  }
@@ -353,58 +344,14 @@ export const OpenCodeMemPlugin = async (ctx) => {
353
344
  error: "query parameter is required for search mode",
354
345
  });
355
346
  }
356
- const scope = args.scope;
357
- if (scope === "user") {
358
- const result = await memoryClient.searchMemories(args.query, tags.user.tag);
359
- if (!result.success) {
360
- return JSON.stringify({
361
- success: false,
362
- error: result.error || "Failed to search memories",
363
- });
364
- }
365
- return formatSearchResults(args.query, scope, result, args.limit);
366
- }
367
- if (scope === "project") {
368
- const result = await memoryClient.searchMemories(args.query, tags.project.tag);
369
- if (!result.success) {
370
- return JSON.stringify({
371
- success: false,
372
- error: result.error || "Failed to search memories",
373
- });
374
- }
375
- return formatSearchResults(args.query, scope, result, args.limit);
376
- }
377
- const [userResult, projectResult] = await Promise.all([
378
- memoryClient.searchMemories(args.query, tags.user.tag),
379
- memoryClient.searchMemories(args.query, tags.project.tag),
380
- ]);
381
- if (!userResult.success || !projectResult.success) {
347
+ const result = await memoryClient.searchMemories(args.query, tags.project.tag);
348
+ if (!result.success) {
382
349
  return JSON.stringify({
383
350
  success: false,
384
- error: userResult.error || projectResult.error || "Failed to search memories",
351
+ error: result.error || "Failed to search memories",
385
352
  });
386
353
  }
387
- const combined = [
388
- ...(userResult.results || []).map((r) => ({
389
- ...r,
390
- scope: "user",
391
- })),
392
- ...(projectResult.results || []).map((r) => ({
393
- ...r,
394
- scope: "project",
395
- })),
396
- ].sort((a, b) => b.similarity - a.similarity);
397
- return JSON.stringify({
398
- success: true,
399
- query: args.query,
400
- count: combined.length,
401
- results: combined.slice(0, args.limit || 10).map((r) => ({
402
- id: r.id,
403
- content: r.memory || r.chunk,
404
- similarity: Math.round(r.similarity * 100),
405
- scope: r.scope,
406
- })),
407
- });
354
+ return formatSearchResults(args.query, result, args.limit);
408
355
  }
409
356
  case "profile": {
410
357
  const { userProfileManager } = await import("./services/user-profile/user-profile-manager.js");
@@ -432,10 +379,8 @@ export const OpenCodeMemPlugin = async (ctx) => {
432
379
  });
433
380
  }
434
381
  case "list": {
435
- const scope = args.scope || "project";
436
382
  const limit = args.limit || 20;
437
- const tagInfo = scope === "user" ? tags.user : tags.project;
438
- const result = await memoryClient.listMemories(tagInfo.tag, limit);
383
+ const result = await memoryClient.listMemories(tags.project.tag, limit);
439
384
  if (!result.success) {
440
385
  return JSON.stringify({
441
386
  success: false,
@@ -445,7 +390,6 @@ export const OpenCodeMemPlugin = async (ctx) => {
445
390
  const memories = result.memories || [];
446
391
  return JSON.stringify({
447
392
  success: true,
448
- scope,
449
393
  count: memories.length,
450
394
  memories: memories.map((m) => ({
451
395
  id: m.id,
@@ -462,7 +406,6 @@ export const OpenCodeMemPlugin = async (ctx) => {
462
406
  error: "memoryId parameter is required for forget mode",
463
407
  });
464
408
  }
465
- const scope = args.scope || "project";
466
409
  const result = await memoryClient.deleteMemory(args.memoryId);
467
410
  if (!result.success) {
468
411
  return JSON.stringify({
@@ -472,7 +415,7 @@ export const OpenCodeMemPlugin = async (ctx) => {
472
415
  }
473
416
  return JSON.stringify({
474
417
  success: true,
475
- message: `Memory ${args.memoryId} removed from ${scope} scope`,
418
+ message: `Memory ${args.memoryId} removed`,
476
419
  });
477
420
  }
478
421
  case "capture-now": {
@@ -509,7 +452,7 @@ export const OpenCodeMemPlugin = async (ctx) => {
509
452
  if (sessionID) {
510
453
  await performAutoCapture(ctx, sessionID, directory);
511
454
  }
512
- await performUserMemoryLearning(ctx, directory);
455
+ await performUserProfileLearning(ctx, directory);
513
456
  const { cleanupService } = await import("./services/cleanup-service.js");
514
457
  const shouldRun = await cleanupService.shouldRunCleanup();
515
458
  if (!shouldRun)
@@ -549,12 +492,11 @@ export const OpenCodeMemPlugin = async (ctx) => {
549
492
  },
550
493
  };
551
494
  };
552
- function formatSearchResults(query, scope, results, limit) {
495
+ function formatSearchResults(query, results, limit) {
553
496
  const memoryResults = results.results || [];
554
497
  return JSON.stringify({
555
498
  success: true,
556
499
  query,
557
- scope,
558
500
  count: memoryResults.length,
559
501
  results: memoryResults.slice(0, limit || 10).map((r) => ({
560
502
  id: r.id,
@@ -8,7 +8,6 @@ interface Memory {
8
8
  id: string;
9
9
  content: string;
10
10
  type?: string;
11
- scope: string;
12
11
  createdAt: string;
13
12
  updatedAt?: string;
14
13
  metadata?: Record<string, unknown>;
@@ -37,10 +36,9 @@ interface PaginatedResponse<T> {
37
36
  totalPages: number;
38
37
  }
39
38
  export declare function handleListTags(): Promise<ApiResponse<{
40
- user: TagInfo[];
41
39
  project: TagInfo[];
42
40
  }>>;
43
- export declare function handleListMemories(tag?: string, page?: number, pageSize?: number, scope?: "user" | "project", includePrompts?: boolean): Promise<ApiResponse<PaginatedResponse<Memory | any>>>;
41
+ export declare function handleListMemories(tag?: string, page?: number, pageSize?: number, includePrompts?: boolean): Promise<ApiResponse<PaginatedResponse<Memory | any>>>;
44
42
  export declare function handleAddMemory(data: {
45
43
  content: string;
46
44
  containerTag: string;
@@ -1 +1 @@
1
- {"version":3,"file":"api-handlers.d.ts","sourceRoot":"","sources":["../../src/services/api-handlers.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"api-handlers.d.ts","sourceRoot":"","sources":["../../src/services/api-handlers.ts"],"names":[],"mappings":"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"}
@@ -33,18 +33,16 @@ function safeJSONParse(jsonString) {
33
33
  function extractScopeFromTag(tag) {
34
34
  const parts = tag.split("_");
35
35
  if (parts.length >= 3) {
36
- const scope = parts[1];
37
36
  const hash = parts.slice(2).join("_");
38
- return { scope, hash };
37
+ return { scope: "project", hash };
39
38
  }
40
- return { scope: "user", hash: tag };
39
+ return { scope: "project", hash: tag };
41
40
  }
42
41
  export async function handleListTags() {
43
42
  try {
44
43
  await embeddingService.warmup();
45
- const userShards = shardManager.getAllShards("user", "");
46
44
  const projectShards = shardManager.getAllShards("project", "");
47
- const allShards = [...userShards, ...projectShards];
45
+ const allShards = [...projectShards];
48
46
  const tagsMap = new Map();
49
47
  for (const shard of allShards) {
50
48
  const db = connectionManager.getConnection(shard.dbPath);
@@ -63,19 +61,15 @@ export async function handleListTags() {
63
61
  }
64
62
  }
65
63
  }
66
- const userTags = [];
67
64
  const projectTags = [];
68
65
  for (const tagInfo of tagsMap.values()) {
69
- if (tagInfo.tag.includes("_user_")) {
70
- userTags.push(tagInfo);
71
- }
72
- else if (tagInfo.tag.includes("_project_")) {
66
+ if (tagInfo.tag.includes("_project_")) {
73
67
  projectTags.push(tagInfo);
74
68
  }
75
69
  }
76
70
  return {
77
71
  success: true,
78
- data: { user: userTags, project: projectTags },
72
+ data: { project: projectTags },
79
73
  };
80
74
  }
81
75
  catch (error) {
@@ -83,7 +77,7 @@ export async function handleListTags() {
83
77
  return { success: false, error: String(error) };
84
78
  }
85
79
  }
86
- export async function handleListMemories(tag, page = 1, pageSize = 20, scope, includePrompts = true) {
80
+ export async function handleListMemories(tag, page = 1, pageSize = 20, includePrompts = true) {
87
81
  try {
88
82
  await embeddingService.warmup();
89
83
  let allMemories = [];
@@ -96,22 +90,12 @@ export async function handleListMemories(tag, page = 1, pageSize = 20, scope, in
96
90
  allMemories.push(...memories);
97
91
  }
98
92
  }
99
- else if (scope) {
100
- const shards = shardManager.getAllShards(scope, "");
101
- for (const shard of shards) {
102
- const db = connectionManager.getConnection(shard.dbPath);
103
- const memories = vectorSearch.getAllMemories(db);
104
- allMemories.push(...memories.filter((m) => m.container_tag?.includes(`_${scope}_`)));
105
- }
106
- }
107
93
  else {
108
- const userShards = shardManager.getAllShards("user", "");
109
- const projectShards = shardManager.getAllShards("project", "");
110
- const allShards = [...userShards, ...projectShards];
111
- for (const shard of allShards) {
94
+ const shards = shardManager.getAllShards("project", "");
95
+ for (const shard of shards) {
112
96
  const db = connectionManager.getConnection(shard.dbPath);
113
97
  const memories = vectorSearch.getAllMemories(db);
114
- allMemories.push(...memories);
98
+ allMemories.push(...memories.filter((m) => m.container_tag?.includes(`_project_`)));
115
99
  }
116
100
  }
117
101
  const memoriesWithType = allMemories.map((r) => {
@@ -121,7 +105,6 @@ export async function handleListMemories(tag, page = 1, pageSize = 20, scope, in
121
105
  id: r.id,
122
106
  content: r.content,
123
107
  memoryType: r.type,
124
- scope: r.container_tag?.includes("_user_") ? "user" : "project",
125
108
  createdAt: Number(r.created_at),
126
109
  updatedAt: r.updated_at ? Number(r.updated_at) : undefined,
127
110
  metadata,
@@ -136,7 +119,7 @@ export async function handleListMemories(tag, page = 1, pageSize = 20, scope, in
136
119
  };
137
120
  });
138
121
  let timeline = memoriesWithType;
139
- if (includePrompts && scope === "project") {
122
+ if (includePrompts) {
140
123
  const prompts = userPromptManager.getCapturedPrompts(tag);
141
124
  const promptsWithType = prompts.map((p) => ({
142
125
  type: "prompt",
@@ -194,7 +177,6 @@ export async function handleListMemories(tag, page = 1, pageSize = 20, scope, in
194
177
  id: item.id,
195
178
  content: item.content,
196
179
  memoryType: item.memoryType,
197
- scope: item.scope,
198
180
  createdAt: safeToISOString(item.createdAt),
199
181
  updatedAt: item.updatedAt ? safeToISOString(item.updatedAt) : undefined,
200
182
  metadata: item.metadata,
@@ -244,12 +226,6 @@ export async function handleAddMemory(data) {
244
226
  await embeddingService.warmup();
245
227
  const vector = await embeddingService.embedWithTimeout(data.content);
246
228
  const { scope, hash } = extractScopeFromTag(data.containerTag);
247
- if (scope === "user") {
248
- return {
249
- success: false,
250
- error: "User-scoped memories are deprecated. Use user profile system instead.",
251
- };
252
- }
253
229
  const shard = shardManager.getWriteShard(scope, hash);
254
230
  const id = `mem_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;
255
231
  const now = Date.now();
@@ -286,9 +262,8 @@ export async function handleDeleteMemory(id, cascade = false) {
286
262
  if (!id) {
287
263
  return { success: false, error: "id is required" };
288
264
  }
289
- const userShards = shardManager.getAllShards("user", "");
290
265
  const projectShards = shardManager.getAllShards("project", "");
291
- const allShards = [...userShards, ...projectShards];
266
+ const allShards = [...projectShards];
292
267
  let deletedPrompt = false;
293
268
  for (const shard of allShards) {
294
269
  const db = connectionManager.getConnection(shard.dbPath);
@@ -339,9 +314,8 @@ export async function handleUpdateMemory(id, data) {
339
314
  return { success: false, error: "id is required" };
340
315
  }
341
316
  await embeddingService.warmup();
342
- const userShards = shardManager.getAllShards("user", "");
343
317
  const projectShards = shardManager.getAllShards("project", "");
344
- const allShards = [...userShards, ...projectShards];
318
+ const allShards = [...projectShards];
345
319
  let foundShard = null;
346
320
  let existingMemory = null;
347
321
  for (const shard of allShards) {
@@ -408,9 +382,8 @@ export async function handleSearch(query, tag, page = 1, pageSize = 20) {
408
382
  }
409
383
  }
410
384
  else {
411
- const userShards = shardManager.getAllShards("user", "");
412
385
  const projectShards = shardManager.getAllShards("project", "");
413
- const allShards = [...userShards, ...projectShards];
386
+ const allShards = [...projectShards];
414
387
  const uniqueTags = new Set();
415
388
  for (const shard of allShards) {
416
389
  const db = connectionManager.getConnection(shard.dbPath);
@@ -444,7 +417,6 @@ export async function handleSearch(query, tag, page = 1, pageSize = 20) {
444
417
  id: r.id,
445
418
  content: r.memory,
446
419
  type: r.metadata?.type,
447
- scope: r.containerTag?.includes("_user_") ? "user" : "project",
448
420
  createdAt: safeToISOString(r.metadata?.createdAt),
449
421
  updatedAt: r.metadata?.updatedAt ? safeToISOString(r.metadata.updatedAt) : undefined,
450
422
  similarity: Math.round(r.similarity * 100),
@@ -476,9 +448,8 @@ export async function handleSearch(query, tag, page = 1, pageSize = 20) {
476
448
  export async function handleStats() {
477
449
  try {
478
450
  await embeddingService.warmup();
479
- const userShards = shardManager.getAllShards("user", "");
480
451
  const projectShards = shardManager.getAllShards("project", "");
481
- const allShards = [...userShards, ...projectShards];
452
+ const allShards = [...projectShards];
482
453
  let userCount = 0;
483
454
  let projectCount = 0;
484
455
  const typeCount = {};
@@ -516,9 +487,8 @@ export async function handlePinMemory(id) {
516
487
  if (!id) {
517
488
  return { success: false, error: "id is required" };
518
489
  }
519
- const userShards = shardManager.getAllShards("user", "");
520
490
  const projectShards = shardManager.getAllShards("project", "");
521
- const allShards = [...userShards, ...projectShards];
491
+ const allShards = [...projectShards];
522
492
  for (const shard of allShards) {
523
493
  const db = connectionManager.getConnection(shard.dbPath);
524
494
  const memory = vectorSearch.getMemoryById(db, id);
@@ -539,9 +509,8 @@ export async function handleUnpinMemory(id) {
539
509
  if (!id) {
540
510
  return { success: false, error: "id is required" };
541
511
  }
542
- const userShards = shardManager.getAllShards("user", "");
543
512
  const projectShards = shardManager.getAllShards("project", "");
544
- const allShards = [...userShards, ...projectShards];
513
+ const allShards = [...projectShards];
545
514
  for (const shard of allShards) {
546
515
  const db = connectionManager.getConnection(shard.dbPath);
547
516
  const memory = vectorSearch.getMemoryById(db, id);
@@ -6,6 +6,6 @@ interface MemoryResultMinimal {
6
6
  interface MemoriesResponseMinimal {
7
7
  results?: MemoryResultMinimal[];
8
8
  }
9
- export declare function formatContextForPrompt(userId: string | null, userMemories: MemoriesResponseMinimal, projectMemories: MemoriesResponseMinimal): string;
9
+ export declare function formatContextForPrompt(userId: string | null, projectMemories: MemoriesResponseMinimal): string;
10
10
  export {};
11
11
  //# sourceMappingURL=context.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/services/context.ts"],"names":[],"mappings":"AAGA,UAAU,mBAAmB;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,uBAAuB;IAC/B,OAAO,CAAC,EAAE,mBAAmB,EAAE,CAAC;CACjC;AAED,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,MAAM,GAAG,IAAI,EACrB,YAAY,EAAE,uBAAuB,EACrC,eAAe,EAAE,uBAAuB,GACvC,MAAM,CAmCR"}
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/services/context.ts"],"names":[],"mappings":"AAGA,UAAU,mBAAmB;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,uBAAuB;IAC/B,OAAO,CAAC,EAAE,mBAAmB,EAAE,CAAC;CACjC;AAED,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,MAAM,GAAG,IAAI,EACrB,eAAe,EAAE,uBAAuB,GACvC,MAAM,CAyBR"}
@@ -1,6 +1,6 @@
1
1
  import { CONFIG } from "../config.js";
2
2
  import { getUserProfileContext } from "./user-profile/profile-context.js";
3
- export function formatContextForPrompt(userId, userMemories, projectMemories) {
3
+ export function formatContextForPrompt(userId, projectMemories) {
4
4
  const parts = ["[MEMORY]"];
5
5
  if (CONFIG.injectProfile && userId) {
6
6
  const profileContext = getUserProfileContext(userId);
@@ -17,15 +17,6 @@ export function formatContextForPrompt(userId, userMemories, projectMemories) {
17
17
  parts.push(`- [${similarity}%] ${content}`);
18
18
  });
19
19
  }
20
- const userResults = userMemories.results || [];
21
- if (userResults.length > 0) {
22
- parts.push("\nRelevant Memories:");
23
- userResults.forEach((mem) => {
24
- const similarity = Math.round(mem.similarity * 100);
25
- const content = mem.memory || mem.chunk || "";
26
- parts.push(`- [${similarity}%] ${content}`);
27
- });
28
- }
29
20
  if (parts.length === 1) {
30
21
  return "";
31
22
  }
@@ -1,6 +1,8 @@
1
1
  import { Database } from "bun:sqlite";
2
2
  export declare class ConnectionManager {
3
3
  private connections;
4
+ private sqliteConfigured;
5
+ private configureSqlite;
4
6
  private initDatabase;
5
7
  getConnection(dbPath: string): Database;
6
8
  closeConnection(dbPath: string): void;
@@ -1 +1 @@
1
- {"version":3,"file":"connection-manager.d.ts","sourceRoot":"","sources":["../../../src/services/sqlite/connection-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAKtC,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,WAAW,CAAoC;IAEvD,OAAO,CAAC,YAAY;IAUpB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ;IAiBvC,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IASrC,QAAQ,IAAI,IAAI;CAWjB;AAED,eAAO,MAAM,iBAAiB,mBAA0B,CAAC"}
1
+ {"version":3,"file":"connection-manager.d.ts","sourceRoot":"","sources":["../../../src/services/sqlite/connection-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAMtC,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,WAAW,CAAoC;IACvD,OAAO,CAAC,gBAAgB,CAAS;IAEjC,OAAO,CAAC,eAAe;IAyEvB,OAAO,CAAC,YAAY;IAqBpB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ;IAmBvC,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IASrC,QAAQ,IAAI,IAAI;CAWjB;AAED,eAAO,MAAM,iBAAiB,mBAA0B,CAAC"}
@@ -2,20 +2,96 @@ import { Database } from "bun:sqlite";
2
2
  import * as sqliteVec from "sqlite-vec";
3
3
  import { existsSync, mkdirSync } from "node:fs";
4
4
  import { log } from "../logger.js";
5
+ import { CONFIG } from "../../config.js";
5
6
  export class ConnectionManager {
6
7
  connections = new Map();
8
+ sqliteConfigured = false;
9
+ configureSqlite() {
10
+ if (this.sqliteConfigured)
11
+ return;
12
+ if (process.platform === "darwin") {
13
+ const customPath = CONFIG.customSqlitePath;
14
+ if (customPath) {
15
+ if (!existsSync(customPath)) {
16
+ throw new Error(`Custom SQLite library not found at: ${customPath}\n` +
17
+ `Please verify the path or install Homebrew SQLite:\n` +
18
+ ` brew install sqlite\n` +
19
+ ` brew --prefix sqlite`);
20
+ }
21
+ try {
22
+ Database.setCustomSQLite(customPath);
23
+ log("Using custom SQLite library", { path: customPath });
24
+ }
25
+ catch (error) {
26
+ throw new Error(`Failed to load custom SQLite library: ${error}\n` +
27
+ `Path: ${customPath}`);
28
+ }
29
+ }
30
+ else {
31
+ const commonPaths = [
32
+ "/opt/homebrew/opt/sqlite/lib/libsqlite3.dylib",
33
+ "/usr/local/opt/sqlite/lib/libsqlite3.dylib",
34
+ ];
35
+ let foundPath = null;
36
+ for (const path of commonPaths) {
37
+ if (existsSync(path)) {
38
+ foundPath = path;
39
+ break;
40
+ }
41
+ }
42
+ if (foundPath) {
43
+ try {
44
+ Database.setCustomSQLite(foundPath);
45
+ log("Auto-detected and using Homebrew SQLite", { path: foundPath });
46
+ }
47
+ catch (error) {
48
+ throw new Error(`Failed to load Homebrew SQLite: ${error}\n` +
49
+ `Path: ${foundPath}`);
50
+ }
51
+ }
52
+ else {
53
+ throw new Error(`macOS detected but no compatible SQLite library found.\n\n` +
54
+ `Apple's default SQLite does not support extension loading.\n` +
55
+ `Please install Homebrew SQLite and configure the path:\n\n` +
56
+ `1. Install Homebrew SQLite:\n` +
57
+ ` brew install sqlite\n\n` +
58
+ `2. Find the library path:\n` +
59
+ ` brew --prefix sqlite\n\n` +
60
+ `3. Add to ~/.config/opencode/opencode-mem.jsonc:\n` +
61
+ ` {\n` +
62
+ ` "customSqlitePath": "/opt/homebrew/opt/sqlite/lib/libsqlite3.dylib"\n` +
63
+ ` }\n\n` +
64
+ `Common paths:\n` +
65
+ ` - Apple Silicon: /opt/homebrew/opt/sqlite/lib/libsqlite3.dylib\n` +
66
+ ` - Intel Mac: /usr/local/opt/sqlite/lib/libsqlite3.dylib`);
67
+ }
68
+ }
69
+ }
70
+ this.sqliteConfigured = true;
71
+ }
7
72
  initDatabase(db) {
8
73
  db.run("PRAGMA journal_mode = WAL");
9
74
  db.run("PRAGMA synchronous = NORMAL");
10
75
  db.run("PRAGMA cache_size = -64000");
11
76
  db.run("PRAGMA temp_store = MEMORY");
12
77
  db.run("PRAGMA foreign_keys = ON");
13
- sqliteVec.load(db);
78
+ try {
79
+ sqliteVec.load(db);
80
+ }
81
+ catch (error) {
82
+ throw new Error(`Failed to load sqlite-vec extension: ${error}\n\n` +
83
+ `This usually means SQLite extension loading is disabled.\n` +
84
+ `On macOS, you must use Homebrew SQLite instead of Apple's SQLite.\n\n` +
85
+ `Solution:\n` +
86
+ `1. Install: brew install sqlite\n` +
87
+ `2. Configure customSqlitePath in ~/.config/opencode/opencode-mem.jsonc`);
88
+ }
14
89
  }
15
90
  getConnection(dbPath) {
16
91
  if (this.connections.has(dbPath)) {
17
92
  return this.connections.get(dbPath);
18
93
  }
94
+ this.configureSqlite();
19
95
  const dir = dbPath.substring(0, dbPath.lastIndexOf("/"));
20
96
  if (!existsSync(dir)) {
21
97
  mkdirSync(dir, { recursive: true });
@@ -1,3 +1,3 @@
1
1
  import type { PluginInput } from "@opencode-ai/plugin";
2
- export declare function performUserMemoryLearning(ctx: PluginInput, directory: string): Promise<void>;
2
+ export declare function performUserProfileLearning(ctx: PluginInput, directory: string): Promise<void>;
3
3
  //# sourceMappingURL=user-memory-learning.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"user-memory-learning.d.ts","sourceRoot":"","sources":["../../src/services/user-memory-learning.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AASvD,wBAAsB,yBAAyB,CAC7C,GAAG,EAAE,WAAW,EAChB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CA8Ef"}
1
+ {"version":3,"file":"user-memory-learning.d.ts","sourceRoot":"","sources":["../../src/services/user-memory-learning.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AASvD,wBAAsB,0BAA0B,CAC9C,GAAG,EAAE,WAAW,EAChB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CA8Ef"}
@@ -3,10 +3,10 @@ import { log } from "./logger.js";
3
3
  import { CONFIG } from "../config.js";
4
4
  import { userPromptManager } from "./user-prompt/user-prompt-manager.js";
5
5
  import { userProfileManager } from "./user-profile/user-profile-manager.js";
6
- export async function performUserMemoryLearning(ctx, directory) {
6
+ export async function performUserProfileLearning(ctx, directory) {
7
7
  try {
8
8
  const count = userPromptManager.countUnanalyzedForUserLearning();
9
- const threshold = CONFIG.userMemoryAnalysisInterval;
9
+ const threshold = CONFIG.userProfileAnalysisInterval;
10
10
  if (count < threshold) {
11
11
  return;
12
12
  }
@@ -30,9 +30,8 @@ async function handleRequest(req) {
30
30
  const tag = url.searchParams.get("tag") || undefined;
31
31
  const page = parseInt(url.searchParams.get("page") || "1");
32
32
  const pageSize = parseInt(url.searchParams.get("pageSize") || "20");
33
- const scope = url.searchParams.get("scope");
34
33
  const includePrompts = url.searchParams.get("includePrompts") !== "false";
35
- const result = await handleListMemories(tag, page, pageSize, scope, includePrompts);
34
+ const result = await handleListMemories(tag, page, pageSize, includePrompts);
36
35
  return jsonResponse(result);
37
36
  }
38
37
  if (path === "/api/memories" && method === "POST") {
package/dist/web/app.js CHANGED
@@ -1,14 +1,13 @@
1
1
  const API_BASE = "";
2
2
 
3
3
  const state = {
4
- tags: { user: [], project: [] },
4
+ tags: { project: [] },
5
5
  memories: [],
6
6
  currentPage: 1,
7
7
  pageSize: 20,
8
8
  totalPages: 1,
9
9
  totalItems: 0,
10
10
  selectedTag: "",
11
- currentScope: "project",
12
11
  currentView: "project",
13
12
  searchQuery: "",
14
13
  isSearching: false,
@@ -55,7 +54,7 @@ function populateTagDropdowns() {
55
54
  tagFilter.innerHTML = '<option value="">All Tags</option>';
56
55
  addTag.innerHTML = '<option value="">Select tag</option>';
57
56
 
58
- const scopeTags = state.currentScope === "user" ? state.tags.user : state.tags.project;
57
+ const scopeTags = state.tags.project;
59
58
 
60
59
  scopeTags.forEach((tagInfo) => {
61
60
  const displayText = tagInfo.displayName || tagInfo.tag;
@@ -77,7 +76,7 @@ function populateTagDropdowns() {
77
76
  async function loadMemories() {
78
77
  showRefreshIndicator(true);
79
78
 
80
- let endpoint = `/api/memories?page=${state.currentPage}&pageSize=${state.pageSize}&scope=${state.currentScope}&includePrompts=true`;
79
+ let endpoint = `/api/memories?page=${state.currentPage}&pageSize=${state.pageSize}&includePrompts=true`;
81
80
 
82
81
  if (state.isSearching && state.searchQuery) {
83
82
  endpoint = `/api/search?q=${encodeURIComponent(state.searchQuery)}&page=${state.currentPage}&pageSize=${state.pageSize}`;
@@ -173,15 +172,13 @@ function renderMemoryCard(memory) {
173
172
  : "";
174
173
 
175
174
  let displayInfo = memory.displayName || memory.id;
176
- if (memory.scope === "project" && memory.projectPath) {
175
+ if (memory.projectPath) {
177
176
  const pathParts = memory.projectPath.split("/");
178
177
  displayInfo = pathParts[pathParts.length - 1] || memory.projectPath;
179
178
  }
180
179
 
181
180
  let subtitle = "";
182
- if (memory.scope === "user" && memory.userEmail) {
183
- subtitle = `<span class="memory-subtitle">${escapeHtml(memory.userEmail)}</span>`;
184
- } else if (memory.scope === "project" && memory.projectPath) {
181
+ if (memory.projectPath) {
185
182
  subtitle = `<span class="memory-subtitle">${escapeHtml(memory.projectPath)}</span>`;
186
183
  }
187
184
 
@@ -202,7 +199,6 @@ function renderMemoryCard(memory) {
202
199
  <div class="memory-header">
203
200
  <div class="meta">
204
201
  <input type="checkbox" class="memory-checkbox" data-id="${memory.id}" ${isSelected ? "checked" : ""} />
205
- <span class="badge badge-${memory.scope}">${memory.scope}</span>
206
202
  ${memory.memoryType ? `<span class="badge badge-type">${memory.memoryType}</span>` : ""}
207
203
  ${isLinked ? '<span class="badge badge-linked"><i data-lucide="link" class="icon-sm"></i> LINKED</span>' : ""}
208
204
  ${similarityHtml}
@@ -280,10 +276,9 @@ function updatePagination() {
280
276
  }
281
277
 
282
278
  function updateSectionTitle() {
283
- const scopeName = state.currentScope.toUpperCase();
284
279
  const title = state.isSearching
285
280
  ? `└─ SEARCH RESULTS (${state.totalItems}) ──`
286
- : `└─ ${scopeName} MEMORIES (${state.totalItems}) ──`;
281
+ : `└─ PROJECT MEMORIES (${state.totalItems}) ──`;
287
282
  document.getElementById("section-title").textContent = title;
288
283
  }
289
284
 
@@ -291,9 +286,6 @@ async function loadStats() {
291
286
  const result = await fetchAPI("/api/stats");
292
287
  if (result.success) {
293
288
  document.getElementById("stats-total").textContent = `Total: ${result.data.total}`;
294
- document.getElementById("stats-user").textContent = `User: ${result.data.byScope.user}`;
295
- document.getElementById("stats-project").textContent =
296
- `Project: ${result.data.byScope.project}`;
297
289
  }
298
290
  }
299
291
 
@@ -495,13 +487,10 @@ function changePage(delta) {
495
487
  }
496
488
 
497
489
  function handleAddScopeChange() {
498
- const scope = document.getElementById("add-scope").value;
499
490
  const tagDropdown = document.getElementById("add-tag");
500
491
 
501
492
  tagDropdown.innerHTML = '<option value="">Select tag</option>';
502
493
 
503
- if (!scope || scope !== "project") return;
504
-
505
494
  const tags = state.tags.project;
506
495
  tags.forEach((tagInfo) => {
507
496
  const displayText = tagInfo.displayName || tagInfo.tag;
@@ -952,8 +941,6 @@ document.addEventListener("DOMContentLoaded", async () => {
952
941
  loadMemories();
953
942
  });
954
943
 
955
- document.getElementById("add-scope").addEventListener("change", handleAddScopeChange);
956
-
957
944
  document.getElementById("search-btn").addEventListener("click", performSearch);
958
945
  document.getElementById("clear-search-btn").addEventListener("click", clearSearch);
959
946
  document.getElementById("search-input").addEventListener("keypress", (e) => {
@@ -27,8 +27,6 @@
27
27
  </div>
28
28
  <div class="stats-bar">
29
29
  <span id="stats-total">Total: 0</span>
30
- <span id="stats-user">User: 0</span>
31
- <span id="stats-project">Project: 0</span>
32
30
  <span id="refresh-indicator" class="hidden"
33
31
  ><i data-lucide="rotate-cw" class="icon icon-spin"></i
34
32
  ></span>
@@ -145,14 +143,6 @@
145
143
  <h2>└─ ADD NEW MEMORY ──</h2>
146
144
  <form id="add-form">
147
145
  <div class="form-row">
148
- <div class="form-group">
149
- <label>Scope:</label>
150
- <select id="add-scope" required>
151
- <option value="">Select scope</option>
152
- <option value="project">Project</option>
153
- </select>
154
- </div>
155
-
156
146
  <div class="form-group">
157
147
  <label>Tag:</label>
158
148
  <select id="add-tag" required>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-mem",
3
- "version": "2.2.0",
3
+ "version": "2.3.1",
4
4
  "description": "OpenCode plugin that gives coding agents persistent memory using local vector database",
5
5
  "type": "module",
6
6
  "main": "dist/plugin.js",