@alex900530/claude-persistent-memory 1.0.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.
package/bin/setup.js ADDED
@@ -0,0 +1,418 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Setup script for claude-persistent-memory
4
+ *
5
+ * Two modes:
6
+ * --postinstall Non-interactive (run by npm postinstall)
7
+ * (no flag) Interactive (run by npx claude-persistent-memory)
8
+ */
9
+
10
+ const fs = require('fs');
11
+ const path = require('path');
12
+ const readline = require('readline');
13
+
14
+ // ── Path constants ──────────────────────────────────────────────────────────
15
+ const isPostinstall = process.argv.includes('--postinstall');
16
+ const PROJECT_ROOT = process.env.INIT_CWD || process.cwd();
17
+ const PKG_DIR = path.resolve(__dirname, '..');
18
+ const NODE_BIN = process.execPath;
19
+
20
+ const CONFIG_FILE = path.join(PROJECT_ROOT, '.claude-memory.config.js');
21
+ const MCP_FILE = path.join(PROJECT_ROOT, '.mcp.json');
22
+ const CLAUDE_DIR = path.join(PROJECT_ROOT, '.claude');
23
+ const SETTINGS_FILE = path.join(CLAUDE_DIR, 'settings.json');
24
+ const DATA_DIR = path.join(PROJECT_ROOT, '.claude-memory');
25
+ const GITIGNORE_FILE = path.join(PROJECT_ROOT, '.gitignore');
26
+
27
+ const PREFIX = '\x1b[36m[claude-memory]\x1b[0m';
28
+
29
+ // ── Helpers ─────────────────────────────────────────────────────────────────
30
+ function log(msg) { console.log(`${PREFIX} ${msg}`); }
31
+ function warn(msg) { console.log(`${PREFIX} \x1b[33m${msg}\x1b[0m`); }
32
+ function ok(msg) { console.log(`${PREFIX} \x1b[32m${msg}\x1b[0m`); }
33
+
34
+ function readJSON(filePath) {
35
+ try { return JSON.parse(fs.readFileSync(filePath, 'utf8')); } catch { return null; }
36
+ }
37
+
38
+ function writeJSON(filePath, data) {
39
+ fs.writeFileSync(filePath, JSON.stringify(data, null, 2) + '\n');
40
+ }
41
+
42
+ function ask(question) {
43
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
44
+ return new Promise(resolve => rl.question(`${PREFIX} ${question}`, ans => { rl.close(); resolve(ans.trim()); }));
45
+ }
46
+
47
+ // ── [1/5] Config ────────────────────────────────────────────────────────────
48
+ async function setupConfig() {
49
+ log('[1/5] Setting up .claude-memory.config.js ...');
50
+
51
+ if (fs.existsSync(CONFIG_FILE)) {
52
+ if (isPostinstall) {
53
+ log(' Config already exists, skipping.');
54
+ return;
55
+ }
56
+ const ans = await ask(' .claude-memory.config.js already exists. Overwrite? (y/N) ');
57
+ if (ans.toLowerCase() !== 'y') { log(' Skipped.'); return; }
58
+ }
59
+
60
+ let endpoint = process.env.AZURE_OPENAI_ENDPOINT || '';
61
+ let apiKey = process.env.AZURE_OPENAI_KEY || '';
62
+ let deployment = process.env.AZURE_OPENAI_DEPLOYMENT || 'gpt-4.1';
63
+
64
+ if (!endpoint && !isPostinstall) {
65
+ log(' Azure OpenAI credentials not found in environment.');
66
+ log(' You can set them now or leave blank to configure later.');
67
+ endpoint = await ask(' AZURE_OPENAI_ENDPOINT: ');
68
+ apiKey = await ask(' AZURE_OPENAI_KEY: ');
69
+ const dep = await ask(' AZURE_OPENAI_DEPLOYMENT (default: gpt-4.1): ');
70
+ if (dep) deployment = dep;
71
+ }
72
+
73
+ // Escape backslashes and quotes for safe embedding in JS string
74
+ const esc = s => s.replace(/\\/g, '\\\\').replace(/'/g, "\\'");
75
+
76
+ const content = `// Auto-generated by claude-persistent-memory setup
77
+ const base = require('${esc(path.join(PKG_DIR, 'config.default').replace(/\\/g, '/'))}');
78
+ const path = require('path');
79
+
80
+ module.exports = {
81
+ ...base,
82
+ dataDir: path.resolve(__dirname, '.claude-memory'),
83
+ logDir: path.resolve(__dirname, '.claude-memory', 'logs'),
84
+ azure: {
85
+ ...base.azure,
86
+ endpoint: process.env.AZURE_OPENAI_ENDPOINT || '${esc(endpoint)}',
87
+ apiKey: process.env.AZURE_OPENAI_KEY || '${esc(apiKey)}',
88
+ deployment: process.env.AZURE_OPENAI_DEPLOYMENT || '${esc(deployment)}',
89
+ },
90
+ };
91
+ `;
92
+ fs.writeFileSync(CONFIG_FILE, content);
93
+
94
+ if (!endpoint) {
95
+ warn(' Config created with empty Azure credentials.');
96
+ warn(' Run "npx claude-persistent-memory" to configure, or set env vars:');
97
+ warn(' export AZURE_OPENAI_ENDPOINT="https://your-resource.openai.azure.com"');
98
+ warn(' export AZURE_OPENAI_KEY="your-api-key"');
99
+ } else {
100
+ ok(' Config created.');
101
+ }
102
+ }
103
+
104
+ // ── [2/5] MCP ───────────────────────────────────────────────────────────────
105
+ function setupMCP() {
106
+ log('[2/5] Setting up .mcp.json ...');
107
+
108
+ const existing = readJSON(MCP_FILE) || {};
109
+ if (!existing.mcpServers) existing.mcpServers = {};
110
+
111
+ existing.mcpServers.memory = {
112
+ type: 'stdio',
113
+ command: NODE_BIN,
114
+ args: [path.join(PKG_DIR, 'services', 'memory-mcp-server.js')],
115
+ env: { MEMORY_CONFIG: CONFIG_FILE },
116
+ };
117
+
118
+ writeJSON(MCP_FILE, existing);
119
+ ok(' .mcp.json configured.');
120
+ }
121
+
122
+ // ── [3/5] Hooks ─────────────────────────────────────────────────────────────
123
+ function setupHooks() {
124
+ log('[3/5] Setting up .claude/settings.json hooks ...');
125
+
126
+ if (!fs.existsSync(CLAUDE_DIR)) fs.mkdirSync(CLAUDE_DIR, { recursive: true });
127
+
128
+ const existing = readJSON(SETTINGS_FILE) || {};
129
+ if (!existing.hooks) existing.hooks = {};
130
+
131
+ const envPrefix = `MEMORY_CONFIG=${CONFIG_FILE}`;
132
+
133
+ const hookDefs = [
134
+ { event: 'UserPromptSubmit', file: 'user-prompt-hook.js' },
135
+ { event: 'PreToolUse', file: 'pre-tool-memory-hook.js' },
136
+ { event: 'PostToolUse', file: 'post-tool-memory-hook.js' },
137
+ { event: 'PreCompact', file: 'pre-compact-hook.js' },
138
+ { event: 'SessionEnd', file: 'session-end-hook.js' },
139
+ ];
140
+
141
+ for (const { event, file } of hookDefs) {
142
+ const command = `${envPrefix} ${NODE_BIN} ${path.join(PKG_DIR, 'hooks', file)}`;
143
+
144
+ if (!existing.hooks[event]) existing.hooks[event] = [];
145
+ const hooks = existing.hooks[event];
146
+
147
+ // Find existing hook by script filename
148
+ const idx = hooks.findIndex(h => h.command && h.command.includes(file));
149
+ const entry = { type: 'command', command };
150
+
151
+ if (idx >= 0) {
152
+ hooks[idx] = entry;
153
+ } else {
154
+ hooks.push(entry);
155
+ }
156
+ }
157
+
158
+ writeJSON(SETTINGS_FILE, existing);
159
+ ok(' Hooks configured (5 hooks).');
160
+ }
161
+
162
+ // ── [4/5] .gitignore ────────────────────────────────────────────────────────
163
+ function setupGitignore() {
164
+ log('[4/5] Updating .gitignore ...');
165
+
166
+ const entries = ['.claude-memory/', '.claude-memory.config.js', '.claude/', '.mcp.json'];
167
+ let content = '';
168
+ try { content = fs.readFileSync(GITIGNORE_FILE, 'utf8'); } catch {}
169
+
170
+ const added = [];
171
+ for (const entry of entries) {
172
+ // Check if already present (exact line match)
173
+ if (!content.split('\n').some(line => line.trim() === entry)) {
174
+ added.push(entry);
175
+ }
176
+ }
177
+
178
+ if (added.length > 0) {
179
+ const suffix = content.endsWith('\n') || content === '' ? '' : '\n';
180
+ const block = `${suffix}# claude-persistent-memory\n${added.join('\n')}\n`;
181
+ fs.appendFileSync(GITIGNORE_FILE, block);
182
+ ok(` Added ${added.length} entries.`);
183
+ } else {
184
+ log(' Already up to date.');
185
+ }
186
+ }
187
+
188
+ // ── [5/5] Services ──────────────────────────────────────────────────────────
189
+ function setupServices() {
190
+ log('[5/5] Setting up background services ...');
191
+
192
+ // Check if Azure credentials are configured
193
+ let hasCredentials = false;
194
+ try {
195
+ const cfg = require(CONFIG_FILE);
196
+ hasCredentials = !!(cfg.azure && cfg.azure.endpoint && cfg.azure.apiKey);
197
+ } catch {}
198
+
199
+ if (!hasCredentials && isPostinstall) {
200
+ warn(' Skipping service startup (no Azure credentials).');
201
+ warn(' Run "npx claude-persistent-memory" after configuring credentials.');
202
+ printSummary();
203
+ return;
204
+ }
205
+
206
+ // Ensure data directory exists
207
+ if (!fs.existsSync(DATA_DIR)) fs.mkdirSync(DATA_DIR, { recursive: true });
208
+ const logsDir = path.join(DATA_DIR, 'logs');
209
+ if (!fs.existsSync(logsDir)) fs.mkdirSync(logsDir, { recursive: true });
210
+
211
+ const platform = process.platform;
212
+
213
+ if (platform === 'darwin') {
214
+ setupLaunchd();
215
+ } else if (platform === 'linux') {
216
+ setupSystemd();
217
+ } else {
218
+ warn(' Unsupported platform for automatic service setup.');
219
+ log(' Start services manually:');
220
+ log(` MEMORY_CONFIG=${CONFIG_FILE} ${NODE_BIN} ${path.join(PKG_DIR, 'services', 'embedding-server.js')}`);
221
+ log(` MEMORY_CONFIG=${CONFIG_FILE} ${NODE_BIN} ${path.join(PKG_DIR, 'services', 'llm-server.js')}`);
222
+ printSummary();
223
+ return;
224
+ }
225
+
226
+ // Wait and verify
227
+ verifyServices();
228
+ }
229
+
230
+ function setupLaunchd() {
231
+ const agentsDir = path.join(process.env.HOME, 'Library', 'LaunchAgents');
232
+ if (!fs.existsSync(agentsDir)) fs.mkdirSync(agentsDir, { recursive: true });
233
+
234
+ const services = [
235
+ { label: 'com.claude-memory.embedding-server', script: 'embedding-server.js' },
236
+ { label: 'com.claude-memory.llm-server', script: 'llm-server.js' },
237
+ ];
238
+
239
+ for (const { label, script } of services) {
240
+ const plistPath = path.join(agentsDir, `${label}.plist`);
241
+ const logPath = path.join(DATA_DIR, 'logs', `${script.replace('.js', '')}.log`);
242
+
243
+ const plist = `<?xml version="1.0" encoding="UTF-8"?>
244
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
245
+ <plist version="1.0">
246
+ <dict>
247
+ <key>Label</key>
248
+ <string>${label}</string>
249
+ <key>ProgramArguments</key>
250
+ <array>
251
+ <string>${NODE_BIN}</string>
252
+ <string>${path.join(PKG_DIR, 'services', script)}</string>
253
+ </array>
254
+ <key>WorkingDirectory</key>
255
+ <string>${PROJECT_ROOT}</string>
256
+ <key>EnvironmentVariables</key>
257
+ <dict>
258
+ <key>MEMORY_CONFIG</key>
259
+ <string>${CONFIG_FILE}</string>
260
+ </dict>
261
+ <key>RunAtLoad</key>
262
+ <true/>
263
+ <key>KeepAlive</key>
264
+ <dict>
265
+ <key>SuccessfulExit</key>
266
+ <false/>
267
+ </dict>
268
+ <key>ThrottleInterval</key>
269
+ <integer>10</integer>
270
+ <key>StandardOutPath</key>
271
+ <string>${logPath}</string>
272
+ <key>StandardErrorPath</key>
273
+ <string>${logPath}</string>
274
+ </dict>
275
+ </plist>
276
+ `;
277
+ fs.writeFileSync(plistPath, plist);
278
+
279
+ // Unload if already loaded, then load
280
+ try {
281
+ require('child_process').execSync(`launchctl unload ${plistPath} 2>/dev/null`, { stdio: 'ignore' });
282
+ } catch {}
283
+ try {
284
+ require('child_process').execSync(`launchctl load ${plistPath}`, { stdio: 'pipe' });
285
+ ok(` Loaded ${label}`);
286
+ } catch (e) {
287
+ warn(` Failed to load ${label}: ${e.message}`);
288
+ }
289
+ }
290
+ }
291
+
292
+ function setupSystemd() {
293
+ const unitDir = path.join(process.env.HOME, '.config', 'systemd', 'user');
294
+ if (!fs.existsSync(unitDir)) fs.mkdirSync(unitDir, { recursive: true });
295
+
296
+ const services = [
297
+ { name: 'claude-memory-embedding', script: 'embedding-server.js' },
298
+ { name: 'claude-memory-llm', script: 'llm-server.js' },
299
+ ];
300
+
301
+ for (const { name, script } of services) {
302
+ const unitPath = path.join(unitDir, `${name}.service`);
303
+ const unit = `[Unit]
304
+ Description=Claude Memory ${script}
305
+
306
+ [Service]
307
+ ExecStart=${NODE_BIN} ${path.join(PKG_DIR, 'services', script)}
308
+ WorkingDirectory=${PROJECT_ROOT}
309
+ Environment=MEMORY_CONFIG=${CONFIG_FILE}
310
+ Restart=on-failure
311
+ RestartSec=10
312
+
313
+ [Install]
314
+ WantedBy=default.target
315
+ `;
316
+ fs.writeFileSync(unitPath, unit);
317
+ try {
318
+ require('child_process').execSync(`systemctl --user daemon-reload`, { stdio: 'pipe' });
319
+ require('child_process').execSync(`systemctl --user enable --now ${name}`, { stdio: 'pipe' });
320
+ ok(` Enabled ${name}`);
321
+ } catch (e) {
322
+ warn(` Failed to enable ${name}: ${e.message}`);
323
+ }
324
+ }
325
+ }
326
+
327
+ function verifyServices() {
328
+ log(' Waiting for services to start ...');
329
+ const net = require('net');
330
+
331
+ const ports = [23811, 23812];
332
+ const names = ['embedding-server', 'llm-server'];
333
+ let attempts = 0;
334
+ const maxAttempts = 6; // 6 * 500ms = 3s
335
+
336
+ function check() {
337
+ attempts++;
338
+ let allOk = true;
339
+ let checked = 0;
340
+
341
+ ports.forEach((port, i) => {
342
+ const sock = new net.Socket();
343
+ sock.setTimeout(400);
344
+ sock.on('connect', () => {
345
+ sock.destroy();
346
+ checked++;
347
+ if (checked === ports.length && allOk) {
348
+ ok(' All services running.');
349
+ printSummary();
350
+ }
351
+ });
352
+ sock.on('error', () => {
353
+ sock.destroy();
354
+ allOk = false;
355
+ checked++;
356
+ if (checked === ports.length) {
357
+ if (attempts < maxAttempts) {
358
+ setTimeout(check, 500);
359
+ } else {
360
+ warn(` Some services not responding. Check logs in .claude-memory/logs/`);
361
+ printSummary();
362
+ }
363
+ }
364
+ });
365
+ sock.on('timeout', () => {
366
+ sock.destroy();
367
+ allOk = false;
368
+ checked++;
369
+ if (checked === ports.length) {
370
+ if (attempts < maxAttempts) {
371
+ setTimeout(check, 500);
372
+ } else {
373
+ warn(` Some services not responding. Check logs in .claude-memory/logs/`);
374
+ printSummary();
375
+ }
376
+ }
377
+ });
378
+ sock.connect(port, '127.0.0.1');
379
+ });
380
+ }
381
+
382
+ check();
383
+ }
384
+
385
+ // ── Summary ─────────────────────────────────────────────────────────────────
386
+ function printSummary() {
387
+ console.log('');
388
+ ok('╔══════════════════════════════════════════════════╗');
389
+ ok('║ claude-persistent-memory installed! ║');
390
+ ok('╚══════════════════════════════════════════════════╝');
391
+ console.log('');
392
+ log(`Config: ${CONFIG_FILE}`);
393
+ log(`Data: ${DATA_DIR}`);
394
+ log(`MCP: ${MCP_FILE}`);
395
+ log(`Hooks: ${SETTINGS_FILE}`);
396
+ console.log('');
397
+ log('Open Claude Code in this project directory to start using memory.');
398
+ console.log('');
399
+ }
400
+
401
+ // ── Main ────────────────────────────────────────────────────────────────────
402
+ async function main() {
403
+ console.log('');
404
+ log(`Setting up claude-persistent-memory in:`);
405
+ log(` ${PROJECT_ROOT}`);
406
+ console.log('');
407
+
408
+ await setupConfig();
409
+ setupMCP();
410
+ setupHooks();
411
+ setupGitignore();
412
+ setupServices();
413
+ }
414
+
415
+ main().catch(err => {
416
+ console.error(`${PREFIX} Error: ${err.message}`);
417
+ process.exit(1);
418
+ });
@@ -0,0 +1,122 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Uninstall script for claude-persistent-memory
4
+ * Removes services, MCP config, and hooks. Does NOT delete .claude-memory/ data.
5
+ */
6
+
7
+ const fs = require('fs');
8
+ const path = require('path');
9
+
10
+ const PROJECT_ROOT = process.env.INIT_CWD || process.cwd();
11
+ const CONFIG_FILE = path.join(PROJECT_ROOT, '.claude-memory.config.js');
12
+ const MCP_FILE = path.join(PROJECT_ROOT, '.mcp.json');
13
+ const SETTINGS_FILE = path.join(PROJECT_ROOT, '.claude', 'settings.json');
14
+
15
+ const PREFIX = '\x1b[36m[claude-memory]\x1b[0m';
16
+ function log(msg) { console.log(`${PREFIX} ${msg}`); }
17
+ function ok(msg) { console.log(`${PREFIX} \x1b[32m${msg}\x1b[0m`); }
18
+ function warn(msg) { console.log(`${PREFIX} \x1b[33m${msg}\x1b[0m`); }
19
+
20
+ // ── [1/4] Remove launchd / systemd services ─────────────────────────────────
21
+ function removeServices() {
22
+ log('[1/4] Removing background services ...');
23
+
24
+ if (process.platform === 'darwin') {
25
+ const agentsDir = path.join(process.env.HOME, 'Library', 'LaunchAgents');
26
+ const labels = ['com.claude-memory.embedding-server', 'com.claude-memory.llm-server'];
27
+ for (const label of labels) {
28
+ const plist = path.join(agentsDir, `${label}.plist`);
29
+ if (fs.existsSync(plist)) {
30
+ try { require('child_process').execSync(`launchctl unload ${plist}`, { stdio: 'ignore' }); } catch {}
31
+ fs.unlinkSync(plist);
32
+ ok(` Removed ${label}`);
33
+ }
34
+ }
35
+ } else if (process.platform === 'linux') {
36
+ const names = ['claude-memory-embedding', 'claude-memory-llm'];
37
+ const unitDir = path.join(process.env.HOME, '.config', 'systemd', 'user');
38
+ for (const name of names) {
39
+ try { require('child_process').execSync(`systemctl --user disable --now ${name}`, { stdio: 'ignore' }); } catch {}
40
+ const unit = path.join(unitDir, `${name}.service`);
41
+ if (fs.existsSync(unit)) { fs.unlinkSync(unit); ok(` Removed ${name}`); }
42
+ }
43
+ try { require('child_process').execSync(`systemctl --user daemon-reload`, { stdio: 'ignore' }); } catch {}
44
+ }
45
+ }
46
+
47
+ // ── [2/4] Remove MCP entry ──────────────────────────────────────────────────
48
+ function removeMCP() {
49
+ log('[2/4] Cleaning .mcp.json ...');
50
+ try {
51
+ const data = JSON.parse(fs.readFileSync(MCP_FILE, 'utf8'));
52
+ if (data.mcpServers && data.mcpServers.memory) {
53
+ delete data.mcpServers.memory;
54
+ if (Object.keys(data.mcpServers).length === 0) {
55
+ fs.unlinkSync(MCP_FILE);
56
+ ok(' Removed .mcp.json (was empty).');
57
+ } else {
58
+ fs.writeFileSync(MCP_FILE, JSON.stringify(data, null, 2) + '\n');
59
+ ok(' Removed memory entry from .mcp.json.');
60
+ }
61
+ }
62
+ } catch {
63
+ log(' .mcp.json not found, skipping.');
64
+ }
65
+ }
66
+
67
+ // ── [3/4] Remove hooks ──────────────────────────────────────────────────────
68
+ function removeHooks() {
69
+ log('[3/4] Cleaning .claude/settings.json hooks ...');
70
+ try {
71
+ const data = JSON.parse(fs.readFileSync(SETTINGS_FILE, 'utf8'));
72
+ if (!data.hooks) { log(' No hooks found.'); return; }
73
+
74
+ const hookFiles = [
75
+ 'user-prompt-hook.js', 'pre-tool-memory-hook.js', 'post-tool-memory-hook.js',
76
+ 'pre-compact-hook.js', 'session-end-hook.js',
77
+ ];
78
+
79
+ let removed = 0;
80
+ for (const event of Object.keys(data.hooks)) {
81
+ const before = data.hooks[event].length;
82
+ data.hooks[event] = data.hooks[event].filter(
83
+ h => !hookFiles.some(f => h.command && h.command.includes(f))
84
+ );
85
+ removed += before - data.hooks[event].length;
86
+ if (data.hooks[event].length === 0) delete data.hooks[event];
87
+ }
88
+ if (Object.keys(data.hooks).length === 0) delete data.hooks;
89
+
90
+ fs.writeFileSync(SETTINGS_FILE, JSON.stringify(data, null, 2) + '\n');
91
+ ok(` Removed ${removed} hooks.`);
92
+ } catch {
93
+ log(' settings.json not found, skipping.');
94
+ }
95
+ }
96
+
97
+ // ── [4/4] Remove config ─────────────────────────────────────────────────────
98
+ function removeConfig() {
99
+ log('[4/4] Removing config ...');
100
+ if (fs.existsSync(CONFIG_FILE)) {
101
+ fs.unlinkSync(CONFIG_FILE);
102
+ ok(' Removed .claude-memory.config.js');
103
+ }
104
+ }
105
+
106
+ // ── Main ────────────────────────────────────────────────────────────────────
107
+ console.log('');
108
+ log('Uninstalling claude-persistent-memory ...');
109
+ console.log('');
110
+
111
+ removeServices();
112
+ removeMCP();
113
+ removeHooks();
114
+ removeConfig();
115
+
116
+ console.log('');
117
+ warn('Data directory .claude-memory/ was NOT deleted.');
118
+ warn('Remove it manually if you no longer need the memory database:');
119
+ warn(` rm -rf ${path.join(PROJECT_ROOT, '.claude-memory')}`);
120
+ console.log('');
121
+ ok('Uninstall complete.');
122
+ console.log('');
@@ -0,0 +1,49 @@
1
+ const path = require('path');
2
+
3
+ module.exports = {
4
+ // TCP ports
5
+ embeddingPort: 23811,
6
+ llmPort: 23812,
7
+
8
+ // Data directories (relative to project root)
9
+ dataDir: path.resolve(__dirname, 'data'),
10
+ logDir: path.resolve(__dirname, 'data', 'logs'),
11
+ pidDir: '/tmp',
12
+
13
+ // Azure OpenAI (configure via environment variables)
14
+ azure: {
15
+ endpoint: process.env.AZURE_OPENAI_ENDPOINT || '',
16
+ apiKey: process.env.AZURE_OPENAI_KEY || '',
17
+ deployment: process.env.AZURE_OPENAI_DEPLOYMENT || 'gpt-4.1',
18
+ apiVersion: '2024-12-01-preview',
19
+ },
20
+
21
+ // Embedding model
22
+ embedding: {
23
+ model: 'Xenova/bge-m3',
24
+ dimensions: 1024,
25
+ },
26
+
27
+ // Search parameters
28
+ search: {
29
+ maxResults: 3,
30
+ minSimilarity: 0.6,
31
+ },
32
+
33
+ // Clustering parameters
34
+ cluster: {
35
+ similarityThreshold: 0.70,
36
+ maturityCount: 5,
37
+ maturityConfidence: 0.65,
38
+ },
39
+
40
+ // Timeouts (ms)
41
+ timeout: {
42
+ hookPreTool: 300,
43
+ hookPostTool: 300,
44
+ hookUserPrompt: 1500,
45
+ embeddingSearch: 1000,
46
+ embeddingClient: 800,
47
+ llmDefault: 5000,
48
+ },
49
+ };
package/config.js ADDED
@@ -0,0 +1,7 @@
1
+ // Config loader — resolves config path from MEMORY_CONFIG env var or falls back to defaults
2
+ const configPath = process.env.MEMORY_CONFIG;
3
+ if (configPath && require('fs').existsSync(configPath)) {
4
+ module.exports = require(configPath);
5
+ } else {
6
+ module.exports = require('./config.default');
7
+ }