claude_memory 0.7.1 → 0.9.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/memory.sqlite3 +0 -0
- data/.claude/rules/claude_memory.generated.md +32 -2
- data/.claude/settings.json +65 -15
- data/.claude/settings.local.json +5 -2
- data/.claude/skills/improve/SKILL.md +113 -25
- data/.claude/skills/upgrade-dependencies/SKILL.md +154 -0
- data/.claude-plugin/commands/distill-transcripts.md +98 -0
- data/.claude-plugin/commands/memory-recall.md +67 -0
- data/.claude-plugin/marketplace.json +2 -2
- data/.claude-plugin/plugin.json +3 -3
- data/.claude-plugin/scripts/hook-runner.sh +14 -0
- data/.claude-plugin/scripts/serve-mcp.sh +14 -0
- data/.ruby-version +1 -1
- data/CHANGELOG.md +90 -1
- data/CLAUDE.md +56 -18
- data/README.md +35 -0
- data/db/migrations/013_add_mcp_tool_calls.rb +26 -0
- data/db/migrations/014_canonicalize_predicates.rb +30 -0
- data/docs/improvements.md +74 -74
- data/docs/influence/claude-mem.md +1 -0
- data/docs/influence/claude-supermemory.md +1 -0
- data/docs/influence/episodic-memory.md +1 -0
- data/docs/influence/grepai.md +1 -0
- data/docs/influence/kbs.md +1 -0
- data/docs/influence/lossless-claw.md +1 -0
- data/docs/influence/qmd.md +1 -0
- data/docs/quality_review.md +119 -224
- data/hooks/hooks.json +39 -7
- data/lib/claude_memory/commands/checks/distill_check.rb +61 -0
- data/lib/claude_memory/commands/checks/hooks_check.rb +2 -2
- data/lib/claude_memory/commands/checks/vec_check.rb +2 -1
- data/lib/claude_memory/commands/completion_command.rb +149 -0
- data/lib/claude_memory/commands/doctor_command.rb +2 -0
- data/lib/claude_memory/commands/embeddings_command.rb +198 -0
- data/lib/claude_memory/commands/help_command.rb +12 -1
- data/lib/claude_memory/commands/hook_command.rb +2 -1
- data/lib/claude_memory/commands/index_command.rb +85 -78
- data/lib/claude_memory/commands/initializers/database_ensurer.rb +16 -0
- data/lib/claude_memory/commands/initializers/global_initializer.rb +2 -1
- data/lib/claude_memory/commands/initializers/hooks_configurator.rb +55 -11
- data/lib/claude_memory/commands/initializers/project_initializer.rb +2 -1
- data/lib/claude_memory/commands/install_skill_command.rb +78 -0
- data/lib/claude_memory/commands/registry.rb +47 -32
- data/lib/claude_memory/commands/reject_command.rb +62 -0
- data/lib/claude_memory/commands/restore_command.rb +77 -0
- data/lib/claude_memory/commands/skills/distill-transcripts.md +102 -0
- data/lib/claude_memory/commands/skills/memory-recall.md +67 -0
- data/lib/claude_memory/commands/stats_command.rb +98 -2
- data/lib/claude_memory/configuration.rb +14 -1
- data/lib/claude_memory/core/fact_ranker.rb +2 -2
- data/lib/claude_memory/core/rr_fusion.rb +23 -6
- data/lib/claude_memory/core/snippet_extractor.rb +7 -3
- data/lib/claude_memory/core/text_builder.rb +11 -0
- data/lib/claude_memory/distill/json_schema.md +8 -4
- data/lib/claude_memory/distill/null_distiller.rb +2 -0
- data/lib/claude_memory/domain/entity.rb +13 -1
- data/lib/claude_memory/domain/fact.rb +26 -2
- data/lib/claude_memory/domain/provenance.rb +0 -1
- data/lib/claude_memory/embeddings/api_adapter.rb +97 -0
- data/lib/claude_memory/embeddings/dimension_check.rb +23 -0
- data/lib/claude_memory/embeddings/fastembed_adapter.rb +46 -12
- data/lib/claude_memory/embeddings/generator.rb +4 -0
- data/lib/claude_memory/embeddings/inspector.rb +91 -0
- data/lib/claude_memory/embeddings/model_registry.rb +210 -0
- data/lib/claude_memory/embeddings/resolver.rb +44 -0
- data/lib/claude_memory/hook/context_injector.rb +58 -2
- data/lib/claude_memory/hook/distillation_runner.rb +46 -0
- data/lib/claude_memory/hook/handler.rb +11 -2
- data/lib/claude_memory/index/vector_index.rb +15 -2
- data/lib/claude_memory/infrastructure/schema_validator.rb +3 -3
- data/lib/claude_memory/ingest/ingester.rb +17 -0
- data/lib/claude_memory/mcp/handlers/context_handlers.rb +38 -0
- data/lib/claude_memory/mcp/handlers/management_handlers.rb +169 -0
- data/lib/claude_memory/mcp/handlers/query_handlers.rb +115 -0
- data/lib/claude_memory/mcp/handlers/setup_handlers.rb +211 -0
- data/lib/claude_memory/mcp/handlers/shortcut_handlers.rb +37 -0
- data/lib/claude_memory/mcp/handlers/stats_handlers.rb +205 -0
- data/lib/claude_memory/mcp/instructions_builder.rb +19 -1
- data/lib/claude_memory/mcp/query_guide.rb +10 -0
- data/lib/claude_memory/mcp/response_formatter.rb +1 -0
- data/lib/claude_memory/mcp/server.rb +22 -1
- data/lib/claude_memory/mcp/telemetry.rb +86 -0
- data/lib/claude_memory/mcp/text_summary.rb +26 -0
- data/lib/claude_memory/mcp/tool_definitions.rb +116 -4
- data/lib/claude_memory/mcp/tool_helpers.rb +43 -0
- data/lib/claude_memory/mcp/tools.rb +50 -679
- data/lib/claude_memory/publish.rb +40 -5
- data/lib/claude_memory/recall/dual_engine.rb +105 -0
- data/lib/claude_memory/recall/legacy_engine.rb +138 -0
- data/lib/claude_memory/recall/query_core.rb +371 -0
- data/lib/claude_memory/recall.rb +121 -673
- data/lib/claude_memory/resolve/predicate_policy.rb +63 -3
- data/lib/claude_memory/resolve/resolver.rb +43 -0
- data/lib/claude_memory/shortcuts.rb +4 -4
- data/lib/claude_memory/store/retry_handler.rb +61 -0
- data/lib/claude_memory/store/schema_manager.rb +68 -0
- data/lib/claude_memory/store/sqlite_store.rb +334 -201
- data/lib/claude_memory/store/store_manager.rb +50 -1
- data/lib/claude_memory/sweep/maintenance.rb +115 -1
- data/lib/claude_memory/sweep/sweeper.rb +3 -0
- data/lib/claude_memory/templates/hooks.example.json +26 -7
- data/lib/claude_memory/version.rb +1 -1
- data/lib/claude_memory.rb +16 -0
- metadata +48 -8
- data/.claude/memory.sqlite3-shm +0 -0
- data/.claude/memory.sqlite3-wal +0 -0
|
@@ -4,15 +4,22 @@ require "digest"
|
|
|
4
4
|
require "fileutils"
|
|
5
5
|
|
|
6
6
|
module ClaudeMemory
|
|
7
|
+
# Generates Markdown snapshots from active facts for use as project memory.
|
|
8
|
+
# Publishes to .claude/rules/ (shared), a local file, or the home directory.
|
|
7
9
|
class Publish
|
|
8
10
|
RULES_DIR = ".claude/rules"
|
|
9
11
|
GENERATED_FILE = "claude_memory.generated.md"
|
|
10
12
|
|
|
13
|
+
# @param store [Store::SQLiteStore] database store for reading facts
|
|
14
|
+
# @param file_system [Infrastructure::FileSystem] filesystem abstraction for I/O
|
|
11
15
|
def initialize(store, file_system: Infrastructure::FileSystem.new)
|
|
12
16
|
@store = store
|
|
13
17
|
@fs = file_system
|
|
14
18
|
end
|
|
15
19
|
|
|
20
|
+
# Generate a complete Markdown snapshot with header and body
|
|
21
|
+
# @param since [String, nil] ISO 8601 timestamp to include recent supersessions
|
|
22
|
+
# @return [String] full Markdown document
|
|
16
23
|
def generate_snapshot(since: nil)
|
|
17
24
|
header = <<~HEADER
|
|
18
25
|
<!--
|
|
@@ -28,6 +35,12 @@ module ClaudeMemory
|
|
|
28
35
|
header + generate_body(since: since)
|
|
29
36
|
end
|
|
30
37
|
|
|
38
|
+
# Write snapshot to disk if content has changed
|
|
39
|
+
# @param mode [Symbol] output target (:shared, :local, or :home)
|
|
40
|
+
# @param granularity [Symbol] snapshot granularity (currently only :repo)
|
|
41
|
+
# @param since [String, nil] ISO 8601 timestamp for recent supersessions
|
|
42
|
+
# @param rules_dir [String, nil] override rules directory path
|
|
43
|
+
# @return [Hash] result with :status (:updated or :unchanged) and :path
|
|
31
44
|
def publish!(mode: :shared, granularity: :repo, since: nil, rules_dir: nil)
|
|
32
45
|
path = output_path(mode, rules_dir: rules_dir)
|
|
33
46
|
body = generate_body(since: since)
|
|
@@ -97,8 +110,9 @@ module ClaudeMemory
|
|
|
97
110
|
.all
|
|
98
111
|
end
|
|
99
112
|
|
|
113
|
+
# @return [String] Markdown section for decision facts
|
|
100
114
|
def generate_decisions_section(facts)
|
|
101
|
-
decisions = facts.select { |f| f[:predicate] ==
|
|
115
|
+
decisions = facts.select { |f| Resolve::PredicatePolicy.section_for(f[:predicate]) == :decisions }
|
|
102
116
|
return "" if decisions.empty?
|
|
103
117
|
|
|
104
118
|
lines = ["## Current Decisions\n"]
|
|
@@ -108,8 +122,9 @@ module ClaudeMemory
|
|
|
108
122
|
lines.join("\n") + "\n"
|
|
109
123
|
end
|
|
110
124
|
|
|
125
|
+
# @return [String] Markdown section for convention facts
|
|
111
126
|
def generate_conventions_section(facts)
|
|
112
|
-
conventions = facts.select { |f| f[:predicate] ==
|
|
127
|
+
conventions = facts.select { |f| Resolve::PredicatePolicy.section_for(f[:predicate]) == :conventions }
|
|
113
128
|
return "" if conventions.empty?
|
|
114
129
|
|
|
115
130
|
lines = ["## Conventions\n"]
|
|
@@ -119,10 +134,9 @@ module ClaudeMemory
|
|
|
119
134
|
lines.join("\n") + "\n"
|
|
120
135
|
end
|
|
121
136
|
|
|
137
|
+
# @return [String] Markdown section for technical constraint facts
|
|
122
138
|
def generate_constraints_section(facts)
|
|
123
|
-
constraints = facts.select
|
|
124
|
-
%w[uses_database uses_framework deployment_platform auth_method].include?(f[:predicate])
|
|
125
|
-
end
|
|
139
|
+
constraints = facts.select { |f| Resolve::PredicatePolicy.section_for(f[:predicate]) == :constraints }
|
|
126
140
|
return "" if constraints.empty?
|
|
127
141
|
|
|
128
142
|
lines = ["## Technical Constraints\n"]
|
|
@@ -132,6 +146,25 @@ module ClaudeMemory
|
|
|
132
146
|
lines.join("\n") + "\n"
|
|
133
147
|
end
|
|
134
148
|
|
|
149
|
+
# @return [String] Markdown section for additional knowledge grouped by predicate
|
|
150
|
+
def generate_additional_section(facts)
|
|
151
|
+
additional = facts.select { |f| Resolve::PredicatePolicy.section_for(f[:predicate]) == :additional }
|
|
152
|
+
return "" if additional.empty?
|
|
153
|
+
|
|
154
|
+
grouped = additional.group_by { |f| f[:predicate] }
|
|
155
|
+
lines = ["## Additional Knowledge\n"]
|
|
156
|
+
grouped.each do |predicate, group_facts|
|
|
157
|
+
lines << "### #{humanize(predicate)}\n"
|
|
158
|
+
group_facts.each do |f|
|
|
159
|
+
subject = f[:subject_name] || "repo"
|
|
160
|
+
lines << "- #{subject}: #{f[:object_literal]}"
|
|
161
|
+
end
|
|
162
|
+
lines << ""
|
|
163
|
+
end
|
|
164
|
+
lines.join("\n") + "\n"
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
# @return [String] Markdown section for open conflicts
|
|
135
168
|
def generate_conflicts_section(conflicts)
|
|
136
169
|
return "" if conflicts.empty?
|
|
137
170
|
|
|
@@ -143,6 +176,7 @@ module ClaudeMemory
|
|
|
143
176
|
lines.join("\n") + "\n"
|
|
144
177
|
end
|
|
145
178
|
|
|
179
|
+
# @return [String] Markdown section for recently superseded facts
|
|
146
180
|
def generate_supersessions_section(supersessions)
|
|
147
181
|
return "" if supersessions.empty?
|
|
148
182
|
|
|
@@ -162,6 +196,7 @@ module ClaudeMemory
|
|
|
162
196
|
sections << generate_decisions_section(facts)
|
|
163
197
|
sections << generate_conventions_section(facts)
|
|
164
198
|
sections << generate_constraints_section(facts)
|
|
199
|
+
sections << generate_additional_section(facts)
|
|
165
200
|
sections << generate_conflicts_section(conflicts) if conflicts.any?
|
|
166
201
|
sections << generate_supersessions_section(recent_supersessions) if recent_supersessions.any?
|
|
167
202
|
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ClaudeMemory
|
|
4
|
+
class Recall
|
|
5
|
+
# Query engine for dual-database mode (StoreManager with global + project DBs).
|
|
6
|
+
# Wraps DualQueryTemplate around shared QueryCore methods.
|
|
7
|
+
class DualEngine
|
|
8
|
+
include QueryCore
|
|
9
|
+
|
|
10
|
+
def initialize(manager, embedding_generator:, project_path:)
|
|
11
|
+
@manager = manager
|
|
12
|
+
@embedding_generator = embedding_generator
|
|
13
|
+
@project_path = project_path
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def query(query_text, limit:, scope:, include_raw_text: false, intent: nil)
|
|
17
|
+
effective_query = intent_augmented_query(query_text, intent)
|
|
18
|
+
results = dual_execute(scope: scope, limit: limit) do |store, source|
|
|
19
|
+
query_single_store(store, effective_query, limit: limit, source: source, include_raw_text: include_raw_text)
|
|
20
|
+
end
|
|
21
|
+
dedupe_and_sort(results, limit)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def query_index(query_text, limit:, scope:, intent: nil)
|
|
25
|
+
effective_query = intent_augmented_query(query_text, intent)
|
|
26
|
+
results = dual_execute(scope: scope, limit: limit) do |store, source|
|
|
27
|
+
query_index_single_store(store, effective_query, limit: limit, source: source)
|
|
28
|
+
end
|
|
29
|
+
dedupe_and_sort_index(results, limit)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def fact_graph(fact_id, depth:, scope:)
|
|
33
|
+
scope ||= SCOPE_PROJECT
|
|
34
|
+
store = @manager.store_for_scope(scope)
|
|
35
|
+
Core::FactGraph.build(store, fact_id, depth: depth)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def explain(fact_id_or_docid, scope:)
|
|
39
|
+
scope ||= SCOPE_PROJECT
|
|
40
|
+
store = @manager.store_for_scope(scope)
|
|
41
|
+
fact_id = resolve_fact_identifier(store, fact_id_or_docid)
|
|
42
|
+
explain_from_store(store, fact_id)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def changes(since:, limit:, scope:)
|
|
46
|
+
results = dual_execute(scope: scope, limit: limit) do |store, source|
|
|
47
|
+
changes = fetch_changes(store, since, limit)
|
|
48
|
+
Core::ResultSorter.annotate_source(changes, source)
|
|
49
|
+
end
|
|
50
|
+
Core::ResultSorter.sort_by_timestamp(results, limit)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def conflicts(scope:)
|
|
54
|
+
dual_execute(scope: scope) do |store, source|
|
|
55
|
+
conflicts = store.open_conflicts
|
|
56
|
+
Core::ResultSorter.annotate_source(conflicts, source)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def facts_by_branch(branch_name, limit:, scope:)
|
|
61
|
+
results = dual_execute(scope: scope, limit: limit) do |store, source|
|
|
62
|
+
facts_by_context_single(store, :git_branch, branch_name, limit: limit, source: source)
|
|
63
|
+
end
|
|
64
|
+
dedupe_and_sort(results, limit)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def facts_by_directory(cwd, limit:, scope:)
|
|
68
|
+
results = dual_execute(scope: scope, limit: limit) do |store, source|
|
|
69
|
+
facts_by_context_single(store, :cwd, cwd, limit: limit, source: source)
|
|
70
|
+
end
|
|
71
|
+
dedupe_and_sort(results, limit)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def facts_by_tool(tool_name, limit:, scope:)
|
|
75
|
+
results = dual_execute(scope: scope, limit: limit) do |store, source|
|
|
76
|
+
facts_by_tool_single(store, tool_name, limit: limit, source: source)
|
|
77
|
+
end
|
|
78
|
+
dedupe_and_sort(results, limit)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def query_semantic(text, limit:, scope:, mode:, explain: false, intent: nil)
|
|
82
|
+
effective_text = intent_augmented_query(text, intent)
|
|
83
|
+
results = dual_execute(scope: scope, limit: limit) do |store, source|
|
|
84
|
+
query_semantic_single(store, effective_text, limit: limit * 3, mode: mode, source: source, explain: explain,
|
|
85
|
+
skip_fts_shortcut: !intent.nil?)
|
|
86
|
+
end
|
|
87
|
+
dedupe_by_fact_id(results, limit)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def query_concepts(concepts, limit:, scope:)
|
|
91
|
+
results = dual_execute(scope: scope, limit: limit) do |store, source|
|
|
92
|
+
query_concepts_single(store, concepts, limit: limit * 2, source: source)
|
|
93
|
+
end
|
|
94
|
+
dedupe_by_fact_id(results, limit)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
private
|
|
98
|
+
|
|
99
|
+
def dual_execute(scope:, limit: nil, &operation)
|
|
100
|
+
template = DualQueryTemplate.new(@manager)
|
|
101
|
+
template.execute(scope: scope, limit: limit, &operation)
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ClaudeMemory
|
|
4
|
+
class Recall
|
|
5
|
+
# Query engine for legacy single-store mode.
|
|
6
|
+
# Operates directly on one SQLiteStore with local scope filtering.
|
|
7
|
+
class LegacyEngine
|
|
8
|
+
include QueryCore
|
|
9
|
+
|
|
10
|
+
def initialize(store, fts:, embedding_generator:, project_path:)
|
|
11
|
+
@store = store
|
|
12
|
+
@fts = fts
|
|
13
|
+
@embedding_generator = embedding_generator
|
|
14
|
+
@project_path = project_path
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def query(query_text, limit:, scope:, include_raw_text: false, intent: nil)
|
|
18
|
+
effective_query = intent_augmented_query(query_text, intent)
|
|
19
|
+
content_ids = @fts.search(effective_query, limit: limit * 3)
|
|
20
|
+
return [] if content_ids.empty?
|
|
21
|
+
|
|
22
|
+
provenance_by_content = @store.provenance
|
|
23
|
+
.select(:fact_id, :content_item_id)
|
|
24
|
+
.where(content_item_id: content_ids)
|
|
25
|
+
.all
|
|
26
|
+
.group_by { |p| p[:content_item_id] }
|
|
27
|
+
|
|
28
|
+
all_fact_ids = []
|
|
29
|
+
seen_fact_ids = Set.new
|
|
30
|
+
content_ids.each do |content_id|
|
|
31
|
+
(provenance_by_content[content_id] || []).each do |prov|
|
|
32
|
+
next if seen_fact_ids.include?(prov[:fact_id])
|
|
33
|
+
seen_fact_ids.add(prov[:fact_id])
|
|
34
|
+
all_fact_ids << prov[:fact_id]
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
return [] if all_fact_ids.empty?
|
|
39
|
+
|
|
40
|
+
facts_by_id = batch_find_facts(@store, all_fact_ids)
|
|
41
|
+
|
|
42
|
+
selected_fact_ids = []
|
|
43
|
+
all_fact_ids.each do |fact_id|
|
|
44
|
+
fact = facts_by_id[fact_id]
|
|
45
|
+
next unless fact
|
|
46
|
+
next unless fact_matches_scope?(fact, scope)
|
|
47
|
+
selected_fact_ids << fact_id
|
|
48
|
+
break if selected_fact_ids.size >= limit
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
return [] if selected_fact_ids.empty?
|
|
52
|
+
|
|
53
|
+
receipts_by_fact_id = batch_find_receipts(@store, selected_fact_ids)
|
|
54
|
+
|
|
55
|
+
facts_with_provenance = selected_fact_ids.map do |fact_id|
|
|
56
|
+
{
|
|
57
|
+
fact: facts_by_id[fact_id],
|
|
58
|
+
receipts: receipts_by_fact_id[fact_id] || []
|
|
59
|
+
}
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
sort_by_scope_priority(facts_with_provenance)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def query_index(query_text, limit:, scope:, intent: nil)
|
|
66
|
+
effective_query = intent_augmented_query(query_text, intent)
|
|
67
|
+
options = Index::QueryOptions.new(
|
|
68
|
+
query_text: effective_query,
|
|
69
|
+
limit: limit,
|
|
70
|
+
scope: :all,
|
|
71
|
+
source: :legacy
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
query = Index::IndexQuery.new(@store, options)
|
|
75
|
+
results = query.execute
|
|
76
|
+
|
|
77
|
+
results.select do |result|
|
|
78
|
+
fact = Core::FactQueryBuilder.find_fact(@store, result[:id])
|
|
79
|
+
fact && fact_matches_scope?(fact, scope)
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def fact_graph(fact_id, depth:, scope:)
|
|
84
|
+
Core::FactGraph.build(@store, fact_id, depth: depth)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def explain(fact_id_or_docid, scope:)
|
|
88
|
+
fact_id = resolve_fact_identifier(@store, fact_id_or_docid)
|
|
89
|
+
explain_from_store(@store, fact_id)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def changes(since:, limit:, scope:)
|
|
93
|
+
ds = @store.facts
|
|
94
|
+
.select(:id, :docid, :subject_entity_id, :predicate, :object_literal, :status, :created_at, :scope, :project_path)
|
|
95
|
+
.where { created_at >= since }
|
|
96
|
+
.order(Sequel.desc(:created_at))
|
|
97
|
+
.limit(limit)
|
|
98
|
+
|
|
99
|
+
ds = apply_scope_filter(ds, scope)
|
|
100
|
+
ds.all
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def conflicts(scope:)
|
|
104
|
+
all_conflicts = @store.open_conflicts
|
|
105
|
+
return all_conflicts if scope == SCOPE_ALL
|
|
106
|
+
|
|
107
|
+
all_conflicts.select do |conflict|
|
|
108
|
+
fact_a = Core::FactQueryBuilder.find_fact(@store, conflict[:fact_a_id])
|
|
109
|
+
fact_b = Core::FactQueryBuilder.find_fact(@store, conflict[:fact_b_id])
|
|
110
|
+
|
|
111
|
+
fact_matches_scope?(fact_a, scope) || fact_matches_scope?(fact_b, scope)
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def facts_by_branch(branch_name, limit:, scope:)
|
|
116
|
+
facts_by_context_single(@store, :git_branch, branch_name, limit: limit, source: :legacy)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def facts_by_directory(cwd, limit:, scope:)
|
|
120
|
+
facts_by_context_single(@store, :cwd, cwd, limit: limit, source: :legacy)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def facts_by_tool(tool_name, limit:, scope:)
|
|
124
|
+
facts_by_tool_single(@store, tool_name, limit: limit, source: :legacy)
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def query_semantic(text, limit:, scope:, mode:, explain: false, intent: nil)
|
|
128
|
+
effective_text = intent_augmented_query(text, intent)
|
|
129
|
+
query_semantic_single(@store, effective_text, limit: limit, mode: mode, source: :legacy, explain: explain,
|
|
130
|
+
skip_fts_shortcut: !intent.nil?)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def query_concepts(concepts, limit:, scope:)
|
|
134
|
+
query_concepts_single(@store, concepts, limit: limit, source: :legacy)
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|