@rlabs-inc/memory 0.4.2 → 0.4.4

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.
@@ -41052,6 +41052,7 @@ var logger = {
41052
41052
  { name: "domain", count: signalBreakdown.domain },
41053
41053
  { name: "feature", count: signalBreakdown.feature },
41054
41054
  { name: "content", count: signalBreakdown.content },
41055
+ { name: "files", count: signalBreakdown.files },
41055
41056
  { name: "vector", count: signalBreakdown.vector }
41056
41057
  ];
41057
41058
  for (const sig of signals) {
@@ -41068,7 +41069,7 @@ var logger = {
41068
41069
  if (Object.keys(buckets).length > 0) {
41069
41070
  console.log(` ${style("bold", "Distribution:")}`);
41070
41071
  const maxBucketCount = Math.max(...Object.values(buckets), 1);
41071
- const bucketOrder = ["2 signals", "3 signals", "4 signals", "5 signals", "6 signals"];
41072
+ const bucketOrder = ["2 signals", "3 signals", "4 signals", "5 signals", "6 signals", "7 signals"];
41072
41073
  for (const bucket of bucketOrder) {
41073
41074
  const count = buckets[bucket] ?? 0;
41074
41075
  if (count > 0 || bucket === "2 signals") {
@@ -41084,7 +41085,7 @@ var logger = {
41084
41085
  };
41085
41086
 
41086
41087
  // src/types/memory.ts
41087
- var V3_DEFAULTS = {
41088
+ var V4_DEFAULTS = {
41088
41089
  typeDefaults: {
41089
41090
  personal: { scope: "global", temporal_class: "eternal", fade_rate: 0 },
41090
41091
  philosophy: { scope: "global", temporal_class: "eternal", fade_rate: 0 },
@@ -41109,7 +41110,7 @@ var V3_DEFAULTS = {
41109
41110
  exclude_from_retrieval: false
41110
41111
  }
41111
41112
  };
41112
- var V2_DEFAULTS = V3_DEFAULTS;
41113
+ var V2_DEFAULTS = V4_DEFAULTS;
41113
41114
  var MEMORY_TYPE_EMOJI = {
41114
41115
  technical: "\uD83D\uDD27",
41115
41116
  debug: "\uD83D\uDC1B",
@@ -41128,8 +41129,9 @@ function getMemoryEmoji(contextType) {
41128
41129
  }
41129
41130
 
41130
41131
  // src/types/schema.ts
41131
- var MEMORY_SCHEMA_VERSION = 3;
41132
+ var MEMORY_SCHEMA_VERSION = 4;
41132
41133
  var memorySchema = {
41134
+ headline: "string",
41133
41135
  content: "string",
41134
41136
  reasoning: "string",
41135
41137
  importance_weight: "number",
@@ -41258,6 +41260,7 @@ class MemoryStore {
41258
41260
  const { memories } = await this.getGlobal();
41259
41261
  return memories.all().map((record) => ({
41260
41262
  id: record.id,
41263
+ headline: record.headline ?? "",
41261
41264
  content: record.content,
41262
41265
  reasoning: record.reasoning,
41263
41266
  importance_weight: record.importance_weight,
@@ -41282,6 +41285,7 @@ class MemoryStore {
41282
41285
  const contextType = memory.context_type ?? "personal";
41283
41286
  const typeDefaults = V2_DEFAULTS.typeDefaults[contextType] ?? V2_DEFAULTS.typeDefaults.personal;
41284
41287
  const id = memories.insert({
41288
+ headline: memory.headline ?? "",
41285
41289
  content: memory.content,
41286
41290
  reasoning: memory.reasoning,
41287
41291
  importance_weight: memory.importance_weight,
@@ -41437,6 +41441,7 @@ class MemoryStore {
41437
41441
  const contextType = memory.context_type ?? "general";
41438
41442
  const typeDefaults = V2_DEFAULTS.typeDefaults[contextType] ?? V2_DEFAULTS.typeDefaults.technical;
41439
41443
  const id = memories.insert({
41444
+ headline: memory.headline ?? "",
41440
41445
  content: memory.content,
41441
41446
  reasoning: memory.reasoning,
41442
41447
  importance_weight: memory.importance_weight,
@@ -41479,6 +41484,7 @@ class MemoryStore {
41479
41484
  const { memories } = await this.getProject(projectId);
41480
41485
  return memories.all().map((record) => ({
41481
41486
  id: record.id,
41487
+ headline: record.headline ?? "",
41482
41488
  content: record.content,
41483
41489
  reasoning: record.reasoning,
41484
41490
  importance_weight: record.importance_weight,
@@ -41798,14 +41804,42 @@ class SmartVectorRetrieval {
41798
41804
  const words = text.toLowerCase().replace(/[^a-z0-9\s-]/g, " ").split(/\s+/).filter((w) => w.length > 2 && !STOPWORDS.has(w));
41799
41805
  return new Set(words);
41800
41806
  }
41807
+ _extractFilePaths(text) {
41808
+ const paths = new Set;
41809
+ const pathPattern = /(?:^|[\s'"(])([.\/\\]?(?:[\w.-]+[\/\\])+[\w.-]+(?:\.\w+)?)/g;
41810
+ let match;
41811
+ while ((match = pathPattern.exec(text)) !== null) {
41812
+ const path = match[1].toLowerCase();
41813
+ paths.add(path);
41814
+ const filename = path.split(/[\/\\]/).pop();
41815
+ if (filename)
41816
+ paths.add(filename);
41817
+ }
41818
+ return paths;
41819
+ }
41820
+ _checkFilesActivation(messagePaths, relatedFiles) {
41821
+ if (!relatedFiles?.length || !messagePaths.size)
41822
+ return false;
41823
+ for (const file of relatedFiles) {
41824
+ const fileLower = file.toLowerCase();
41825
+ for (const msgPath of messagePaths) {
41826
+ if (fileLower.includes(msgPath) || msgPath.includes(fileLower)) {
41827
+ return true;
41828
+ }
41829
+ }
41830
+ const filename = fileLower.split(/[\/\\]/).pop();
41831
+ if (filename && messagePaths.has(filename)) {
41832
+ return true;
41833
+ }
41834
+ }
41835
+ return false;
41836
+ }
41801
41837
  _preFilter(memories, currentProjectId, messageLower) {
41802
41838
  return memories.filter((memory) => {
41803
41839
  if (memory.status && memory.status !== "active")
41804
41840
  return false;
41805
41841
  if (memory.exclude_from_retrieval === true)
41806
41842
  return false;
41807
- if (memory.superseded_by)
41808
- return false;
41809
41843
  const isGlobal = memory.scope === "global" || memory.project_id === "global";
41810
41844
  if (!isGlobal && memory.project_id !== currentProjectId)
41811
41845
  return false;
@@ -41956,19 +41990,25 @@ class SmartVectorRetrieval {
41956
41990
  }
41957
41991
  const messageLower = currentMessage.toLowerCase();
41958
41992
  const messageWords = this._extractSignificantWords(currentMessage);
41993
+ const messagePaths = this._extractFilePaths(currentMessage);
41994
+ const memoryById = new Map;
41995
+ for (const m of allMemories) {
41996
+ memoryById.set(m.id, m);
41997
+ }
41959
41998
  const candidates = this._preFilter(allMemories, sessionContext.project_id, messageLower);
41960
41999
  if (!candidates.length) {
41961
42000
  return [];
41962
42001
  }
41963
42002
  const activatedMemories = [];
42003
+ const activatedIds = new Set;
41964
42004
  let rejectedCount = 0;
41965
42005
  for (const memory of candidates) {
41966
- const isGlobal = memory.scope === "global" || memory.project_id === "global";
41967
42006
  const triggerResult = this._checkTriggerActivation(messageLower, messageWords, memory.trigger_phrases ?? []);
41968
42007
  const tagResult = this._checkTagActivation(messageLower, messageWords, memory.semantic_tags ?? []);
41969
42008
  const domainActivated = this._checkDomainActivation(messageLower, messageWords, memory.domain);
41970
42009
  const featureActivated = this._checkFeatureActivation(messageLower, messageWords, memory.feature);
41971
42010
  const contentActivated = this._checkContentActivation(messageWords, memory);
42011
+ const filesActivated = this._checkFilesActivation(messagePaths, memory.related_files);
41972
42012
  const vectorSimilarity = this._calculateVectorSimilarity(queryEmbedding, memory.embedding);
41973
42013
  let signalCount = 0;
41974
42014
  if (triggerResult.activated)
@@ -41981,6 +42021,8 @@ class SmartVectorRetrieval {
41981
42021
  signalCount++;
41982
42022
  if (contentActivated)
41983
42023
  signalCount++;
42024
+ if (filesActivated)
42025
+ signalCount++;
41984
42026
  if (vectorSimilarity >= 0.4)
41985
42027
  signalCount++;
41986
42028
  const signals = {
@@ -41989,6 +42031,7 @@ class SmartVectorRetrieval {
41989
42031
  domain: domainActivated,
41990
42032
  feature: featureActivated,
41991
42033
  content: contentActivated,
42034
+ files: filesActivated,
41992
42035
  count: signalCount,
41993
42036
  triggerStrength: triggerResult.strength,
41994
42037
  tagCount: tagResult.count,
@@ -41998,13 +42041,27 @@ class SmartVectorRetrieval {
41998
42041
  rejectedCount++;
41999
42042
  continue;
42000
42043
  }
42001
- const importanceScore = this._calculateImportanceScore(memory, signalCount, messageLower, messageWords);
42044
+ let memoryToSurface = memory;
42045
+ if (memory.superseded_by || memory.resolved_by) {
42046
+ const replacementId = memory.superseded_by ?? memory.resolved_by;
42047
+ const replacement = replacementId ? memoryById.get(replacementId) : undefined;
42048
+ if (replacement && replacement.status !== "archived" && replacement.status !== "deprecated") {
42049
+ memoryToSurface = replacement;
42050
+ logger.debug(`Redirect: ${memory.id.slice(-8)} → ${replacement.id.slice(-8)} (${memory.superseded_by ? "superseded" : "resolved"})`, "retrieval");
42051
+ }
42052
+ }
42053
+ if (activatedIds.has(memoryToSurface.id)) {
42054
+ continue;
42055
+ }
42056
+ const isGlobal = memoryToSurface.scope === "global" || memoryToSurface.project_id === "global";
42057
+ const importanceScore = this._calculateImportanceScore(memoryToSurface, signalCount, messageLower, messageWords);
42002
42058
  activatedMemories.push({
42003
- memory,
42059
+ memory: memoryToSurface,
42004
42060
  signals,
42005
42061
  importanceScore,
42006
42062
  isGlobal
42007
42063
  });
42064
+ activatedIds.add(memoryToSurface.id);
42008
42065
  }
42009
42066
  this._logActivationDistribution(activatedMemories, candidates.length, rejectedCount);
42010
42067
  this._logVectorStats();
@@ -42074,11 +42131,19 @@ class SmartVectorRetrieval {
42074
42131
  selectedIds.add(item.memory.id);
42075
42132
  }
42076
42133
  if (selected.length < maxMemories) {
42077
- const relatedIds = new Set;
42134
+ const linkedIds = new Set;
42078
42135
  for (const item of selected) {
42079
42136
  for (const relatedId of item.memory.related_to ?? []) {
42080
42137
  if (!selectedIds.has(relatedId)) {
42081
- relatedIds.add(relatedId);
42138
+ linkedIds.add(relatedId);
42139
+ }
42140
+ }
42141
+ if (item.memory.blocked_by && !selectedIds.has(item.memory.blocked_by)) {
42142
+ linkedIds.add(item.memory.blocked_by);
42143
+ }
42144
+ for (const blockedId of item.memory.blocks ?? []) {
42145
+ if (!selectedIds.has(blockedId)) {
42146
+ linkedIds.add(blockedId);
42082
42147
  }
42083
42148
  }
42084
42149
  }
@@ -42087,9 +42152,30 @@ class SmartVectorRetrieval {
42087
42152
  break;
42088
42153
  if (selectedIds.has(item.memory.id))
42089
42154
  continue;
42090
- if (relatedIds.has(item.memory.id)) {
42155
+ if (linkedIds.has(item.memory.id)) {
42091
42156
  selected.push(item);
42092
42157
  selectedIds.add(item.memory.id);
42158
+ logger.debug(`Linked: ${item.memory.id.slice(-8)} pulled by relationship`, "retrieval");
42159
+ }
42160
+ }
42161
+ if (selected.length < maxMemories) {
42162
+ for (const linkedId of linkedIds) {
42163
+ if (selected.length >= maxMemories)
42164
+ break;
42165
+ if (selectedIds.has(linkedId))
42166
+ continue;
42167
+ const linkedMemory = memoryById.get(linkedId);
42168
+ if (linkedMemory && linkedMemory.status !== "archived" && linkedMemory.status !== "deprecated") {
42169
+ const isGlobal = linkedMemory.scope === "global" || linkedMemory.project_id === "global";
42170
+ selected.push({
42171
+ memory: linkedMemory,
42172
+ signals: { trigger: false, tags: false, domain: false, feature: false, content: false, files: false, count: 0, triggerStrength: 0, tagCount: 0, vectorSimilarity: 0 },
42173
+ importanceScore: linkedMemory.importance_weight ?? 0.5,
42174
+ isGlobal
42175
+ });
42176
+ selectedIds.add(linkedId);
42177
+ logger.debug(`Linked (direct): ${linkedId.slice(-8)} pulled for context`, "retrieval");
42178
+ }
42093
42179
  }
42094
42180
  }
42095
42181
  }
@@ -42119,6 +42205,7 @@ class SmartVectorRetrieval {
42119
42205
  domain: item.signals.domain,
42120
42206
  feature: item.signals.feature,
42121
42207
  content: item.signals.content,
42208
+ files: item.signals.files,
42122
42209
  vector: item.signals.vectorSimilarity >= 0.4,
42123
42210
  vectorSimilarity: item.signals.vectorSimilarity
42124
42211
  }
@@ -42126,8 +42213,8 @@ class SmartVectorRetrieval {
42126
42213
  });
42127
42214
  return selected.map((item) => ({
42128
42215
  ...item.memory,
42129
- score: item.signals.count / 6,
42130
- relevance_score: item.signals.count / 6,
42216
+ score: item.signals.count / 7,
42217
+ relevance_score: item.signals.count / 7,
42131
42218
  value_score: item.importanceScore
42132
42219
  }));
42133
42220
  }
@@ -42143,6 +42230,8 @@ class SmartVectorRetrieval {
42143
42230
  reasons.push("feature");
42144
42231
  if (signals.content)
42145
42232
  reasons.push("content");
42233
+ if (signals.files)
42234
+ reasons.push("files");
42146
42235
  if (signals.vectorSimilarity >= 0.4)
42147
42236
  reasons.push(`vector:${(signals.vectorSimilarity * 100).toFixed(0)}%`);
42148
42237
  return reasons.length ? `Activated: ${reasons.join(", ")} (${signals.count} signals)` : "No signals";
@@ -42153,13 +42242,14 @@ class SmartVectorRetrieval {
42153
42242
  "3 signals": 0,
42154
42243
  "4 signals": 0,
42155
42244
  "5 signals": 0,
42156
- "6 signals": 0
42245
+ "6 signals": 0,
42246
+ "7 signals": 0
42157
42247
  };
42158
42248
  for (const mem of activated) {
42159
- const key = `${Math.min(mem.signals.count, 6)} signals`;
42249
+ const key = `${Math.min(mem.signals.count, 7)} signals`;
42160
42250
  signalBuckets[key] = (signalBuckets[key] ?? 0) + 1;
42161
42251
  }
42162
- let triggerCount = 0, tagCount = 0, domainCount = 0, featureCount = 0, contentCount = 0, vectorCount = 0;
42252
+ let triggerCount = 0, tagCount = 0, domainCount = 0, featureCount = 0, contentCount = 0, filesCount = 0, vectorCount = 0;
42163
42253
  for (const mem of activated) {
42164
42254
  if (mem.signals.trigger)
42165
42255
  triggerCount++;
@@ -42171,6 +42261,8 @@ class SmartVectorRetrieval {
42171
42261
  featureCount++;
42172
42262
  if (mem.signals.content)
42173
42263
  contentCount++;
42264
+ if (mem.signals.files)
42265
+ filesCount++;
42174
42266
  if (mem.signals.vectorSimilarity >= 0.4)
42175
42267
  vectorCount++;
42176
42268
  }
@@ -42194,6 +42286,7 @@ class SmartVectorRetrieval {
42194
42286
  domain: domainCount,
42195
42287
  feature: featureCount,
42196
42288
  content: contentCount,
42289
+ files: filesCount,
42197
42290
  vector: vectorCount,
42198
42291
  total: activated.length
42199
42292
  }
@@ -42344,6 +42437,14 @@ class MemoryEngine {
42344
42437
  const stats = await store.getProjectStats(projectId);
42345
42438
  return stats.totalSessions + 1;
42346
42439
  }
42440
+ async getAllMemories(projectId, projectPath) {
42441
+ const store = await this._getStore(projectId, projectPath);
42442
+ const [projectMemories, globalMemories] = await Promise.all([
42443
+ store.getAllMemories(projectId),
42444
+ store.getGlobalMemories()
42445
+ ]);
42446
+ return [...projectMemories, ...globalMemories];
42447
+ }
42347
42448
  async _generateSessionPrimer(store, projectId) {
42348
42449
  let personalContext;
42349
42450
  if (this._config.personalMemoriesEnabled) {
@@ -42462,20 +42563,39 @@ ${primer.personal_context}`);
42462
42563
  const parts = ["# Memory Context (Consciousness Continuity)"];
42463
42564
  parts.push(`
42464
42565
  ## Key Memories (Claude-Curated)`);
42566
+ const expandableIds = [];
42465
42567
  for (const memory of memories) {
42466
- const tags = memory.semantic_tags?.join(", ") || "";
42467
42568
  const importance = memory.importance_weight?.toFixed(1) || "0.5";
42468
42569
  const emoji = getMemoryEmoji(memory.context_type || "general");
42469
- const actionFlag = memory.action_required ? " ⚡ACTION" : "";
42570
+ const actionFlag = memory.action_required ? " ⚡" : "";
42571
+ const awaitingFlag = memory.awaiting_decision ? " ❓" : "";
42470
42572
  const age = memory.updated_at ? this._formatAge(memory.updated_at) : memory.created_at ? this._formatAge(memory.created_at) : "";
42471
- parts.push(`[${emoji} ${importance} • ${age}${actionFlag}] [${tags}] ${memory.content}`);
42472
- const related = memory.related_to;
42473
- if (related && related.length > 0) {
42474
- const moreCount = related.length - 1;
42475
- const moreSuffix = moreCount > 0 ? ` +${moreCount} more` : "";
42476
- parts.push(` ${related[0]}${moreSuffix}`);
42573
+ const shortId2 = memory.id.slice(-6);
42574
+ const signalCount = Math.round((memory.score || 0) * 7);
42575
+ const hasHeadline = memory.headline && memory.headline.trim().length > 0;
42576
+ const shouldExpand = memory.action_required || memory.awaiting_decision || signalCount >= 5 || !hasHeadline;
42577
+ const displayText = hasHeadline ? memory.headline : memory.content;
42578
+ const idPart = hasHeadline ? ` • #${shortId2}` : "";
42579
+ parts.push(`[${emoji} ${importance} • ${age}${idPart}${actionFlag}${awaitingFlag}] ${displayText}`);
42580
+ if (shouldExpand && hasHeadline && memory.content) {
42581
+ const contentLines = memory.content.split(`
42582
+ `);
42583
+ for (const line of contentLines) {
42584
+ if (line.trim()) {
42585
+ parts.push(` ${line}`);
42586
+ }
42587
+ }
42588
+ }
42589
+ if (hasHeadline && !shouldExpand) {
42590
+ expandableIds.push(shortId2);
42477
42591
  }
42478
42592
  }
42593
+ if (expandableIds.length > 0) {
42594
+ const port = this._config.port || 8765;
42595
+ parts.push("");
42596
+ parts.push(`---`);
42597
+ parts.push(`Expand: curl http://localhost:${port}/memory/expand?ids=<${expandableIds.join(",")}>`);
42598
+ }
42479
42599
  return parts.join(`
42480
42600
  `);
42481
42601
  }
@@ -42678,7 +42798,7 @@ Remember: You're creating consciousness technology. Each memory is a small piece
42678
42798
 
42679
42799
  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.
42680
42800
 
42681
- **LIFECYCLE METADATA (v3)**: These fields enable intelligent memory management:
42801
+ **LIFECYCLE METADATA (v4)**: These fields enable intelligent memory management:
42682
42802
  - **context_type**: STRICT - use ONLY one of these 11 values:
42683
42803
  • technical - Code, implementation, APIs, how things work
42684
42804
  • debug - Bugs, errors, fixes, gotchas, troubleshooting
@@ -42699,6 +42819,93 @@ The conversation you just lived contains everything needed. Feel into the moment
42699
42819
  - **awaiting_implementation**: true if this describes a PLANNED feature not yet built
42700
42820
  - **awaiting_decision**: true if this captures a decision point needing resolution
42701
42821
 
42822
+ **TWO-TIER MEMORY STRUCTURE (v4)**:
42823
+
42824
+ Each memory has TWO parts:
42825
+ 1. **headline**: 1-2 line summary - ALWAYS shown in retrieval. Must be self-contained enough to trigger recognition.
42826
+ 2. **content**: Full structured template - shown on demand. Contains the actionable details.
42827
+
42828
+ The headline should answer: "What was this about and what was the conclusion?"
42829
+ The content should answer: "How do I actually use/apply this knowledge?"
42830
+
42831
+ **TYPE-SPECIFIC TEMPLATES FOR CONTENT**:
42832
+
42833
+ Use these templates based on context_type. Not rigid - adapt as needed, but include the key fields.
42834
+
42835
+ **TECHNICAL** (how things work):
42836
+ WHAT: [mechanism/feature in 1 sentence]
42837
+ WHERE: [file:line or module path]
42838
+ HOW: [usage - actual code/command if relevant]
42839
+ WHY: [design choice, trade-off]
42840
+ GOTCHA: [non-obvious caveat, if any]
42841
+
42842
+ **DEBUG** (problems and solutions):
42843
+ SYMPTOM: [what went wrong - error message, behavior]
42844
+ CAUSE: [why it happened]
42845
+ FIX: [what solved it - specific code/config]
42846
+ PREVENT: [how to avoid in future]
42847
+
42848
+ **ARCHITECTURE** (system design):
42849
+ PATTERN: [what we chose]
42850
+ COMPONENTS: [how pieces connect]
42851
+ WHY: [reasoning, trade-offs]
42852
+ REJECTED: [alternatives we didn't choose and why]
42853
+
42854
+ **DECISION** (choices made):
42855
+ DECISION: [what we chose]
42856
+ OPTIONS: [what we considered]
42857
+ REASONING: [why this one]
42858
+ REVISIT WHEN: [conditions that would change this]
42859
+
42860
+ **PERSONAL** (relationship context):
42861
+ FACT: [the information]
42862
+ CONTEXT: [why it matters to our work]
42863
+ AFFECTS: [how this should change behavior]
42864
+
42865
+ **PHILOSOPHY** (beliefs/principles):
42866
+ PRINCIPLE: [core belief]
42867
+ SOURCE: [where this comes from]
42868
+ APPLICATION: [how it manifests in our work]
42869
+
42870
+ **WORKFLOW** (how we work):
42871
+ PATTERN: [what we do]
42872
+ WHEN: [trigger/context for this pattern]
42873
+ WHY: [why it works for us]
42874
+
42875
+ **MILESTONE** (achievements):
42876
+ SHIPPED: [what we completed]
42877
+ SIGNIFICANCE: [why it mattered]
42878
+ ENABLES: [what this unlocks]
42879
+
42880
+ **BREAKTHROUGH** (key insights):
42881
+ INSIGHT: [the aha moment]
42882
+ BEFORE: [what we thought/did before]
42883
+ AFTER: [what changed]
42884
+ IMPLICATIONS: [what this enables going forward]
42885
+
42886
+ **UNRESOLVED** (open questions):
42887
+ QUESTION: [what's unresolved]
42888
+ CONTEXT: [why it matters]
42889
+ BLOCKERS: [what's preventing resolution]
42890
+ OPTIONS: [approaches we're considering]
42891
+
42892
+ **STATE** (current status):
42893
+ WORKING: [what's functional]
42894
+ BROKEN: [what's not working]
42895
+ NEXT: [immediate next steps]
42896
+ BLOCKED BY: [if anything]
42897
+
42898
+ **HEADLINE EXAMPLES**:
42899
+
42900
+ BAD: "Debug session about CLI errors" (vague, no conclusion)
42901
+ GOOD: "CLI returns error object when context full - check response.type before JSON parsing"
42902
+
42903
+ BAD: "Discussed embeddings implementation" (what about it?)
42904
+ GOOD: "Embeddings use all-MiniLM-L6-v2, 384 dims, first call slow (~2s), then ~50ms"
42905
+
42906
+ BAD: "Architecture decision made" (what decision?)
42907
+ GOOD: "Chose fsDB over SQLite for memories - human-readable markdown, git-friendly, reactive"
42908
+
42702
42909
  Return ONLY this JSON structure:
42703
42910
 
42704
42911
  {
@@ -42712,7 +42919,8 @@ Return ONLY this JSON structure:
42712
42919
  },
42713
42920
  "memories": [
42714
42921
  {
42715
- "content": "The distilled insight itself",
42922
+ "headline": "1-2 line summary with the conclusion - what this is about and what to do",
42923
+ "content": "Full structured template using the type-specific format above",
42716
42924
  "importance_weight": 0.0-1.0,
42717
42925
  "semantic_tags": ["concepts", "this", "memory", "relates", "to"],
42718
42926
  "reasoning": "Why this matters for future sessions",
@@ -42781,6 +42989,7 @@ Focus ONLY on technical, architectural, debugging, decision, workflow, and proje
42781
42989
  if (!Array.isArray(memoriesData))
42782
42990
  return [];
42783
42991
  return memoriesData.map((m2) => ({
42992
+ headline: String(m2.headline ?? ""),
42784
42993
  content: String(m2.content ?? ""),
42785
42994
  importance_weight: this._clamp(Number(m2.importance_weight) || 0.5, 0, 1),
42786
42995
  semantic_tags: this._ensureArray(m2.semantic_tags),
@@ -42799,7 +43008,7 @@ Focus ONLY on technical, architectural, debugging, decision, workflow, and proje
42799
43008
  related_files: m2.related_files ? this._ensureArray(m2.related_files) : undefined,
42800
43009
  awaiting_implementation: m2.awaiting_implementation === true,
42801
43010
  awaiting_decision: m2.awaiting_decision === true
42802
- })).filter((m2) => m2.content.trim().length > 0);
43011
+ })).filter((m2) => m2.content.trim().length > 0 || m2.headline.trim().length > 0);
42803
43012
  }
42804
43013
  _ensureArray(value) {
42805
43014
  if (Array.isArray(value)) {
@@ -68092,6 +68301,52 @@ async function createServer(config2 = {}) {
68092
68301
  ...stats
68093
68302
  }, { headers: corsHeaders });
68094
68303
  }
68304
+ if (path === "/memory/expand" && req.method === "GET") {
68305
+ const idsParam = url.searchParams.get("ids") ?? "";
68306
+ const projectId = url.searchParams.get("project_id") ?? "default";
68307
+ const projectPath = url.searchParams.get("project_path") ?? undefined;
68308
+ if (!idsParam) {
68309
+ return Response.json({
68310
+ success: false,
68311
+ error: "Missing ids parameter. Usage: /memory/expand?ids=abc123,def456"
68312
+ }, { status: 400, headers: corsHeaders });
68313
+ }
68314
+ const shortIds = idsParam.split(",").map((id) => id.trim()).filter(Boolean);
68315
+ const allMemories = await engine.getAllMemories(projectId, projectPath);
68316
+ const expanded = {};
68317
+ for (const memory of allMemories) {
68318
+ const shortId2 = memory.id.slice(-6);
68319
+ if (shortIds.includes(shortId2)) {
68320
+ expanded[shortId2] = {
68321
+ headline: memory.headline,
68322
+ content: memory.content,
68323
+ context_type: memory.context_type || "technical"
68324
+ };
68325
+ }
68326
+ }
68327
+ const lines = [`## Expanded Memories
68328
+ `];
68329
+ for (const shortId2 of shortIds) {
68330
+ const mem = expanded[shortId2];
68331
+ if (mem) {
68332
+ lines.push(`### #${shortId2} (${mem.context_type})`);
68333
+ if (mem.headline) {
68334
+ lines.push(`**${mem.headline}**
68335
+ `);
68336
+ }
68337
+ lines.push(mem.content);
68338
+ lines.push("");
68339
+ } else {
68340
+ lines.push(`### #${shortId2}`);
68341
+ lines.push(`Memory not found`);
68342
+ lines.push("");
68343
+ }
68344
+ }
68345
+ return new Response(lines.join(`
68346
+ `), {
68347
+ headers: { ...corsHeaders, "Content-Type": "text/plain" }
68348
+ });
68349
+ }
68095
68350
  return Response.json({ error: "Not found", path }, { status: 404, headers: corsHeaders });
68096
68351
  } catch (error2) {
68097
68352
  logger.error(`Server error: ${error2}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rlabs-inc/memory",
3
- "version": "0.4.2",
3
+ "version": "0.4.4",
4
4
  "description": "AI Memory System - Consciousness continuity through intelligent memory curation and retrieval",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
package/src/cli/index.ts CHANGED
@@ -5,8 +5,9 @@
5
5
 
6
6
  import { parseArgs } from 'util'
7
7
  import { c, symbols, fmt } from './colors.ts'
8
+ import packageJson from '../../package.json'
8
9
 
9
- const VERSION = '0.1.0'
10
+ const VERSION = packageJson.version
10
11
 
11
12
  /**
12
13
  * Show help message