omni-cortex 1.17.2__py3-none-any.whl → 1.17.4__py3-none-any.whl
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.
- omni_cortex/_bundled/dashboard/backend/.env.example +12 -0
- omni_cortex/_bundled/dashboard/backend/backfill_summaries.py +280 -0
- omni_cortex/_bundled/dashboard/backend/chat_service.py +631 -0
- omni_cortex/_bundled/dashboard/backend/database.py +1773 -0
- omni_cortex/_bundled/dashboard/backend/image_service.py +552 -0
- omni_cortex/_bundled/dashboard/backend/logging_config.py +122 -0
- omni_cortex/_bundled/dashboard/backend/main.py +1888 -0
- omni_cortex/_bundled/dashboard/backend/models.py +472 -0
- omni_cortex/_bundled/dashboard/backend/project_config.py +170 -0
- omni_cortex/_bundled/dashboard/backend/project_scanner.py +164 -0
- omni_cortex/_bundled/dashboard/backend/prompt_security.py +111 -0
- omni_cortex/_bundled/dashboard/backend/pyproject.toml +23 -0
- omni_cortex/_bundled/dashboard/backend/security.py +104 -0
- omni_cortex/_bundled/dashboard/backend/test_database.py +301 -0
- omni_cortex/_bundled/dashboard/backend/tmpclaude-2dfa-cwd +1 -0
- omni_cortex/_bundled/dashboard/backend/tmpclaude-c460-cwd +1 -0
- omni_cortex/_bundled/dashboard/backend/uv.lock +1110 -0
- omni_cortex/_bundled/dashboard/backend/websocket_manager.py +104 -0
- omni_cortex/_bundled/dashboard/frontend/dist/assets/index-CQlQK3nE.js +551 -0
- omni_cortex/_bundled/dashboard/frontend/dist/assets/index-CmUNNfe4.css +1 -0
- omni_cortex/_bundled/dashboard/frontend/dist/index.html +14 -0
- omni_cortex/_bundled/hooks/post_tool_use.py +497 -0
- omni_cortex/_bundled/hooks/pre_tool_use.py +277 -0
- omni_cortex/_bundled/hooks/session_utils.py +186 -0
- omni_cortex/_bundled/hooks/stop.py +219 -0
- omni_cortex/_bundled/hooks/subagent_stop.py +120 -0
- omni_cortex/_bundled/hooks/user_prompt.py +331 -0
- {omni_cortex-1.17.2.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/dashboard/backend/main.py +2 -2
- {omni_cortex-1.17.2.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/hooks/user_prompt.py +113 -2
- {omni_cortex-1.17.2.dist-info → omni_cortex-1.17.4.dist-info}/METADATA +6 -1
- omni_cortex-1.17.4.dist-info/RECORD +53 -0
- omni_cortex/__init__.py +0 -3
- omni_cortex/categorization/__init__.py +0 -9
- omni_cortex/categorization/auto_tags.py +0 -166
- omni_cortex/categorization/auto_type.py +0 -165
- omni_cortex/config.py +0 -141
- omni_cortex/dashboard.py +0 -232
- omni_cortex/database/__init__.py +0 -24
- omni_cortex/database/connection.py +0 -137
- omni_cortex/database/migrations.py +0 -210
- omni_cortex/database/schema.py +0 -212
- omni_cortex/database/sync.py +0 -421
- omni_cortex/decay/__init__.py +0 -7
- omni_cortex/decay/importance.py +0 -147
- omni_cortex/embeddings/__init__.py +0 -35
- omni_cortex/embeddings/local.py +0 -442
- omni_cortex/models/__init__.py +0 -20
- omni_cortex/models/activity.py +0 -265
- omni_cortex/models/agent.py +0 -144
- omni_cortex/models/memory.py +0 -395
- omni_cortex/models/relationship.py +0 -206
- omni_cortex/models/session.py +0 -290
- omni_cortex/resources/__init__.py +0 -1
- omni_cortex/search/__init__.py +0 -22
- omni_cortex/search/hybrid.py +0 -197
- omni_cortex/search/keyword.py +0 -204
- omni_cortex/search/ranking.py +0 -127
- omni_cortex/search/semantic.py +0 -232
- omni_cortex/server.py +0 -360
- omni_cortex/setup.py +0 -278
- omni_cortex/tools/__init__.py +0 -13
- omni_cortex/tools/activities.py +0 -453
- omni_cortex/tools/memories.py +0 -536
- omni_cortex/tools/sessions.py +0 -311
- omni_cortex/tools/utilities.py +0 -477
- omni_cortex/utils/__init__.py +0 -13
- omni_cortex/utils/formatting.py +0 -282
- omni_cortex/utils/ids.py +0 -72
- omni_cortex/utils/timestamps.py +0 -129
- omni_cortex/utils/truncation.py +0 -111
- omni_cortex-1.17.2.dist-info/RECORD +0 -65
- {omni_cortex-1.17.2.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/dashboard/backend/.env.example +0 -0
- {omni_cortex-1.17.2.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/dashboard/backend/backfill_summaries.py +0 -0
- {omni_cortex-1.17.2.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/dashboard/backend/chat_service.py +0 -0
- {omni_cortex-1.17.2.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/dashboard/backend/database.py +0 -0
- {omni_cortex-1.17.2.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/dashboard/backend/image_service.py +0 -0
- {omni_cortex-1.17.2.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/dashboard/backend/logging_config.py +0 -0
- {omni_cortex-1.17.2.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/dashboard/backend/models.py +0 -0
- {omni_cortex-1.17.2.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/dashboard/backend/project_config.py +0 -0
- {omni_cortex-1.17.2.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/dashboard/backend/project_scanner.py +0 -0
- {omni_cortex-1.17.2.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/dashboard/backend/prompt_security.py +0 -0
- {omni_cortex-1.17.2.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/dashboard/backend/pyproject.toml +0 -0
- {omni_cortex-1.17.2.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/dashboard/backend/security.py +0 -0
- {omni_cortex-1.17.2.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/dashboard/backend/uv.lock +0 -0
- {omni_cortex-1.17.2.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/dashboard/backend/websocket_manager.py +0 -0
- {omni_cortex-1.17.2.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/hooks/post_tool_use.py +0 -0
- {omni_cortex-1.17.2.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/hooks/pre_tool_use.py +0 -0
- {omni_cortex-1.17.2.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/hooks/session_utils.py +0 -0
- {omni_cortex-1.17.2.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/hooks/stop.py +0 -0
- {omni_cortex-1.17.2.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/hooks/subagent_stop.py +0 -0
- {omni_cortex-1.17.2.dist-info → omni_cortex-1.17.4.dist-info}/WHEEL +0 -0
- {omni_cortex-1.17.2.dist-info → omni_cortex-1.17.4.dist-info}/entry_points.txt +0 -0
- {omni_cortex-1.17.2.dist-info → omni_cortex-1.17.4.dist-info}/licenses/LICENSE +0 -0
omni_cortex/server.py
DELETED
|
@@ -1,360 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""Omni Cortex MCP Server - Universal Memory System for Claude Code.
|
|
3
|
-
|
|
4
|
-
This server provides a dual-layer memory system combining:
|
|
5
|
-
- Activity logging (audit trail of all tool calls and decisions)
|
|
6
|
-
- Knowledge storage (distilled insights, solutions, and learnings)
|
|
7
|
-
|
|
8
|
-
Features:
|
|
9
|
-
- 15 tools across 4 categories: Activities, Memories, Sessions, Utilities
|
|
10
|
-
- Full-text search with FTS5
|
|
11
|
-
- Auto-categorization and smart tagging
|
|
12
|
-
- Multi-factor relevance ranking
|
|
13
|
-
- Session continuity ("Last time you were working on...")
|
|
14
|
-
- Importance decay over time
|
|
15
|
-
"""
|
|
16
|
-
|
|
17
|
-
from contextlib import asynccontextmanager
|
|
18
|
-
from typing import AsyncGenerator
|
|
19
|
-
|
|
20
|
-
from mcp.server.fastmcp import FastMCP
|
|
21
|
-
|
|
22
|
-
from .database.connection import init_database, close_all_connections
|
|
23
|
-
from .tools.memories import register_memory_tools
|
|
24
|
-
from .tools.activities import register_activity_tools
|
|
25
|
-
from .tools.sessions import register_session_tools
|
|
26
|
-
from .tools.utilities import register_utility_tools
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
@asynccontextmanager
|
|
30
|
-
async def lifespan(mcp: FastMCP) -> AsyncGenerator[dict, None]:
|
|
31
|
-
"""Manage server lifecycle - initialize and cleanup resources."""
|
|
32
|
-
# Initialize database on startup
|
|
33
|
-
try:
|
|
34
|
-
init_database()
|
|
35
|
-
init_database(is_global=True)
|
|
36
|
-
except Exception as e:
|
|
37
|
-
print(f"Warning: Failed to initialize database: {e}")
|
|
38
|
-
|
|
39
|
-
yield {}
|
|
40
|
-
|
|
41
|
-
# Cleanup on shutdown
|
|
42
|
-
close_all_connections()
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
# Create the MCP server
|
|
46
|
-
mcp = FastMCP(
|
|
47
|
-
"omni_cortex",
|
|
48
|
-
lifespan=lifespan,
|
|
49
|
-
)
|
|
50
|
-
|
|
51
|
-
# Register all tools
|
|
52
|
-
register_memory_tools(mcp)
|
|
53
|
-
register_activity_tools(mcp)
|
|
54
|
-
register_session_tools(mcp)
|
|
55
|
-
register_utility_tools(mcp)
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
# === MCP Resources ===
|
|
59
|
-
|
|
60
|
-
@mcp.resource("cortex://stats")
|
|
61
|
-
async def get_stats() -> str:
|
|
62
|
-
"""Get statistics about the Cortex database."""
|
|
63
|
-
try:
|
|
64
|
-
conn = init_database()
|
|
65
|
-
cursor = conn.cursor()
|
|
66
|
-
|
|
67
|
-
stats = {}
|
|
68
|
-
|
|
69
|
-
# Count memories
|
|
70
|
-
cursor.execute("SELECT COUNT(*) FROM memories")
|
|
71
|
-
stats["total_memories"] = cursor.fetchone()[0]
|
|
72
|
-
|
|
73
|
-
# Count by type
|
|
74
|
-
cursor.execute("""
|
|
75
|
-
SELECT type, COUNT(*) as cnt
|
|
76
|
-
FROM memories
|
|
77
|
-
GROUP BY type
|
|
78
|
-
ORDER BY cnt DESC
|
|
79
|
-
""")
|
|
80
|
-
stats["memories_by_type"] = {row["type"]: row["cnt"] for row in cursor.fetchall()}
|
|
81
|
-
|
|
82
|
-
# Count by status
|
|
83
|
-
cursor.execute("""
|
|
84
|
-
SELECT status, COUNT(*) as cnt
|
|
85
|
-
FROM memories
|
|
86
|
-
GROUP BY status
|
|
87
|
-
""")
|
|
88
|
-
stats["memories_by_status"] = {row["status"]: row["cnt"] for row in cursor.fetchall()}
|
|
89
|
-
|
|
90
|
-
# Count activities
|
|
91
|
-
cursor.execute("SELECT COUNT(*) FROM activities")
|
|
92
|
-
stats["total_activities"] = cursor.fetchone()[0]
|
|
93
|
-
|
|
94
|
-
# Count sessions
|
|
95
|
-
cursor.execute("SELECT COUNT(*) FROM sessions")
|
|
96
|
-
stats["total_sessions"] = cursor.fetchone()[0]
|
|
97
|
-
|
|
98
|
-
import json
|
|
99
|
-
return json.dumps(stats, indent=2)
|
|
100
|
-
|
|
101
|
-
except Exception as e:
|
|
102
|
-
return f"Error getting stats: {e}"
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
@mcp.resource("cortex://types")
|
|
106
|
-
async def get_memory_types() -> str:
|
|
107
|
-
"""Get available memory types with descriptions."""
|
|
108
|
-
types = {
|
|
109
|
-
"general": "General information or notes",
|
|
110
|
-
"warning": "Warnings, cautions, things to avoid",
|
|
111
|
-
"tip": "Tips, tricks, best practices",
|
|
112
|
-
"config": "Configuration, settings, environment variables",
|
|
113
|
-
"troubleshooting": "Problem solving, debugging guides",
|
|
114
|
-
"code": "Code snippets, functions, algorithms",
|
|
115
|
-
"error": "Errors, exceptions, failure cases",
|
|
116
|
-
"solution": "Solutions to problems, fixes",
|
|
117
|
-
"command": "CLI commands, terminal operations",
|
|
118
|
-
"concept": "Definitions, explanations, concepts",
|
|
119
|
-
"decision": "Decisions made, architectural choices",
|
|
120
|
-
}
|
|
121
|
-
import json
|
|
122
|
-
return json.dumps(types, indent=2)
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
@mcp.resource("cortex://config")
|
|
126
|
-
async def get_config() -> str:
|
|
127
|
-
"""Get current Cortex configuration."""
|
|
128
|
-
from .config import load_config
|
|
129
|
-
|
|
130
|
-
config = load_config()
|
|
131
|
-
import json
|
|
132
|
-
return json.dumps({
|
|
133
|
-
"schema_version": config.schema_version,
|
|
134
|
-
"embedding_model": config.embedding_model,
|
|
135
|
-
"embedding_enabled": config.embedding_enabled,
|
|
136
|
-
"decay_rate_per_day": config.decay_rate_per_day,
|
|
137
|
-
"freshness_review_days": config.freshness_review_days,
|
|
138
|
-
"auto_provide_context": config.auto_provide_context,
|
|
139
|
-
"context_depth": config.context_depth,
|
|
140
|
-
"default_search_mode": config.default_search_mode,
|
|
141
|
-
"global_sync_enabled": config.global_sync_enabled,
|
|
142
|
-
}, indent=2)
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
@mcp.resource("cortex://tags")
|
|
146
|
-
async def get_tags() -> str:
|
|
147
|
-
"""Get all tags used in memories with usage counts."""
|
|
148
|
-
try:
|
|
149
|
-
conn = init_database()
|
|
150
|
-
cursor = conn.cursor()
|
|
151
|
-
|
|
152
|
-
# Query all memories and extract tags
|
|
153
|
-
cursor.execute("SELECT tags FROM memories WHERE tags IS NOT NULL")
|
|
154
|
-
|
|
155
|
-
import json
|
|
156
|
-
tag_counts: dict[str, int] = {}
|
|
157
|
-
|
|
158
|
-
for row in cursor.fetchall():
|
|
159
|
-
tags_json = row["tags"]
|
|
160
|
-
if tags_json:
|
|
161
|
-
try:
|
|
162
|
-
tags = json.loads(tags_json)
|
|
163
|
-
for tag in tags:
|
|
164
|
-
tag_counts[tag] = tag_counts.get(tag, 0) + 1
|
|
165
|
-
except json.JSONDecodeError:
|
|
166
|
-
pass
|
|
167
|
-
|
|
168
|
-
# Sort by count descending
|
|
169
|
-
sorted_tags = sorted(tag_counts.items(), key=lambda x: x[1], reverse=True)
|
|
170
|
-
|
|
171
|
-
return json.dumps({
|
|
172
|
-
"total_unique_tags": len(sorted_tags),
|
|
173
|
-
"tags": [{"name": name, "count": count} for name, count in sorted_tags],
|
|
174
|
-
}, indent=2)
|
|
175
|
-
|
|
176
|
-
except Exception as e:
|
|
177
|
-
return f"Error getting tags: {e}"
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
@mcp.resource("cortex://sessions/recent")
|
|
181
|
-
async def get_recent_sessions_resource() -> str:
|
|
182
|
-
"""Get recent sessions with summaries."""
|
|
183
|
-
try:
|
|
184
|
-
conn = init_database()
|
|
185
|
-
from .models.session import get_recent_sessions, get_session_summary
|
|
186
|
-
|
|
187
|
-
sessions = get_recent_sessions(conn, limit=10)
|
|
188
|
-
|
|
189
|
-
import json
|
|
190
|
-
result = []
|
|
191
|
-
|
|
192
|
-
for session in sessions:
|
|
193
|
-
session_data = {
|
|
194
|
-
"id": session.id,
|
|
195
|
-
"project_path": session.project_path,
|
|
196
|
-
"started_at": session.started_at,
|
|
197
|
-
"ended_at": session.ended_at,
|
|
198
|
-
"summary": session.summary,
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
# Get summary if available
|
|
202
|
-
summary = get_session_summary(conn, session.id)
|
|
203
|
-
if summary:
|
|
204
|
-
session_data["stats"] = {
|
|
205
|
-
"total_activities": summary.total_activities,
|
|
206
|
-
"memories_created": summary.total_memories_created,
|
|
207
|
-
"tools_used": summary.tools_used,
|
|
208
|
-
"key_learnings": summary.key_learnings,
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
result.append(session_data)
|
|
212
|
-
|
|
213
|
-
return json.dumps({
|
|
214
|
-
"total_sessions": len(result),
|
|
215
|
-
"sessions": result,
|
|
216
|
-
}, indent=2)
|
|
217
|
-
|
|
218
|
-
except Exception as e:
|
|
219
|
-
return f"Error getting recent sessions: {e}"
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
@mcp.resource("cortex://status")
|
|
223
|
-
async def get_cli_status() -> str:
|
|
224
|
-
"""Get current session status for CLI display.
|
|
225
|
-
|
|
226
|
-
Provides real-time status information that can be used for:
|
|
227
|
-
- Session timer display
|
|
228
|
-
- Activity counts
|
|
229
|
-
- Tool usage statistics
|
|
230
|
-
- Memory creation stats
|
|
231
|
-
|
|
232
|
-
This resource is designed to support future CLI status bar integration.
|
|
233
|
-
"""
|
|
234
|
-
try:
|
|
235
|
-
import json
|
|
236
|
-
from datetime import datetime, timezone
|
|
237
|
-
conn = init_database()
|
|
238
|
-
cursor = conn.cursor()
|
|
239
|
-
|
|
240
|
-
status = {
|
|
241
|
-
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
242
|
-
"session": None,
|
|
243
|
-
"activity_summary": {},
|
|
244
|
-
"memory_summary": {},
|
|
245
|
-
"tool_stats": {},
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
# Get current/most recent session
|
|
249
|
-
cursor.execute("""
|
|
250
|
-
SELECT id, started_at, ended_at, duration_ms
|
|
251
|
-
FROM sessions
|
|
252
|
-
ORDER BY started_at DESC
|
|
253
|
-
LIMIT 1
|
|
254
|
-
""")
|
|
255
|
-
row = cursor.fetchone()
|
|
256
|
-
if row:
|
|
257
|
-
session_id = row["id"]
|
|
258
|
-
started_at = row["started_at"]
|
|
259
|
-
ended_at = row["ended_at"]
|
|
260
|
-
duration_ms = row["duration_ms"]
|
|
261
|
-
|
|
262
|
-
# Calculate session duration
|
|
263
|
-
if started_at:
|
|
264
|
-
try:
|
|
265
|
-
start_time = datetime.fromisoformat(started_at.replace("Z", "+00:00"))
|
|
266
|
-
now = datetime.now(timezone.utc)
|
|
267
|
-
elapsed_seconds = (now - start_time).total_seconds()
|
|
268
|
-
elapsed_minutes = int(elapsed_seconds / 60)
|
|
269
|
-
elapsed_hours = int(elapsed_minutes / 60)
|
|
270
|
-
except Exception:
|
|
271
|
-
elapsed_seconds = 0
|
|
272
|
-
elapsed_minutes = 0
|
|
273
|
-
elapsed_hours = 0
|
|
274
|
-
else:
|
|
275
|
-
elapsed_seconds = elapsed_minutes = elapsed_hours = 0
|
|
276
|
-
|
|
277
|
-
status["session"] = {
|
|
278
|
-
"id": session_id,
|
|
279
|
-
"started_at": started_at,
|
|
280
|
-
"ended_at": ended_at,
|
|
281
|
-
"is_active": ended_at is None,
|
|
282
|
-
"elapsed_seconds": int(elapsed_seconds),
|
|
283
|
-
"elapsed_minutes": elapsed_minutes,
|
|
284
|
-
"elapsed_hours": elapsed_hours,
|
|
285
|
-
"elapsed_display": f"{elapsed_hours}h {elapsed_minutes % 60}m" if elapsed_hours > 0 else f"{elapsed_minutes}m",
|
|
286
|
-
"recorded_duration_ms": duration_ms,
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
# Get activity count for this session
|
|
290
|
-
cursor.execute("""
|
|
291
|
-
SELECT COUNT(*) as count
|
|
292
|
-
FROM activities
|
|
293
|
-
WHERE session_id = ?
|
|
294
|
-
""", (session_id,))
|
|
295
|
-
activity_count = cursor.fetchone()["count"]
|
|
296
|
-
|
|
297
|
-
# Get tool breakdown for this session
|
|
298
|
-
cursor.execute("""
|
|
299
|
-
SELECT tool_name, COUNT(*) as count, SUM(duration_ms) as total_ms
|
|
300
|
-
FROM activities
|
|
301
|
-
WHERE session_id = ? AND tool_name IS NOT NULL
|
|
302
|
-
GROUP BY tool_name
|
|
303
|
-
ORDER BY count DESC
|
|
304
|
-
LIMIT 10
|
|
305
|
-
""", (session_id,))
|
|
306
|
-
tool_stats = {}
|
|
307
|
-
for tool_row in cursor.fetchall():
|
|
308
|
-
tool_stats[tool_row["tool_name"]] = {
|
|
309
|
-
"count": tool_row["count"],
|
|
310
|
-
"total_ms": tool_row["total_ms"],
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
status["activity_summary"] = {
|
|
314
|
-
"session_activity_count": activity_count,
|
|
315
|
-
"top_tools": tool_stats,
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
# Get memories created in this session
|
|
319
|
-
cursor.execute("""
|
|
320
|
-
SELECT COUNT(*) as count
|
|
321
|
-
FROM memories
|
|
322
|
-
WHERE source_session_id = ?
|
|
323
|
-
""", (session_id,))
|
|
324
|
-
memories_created = cursor.fetchone()["count"]
|
|
325
|
-
|
|
326
|
-
status["memory_summary"] = {
|
|
327
|
-
"session_memories_created": memories_created,
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
# Get all-time totals
|
|
331
|
-
cursor.execute("SELECT COUNT(*) FROM activities")
|
|
332
|
-
status["totals"] = {
|
|
333
|
-
"all_activities": cursor.fetchone()[0],
|
|
334
|
-
}
|
|
335
|
-
cursor.execute("SELECT COUNT(*) FROM memories")
|
|
336
|
-
status["totals"]["all_memories"] = cursor.fetchone()[0]
|
|
337
|
-
cursor.execute("SELECT COUNT(*) FROM sessions")
|
|
338
|
-
status["totals"]["all_sessions"] = cursor.fetchone()[0]
|
|
339
|
-
|
|
340
|
-
# Get user message count if table exists
|
|
341
|
-
try:
|
|
342
|
-
cursor.execute("SELECT COUNT(*) FROM user_messages")
|
|
343
|
-
status["totals"]["all_user_messages"] = cursor.fetchone()[0]
|
|
344
|
-
except Exception:
|
|
345
|
-
status["totals"]["all_user_messages"] = 0
|
|
346
|
-
|
|
347
|
-
return json.dumps(status, indent=2)
|
|
348
|
-
|
|
349
|
-
except Exception as e:
|
|
350
|
-
import json
|
|
351
|
-
return json.dumps({"error": str(e)})
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
def main():
|
|
355
|
-
"""Run the MCP server."""
|
|
356
|
-
mcp.run()
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
if __name__ == "__main__":
|
|
360
|
-
main()
|
omni_cortex/setup.py
DELETED
|
@@ -1,278 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""Omni Cortex MCP Setup Module.
|
|
3
|
-
|
|
4
|
-
This module automatically configures Omni Cortex MCP for Claude Code:
|
|
5
|
-
1. Adds the MCP server to ~/.claude.json
|
|
6
|
-
2. Configures activity logging hooks in Claude's settings.json
|
|
7
|
-
|
|
8
|
-
Usage:
|
|
9
|
-
python -m omni_cortex.setup
|
|
10
|
-
# or after pip install:
|
|
11
|
-
omni-cortex-setup
|
|
12
|
-
"""
|
|
13
|
-
|
|
14
|
-
import json
|
|
15
|
-
import os
|
|
16
|
-
import sys
|
|
17
|
-
from pathlib import Path
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
def get_claude_config_path() -> Path:
|
|
21
|
-
"""Get the path to Claude's config file."""
|
|
22
|
-
home = Path.home()
|
|
23
|
-
return home / ".claude.json"
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
def get_claude_settings_path() -> Path:
|
|
27
|
-
"""Get the path to Claude Code's settings.json."""
|
|
28
|
-
home = Path.home()
|
|
29
|
-
|
|
30
|
-
# Check common locations
|
|
31
|
-
if sys.platform == "win32":
|
|
32
|
-
paths = [
|
|
33
|
-
home / ".claude" / "settings.json",
|
|
34
|
-
home / "AppData" / "Roaming" / "Claude" / "settings.json",
|
|
35
|
-
]
|
|
36
|
-
else:
|
|
37
|
-
paths = [
|
|
38
|
-
home / ".claude" / "settings.json",
|
|
39
|
-
home / ".config" / "claude" / "settings.json",
|
|
40
|
-
]
|
|
41
|
-
|
|
42
|
-
for path in paths:
|
|
43
|
-
if path.exists():
|
|
44
|
-
return path
|
|
45
|
-
|
|
46
|
-
# Default to .claude/settings.json
|
|
47
|
-
return home / ".claude" / "settings.json"
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
def get_package_dir() -> Path:
|
|
51
|
-
"""Get the directory where omni-cortex is installed."""
|
|
52
|
-
return Path(__file__).parent.parent.parent
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
def get_hooks_dir() -> Path:
|
|
56
|
-
"""Get the hooks directory.
|
|
57
|
-
|
|
58
|
-
Checks multiple locations for hooks:
|
|
59
|
-
1. Development: <project>/hooks/
|
|
60
|
-
2. Installed: <site-packages>/../share/omni-cortex/hooks/
|
|
61
|
-
3. Installed: <prefix>/share/omni-cortex/hooks/
|
|
62
|
-
"""
|
|
63
|
-
# Try development location
|
|
64
|
-
package_dir = get_package_dir()
|
|
65
|
-
hooks_dir = package_dir / "hooks"
|
|
66
|
-
if hooks_dir.exists():
|
|
67
|
-
return hooks_dir
|
|
68
|
-
|
|
69
|
-
# Try relative to package
|
|
70
|
-
import omni_cortex
|
|
71
|
-
pkg_path = Path(omni_cortex.__file__).parent
|
|
72
|
-
|
|
73
|
-
# Check various installed locations
|
|
74
|
-
candidates = [
|
|
75
|
-
pkg_path.parent.parent / "hooks",
|
|
76
|
-
pkg_path.parent.parent / "share" / "omni-cortex" / "hooks",
|
|
77
|
-
Path(sys.prefix) / "share" / "omni-cortex" / "hooks",
|
|
78
|
-
Path(sys.base_prefix) / "share" / "omni-cortex" / "hooks",
|
|
79
|
-
]
|
|
80
|
-
|
|
81
|
-
for candidate in candidates:
|
|
82
|
-
if candidate.exists():
|
|
83
|
-
return candidate
|
|
84
|
-
|
|
85
|
-
# Fall back to package dir even if it doesn't exist
|
|
86
|
-
return package_dir / "hooks"
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
def setup_mcp_server() -> bool:
|
|
90
|
-
"""Add Omni Cortex MCP server to Claude's config."""
|
|
91
|
-
config_path = get_claude_config_path()
|
|
92
|
-
|
|
93
|
-
# Read existing config or create new
|
|
94
|
-
if config_path.exists():
|
|
95
|
-
with open(config_path) as f:
|
|
96
|
-
config = json.load(f)
|
|
97
|
-
else:
|
|
98
|
-
config = {}
|
|
99
|
-
|
|
100
|
-
# Ensure mcpServers exists
|
|
101
|
-
if "mcpServers" not in config:
|
|
102
|
-
config["mcpServers"] = {}
|
|
103
|
-
|
|
104
|
-
# Add omni-cortex server
|
|
105
|
-
config["mcpServers"]["omni-cortex"] = {
|
|
106
|
-
"command": sys.executable,
|
|
107
|
-
"args": ["-m", "omni_cortex.server"],
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
# Write config
|
|
111
|
-
config_path.parent.mkdir(parents=True, exist_ok=True)
|
|
112
|
-
with open(config_path, "w") as f:
|
|
113
|
-
json.dump(config, f, indent=2)
|
|
114
|
-
|
|
115
|
-
print(f" Added MCP server to {config_path}")
|
|
116
|
-
return True
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
def setup_hooks() -> bool:
|
|
120
|
-
"""Configure activity logging hooks in Claude's settings.json."""
|
|
121
|
-
settings_path = get_claude_settings_path()
|
|
122
|
-
hooks_dir = get_hooks_dir()
|
|
123
|
-
|
|
124
|
-
if not hooks_dir.exists():
|
|
125
|
-
print(f" Warning: hooks directory not found at {hooks_dir}")
|
|
126
|
-
print(" Skipping hooks configuration.")
|
|
127
|
-
return False
|
|
128
|
-
|
|
129
|
-
# Read existing settings or create new
|
|
130
|
-
if settings_path.exists():
|
|
131
|
-
with open(settings_path) as f:
|
|
132
|
-
settings = json.load(f)
|
|
133
|
-
else:
|
|
134
|
-
settings = {}
|
|
135
|
-
|
|
136
|
-
# Ensure hooks section exists
|
|
137
|
-
if "hooks" not in settings:
|
|
138
|
-
settings["hooks"] = {}
|
|
139
|
-
|
|
140
|
-
# Get Python executable
|
|
141
|
-
python_exe = sys.executable
|
|
142
|
-
|
|
143
|
-
# Helper to check if hook already exists (handles both old and new format)
|
|
144
|
-
def hook_exists(hook_list, script_name):
|
|
145
|
-
for h in hook_list:
|
|
146
|
-
# Check old format
|
|
147
|
-
cmd = str(h.get("command", ""))
|
|
148
|
-
if "omni-cortex" in cmd or script_name in cmd:
|
|
149
|
-
return True
|
|
150
|
-
# Check new format (matcher + hooks array)
|
|
151
|
-
if "hooks" in h:
|
|
152
|
-
for inner_hook in h.get("hooks", []):
|
|
153
|
-
inner_cmd = str(inner_hook.get("command", ""))
|
|
154
|
-
if "omni-cortex" in inner_cmd or script_name in inner_cmd:
|
|
155
|
-
return True
|
|
156
|
-
return False
|
|
157
|
-
|
|
158
|
-
# Configure hooks (new format with matcher and hooks array)
|
|
159
|
-
hooks_config = {
|
|
160
|
-
"PreToolUse": ("pre_tool_use.py", f'"{python_exe}" "{hooks_dir / "pre_tool_use.py"}"'),
|
|
161
|
-
"PostToolUse": ("post_tool_use.py", f'"{python_exe}" "{hooks_dir / "post_tool_use.py"}"'),
|
|
162
|
-
"Stop": ("stop.py", f'"{python_exe}" "{hooks_dir / "stop.py"}"'),
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
for hook_name, (script_name, command) in hooks_config.items():
|
|
166
|
-
if hook_name not in settings["hooks"]:
|
|
167
|
-
settings["hooks"][hook_name] = []
|
|
168
|
-
|
|
169
|
-
if not hook_exists(settings["hooks"][hook_name], script_name):
|
|
170
|
-
# New format: matcher + hooks array
|
|
171
|
-
settings["hooks"][hook_name].append({
|
|
172
|
-
"matcher": "",
|
|
173
|
-
"hooks": [
|
|
174
|
-
{
|
|
175
|
-
"type": "command",
|
|
176
|
-
"command": command,
|
|
177
|
-
}
|
|
178
|
-
]
|
|
179
|
-
})
|
|
180
|
-
|
|
181
|
-
# Write settings
|
|
182
|
-
settings_path.parent.mkdir(parents=True, exist_ok=True)
|
|
183
|
-
with open(settings_path, "w") as f:
|
|
184
|
-
json.dump(settings, f, indent=2)
|
|
185
|
-
|
|
186
|
-
print(f" Configured hooks in {settings_path}")
|
|
187
|
-
return True
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
def uninstall() -> bool:
|
|
191
|
-
"""Remove Omni Cortex from Claude's configuration."""
|
|
192
|
-
config_path = get_claude_config_path()
|
|
193
|
-
settings_path = get_claude_settings_path()
|
|
194
|
-
|
|
195
|
-
# Remove from MCP servers
|
|
196
|
-
if config_path.exists():
|
|
197
|
-
with open(config_path) as f:
|
|
198
|
-
config = json.load(f)
|
|
199
|
-
|
|
200
|
-
if "mcpServers" in config and "omni-cortex" in config["mcpServers"]:
|
|
201
|
-
del config["mcpServers"]["omni-cortex"]
|
|
202
|
-
with open(config_path, "w") as f:
|
|
203
|
-
json.dump(config, f, indent=2)
|
|
204
|
-
print(f" Removed MCP server from {config_path}")
|
|
205
|
-
|
|
206
|
-
# Remove hooks
|
|
207
|
-
if settings_path.exists():
|
|
208
|
-
with open(settings_path) as f:
|
|
209
|
-
settings = json.load(f)
|
|
210
|
-
|
|
211
|
-
if "hooks" in settings:
|
|
212
|
-
for hook_name in ["PreToolUse", "PostToolUse", "Stop"]:
|
|
213
|
-
if hook_name in settings["hooks"]:
|
|
214
|
-
settings["hooks"][hook_name] = [
|
|
215
|
-
h for h in settings["hooks"][hook_name]
|
|
216
|
-
if "omni-cortex" not in str(h.get("command", ""))
|
|
217
|
-
and "pre_tool_use" not in str(h.get("command", ""))
|
|
218
|
-
and "post_tool_use" not in str(h.get("command", ""))
|
|
219
|
-
and "stop.py" not in str(h.get("command", ""))
|
|
220
|
-
]
|
|
221
|
-
|
|
222
|
-
with open(settings_path, "w") as f:
|
|
223
|
-
json.dump(settings, f, indent=2)
|
|
224
|
-
print(f" Removed hooks from {settings_path}")
|
|
225
|
-
|
|
226
|
-
return True
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
def main():
|
|
230
|
-
"""Run the setup process."""
|
|
231
|
-
args = sys.argv[1:]
|
|
232
|
-
|
|
233
|
-
if "--uninstall" in args or "uninstall" in args:
|
|
234
|
-
print("=" * 50)
|
|
235
|
-
print("Omni Cortex MCP Uninstall")
|
|
236
|
-
print("=" * 50)
|
|
237
|
-
print()
|
|
238
|
-
uninstall()
|
|
239
|
-
print()
|
|
240
|
-
print("Uninstall complete. Restart Claude Code.")
|
|
241
|
-
return
|
|
242
|
-
|
|
243
|
-
print("=" * 50)
|
|
244
|
-
print("Omni Cortex MCP Setup")
|
|
245
|
-
print("=" * 50)
|
|
246
|
-
print()
|
|
247
|
-
|
|
248
|
-
# Step 1: Setup MCP server
|
|
249
|
-
print("Step 1: Configuring MCP server...")
|
|
250
|
-
setup_mcp_server()
|
|
251
|
-
|
|
252
|
-
print()
|
|
253
|
-
|
|
254
|
-
# Step 2: Setup hooks
|
|
255
|
-
print("Step 2: Configuring activity hooks...")
|
|
256
|
-
setup_hooks()
|
|
257
|
-
|
|
258
|
-
print()
|
|
259
|
-
print("=" * 50)
|
|
260
|
-
print("Setup complete!")
|
|
261
|
-
print()
|
|
262
|
-
print("Omni Cortex MCP is now ready to use.")
|
|
263
|
-
print("Restart Claude Code for changes to take effect.")
|
|
264
|
-
print()
|
|
265
|
-
print("The MCP will automatically:")
|
|
266
|
-
print(" - Log all tool calls to .omni-cortex/cortex.db")
|
|
267
|
-
print(" - Provide cortex_remember/cortex_recall tools")
|
|
268
|
-
print(" - Track sessions and activities")
|
|
269
|
-
print()
|
|
270
|
-
print("For semantic search, install:")
|
|
271
|
-
print(" pip install sentence-transformers")
|
|
272
|
-
print()
|
|
273
|
-
print("To uninstall: omni-cortex-setup --uninstall")
|
|
274
|
-
print("=" * 50)
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
if __name__ == "__main__":
|
|
278
|
-
main()
|
omni_cortex/tools/__init__.py
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
"""MCP tools for Omni Cortex."""
|
|
2
|
-
|
|
3
|
-
from .memories import register_memory_tools
|
|
4
|
-
from .activities import register_activity_tools
|
|
5
|
-
from .sessions import register_session_tools
|
|
6
|
-
from .utilities import register_utility_tools
|
|
7
|
-
|
|
8
|
-
__all__ = [
|
|
9
|
-
"register_memory_tools",
|
|
10
|
-
"register_activity_tools",
|
|
11
|
-
"register_session_tools",
|
|
12
|
-
"register_utility_tools",
|
|
13
|
-
]
|