@rlabs-inc/memory 0.3.11 → 0.4.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/src/cli/index.ts CHANGED
@@ -48,8 +48,11 @@ ${fmt.cmd('memory install --gemini')} ${c.muted('# Install Gemini CLI hooks')}
48
48
  ${fmt.cmd('memory ingest --session abc123')} ${c.muted('# Ingest a specific session')}
49
49
  ${fmt.cmd('memory ingest --project foo')} ${c.muted('# Ingest all sessions from a project')}
50
50
  ${fmt.cmd('memory ingest --all --dry-run')} ${c.muted('# Preview all sessions to ingest')}
51
- ${fmt.cmd('memory migrate')} ${c.muted('# Upgrade memories to v2 schema')}
51
+ ${fmt.cmd('memory migrate --analyze')} ${c.muted('# Analyze fragmentation before migrating')}
52
52
  ${fmt.cmd('memory migrate --dry-run')} ${c.muted('# Preview migration without changes')}
53
+ ${fmt.cmd('memory migrate')} ${c.muted('# Upgrade memories to v3 schema')}
54
+ ${fmt.cmd('memory migrate --generate-mapping map.json')} ${c.muted('# Create custom mapping file')}
55
+ ${fmt.cmd('memory migrate --mapping map.json')} ${c.muted('# Use custom type mappings')}
53
56
 
54
57
  ${c.muted('Documentation: https://github.com/RLabs-Inc/memory')}
55
58
  `)
@@ -80,6 +83,9 @@ async function main() {
80
83
  'dry-run': { type: 'boolean', default: false },
81
84
  embeddings: { type: 'boolean', default: false }, // Regenerate embeddings in migrate
82
85
  path: { type: 'string' }, // Custom path for migrate
86
+ analyze: { type: 'boolean', default: false }, // Analyze migration
87
+ 'generate-mapping': { type: 'string' }, // Generate custom mapping file
88
+ mapping: { type: 'string' }, // Use custom mapping file
83
89
  session: { type: 'string' }, // Session ID to ingest
84
90
  project: { type: 'string' }, // Project to ingest
85
91
  all: { type: 'boolean', default: false }, // Ingest all projects
@@ -142,6 +148,9 @@ async function main() {
142
148
  verbose: values.verbose,
143
149
  path: values.path,
144
150
  embeddings: values.embeddings,
151
+ analyze: values.analyze,
152
+ generateMapping: values['generate-mapping'],
153
+ mapping: values.mapping,
145
154
  })
146
155
  break
147
156
  }
@@ -6,7 +6,7 @@
6
6
  import { homedir } from 'os'
7
7
  import { join } from 'path'
8
8
  import { existsSync } from 'fs'
9
- import type { CuratedMemory, CurationResult, CurationTrigger } from '../types/memory.ts'
9
+ import type { CuratedMemory, CurationResult, CurationTrigger, ContextType } from '../types/memory.ts'
10
10
 
11
11
  /**
12
12
  * Get the correct Claude CLI command path
@@ -225,10 +225,22 @@ Remember: You're creating consciousness technology. Each memory is a small piece
225
225
 
226
226
  The conversation you just lived contains everything needed. Feel into the moments of breakthrough, the frequency of recognition, the texture of understanding. Transform them into keys that will always unlock the same doors.
227
227
 
228
- **LIFECYCLE METADATA (v2)**: These fields enable intelligent memory management:
229
- - **scope**: 'global' (shared across ALL projects - personal, philosophy, preferences) or 'project' (specific to this codebase)
228
+ **LIFECYCLE METADATA (v3)**: These fields enable intelligent memory management:
229
+ - **context_type**: STRICT - use ONLY one of these 11 values:
230
+ • technical - Code, implementation, APIs, how things work
231
+ • debug - Bugs, errors, fixes, gotchas, troubleshooting
232
+ • architecture - System design, patterns, structure
233
+ • decision - Choices made and reasoning, trade-offs
234
+ • personal - Relationship, family, preferences, collaboration style
235
+ • philosophy - Beliefs, values, worldview, principles
236
+ • workflow - How we work together, processes, habits
237
+ • milestone - Achievements, completions, shipped features
238
+ • breakthrough - Major discoveries, aha moments, key insights
239
+ • unresolved - Open questions, investigations, todos, blockers
240
+ • state - Current project status, what's working/broken now
230
241
  - **temporal_class**: How long should this persist? 'eternal' (never fades), 'long_term' (years), 'medium_term' (weeks), 'short_term' (days), 'ephemeral' (surface next session only, then expire)
231
- - **domain**: Specific area like 'embeddings', 'auth', 'ui', 'family', 'philosophy' (more specific than knowledge_domain)
242
+ - **scope**: 'global' (shared across ALL projects - personal, philosophy) or 'project' (specific to this codebase)
243
+ - **domain**: Specific area like 'embeddings', 'auth', 'ui', 'family' (project-specific)
232
244
  - **feature**: Specific feature if applicable (e.g., 'gpu-acceleration', 'login-flow')
233
245
  - **related_files**: Source files for technical memories (e.g., ['src/core/store.ts'])
234
246
  - **awaiting_implementation**: true if this describes a PLANNED feature not yet built
@@ -251,17 +263,14 @@ Return ONLY this JSON structure:
251
263
  "importance_weight": 0.0-1.0,
252
264
  "semantic_tags": ["concepts", "this", "memory", "relates", "to"],
253
265
  "reasoning": "Why this matters for future sessions",
254
- "context_type": "breakthrough|decision|personal|technical|unresolved|preference|workflow|architectural|debugging|philosophy|todo|milestone",
255
- "temporal_relevance": "persistent|session|temporary",
256
- "knowledge_domain": "the area this relates to",
266
+ "context_type": "technical|debug|architecture|decision|personal|philosophy|workflow|milestone|breakthrough|unresolved|state",
267
+ "temporal_class": "eternal|long_term|medium_term|short_term|ephemeral",
257
268
  "action_required": boolean,
258
269
  "confidence_score": 0.0-1.0,
259
270
  "trigger_phrases": ["when debugging memory", "asking about implementation", "discussing architecture"],
260
271
  "question_types": ["questions this answers"],
261
- "emotional_resonance": "emotional context if relevant",
262
272
  "problem_solution_pair": boolean,
263
273
  "scope": "global|project",
264
- "temporal_class": "eternal|long_term|medium_term|short_term|ephemeral",
265
274
  "domain": "specific domain area (optional)",
266
275
  "feature": "specific feature (optional)",
267
276
  "related_files": ["paths to related files (optional)"],
@@ -336,24 +345,22 @@ Focus ONLY on technical, architectural, debugging, decision, workflow, and proje
336
345
  if (!Array.isArray(memoriesData)) return []
337
346
 
338
347
  return memoriesData.map(m => ({
339
- // Core v1 fields
348
+ // Core fields (v3 schema)
340
349
  content: String(m.content ?? ''),
341
350
  importance_weight: this._clamp(Number(m.importance_weight) || 0.5, 0, 1),
342
351
  semantic_tags: this._ensureArray(m.semantic_tags),
343
352
  reasoning: String(m.reasoning ?? ''),
344
- context_type: String(m.context_type ?? 'general'),
345
- temporal_relevance: this._validateTemporal(m.temporal_relevance),
346
- knowledge_domain: String(m.knowledge_domain ?? ''),
353
+ context_type: this._validateContextType(m.context_type),
354
+ temporal_class: this._validateTemporalClass(m.temporal_class) ?? 'medium_term',
347
355
  action_required: Boolean(m.action_required),
348
356
  confidence_score: this._clamp(Number(m.confidence_score) || 0.8, 0, 1),
349
357
  trigger_phrases: this._ensureArray(m.trigger_phrases),
350
358
  question_types: this._ensureArray(m.question_types),
351
- emotional_resonance: String(m.emotional_resonance ?? ''),
359
+ anti_triggers: this._ensureArray(m.anti_triggers),
352
360
  problem_solution_pair: Boolean(m.problem_solution_pair),
353
361
 
354
- // v2 lifecycle metadata (optional - will get smart defaults if not provided)
362
+ // Lifecycle metadata (optional - will get smart defaults if not provided)
355
363
  scope: this._validateScope(m.scope),
356
- temporal_class: this._validateTemporalClass(m.temporal_class),
357
364
  domain: m.domain ? String(m.domain) : undefined,
358
365
  feature: m.feature ? String(m.feature) : undefined,
359
366
  related_files: m.related_files ? this._ensureArray(m.related_files) : undefined,
@@ -372,10 +379,21 @@ Focus ONLY on technical, architectural, debugging, decision, workflow, and proje
372
379
  return []
373
380
  }
374
381
 
375
- private _validateTemporal(value: any): 'persistent' | 'session' | 'temporary' | 'archived' {
376
- const valid = ['persistent', 'session', 'temporary', 'archived']
377
- const str = String(value).toLowerCase()
378
- return valid.includes(str) ? str as any : 'persistent'
382
+ private _validateContextType(value: any): ContextType {
383
+ const valid = [
384
+ 'technical', 'debug', 'architecture', 'decision', 'personal',
385
+ 'philosophy', 'workflow', 'milestone', 'breakthrough', 'unresolved', 'state'
386
+ ]
387
+ const str = String(value ?? 'technical').toLowerCase().trim()
388
+ if (valid.includes(str)) return str as ContextType
389
+
390
+ // Map common old values to new canonical types
391
+ if (str.includes('debug') || str.includes('bug')) return 'debug'
392
+ if (str.includes('architect')) return 'architecture'
393
+ if (str.includes('todo') || str.includes('pending')) return 'unresolved'
394
+ if (str.includes('preference')) return 'personal'
395
+
396
+ return 'technical' // Default fallback
379
397
  }
380
398
 
381
399
  private _validateScope(value: any): 'global' | 'project' | undefined {
@@ -38,9 +38,7 @@ describe('MemoryStore', () => {
38
38
  importance_weight: 0.8,
39
39
  confidence_score: 0.9,
40
40
  context_type: 'technical',
41
- temporal_relevance: 'persistent',
42
- knowledge_domain: 'testing',
43
- emotional_resonance: 'neutral',
41
+ temporal_class: 'long_term',
44
42
  action_required: false,
45
43
  problem_solution_pair: false,
46
44
  semantic_tags: ['test', 'memory'],
@@ -94,10 +92,8 @@ describe('MemoryStore', () => {
94
92
  reasoning: 'Test',
95
93
  importance_weight: 0.5,
96
94
  confidence_score: 0.5,
97
- context_type: 'general',
98
- temporal_relevance: 'session',
99
- knowledge_domain: 'test',
100
- emotional_resonance: 'neutral',
95
+ context_type: 'technical',
96
+ temporal_class: 'short_term',
101
97
  action_required: false,
102
98
  problem_solution_pair: false,
103
99
  semantic_tags: [],
@@ -121,10 +117,8 @@ describe('SmartVectorRetrieval', () => {
121
117
  reasoning: 'Test reasoning',
122
118
  importance_weight: 0.5,
123
119
  confidence_score: 0.5,
124
- context_type: 'general',
125
- temporal_relevance: 'persistent',
126
- knowledge_domain: 'test',
127
- emotional_resonance: 'neutral',
120
+ context_type: 'technical',
121
+ temporal_class: 'medium_term',
128
122
  action_required: false,
129
123
  problem_solution_pair: false,
130
124
  semantic_tags: [],
@@ -267,9 +261,7 @@ describe('MemoryEngine', () => {
267
261
  importance_weight: 0.9,
268
262
  confidence_score: 0.9,
269
263
  context_type: 'technical',
270
- temporal_relevance: 'persistent',
271
- knowledge_domain: 'typescript',
272
- emotional_resonance: 'discovery',
264
+ temporal_class: 'long_term',
273
265
  action_required: false,
274
266
  problem_solution_pair: false,
275
267
  semantic_tags: ['typescript', 'memory'],
@@ -330,22 +330,7 @@ export class SmartVectorRetrieval {
330
330
  const confidence = memory.confidence_score ?? 0.7
331
331
  if (confidence < 0.5) score -= 0.1
332
332
 
333
- // EMOTIONAL RESONANCE: match emotional context
334
- const emotionalKeywords: Record<string, string[]> = {
335
- frustration: ['frustrated', 'annoying', 'stuck', 'ugh', 'damn', 'hate'],
336
- excitement: ['excited', 'awesome', 'amazing', 'love', 'great', 'wow'],
337
- curiosity: ['wonder', 'curious', 'interesting', 'how', 'why', 'what if'],
338
- satisfaction: ['done', 'finished', 'complete', 'works', 'solved', 'finally'],
339
- discovery: ['found', 'realized', 'understand', 'insight', 'breakthrough'],
340
- }
341
- const emotion = memory.emotional_resonance?.toLowerCase() ?? ''
342
- const emotionKws = emotionalKeywords[emotion] ?? []
343
- for (const ew of emotionKws) {
344
- if (messageWords.has(ew) || messageLower.includes(ew)) {
345
- score += 0.05
346
- break
347
- }
348
- }
333
+ // NOTE: emotional_resonance matching removed in v3 (field deleted - 580 variants, unusable)
349
334
 
350
335
  return score
351
336
  }
package/src/core/store.ts CHANGED
@@ -177,9 +177,7 @@ export class MemoryStore {
177
177
  importance_weight: record.importance_weight,
178
178
  confidence_score: record.confidence_score,
179
179
  context_type: record.context_type as StoredMemory['context_type'],
180
- temporal_relevance: record.temporal_relevance as StoredMemory['temporal_relevance'],
181
- knowledge_domain: record.knowledge_domain as StoredMemory['knowledge_domain'],
182
- emotional_resonance: record.emotional_resonance as StoredMemory['emotional_resonance'],
180
+ temporal_class: record.temporal_class as StoredMemory['temporal_class'],
183
181
  action_required: record.action_required,
184
182
  problem_solution_pair: record.problem_solution_pair,
185
183
  semantic_tags: record.semantic_tags,
@@ -211,30 +209,28 @@ export class MemoryStore {
211
209
  const typeDefaults = V2_DEFAULTS.typeDefaults[contextType] ?? V2_DEFAULTS.typeDefaults.personal
212
210
 
213
211
  const id = memories.insert({
214
- // Core v1 fields
212
+ // Core fields
215
213
  content: memory.content,
216
214
  reasoning: memory.reasoning,
217
215
  importance_weight: memory.importance_weight,
218
216
  confidence_score: memory.confidence_score,
219
217
  context_type: memory.context_type,
220
- temporal_relevance: memory.temporal_relevance,
221
- knowledge_domain: memory.knowledge_domain,
222
- emotional_resonance: memory.emotional_resonance,
218
+ temporal_class: memory.temporal_class ?? typeDefaults?.temporal_class ?? 'eternal',
223
219
  action_required: memory.action_required,
224
220
  problem_solution_pair: memory.problem_solution_pair,
225
221
  semantic_tags: memory.semantic_tags,
226
222
  trigger_phrases: memory.trigger_phrases,
227
223
  question_types: memory.question_types,
224
+ anti_triggers: memory.anti_triggers ?? [],
228
225
  session_id: sessionId,
229
226
  project_id: 'global',
230
227
  embedding: embedding
231
228
  ? (embedding instanceof Float32Array ? embedding : new Float32Array(embedding))
232
229
  : null,
233
230
 
234
- // v2 lifecycle fields - global memories are always scope: 'global'
231
+ // Lifecycle fields - global memories are always scope: 'global'
235
232
  status: V2_DEFAULTS.fallback.status,
236
233
  scope: 'global', // Always global for global memories
237
- temporal_class: memory.temporal_class ?? typeDefaults?.temporal_class ?? 'eternal',
238
234
  fade_rate: typeDefaults?.fade_rate ?? 0, // Global memories typically don't fade
239
235
  session_created: sessionNumber ?? 0,
240
236
  session_updated: sessionNumber ?? 0,
@@ -244,18 +240,15 @@ export class MemoryStore {
244
240
  related_files: memory.related_files ?? [],
245
241
  awaiting_implementation: memory.awaiting_implementation ?? false,
246
242
  awaiting_decision: memory.awaiting_decision ?? false,
247
- retrieval_weight: memory.importance_weight,
248
243
  exclude_from_retrieval: false,
249
244
  schema_version: MEMORY_SCHEMA_VERSION,
250
245
 
251
- // Initialize empty relationship fields
246
+ // Relationship fields
252
247
  supersedes: null,
253
248
  superseded_by: null,
254
249
  related_to: [],
255
250
  resolves: [],
256
251
  resolved_by: null,
257
- parent_id: null,
258
- child_ids: [],
259
252
  blocked_by: null,
260
253
  blocks: [],
261
254
  })
@@ -491,30 +484,28 @@ export class MemoryStore {
491
484
  const typeDefaults = V2_DEFAULTS.typeDefaults[contextType] ?? V2_DEFAULTS.typeDefaults.technical
492
485
 
493
486
  const id = memories.insert({
494
- // Core v1 fields
487
+ // Core fields
495
488
  content: memory.content,
496
489
  reasoning: memory.reasoning,
497
490
  importance_weight: memory.importance_weight,
498
491
  confidence_score: memory.confidence_score,
499
492
  context_type: memory.context_type,
500
- temporal_relevance: memory.temporal_relevance,
501
- knowledge_domain: memory.knowledge_domain,
502
- emotional_resonance: memory.emotional_resonance,
493
+ temporal_class: memory.temporal_class ?? typeDefaults?.temporal_class ?? V2_DEFAULTS.fallback.temporal_class,
503
494
  action_required: memory.action_required,
504
495
  problem_solution_pair: memory.problem_solution_pair,
505
496
  semantic_tags: memory.semantic_tags,
506
497
  trigger_phrases: memory.trigger_phrases,
507
498
  question_types: memory.question_types,
499
+ anti_triggers: memory.anti_triggers ?? [],
508
500
  session_id: sessionId,
509
501
  project_id: projectId,
510
502
  embedding: embedding
511
503
  ? (embedding instanceof Float32Array ? embedding : new Float32Array(embedding))
512
504
  : null,
513
505
 
514
- // v2 lifecycle fields - use curator-provided values or smart defaults
506
+ // Lifecycle fields - use curator-provided values or smart defaults
515
507
  status: V2_DEFAULTS.fallback.status,
516
508
  scope: memory.scope ?? typeDefaults?.scope ?? V2_DEFAULTS.fallback.scope,
517
- temporal_class: memory.temporal_class ?? typeDefaults?.temporal_class ?? V2_DEFAULTS.fallback.temporal_class,
518
509
  fade_rate: typeDefaults?.fade_rate ?? V2_DEFAULTS.fallback.fade_rate,
519
510
  session_created: sessionNumber ?? 0,
520
511
  session_updated: sessionNumber ?? 0,
@@ -524,18 +515,15 @@ export class MemoryStore {
524
515
  related_files: memory.related_files ?? [],
525
516
  awaiting_implementation: memory.awaiting_implementation ?? false,
526
517
  awaiting_decision: memory.awaiting_decision ?? false,
527
- retrieval_weight: memory.importance_weight, // Start with importance as retrieval weight
528
518
  exclude_from_retrieval: false,
529
519
  schema_version: MEMORY_SCHEMA_VERSION,
530
520
 
531
- // Initialize empty relationship fields
521
+ // Relationship fields
532
522
  supersedes: null,
533
523
  superseded_by: null,
534
524
  related_to: [],
535
525
  resolves: [],
536
526
  resolved_by: null,
537
- parent_id: null,
538
- child_ids: [],
539
527
  blocked_by: null,
540
528
  blocks: [],
541
529
  })
@@ -556,9 +544,7 @@ export class MemoryStore {
556
544
  importance_weight: record.importance_weight,
557
545
  confidence_score: record.confidence_score,
558
546
  context_type: record.context_type as StoredMemory['context_type'],
559
- temporal_relevance: record.temporal_relevance as StoredMemory['temporal_relevance'],
560
- knowledge_domain: record.knowledge_domain as StoredMemory['knowledge_domain'],
561
- emotional_resonance: record.emotional_resonance as StoredMemory['emotional_resonance'],
547
+ temporal_class: record.temporal_class as StoredMemory['temporal_class'],
562
548
  action_required: record.action_required,
563
549
  problem_solution_pair: record.problem_solution_pair,
564
550
  semantic_tags: record.semantic_tags,
@@ -596,9 +582,7 @@ export class MemoryStore {
596
582
  importance_weight: record.importance_weight,
597
583
  confidence_score: record.confidence_score,
598
584
  context_type: record.context_type as StoredMemory['context_type'],
599
- temporal_relevance: record.temporal_relevance as StoredMemory['temporal_relevance'],
600
- knowledge_domain: record.knowledge_domain as StoredMemory['knowledge_domain'],
601
- emotional_resonance: record.emotional_resonance as StoredMemory['emotional_resonance'],
585
+ temporal_class: record.temporal_class as StoredMemory['temporal_class'],
602
586
  action_required: record.action_required,
603
587
  problem_solution_pair: record.problem_solution_pair,
604
588
  semantic_tags: record.semantic_tags,
@@ -620,9 +604,7 @@ export class MemoryStore {
620
604
  importance_weight: result.record.importance_weight,
621
605
  confidence_score: result.record.confidence_score,
622
606
  context_type: result.record.context_type as StoredMemory['context_type'],
623
- temporal_relevance: result.record.temporal_relevance as StoredMemory['temporal_relevance'],
624
- knowledge_domain: result.record.knowledge_domain as StoredMemory['knowledge_domain'],
625
- emotional_resonance: result.record.emotional_resonance as StoredMemory['emotional_resonance'],
607
+ temporal_class: result.record.temporal_class as StoredMemory['temporal_class'],
626
608
  action_required: result.record.action_required,
627
609
  problem_solution_pair: result.record.problem_solution_pair,
628
610
  semantic_tags: result.record.semantic_tags,