@shahmilsaari/memory-core 0.2.8 → 0.2.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -8,7 +8,7 @@ You decide the architecture. memory-core remembers it. Every AI tool — Copilot
8
8
  npx @shahmilsaari/memory-core init
9
9
  ```
10
10
 
11
- No OpenAI key. No cloud. Fully local.
11
+ Fully local or cloud your choice. **v0.2.10**
12
12
 
13
13
  ---
14
14
 
@@ -18,10 +18,10 @@ Without memory-core, every AI agent starts fresh. It doesn't know you're using C
18
18
 
19
19
  With memory-core:
20
20
 
21
- 1. You run `init` once — it verifies your PostgreSQL and Ollama connections, picks your model, and generates config files for every AI agent
21
+ 1. You run `init` once — it verifies your PostgreSQL and Ollama connections, picks your model, lets you choose which agents to generate files for, and installs a pre-commit hook
22
22
  2. Those agents read the files and follow your rules — automatically
23
23
  3. Watch mode catches violations as you type, not just at commit time
24
- 4. When you commit, Claude Code automatically checks your code before the commit goes through
24
+ 4. When you commit, the hook checks your code before the commit goes through (advisory by default — logs violations but never blocks)
25
25
 
26
26
  ---
27
27
 
@@ -152,7 +152,7 @@ CREATE INDEX IF NOT EXISTS memories_scope_idx ON memories (scope);
152
152
  # 1. Go to your project
153
153
  cd my-api
154
154
 
155
- # 2. Initialize — verifies connections, picks your model, generates all config files
155
+ # 2. Initialize — verifies connections, picks your model, generates config files
156
156
  npx @shahmilsaari/memory-core init
157
157
 
158
158
  # 3. Load 281 predefined best-practice rules
@@ -173,18 +173,36 @@ npx @shahmilsaari/memory-core init
173
173
 
174
174
  Walks you through:
175
175
  - PostgreSQL connection URL — **tested live, retries until connected**
176
- - Ollama URL — **tested live, retries until reachable**
177
- - Code-checking model — **verified to be installed in your Ollama**
176
+ - Ollama URL — **tested live, retries until reachable** (used for embeddings)
177
+ - Code-checking provider — **Ollama (local), OpenAI, Anthropic, or MiniMax**
178
+ - Code-checking model — picked from a list, verified before continuing
178
179
  - Project name, type, architecture, language
179
- - Whether to enable the pre-commit hook (asked during setup no separate step needed)
180
+ - Which agents to generate files for — **multi-select, all pre-checked, Space to deselect**saved to `.memory-core.json`
181
+ - Hook mode — **advisory** (logs violations, never blocks) or **strict** (blocks commits)
180
182
  - Whether to enable caveman mode (optional token saver)
181
183
 
182
- Generates config files for every supported AI agent and saves your choices to `.memory-core.json`.
184
+ Generates config files for every selected AI agent, saves your choices to `.memory-core.json`, and automatically adds all generated files to `.gitignore` under a `# memory-core generated files` block.
183
185
 
184
186
  At the end, the banner shows live ✓/✗ status for PostgreSQL and Ollama so you know everything is working.
185
187
 
186
188
  ---
187
189
 
190
+ ### `sync` — Refresh all agent files
191
+
192
+ After saving new memories, regenerate every agent file to include them.
193
+
194
+ ```bash
195
+ npx @shahmilsaari/memory-core sync
196
+ ```
197
+
198
+ Multi-selects which agents to sync (pre-checked from your `.memory-core.json` config). Skips files that haven't changed and reports how many were updated vs already up to date:
199
+
200
+ ```
201
+ 3 updated, 11 already up to date
202
+ ```
203
+
204
+ ---
205
+
188
206
  ### `remember` — Save a decision
189
207
 
190
208
  Made a decision your team should never forget? Save it.
@@ -213,16 +231,6 @@ npx @shahmilsaari/memory-core remember "Use DTOs for all API responses" \
213
231
 
214
232
  ---
215
233
 
216
- ### `sync` — Refresh all agent files
217
-
218
- After saving new memories, regenerate every agent file to include them.
219
-
220
- ```bash
221
- npx @shahmilsaari/memory-core sync
222
- ```
223
-
224
- ---
225
-
226
234
  ### `search` — Find a rule or decision
227
235
 
228
236
  ```bash
@@ -246,17 +254,67 @@ npx @shahmilsaari/memory-core seed --force # re-seed existin
246
254
 
247
255
  ---
248
256
 
249
- ### `hook install` — Block bad commits
257
+ ### `watch` — Catch violations as you type
250
258
 
251
259
  ```bash
252
- npx @shahmilsaari/memory-core hook install
260
+ npx @shahmilsaari/memory-core watch
253
261
  ```
254
262
 
255
- Installs a git pre-commit hook in the current project. Every time you run `git commit`, your code is checked against your architecture rules before the commit goes through.
263
+ Runs in the background and checks each file the moment you save it. You see violations immediately before you even think about committing.
256
264
 
257
- > **Note:** If you use Claude Code, the hook is offered automatically during `init` — no separate step needed.
265
+ ```
266
+ archmind watch — real-time rule enforcement
258
267
 
259
- When a violation is found, the commit is blocked and you see exactly what's wrong and how to fix it:
268
+ watching: /your/project
269
+ model: llama3.2
270
+ rules: 24
271
+ ctrl+c to stop
272
+
273
+ [10:42:11] saved: src/controllers/user.ts
274
+
275
+ ✗ 1 violation in src/controllers/user.ts
276
+
277
+ [1] src/controllers/user.ts:34
278
+ Rule: Thin controllers — business logic belongs in services
279
+ Why: Logic in controllers cannot be reused from other entry points
280
+ Issue: Password hashing inside the route handler
281
+ Fix: Move to UserService.hashPassword()
282
+ ```
283
+
284
+ Options:
285
+ ```bash
286
+ npx @shahmilsaari/memory-core watch --path src/ # watch a specific folder only
287
+ npx @shahmilsaari/memory-core watch --verbose # show extra details
288
+ ```
289
+
290
+ Only checks source files — ignores `node_modules`, `dist`, config files, JSON, etc.
291
+
292
+ ---
293
+
294
+ ### `check` — Manual check (for CI)
295
+
296
+ ```bash
297
+ npx @shahmilsaari/memory-core check --staged # check staged files
298
+ npx @shahmilsaari/memory-core check --staged --verbose # with extra detail
299
+ ```
300
+
301
+ Same as the pre-commit hook. Use this in CI/CD pipelines.
302
+
303
+ ---
304
+
305
+ ### `hook install` — Install the pre-commit hook
306
+
307
+ ```bash
308
+ npx @shahmilsaari/memory-core hook install # advisory mode (default)
309
+ npx @shahmilsaari/memory-core hook install --advisory # logs violations, never blocks
310
+ npx @shahmilsaari/memory-core hook install --strict # blocks commits on violations
311
+ ```
312
+
313
+ Installs a git pre-commit hook in the current project. Every time you run `git commit`, your code is checked against your architecture rules.
314
+
315
+ **Advisory mode (default):** violations are logged so you can see them, but the commit always goes through. Useful for getting used to the rules without disrupting your flow.
316
+
317
+ **Strict mode:** violations block the commit entirely. You see exactly what's wrong and how to fix it:
260
318
 
261
319
  ```
262
320
  ✗ 2 rule violations found — commit blocked
@@ -278,57 +336,130 @@ When a violation is found, the commit is blocked and you see exactly what's wron
278
336
  To save as memory: memory-core remember "<lesson>"
279
337
  ```
280
338
 
339
+ The hook mode is chosen during `init` — no separate step needed unless you want to change it later.
340
+
281
341
  ```bash
282
342
  npx @shahmilsaari/memory-core hook uninstall # remove the hook
283
343
  ```
284
344
 
285
345
  ---
286
346
 
287
- ### `watch` — Catch violations as you type
347
+ ### `list` — List memories from the database
288
348
 
289
349
  ```bash
290
- npx @shahmilsaari/memory-core watch
350
+ npx @shahmilsaari/memory-core list
291
351
  ```
292
352
 
293
- Runs in the background and checks each file the moment you save it. You see violations immediately — before you even think about committing.
353
+ Shows all stored memories. Filter the results:
294
354
 
355
+ ```bash
356
+ npx @shahmilsaari/memory-core list --type rule
357
+ npx @shahmilsaari/memory-core list --scope global
358
+ npx @shahmilsaari/memory-core list --arch clean-architecture
359
+ npx @shahmilsaari/memory-core list --limit 50
295
360
  ```
296
- archmind watch — real-time rule enforcement
297
361
 
298
- watching: /your/project
299
- model: llama3.2
300
- rules: 24
301
- ctrl+c to stop
362
+ | Flag | What it does |
363
+ |---|---|
364
+ | `--type <type>` | Filter by type: `decision` `rule` `pattern` `note` |
365
+ | `--scope <scope>` | Filter by scope: `global` `project` |
366
+ | `--arch <architecture>` | Filter by architecture profile |
367
+ | `--limit <n>` | Max results (default 200) |
302
368
 
303
- [10:42:11] saved: src/controllers/user.ts
369
+ ---
304
370
 
305
- 1 violation in src/controllers/user.ts
371
+ ### `remove` Delete a memory
306
372
 
307
- [1] src/controllers/user.ts:34
308
- Rule: Thin controllers business logic belongs in services
309
- Why: Logic in controllers cannot be reused from other entry points
310
- Issue: Password hashing inside the route handler
311
- Fix: Move to UserService.hashPassword()
373
+ ```bash
374
+ npx @shahmilsaari/memory-core remove <id>
312
375
  ```
313
376
 
314
- Options:
377
+ Deletes a memory by its ID. Get the ID from `list` or `search`.
378
+
379
+ ---
380
+
381
+ ### `edit` — Edit a memory
382
+
315
383
  ```bash
316
- npx @shahmilsaari/memory-core watch --path src/ # watch a specific folder only
317
- npx @shahmilsaari/memory-core watch --verbose # show extra details
384
+ npx @shahmilsaari/memory-core edit <id>
318
385
  ```
319
386
 
320
- Only checks source files ignores `node_modules`, `dist`, config files, JSON, etc.
387
+ Opens the memory interactively so you can update its content, reason, tags, type, or scope.
321
388
 
322
389
  ---
323
390
 
324
- ### `check` — Manual check (for CI)
391
+ ### `export` — Export memories to a file
325
392
 
326
393
  ```bash
327
- npx @shahmilsaari/memory-core check --staged # check staged files
328
- npx @shahmilsaari/memory-core check --staged --verbose # with extra detail
394
+ npx @shahmilsaari/memory-core export
395
+ npx @shahmilsaari/memory-core export --output path/to/my-rules.json
329
396
  ```
330
397
 
331
- Same as the pre-commit hook. Use this in CI/CD pipelines.
398
+ Exports all memories from the database to `memories.json` in the project root (or the path you specify). Makes your rules portable and version-controllable — commit the file alongside your code.
399
+
400
+ ---
401
+
402
+ ### `import` — Import memories from a file
403
+
404
+ ```bash
405
+ npx @shahmilsaari/memory-core import
406
+ npx @shahmilsaari/memory-core import --file path/to/my-rules.json
407
+ npx @shahmilsaari/memory-core import --url https://example.com/team-rules.json
408
+ ```
409
+
410
+ Imports memories into the local database. Skips duplicates by content hash — safe to run more than once.
411
+
412
+ | Flag | What it does |
413
+ |---|---|
414
+ | `--file <path>` | Import from a custom local file path |
415
+ | `--url <url>` | Import from a remote URL |
416
+
417
+ ---
418
+
419
+ ### `ignore` — Mark false positives
420
+
421
+ ```bash
422
+ npx @shahmilsaari/memory-core ignore "controllers may import prisma directly in migration scripts"
423
+ ```
424
+
425
+ Saves a pattern so the hook and watcher never flag it again. Useful for intentional exceptions to a rule.
426
+
427
+ ```bash
428
+ npx @shahmilsaari/memory-core ignore --list # show all saved ignore patterns
429
+ npx @shahmilsaari/memory-core ignore --remove <id> # delete an ignore pattern
430
+ ```
431
+
432
+ ---
433
+
434
+ ### `ci-setup` — GitHub Actions integration
435
+
436
+ ```bash
437
+ npx @shahmilsaari/memory-core ci-setup
438
+ ```
439
+
440
+ Generates `.github/workflows/memory-core.yml`. Adds a PR check that runs your architecture rules on every pull request — same checks as the local hook, enforced in CI.
441
+
442
+ ---
443
+
444
+ ### `stats` — Violation counters
445
+
446
+ ```bash
447
+ npx @shahmilsaari/memory-core stats
448
+ ```
449
+
450
+ Shows which rules fire most often and which files have the most violations. Useful for spotting systemic issues in the codebase.
451
+
452
+ ---
453
+
454
+ ### `reset` — Remove all generated files
455
+
456
+ ```bash
457
+ npx @shahmilsaari/memory-core reset # remove all generated files + .memory-core.json
458
+ npx @shahmilsaari/memory-core reset --soft # keep config and DB, remove only generated files
459
+ npx @shahmilsaari/memory-core reset --db # also drop the memories table from the database
460
+ ```
461
+
462
+ Cleans up everything memory-core created. Use `--soft` if you want to re-run `init` without losing your saved memories.
332
463
 
333
464
  ---
334
465
 
@@ -387,7 +518,7 @@ Pick the one that matches how your project is structured.
387
518
  | Modular Monolith | You're building feature modules that might become microservices later |
388
519
  | MVC | Standard web app with controllers and services |
389
520
  | Hexagonal | You want ports and adapters for maximum testability |
390
- | Next.js | Next.js 13+ with server components and server actions |
521
+ | Go REST API | Go backend API with idiomatic error handling and clean package structure |
391
522
  | Laravel | Laravel with service-repository pattern |
392
523
  | NestJS | Modules, guards, pipes, DTOs, repository pattern |
393
524
 
@@ -422,7 +553,7 @@ Cuts AI response length by 65–75% by removing filler words. Opt in during `ini
422
553
  ```bash
423
554
  # Starting a new project
424
555
  cd my-api
425
- npx @shahmilsaari/memory-core init # verifies connections, picks model, installs hook
556
+ npx @shahmilsaari/memory-core init # verifies connections, picks model, selects agents, installs hook
426
557
  npx @shahmilsaari/memory-core seed # load 281 best-practice rules
427
558
 
428
559
  # Made an architectural decision? Save it.
@@ -435,7 +566,13 @@ npx @shahmilsaari/memory-core sync
435
566
  # Not sure how something was decided? Search.
436
567
  npx @shahmilsaari/memory-core search "caching strategy"
437
568
 
438
- # Commit code Claude Code checks it automatically before committing
569
+ # See what rules are saved
570
+ npx @shahmilsaari/memory-core list --type rule
571
+
572
+ # Export rules to version control
573
+ npx @shahmilsaari/memory-core export
574
+
575
+ # Commit code → hook checks it automatically before committing
439
576
  git commit -m "add user endpoint"
440
577
  ```
441
578
 
@@ -448,9 +585,12 @@ memory-core creates `.memory-core.env` automatically during `init`. You can also
448
585
  | Variable | Required | Default | What it does |
449
586
  |---|---|---|---|
450
587
  | `DATABASE_URL` | Yes | — | PostgreSQL connection string |
451
- | `OLLAMA_URL` | No | `http://localhost:11434` | Where Ollama is running |
452
- | `OLLAMA_MODEL` | No | `nomic-embed-text` | Model used for search (embeddings) |
453
- | `OLLAMA_CHAT_MODEL` | No | `llama3.2` | Model used for code checking chosen during `init` |
588
+ | `OLLAMA_URL` | No | `http://localhost:11434` | Where Ollama is running (used for embeddings) |
589
+ | `OLLAMA_MODEL` | No | `nomic-embed-text` | Model used for search (embeddings) — always Ollama |
590
+ | `CHAT_PROVIDER` | No | `ollama` | Provider for code checking: `ollama`, `openai`, `anthropic`, `minimax` |
591
+ | `CHAT_MODEL` | No | `llama3.2` | Model used for code checking — chosen during `init` |
592
+ | `CHAT_API_KEY` | No | — | API key for OpenAI / Anthropic / MiniMax (not needed for Ollama) |
593
+ | `OLLAMA_CHAT_MODEL` | No | `llama3.2` | Legacy alias for `CHAT_MODEL` when provider is `ollama` |
454
594
 
455
595
  ---
456
596
 
@@ -463,7 +603,16 @@ pgvector isn't installed for your PostgreSQL version. Follow the [pgvector insta
463
603
  Start Ollama: `brew services start ollama` (macOS) or `ollama serve` (Linux).
464
604
 
465
605
  **`Chat model "llama3.2" not found`**
466
- Run `ollama pull llama3.2`. Or switch to another model: add `OLLAMA_CHAT_MODEL=mistral` to `.memory-core.env`.
606
+ Run `ollama pull llama3.2`. Or switch provider/model by updating `CHAT_PROVIDER` and `CHAT_MODEL` in `.memory-core.env`.
607
+
608
+ **Using an API key instead of Ollama for code checking**
609
+ During `init` choose OpenAI, Anthropic, or MiniMax when prompted for the check provider. Or set manually in `.memory-core.env`:
610
+ ```
611
+ CHAT_PROVIDER=openai
612
+ CHAT_MODEL=gpt-4o
613
+ CHAT_API_KEY=sk-...
614
+ ```
615
+ Embeddings always use Ollama (`nomic-embed-text`) regardless of provider.
467
616
 
468
617
  **`DATABASE_URL is not set`**
469
618
  Run `npx @shahmilsaari/memory-core init` — it will create the `.memory-core.env` file for you.
@@ -476,6 +625,9 @@ createuser -s $(whoami)
476
625
  **Hook is flagging JSON or config files**
477
626
  It won't — the hook only checks source code files: `.ts .tsx .js .jsx .py .php .rb .go .java .cs .swift .kt .rs .vue .svelte`. Everything else is skipped automatically.
478
627
 
628
+ **Hook is flagging something that's intentional**
629
+ Save an ignore pattern: `npx @shahmilsaari/memory-core ignore "your exception here"`. The hook and watcher will never flag it again.
630
+
479
631
  ---
480
632
 
481
633
  ## Roadmap
@@ -487,11 +639,22 @@ It won't — the hook only checks source code files: `.ts .tsx .js .jsx .py .php
487
639
  | ✓ | Connection validation — PostgreSQL and Ollama verified during setup |
488
640
  | ✓ | Svelte 5 / SvelteKit profile and 37 rules |
489
641
  | ✓ | NestJS profile and 39 rules |
490
- | | CI/CDfail PRs that violate your rules |
491
- | | Violation memory auto-save what went wrong as a new rule |
492
- | | Rule analytics — see which rules get broken most |
493
- | | Team syncshare memory across your whole team |
494
- | | Memory reviewapprove rules before they propagate |
642
+ | | Hook auto-prompt hook mode offered during init, no separate step needed |
643
+ | | CI/CD`ci-setup` generates GitHub Actions workflow for PR enforcement |
644
+ | | Violation stats — see which rules fire most and which files break most |
645
+ | | Agent selectionchoose which agents to generate files for during init |
646
+ | | Export / import portable memories.json for version control and team sharing |
647
+ | ✓ | List / remove / edit — full CRUD for stored memories |
648
+ | ✓ | False positive tagging — `ignore` command saves exceptions for hook and watcher |
649
+ | ✓ | Reset command — clean up generated files and optionally drop the DB table |
650
+ | ✓ | Test suite — Vitest smoke tests for all core commands and providers |
651
+ | ✓ | Multi-provider code checking — Ollama, OpenAI, Anthropic, MiniMax |
652
+ | | Context-aware retrieval — surface the most relevant rules for the file being edited |
653
+ | | Model guidance during init — recommend a model based on machine specs |
654
+ | | `--debug` flag — verbose output for diagnosing hook and watcher issues |
655
+ | | Violation → rule pipeline — auto-suggest a new rule when the same violation repeats |
656
+ | | Rule analytics dashboard — visual breakdown of rule coverage and violations |
657
+ | | Team sync — shared database so the whole team works from the same rule set |
495
658
 
496
659
  ---
497
660
 
@@ -0,0 +1,196 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ Config
4
+ } from "./chunk-KSLFLWB4.js";
5
+
6
+ // src/db.ts
7
+ import pg from "pg";
8
+ import { createHash } from "crypto";
9
+ var { Pool } = pg;
10
+ var pool = null;
11
+ var migrationsRun = false;
12
+ function hashMemoryContent(content) {
13
+ return createHash("md5").update(content.trim()).digest("hex");
14
+ }
15
+ function getPool() {
16
+ if (!pool) {
17
+ if (!Config.databaseUrl) {
18
+ throw new Error("DATABASE_URL is not set. Add it to your .env or .memory-core.env file.");
19
+ }
20
+ pool = new Pool({ connectionString: Config.databaseUrl });
21
+ }
22
+ return pool;
23
+ }
24
+ async function runMigrations() {
25
+ if (migrationsRun) return;
26
+ const client = await getPool().connect();
27
+ try {
28
+ await client.query("BEGIN");
29
+ await client.query(`ALTER TABLE memories ADD COLUMN IF NOT EXISTS reason TEXT`);
30
+ await client.query(`ALTER TABLE memories ADD COLUMN IF NOT EXISTS content_hash TEXT`);
31
+ await client.query(
32
+ `UPDATE memories
33
+ SET content_hash = md5(trim(content))
34
+ WHERE content_hash IS NULL`
35
+ );
36
+ await client.query(`CREATE INDEX IF NOT EXISTS memories_content_hash_idx ON memories (content_hash)`);
37
+ await client.query("COMMIT");
38
+ migrationsRun = true;
39
+ } catch (err) {
40
+ await client.query("ROLLBACK");
41
+ throw err;
42
+ } finally {
43
+ client.release();
44
+ }
45
+ }
46
+ async function saveMemory(memory) {
47
+ await runMigrations();
48
+ const { type, scope, architecture, projectName, title, content, reason, tags, embedding } = memory;
49
+ const contentHash = hashMemoryContent(content);
50
+ await getPool().query(
51
+ `INSERT INTO memories (type, scope, architecture, project_name, title, content, reason, tags, embedding, content_hash)
52
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)`,
53
+ [type, scope, architecture ?? null, projectName ?? null, title ?? null, content, reason ?? null, tags ?? [], `[${embedding.join(",")}]`, contentHash]
54
+ );
55
+ }
56
+ async function upsertMemory(memory) {
57
+ await runMigrations();
58
+ const contentHash = hashMemoryContent(memory.content);
59
+ const existing = await getPool().query(
60
+ `SELECT id FROM memories
61
+ WHERE content_hash = $1
62
+ AND COALESCE(architecture, '') = COALESCE($2, '')
63
+ AND scope = $3
64
+ AND type = $4
65
+ LIMIT 1`,
66
+ [contentHash, memory.architecture ?? null, memory.scope, memory.type]
67
+ );
68
+ if (existing.rowCount) return "skipped";
69
+ await saveMemory(memory);
70
+ return "inserted";
71
+ }
72
+ async function listMemories(filters = {}) {
73
+ await runMigrations();
74
+ const where = [];
75
+ const params = [];
76
+ if (filters.type) {
77
+ params.push(filters.type);
78
+ where.push(`type = $${params.length}`);
79
+ }
80
+ if (filters.scope) {
81
+ params.push(filters.scope);
82
+ where.push(`scope = $${params.length}`);
83
+ }
84
+ if (filters.architecture) {
85
+ params.push(filters.architecture);
86
+ where.push(`architecture = $${params.length}`);
87
+ }
88
+ const limit = filters.limit ?? 200;
89
+ params.push(limit);
90
+ const result = await getPool().query(
91
+ `SELECT id, type, scope, architecture, project_name, title, content, reason, tags, content_hash
92
+ FROM memories
93
+ ${where.length ? `WHERE ${where.join(" AND ")}` : ""}
94
+ ORDER BY id ASC
95
+ LIMIT $${params.length}`,
96
+ params
97
+ );
98
+ return result.rows;
99
+ }
100
+ async function getMemory(id) {
101
+ await runMigrations();
102
+ const result = await getPool().query(
103
+ `SELECT id, type, scope, architecture, project_name, title, content, reason, tags, content_hash
104
+ FROM memories
105
+ WHERE id = $1`,
106
+ [id]
107
+ );
108
+ return result.rows[0] ?? null;
109
+ }
110
+ async function deleteMemory(id) {
111
+ await runMigrations();
112
+ const result = await getPool().query(`DELETE FROM memories WHERE id = $1`, [id]);
113
+ return (result.rowCount ?? 0) > 0;
114
+ }
115
+ async function updateMemory(id, patch) {
116
+ await runMigrations();
117
+ const current = await getMemory(id);
118
+ if (!current) return null;
119
+ const content = patch.content ?? current.content;
120
+ const contentHash = hashMemoryContent(content);
121
+ const embedding = patch.embedding ? `[${patch.embedding.join(",")}]` : null;
122
+ const result = await getPool().query(
123
+ `UPDATE memories
124
+ SET type = $2,
125
+ scope = $3,
126
+ title = $4,
127
+ content = $5,
128
+ reason = $6,
129
+ tags = $7,
130
+ content_hash = $8,
131
+ embedding = COALESCE($9::vector, embedding)
132
+ WHERE id = $1
133
+ RETURNING id, type, scope, architecture, project_name, title, content, reason, tags, content_hash`,
134
+ [
135
+ id,
136
+ patch.type ?? current.type,
137
+ patch.scope ?? current.scope,
138
+ patch.title ?? current.title ?? null,
139
+ content,
140
+ patch.reason ?? current.reason ?? null,
141
+ patch.tags ?? current.tags ?? [],
142
+ contentHash,
143
+ embedding
144
+ ]
145
+ );
146
+ return result.rows[0] ?? null;
147
+ }
148
+ async function searchMemories(embedding, architecture, limit = 10) {
149
+ await runMigrations();
150
+ const vector = `[${embedding.join(",")}]`;
151
+ const params = [vector];
152
+ let whereClause = "";
153
+ if (architecture) {
154
+ whereClause = `WHERE (architecture = $2 OR scope = 'global')`;
155
+ params.push(architecture);
156
+ }
157
+ const client = await getPool().connect();
158
+ try {
159
+ await client.query("BEGIN");
160
+ await client.query("SET LOCAL ivfflat.probes = 10");
161
+ const result = await client.query(
162
+ `SELECT id, type, scope, architecture, project_name, title, content, reason, tags,
163
+ 1 - (embedding <=> $1) AS similarity
164
+ FROM memories
165
+ ${whereClause}
166
+ ORDER BY embedding <=> $1
167
+ LIMIT $${params.length + 1}`,
168
+ [...params, limit]
169
+ );
170
+ await client.query("COMMIT");
171
+ return result.rows;
172
+ } finally {
173
+ client.release();
174
+ }
175
+ }
176
+ async function closePool() {
177
+ if (pool) {
178
+ await pool.end();
179
+ pool = null;
180
+ migrationsRun = false;
181
+ }
182
+ }
183
+
184
+ export {
185
+ hashMemoryContent,
186
+ getPool,
187
+ runMigrations,
188
+ saveMemory,
189
+ upsertMemory,
190
+ listMemories,
191
+ getMemory,
192
+ deleteMemory,
193
+ updateMemory,
194
+ searchMemories,
195
+ closePool
196
+ };
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ Config
4
+ } from "./chunk-KSLFLWB4.js";
5
+
6
+ // src/embedding.ts
7
+ async function embed(text) {
8
+ let response;
9
+ try {
10
+ response = await fetch(`${Config.ollamaUrl}/api/embeddings`, {
11
+ method: "POST",
12
+ headers: { "Content-Type": "application/json" },
13
+ body: JSON.stringify({ model: Config.ollamaModel, prompt: text })
14
+ });
15
+ } catch {
16
+ throw new Error(
17
+ `Cannot reach Ollama at ${Config.ollamaUrl}. Run: ollama serve`
18
+ );
19
+ }
20
+ if (!response.ok) {
21
+ const body = await response.text();
22
+ throw new Error(`Ollama embedding failed (${response.status}): ${body}`);
23
+ }
24
+ const data = await response.json();
25
+ return data.embedding;
26
+ }
27
+
28
+ export {
29
+ embed
30
+ };
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/config.ts
4
+ import { config } from "dotenv";
5
+ import { existsSync } from "fs";
6
+ import { join } from "path";
7
+ var localEnv = join(process.cwd(), ".memory-core.env");
8
+ config({ path: existsSync(localEnv) ? localEnv : join(process.cwd(), ".env") });
9
+ var Config = {
10
+ get databaseUrl() {
11
+ return process.env.DATABASE_URL ?? "";
12
+ },
13
+ get ollamaUrl() {
14
+ return process.env.OLLAMA_URL ?? "http://localhost:11434";
15
+ },
16
+ get ollamaModel() {
17
+ return process.env.OLLAMA_MODEL ?? "nomic-embed-text";
18
+ },
19
+ get chatModel() {
20
+ return process.env.CHAT_MODEL ?? process.env.OLLAMA_CHAT_MODEL ?? "llama3.2";
21
+ },
22
+ get chatProvider() {
23
+ return process.env.CHAT_PROVIDER ?? "ollama";
24
+ },
25
+ get chatApiKey() {
26
+ return process.env.CHAT_API_KEY ?? "";
27
+ }
28
+ };
29
+
30
+ export {
31
+ Config
32
+ };