claude_memory 0.2.0 → 0.3.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.o2N83S +0 -0
- data/.claude/CLAUDE.md +1 -0
- data/.claude/rules/claude_memory.generated.md +28 -9
- data/.claude/settings.local.json +9 -1
- data/.claude/skills/check-memory/SKILL.md +77 -0
- data/.claude/skills/improve/SKILL.md +532 -0
- data/.claude/skills/improve/feature-patterns.md +1221 -0
- data/.claude/skills/quality-update/SKILL.md +229 -0
- data/.claude/skills/quality-update/implementation-guide.md +346 -0
- data/.claude/skills/review-commit/SKILL.md +199 -0
- data/.claude/skills/review-for-quality/SKILL.md +154 -0
- data/.claude/skills/review-for-quality/expert-checklists.md +79 -0
- data/.claude/skills/setup-memory/SKILL.md +168 -0
- data/.claude/skills/study-repo/SKILL.md +307 -0
- data/.claude/skills/study-repo/analysis-template.md +323 -0
- data/.claude/skills/study-repo/focus-examples.md +327 -0
- data/CHANGELOG.md +133 -0
- data/CLAUDE.md +130 -11
- data/README.md +117 -10
- data/db/migrations/001_create_initial_schema.rb +117 -0
- data/db/migrations/002_add_project_scoping.rb +33 -0
- data/db/migrations/003_add_session_metadata.rb +42 -0
- data/db/migrations/004_add_fact_embeddings.rb +20 -0
- data/db/migrations/005_add_incremental_sync.rb +21 -0
- data/db/migrations/006_add_operation_tracking.rb +40 -0
- data/db/migrations/007_add_ingestion_metrics.rb +26 -0
- data/docs/.claude/mind.mv2.lock +0 -0
- data/docs/GETTING_STARTED.md +587 -0
- data/docs/RELEASE_NOTES_v0.2.0.md +0 -1
- data/docs/RUBY_COMMUNITY_POST_v0.2.0.md +0 -2
- data/docs/architecture.md +9 -8
- data/docs/auto_init_design.md +230 -0
- data/docs/improvements.md +557 -731
- data/docs/influence/.gitkeep +13 -0
- data/docs/influence/grepai.md +933 -0
- data/docs/influence/qmd.md +2195 -0
- data/docs/plugin.md +257 -11
- data/docs/quality_review.md +472 -1273
- data/docs/remaining_improvements.md +330 -0
- data/lefthook.yml +13 -0
- data/lib/claude_memory/commands/checks/claude_md_check.rb +41 -0
- data/lib/claude_memory/commands/checks/database_check.rb +120 -0
- data/lib/claude_memory/commands/checks/hooks_check.rb +112 -0
- data/lib/claude_memory/commands/checks/reporter.rb +110 -0
- data/lib/claude_memory/commands/checks/snapshot_check.rb +30 -0
- data/lib/claude_memory/commands/doctor_command.rb +12 -129
- data/lib/claude_memory/commands/help_command.rb +1 -0
- data/lib/claude_memory/commands/hook_command.rb +9 -2
- data/lib/claude_memory/commands/index_command.rb +169 -0
- data/lib/claude_memory/commands/ingest_command.rb +1 -1
- data/lib/claude_memory/commands/init_command.rb +5 -197
- data/lib/claude_memory/commands/initializers/database_ensurer.rb +30 -0
- data/lib/claude_memory/commands/initializers/global_initializer.rb +85 -0
- data/lib/claude_memory/commands/initializers/hooks_configurator.rb +156 -0
- data/lib/claude_memory/commands/initializers/mcp_configurator.rb +56 -0
- data/lib/claude_memory/commands/initializers/memory_instructions_writer.rb +135 -0
- data/lib/claude_memory/commands/initializers/project_initializer.rb +111 -0
- data/lib/claude_memory/commands/recover_command.rb +75 -0
- data/lib/claude_memory/commands/registry.rb +5 -1
- data/lib/claude_memory/commands/stats_command.rb +239 -0
- data/lib/claude_memory/commands/uninstall_command.rb +226 -0
- data/lib/claude_memory/core/batch_loader.rb +32 -0
- data/lib/claude_memory/core/concept_ranker.rb +73 -0
- data/lib/claude_memory/core/embedding_candidate_builder.rb +37 -0
- data/lib/claude_memory/core/fact_collector.rb +51 -0
- data/lib/claude_memory/core/fact_query_builder.rb +154 -0
- data/lib/claude_memory/core/fact_ranker.rb +113 -0
- data/lib/claude_memory/core/result_builder.rb +54 -0
- data/lib/claude_memory/core/result_sorter.rb +25 -0
- data/lib/claude_memory/core/scope_filter.rb +61 -0
- data/lib/claude_memory/core/text_builder.rb +29 -0
- data/lib/claude_memory/embeddings/generator.rb +161 -0
- data/lib/claude_memory/embeddings/similarity.rb +69 -0
- data/lib/claude_memory/hook/handler.rb +4 -3
- data/lib/claude_memory/index/lexical_fts.rb +7 -2
- data/lib/claude_memory/infrastructure/operation_tracker.rb +158 -0
- data/lib/claude_memory/infrastructure/schema_validator.rb +206 -0
- data/lib/claude_memory/ingest/content_sanitizer.rb +6 -7
- data/lib/claude_memory/ingest/ingester.rb +99 -15
- data/lib/claude_memory/ingest/metadata_extractor.rb +57 -0
- data/lib/claude_memory/ingest/tool_extractor.rb +71 -0
- data/lib/claude_memory/mcp/response_formatter.rb +331 -0
- data/lib/claude_memory/mcp/server.rb +19 -0
- data/lib/claude_memory/mcp/setup_status_analyzer.rb +73 -0
- data/lib/claude_memory/mcp/tool_definitions.rb +279 -0
- data/lib/claude_memory/mcp/tool_helpers.rb +80 -0
- data/lib/claude_memory/mcp/tools.rb +330 -320
- data/lib/claude_memory/recall/dual_query_template.rb +63 -0
- data/lib/claude_memory/recall.rb +304 -237
- data/lib/claude_memory/resolve/resolver.rb +52 -49
- data/lib/claude_memory/store/sqlite_store.rb +210 -144
- data/lib/claude_memory/store/store_manager.rb +6 -6
- data/lib/claude_memory/sweep/sweeper.rb +6 -0
- data/lib/claude_memory/version.rb +1 -1
- data/lib/claude_memory.rb +35 -3
- metadata +71 -11
- data/.claude/.mind.mv2.aLCUZd +0 -0
- data/.claude/memory.sqlite3 +0 -0
- data/.mcp.json +0 -11
- /data/docs/{feature_adoption_plan.md → plans/feature_adoption_plan.md} +0 -0
- /data/docs/{feature_adoption_plan_revised.md → plans/feature_adoption_plan_revised.md} +0 -0
- /data/docs/{plan.md → plans/plan.md} +0 -0
- /data/docs/{updated_plan.md → plans/updated_plan.md} +0 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ClaudeMemory
|
|
4
|
+
module MCP
|
|
5
|
+
# Pure logic for analyzing setup status and generating recommendations
|
|
6
|
+
# Follows Functional Core pattern - no I/O, just decision logic
|
|
7
|
+
class SetupStatusAnalyzer
|
|
8
|
+
# Determine overall setup status based on component states
|
|
9
|
+
# @param global_db_exists [Boolean] Global database exists
|
|
10
|
+
# @param claude_md_exists [Boolean] CLAUDE.md file exists
|
|
11
|
+
# @param version_status [String, nil] Version status (up_to_date, outdated, etc.)
|
|
12
|
+
# @return [String] Overall status (healthy, needs_upgrade, partially_initialized, not_initialized)
|
|
13
|
+
def self.determine_status(global_db_exists, claude_md_exists, version_status)
|
|
14
|
+
initialized = global_db_exists && claude_md_exists
|
|
15
|
+
|
|
16
|
+
if initialized && version_status == "up_to_date"
|
|
17
|
+
"healthy"
|
|
18
|
+
elsif initialized && version_status == "outdated"
|
|
19
|
+
"needs_upgrade"
|
|
20
|
+
elsif global_db_exists && !claude_md_exists
|
|
21
|
+
"partially_initialized"
|
|
22
|
+
else
|
|
23
|
+
"not_initialized"
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Generate recommendations based on setup status
|
|
28
|
+
# @param initialized [Boolean] Whether system is initialized
|
|
29
|
+
# @param version_status [String, nil] Version status
|
|
30
|
+
# @param has_warnings [Boolean] Whether there are warnings
|
|
31
|
+
# @return [Array<String>] List of recommendations
|
|
32
|
+
def self.generate_recommendations(initialized, version_status, has_warnings)
|
|
33
|
+
recommendations = []
|
|
34
|
+
|
|
35
|
+
if !initialized
|
|
36
|
+
recommendations << "Run: claude-memory init"
|
|
37
|
+
recommendations << "This will create databases, configure hooks, and set up CLAUDE.md"
|
|
38
|
+
elsif version_status == "outdated"
|
|
39
|
+
recommendations << "Run: claude-memory upgrade (when available)"
|
|
40
|
+
recommendations << "Or manually run: claude-memory init to update CLAUDE.md"
|
|
41
|
+
elsif has_warnings
|
|
42
|
+
recommendations << "Run: claude-memory doctor --fix (when available)"
|
|
43
|
+
recommendations << "Or check individual issues and fix manually"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
recommendations
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Extract version from CLAUDE.md content
|
|
50
|
+
# @param content [String] CLAUDE.md file content
|
|
51
|
+
# @return [String, nil] Extracted version or nil
|
|
52
|
+
def self.extract_version(content)
|
|
53
|
+
if content =~ /<!-- ClaudeMemory v([\d.]+) -->/
|
|
54
|
+
$1
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Determine version status by comparing current and latest
|
|
59
|
+
# @param current_version [String, nil] Version from config
|
|
60
|
+
# @param latest_version [String] Latest version
|
|
61
|
+
# @return [String] Version status (up_to_date, outdated, no_version_marker, unknown)
|
|
62
|
+
def self.determine_version_status(current_version, latest_version)
|
|
63
|
+
return "unknown" unless current_version
|
|
64
|
+
|
|
65
|
+
if current_version == latest_version
|
|
66
|
+
"up_to_date"
|
|
67
|
+
else
|
|
68
|
+
"outdated"
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ClaudeMemory
|
|
4
|
+
module MCP
|
|
5
|
+
# MCP tool definitions for Claude Memory
|
|
6
|
+
# Pure data structure - no logic, just tool schemas
|
|
7
|
+
module ToolDefinitions
|
|
8
|
+
# Returns array of tool definitions for MCP protocol
|
|
9
|
+
# @return [Array<Hash>] Tool definitions with name, description, and inputSchema
|
|
10
|
+
def self.all
|
|
11
|
+
[
|
|
12
|
+
{
|
|
13
|
+
name: "memory.recall",
|
|
14
|
+
description: "IMPORTANT: Check memory FIRST before reading files or exploring code. Recalls facts matching a query from distilled knowledge in both global and project databases. Use this to find existing knowledge about modules, patterns, decisions, and conventions before resorting to file reads or code searches.",
|
|
15
|
+
inputSchema: {
|
|
16
|
+
type: "object",
|
|
17
|
+
properties: {
|
|
18
|
+
query: {type: "string", description: "Search query for existing knowledge (e.g., 'authentication flow', 'error handling', 'database setup')"},
|
|
19
|
+
limit: {type: "integer", description: "Max results", default: 10},
|
|
20
|
+
scope: {type: "string", enum: ["all", "global", "project"], description: "Filter by scope: 'all' (default), 'global', or 'project'", default: "all"}
|
|
21
|
+
},
|
|
22
|
+
required: ["query"]
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
name: "memory.recall_index",
|
|
27
|
+
description: "Layer 1: CHECK MEMORY FIRST with this lightweight search. Returns fact previews, IDs, and token costs without full details. Use before exploring code to see what knowledge already exists. Follow up with memory.recall_details for specific facts.",
|
|
28
|
+
inputSchema: {
|
|
29
|
+
type: "object",
|
|
30
|
+
properties: {
|
|
31
|
+
query: {type: "string", description: "Search query for existing knowledge (e.g., 'client errors', 'database choice')"},
|
|
32
|
+
limit: {type: "integer", description: "Maximum results to return", default: 20},
|
|
33
|
+
scope: {type: "string", enum: ["all", "global", "project"], description: "Scope: 'all' (both), 'global' (user-wide), 'project' (current only)", default: "all"}
|
|
34
|
+
},
|
|
35
|
+
required: ["query"]
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
name: "memory.recall_details",
|
|
40
|
+
description: "Layer 2: Fetch full details for specific fact IDs from the index. Use after memory.recall_index to get complete information.",
|
|
41
|
+
inputSchema: {
|
|
42
|
+
type: "object",
|
|
43
|
+
properties: {
|
|
44
|
+
fact_ids: {type: "array", items: {type: "integer"}, description: "Fact IDs from memory.recall_index"},
|
|
45
|
+
scope: {type: "string", enum: ["project", "global"], description: "Database to query", default: "project"}
|
|
46
|
+
},
|
|
47
|
+
required: ["fact_ids"]
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
name: "memory.explain",
|
|
52
|
+
description: "Get detailed explanation of a fact with provenance",
|
|
53
|
+
inputSchema: {
|
|
54
|
+
type: "object",
|
|
55
|
+
properties: {
|
|
56
|
+
fact_id: {type: "integer", description: "Fact ID to explain"},
|
|
57
|
+
scope: {type: "string", enum: ["global", "project"], description: "Which database to look in", default: "project"}
|
|
58
|
+
},
|
|
59
|
+
required: ["fact_id"]
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
name: "memory.changes",
|
|
64
|
+
description: "List recent fact changes from both databases",
|
|
65
|
+
inputSchema: {
|
|
66
|
+
type: "object",
|
|
67
|
+
properties: {
|
|
68
|
+
since: {type: "string", description: "ISO timestamp"},
|
|
69
|
+
limit: {type: "integer", default: 20},
|
|
70
|
+
scope: {type: "string", enum: ["all", "global", "project"], default: "all"}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
name: "memory.conflicts",
|
|
76
|
+
description: "List open conflicts from both databases",
|
|
77
|
+
inputSchema: {
|
|
78
|
+
type: "object",
|
|
79
|
+
properties: {
|
|
80
|
+
scope: {type: "string", enum: ["all", "global", "project"], default: "all"}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
name: "memory.sweep_now",
|
|
86
|
+
description: "Run maintenance sweep on a database",
|
|
87
|
+
inputSchema: {
|
|
88
|
+
type: "object",
|
|
89
|
+
properties: {
|
|
90
|
+
budget_seconds: {type: "integer", default: 5},
|
|
91
|
+
scope: {type: "string", enum: ["global", "project"], default: "project"}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
name: "memory.status",
|
|
97
|
+
description: "Get memory system status for both databases",
|
|
98
|
+
inputSchema: {
|
|
99
|
+
type: "object",
|
|
100
|
+
properties: {}
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
name: "memory.stats",
|
|
105
|
+
description: "Get detailed statistics about the memory system (facts by predicate, entities by type, provenance coverage, conflicts, database sizes)",
|
|
106
|
+
inputSchema: {
|
|
107
|
+
type: "object",
|
|
108
|
+
properties: {
|
|
109
|
+
scope: {type: "string", enum: ["all", "global", "project"], description: "Show stats for: all (default), global, or project", default: "all"}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
name: "memory.promote",
|
|
115
|
+
description: "Promote a project fact to global memory. Use when user says a preference should apply everywhere.",
|
|
116
|
+
inputSchema: {
|
|
117
|
+
type: "object",
|
|
118
|
+
properties: {
|
|
119
|
+
fact_id: {type: "integer", description: "Project fact ID to promote to global"}
|
|
120
|
+
},
|
|
121
|
+
required: ["fact_id"]
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
name: "memory.store_extraction",
|
|
126
|
+
description: "Store extracted facts, entities, and decisions from a conversation. Call this to persist knowledge you've learned during the session.",
|
|
127
|
+
inputSchema: {
|
|
128
|
+
type: "object",
|
|
129
|
+
properties: {
|
|
130
|
+
entities: {
|
|
131
|
+
type: "array",
|
|
132
|
+
description: "Entities mentioned (databases, frameworks, services, etc.)",
|
|
133
|
+
items: {
|
|
134
|
+
type: "object",
|
|
135
|
+
properties: {
|
|
136
|
+
type: {type: "string", description: "Entity type: database, framework, language, platform, repo, module, person, service"},
|
|
137
|
+
name: {type: "string", description: "Canonical name"},
|
|
138
|
+
confidence: {type: "number", description: "0.0-1.0 extraction confidence"}
|
|
139
|
+
},
|
|
140
|
+
required: ["type", "name"]
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
facts: {
|
|
144
|
+
type: "array",
|
|
145
|
+
description: "Facts learned during the session",
|
|
146
|
+
items: {
|
|
147
|
+
type: "object",
|
|
148
|
+
properties: {
|
|
149
|
+
subject: {type: "string", description: "Entity name or 'repo' for project-level facts"},
|
|
150
|
+
predicate: {type: "string", description: "Relationship type: uses_database, uses_framework, convention, decision, auth_method, deployment_platform"},
|
|
151
|
+
object: {type: "string", description: "The value or target entity"},
|
|
152
|
+
confidence: {type: "number", description: "0.0-1.0 how confident"},
|
|
153
|
+
quote: {type: "string", description: "Source text excerpt (max 200 chars)"},
|
|
154
|
+
strength: {type: "string", enum: ["stated", "inferred"], description: "Was this explicitly stated or inferred?"},
|
|
155
|
+
scope_hint: {type: "string", enum: ["project", "global"], description: "Should this apply to just this project or globally?"}
|
|
156
|
+
},
|
|
157
|
+
required: ["subject", "predicate", "object"]
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
decisions: {
|
|
161
|
+
type: "array",
|
|
162
|
+
description: "Decisions made during the session",
|
|
163
|
+
items: {
|
|
164
|
+
type: "object",
|
|
165
|
+
properties: {
|
|
166
|
+
title: {type: "string", description: "Short summary (max 100 chars)"},
|
|
167
|
+
summary: {type: "string", description: "Full description"},
|
|
168
|
+
status_hint: {type: "string", enum: ["accepted", "proposed", "rejected"]}
|
|
169
|
+
},
|
|
170
|
+
required: ["title", "summary"]
|
|
171
|
+
}
|
|
172
|
+
},
|
|
173
|
+
scope: {type: "string", enum: ["global", "project"], description: "Default scope for facts", default: "project"}
|
|
174
|
+
},
|
|
175
|
+
required: ["facts"]
|
|
176
|
+
}
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
name: "memory.decisions",
|
|
180
|
+
description: "Quick access to architectural decisions, constraints, and rules. Use BEFORE implementing features to understand existing decisions and constraints.",
|
|
181
|
+
inputSchema: {
|
|
182
|
+
type: "object",
|
|
183
|
+
properties: {
|
|
184
|
+
limit: {type: "integer", default: 10, description: "Maximum results to return"}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
name: "memory.conventions",
|
|
190
|
+
description: "Quick access to coding conventions and style preferences (global scope). Check BEFORE writing code to follow established patterns.",
|
|
191
|
+
inputSchema: {
|
|
192
|
+
type: "object",
|
|
193
|
+
properties: {
|
|
194
|
+
limit: {type: "integer", default: 20, description: "Maximum results to return"}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
name: "memory.architecture",
|
|
200
|
+
description: "Quick access to framework choices and architectural patterns. Check FIRST when working with frameworks or making architectural decisions.",
|
|
201
|
+
inputSchema: {
|
|
202
|
+
type: "object",
|
|
203
|
+
properties: {
|
|
204
|
+
limit: {type: "integer", default: 10, description: "Maximum results to return"}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
name: "memory.facts_by_tool",
|
|
210
|
+
description: "Find facts discovered using a specific tool (Read, Edit, Bash, etc.)",
|
|
211
|
+
inputSchema: {
|
|
212
|
+
type: "object",
|
|
213
|
+
properties: {
|
|
214
|
+
tool_name: {type: "string", description: "Tool name (Read, Edit, Bash, etc.)"},
|
|
215
|
+
limit: {type: "integer", default: 20, description: "Maximum results to return"},
|
|
216
|
+
scope: {type: "string", enum: ["all", "global", "project"], default: "all", description: "Filter by scope"}
|
|
217
|
+
},
|
|
218
|
+
required: ["tool_name"]
|
|
219
|
+
}
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
name: "memory.facts_by_context",
|
|
223
|
+
description: "Find facts learned in specific context (branch, directory)",
|
|
224
|
+
inputSchema: {
|
|
225
|
+
type: "object",
|
|
226
|
+
properties: {
|
|
227
|
+
git_branch: {type: "string", description: "Git branch name"},
|
|
228
|
+
cwd: {type: "string", description: "Working directory path"},
|
|
229
|
+
limit: {type: "integer", default: 20, description: "Maximum results to return"},
|
|
230
|
+
scope: {type: "string", enum: ["all", "global", "project"], default: "all", description: "Filter by scope"}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
},
|
|
234
|
+
{
|
|
235
|
+
name: "memory.recall_semantic",
|
|
236
|
+
description: "Search facts using semantic similarity (finds conceptually related facts using vector embeddings)",
|
|
237
|
+
inputSchema: {
|
|
238
|
+
type: "object",
|
|
239
|
+
properties: {
|
|
240
|
+
query: {type: "string", description: "Search query"},
|
|
241
|
+
mode: {type: "string", enum: ["vector", "text", "both"], default: "both", description: "Search mode: vector (embeddings), text (FTS), or both (hybrid)"},
|
|
242
|
+
limit: {type: "integer", default: 10, description: "Maximum results to return"},
|
|
243
|
+
scope: {type: "string", enum: ["all", "global", "project"], default: "all", description: "Filter by scope"}
|
|
244
|
+
},
|
|
245
|
+
required: ["query"]
|
|
246
|
+
}
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
name: "memory.search_concepts",
|
|
250
|
+
description: "Search for facts matching ALL of the provided concepts (AND query). Ranks by average similarity across all concepts.",
|
|
251
|
+
inputSchema: {
|
|
252
|
+
type: "object",
|
|
253
|
+
properties: {
|
|
254
|
+
concepts: {
|
|
255
|
+
type: "array",
|
|
256
|
+
items: {type: "string"},
|
|
257
|
+
minItems: 2,
|
|
258
|
+
maxItems: 5,
|
|
259
|
+
description: "2-5 concepts that must all be present"
|
|
260
|
+
},
|
|
261
|
+
limit: {type: "integer", default: 10, description: "Maximum results to return"},
|
|
262
|
+
scope: {type: "string", enum: ["all", "global", "project"], default: "all", description: "Filter by scope"}
|
|
263
|
+
},
|
|
264
|
+
required: ["concepts"]
|
|
265
|
+
}
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
name: "memory.check_setup",
|
|
269
|
+
description: "Check if ClaudeMemory is properly initialized. CALL THIS FIRST if memory tools fail or on first use. Returns initialization status, version info, and actionable recommendations.",
|
|
270
|
+
inputSchema: {
|
|
271
|
+
type: "object",
|
|
272
|
+
properties: {}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
]
|
|
276
|
+
end
|
|
277
|
+
end
|
|
278
|
+
end
|
|
279
|
+
end
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ClaudeMemory
|
|
4
|
+
module MCP
|
|
5
|
+
# Shared utility methods for MCP tool implementations
|
|
6
|
+
# Reduces duplication across tool methods
|
|
7
|
+
module ToolHelpers
|
|
8
|
+
# Standard error response when database is not accessible
|
|
9
|
+
# @param error [Exception] The caught database error
|
|
10
|
+
# @return [Hash] Formatted error response with recommendations
|
|
11
|
+
def database_not_found_error(error)
|
|
12
|
+
{
|
|
13
|
+
error: "Database not found or not accessible",
|
|
14
|
+
message: "ClaudeMemory may not be initialized. Run memory.check_setup for detailed status.",
|
|
15
|
+
details: error.message,
|
|
16
|
+
recommendations: [
|
|
17
|
+
"Run memory.check_setup to diagnose the issue",
|
|
18
|
+
"If not initialized, run: claude-memory init",
|
|
19
|
+
"For help: claude-memory doctor"
|
|
20
|
+
]
|
|
21
|
+
}
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Format a fact hash for API response
|
|
25
|
+
# @param fact [Hash] Fact record from database
|
|
26
|
+
# @return [Hash] Formatted fact with standard fields
|
|
27
|
+
def format_fact(fact)
|
|
28
|
+
{
|
|
29
|
+
id: fact[:id],
|
|
30
|
+
subject: fact[:subject_name],
|
|
31
|
+
predicate: fact[:predicate],
|
|
32
|
+
object: fact[:object_literal],
|
|
33
|
+
status: fact[:status],
|
|
34
|
+
scope: fact[:scope]
|
|
35
|
+
}
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Format a receipt hash for API response
|
|
39
|
+
# @param receipt [Hash] Provenance record from database
|
|
40
|
+
# @return [Hash] Formatted receipt with quote and strength
|
|
41
|
+
def format_receipt(receipt)
|
|
42
|
+
{
|
|
43
|
+
quote: receipt[:quote],
|
|
44
|
+
strength: receipt[:strength]
|
|
45
|
+
}
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Format a result with fact and receipts
|
|
49
|
+
# @param result [Hash] Result hash with :fact and :receipts keys
|
|
50
|
+
# @return [Hash] Formatted result with source
|
|
51
|
+
def format_result(result)
|
|
52
|
+
{
|
|
53
|
+
id: result[:fact][:id],
|
|
54
|
+
subject: result[:fact][:subject_name],
|
|
55
|
+
predicate: result[:fact][:predicate],
|
|
56
|
+
object: result[:fact][:object_literal],
|
|
57
|
+
scope: result[:fact][:scope],
|
|
58
|
+
source: result[:source],
|
|
59
|
+
receipts: result[:receipts].map { |r| format_receipt(r) }
|
|
60
|
+
}
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Get default scope from arguments
|
|
64
|
+
# @param args [Hash] Tool arguments
|
|
65
|
+
# @param default [String] Default scope if not specified
|
|
66
|
+
# @return [String] Scope value
|
|
67
|
+
def extract_scope(args, default: "all")
|
|
68
|
+
args["scope"] || default
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Get default limit from arguments
|
|
72
|
+
# @param args [Hash] Tool arguments
|
|
73
|
+
# @param default [Integer] Default limit if not specified
|
|
74
|
+
# @return [Integer] Limit value
|
|
75
|
+
def extract_limit(args, default: 10)
|
|
76
|
+
args["limit"] || default
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|