claude_memory 0.1.0 → 0.2.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/.mind.mv2.aLCUZd +0 -0
- data/.claude/memory.sqlite3 +0 -0
- data/.claude/rules/claude_memory.generated.md +7 -1
- data/.claude/settings.json +0 -4
- data/.claude/settings.local.json +4 -1
- data/.claude-plugin/plugin.json +1 -1
- data/.claude.json +11 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +62 -11
- data/CLAUDE.md +87 -24
- data/README.md +76 -159
- data/docs/EXAMPLES.md +436 -0
- data/docs/RELEASE_NOTES_v0.2.0.md +179 -0
- data/docs/RUBY_COMMUNITY_POST_v0.2.0.md +582 -0
- data/docs/SOCIAL_MEDIA_v0.2.0.md +420 -0
- data/docs/architecture.md +360 -0
- data/docs/expert_review.md +1718 -0
- data/docs/feature_adoption_plan.md +1241 -0
- data/docs/feature_adoption_plan_revised.md +2374 -0
- data/docs/improvements.md +1325 -0
- data/docs/quality_review.md +1544 -0
- data/docs/review_summary.md +480 -0
- data/lefthook.yml +10 -0
- data/lib/claude_memory/cli.rb +16 -844
- data/lib/claude_memory/commands/base_command.rb +95 -0
- data/lib/claude_memory/commands/changes_command.rb +39 -0
- data/lib/claude_memory/commands/conflicts_command.rb +37 -0
- data/lib/claude_memory/commands/db_init_command.rb +40 -0
- data/lib/claude_memory/commands/doctor_command.rb +147 -0
- data/lib/claude_memory/commands/explain_command.rb +65 -0
- data/lib/claude_memory/commands/help_command.rb +37 -0
- data/lib/claude_memory/commands/hook_command.rb +106 -0
- data/lib/claude_memory/commands/ingest_command.rb +47 -0
- data/lib/claude_memory/commands/init_command.rb +218 -0
- data/lib/claude_memory/commands/promote_command.rb +30 -0
- data/lib/claude_memory/commands/publish_command.rb +36 -0
- data/lib/claude_memory/commands/recall_command.rb +61 -0
- data/lib/claude_memory/commands/registry.rb +55 -0
- data/lib/claude_memory/commands/search_command.rb +43 -0
- data/lib/claude_memory/commands/serve_mcp_command.rb +16 -0
- data/lib/claude_memory/commands/sweep_command.rb +36 -0
- data/lib/claude_memory/commands/version_command.rb +13 -0
- data/lib/claude_memory/configuration.rb +38 -0
- data/lib/claude_memory/core/fact_id.rb +41 -0
- data/lib/claude_memory/core/null_explanation.rb +47 -0
- data/lib/claude_memory/core/null_fact.rb +30 -0
- data/lib/claude_memory/core/result.rb +143 -0
- data/lib/claude_memory/core/session_id.rb +37 -0
- data/lib/claude_memory/core/token_estimator.rb +33 -0
- data/lib/claude_memory/core/transcript_path.rb +37 -0
- data/lib/claude_memory/domain/conflict.rb +51 -0
- data/lib/claude_memory/domain/entity.rb +51 -0
- data/lib/claude_memory/domain/fact.rb +70 -0
- data/lib/claude_memory/domain/provenance.rb +48 -0
- data/lib/claude_memory/hook/exit_codes.rb +18 -0
- data/lib/claude_memory/hook/handler.rb +7 -2
- data/lib/claude_memory/index/index_query.rb +89 -0
- data/lib/claude_memory/index/index_query_logic.rb +41 -0
- data/lib/claude_memory/index/query_options.rb +67 -0
- data/lib/claude_memory/infrastructure/file_system.rb +29 -0
- data/lib/claude_memory/infrastructure/in_memory_file_system.rb +32 -0
- data/lib/claude_memory/ingest/content_sanitizer.rb +42 -0
- data/lib/claude_memory/ingest/ingester.rb +3 -0
- data/lib/claude_memory/ingest/privacy_tag.rb +48 -0
- data/lib/claude_memory/mcp/tools.rb +174 -1
- data/lib/claude_memory/publish.rb +29 -20
- data/lib/claude_memory/recall.rb +164 -16
- data/lib/claude_memory/resolve/resolver.rb +41 -37
- data/lib/claude_memory/shortcuts.rb +56 -0
- data/lib/claude_memory/store/store_manager.rb +35 -32
- data/lib/claude_memory/templates/hooks.example.json +0 -4
- data/lib/claude_memory/version.rb +1 -1
- data/lib/claude_memory.rb +59 -21
- metadata +55 -1
data/lib/claude_memory/recall.rb
CHANGED
|
@@ -6,6 +6,24 @@ module ClaudeMemory
|
|
|
6
6
|
SCOPE_GLOBAL = "global"
|
|
7
7
|
SCOPE_ALL = "all"
|
|
8
8
|
|
|
9
|
+
class << self
|
|
10
|
+
def recent_decisions(manager, limit: 10)
|
|
11
|
+
Shortcuts.for(:decisions, manager, limit: limit)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def architecture_choices(manager, limit: 10)
|
|
15
|
+
Shortcuts.for(:architecture, manager, limit: limit)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def conventions(manager, limit: 20)
|
|
19
|
+
Shortcuts.for(:conventions, manager, limit: limit)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def project_config(manager, limit: 10)
|
|
23
|
+
Shortcuts.for(:project_config, manager, limit: limit)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
9
27
|
def initialize(store_or_manager, fts: nil, project_path: nil, env: ENV)
|
|
10
28
|
@project_path = project_path || env["CLAUDE_PROJECT_DIR"] || Dir.pwd
|
|
11
29
|
|
|
@@ -27,6 +45,14 @@ module ClaudeMemory
|
|
|
27
45
|
end
|
|
28
46
|
end
|
|
29
47
|
|
|
48
|
+
def query_index(query_text, limit: 20, scope: SCOPE_ALL)
|
|
49
|
+
if @legacy_mode
|
|
50
|
+
query_index_legacy(query_text, limit: limit, scope: scope)
|
|
51
|
+
else
|
|
52
|
+
query_index_dual(query_text, limit: limit, scope: scope)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
30
56
|
def explain(fact_id, scope: nil)
|
|
31
57
|
if @legacy_mode
|
|
32
58
|
explain_from_store(@legacy_store, fact_id)
|
|
@@ -77,38 +103,141 @@ module ClaudeMemory
|
|
|
77
103
|
dedupe_and_sort(results, limit)
|
|
78
104
|
end
|
|
79
105
|
|
|
106
|
+
def query_index_dual(query_text, limit:, scope:)
|
|
107
|
+
results = []
|
|
108
|
+
|
|
109
|
+
if scope == SCOPE_ALL || scope == SCOPE_PROJECT
|
|
110
|
+
@manager.ensure_project! if @manager.project_exists?
|
|
111
|
+
if @manager.project_store
|
|
112
|
+
project_results = query_index_single_store(@manager.project_store, query_text, limit: limit, source: :project)
|
|
113
|
+
results.concat(project_results)
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
if scope == SCOPE_ALL || scope == SCOPE_GLOBAL
|
|
118
|
+
@manager.ensure_global! if @manager.global_exists?
|
|
119
|
+
if @manager.global_store
|
|
120
|
+
global_results = query_index_single_store(@manager.global_store, query_text, limit: limit, source: :global)
|
|
121
|
+
results.concat(global_results)
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
dedupe_and_sort_index(results, limit)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def query_index_single_store(store, query_text, limit:, source:)
|
|
129
|
+
options = Index::QueryOptions.new(
|
|
130
|
+
query_text: query_text,
|
|
131
|
+
limit: limit,
|
|
132
|
+
scope: :all,
|
|
133
|
+
source: source
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
query = Index::IndexQuery.new(store, options)
|
|
137
|
+
query.execute
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def dedupe_and_sort_index(results, limit)
|
|
141
|
+
seen_signatures = Set.new
|
|
142
|
+
unique_results = []
|
|
143
|
+
|
|
144
|
+
results.each do |result|
|
|
145
|
+
sig = "#{result[:subject]}:#{result[:predicate]}:#{result[:object_preview]}"
|
|
146
|
+
next if seen_signatures.include?(sig)
|
|
147
|
+
|
|
148
|
+
seen_signatures.add(sig)
|
|
149
|
+
unique_results << result
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# Sort by source priority (project first)
|
|
153
|
+
unique_results.sort_by do |item|
|
|
154
|
+
source_priority = (item[:source] == :project) ? 0 : 1
|
|
155
|
+
[source_priority]
|
|
156
|
+
end.first(limit)
|
|
157
|
+
end
|
|
158
|
+
|
|
80
159
|
def query_single_store(store, query_text, limit:, source:)
|
|
81
160
|
fts = Index::LexicalFTS.new(store)
|
|
82
161
|
content_ids = fts.search(query_text, limit: limit * 3)
|
|
83
162
|
return [] if content_ids.empty?
|
|
84
163
|
|
|
85
|
-
|
|
164
|
+
# Collect all fact_ids first
|
|
86
165
|
seen_fact_ids = Set.new
|
|
166
|
+
ordered_fact_ids = []
|
|
87
167
|
|
|
88
168
|
content_ids.each do |content_id|
|
|
89
169
|
provenance_records = store.provenance
|
|
90
|
-
.select(:
|
|
170
|
+
.select(:fact_id)
|
|
91
171
|
.where(content_item_id: content_id)
|
|
92
172
|
.all
|
|
93
173
|
|
|
94
174
|
provenance_records.each do |prov|
|
|
95
|
-
|
|
175
|
+
fact_id = prov[:fact_id]
|
|
176
|
+
next if seen_fact_ids.include?(fact_id)
|
|
96
177
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
seen_fact_ids.add(prov[:fact_id])
|
|
101
|
-
facts_with_provenance << {
|
|
102
|
-
fact: fact,
|
|
103
|
-
receipts: find_receipts_from_store(store, prov[:fact_id]),
|
|
104
|
-
source: source
|
|
105
|
-
}
|
|
106
|
-
break if facts_with_provenance.size >= limit
|
|
178
|
+
seen_fact_ids.add(fact_id)
|
|
179
|
+
ordered_fact_ids << fact_id
|
|
180
|
+
break if ordered_fact_ids.size >= limit
|
|
107
181
|
end
|
|
108
|
-
break if
|
|
182
|
+
break if ordered_fact_ids.size >= limit
|
|
109
183
|
end
|
|
110
184
|
|
|
111
|
-
|
|
185
|
+
return [] if ordered_fact_ids.empty?
|
|
186
|
+
|
|
187
|
+
# Batch query all facts at once
|
|
188
|
+
facts_by_id = batch_find_facts(store, ordered_fact_ids)
|
|
189
|
+
|
|
190
|
+
# Batch query all receipts at once
|
|
191
|
+
receipts_by_fact_id = batch_find_receipts(store, ordered_fact_ids)
|
|
192
|
+
|
|
193
|
+
# Build results maintaining order
|
|
194
|
+
ordered_fact_ids.map do |fact_id|
|
|
195
|
+
fact = facts_by_id[fact_id]
|
|
196
|
+
next unless fact
|
|
197
|
+
|
|
198
|
+
{
|
|
199
|
+
fact: fact,
|
|
200
|
+
receipts: receipts_by_fact_id[fact_id] || [],
|
|
201
|
+
source: source
|
|
202
|
+
}
|
|
203
|
+
end.compact
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def batch_find_facts(store, fact_ids)
|
|
207
|
+
store.facts
|
|
208
|
+
.left_join(:entities, id: :subject_entity_id)
|
|
209
|
+
.select(
|
|
210
|
+
Sequel[:facts][:id],
|
|
211
|
+
Sequel[:facts][:predicate],
|
|
212
|
+
Sequel[:facts][:object_literal],
|
|
213
|
+
Sequel[:facts][:status],
|
|
214
|
+
Sequel[:facts][:confidence],
|
|
215
|
+
Sequel[:facts][:valid_from],
|
|
216
|
+
Sequel[:facts][:valid_to],
|
|
217
|
+
Sequel[:facts][:created_at],
|
|
218
|
+
Sequel[:entities][:canonical_name].as(:subject_name),
|
|
219
|
+
Sequel[:facts][:scope],
|
|
220
|
+
Sequel[:facts][:project_path]
|
|
221
|
+
)
|
|
222
|
+
.where(Sequel[:facts][:id] => fact_ids)
|
|
223
|
+
.all
|
|
224
|
+
.each_with_object({}) { |fact, hash| hash[fact[:id]] = fact }
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
def batch_find_receipts(store, fact_ids)
|
|
228
|
+
store.provenance
|
|
229
|
+
.left_join(:content_items, id: :content_item_id)
|
|
230
|
+
.select(
|
|
231
|
+
Sequel[:provenance][:id],
|
|
232
|
+
Sequel[:provenance][:fact_id],
|
|
233
|
+
Sequel[:provenance][:quote],
|
|
234
|
+
Sequel[:provenance][:strength],
|
|
235
|
+
Sequel[:content_items][:session_id],
|
|
236
|
+
Sequel[:content_items][:occurred_at]
|
|
237
|
+
)
|
|
238
|
+
.where(Sequel[:provenance][:fact_id] => fact_ids)
|
|
239
|
+
.all
|
|
240
|
+
.group_by { |receipt| receipt[:fact_id] }
|
|
112
241
|
end
|
|
113
242
|
|
|
114
243
|
def dedupe_and_sort(results, limit)
|
|
@@ -189,7 +318,7 @@ module ClaudeMemory
|
|
|
189
318
|
|
|
190
319
|
def explain_from_store(store, fact_id)
|
|
191
320
|
fact = find_fact_from_store(store, fact_id)
|
|
192
|
-
return
|
|
321
|
+
return Core::NullExplanation.new unless fact
|
|
193
322
|
|
|
194
323
|
{
|
|
195
324
|
fact: fact,
|
|
@@ -282,6 +411,25 @@ module ClaudeMemory
|
|
|
282
411
|
sort_by_scope_priority(facts_with_provenance)
|
|
283
412
|
end
|
|
284
413
|
|
|
414
|
+
def query_index_legacy(query_text, limit:, scope:)
|
|
415
|
+
options = Index::QueryOptions.new(
|
|
416
|
+
query_text: query_text,
|
|
417
|
+
limit: limit,
|
|
418
|
+
scope: :all,
|
|
419
|
+
source: :legacy
|
|
420
|
+
)
|
|
421
|
+
|
|
422
|
+
query = Index::IndexQuery.new(@legacy_store, options)
|
|
423
|
+
results = query.execute
|
|
424
|
+
|
|
425
|
+
# Filter by scope in legacy mode
|
|
426
|
+
results.select do |result|
|
|
427
|
+
# Need to get full fact to check scope
|
|
428
|
+
fact = find_fact(result[:id])
|
|
429
|
+
fact && fact_matches_scope?(fact, scope)
|
|
430
|
+
end
|
|
431
|
+
end
|
|
432
|
+
|
|
285
433
|
def changes_legacy(since:, limit:, scope:)
|
|
286
434
|
ds = @legacy_store.facts
|
|
287
435
|
.select(:id, :subject_entity_id, :predicate, :object_literal, :status, :created_at, :scope, :project_path)
|
|
@@ -57,48 +57,51 @@ module ClaudeMemory
|
|
|
57
57
|
|
|
58
58
|
existing_facts = @store.facts_for_slot(subject_id, predicate)
|
|
59
59
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
if
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
60
|
+
# Wrap all database operations in a transaction for atomicity
|
|
61
|
+
@store.db.transaction do
|
|
62
|
+
if PredicatePolicy.single?(predicate) && existing_facts.any?
|
|
63
|
+
matching = existing_facts.find { |f| values_match?(f, object_val, object_entity_id) }
|
|
64
|
+
if matching
|
|
65
|
+
add_provenance(matching[:id], content_item_id, fact_data)
|
|
66
|
+
outcome[:provenance] = 1
|
|
67
|
+
return outcome
|
|
68
|
+
elsif supersession_signal?(fact_data)
|
|
69
|
+
supersede_facts(existing_facts, occurred_at)
|
|
70
|
+
outcome[:superseded] = existing_facts.size
|
|
71
|
+
else
|
|
72
|
+
create_conflict(existing_facts.first[:id], fact_data, subject_id, content_item_id, occurred_at)
|
|
73
|
+
outcome[:conflicts] = 1
|
|
74
|
+
return outcome
|
|
75
|
+
end
|
|
73
76
|
end
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
fact_scope = fact_data[:scope_hint] || @current_scope
|
|
77
|
-
fact_project = (fact_scope == "global") ? nil : @current_project_path
|
|
78
|
-
|
|
79
|
-
fact_id = @store.insert_fact(
|
|
80
|
-
subject_entity_id: subject_id,
|
|
81
|
-
predicate: predicate,
|
|
82
|
-
object_entity_id: object_entity_id,
|
|
83
|
-
object_literal: object_val,
|
|
84
|
-
polarity: fact_data[:polarity] || "positive",
|
|
85
|
-
confidence: fact_data[:confidence] || 1.0,
|
|
86
|
-
valid_from: occurred_at,
|
|
87
|
-
scope: fact_scope,
|
|
88
|
-
project_path: fact_project
|
|
89
|
-
)
|
|
90
|
-
outcome[:created] = 1
|
|
91
77
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
78
|
+
fact_scope = fact_data[:scope_hint] || @current_scope
|
|
79
|
+
fact_project = (fact_scope == "global") ? nil : @current_project_path
|
|
80
|
+
|
|
81
|
+
fact_id = @store.insert_fact(
|
|
82
|
+
subject_entity_id: subject_id,
|
|
83
|
+
predicate: predicate,
|
|
84
|
+
object_entity_id: object_entity_id,
|
|
85
|
+
object_literal: object_val,
|
|
86
|
+
polarity: fact_data[:polarity] || "positive",
|
|
87
|
+
confidence: fact_data[:confidence] || 1.0,
|
|
88
|
+
valid_from: occurred_at,
|
|
89
|
+
scope: fact_scope,
|
|
90
|
+
project_path: fact_project
|
|
91
|
+
)
|
|
92
|
+
outcome[:created] = 1
|
|
93
|
+
|
|
94
|
+
if existing_facts.any? && outcome[:superseded] > 0
|
|
95
|
+
existing_facts.each do |old_fact|
|
|
96
|
+
@store.insert_fact_link(from_fact_id: fact_id, to_fact_id: old_fact[:id], link_type: "supersedes")
|
|
97
|
+
end
|
|
95
98
|
end
|
|
96
|
-
end
|
|
97
99
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
+
add_provenance(fact_id, content_item_id, fact_data)
|
|
101
|
+
outcome[:provenance] = 1
|
|
100
102
|
|
|
101
|
-
|
|
103
|
+
outcome
|
|
104
|
+
end
|
|
102
105
|
end
|
|
103
106
|
|
|
104
107
|
def supersession_signal?(fact_data)
|
|
@@ -118,6 +121,7 @@ module ClaudeMemory
|
|
|
118
121
|
end
|
|
119
122
|
|
|
120
123
|
def create_conflict(existing_fact_id, new_fact_data, subject_id, content_item_id, occurred_at)
|
|
124
|
+
# Already within transaction from resolve_fact
|
|
121
125
|
new_fact_id = @store.insert_fact(
|
|
122
126
|
subject_entity_id: subject_id,
|
|
123
127
|
predicate: new_fact_data[:predicate],
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ClaudeMemory
|
|
4
|
+
class Shortcuts
|
|
5
|
+
QUERIES = {
|
|
6
|
+
decisions: {
|
|
7
|
+
query: "decision constraint rule requirement",
|
|
8
|
+
scope: :all,
|
|
9
|
+
limit: 10
|
|
10
|
+
},
|
|
11
|
+
architecture: {
|
|
12
|
+
query: "uses framework implements architecture pattern",
|
|
13
|
+
scope: :all,
|
|
14
|
+
limit: 10
|
|
15
|
+
},
|
|
16
|
+
conventions: {
|
|
17
|
+
query: "convention style format pattern prefer",
|
|
18
|
+
scope: :global,
|
|
19
|
+
limit: 20
|
|
20
|
+
},
|
|
21
|
+
project_config: {
|
|
22
|
+
query: "uses requires depends_on configuration",
|
|
23
|
+
scope: :project,
|
|
24
|
+
limit: 10
|
|
25
|
+
}
|
|
26
|
+
}.freeze
|
|
27
|
+
|
|
28
|
+
def self.for(shortcut_name, manager, **overrides)
|
|
29
|
+
config = QUERIES.fetch(shortcut_name)
|
|
30
|
+
options = config.merge(overrides)
|
|
31
|
+
|
|
32
|
+
recall = Recall.new(manager)
|
|
33
|
+
recall.query(
|
|
34
|
+
options[:query],
|
|
35
|
+
limit: options[:limit],
|
|
36
|
+
scope: options[:scope]
|
|
37
|
+
)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def self.decisions(manager, **overrides)
|
|
41
|
+
self.for(:decisions, manager, **overrides)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def self.architecture(manager, **overrides)
|
|
45
|
+
self.for(:architecture, manager, **overrides)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def self.conventions(manager, **overrides)
|
|
49
|
+
self.for(:conventions, manager, **overrides)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def self.project_config(manager, **overrides)
|
|
53
|
+
self.for(:project_config, manager, **overrides)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -85,40 +85,43 @@ module ClaudeMemory
|
|
|
85
85
|
subject = @project_store.entities.where(id: fact[:subject_entity_id]).first
|
|
86
86
|
return nil unless subject
|
|
87
87
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
if
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
88
|
+
# Wrap all database operations in a transaction for atomicity
|
|
89
|
+
@global_store.db.transaction do
|
|
90
|
+
global_subject_id = @global_store.find_or_create_entity(
|
|
91
|
+
type: subject[:type],
|
|
92
|
+
name: subject[:canonical_name]
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
global_object_id = nil
|
|
96
|
+
if fact[:object_entity_id]
|
|
97
|
+
object = @project_store.entities.where(id: fact[:object_entity_id]).first
|
|
98
|
+
if object
|
|
99
|
+
global_object_id = @global_store.find_or_create_entity(
|
|
100
|
+
type: object[:type],
|
|
101
|
+
name: object[:canonical_name]
|
|
102
|
+
)
|
|
103
|
+
end
|
|
101
104
|
end
|
|
102
|
-
end
|
|
103
105
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
106
|
+
global_fact_id = @global_store.insert_fact(
|
|
107
|
+
subject_entity_id: global_subject_id,
|
|
108
|
+
predicate: fact[:predicate],
|
|
109
|
+
object_entity_id: global_object_id,
|
|
110
|
+
object_literal: fact[:object_literal],
|
|
111
|
+
datatype: fact[:datatype],
|
|
112
|
+
polarity: fact[:polarity],
|
|
113
|
+
valid_from: fact[:valid_from],
|
|
114
|
+
status: fact[:status],
|
|
115
|
+
confidence: fact[:confidence],
|
|
116
|
+
created_from: "promoted:#{@project_path}:#{fact_id}",
|
|
117
|
+
scope: "global",
|
|
118
|
+
project_path: nil
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
copy_provenance(fact_id, global_fact_id)
|
|
122
|
+
|
|
123
|
+
global_fact_id
|
|
124
|
+
end
|
|
122
125
|
end
|
|
123
126
|
|
|
124
127
|
private
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
"hooks": {
|
|
3
3
|
"Stop": [
|
|
4
4
|
{
|
|
5
|
-
"matcher": "",
|
|
6
5
|
"hooks": [
|
|
7
6
|
{
|
|
8
7
|
"type": "command",
|
|
@@ -14,7 +13,6 @@
|
|
|
14
13
|
],
|
|
15
14
|
"SessionStart": [
|
|
16
15
|
{
|
|
17
|
-
"matcher": "",
|
|
18
16
|
"hooks": [
|
|
19
17
|
{
|
|
20
18
|
"type": "command",
|
|
@@ -26,7 +24,6 @@
|
|
|
26
24
|
],
|
|
27
25
|
"PreCompact": [
|
|
28
26
|
{
|
|
29
|
-
"matcher": "",
|
|
30
27
|
"hooks": [
|
|
31
28
|
{
|
|
32
29
|
"type": "command",
|
|
@@ -43,7 +40,6 @@
|
|
|
43
40
|
],
|
|
44
41
|
"SessionEnd": [
|
|
45
42
|
{
|
|
46
|
-
"matcher": "",
|
|
47
43
|
"hooks": [
|
|
48
44
|
{
|
|
49
45
|
"type": "command",
|
data/lib/claude_memory.rb
CHANGED
|
@@ -2,10 +2,67 @@
|
|
|
2
2
|
|
|
3
3
|
module ClaudeMemory
|
|
4
4
|
class Error < StandardError; end
|
|
5
|
+
end
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
|
|
7
|
+
require_relative "claude_memory/core/result"
|
|
8
|
+
require_relative "claude_memory/core/session_id"
|
|
9
|
+
require_relative "claude_memory/core/transcript_path"
|
|
10
|
+
require_relative "claude_memory/core/fact_id"
|
|
11
|
+
require_relative "claude_memory/core/null_fact"
|
|
12
|
+
require_relative "claude_memory/core/null_explanation"
|
|
13
|
+
require_relative "claude_memory/core/token_estimator"
|
|
14
|
+
require_relative "claude_memory/commands/base_command"
|
|
15
|
+
require_relative "claude_memory/commands/help_command"
|
|
16
|
+
require_relative "claude_memory/commands/version_command"
|
|
17
|
+
require_relative "claude_memory/commands/doctor_command"
|
|
18
|
+
require_relative "claude_memory/commands/promote_command"
|
|
19
|
+
require_relative "claude_memory/commands/search_command"
|
|
20
|
+
require_relative "claude_memory/commands/explain_command"
|
|
21
|
+
require_relative "claude_memory/commands/conflicts_command"
|
|
22
|
+
require_relative "claude_memory/commands/changes_command"
|
|
23
|
+
require_relative "claude_memory/commands/recall_command"
|
|
24
|
+
require_relative "claude_memory/commands/sweep_command"
|
|
25
|
+
require_relative "claude_memory/commands/ingest_command"
|
|
26
|
+
require_relative "claude_memory/commands/publish_command"
|
|
27
|
+
require_relative "claude_memory/commands/db_init_command"
|
|
28
|
+
require_relative "claude_memory/commands/init_command"
|
|
29
|
+
require_relative "claude_memory/commands/serve_mcp_command"
|
|
30
|
+
require_relative "claude_memory/commands/hook_command"
|
|
31
|
+
require_relative "claude_memory/commands/registry"
|
|
32
|
+
require_relative "claude_memory/cli"
|
|
33
|
+
require_relative "claude_memory/configuration"
|
|
34
|
+
require_relative "claude_memory/distill/distiller"
|
|
35
|
+
require_relative "claude_memory/distill/extraction"
|
|
36
|
+
require_relative "claude_memory/distill/null_distiller"
|
|
37
|
+
require_relative "claude_memory/domain/fact"
|
|
38
|
+
require_relative "claude_memory/domain/entity"
|
|
39
|
+
require_relative "claude_memory/domain/provenance"
|
|
40
|
+
require_relative "claude_memory/domain/conflict"
|
|
41
|
+
require_relative "claude_memory/hook/exit_codes"
|
|
42
|
+
require_relative "claude_memory/hook/handler"
|
|
43
|
+
require_relative "claude_memory/index/query_options"
|
|
44
|
+
require_relative "claude_memory/index/index_query_logic"
|
|
45
|
+
require_relative "claude_memory/index/index_query"
|
|
46
|
+
require_relative "claude_memory/index/lexical_fts"
|
|
47
|
+
require_relative "claude_memory/ingest/privacy_tag"
|
|
48
|
+
require_relative "claude_memory/ingest/content_sanitizer"
|
|
49
|
+
require_relative "claude_memory/ingest/ingester"
|
|
50
|
+
require_relative "claude_memory/ingest/transcript_reader"
|
|
51
|
+
require_relative "claude_memory/infrastructure/file_system"
|
|
52
|
+
require_relative "claude_memory/infrastructure/in_memory_file_system"
|
|
53
|
+
require_relative "claude_memory/mcp/server"
|
|
54
|
+
require_relative "claude_memory/mcp/tools"
|
|
55
|
+
require_relative "claude_memory/publish"
|
|
56
|
+
require_relative "claude_memory/recall"
|
|
57
|
+
require_relative "claude_memory/shortcuts"
|
|
58
|
+
require_relative "claude_memory/resolve/predicate_policy"
|
|
59
|
+
require_relative "claude_memory/resolve/resolver"
|
|
60
|
+
require_relative "claude_memory/store/sqlite_store"
|
|
61
|
+
require_relative "claude_memory/store/store_manager"
|
|
62
|
+
require_relative "claude_memory/sweep/sweeper"
|
|
63
|
+
require_relative "claude_memory/version"
|
|
8
64
|
|
|
65
|
+
module ClaudeMemory
|
|
9
66
|
def self.global_db_path(env = ENV)
|
|
10
67
|
home = env["HOME"] || File.expand_path("~")
|
|
11
68
|
File.join(home, ".claude", "memory.sqlite3")
|
|
@@ -15,22 +72,3 @@ module ClaudeMemory
|
|
|
15
72
|
File.join(project_path, ".claude", "memory.sqlite3")
|
|
16
73
|
end
|
|
17
74
|
end
|
|
18
|
-
|
|
19
|
-
require_relative "claude_memory/version"
|
|
20
|
-
require_relative "claude_memory/cli"
|
|
21
|
-
require_relative "claude_memory/store/sqlite_store"
|
|
22
|
-
require_relative "claude_memory/store/store_manager"
|
|
23
|
-
require_relative "claude_memory/ingest/transcript_reader"
|
|
24
|
-
require_relative "claude_memory/ingest/ingester"
|
|
25
|
-
require_relative "claude_memory/index/lexical_fts"
|
|
26
|
-
require_relative "claude_memory/distill/extraction"
|
|
27
|
-
require_relative "claude_memory/distill/distiller"
|
|
28
|
-
require_relative "claude_memory/distill/null_distiller"
|
|
29
|
-
require_relative "claude_memory/resolve/predicate_policy"
|
|
30
|
-
require_relative "claude_memory/resolve/resolver"
|
|
31
|
-
require_relative "claude_memory/recall"
|
|
32
|
-
require_relative "claude_memory/sweep/sweeper"
|
|
33
|
-
require_relative "claude_memory/mcp/tools"
|
|
34
|
-
require_relative "claude_memory/mcp/server"
|
|
35
|
-
require_relative "claude_memory/publish"
|
|
36
|
-
require_relative "claude_memory/hook/handler"
|