@shahmilsaari/memory-core 0.2.14 → 0.2.16

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
- Fully local or cloud — your choice. **v0.2.13**
11
+ Fully local or cloud — your choice. **v0.2.16**
12
12
 
13
13
  ---
14
14
 
@@ -133,6 +133,7 @@ CREATE TABLE IF NOT EXISTS memories (
133
133
  title TEXT,
134
134
  content TEXT NOT NULL,
135
135
  reason TEXT,
136
+ context JSONB NOT NULL DEFAULT '{}',
136
137
  tags TEXT[] DEFAULT '{}',
137
138
  embedding vector(768),
138
139
  created_at TIMESTAMP DEFAULT now()
@@ -169,6 +170,7 @@ For the full CLI reference, examples, and command behavior notes, see [COMMANDS.
169
170
 
170
171
  New setup-management commands:
171
172
  - `memory-core status` — show project name, provider/model, agents, hook state, generated files, and health checks
173
+ - `memory-core auto-sync` — show or change automatic agent file regeneration (`on`, `off`, or `status`)
172
174
  - `memory-core provider set <provider>` — switch code-checking provider without rerunning `init`
173
175
  - `memory-core model set <model>` — update chat or embedding model from the CLI
174
176
  - `memory-core model doctor` — verify database, Ollama, model installation, and cloud API key presence
@@ -189,7 +191,7 @@ Walks you through:
189
191
  - Hook mode — **advisory** (logs violations, never blocks) or **strict** (blocks commits)
190
192
  - Whether to enable caveman mode (optional token saver)
191
193
 
192
- 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.
194
+ Generates config files for every selected AI agent, saves your choices to `.memory-core.json`, enables auto-sync by default, and automatically adds all generated files to `.gitignore` under a `# memory-core generated files` block.
193
195
 
194
196
  At the end, the banner shows live ✓/✗ status for PostgreSQL and Ollama so you know everything is working.
195
197
 
@@ -197,7 +199,7 @@ At the end, the banner shows live ✓/✗ status for PostgreSQL and Ollama so yo
197
199
 
198
200
  ### `sync` — Refresh all agent files
199
201
 
200
- After saving new memories, regenerate every agent file to include them.
202
+ Regenerate every agent file on demand. This still exists even though `remember`, `import`, `edit`, `remove`, `forget`, and `ignore` auto-sync by default after changing memories.
201
203
 
202
204
  ```bash
203
205
  npx @shahmilsaari/memory-core sync
@@ -209,6 +211,18 @@ Multi-selects which agents to sync (pre-checked from your `.memory-core.json` co
209
211
  3 updated, 11 already up to date
210
212
  ```
211
213
 
214
+ Use `--no-sync` on memory-changing commands when you want to save database changes without regenerating files immediately.
215
+
216
+ Manage the default:
217
+
218
+ ```bash
219
+ npx @shahmilsaari/memory-core auto-sync # show current setting
220
+ npx @shahmilsaari/memory-core auto-sync off # save only, sync manually later
221
+ npx @shahmilsaari/memory-core auto-sync on # restore default behavior
222
+ ```
223
+
224
+ Auto-sync failures are non-fatal. If regeneration cannot run, memory-core prints the reason and tells you to run `memory-core sync` manually.
225
+
212
226
  ---
213
227
 
214
228
  ### `remember` — Save a decision
@@ -227,6 +241,9 @@ npx @shahmilsaari/memory-core remember "Use DTOs for all API responses" \
227
241
  --type rule \
228
242
  --scope global \
229
243
  --reason "Raw DB entities expose internal schema and sensitive fields" \
244
+ --applies-to "controllers,API responses" \
245
+ --avoid-when "internal domain transformations" \
246
+ --example "return UserResponseDto instead of UserEntity" \
230
247
  --tags "api,dto"
231
248
  ```
232
249
 
@@ -235,8 +252,14 @@ npx @shahmilsaari/memory-core remember "Use DTOs for all API responses" \
235
252
  | `--type` | `decision` `rule` `pattern` `note` | `decision` |
236
253
  | `--scope` | `global` `project` | `project` |
237
254
  | `--reason` | any text | asked interactively |
255
+ | `--applies-to` | comma-separated use cases | none |
256
+ | `--avoid-when` | comma-separated exceptions | none |
257
+ | `--example` | comma-separated examples | none |
258
+ | `--source` | source note, ticket, or review | none |
238
259
  | `--tags` | comma-separated | none |
239
260
 
261
+ Structured context is stored in the database as JSON and rendered into generated agent files as `Why`, `Use when`, `Avoid when`, and `Examples`, which gives AI agents clearer guidance than a flat rule sentence.
262
+
240
263
  ---
241
264
 
242
265
  ### `search` — Find a rule or decision
@@ -293,6 +316,7 @@ Options:
293
316
  ```bash
294
317
  npx @shahmilsaari/memory-core watch --path src/ # watch a specific folder only
295
318
  npx @shahmilsaari/memory-core watch --verbose # show extra details
319
+ npx @shahmilsaari/memory-core watch --debug # show prompt, diff, and raw model output
296
320
  ```
297
321
 
298
322
  Only checks source files — ignores `node_modules`, `dist`, config files, JSON, etc.
@@ -304,9 +328,11 @@ Only checks source files — ignores `node_modules`, `dist`, config files, JSON,
304
328
  ```bash
305
329
  npx @shahmilsaari/memory-core check --staged # check staged files
306
330
  npx @shahmilsaari/memory-core check --staged --verbose # with extra detail
331
+ npx @shahmilsaari/memory-core check --staged --debug # show prompt, diff, and raw model output
332
+ npx @shahmilsaari/memory-core check --ci # CI mode using memories.json
307
333
  ```
308
334
 
309
- Same as the pre-commit hook. Use this in CI/CD pipelines.
335
+ `--staged` is the same path used by the pre-commit hook. `--ci` reads `memories.json` and uses a deterministic CI-friendly diff check, so pull requests can enforce rules without a local database or Ollama setup.
310
336
 
311
337
  ---
312
338
 
@@ -358,12 +384,14 @@ npx @shahmilsaari/memory-core hook uninstall # remove the hook
358
384
  npx @shahmilsaari/memory-core list
359
385
  ```
360
386
 
361
- Shows all stored memories. Filter the results:
387
+ By default, shows memories relevant to the current project context: detected stack, current project name, plus shared/global memories. Use `--all` for the old database-wide view.
362
388
 
363
389
  ```bash
390
+ npx @shahmilsaari/memory-core list --all
364
391
  npx @shahmilsaari/memory-core list --type rule
365
392
  npx @shahmilsaari/memory-core list --scope global
366
393
  npx @shahmilsaari/memory-core list --arch clean-architecture
394
+ npx @shahmilsaari/memory-core list --project my-api
367
395
  npx @shahmilsaari/memory-core list --limit 50
368
396
  ```
369
397
 
@@ -372,6 +400,9 @@ npx @shahmilsaari/memory-core list --limit 50
372
400
  | `--type <type>` | Filter by type: `decision` `rule` `pattern` `note` |
373
401
  | `--scope <scope>` | Filter by scope: `global` `project` |
374
402
  | `--arch <architecture>` | Filter by architecture profile |
403
+ | `--project <name>` | Filter by project name |
404
+ | `--all` | Show the full shared database |
405
+ | `--current` | Explicitly use the current project context |
375
406
  | `--limit <n>` | Max results (default 200) |
376
407
 
377
408
  ---
@@ -380,19 +411,41 @@ npx @shahmilsaari/memory-core list --limit 50
380
411
 
381
412
  ```bash
382
413
  npx @shahmilsaari/memory-core remove <id>
414
+ npx @shahmilsaari/memory-core remove <id> --no-sync
383
415
  ```
384
416
 
385
417
  Deletes a memory by its ID. Get the ID from `list` or `search`.
386
418
 
387
419
  ---
388
420
 
421
+ ### `forget` — Bulk-delete memories
422
+
423
+ ```bash
424
+ npx @shahmilsaari/memory-core forget --tag nextjs --scope global
425
+ npx @shahmilsaari/memory-core forget --type ignore
426
+ npx @shahmilsaari/memory-core forget --arch nuxt
427
+ ```
428
+
429
+ Deletes memories by filter. At least one filter is required, so an empty `forget` command cannot wipe the database by accident.
430
+
431
+ | Flag | What it does |
432
+ |---|---|
433
+ | `--tag <tag>` | Delete memories with a tag |
434
+ | `--scope <scope>` | Filter by scope: `global` `project` |
435
+ | `--type <type>` | Filter by type |
436
+ | `--arch <architecture>` | Filter by architecture profile |
437
+ | `--no-sync` | Skip automatic agent file regeneration |
438
+
439
+ ---
440
+
389
441
  ### `edit` — Edit a memory
390
442
 
391
443
  ```bash
392
444
  npx @shahmilsaari/memory-core edit <id>
445
+ npx @shahmilsaari/memory-core edit <id> --no-sync
393
446
  ```
394
447
 
395
- Opens the memory interactively so you can update its content, reason, tags, type, or scope.
448
+ Opens the memory interactively so you can update its content, reason, structured context, tags, type, or scope.
396
449
 
397
450
  ---
398
451
 
@@ -413,6 +466,7 @@ Exports all memories from the database to `memories.json` in the project root (o
413
466
  npx @shahmilsaari/memory-core import
414
467
  npx @shahmilsaari/memory-core import --file path/to/my-rules.json
415
468
  npx @shahmilsaari/memory-core import --url https://example.com/team-rules.json
469
+ npx @shahmilsaari/memory-core import --no-sync
416
470
  ```
417
471
 
418
472
  Imports memories into the local database. Skips duplicates by content hash — safe to run more than once.
@@ -421,6 +475,7 @@ Imports memories into the local database. Skips duplicates by content hash — s
421
475
  |---|---|
422
476
  | `--file <path>` | Import from a custom local file path |
423
477
  | `--url <url>` | Import from a remote URL |
478
+ | `--no-sync` | Skip automatic agent file regeneration |
424
479
 
425
480
  ---
426
481
 
@@ -435,17 +490,30 @@ Saves a pattern so the hook and watcher never flag it again. Useful for intentio
435
490
  ```bash
436
491
  npx @shahmilsaari/memory-core ignore --list # show all saved ignore patterns
437
492
  npx @shahmilsaari/memory-core ignore --remove <id> # delete an ignore pattern
493
+ npx @shahmilsaari/memory-core ignore "..." --no-sync # save without regenerating agent files
438
494
  ```
439
495
 
440
496
  ---
441
497
 
498
+ ### `allow` — Allow intentional project patterns
499
+
500
+ ```bash
501
+ npx @shahmilsaari/memory-core allow "generated by sqlc"
502
+ npx @shahmilsaari/memory-core allow --list
503
+ npx @shahmilsaari/memory-core allow --remove "generated by sqlc"
504
+ ```
505
+
506
+ Stores lightweight per-project allowlist strings in `.memory-core.json`. Hook and watch checks treat these patterns as intentional before surfacing violations.
507
+
508
+ ---
509
+
442
510
  ### `ci-setup` — GitHub Actions integration
443
511
 
444
512
  ```bash
445
513
  npx @shahmilsaari/memory-core ci-setup
446
514
  ```
447
515
 
448
- 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.
516
+ Generates `.github/workflows/memory-core.yml`. Adds a PR check that runs `npx @shahmilsaari/memory-core check --ci`, using `memories.json` so CI can enforce architecture rules without a project-local database.
449
517
 
450
518
  ---
451
519
 
@@ -568,7 +636,7 @@ npx @shahmilsaari/memory-core seed # load 281 best-practice rules
568
636
  npx @shahmilsaari/memory-core remember "All auth goes through middleware, never in controllers" \
569
637
  --type decision --scope global
570
638
 
571
- # Refresh agent files after saving new memories
639
+ # Optional: refresh agent files manually anytime
572
640
  npx @shahmilsaari/memory-core sync
573
641
 
574
642
  # Not sure how something was decided? Search.
@@ -656,6 +724,24 @@ Save an ignore pattern: `npx @shahmilsaari/memory-core ignore "your exception he
656
724
 
657
725
  ---
658
726
 
727
+ ## Release checks
728
+
729
+ Before publishing, run the same checks as CI:
730
+
731
+ ```bash
732
+ npm run lint
733
+ npm run typecheck
734
+ npm test
735
+ npm run build
736
+ npm run smoke:pack
737
+ npm run smoke:npx
738
+ ```
739
+
740
+ `smoke:pack` verifies the npm tarball includes the built CLI plus templates/profiles.
741
+ `smoke:npx` installs that tarball into a fresh temporary project and runs `npx --no-install memory-core init --quick`.
742
+
743
+ ---
744
+
659
745
  ## Roadmap
660
746
 
661
747
  | | Feature |
@@ -669,6 +755,7 @@ Save an ignore pattern: `npx @shahmilsaari/memory-core ignore "your exception he
669
755
  | ✓ | CI/CD — `ci-setup` generates GitHub Actions workflow for PR enforcement |
670
756
  | ✓ | Violation stats — see which rules fire most and which files break most |
671
757
  | ✓ | Agent selection — choose which agents to generate files for during init |
758
+ | ✓ | Auto-sync — memory-changing commands refresh selected agent files by default |
672
759
  | ✓ | Export / import — portable memories.json for version control and team sharing |
673
760
  | ✓ | List / remove / edit — full CRUD for stored memories |
674
761
  | ✓ | False positive tagging — `ignore` command saves exceptions for hook and watcher |
@@ -28,6 +28,7 @@ async function runMigrations() {
28
28
  await client.query("BEGIN");
29
29
  await client.query(`ALTER TABLE memories ADD COLUMN IF NOT EXISTS reason TEXT`);
30
30
  await client.query(`ALTER TABLE memories ADD COLUMN IF NOT EXISTS content_hash TEXT`);
31
+ await client.query(`ALTER TABLE memories ADD COLUMN IF NOT EXISTS context JSONB NOT NULL DEFAULT '{}'::jsonb`);
31
32
  await client.query(
32
33
  `UPDATE memories
33
34
  SET content_hash = md5(trim(content))
@@ -45,12 +46,24 @@ async function runMigrations() {
45
46
  }
46
47
  async function saveMemory(memory) {
47
48
  await runMigrations();
48
- const { type, scope, architecture, projectName, title, content, reason, tags, embedding } = memory;
49
+ const { type, scope, architecture, projectName, title, content, reason, context, tags, embedding } = memory;
49
50
  const contentHash = hashMemoryContent(content);
50
51
  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]
52
+ `INSERT INTO memories (type, scope, architecture, project_name, title, content, reason, context, tags, embedding, content_hash)
53
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8::jsonb, $9, $10, $11)`,
54
+ [
55
+ type,
56
+ scope,
57
+ architecture ?? null,
58
+ projectName ?? null,
59
+ title ?? null,
60
+ content,
61
+ reason ?? null,
62
+ JSON.stringify(context ?? {}),
63
+ tags ?? [],
64
+ `[${embedding.join(",")}]`,
65
+ contentHash
66
+ ]
54
67
  );
55
68
  }
56
69
  async function upsertMemory(memory) {
@@ -84,12 +97,16 @@ async function listMemories(filters = {}) {
84
97
  if (filters.architecture) {
85
98
  if (Array.isArray(filters.architecture)) {
86
99
  params.push(filters.architecture);
87
- where.push(`architecture = ANY($${params.length})`);
100
+ where.push(filters.includeGlobal ? `(architecture IS NULL OR architecture = ANY($${params.length}))` : `architecture = ANY($${params.length})`);
88
101
  } else {
89
102
  params.push(filters.architecture);
90
- where.push(`architecture = $${params.length}`);
103
+ where.push(filters.includeGlobal ? `(architecture IS NULL OR architecture = $${params.length})` : `architecture = $${params.length}`);
91
104
  }
92
105
  }
106
+ if (filters.projectName) {
107
+ params.push(filters.projectName);
108
+ where.push(filters.includeGlobal ? `(project_name IS NULL OR project_name = $${params.length})` : `project_name = $${params.length}`);
109
+ }
93
110
  if (filters.tags?.length) {
94
111
  params.push(filters.tags);
95
112
  where.push(`tags && $${params.length}::text[]`);
@@ -97,7 +114,7 @@ async function listMemories(filters = {}) {
97
114
  const limit = filters.limit ?? 200;
98
115
  params.push(limit);
99
116
  const result = await getPool().query(
100
- `SELECT id, type, scope, architecture, project_name, title, content, reason, tags, content_hash
117
+ `SELECT id, type, scope, architecture, project_name, title, content, reason, context, tags, content_hash
101
118
  FROM memories
102
119
  ${where.length ? `WHERE ${where.join(" AND ")}` : ""}
103
120
  ORDER BY id ASC
@@ -109,7 +126,7 @@ async function listMemories(filters = {}) {
109
126
  async function getMemory(id) {
110
127
  await runMigrations();
111
128
  const result = await getPool().query(
112
- `SELECT id, type, scope, architecture, project_name, title, content, reason, tags, content_hash
129
+ `SELECT id, type, scope, architecture, project_name, title, content, reason, context, tags, content_hash
113
130
  FROM memories
114
131
  WHERE id = $1`,
115
132
  [id]
@@ -169,11 +186,12 @@ async function updateMemory(id, patch) {
169
186
  title = $4,
170
187
  content = $5,
171
188
  reason = $6,
172
- tags = $7,
173
- content_hash = $8,
174
- embedding = COALESCE($9::vector, embedding)
189
+ context = $7::jsonb,
190
+ tags = $8,
191
+ content_hash = $9,
192
+ embedding = COALESCE($10::vector, embedding)
175
193
  WHERE id = $1
176
- RETURNING id, type, scope, architecture, project_name, title, content, reason, tags, content_hash`,
194
+ RETURNING id, type, scope, architecture, project_name, title, content, reason, context, tags, content_hash`,
177
195
  [
178
196
  id,
179
197
  patch.type ?? current.type,
@@ -181,6 +199,7 @@ async function updateMemory(id, patch) {
181
199
  patch.title ?? current.title ?? null,
182
200
  content,
183
201
  patch.reason ?? current.reason ?? null,
202
+ JSON.stringify(patch.context ?? current.context ?? {}),
184
203
  patch.tags ?? current.tags ?? [],
185
204
  contentHash,
186
205
  embedding
@@ -207,7 +226,7 @@ async function searchMemories(embedding, architectures, limit = 10) {
207
226
  await client.query("BEGIN");
208
227
  await client.query("SET LOCAL ivfflat.probes = 10");
209
228
  const result = await client.query(
210
- `SELECT id, type, scope, architecture, project_name, title, content, reason, tags,
229
+ `SELECT id, type, scope, architecture, project_name, title, content, reason, context, tags,
211
230
  1 - (embedding <=> $1) AS similarity
212
231
  FROM memories
213
232
  ${whereClause}