claude_memory 0.4.0 → 0.5.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.
- checksums.yaml +4 -4
- data/.claude/CLAUDE.md +1 -1
- data/.claude/rules/claude_memory.generated.md +14 -1
- data/.claude/skills/check-memory/SKILL.md +10 -0
- data/.claude/skills/improve/SKILL.md +12 -1
- data/.claude-plugin/plugin.json +1 -1
- data/CHANGELOG.md +70 -0
- data/db/migrations/008_add_provenance_line_range.rb +21 -0
- data/db/migrations/009_add_docid.rb +39 -0
- data/db/migrations/010_add_llm_cache.rb +30 -0
- data/docs/improvements.md +72 -1084
- data/docs/influence/claude-supermemory.md +498 -0
- data/docs/influence/qmd.md +424 -2022
- data/docs/quality_review.md +64 -705
- data/lib/claude_memory/commands/doctor_command.rb +45 -4
- data/lib/claude_memory/commands/explain_command.rb +11 -6
- data/lib/claude_memory/commands/stats_command.rb +1 -1
- data/lib/claude_memory/core/fact_graph.rb +122 -0
- data/lib/claude_memory/core/fact_query_builder.rb +34 -14
- data/lib/claude_memory/core/fact_ranker.rb +3 -20
- data/lib/claude_memory/core/relative_time.rb +45 -0
- data/lib/claude_memory/core/result_sorter.rb +2 -2
- data/lib/claude_memory/core/rr_fusion.rb +57 -0
- data/lib/claude_memory/core/snippet_extractor.rb +97 -0
- data/lib/claude_memory/domain/fact.rb +3 -1
- data/lib/claude_memory/index/index_query.rb +2 -0
- data/lib/claude_memory/index/lexical_fts.rb +18 -0
- data/lib/claude_memory/infrastructure/operation_tracker.rb +7 -21
- data/lib/claude_memory/infrastructure/schema_validator.rb +30 -25
- data/lib/claude_memory/ingest/content_sanitizer.rb +8 -1
- data/lib/claude_memory/ingest/ingester.rb +67 -56
- data/lib/claude_memory/ingest/tool_extractor.rb +1 -1
- data/lib/claude_memory/ingest/tool_filter.rb +55 -0
- data/lib/claude_memory/logging/logger.rb +112 -0
- data/lib/claude_memory/mcp/query_guide.rb +96 -0
- data/lib/claude_memory/mcp/response_formatter.rb +86 -23
- data/lib/claude_memory/mcp/server.rb +34 -4
- data/lib/claude_memory/mcp/text_summary.rb +257 -0
- data/lib/claude_memory/mcp/tool_definitions.rb +20 -4
- data/lib/claude_memory/mcp/tools.rb +133 -120
- data/lib/claude_memory/publish.rb +12 -2
- data/lib/claude_memory/recall/expansion_detector.rb +44 -0
- data/lib/claude_memory/recall.rb +93 -41
- data/lib/claude_memory/resolve/resolver.rb +72 -40
- data/lib/claude_memory/store/sqlite_store.rb +99 -24
- data/lib/claude_memory/sweep/sweeper.rb +6 -0
- data/lib/claude_memory/version.rb +1 -1
- data/lib/claude_memory.rb +21 -0
- metadata +14 -2
- data/docs/remaining_improvements.md +0 -330
|
@@ -50,61 +50,91 @@ module ClaudeMemory
|
|
|
50
50
|
end
|
|
51
51
|
|
|
52
52
|
def resolve_fact(fact_data, entity_ids, content_item_id, occurred_at)
|
|
53
|
-
subject_id =
|
|
53
|
+
subject_id = resolve_subject(fact_data, entity_ids)
|
|
54
|
+
existing_facts = @store.facts_for_slot(subject_id, fact_data[:predicate])
|
|
55
|
+
resolution = determine_resolution(existing_facts, fact_data, entity_ids)
|
|
56
|
+
|
|
57
|
+
apply_resolution(resolution, fact_data, subject_id, entity_ids, content_item_id, occurred_at, existing_facts)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def resolve_subject(fact_data, entity_ids)
|
|
61
|
+
entity_ids[fact_data[:subject]] ||
|
|
54
62
|
@store.find_or_create_entity(type: "repo", name: fact_data[:subject])
|
|
63
|
+
end
|
|
55
64
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
65
|
+
def determine_resolution(existing_facts, fact_data, entity_ids)
|
|
66
|
+
return :insert unless PredicatePolicy.single?(fact_data[:predicate]) && existing_facts.any?
|
|
67
|
+
|
|
68
|
+
object_entity_id = entity_ids[fact_data[:object]]
|
|
69
|
+
matching = existing_facts.find { |f| values_match?(f, fact_data[:object], object_entity_id) }
|
|
70
|
+
|
|
71
|
+
if matching
|
|
72
|
+
:reinforce
|
|
73
|
+
elsif supersession_signal?(fact_data)
|
|
74
|
+
:supersede
|
|
75
|
+
else
|
|
76
|
+
:conflict
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def apply_resolution(resolution, fact_data, subject_id, entity_ids, content_item_id, occurred_at, existing_facts)
|
|
81
|
+
case resolution
|
|
82
|
+
when :reinforce
|
|
83
|
+
apply_reinforcement(existing_facts, fact_data, entity_ids, content_item_id)
|
|
84
|
+
when :conflict
|
|
85
|
+
apply_conflict(existing_facts, fact_data, subject_id, content_item_id, occurred_at)
|
|
86
|
+
else
|
|
87
|
+
apply_insert(fact_data, subject_id, entity_ids, content_item_id, occurred_at, existing_facts, resolution)
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def apply_reinforcement(existing_facts, fact_data, entity_ids, content_item_id)
|
|
92
|
+
object_entity_id = entity_ids[fact_data[:object]]
|
|
93
|
+
matching = existing_facts.find { |f| values_match?(f, fact_data[:object], object_entity_id) }
|
|
94
|
+
add_provenance(matching[:id], content_item_id, fact_data)
|
|
95
|
+
{created: 0, superseded: 0, conflicts: 0, provenance: 1}
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def apply_conflict(existing_facts, fact_data, subject_id, content_item_id, occurred_at)
|
|
99
|
+
create_conflict(existing_facts.first[:id], fact_data, subject_id, content_item_id, occurred_at)
|
|
100
|
+
{created: 0, superseded: 0, conflicts: 1, provenance: 0}
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def apply_insert(fact_data, subject_id, entity_ids, content_item_id, occurred_at, existing_facts, resolution)
|
|
104
|
+
superseded_count = 0
|
|
105
|
+
if resolution == :supersede
|
|
106
|
+
supersede_facts(existing_facts, occurred_at)
|
|
107
|
+
superseded_count = existing_facts.size
|
|
80
108
|
end
|
|
81
109
|
|
|
110
|
+
fact_id = insert_new_fact(fact_data, subject_id, entity_ids, occurred_at)
|
|
111
|
+
link_superseded_facts(fact_id, existing_facts) if superseded_count > 0
|
|
112
|
+
add_provenance(fact_id, content_item_id, fact_data)
|
|
113
|
+
|
|
114
|
+
{created: 1, superseded: superseded_count, conflicts: 0, provenance: 1}
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def insert_new_fact(fact_data, subject_id, entity_ids, occurred_at)
|
|
82
118
|
fact_scope = fact_data[:scope_hint] || @current_scope
|
|
83
119
|
fact_project = (fact_scope == "global") ? nil : @current_project_path
|
|
84
120
|
|
|
85
|
-
|
|
121
|
+
@store.insert_fact(
|
|
86
122
|
subject_entity_id: subject_id,
|
|
87
|
-
predicate: predicate,
|
|
88
|
-
object_entity_id:
|
|
89
|
-
object_literal:
|
|
123
|
+
predicate: fact_data[:predicate],
|
|
124
|
+
object_entity_id: entity_ids[fact_data[:object]],
|
|
125
|
+
object_literal: fact_data[:object],
|
|
90
126
|
polarity: fact_data[:polarity] || "positive",
|
|
91
127
|
confidence: fact_data[:confidence] || 1.0,
|
|
92
128
|
valid_from: occurred_at,
|
|
93
129
|
scope: fact_scope,
|
|
94
130
|
project_path: fact_project
|
|
95
131
|
)
|
|
96
|
-
|
|
132
|
+
end
|
|
97
133
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
end
|
|
134
|
+
def link_superseded_facts(new_fact_id, old_facts)
|
|
135
|
+
old_facts.each do |old_fact|
|
|
136
|
+
@store.insert_fact_link(from_fact_id: new_fact_id, to_fact_id: old_fact[:id], link_type: "supersedes")
|
|
102
137
|
end
|
|
103
|
-
|
|
104
|
-
add_provenance(fact_id, content_item_id, fact_data)
|
|
105
|
-
outcome[:provenance] = 1
|
|
106
|
-
|
|
107
|
-
outcome
|
|
108
138
|
end
|
|
109
139
|
|
|
110
140
|
def supersession_signal?(fact_data)
|
|
@@ -151,7 +181,9 @@ module ClaudeMemory
|
|
|
151
181
|
fact_id: fact_id,
|
|
152
182
|
content_item_id: content_item_id,
|
|
153
183
|
quote: fact_data[:quote],
|
|
154
|
-
strength: fact_data[:strength] || "stated"
|
|
184
|
+
strength: fact_data[:strength] || "stated",
|
|
185
|
+
line_start: fact_data[:line_start],
|
|
186
|
+
line_end: fact_data[:line_end]
|
|
155
187
|
)
|
|
156
188
|
end
|
|
157
189
|
end
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require "sequel"
|
|
4
4
|
require "sequel/extensions/migration"
|
|
5
|
+
require "digest"
|
|
5
6
|
require "json"
|
|
6
7
|
require "extralite"
|
|
7
8
|
require "sequel/adapters/extralite"
|
|
@@ -9,7 +10,7 @@ require "sequel/adapters/extralite"
|
|
|
9
10
|
module ClaudeMemory
|
|
10
11
|
module Store
|
|
11
12
|
class SQLiteStore
|
|
12
|
-
SCHEMA_VERSION =
|
|
13
|
+
SCHEMA_VERSION = 10
|
|
13
14
|
|
|
14
15
|
attr_reader :db
|
|
15
16
|
|
|
@@ -17,32 +18,20 @@ module ClaudeMemory
|
|
|
17
18
|
@db_path = db_path
|
|
18
19
|
@db = connect_database(db_path)
|
|
19
20
|
|
|
20
|
-
configure_pragmas
|
|
21
|
-
|
|
22
21
|
ensure_schema!
|
|
23
22
|
end
|
|
24
23
|
|
|
25
24
|
private
|
|
26
25
|
|
|
27
26
|
def connect_database(db_path)
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
# - Safer concurrent hook execution
|
|
37
|
-
@db.run("PRAGMA journal_mode = WAL")
|
|
38
|
-
@db.run("PRAGMA synchronous = NORMAL")
|
|
39
|
-
|
|
40
|
-
# Set busy timeout to 30 seconds (increased from 5s)
|
|
41
|
-
# - Allows much longer wait times before raising BusyException
|
|
42
|
-
# - Critical for concurrent hook execution with MCP server
|
|
43
|
-
# - Combined with ingester retry logic, provides ~5 minutes total wait
|
|
44
|
-
# - Extralite releases GVL for better threading performance
|
|
45
|
-
@db.run("PRAGMA busy_timeout = 30000")
|
|
27
|
+
Sequel.connect(
|
|
28
|
+
"extralite:#{db_path}",
|
|
29
|
+
connect_sqls: [
|
|
30
|
+
"PRAGMA journal_mode = WAL",
|
|
31
|
+
"PRAGMA synchronous = NORMAL",
|
|
32
|
+
"PRAGMA busy_timeout = 30000"
|
|
33
|
+
]
|
|
34
|
+
)
|
|
46
35
|
end
|
|
47
36
|
|
|
48
37
|
public
|
|
@@ -110,6 +99,10 @@ module ClaudeMemory
|
|
|
110
99
|
@db[:ingestion_metrics]
|
|
111
100
|
end
|
|
112
101
|
|
|
102
|
+
def llm_cache
|
|
103
|
+
@db[:llm_cache]
|
|
104
|
+
end
|
|
105
|
+
|
|
113
106
|
def upsert_content_item(source:, text_hash:, byte_len:, session_id: nil, transcript_path: nil,
|
|
114
107
|
project_path: nil, occurred_at: nil, raw_text: nil, metadata: nil,
|
|
115
108
|
git_branch: nil, cwd: nil, claude_version: nil, thinking_level: nil, source_mtime: nil)
|
|
@@ -194,6 +187,7 @@ module ClaudeMemory
|
|
|
194
187
|
datatype: nil, polarity: "positive", valid_from: nil, status: "active",
|
|
195
188
|
confidence: 1.0, created_from: nil, scope: "project", project_path: nil)
|
|
196
189
|
now = Time.now.utc.iso8601
|
|
190
|
+
docid = generate_docid(subject_entity_id, predicate, object_literal, now)
|
|
197
191
|
facts.insert(
|
|
198
192
|
subject_entity_id: subject_entity_id,
|
|
199
193
|
predicate: predicate,
|
|
@@ -207,10 +201,15 @@ module ClaudeMemory
|
|
|
207
201
|
created_from: created_from,
|
|
208
202
|
created_at: now,
|
|
209
203
|
scope: scope,
|
|
210
|
-
project_path: project_path
|
|
204
|
+
project_path: project_path,
|
|
205
|
+
docid: docid
|
|
211
206
|
)
|
|
212
207
|
end
|
|
213
208
|
|
|
209
|
+
def find_fact_by_docid(docid)
|
|
210
|
+
facts.where(docid: docid).first
|
|
211
|
+
end
|
|
212
|
+
|
|
214
213
|
def update_fact(fact_id, status: nil, valid_to: nil, scope: nil, project_path: nil, embedding: nil)
|
|
215
214
|
updates = {}
|
|
216
215
|
updates[:status] = status if status
|
|
@@ -253,13 +252,16 @@ module ClaudeMemory
|
|
|
253
252
|
.all
|
|
254
253
|
end
|
|
255
254
|
|
|
256
|
-
def insert_provenance(fact_id:, content_item_id: nil, quote: nil, attribution_entity_id: nil, strength: "stated"
|
|
255
|
+
def insert_provenance(fact_id:, content_item_id: nil, quote: nil, attribution_entity_id: nil, strength: "stated",
|
|
256
|
+
line_start: nil, line_end: nil)
|
|
257
257
|
provenance.insert(
|
|
258
258
|
fact_id: fact_id,
|
|
259
259
|
content_item_id: content_item_id,
|
|
260
260
|
quote: quote,
|
|
261
261
|
attribution_entity_id: attribution_entity_id,
|
|
262
|
-
strength: strength
|
|
262
|
+
strength: strength,
|
|
263
|
+
line_start: line_start,
|
|
264
|
+
line_end: line_end
|
|
263
265
|
)
|
|
264
266
|
end
|
|
265
267
|
|
|
@@ -343,6 +345,65 @@ module ClaudeMemory
|
|
|
343
345
|
}
|
|
344
346
|
end
|
|
345
347
|
|
|
348
|
+
# Look up a cached LLM response by cache key
|
|
349
|
+
#
|
|
350
|
+
# @param cache_key [String] SHA256 hex digest of operation+model+input
|
|
351
|
+
# @return [Hash, nil] Cached result row or nil
|
|
352
|
+
def llm_cache_lookup(cache_key)
|
|
353
|
+
llm_cache.where(cache_key: cache_key).first
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
# Store an LLM response in the cache
|
|
357
|
+
#
|
|
358
|
+
# @param operation [String] Operation type (e.g., "distill", "extract")
|
|
359
|
+
# @param model [String] Model identifier
|
|
360
|
+
# @param input_hash [String] SHA256 of input content
|
|
361
|
+
# @param result_json [String] JSON response to cache
|
|
362
|
+
# @param input_tokens [Integer, nil] Tokens in request
|
|
363
|
+
# @param output_tokens [Integer, nil] Tokens in response
|
|
364
|
+
# @return [Integer] The created cache entry ID
|
|
365
|
+
def llm_cache_store(operation:, model:, input_hash:, result_json:, input_tokens: nil, output_tokens: nil)
|
|
366
|
+
cache_key = Digest::SHA256.hexdigest("#{operation}:#{model}:#{input_hash}")
|
|
367
|
+
|
|
368
|
+
llm_cache
|
|
369
|
+
.insert_conflict(target: :cache_key, update: {
|
|
370
|
+
result_json: result_json,
|
|
371
|
+
input_tokens: input_tokens,
|
|
372
|
+
output_tokens: output_tokens,
|
|
373
|
+
created_at: Time.now.utc.iso8601
|
|
374
|
+
})
|
|
375
|
+
.insert(
|
|
376
|
+
cache_key: cache_key,
|
|
377
|
+
operation: operation,
|
|
378
|
+
model: model,
|
|
379
|
+
input_hash: input_hash,
|
|
380
|
+
result_json: result_json,
|
|
381
|
+
input_tokens: input_tokens,
|
|
382
|
+
output_tokens: output_tokens,
|
|
383
|
+
created_at: Time.now.utc.iso8601
|
|
384
|
+
)
|
|
385
|
+
end
|
|
386
|
+
|
|
387
|
+
# Generate a cache key for LLM response lookup
|
|
388
|
+
#
|
|
389
|
+
# @param operation [String] Operation type
|
|
390
|
+
# @param model [String] Model identifier
|
|
391
|
+
# @param input [String] Raw input content
|
|
392
|
+
# @return [String] SHA256 hex digest cache key
|
|
393
|
+
def llm_cache_key(operation, model, input)
|
|
394
|
+
input_hash = Digest::SHA256.hexdigest(input)
|
|
395
|
+
Digest::SHA256.hexdigest("#{operation}:#{model}:#{input_hash}")
|
|
396
|
+
end
|
|
397
|
+
|
|
398
|
+
# Prune cache entries older than the given age
|
|
399
|
+
#
|
|
400
|
+
# @param max_age_seconds [Integer] Maximum age in seconds (default: 7 days)
|
|
401
|
+
# @return [Integer] Number of entries pruned
|
|
402
|
+
def llm_cache_prune(max_age_seconds: 604_800)
|
|
403
|
+
cutoff = (Time.now - max_age_seconds).utc.iso8601
|
|
404
|
+
llm_cache.where { created_at < cutoff }.delete
|
|
405
|
+
end
|
|
406
|
+
|
|
346
407
|
private
|
|
347
408
|
|
|
348
409
|
def ensure_schema!
|
|
@@ -398,6 +459,20 @@ module ClaudeMemory
|
|
|
398
459
|
@db[:meta].where(key: key).get(:value)
|
|
399
460
|
end
|
|
400
461
|
|
|
462
|
+
def generate_docid(subject_entity_id, predicate, object_literal, created_at)
|
|
463
|
+
input = "#{subject_entity_id}:#{predicate}:#{object_literal}:#{created_at}"
|
|
464
|
+
docid = Digest::SHA256.hexdigest(input)[0, 8]
|
|
465
|
+
|
|
466
|
+
# Handle unlikely collisions by rehashing with a counter
|
|
467
|
+
counter = 0
|
|
468
|
+
while facts.where(docid: docid).any?
|
|
469
|
+
counter += 1
|
|
470
|
+
docid = Digest::SHA256.hexdigest("#{input}:#{counter}")[0, 8]
|
|
471
|
+
end
|
|
472
|
+
|
|
473
|
+
docid
|
|
474
|
+
end
|
|
475
|
+
|
|
401
476
|
def slugify(type, name)
|
|
402
477
|
"#{type}:#{name.downcase.gsub(/[^a-z0-9]+/, "_").gsub(/^_|_$/, "")}"
|
|
403
478
|
end
|
|
@@ -35,6 +35,12 @@ module ClaudeMemory
|
|
|
35
35
|
|
|
36
36
|
@stats[:elapsed_seconds] = Time.now - @start_time
|
|
37
37
|
@stats[:budget_honored] = @stats[:elapsed_seconds] <= budget
|
|
38
|
+
ClaudeMemory.logger.info("sweep",
|
|
39
|
+
message: "Sweep complete",
|
|
40
|
+
elapsed_seconds: @stats[:elapsed_seconds].round(3),
|
|
41
|
+
budget_honored: @stats[:budget_honored],
|
|
42
|
+
proposed_expired: @stats[:proposed_facts_expired],
|
|
43
|
+
disputed_expired: @stats[:disputed_facts_expired])
|
|
38
44
|
@stats
|
|
39
45
|
end
|
|
40
46
|
|
data/lib/claude_memory.rb
CHANGED
|
@@ -13,6 +13,7 @@ require_relative "claude_memory/core/null_explanation"
|
|
|
13
13
|
require_relative "claude_memory/core/token_estimator"
|
|
14
14
|
require_relative "claude_memory/core/batch_loader"
|
|
15
15
|
require_relative "claude_memory/core/fact_ranker"
|
|
16
|
+
require_relative "claude_memory/core/rr_fusion"
|
|
16
17
|
require_relative "claude_memory/core/concept_ranker"
|
|
17
18
|
require_relative "claude_memory/core/scope_filter"
|
|
18
19
|
require_relative "claude_memory/core/result_builder"
|
|
@@ -20,7 +21,10 @@ require_relative "claude_memory/core/fact_collector"
|
|
|
20
21
|
require_relative "claude_memory/core/embedding_candidate_builder"
|
|
21
22
|
require_relative "claude_memory/core/fact_query_builder"
|
|
22
23
|
require_relative "claude_memory/core/result_sorter"
|
|
24
|
+
require_relative "claude_memory/core/relative_time"
|
|
23
25
|
require_relative "claude_memory/core/text_builder"
|
|
26
|
+
require_relative "claude_memory/core/snippet_extractor"
|
|
27
|
+
require_relative "claude_memory/core/fact_graph"
|
|
24
28
|
require_relative "claude_memory/commands/base_command"
|
|
25
29
|
require_relative "claude_memory/commands/checks/database_check"
|
|
26
30
|
require_relative "claude_memory/commands/checks/snapshot_check"
|
|
@@ -75,17 +79,22 @@ require_relative "claude_memory/ingest/privacy_tag"
|
|
|
75
79
|
require_relative "claude_memory/ingest/content_sanitizer"
|
|
76
80
|
require_relative "claude_memory/ingest/metadata_extractor"
|
|
77
81
|
require_relative "claude_memory/ingest/tool_extractor"
|
|
82
|
+
require_relative "claude_memory/ingest/tool_filter"
|
|
78
83
|
require_relative "claude_memory/ingest/ingester"
|
|
79
84
|
require_relative "claude_memory/ingest/transcript_reader"
|
|
85
|
+
require_relative "claude_memory/logging/logger"
|
|
80
86
|
require_relative "claude_memory/infrastructure/file_system"
|
|
81
87
|
require_relative "claude_memory/infrastructure/in_memory_file_system"
|
|
82
88
|
require_relative "claude_memory/infrastructure/operation_tracker"
|
|
83
89
|
require_relative "claude_memory/infrastructure/schema_validator"
|
|
90
|
+
require_relative "claude_memory/mcp/query_guide"
|
|
91
|
+
require_relative "claude_memory/mcp/text_summary"
|
|
84
92
|
require_relative "claude_memory/mcp/tool_helpers"
|
|
85
93
|
require_relative "claude_memory/mcp/server"
|
|
86
94
|
require_relative "claude_memory/mcp/tools"
|
|
87
95
|
require_relative "claude_memory/publish"
|
|
88
96
|
require_relative "claude_memory/recall/dual_query_template"
|
|
97
|
+
require_relative "claude_memory/recall/expansion_detector"
|
|
89
98
|
require_relative "claude_memory/recall"
|
|
90
99
|
require_relative "claude_memory/shortcuts"
|
|
91
100
|
require_relative "claude_memory/resolve/predicate_policy"
|
|
@@ -103,4 +112,16 @@ module ClaudeMemory
|
|
|
103
112
|
def self.project_db_path(project_path = Dir.pwd)
|
|
104
113
|
Configuration.new.project_db_path(project_path)
|
|
105
114
|
end
|
|
115
|
+
|
|
116
|
+
# Module-level logger instance, shared across components
|
|
117
|
+
# @return [Logging::Logger, Logging::NullLogger]
|
|
118
|
+
def self.logger
|
|
119
|
+
@logger ||= Logging::Logger.new
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# Replace the module-level logger (useful for testing)
|
|
123
|
+
# @param logger [Logging::Logger, Logging::NullLogger]
|
|
124
|
+
def self.logger=(logger)
|
|
125
|
+
@logger = logger
|
|
126
|
+
end
|
|
106
127
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: claude_memory
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Valentino Stoll
|
|
@@ -88,6 +88,9 @@ files:
|
|
|
88
88
|
- db/migrations/005_add_incremental_sync.rb
|
|
89
89
|
- db/migrations/006_add_operation_tracking.rb
|
|
90
90
|
- db/migrations/007_add_ingestion_metrics.rb
|
|
91
|
+
- db/migrations/008_add_provenance_line_range.rb
|
|
92
|
+
- db/migrations/009_add_docid.rb
|
|
93
|
+
- db/migrations/010_add_llm_cache.rb
|
|
91
94
|
- docs/EXAMPLES.md
|
|
92
95
|
- docs/GETTING_STARTED.md
|
|
93
96
|
- docs/RELEASE_NOTES_v0.2.0.md
|
|
@@ -103,6 +106,7 @@ files:
|
|
|
103
106
|
- docs/expert_review.md
|
|
104
107
|
- docs/improvements.md
|
|
105
108
|
- docs/influence/.gitkeep
|
|
109
|
+
- docs/influence/claude-supermemory.md
|
|
106
110
|
- docs/influence/grepai.md
|
|
107
111
|
- docs/influence/qmd.md
|
|
108
112
|
- docs/organizational_memory_playbook.md
|
|
@@ -112,7 +116,6 @@ files:
|
|
|
112
116
|
- docs/plans/updated_plan.md
|
|
113
117
|
- docs/plugin.md
|
|
114
118
|
- docs/quality_review.md
|
|
115
|
-
- docs/remaining_improvements.md
|
|
116
119
|
- docs/review_summary.md
|
|
117
120
|
- exe/claude-memory
|
|
118
121
|
- hooks/hooks.json
|
|
@@ -157,16 +160,20 @@ files:
|
|
|
157
160
|
- lib/claude_memory/core/concept_ranker.rb
|
|
158
161
|
- lib/claude_memory/core/embedding_candidate_builder.rb
|
|
159
162
|
- lib/claude_memory/core/fact_collector.rb
|
|
163
|
+
- lib/claude_memory/core/fact_graph.rb
|
|
160
164
|
- lib/claude_memory/core/fact_id.rb
|
|
161
165
|
- lib/claude_memory/core/fact_query_builder.rb
|
|
162
166
|
- lib/claude_memory/core/fact_ranker.rb
|
|
163
167
|
- lib/claude_memory/core/null_explanation.rb
|
|
164
168
|
- lib/claude_memory/core/null_fact.rb
|
|
169
|
+
- lib/claude_memory/core/relative_time.rb
|
|
165
170
|
- lib/claude_memory/core/result.rb
|
|
166
171
|
- lib/claude_memory/core/result_builder.rb
|
|
167
172
|
- lib/claude_memory/core/result_sorter.rb
|
|
173
|
+
- lib/claude_memory/core/rr_fusion.rb
|
|
168
174
|
- lib/claude_memory/core/scope_filter.rb
|
|
169
175
|
- lib/claude_memory/core/session_id.rb
|
|
176
|
+
- lib/claude_memory/core/snippet_extractor.rb
|
|
170
177
|
- lib/claude_memory/core/text_builder.rb
|
|
171
178
|
- lib/claude_memory/core/token_estimator.rb
|
|
172
179
|
- lib/claude_memory/core/transcript_path.rb
|
|
@@ -196,16 +203,21 @@ files:
|
|
|
196
203
|
- lib/claude_memory/ingest/metadata_extractor.rb
|
|
197
204
|
- lib/claude_memory/ingest/privacy_tag.rb
|
|
198
205
|
- lib/claude_memory/ingest/tool_extractor.rb
|
|
206
|
+
- lib/claude_memory/ingest/tool_filter.rb
|
|
199
207
|
- lib/claude_memory/ingest/transcript_reader.rb
|
|
208
|
+
- lib/claude_memory/logging/logger.rb
|
|
209
|
+
- lib/claude_memory/mcp/query_guide.rb
|
|
200
210
|
- lib/claude_memory/mcp/response_formatter.rb
|
|
201
211
|
- lib/claude_memory/mcp/server.rb
|
|
202
212
|
- lib/claude_memory/mcp/setup_status_analyzer.rb
|
|
213
|
+
- lib/claude_memory/mcp/text_summary.rb
|
|
203
214
|
- lib/claude_memory/mcp/tool_definitions.rb
|
|
204
215
|
- lib/claude_memory/mcp/tool_helpers.rb
|
|
205
216
|
- lib/claude_memory/mcp/tools.rb
|
|
206
217
|
- lib/claude_memory/publish.rb
|
|
207
218
|
- lib/claude_memory/recall.rb
|
|
208
219
|
- lib/claude_memory/recall/dual_query_template.rb
|
|
220
|
+
- lib/claude_memory/recall/expansion_detector.rb
|
|
209
221
|
- lib/claude_memory/resolve/predicate_policy.rb
|
|
210
222
|
- lib/claude_memory/resolve/resolver.rb
|
|
211
223
|
- lib/claude_memory/shortcuts.rb
|