@haisto/opencode-mem 2.14.3-beta.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 (152) hide show
  1. package/README.md +165 -0
  2. package/dist/config.d.ts +62 -0
  3. package/dist/config.d.ts.map +1 -0
  4. package/dist/config.js +457 -0
  5. package/dist/index.d.ts +3 -0
  6. package/dist/index.d.ts.map +1 -0
  7. package/dist/index.js +486 -0
  8. package/dist/plugin.d.ts +9 -0
  9. package/dist/plugin.d.ts.map +1 -0
  10. package/dist/plugin.js +5 -0
  11. package/dist/services/ai/ai-provider-factory.d.ts +8 -0
  12. package/dist/services/ai/ai-provider-factory.d.ts.map +1 -0
  13. package/dist/services/ai/ai-provider-factory.js +28 -0
  14. package/dist/services/ai/opencode-provider.d.ts +36 -0
  15. package/dist/services/ai/opencode-provider.d.ts.map +1 -0
  16. package/dist/services/ai/opencode-provider.js +92 -0
  17. package/dist/services/ai/provider-config.d.ts +17 -0
  18. package/dist/services/ai/provider-config.d.ts.map +1 -0
  19. package/dist/services/ai/provider-config.js +14 -0
  20. package/dist/services/ai/providers/anthropic-messages.d.ts +12 -0
  21. package/dist/services/ai/providers/anthropic-messages.d.ts.map +1 -0
  22. package/dist/services/ai/providers/anthropic-messages.js +184 -0
  23. package/dist/services/ai/providers/base-provider.d.ts +25 -0
  24. package/dist/services/ai/providers/base-provider.d.ts.map +1 -0
  25. package/dist/services/ai/providers/base-provider.js +23 -0
  26. package/dist/services/ai/providers/google-gemini.d.ts +16 -0
  27. package/dist/services/ai/providers/google-gemini.d.ts.map +1 -0
  28. package/dist/services/ai/providers/google-gemini.js +228 -0
  29. package/dist/services/ai/providers/openai-chat-completion.d.ts +14 -0
  30. package/dist/services/ai/providers/openai-chat-completion.d.ts.map +1 -0
  31. package/dist/services/ai/providers/openai-chat-completion.js +318 -0
  32. package/dist/services/ai/providers/openai-responses.d.ts +14 -0
  33. package/dist/services/ai/providers/openai-responses.d.ts.map +1 -0
  34. package/dist/services/ai/providers/openai-responses.js +182 -0
  35. package/dist/services/ai/session/ai-session-manager.d.ts +21 -0
  36. package/dist/services/ai/session/ai-session-manager.d.ts.map +1 -0
  37. package/dist/services/ai/session/ai-session-manager.js +166 -0
  38. package/dist/services/ai/session/session-types.d.ts +43 -0
  39. package/dist/services/ai/session/session-types.d.ts.map +1 -0
  40. package/dist/services/ai/session/session-types.js +1 -0
  41. package/dist/services/ai/tools/tool-schema.d.ts +41 -0
  42. package/dist/services/ai/tools/tool-schema.d.ts.map +1 -0
  43. package/dist/services/ai/tools/tool-schema.js +24 -0
  44. package/dist/services/ai/validators/user-profile-validator.d.ts +13 -0
  45. package/dist/services/ai/validators/user-profile-validator.d.ts.map +1 -0
  46. package/dist/services/ai/validators/user-profile-validator.js +111 -0
  47. package/dist/services/api-handlers.d.ts +164 -0
  48. package/dist/services/api-handlers.d.ts.map +1 -0
  49. package/dist/services/api-handlers.js +927 -0
  50. package/dist/services/auto-capture.d.ts +3 -0
  51. package/dist/services/auto-capture.d.ts.map +1 -0
  52. package/dist/services/auto-capture.js +309 -0
  53. package/dist/services/cleanup-service.d.ts +23 -0
  54. package/dist/services/cleanup-service.d.ts.map +1 -0
  55. package/dist/services/cleanup-service.js +102 -0
  56. package/dist/services/client.d.ts +119 -0
  57. package/dist/services/client.d.ts.map +1 -0
  58. package/dist/services/client.js +257 -0
  59. package/dist/services/context.d.ts +11 -0
  60. package/dist/services/context.d.ts.map +1 -0
  61. package/dist/services/context.js +34 -0
  62. package/dist/services/deduplication-service.d.ts +30 -0
  63. package/dist/services/deduplication-service.d.ts.map +1 -0
  64. package/dist/services/deduplication-service.js +124 -0
  65. package/dist/services/embedding.d.ts +15 -0
  66. package/dist/services/embedding.d.ts.map +1 -0
  67. package/dist/services/embedding.js +127 -0
  68. package/dist/services/jsonc.d.ts +7 -0
  69. package/dist/services/jsonc.d.ts.map +1 -0
  70. package/dist/services/jsonc.js +76 -0
  71. package/dist/services/language-detector.d.ts +3 -0
  72. package/dist/services/language-detector.d.ts.map +1 -0
  73. package/dist/services/language-detector.js +33 -0
  74. package/dist/services/logger.d.ts +11 -0
  75. package/dist/services/logger.d.ts.map +1 -0
  76. package/dist/services/logger.js +97 -0
  77. package/dist/services/migration-service.d.ts +42 -0
  78. package/dist/services/migration-service.d.ts.map +1 -0
  79. package/dist/services/migration-service.js +250 -0
  80. package/dist/services/privacy.d.ts +3 -0
  81. package/dist/services/privacy.d.ts.map +1 -0
  82. package/dist/services/privacy.js +7 -0
  83. package/dist/services/secret-resolver.d.ts +2 -0
  84. package/dist/services/secret-resolver.d.ts.map +1 -0
  85. package/dist/services/secret-resolver.js +55 -0
  86. package/dist/services/sqlite/connection-manager.d.ts +13 -0
  87. package/dist/services/sqlite/connection-manager.d.ts.map +1 -0
  88. package/dist/services/sqlite/connection-manager.js +74 -0
  89. package/dist/services/sqlite/shard-manager.d.ts +23 -0
  90. package/dist/services/sqlite/shard-manager.d.ts.map +1 -0
  91. package/dist/services/sqlite/shard-manager.js +288 -0
  92. package/dist/services/sqlite/sqlite-bootstrap.d.ts +2 -0
  93. package/dist/services/sqlite/sqlite-bootstrap.d.ts.map +1 -0
  94. package/dist/services/sqlite/sqlite-bootstrap.js +8 -0
  95. package/dist/services/sqlite/types.d.ts +42 -0
  96. package/dist/services/sqlite/types.d.ts.map +1 -0
  97. package/dist/services/sqlite/types.js +1 -0
  98. package/dist/services/sqlite/vector-search.d.ts +29 -0
  99. package/dist/services/sqlite/vector-search.d.ts.map +1 -0
  100. package/dist/services/sqlite/vector-search.js +279 -0
  101. package/dist/services/tags.d.ts +24 -0
  102. package/dist/services/tags.d.ts.map +1 -0
  103. package/dist/services/tags.js +145 -0
  104. package/dist/services/user-memory-learning.d.ts +3 -0
  105. package/dist/services/user-memory-learning.d.ts.map +1 -0
  106. package/dist/services/user-memory-learning.js +235 -0
  107. package/dist/services/user-profile/profile-context.d.ts +2 -0
  108. package/dist/services/user-profile/profile-context.d.ts.map +1 -0
  109. package/dist/services/user-profile/profile-context.js +40 -0
  110. package/dist/services/user-profile/profile-utils.d.ts +3 -0
  111. package/dist/services/user-profile/profile-utils.d.ts.map +1 -0
  112. package/dist/services/user-profile/profile-utils.js +45 -0
  113. package/dist/services/user-profile/types.d.ts +46 -0
  114. package/dist/services/user-profile/types.d.ts.map +1 -0
  115. package/dist/services/user-profile/types.js +1 -0
  116. package/dist/services/user-profile/user-profile-manager.d.ts +23 -0
  117. package/dist/services/user-profile/user-profile-manager.d.ts.map +1 -0
  118. package/dist/services/user-profile/user-profile-manager.js +337 -0
  119. package/dist/services/user-prompt/user-prompt-manager.d.ts +41 -0
  120. package/dist/services/user-prompt/user-prompt-manager.d.ts.map +1 -0
  121. package/dist/services/user-prompt/user-prompt-manager.js +192 -0
  122. package/dist/services/vector-backends/backend-factory.d.ts +3 -0
  123. package/dist/services/vector-backends/backend-factory.d.ts.map +1 -0
  124. package/dist/services/vector-backends/backend-factory.js +104 -0
  125. package/dist/services/vector-backends/exact-scan-backend.d.ts +39 -0
  126. package/dist/services/vector-backends/exact-scan-backend.d.ts.map +1 -0
  127. package/dist/services/vector-backends/exact-scan-backend.js +63 -0
  128. package/dist/services/vector-backends/types.d.ts +51 -0
  129. package/dist/services/vector-backends/types.d.ts.map +1 -0
  130. package/dist/services/vector-backends/types.js +1 -0
  131. package/dist/services/vector-backends/usearch-backend.d.ts +47 -0
  132. package/dist/services/vector-backends/usearch-backend.d.ts.map +1 -0
  133. package/dist/services/vector-backends/usearch-backend.js +174 -0
  134. package/dist/services/web-server-worker.d.ts +2 -0
  135. package/dist/services/web-server-worker.d.ts.map +1 -0
  136. package/dist/services/web-server-worker.js +283 -0
  137. package/dist/services/web-server.d.ts +31 -0
  138. package/dist/services/web-server.d.ts.map +1 -0
  139. package/dist/services/web-server.js +356 -0
  140. package/dist/types/index.d.ts +19 -0
  141. package/dist/types/index.d.ts.map +1 -0
  142. package/dist/types/index.js +1 -0
  143. package/dist/web/app.d.ts +2 -0
  144. package/dist/web/app.d.ts.map +1 -0
  145. package/dist/web/app.js +1238 -0
  146. package/dist/web/favicon.ico +0 -0
  147. package/dist/web/i18n.d.ts +2 -0
  148. package/dist/web/i18n.d.ts.map +1 -0
  149. package/dist/web/i18n.js +312 -0
  150. package/dist/web/index.html +293 -0
  151. package/dist/web/styles.css +1786 -0
  152. package/package.json +78 -0
package/README.md ADDED
@@ -0,0 +1,165 @@
1
+ # OpenCode Memory
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
+
7
+ ![OpenCode Memory Banner](.github/banner.png)
8
+
9
+ A persistent memory system for AI coding agents that enables long-term context retention across sessions using local vector database technology.
10
+
11
+ ## Visual Overview
12
+
13
+ **Project Memory Timeline:**
14
+
15
+ ![Project Memory Timeline](.github/screenshot-project-memory.png)
16
+
17
+ **User Profile Viewer:**
18
+
19
+ ![User Profile Viewer](.github/screenshot-user-profile.png)
20
+
21
+ ## Core Features
22
+
23
+ Local vector database with SQLite + USearch-first vector indexing and ExactScan fallback, persistent project memories, automatic user profile learning, unified memory-prompt timeline, full-featured web UI, intelligent prompt-based memory extraction, multi-provider AI support (OpenAI, Anthropic), 12+ local embedding models, smart deduplication, and built-in privacy protection.
24
+
25
+ ## Prerequisites
26
+
27
+ This plugin uses `USearch` for preferred in-memory vector indexing with automatic ExactScan fallback. No custom SQLite build or browser runtime shim is required.
28
+
29
+ **Recommended runtime:**
30
+
31
+ - Bun
32
+ - Standard OpenCode plugin environment
33
+
34
+ **Notes:**
35
+
36
+ - If `USearch` is unavailable or fails at runtime, the plugin automatically falls back to exact vector scanning.
37
+ - SQLite remains the source of truth; search indexes are rebuilt from SQLite data when needed.
38
+
39
+ ## Getting Started
40
+
41
+ Add to your OpenCode configuration at `~/.config/opencode/opencode.json`:
42
+
43
+ ```jsonc
44
+ {
45
+ "plugin": ["opencode-mem"],
46
+ }
47
+ ```
48
+
49
+ The plugin downloads automatically on next startup.
50
+
51
+ ## Usage Examples
52
+
53
+ ```typescript
54
+ memory({ mode: "add", content: "Project uses microservices architecture" });
55
+ memory({ mode: "search", query: "architecture decisions" });
56
+ memory({ mode: "search", query: "architecture decisions", scope: "all-projects" });
57
+ memory({ mode: "profile" });
58
+ memory({ mode: "list", limit: 10 });
59
+ ```
60
+
61
+ Access the web interface at `http://127.0.0.1:4747` for visual memory browsing and management.
62
+
63
+ ## Configuration Essentials
64
+
65
+ Configure at `~/.config/opencode/opencode-mem.jsonc`:
66
+
67
+ ```jsonc
68
+ {
69
+ "storagePath": "~/.opencode-mem/data",
70
+ "userEmailOverride": "user@example.com",
71
+ "userNameOverride": "John Doe",
72
+ "embeddingModel": "Xenova/nomic-embed-text-v1",
73
+ "memory": {
74
+ "defaultScope": "project",
75
+ },
76
+ "webServerEnabled": true,
77
+ "webServerPort": 4747,
78
+
79
+ "autoCaptureEnabled": true,
80
+ "autoCaptureLanguage": "auto",
81
+
82
+ "opencodeProvider": "anthropic",
83
+ "opencodeModel": "claude-haiku-4-5-20251001",
84
+
85
+ "showAutoCaptureToasts": true,
86
+ "showUserProfileToasts": true,
87
+ "showErrorToasts": true,
88
+
89
+ "userProfileAnalysisInterval": 10,
90
+ "maxMemories": 10,
91
+
92
+ "compaction": {
93
+ "enabled": true,
94
+ "memoryLimit": 10,
95
+ },
96
+ "chatMessage": {
97
+ "enabled": true,
98
+ "maxMemories": 3,
99
+ "excludeCurrentSession": true,
100
+ "maxAgeDays": undefined,
101
+ "injectOn": "first",
102
+ },
103
+ }
104
+ ```
105
+
106
+ ### Memory Scope
107
+
108
+ - `scope: "project"`: query only the current project. This is the default.
109
+ - `scope: "all-projects"`: query `search` / `list` across all project shards.
110
+ - `memory.defaultScope` sets the default query scope when no explicit scope is provided.
111
+
112
+ ### Auto-Capture AI Provider
113
+
114
+ **Recommended:** Use any provider that is already authenticated in opencode (no separate API key needed in this plugin):
115
+
116
+ ```jsonc
117
+ "opencodeProvider": "anthropic",
118
+ "opencodeModel": "claude-haiku-4-5-20251001",
119
+ ```
120
+
121
+ The plugin issues structured-output requests to opencode's session API instead of calling provider endpoints directly, so opencode owns the auth, token refresh, and provider routing. Whatever you configured in opencode just works — Claude Pro/Max via OAuth, GitHub Copilot (personal & business), OpenAI / Anthropic API keys, custom providers, etc.
122
+
123
+ Supported providers: any provider listed by `opencode providers list` (e.g. `anthropic`, `openai`, `github-copilot`, ...).
124
+
125
+ **Fallback:** Manual API configuration (if not using opencodeProvider):
126
+
127
+ ```jsonc
128
+ "memoryProvider": "openai-chat",
129
+ "memoryModel": "gpt-4o-mini",
130
+ "memoryApiUrl": "https://api.openai.com/v1",
131
+ "memoryApiKey": "sk-...",
132
+ ```
133
+
134
+ **API Key Formats:**
135
+
136
+ ```jsonc
137
+ "memoryApiKey": "sk-..."
138
+ "memoryApiKey": "file://~/.config/opencode/api-key.txt"
139
+ "memoryApiKey": "env://OPENAI_API_KEY"
140
+ ```
141
+
142
+ Full documentation available in this README.
143
+
144
+ ## Development & Contribution
145
+
146
+ Build and test locally:
147
+
148
+ ```bash
149
+ bun install
150
+ bun run build
151
+ bun run typecheck
152
+ bun run format
153
+ ```
154
+
155
+ This project is actively seeking contributions to become the definitive memory plugin for AI coding agents. Whether you are fixing bugs, adding features, improving documentation, or expanding embedding model support, your contributions are critical. The codebase is well-structured and ready for enhancement. If you hit a blocker or have improvement ideas, submit a pull request - we review and merge contributions quickly.
156
+
157
+ ## License & Links
158
+
159
+ MIT License - see LICENSE file
160
+
161
+ - **Repository**: https://github.com/tickernelz/opencode-mem
162
+ - **Issues**: https://github.com/tickernelz/opencode-mem/issues
163
+ - **OpenCode Platform**: https://opencode.ai
164
+
165
+ Inspired by [opencode-supermemory](https://github.com/supermemoryai/opencode-supermemory)
@@ -0,0 +1,62 @@
1
+ export declare let CONFIG: {
2
+ storagePath: string;
3
+ userEmailOverride: string | undefined;
4
+ userNameOverride: string | undefined;
5
+ embeddingModel: string;
6
+ embeddingDimensions: number;
7
+ embeddingApiUrl: string | undefined;
8
+ embeddingApiKey: string | undefined;
9
+ similarityThreshold: number;
10
+ maxMemories: number;
11
+ maxProfileItems: number;
12
+ injectProfile: boolean;
13
+ containerTagPrefix: string;
14
+ autoCaptureEnabled: boolean;
15
+ autoCaptureMaxIterations: number;
16
+ autoCaptureIterationTimeout: number;
17
+ autoCaptureLanguage: string | undefined;
18
+ memoryProvider: "openai-chat" | "openai-responses" | "anthropic";
19
+ memoryModel: string | undefined;
20
+ memoryApiUrl: string | undefined;
21
+ memoryApiKey: string | undefined;
22
+ memoryTemperature: number | false | undefined;
23
+ memoryExtraParams: Record<string, unknown> | undefined;
24
+ opencodeProvider: string | undefined;
25
+ opencodeModel: string | undefined;
26
+ vectorBackend: "usearch-first" | "usearch" | "exact-scan";
27
+ aiSessionRetentionDays: number;
28
+ webServerEnabled: boolean;
29
+ webServerPort: number;
30
+ webServerHost: string;
31
+ maxVectorsPerShard: number;
32
+ autoCleanupEnabled: boolean;
33
+ autoCleanupRetentionDays: number;
34
+ deduplicationEnabled: boolean;
35
+ deduplicationSimilarityThreshold: number;
36
+ userProfileAnalysisInterval: number;
37
+ userProfileMaxPreferences: number;
38
+ userProfileMaxPatterns: number;
39
+ userProfileMaxWorkflows: number;
40
+ userProfileConfidenceDecayDays: number;
41
+ userProfileChangelogRetentionCount: number;
42
+ showAutoCaptureToasts: boolean;
43
+ showUserProfileToasts: boolean;
44
+ showErrorToasts: boolean;
45
+ memory: {
46
+ defaultScope: "project" | "all-projects" | undefined;
47
+ };
48
+ compaction: {
49
+ enabled: boolean | undefined;
50
+ memoryLimit: number | undefined;
51
+ };
52
+ chatMessage: {
53
+ enabled: boolean | undefined;
54
+ maxMemories: number | undefined;
55
+ excludeCurrentSession: boolean | undefined;
56
+ maxAgeDays: number | undefined;
57
+ injectOn: "first" | "always";
58
+ };
59
+ };
60
+ export declare function initConfig(directory: string): void;
61
+ export declare function isConfigured(): boolean;
62
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AA2jBA,eAAO,IAAI,MAAM;;;;;;;;;;;;;;;;;oBA3DT,aAAa,GACb,kBAAkB,GAClB,WAAW;;;;;;;;mBASX,eAAe,GACf,SAAS,GACT,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAuCV,OAAO,GACP,QAAQ;;CAMgC,CAAC;AAEnD,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CASlD;AAED,wBAAgB,YAAY,IAAI,OAAO,CAEtC"}
package/dist/config.js ADDED
@@ -0,0 +1,457 @@
1
+ import { existsSync, readFileSync, mkdirSync, writeFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { homedir } from "node:os";
4
+ import { stripJsoncComments } from "./services/jsonc.js";
5
+ import { resolveSecretValue } from "./services/secret-resolver.js";
6
+ const CONFIG_DIR = join(homedir(), ".config", "opencode");
7
+ const DATA_DIR = join(homedir(), ".opencode-mem");
8
+ const CONFIG_FILES = [
9
+ join(CONFIG_DIR, "opencode-mem.jsonc"),
10
+ join(CONFIG_DIR, "opencode-mem.json"),
11
+ ];
12
+ if (!existsSync(CONFIG_DIR)) {
13
+ mkdirSync(CONFIG_DIR, { recursive: true });
14
+ }
15
+ if (!existsSync(DATA_DIR)) {
16
+ mkdirSync(DATA_DIR, { recursive: true });
17
+ }
18
+ const DEFAULTS = {
19
+ storagePath: join(DATA_DIR, "data"),
20
+ embeddingModel: "Xenova/nomic-embed-text-v1",
21
+ embeddingDimensions: 768,
22
+ similarityThreshold: 0.6,
23
+ maxMemories: 10,
24
+ maxProfileItems: 5,
25
+ injectProfile: true,
26
+ containerTagPrefix: "opencode",
27
+ autoCaptureEnabled: true,
28
+ autoCaptureMaxIterations: 5,
29
+ autoCaptureIterationTimeout: 30000,
30
+ vectorBackend: "usearch-first",
31
+ aiSessionRetentionDays: 7,
32
+ webServerEnabled: true,
33
+ webServerPort: 4747,
34
+ webServerHost: "127.0.0.1",
35
+ maxVectorsPerShard: 50000,
36
+ autoCleanupEnabled: true,
37
+ autoCleanupRetentionDays: 30,
38
+ deduplicationEnabled: true,
39
+ deduplicationSimilarityThreshold: 0.9,
40
+ userProfileAnalysisInterval: 10,
41
+ userProfileMaxPreferences: 20,
42
+ userProfileMaxPatterns: 15,
43
+ userProfileMaxWorkflows: 10,
44
+ userProfileConfidenceDecayDays: 30,
45
+ userProfileChangelogRetentionCount: 5,
46
+ showAutoCaptureToasts: true,
47
+ showUserProfileToasts: true,
48
+ showErrorToasts: true,
49
+ memory: {
50
+ defaultScope: "project",
51
+ },
52
+ compaction: {
53
+ enabled: true,
54
+ memoryLimit: 10,
55
+ },
56
+ chatMessage: {
57
+ enabled: true,
58
+ maxMemories: 3,
59
+ excludeCurrentSession: true,
60
+ maxAgeDays: undefined,
61
+ injectOn: "first",
62
+ },
63
+ };
64
+ function expandPath(path) {
65
+ if (path.startsWith("~/")) {
66
+ return join(homedir(), path.slice(2));
67
+ }
68
+ if (path === "~") {
69
+ return homedir();
70
+ }
71
+ return path;
72
+ }
73
+ function loadConfigFromPaths(paths) {
74
+ for (const path of paths) {
75
+ if (existsSync(path)) {
76
+ try {
77
+ const content = readFileSync(path, "utf-8");
78
+ const json = stripJsoncComments(content);
79
+ return JSON.parse(json);
80
+ }
81
+ catch { }
82
+ }
83
+ }
84
+ return {};
85
+ }
86
+ const CONFIG_TEMPLATE = `{
87
+ // ============================================
88
+ // OpenCode Memory Plugin Configuration
89
+ // ============================================
90
+
91
+ // Storage location for vector database
92
+ "storagePath": "~/.opencode-mem/data",
93
+
94
+ "userEmailOverride": "",
95
+ "userNameOverride": "",
96
+
97
+ // ============================================
98
+ // Embedding Model (for similarity search)
99
+ // ============================================
100
+
101
+ // Default: Nomic Embed v1 (768 dimensions, 8192 context, multilingual)
102
+ "embeddingModel": "Xenova/nomic-embed-text-v1",
103
+
104
+ // Auto-detected dimensions (no need to set manually)
105
+ // "embeddingDimensions": 768,
106
+
107
+ // Other recommended models:
108
+ // "embeddingModel": "Xenova/jina-embeddings-v2-base-en", // 768 dims, English-only, 8192 context
109
+ // "embeddingModel": "Xenova/jina-embeddings-v2-small-en", // 512 dims, faster, 8192 context
110
+ // "embeddingModel": "Xenova/all-MiniLM-L6-v2", // 384 dims, very fast, 512 context
111
+ // "embeddingModel": "Xenova/all-mpnet-base-v2", // 768 dims, good quality, 512 context
112
+
113
+ // Optional: Use OpenAI-compatible API for embeddings
114
+ // "embeddingApiUrl": "https://api.openai.com/v1",
115
+ // "embeddingApiKey": "sk-...",
116
+ // "embeddingModel": "text-embedding-3-small", // 1536 dims, auto-detected
117
+
118
+ // ============================================
119
+ // Web Server Settings
120
+ // ============================================
121
+
122
+ // Enable web UI for managing memories (accessible at http://localhost:4747)
123
+ "webServerEnabled": true,
124
+
125
+ // Port for web UI server
126
+ "webServerPort": 4747,
127
+
128
+ // Host address for web UI (use 127.0.0.1 for local only, 0.0.0.0 for network access)
129
+ "webServerHost": "127.0.0.1",
130
+
131
+ // ============================================
132
+ // Database Settings
133
+ // ============================================
134
+
135
+ // Maximum vectors per database shard (auto-creates new shard when limit reached)
136
+ "maxVectorsPerShard": 50000,
137
+
138
+ // Automatically delete old memories based on retention period
139
+ "autoCleanupEnabled": true,
140
+
141
+ // Days to keep memories before auto-cleanup (only if autoCleanupEnabled is true)
142
+ "autoCleanupRetentionDays": 30,
143
+
144
+ // Automatically detect and remove duplicate memories
145
+ "deduplicationEnabled": true,
146
+
147
+ // Similarity threshold (0-1) for detecting duplicates (higher = stricter)
148
+ "deduplicationSimilarityThreshold": 0.90,
149
+
150
+ // ============================================
151
+ // Memory Scope Settings
152
+ // ============================================
153
+
154
+ // Default scope for memory list/search queries
155
+ // "project" keeps queries within the current project, "all-projects" searches across all project shards
156
+ "memory": {
157
+ "defaultScope": "project"
158
+ },
159
+
160
+ // ============================================
161
+ // OpenCode Provider Settings (RECOMMENDED)
162
+ // ============================================
163
+
164
+ // Use any provider that is already authenticated in opencode for auto-capture
165
+ // and user profile learning. The plugin calls opencode's session.prompt API
166
+ // (with structured output) instead of talking to provider HTTPS endpoints
167
+ // directly, so opencode owns the auth, token refresh, and provider routing.
168
+ //
169
+ // No separate API key is needed in this plugin — whatever you configured in
170
+ // opencode (OAuth like Claude Pro/Max, GitHub Copilot personal/business,
171
+ // bring-your-own API key, custom provider, ...) just works.
172
+ //
173
+ // If NOT set, falls back to the manual config (memoryApiKey/memoryApiUrl/memoryModel below).
174
+ //
175
+ // Examples (the provider name must be one returned by 'opencode providers list'):
176
+ // Anthropic (OAuth/API key): "opencodeProvider": "anthropic", "opencodeModel": "claude-haiku-4-5-20251001"
177
+ // OpenAI (API key): "opencodeProvider": "openai", "opencodeModel": "gpt-4o-mini"
178
+ // GitHub Copilot: "opencodeProvider": "github-copilot", "opencodeModel": "gpt-4o-mini"
179
+ //
180
+ // "opencodeProvider": "anthropic",
181
+ // "opencodeModel": "claude-haiku-4-5-20251001",
182
+
183
+ // ============================================
184
+ // Auto-Capture Settings (REQUIRES EXTERNAL API)
185
+ // ============================================
186
+
187
+ // IMPORTANT: Auto-capture ONLY works with external API
188
+ // It runs in background without blocking your main session
189
+ // Note: Ollama may not support tool calling. Use OpenAI, Anthropic, or Groq for best results.
190
+
191
+ "autoCaptureEnabled": true,
192
+
193
+ // Provider type: "openai-chat" | "openai-responses" | "anthropic"
194
+ // Note: "openai-chat" is a generic OpenAI API-compatible mode.
195
+ // Any service that follows the OpenAI Chat Completions API can use it via custom "memoryApiUrl".
196
+ "memoryProvider": "openai-chat",
197
+
198
+ // REQUIRED for auto-capture (all 3 must be set):
199
+ "memoryModel": "gpt-4o-mini",
200
+ "memoryApiUrl": "https://api.openai.com/v1",
201
+ "memoryApiKey": "sk-...",
202
+
203
+ // API Key Formats:
204
+ // Direct value: "sk-..."
205
+ // From file: "file://~/.config/litellm-key.txt"
206
+ // From env variable: "env://LITELLM_API_KEY"
207
+
208
+ // Examples for different providers:
209
+ // Any OpenAI-compatible endpoint can use the "openai-chat" provider pattern below.
210
+ // Common examples: DeepSeek, Qwen (via Alibaba Cloud ModelStudio),
211
+ // Zhipu GLM (BigModel platform), and Kimi (Moonshot AI platform).
212
+
213
+ // OpenAI Chat Completion (default, backward compatible):
214
+ // "memoryProvider": "openai-chat"
215
+ // "memoryModel": "gpt-4o-mini"
216
+ // "memoryApiUrl": "https://api.openai.com/v1"
217
+ // "memoryApiKey": "sk-..."
218
+
219
+ // DeepSeek (OpenAI-compatible example):
220
+ // "memoryProvider": "openai-chat"
221
+ // "memoryModel": "deepseek-chat"
222
+ // "memoryApiUrl": "https://api.deepseek.com/v1"
223
+ // "memoryApiKey": "sk-..."
224
+
225
+ // OpenAI Responses API (recommended, with session support):
226
+ // "memoryProvider": "openai-responses"
227
+ // "memoryModel": "gpt-4o"
228
+ // "memoryApiUrl": "https://api.openai.com/v1"
229
+ // "memoryApiKey": "sk-..."
230
+
231
+ // Anthropic (with session support):
232
+ // "memoryProvider": "anthropic"
233
+ // "memoryModel": "claude-3-5-haiku-20241022"
234
+ // "memoryApiUrl": "https://api.anthropic.com/v1"
235
+ // "memoryApiKey": "sk-ant-..."
236
+
237
+ // Groq (OpenAI-compatible, use openai-chat provider):
238
+ // "memoryProvider": "openai-chat"
239
+ // "memoryModel": "llama-3.3-70b-versatile"
240
+ // "memoryApiUrl": "https://api.groq.com/openai/v1"
241
+ // "memoryApiKey": "gsk_..."
242
+
243
+ // Maximum iterations for multi-turn AI analysis (for openai-responses and anthropic)
244
+ "autoCaptureMaxIterations": 5,
245
+
246
+ // Timeout per iteration in milliseconds (30 seconds default)
247
+ "autoCaptureIterationTimeout": 30000,
248
+
249
+ // Days to keep AI session history before cleanup
250
+ "aiSessionRetentionDays": 7,
251
+
252
+ // Temperature for AI API requests (set to false to omit parameter for models that don't support it)
253
+ // Some reasoning models (like o1, o3, gpt-5) don't support temperature parameter
254
+ // Set to false and add "memoryTemperature": false in config when using such models
255
+ "memoryTemperature": 0.3,
256
+
257
+ // Extra parameters to include in API request body
258
+ // Useful for local inference servers (e.g. llama-server with --jinja) that support
259
+ // additional parameters like disabling thinking/reasoning mode
260
+ // Example for Qwen3 models: { "enable_thinking": false }
261
+ // "memoryExtraParams": {},
262
+
263
+ // Language for auto-capture summaries (default: "auto" for auto-detection)
264
+ // Options: "auto", "en", "id", "zh", "ja", "es", "fr", "de", "ru", "pt", "ar", "ko"
265
+ // "autoCaptureLanguage": "auto",
266
+
267
+ // ============================================
268
+ // Toast Notifications
269
+ // ============================================
270
+
271
+ // Show toast when memory is auto-captured
272
+ "showAutoCaptureToasts": true,
273
+
274
+ // Show toast when user profile is updated
275
+ "showUserProfileToasts": true,
276
+
277
+ // Show toast for error messages
278
+ "showErrorToasts": true,
279
+
280
+ // ============================================
281
+ // User Profile System
282
+ // ============================================
283
+
284
+ // Analyze user prompts every N prompts to build/update your user profile
285
+ // When N uncaptured prompts accumulate, AI will analyze them to identify:
286
+ // - User preferences (code style, communication style, tool preferences)
287
+ // - User patterns (recurring topics, problem domains, technical interests)
288
+ // - User workflows (development habits, sequences, learning style)
289
+ // - Skill level (overall and per-domain assessment)
290
+ "userProfileAnalysisInterval": 10,
291
+
292
+ // Maximum number of preferences to keep in user profile (sorted by confidence)
293
+ // Preferences are things like "prefers code without comments", "likes concise responses"
294
+ "userProfileMaxPreferences": 20,
295
+
296
+ // Maximum number of patterns to keep in user profile (sorted by frequency)
297
+ // Patterns are recurring topics like "often asks about database optimization"
298
+ "userProfileMaxPatterns": 15,
299
+
300
+ // Maximum number of workflows to keep in user profile (sorted by frequency)
301
+ // Workflows are sequences like "usually asks for tests after implementation"
302
+ "userProfileMaxWorkflows": 10,
303
+
304
+ // Days before preference confidence starts to decay (if not reinforced)
305
+ // Preferences that aren't seen again will gradually lose confidence and be removed
306
+ "userProfileConfidenceDecayDays": 30,
307
+
308
+ // Number of profile versions to keep in changelog (for rollback/debugging)
309
+ // Older versions are automatically cleaned up
310
+ "userProfileChangelogRetentionCount": 5,
311
+
312
+ // ============================================
313
+ // Search Settings
314
+ // ============================================
315
+
316
+ // Minimum similarity score (0-1) for memory search results
317
+ "similarityThreshold": 0.6,
318
+
319
+ // Maximum number of memories to return in search results
320
+ "maxMemories": 10,
321
+
322
+ // ============================================
323
+ // Advanced Settings
324
+ // ============================================
325
+
326
+ // Inject user profile into AI context (preferences, patterns, workflows)
327
+ "injectProfile": true
328
+ }
329
+ `;
330
+ function ensureConfigExists() {
331
+ const configPath = join(CONFIG_DIR, "opencode-mem.jsonc");
332
+ if (!existsSync(configPath)) {
333
+ try {
334
+ writeFileSync(configPath, CONFIG_TEMPLATE, "utf-8");
335
+ console.log(`\n✓ Created config template: ${configPath}`);
336
+ console.log(" Edit this file to customize opencode-mem settings.\n");
337
+ }
338
+ catch { }
339
+ }
340
+ }
341
+ ensureConfigExists();
342
+ function getEmbeddingDimensions(model) {
343
+ const dimensionMap = {
344
+ // Local Xenova models
345
+ "Xenova/nomic-embed-text-v1": 768,
346
+ "Xenova/nomic-embed-text-v1-unsupervised": 768,
347
+ "Xenova/nomic-embed-text-v1-ablated": 768,
348
+ "Xenova/jina-embeddings-v2-base-en": 768,
349
+ "Xenova/jina-embeddings-v2-base-zh": 768,
350
+ "Xenova/jina-embeddings-v2-base-de": 768,
351
+ "Xenova/jina-embeddings-v2-small-en": 512,
352
+ "Xenova/all-MiniLM-L6-v2": 384,
353
+ "Xenova/all-MiniLM-L12-v2": 384,
354
+ "Xenova/all-mpnet-base-v2": 768,
355
+ "Xenova/bge-base-en-v1.5": 768,
356
+ "Xenova/bge-small-en-v1.5": 384,
357
+ "Xenova/gte-small": 384,
358
+ "Xenova/GIST-small-Embedding-v0": 384,
359
+ "Xenova/text-embedding-ada-002": 1536,
360
+ // OpenAI API models
361
+ "text-embedding-3-small": 1536,
362
+ "text-embedding-3-large": 3072,
363
+ "text-embedding-ada-002": 1536,
364
+ // Cohere API models
365
+ "embed-english-v3.0": 1024,
366
+ "embed-multilingual-v3.0": 1024,
367
+ "embed-english-light-v3.0": 384,
368
+ "embed-multilingual-light-v3.0": 384,
369
+ // Google API models
370
+ "text-embedding-004": 768,
371
+ "text-multilingual-embedding-002": 768,
372
+ // Voyage AI models
373
+ "voyage-3": 1024,
374
+ "voyage-3-lite": 512,
375
+ "voyage-code-3": 1024,
376
+ };
377
+ return dimensionMap[model] || 768;
378
+ }
379
+ function buildConfig(fileConfig) {
380
+ return {
381
+ storagePath: expandPath(fileConfig.storagePath ?? DEFAULTS.storagePath),
382
+ userEmailOverride: fileConfig.userEmailOverride,
383
+ userNameOverride: fileConfig.userNameOverride,
384
+ embeddingModel: fileConfig.embeddingModel ?? DEFAULTS.embeddingModel,
385
+ embeddingDimensions: fileConfig.embeddingDimensions ??
386
+ getEmbeddingDimensions(fileConfig.embeddingModel ?? DEFAULTS.embeddingModel),
387
+ embeddingApiUrl: fileConfig.embeddingApiUrl,
388
+ embeddingApiKey: fileConfig.embeddingApiUrl
389
+ ? resolveSecretValue(fileConfig.embeddingApiKey ?? process.env.OPENAI_API_KEY)
390
+ : undefined,
391
+ similarityThreshold: fileConfig.similarityThreshold ?? DEFAULTS.similarityThreshold,
392
+ maxMemories: fileConfig.maxMemories ?? DEFAULTS.maxMemories,
393
+ maxProfileItems: fileConfig.maxProfileItems ?? DEFAULTS.maxProfileItems,
394
+ injectProfile: fileConfig.injectProfile ?? DEFAULTS.injectProfile,
395
+ containerTagPrefix: fileConfig.containerTagPrefix ?? DEFAULTS.containerTagPrefix,
396
+ autoCaptureEnabled: fileConfig.autoCaptureEnabled ?? DEFAULTS.autoCaptureEnabled,
397
+ autoCaptureMaxIterations: fileConfig.autoCaptureMaxIterations ?? DEFAULTS.autoCaptureMaxIterations,
398
+ autoCaptureIterationTimeout: fileConfig.autoCaptureIterationTimeout ?? DEFAULTS.autoCaptureIterationTimeout,
399
+ autoCaptureLanguage: fileConfig.autoCaptureLanguage,
400
+ memoryProvider: (fileConfig.memoryProvider ?? "openai-chat"),
401
+ memoryModel: fileConfig.memoryModel,
402
+ memoryApiUrl: fileConfig.memoryApiUrl,
403
+ memoryApiKey: resolveSecretValue(fileConfig.memoryApiKey),
404
+ memoryTemperature: fileConfig.memoryTemperature,
405
+ memoryExtraParams: fileConfig.memoryExtraParams,
406
+ opencodeProvider: fileConfig.opencodeProvider,
407
+ opencodeModel: fileConfig.opencodeModel,
408
+ vectorBackend: (fileConfig.vectorBackend ?? "usearch-first"),
409
+ aiSessionRetentionDays: fileConfig.aiSessionRetentionDays ?? DEFAULTS.aiSessionRetentionDays,
410
+ webServerEnabled: fileConfig.webServerEnabled ?? DEFAULTS.webServerEnabled,
411
+ webServerPort: fileConfig.webServerPort ?? DEFAULTS.webServerPort,
412
+ webServerHost: fileConfig.webServerHost ?? DEFAULTS.webServerHost,
413
+ maxVectorsPerShard: fileConfig.maxVectorsPerShard ?? DEFAULTS.maxVectorsPerShard,
414
+ autoCleanupEnabled: fileConfig.autoCleanupEnabled ?? DEFAULTS.autoCleanupEnabled,
415
+ autoCleanupRetentionDays: fileConfig.autoCleanupRetentionDays ?? DEFAULTS.autoCleanupRetentionDays,
416
+ deduplicationEnabled: fileConfig.deduplicationEnabled ?? DEFAULTS.deduplicationEnabled,
417
+ deduplicationSimilarityThreshold: fileConfig.deduplicationSimilarityThreshold ?? DEFAULTS.deduplicationSimilarityThreshold,
418
+ userProfileAnalysisInterval: fileConfig.userProfileAnalysisInterval ?? DEFAULTS.userProfileAnalysisInterval,
419
+ userProfileMaxPreferences: fileConfig.userProfileMaxPreferences ?? DEFAULTS.userProfileMaxPreferences,
420
+ userProfileMaxPatterns: fileConfig.userProfileMaxPatterns ?? DEFAULTS.userProfileMaxPatterns,
421
+ userProfileMaxWorkflows: fileConfig.userProfileMaxWorkflows ?? DEFAULTS.userProfileMaxWorkflows,
422
+ userProfileConfidenceDecayDays: fileConfig.userProfileConfidenceDecayDays ?? DEFAULTS.userProfileConfidenceDecayDays,
423
+ userProfileChangelogRetentionCount: fileConfig.userProfileChangelogRetentionCount ?? DEFAULTS.userProfileChangelogRetentionCount,
424
+ showAutoCaptureToasts: fileConfig.showAutoCaptureToasts ?? DEFAULTS.showAutoCaptureToasts,
425
+ showUserProfileToasts: fileConfig.showUserProfileToasts ?? DEFAULTS.showUserProfileToasts,
426
+ showErrorToasts: fileConfig.showErrorToasts ?? DEFAULTS.showErrorToasts,
427
+ memory: {
428
+ defaultScope: fileConfig.memory?.defaultScope ?? DEFAULTS.memory.defaultScope,
429
+ },
430
+ compaction: {
431
+ enabled: fileConfig.compaction?.enabled ?? DEFAULTS.compaction.enabled,
432
+ memoryLimit: fileConfig.compaction?.memoryLimit ?? DEFAULTS.compaction.memoryLimit,
433
+ },
434
+ chatMessage: {
435
+ enabled: fileConfig.chatMessage?.enabled ?? DEFAULTS.chatMessage.enabled,
436
+ maxMemories: fileConfig.chatMessage?.maxMemories ?? DEFAULTS.chatMessage.maxMemories,
437
+ excludeCurrentSession: fileConfig.chatMessage?.excludeCurrentSession ?? DEFAULTS.chatMessage.excludeCurrentSession,
438
+ maxAgeDays: fileConfig.chatMessage?.maxAgeDays,
439
+ injectOn: (fileConfig.chatMessage?.injectOn ?? DEFAULTS.chatMessage.injectOn),
440
+ },
441
+ };
442
+ }
443
+ let _globalFileConfig = loadConfigFromPaths(CONFIG_FILES);
444
+ export let CONFIG = buildConfig(_globalFileConfig);
445
+ export function initConfig(directory) {
446
+ const projectPaths = [
447
+ join(directory, ".opencode", "opencode-mem.jsonc"),
448
+ join(directory, ".opencode", "opencode-mem.json"),
449
+ ];
450
+ const globalConfig = loadConfigFromPaths(CONFIG_FILES);
451
+ const projectConfig = loadConfigFromPaths(projectPaths);
452
+ const merged = { ...globalConfig, ...projectConfig };
453
+ CONFIG = buildConfig(merged);
454
+ }
455
+ export function isConfigured() {
456
+ return true;
457
+ }