opencode-mem 2.1.1 → 2.3.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 (33) hide show
  1. package/README.md +60 -77
  2. package/dist/config.d.ts +1 -2
  3. package/dist/config.d.ts.map +1 -1
  4. package/dist/config.js +11 -16
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +27 -86
  7. package/dist/plugin.d.ts.map +1 -1
  8. package/dist/plugin.js +0 -4
  9. package/dist/services/ai/providers/anthropic-messages.d.ts.map +1 -1
  10. package/dist/services/ai/providers/anthropic-messages.js +11 -17
  11. package/dist/services/ai/providers/openai-chat-completion.d.ts.map +1 -1
  12. package/dist/services/ai/providers/openai-chat-completion.js +11 -17
  13. package/dist/services/ai/providers/openai-responses.d.ts.map +1 -1
  14. package/dist/services/ai/providers/openai-responses.js +11 -17
  15. package/dist/services/api-handlers.d.ts +5 -3
  16. package/dist/services/api-handlers.d.ts.map +1 -1
  17. package/dist/services/api-handlers.js +165 -42
  18. package/dist/services/auto-capture.js +2 -2
  19. package/dist/services/context.d.ts +1 -1
  20. package/dist/services/context.d.ts.map +1 -1
  21. package/dist/services/context.js +1 -10
  22. package/dist/services/deduplication-service.d.ts.map +1 -1
  23. package/dist/services/deduplication-service.js +1 -3
  24. package/dist/services/logger.js +1 -1
  25. package/dist/services/user-memory-learning.d.ts +1 -1
  26. package/dist/services/user-memory-learning.d.ts.map +1 -1
  27. package/dist/services/user-memory-learning.js +5 -3
  28. package/dist/services/user-profile/user-profile-manager.d.ts.map +1 -1
  29. package/dist/services/web-server-worker.js +30 -3
  30. package/dist/web/app.js +254 -47
  31. package/dist/web/index.html +31 -15
  32. package/dist/web/styles.css +309 -0
  33. package/package.json +1 -1
package/README.md CHANGED
@@ -11,10 +11,9 @@ OpenCode Memory provides AI coding agents with the ability to remember and recal
11
11
  ## Key Features
12
12
 
13
13
  - **Local Vector Database**: SQLite-based storage with sqlite-vec extension
14
- - **Dual Memory Scopes**: Separate user-level and project-level memory contexts
14
+ - **Project Memory System**: Persistent storage for project-specific knowledge
15
+ - **User Profile System**: Automatic learning of preferences, patterns, and workflows
15
16
  - **Unified Timeline**: Browse memories and prompts together with linking support
16
- - **Prompt-Memory Linking**: Bidirectional links between prompts and generated memories
17
- - **User Learning System**: Analyzes user patterns and preferences from conversation history
18
17
  - **Web Interface**: Full-featured UI for memory management and search
19
18
  - **Auto-Capture System**: Intelligent prompt-based memory extraction
20
19
  - **Multi-Provider AI**: Support for OpenAI, Anthropic, and OpenAI-compatible APIs
@@ -52,16 +51,32 @@ bun run build
52
51
  ### Basic Usage
53
52
 
54
53
  ```typescript
55
- memory({ mode: "add", content: "User prefers TypeScript", scope: "user" })
56
- memory({ mode: "search", query: "coding preferences", scope: "user" })
54
+ // Add project memory
55
+ memory({ mode: "add", content: "Project uses microservices architecture" })
56
+
57
+ // Search memories
58
+ memory({ mode: "search", query: "architecture decisions" })
59
+
60
+ // View user profile
57
61
  memory({ mode: "profile" })
62
+
63
+ // List recent memories
64
+ memory({ mode: "list", limit: 10 })
58
65
  ```
59
66
 
60
67
  ### Web Interface
61
68
 
62
69
  Access at `http://127.0.0.1:4747` to browse memories, view prompt-memory links, and manage your memory database.
63
70
 
64
- ### Configuration
71
+ **Project Memory Timeline:**
72
+
73
+ ![Project Memory Timeline](.github/screenshot-project-memory.png)
74
+
75
+ **User Profile Viewer:**
76
+
77
+ ![User Profile Viewer](.github/screenshot-user-profile.png)
78
+
79
+ ## Configuration
65
80
 
66
81
  Configuration file: `~/.config/opencode/opencode-mem.jsonc`
67
82
 
@@ -75,21 +90,49 @@ Configuration file: `~/.config/opencode/opencode-mem.jsonc`
75
90
  "memoryProvider": "openai-chat",
76
91
  "memoryModel": "gpt-4",
77
92
  "memoryApiUrl": "https://api.openai.com/v1",
78
- "memoryApiKey": "sk-..."
93
+ "memoryApiKey": "sk-...",
94
+ "userProfileAnalysisInterval": 10,
95
+ "maxMemories": 10
79
96
  }
80
97
  ```
81
98
 
82
- ## Breaking Changes (v2.0)
99
+ See [Configuration Guide](https://github.com/tickernelz/opencode-mem/wiki/Configuration-Guide) for all options.
100
+
101
+ ## Breaking Changes (v2.3)
102
+
103
+ **User-scoped memories completely removed:**
104
+
105
+ - **Removed**: `scope` parameter from all memory operations
106
+ - **Removed**: `maxProjectMemories` config (use `maxMemories` instead)
107
+ - **Renamed**: `userMemoryAnalysisInterval` → `userProfileAnalysisInterval`
108
+ - **Renamed**: `performUserMemoryLearning()` → `performUserProfileLearning()`
109
+ - **Changed**: All memories are now project-scoped by default
110
+ - **Changed**: User preferences managed exclusively through automatic profile system
83
111
 
84
- **Token-based auto-capture has been replaced with prompt-based system:**
112
+ **Migration required:**
113
+ ```jsonc
114
+ // OLD
115
+ {
116
+ "userMemoryAnalysisInterval": 10,
117
+ "maxMemories": 5,
118
+ "maxProjectMemories": 10
119
+ }
120
+
121
+ // NEW
122
+ {
123
+ "userProfileAnalysisInterval": 10,
124
+ "maxMemories": 10
125
+ }
126
+ ```
85
127
 
86
- - Removed: `autoCaptureTokenThreshold`, `autoCaptureMinTokens`, `autoCaptureMaxMemories`, `autoCaptureSummaryMaxLength`, `autoCaptureContextWindow`
87
- - Added: `memoryProvider`, `userMemoryAnalysisInterval`, `autoCaptureMaxIterations`, `autoCaptureIterationTimeout`
88
- - New behavior: Triggers on session idle, analyzes last uncaptured prompt
89
- - Automatic skip logic for non-technical conversations
90
- - Prompt-memory linking with cascade delete support
128
+ Remove `scope` parameter from all `memory()` calls:
129
+ ```typescript
130
+ // OLD
131
+ memory({ mode: "add", content: "...", scope: "project" })
91
132
 
92
- **Migration required**: Remove deprecated config options and add new ones.
133
+ // NEW
134
+ memory({ mode: "add", content: "..." })
135
+ ```
93
136
 
94
137
  ## Documentation
95
138
 
@@ -98,73 +141,13 @@ For detailed documentation, see the [Wiki](https://github.com/tickernelz/opencod
98
141
  - [Installation Guide](https://github.com/tickernelz/opencode-mem/wiki/Installation-Guide)
99
142
  - [Quick Start](https://github.com/tickernelz/opencode-mem/wiki/Quick-Start)
100
143
  - [Configuration Guide](https://github.com/tickernelz/opencode-mem/wiki/Configuration-Guide)
144
+ - [User Profile System](https://github.com/tickernelz/opencode-mem/wiki/User-Profile-System)
101
145
  - [Memory Operations](https://github.com/tickernelz/opencode-mem/wiki/Memory-Operations)
102
146
  - [Auto-Capture System](https://github.com/tickernelz/opencode-mem/wiki/Auto-Capture-System)
103
147
  - [Web Interface](https://github.com/tickernelz/opencode-mem/wiki/Web-Interface)
104
- - [Embedding Models](https://github.com/tickernelz/opencode-mem/wiki/Embedding-Models)
105
- - [Performance Tuning](https://github.com/tickernelz/opencode-mem/wiki/Performance-Tuning)
148
+ - [API Reference](https://github.com/tickernelz/opencode-mem/wiki/API-Reference)
106
149
  - [Troubleshooting](https://github.com/tickernelz/opencode-mem/wiki/Troubleshooting)
107
150
 
108
- ## Features Overview
109
-
110
- ### Memory Scopes
111
-
112
- - **User Scope**: Cross-project preferences, coding style, communication patterns
113
- - **Project Scope**: Architecture decisions, technology stack, implementation details
114
-
115
- ### Auto-Capture System
116
-
117
- Automatically extracts memories from conversations:
118
-
119
- 1. Triggers on session idle
120
- 2. Analyzes last uncaptured prompt and response
121
- 3. Links memory to source prompt
122
- 4. Skips non-technical conversations
123
-
124
- ### User Learning System
125
-
126
- Analyzes batches of prompts to identify patterns (default: every 10 prompts):
127
-
128
- - Coding style preferences
129
- - Communication patterns
130
- - Tool preferences
131
- - Skill level indicators
132
-
133
- ### Web Interface
134
-
135
- - Unified timeline of memories and prompts
136
- - Visual prompt-memory link indicators
137
- - Cascade delete for linked items
138
- - Bulk operations
139
- - Search and filters
140
- - Maintenance tools (cleanup, deduplication)
141
-
142
- ## API Reference
143
-
144
- ### Memory Tool
145
-
146
- ```typescript
147
- memory({ mode: "add", content: "...", scope: "user|project" })
148
- memory({ mode: "search", query: "...", scope: "user|project" })
149
- memory({ mode: "list", scope: "user|project", limit: 10 })
150
- memory({ mode: "profile" })
151
- memory({ mode: "forget", memoryId: "..." })
152
- memory({ mode: "auto-capture-toggle" })
153
- memory({ mode: "auto-capture-stats" })
154
- memory({ mode: "capture-now" })
155
- ```
156
-
157
- ### REST API
158
-
159
- - `GET /api/memories?scope=project&includePrompts=true` - List memories/prompts
160
- - `POST /api/memories` - Create memory
161
- - `PUT /api/memories/:id` - Update memory
162
- - `DELETE /api/memories/:id?cascade=true` - Delete memory (and linked prompt)
163
- - `DELETE /api/prompts/:id?cascade=true` - Delete prompt (and linked memory)
164
- - `POST /api/search` - Vector search
165
- - `POST /api/cleanup` - Run cleanup
166
- - `POST /api/deduplicate` - Run deduplication
167
-
168
151
  ## Development
169
152
 
170
153
  ```bash
package/dist/config.d.ts CHANGED
@@ -6,7 +6,6 @@ export declare const CONFIG: {
6
6
  embeddingApiKey: string | undefined;
7
7
  similarityThreshold: number;
8
8
  maxMemories: number;
9
- maxProjectMemories: number;
10
9
  maxProfileItems: number;
11
10
  injectProfile: boolean;
12
11
  containerTagPrefix: string;
@@ -27,7 +26,7 @@ export declare const CONFIG: {
27
26
  autoCleanupRetentionDays: number;
28
27
  deduplicationEnabled: boolean;
29
28
  deduplicationSimilarityThreshold: number;
30
- userMemoryAnalysisInterval: number;
29
+ userProfileAnalysisInterval: number;
31
30
  userProfileMaxPreferences: number;
32
31
  userProfileMaxPatterns: number;
33
32
  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":"AAsWA,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;oBAuBb,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,
@@ -205,18 +204,18 @@ const CONFIG_TEMPLATE = `{
205
204
 
206
205
  // Days to keep AI session history before cleanup
207
206
  "aiSessionRetentionDays": 7,
208
-
207
+
209
208
  // ============================================
210
- // User Memory Learning
209
+ // User Profile System
211
210
  // ============================================
212
-
211
+
213
212
  // Analyze user prompts every N prompts to build/update your user profile
214
213
  // When N uncaptured prompts accumulate, AI will analyze them to identify:
215
214
  // - User preferences (code style, communication style, tool preferences)
216
215
  // - User patterns (recurring topics, problem domains, technical interests)
217
216
  // - User workflows (development habits, sequences, learning style)
218
217
  // - Skill level (overall and per-domain assessment)
219
- "userMemoryAnalysisInterval": 10,
218
+ "userProfileAnalysisInterval": 10,
220
219
 
221
220
  // Maximum number of preferences to keep in user profile (sorted by confidence)
222
221
  // Preferences are things like "prefers code without comments", "likes concise responses"
@@ -244,13 +243,10 @@ const CONFIG_TEMPLATE = `{
244
243
 
245
244
  // Minimum similarity score (0-1) for memory search results
246
245
  "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
-
246
+
247
+ // Maximum number of memories to return in search results
248
+ "maxMemories": 10,
249
+
254
250
  // ============================================
255
251
  // Advanced Settings
256
252
  // ============================================
@@ -304,7 +300,6 @@ export const CONFIG = {
304
300
  embeddingApiKey: fileConfig.embeddingApiKey ?? process.env.OPENAI_API_KEY,
305
301
  similarityThreshold: fileConfig.similarityThreshold ?? DEFAULTS.similarityThreshold,
306
302
  maxMemories: fileConfig.maxMemories ?? DEFAULTS.maxMemories,
307
- maxProjectMemories: fileConfig.maxProjectMemories ?? DEFAULTS.maxProjectMemories,
308
303
  maxProfileItems: fileConfig.maxProfileItems ?? DEFAULTS.maxProfileItems,
309
304
  injectProfile: fileConfig.injectProfile ?? DEFAULTS.injectProfile,
310
305
  containerTagPrefix: fileConfig.containerTagPrefix ?? DEFAULTS.containerTagPrefix,
@@ -328,7 +323,7 @@ export const CONFIG = {
328
323
  autoCleanupRetentionDays: fileConfig.autoCleanupRetentionDays ?? DEFAULTS.autoCleanupRetentionDays,
329
324
  deduplicationEnabled: fileConfig.deduplicationEnabled ?? DEFAULTS.deduplicationEnabled,
330
325
  deduplicationSimilarityThreshold: fileConfig.deduplicationSimilarityThreshold ?? DEFAULTS.deduplicationSimilarityThreshold,
331
- userMemoryAnalysisInterval: fileConfig.userMemoryAnalysisInterval ?? DEFAULTS.userMemoryAnalysisInterval,
326
+ userProfileAnalysisInterval: fileConfig.userProfileAnalysisInterval ?? DEFAULTS.userProfileAnalysisInterval,
332
327
  userProfileMaxPreferences: fileConfig.userProfileMaxPreferences ?? DEFAULTS.userProfileMaxPreferences,
333
328
  userProfileMaxPatterns: fileConfig.userProfileMaxPatterns ?? DEFAULTS.userProfileMaxPatterns,
334
329
  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,MAwlB/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, "");
@@ -109,7 +110,6 @@ export const OpenCodeMemPlugin = async (ctx) => {
109
110
  "chat.message": async (input, output) => {
110
111
  if (!isConfigured())
111
112
  return;
112
- const start = Date.now();
113
113
  try {
114
114
  const textParts = output.parts.filter((p) => p.type === "text");
115
115
  if (textParts.length === 0)
@@ -184,11 +184,7 @@ export const OpenCodeMemPlugin = async (ctx) => {
184
184
  return;
185
185
  }
186
186
  }
187
- const [userMemoriesResult, projectMemoriesListResult] = await Promise.all([
188
- memoryClient.searchMemories(userMessage, tags.user.tag),
189
- memoryClient.listMemories(tags.project.tag, CONFIG.maxProjectMemories),
190
- ]);
191
- const userMemories = userMemoriesResult.success ? userMemoriesResult : { results: [] };
187
+ const projectMemoriesListResult = await memoryClient.listMemories(tags.project.tag, CONFIG.maxMemories);
192
188
  const projectMemoriesList = projectMemoriesListResult.success
193
189
  ? projectMemoriesListResult
194
190
  : { memories: [] };
@@ -204,7 +200,7 @@ export const OpenCodeMemPlugin = async (ctx) => {
204
200
  timing: 0,
205
201
  };
206
202
  const userId = tags.user.userEmail || null;
207
- const memoryContext = formatContextForPrompt(userId, userMemories, projectMemories);
203
+ const memoryContext = formatContextForPrompt(userId, projectMemories);
208
204
  if (memoryContext) {
209
205
  const contextPart = {
210
206
  id: `memory-context-${Date.now()}`,
@@ -244,7 +240,6 @@ export const OpenCodeMemPlugin = async (ctx) => {
244
240
  content: tool.schema.string().optional(),
245
241
  query: tool.schema.string().optional(),
246
242
  type: tool.schema.string().optional(),
247
- scope: tool.schema.enum(["user", "project"]).optional(),
248
243
  memoryId: tool.schema.string().optional(),
249
244
  limit: tool.schema.number().optional(),
250
245
  },
@@ -272,28 +267,28 @@ export const OpenCodeMemPlugin = async (ctx) => {
272
267
  commands: [
273
268
  {
274
269
  command: "add",
275
- description: "Store a new memory",
276
- args: ["content", "type?", "scope?"],
270
+ description: "Store a new project memory",
271
+ args: ["content", "type?"],
277
272
  },
278
273
  {
279
274
  command: "search",
280
- description: "Search memories",
281
- args: ["query", "scope?"],
275
+ description: "Search project memories",
276
+ args: ["query"],
282
277
  },
283
278
  {
284
279
  command: "profile",
285
- description: "View user profile",
286
- args: ["query?"],
280
+ description: "View user profile (preferences, patterns, workflows)",
281
+ args: [],
287
282
  },
288
283
  {
289
284
  command: "list",
290
- description: "List recent memories",
291
- args: ["scope?", "limit?"],
285
+ description: "List recent project memories",
286
+ args: ["limit?"],
292
287
  },
293
288
  {
294
289
  command: "forget",
295
- description: "Remove a memory",
296
- args: ["memoryId", "scope?"],
290
+ description: "Remove a project memory",
291
+ args: ["memoryId"],
297
292
  },
298
293
  {
299
294
  command: "capture-now",
@@ -301,10 +296,7 @@ export const OpenCodeMemPlugin = async (ctx) => {
301
296
  args: [],
302
297
  },
303
298
  ],
304
- scopes: {
305
- user: "Cross-project user behaviors, preferences, patterns, requests",
306
- project: "Project-specific knowledge, decisions, architecture, context",
307
- },
299
+ note: "User preferences are automatically learned through the user profile system. Only project-specific memories can be added manually.",
308
300
  typeGuidance: "Choose appropriate type: preference, architecture, workflow, bug-fix, configuration, pattern, request, context, etc. Be specific and descriptive with categories.",
309
301
  });
310
302
  }
@@ -322,8 +314,7 @@ export const OpenCodeMemPlugin = async (ctx) => {
322
314
  error: "Cannot store fully private content",
323
315
  });
324
316
  }
325
- const scope = args.scope || "project";
326
- const tagInfo = scope === "user" ? tags.user : tags.project;
317
+ const tagInfo = tags.project;
327
318
  const result = await memoryClient.addMemory(sanitizedContent, tagInfo.tag, {
328
319
  type: args.type,
329
320
  displayName: tagInfo.displayName,
@@ -341,9 +332,8 @@ export const OpenCodeMemPlugin = async (ctx) => {
341
332
  }
342
333
  return JSON.stringify({
343
334
  success: true,
344
- message: `Memory added to ${scope} scope`,
335
+ message: `Memory added to project`,
345
336
  id: result.id,
346
- scope,
347
337
  type: args.type,
348
338
  });
349
339
  }
@@ -354,58 +344,14 @@ export const OpenCodeMemPlugin = async (ctx) => {
354
344
  error: "query parameter is required for search mode",
355
345
  });
356
346
  }
357
- const scope = args.scope;
358
- if (scope === "user") {
359
- const result = await memoryClient.searchMemories(args.query, tags.user.tag);
360
- if (!result.success) {
361
- return JSON.stringify({
362
- success: false,
363
- error: result.error || "Failed to search memories",
364
- });
365
- }
366
- return formatSearchResults(args.query, scope, result, args.limit);
367
- }
368
- if (scope === "project") {
369
- const result = await memoryClient.searchMemories(args.query, tags.project.tag);
370
- if (!result.success) {
371
- return JSON.stringify({
372
- success: false,
373
- error: result.error || "Failed to search memories",
374
- });
375
- }
376
- return formatSearchResults(args.query, scope, result, args.limit);
377
- }
378
- const [userResult, projectResult] = await Promise.all([
379
- memoryClient.searchMemories(args.query, tags.user.tag),
380
- memoryClient.searchMemories(args.query, tags.project.tag),
381
- ]);
382
- if (!userResult.success || !projectResult.success) {
347
+ const result = await memoryClient.searchMemories(args.query, tags.project.tag);
348
+ if (!result.success) {
383
349
  return JSON.stringify({
384
350
  success: false,
385
- error: userResult.error || projectResult.error || "Failed to search memories",
351
+ error: result.error || "Failed to search memories",
386
352
  });
387
353
  }
388
- const combined = [
389
- ...(userResult.results || []).map((r) => ({
390
- ...r,
391
- scope: "user",
392
- })),
393
- ...(projectResult.results || []).map((r) => ({
394
- ...r,
395
- scope: "project",
396
- })),
397
- ].sort((a, b) => b.similarity - a.similarity);
398
- return JSON.stringify({
399
- success: true,
400
- query: args.query,
401
- count: combined.length,
402
- results: combined.slice(0, args.limit || 10).map((r) => ({
403
- id: r.id,
404
- content: r.memory || r.chunk,
405
- similarity: Math.round(r.similarity * 100),
406
- scope: r.scope,
407
- })),
408
- });
354
+ return formatSearchResults(args.query, result, args.limit);
409
355
  }
410
356
  case "profile": {
411
357
  const { userProfileManager } = await import("./services/user-profile/user-profile-manager.js");
@@ -433,10 +379,8 @@ export const OpenCodeMemPlugin = async (ctx) => {
433
379
  });
434
380
  }
435
381
  case "list": {
436
- const scope = args.scope || "project";
437
382
  const limit = args.limit || 20;
438
- const tagInfo = scope === "user" ? tags.user : tags.project;
439
- const result = await memoryClient.listMemories(tagInfo.tag, limit);
383
+ const result = await memoryClient.listMemories(tags.project.tag, limit);
440
384
  if (!result.success) {
441
385
  return JSON.stringify({
442
386
  success: false,
@@ -446,7 +390,6 @@ export const OpenCodeMemPlugin = async (ctx) => {
446
390
  const memories = result.memories || [];
447
391
  return JSON.stringify({
448
392
  success: true,
449
- scope,
450
393
  count: memories.length,
451
394
  memories: memories.map((m) => ({
452
395
  id: m.id,
@@ -463,7 +406,6 @@ export const OpenCodeMemPlugin = async (ctx) => {
463
406
  error: "memoryId parameter is required for forget mode",
464
407
  });
465
408
  }
466
- const scope = args.scope || "project";
467
409
  const result = await memoryClient.deleteMemory(args.memoryId);
468
410
  if (!result.success) {
469
411
  return JSON.stringify({
@@ -473,7 +415,7 @@ export const OpenCodeMemPlugin = async (ctx) => {
473
415
  }
474
416
  return JSON.stringify({
475
417
  success: true,
476
- message: `Memory ${args.memoryId} removed from ${scope} scope`,
418
+ message: `Memory ${args.memoryId} removed`,
477
419
  });
478
420
  }
479
421
  case "capture-now": {
@@ -510,7 +452,7 @@ export const OpenCodeMemPlugin = async (ctx) => {
510
452
  if (sessionID) {
511
453
  await performAutoCapture(ctx, sessionID, directory);
512
454
  }
513
- await performUserMemoryLearning(ctx, directory);
455
+ await performUserProfileLearning(ctx, directory);
514
456
  const { cleanupService } = await import("./services/cleanup-service.js");
515
457
  const shouldRun = await cleanupService.shouldRunCleanup();
516
458
  if (!shouldRun)
@@ -550,12 +492,11 @@ export const OpenCodeMemPlugin = async (ctx) => {
550
492
  },
551
493
  };
552
494
  };
553
- function formatSearchResults(query, scope, results, limit) {
495
+ function formatSearchResults(query, results, limit) {
554
496
  const memoryResults = results.results || [];
555
497
  return JSON.stringify({
556
498
  success: true,
557
499
  query,
558
- scope,
559
500
  count: memoryResults.length,
560
501
  results: memoryResults.slice(0, limit || 10).map((r) => ({
561
502
  id: r.id,
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":";AAOA,QAAA,MAAQ,iBAAiB,sCAA+B,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,CAAC;AAC7B,eAAe,iBAAiB,CAAC"}
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":";AACA,QAAA,MAAQ,iBAAiB,sCAA+B,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,CAAC;AAC7B,eAAe,iBAAiB,CAAC"}
package/dist/plugin.js CHANGED
@@ -1,8 +1,4 @@
1
1
  #!/usr/bin/env node
2
- import { fileURLToPath } from "node:url";
3
- import { dirname } from "node:path";
4
- const __filename = fileURLToPath(import.meta.url);
5
- const __dirname = dirname(__filename);
6
2
  const { OpenCodeMemPlugin } = await import("./index.js");
7
3
  export { OpenCodeMemPlugin };
8
4
  export default OpenCodeMemPlugin;
@@ -1 +1 @@
1
- {"version":3,"file":"anthropic-messages.d.ts","sourceRoot":"","sources":["../../../../src/services/ai/providers/anthropic-messages.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,EAAuB,KAAK,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AA2BvF,qBAAa,yBAA0B,SAAQ,cAAc;IAC3D,OAAO,CAAC,gBAAgB,CAAmB;gBAE/B,MAAM,EAAE,GAAG,EAAE,gBAAgB,EAAE,gBAAgB;IAK3D,eAAe,IAAI,MAAM;IAIzB,eAAe,IAAI,OAAO;IAIpB,eAAe,CACnB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,kBAAkB,EAC9B,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,cAAc,CAAC;IAmJ1B,OAAO,CAAC,cAAc;IActB,OAAO,CAAC,gBAAgB;CA+BzB"}
1
+ {"version":3,"file":"anthropic-messages.d.ts","sourceRoot":"","sources":["../../../../src/services/ai/providers/anthropic-messages.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,EAAuB,KAAK,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AA2BvF,qBAAa,yBAA0B,SAAQ,cAAc;IAC3D,OAAO,CAAC,gBAAgB,CAAmB;gBAE/B,MAAM,EAAE,GAAG,EAAE,gBAAgB,EAAE,gBAAgB;IAK3D,eAAe,IAAI,MAAM;IAIzB,eAAe,IAAI,OAAO;IAIpB,eAAe,CACnB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,kBAAkB,EAC9B,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,cAAc,CAAC;IAmJ1B,OAAO,CAAC,cAAc;IActB,OAAO,CAAC,gBAAgB;CAsBzB"}
@@ -153,24 +153,18 @@ export class AnthropicMessagesProvider extends BaseAIProvider {
153
153
  if (!data || typeof data !== "object") {
154
154
  throw new Error("Response is not an object");
155
155
  }
156
- if (data.memories && Array.isArray(data.memories)) {
157
- const validMemories = data.memories.filter((m) => {
158
- return (m &&
159
- typeof m === "object" &&
160
- typeof m.summary === "string" &&
161
- m.summary.trim().length > 0 &&
162
- (m.scope === "user" || m.scope === "project") &&
163
- typeof m.type === "string" &&
164
- m.type.trim().length > 0);
165
- });
166
- if (validMemories.length === 0) {
167
- throw new Error("No valid memories in response");
168
- }
169
- return { memories: validMemories };
156
+ if (Array.isArray(data)) {
157
+ throw new Error("Response cannot be an array");
170
158
  }
171
- if (data.summary && typeof data.summary === "string" && data.summary.trim().length > 0) {
172
- return data;
159
+ const keys = Object.keys(data);
160
+ if (keys.length === 0) {
161
+ throw new Error("Response object is empty");
162
+ }
163
+ for (const key of keys) {
164
+ if (data[key] === undefined || data[key] === null) {
165
+ throw new Error(`Response field '${key}' is null or undefined`);
166
+ }
173
167
  }
174
- throw new Error("Invalid response format: missing summary or memories field");
168
+ return data;
175
169
  }
176
170
  }
@@ -1 +1 @@
1
- {"version":3,"file":"openai-chat-completion.d.ts","sourceRoot":"","sources":["../../../../src/services/ai/providers/openai-chat-completion.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAkBlE,qBAAa,4BAA6B,SAAQ,cAAc;IAC9D,OAAO,CAAC,gBAAgB,CAAmB;gBAE/B,MAAM,EAAE,GAAG,EAAE,gBAAgB,EAAE,gBAAgB;IAK3D,eAAe,IAAI,MAAM;IAIzB,eAAe,IAAI,OAAO;IAIpB,eAAe,CACnB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,kBAAkB,EAC9B,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,cAAc,CAAC;IA2K1B,OAAO,CAAC,gBAAgB;CA+BzB"}
1
+ {"version":3,"file":"openai-chat-completion.d.ts","sourceRoot":"","sources":["../../../../src/services/ai/providers/openai-chat-completion.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAkBlE,qBAAa,4BAA6B,SAAQ,cAAc;IAC9D,OAAO,CAAC,gBAAgB,CAAmB;gBAE/B,MAAM,EAAE,GAAG,EAAE,gBAAgB,EAAE,gBAAgB;IAK3D,eAAe,IAAI,MAAM;IAIzB,eAAe,IAAI,OAAO;IAIpB,eAAe,CACnB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,kBAAkB,EAC9B,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,cAAc,CAAC;IA2K1B,OAAO,CAAC,gBAAgB;CAsBzB"}
@@ -158,24 +158,18 @@ export class OpenAIChatCompletionProvider extends BaseAIProvider {
158
158
  if (!data || typeof data !== "object") {
159
159
  throw new Error("Response is not an object");
160
160
  }
161
- if (data.memories && Array.isArray(data.memories)) {
162
- const validMemories = data.memories.filter((m) => {
163
- return (m &&
164
- typeof m === "object" &&
165
- typeof m.summary === "string" &&
166
- m.summary.trim().length > 0 &&
167
- (m.scope === "user" || m.scope === "project") &&
168
- typeof m.type === "string" &&
169
- m.type.trim().length > 0);
170
- });
171
- if (validMemories.length === 0) {
172
- throw new Error("No valid memories in response");
173
- }
174
- return { memories: validMemories };
161
+ if (Array.isArray(data)) {
162
+ throw new Error("Response cannot be an array");
175
163
  }
176
- if (data.summary && typeof data.summary === "string" && data.summary.trim().length > 0) {
177
- return data;
164
+ const keys = Object.keys(data);
165
+ if (keys.length === 0) {
166
+ throw new Error("Response object is empty");
167
+ }
168
+ for (const key of keys) {
169
+ if (data[key] === undefined || data[key] === null) {
170
+ throw new Error(`Response field '${key}' is null or undefined`);
171
+ }
178
172
  }
179
- throw new Error("Invalid response format: missing summary or memories field");
173
+ return data;
180
174
  }
181
175
  }
@@ -1 +1 @@
1
- {"version":3,"file":"openai-responses.d.ts","sourceRoot":"","sources":["../../../../src/services/ai/providers/openai-responses.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,EAAuB,KAAK,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAsBvF,qBAAa,uBAAwB,SAAQ,cAAc;IACzD,OAAO,CAAC,gBAAgB,CAAmB;gBAE/B,MAAM,EAAE,GAAG,EAAE,gBAAgB,EAAE,gBAAgB;IAK3D,eAAe,IAAI,MAAM;IAIzB,eAAe,IAAI,OAAO;IAIpB,eAAe,CACnB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,kBAAkB,EAC9B,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,cAAc,CAAC;IAuH1B,OAAO,CAAC,eAAe;IAsCvB,OAAO,CAAC,gBAAgB;IAgBxB,OAAO,CAAC,gBAAgB;CA+BzB"}
1
+ {"version":3,"file":"openai-responses.d.ts","sourceRoot":"","sources":["../../../../src/services/ai/providers/openai-responses.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,EAAuB,KAAK,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAsBvF,qBAAa,uBAAwB,SAAQ,cAAc;IACzD,OAAO,CAAC,gBAAgB,CAAmB;gBAE/B,MAAM,EAAE,GAAG,EAAE,gBAAgB,EAAE,gBAAgB;IAK3D,eAAe,IAAI,MAAM;IAIzB,eAAe,IAAI,OAAO;IAIpB,eAAe,CACnB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,kBAAkB,EAC9B,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,cAAc,CAAC;IAuH1B,OAAO,CAAC,eAAe;IAsCvB,OAAO,CAAC,gBAAgB;IAgBxB,OAAO,CAAC,gBAAgB;CAsBzB"}