omni-cortex 1.17.3__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.
Files changed (74) hide show
  1. omni_cortex/_bundled/dashboard/backend/main.py +2 -2
  2. omni_cortex/_bundled/dashboard/backend/test_database.py +301 -0
  3. omni_cortex/_bundled/dashboard/backend/tmpclaude-2dfa-cwd +1 -0
  4. omni_cortex/_bundled/dashboard/backend/tmpclaude-c460-cwd +1 -0
  5. omni_cortex/_bundled/dashboard/frontend/dist/assets/index-CQlQK3nE.js +551 -0
  6. omni_cortex/_bundled/dashboard/frontend/dist/assets/index-CmUNNfe4.css +1 -0
  7. omni_cortex/_bundled/dashboard/frontend/dist/index.html +14 -0
  8. omni_cortex/_bundled/hooks/user_prompt.py +113 -2
  9. {omni_cortex-1.17.3.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/dashboard/backend/main.py +2 -2
  10. {omni_cortex-1.17.3.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/hooks/user_prompt.py +113 -2
  11. {omni_cortex-1.17.3.dist-info → omni_cortex-1.17.4.dist-info}/METADATA +6 -1
  12. omni_cortex-1.17.4.dist-info/RECORD +53 -0
  13. omni_cortex/__init__.py +0 -3
  14. omni_cortex/categorization/__init__.py +0 -9
  15. omni_cortex/categorization/auto_tags.py +0 -166
  16. omni_cortex/categorization/auto_type.py +0 -165
  17. omni_cortex/config.py +0 -141
  18. omni_cortex/dashboard.py +0 -238
  19. omni_cortex/database/__init__.py +0 -24
  20. omni_cortex/database/connection.py +0 -137
  21. omni_cortex/database/migrations.py +0 -210
  22. omni_cortex/database/schema.py +0 -212
  23. omni_cortex/database/sync.py +0 -421
  24. omni_cortex/decay/__init__.py +0 -7
  25. omni_cortex/decay/importance.py +0 -147
  26. omni_cortex/embeddings/__init__.py +0 -35
  27. omni_cortex/embeddings/local.py +0 -442
  28. omni_cortex/models/__init__.py +0 -20
  29. omni_cortex/models/activity.py +0 -265
  30. omni_cortex/models/agent.py +0 -144
  31. omni_cortex/models/memory.py +0 -395
  32. omni_cortex/models/relationship.py +0 -206
  33. omni_cortex/models/session.py +0 -290
  34. omni_cortex/resources/__init__.py +0 -1
  35. omni_cortex/search/__init__.py +0 -22
  36. omni_cortex/search/hybrid.py +0 -197
  37. omni_cortex/search/keyword.py +0 -204
  38. omni_cortex/search/ranking.py +0 -127
  39. omni_cortex/search/semantic.py +0 -232
  40. omni_cortex/server.py +0 -360
  41. omni_cortex/setup.py +0 -284
  42. omni_cortex/tools/__init__.py +0 -13
  43. omni_cortex/tools/activities.py +0 -453
  44. omni_cortex/tools/memories.py +0 -536
  45. omni_cortex/tools/sessions.py +0 -311
  46. omni_cortex/tools/utilities.py +0 -477
  47. omni_cortex/utils/__init__.py +0 -13
  48. omni_cortex/utils/formatting.py +0 -282
  49. omni_cortex/utils/ids.py +0 -72
  50. omni_cortex/utils/timestamps.py +0 -129
  51. omni_cortex/utils/truncation.py +0 -111
  52. omni_cortex-1.17.3.dist-info/RECORD +0 -86
  53. {omni_cortex-1.17.3.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/dashboard/backend/.env.example +0 -0
  54. {omni_cortex-1.17.3.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/dashboard/backend/backfill_summaries.py +0 -0
  55. {omni_cortex-1.17.3.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/dashboard/backend/chat_service.py +0 -0
  56. {omni_cortex-1.17.3.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/dashboard/backend/database.py +0 -0
  57. {omni_cortex-1.17.3.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/dashboard/backend/image_service.py +0 -0
  58. {omni_cortex-1.17.3.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/dashboard/backend/logging_config.py +0 -0
  59. {omni_cortex-1.17.3.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/dashboard/backend/models.py +0 -0
  60. {omni_cortex-1.17.3.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/dashboard/backend/project_config.py +0 -0
  61. {omni_cortex-1.17.3.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/dashboard/backend/project_scanner.py +0 -0
  62. {omni_cortex-1.17.3.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/dashboard/backend/prompt_security.py +0 -0
  63. {omni_cortex-1.17.3.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/dashboard/backend/pyproject.toml +0 -0
  64. {omni_cortex-1.17.3.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/dashboard/backend/security.py +0 -0
  65. {omni_cortex-1.17.3.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/dashboard/backend/uv.lock +0 -0
  66. {omni_cortex-1.17.3.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/dashboard/backend/websocket_manager.py +0 -0
  67. {omni_cortex-1.17.3.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/hooks/post_tool_use.py +0 -0
  68. {omni_cortex-1.17.3.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/hooks/pre_tool_use.py +0 -0
  69. {omni_cortex-1.17.3.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/hooks/session_utils.py +0 -0
  70. {omni_cortex-1.17.3.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/hooks/stop.py +0 -0
  71. {omni_cortex-1.17.3.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/hooks/subagent_stop.py +0 -0
  72. {omni_cortex-1.17.3.dist-info → omni_cortex-1.17.4.dist-info}/WHEEL +0 -0
  73. {omni_cortex-1.17.3.dist-info → omni_cortex-1.17.4.dist-info}/entry_points.txt +0 -0
  74. {omni_cortex-1.17.3.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,284 +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. Bundled inside package (works for user and system installs)
60
- 2. Development: <project>/hooks/
61
- 3. Installed: <site-packages>/../share/omni-cortex/hooks/
62
- 4. Installed: <prefix>/share/omni-cortex/hooks/
63
- """
64
- # Try relative to package first (bundled location)
65
- import omni_cortex
66
- pkg_path = Path(omni_cortex.__file__).parent
67
-
68
- # Check bundled location inside package (most reliable for pip installs)
69
- bundled_hooks = pkg_path / "_bundled" / "hooks"
70
- if bundled_hooks.exists():
71
- return bundled_hooks
72
-
73
- # Try development location
74
- package_dir = get_package_dir()
75
- hooks_dir = package_dir / "hooks"
76
- if hooks_dir.exists():
77
- return hooks_dir
78
-
79
- # Check various installed locations (shared-data, for backwards compatibility)
80
- candidates = [
81
- pkg_path.parent.parent / "hooks",
82
- pkg_path.parent.parent / "share" / "omni-cortex" / "hooks",
83
- Path(sys.prefix) / "share" / "omni-cortex" / "hooks",
84
- Path(sys.base_prefix) / "share" / "omni-cortex" / "hooks",
85
- ]
86
-
87
- for candidate in candidates:
88
- if candidate.exists():
89
- return candidate
90
-
91
- # Fall back to package dir even if it doesn't exist
92
- return package_dir / "hooks"
93
-
94
-
95
- def setup_mcp_server() -> bool:
96
- """Add Omni Cortex MCP server to Claude's config."""
97
- config_path = get_claude_config_path()
98
-
99
- # Read existing config or create new
100
- if config_path.exists():
101
- with open(config_path) as f:
102
- config = json.load(f)
103
- else:
104
- config = {}
105
-
106
- # Ensure mcpServers exists
107
- if "mcpServers" not in config:
108
- config["mcpServers"] = {}
109
-
110
- # Add omni-cortex server
111
- config["mcpServers"]["omni-cortex"] = {
112
- "command": sys.executable,
113
- "args": ["-m", "omni_cortex.server"],
114
- }
115
-
116
- # Write config
117
- config_path.parent.mkdir(parents=True, exist_ok=True)
118
- with open(config_path, "w") as f:
119
- json.dump(config, f, indent=2)
120
-
121
- print(f" Added MCP server to {config_path}")
122
- return True
123
-
124
-
125
- def setup_hooks() -> bool:
126
- """Configure activity logging hooks in Claude's settings.json."""
127
- settings_path = get_claude_settings_path()
128
- hooks_dir = get_hooks_dir()
129
-
130
- if not hooks_dir.exists():
131
- print(f" Warning: hooks directory not found at {hooks_dir}")
132
- print(" Skipping hooks configuration.")
133
- return False
134
-
135
- # Read existing settings or create new
136
- if settings_path.exists():
137
- with open(settings_path) as f:
138
- settings = json.load(f)
139
- else:
140
- settings = {}
141
-
142
- # Ensure hooks section exists
143
- if "hooks" not in settings:
144
- settings["hooks"] = {}
145
-
146
- # Get Python executable
147
- python_exe = sys.executable
148
-
149
- # Helper to check if hook already exists (handles both old and new format)
150
- def hook_exists(hook_list, script_name):
151
- for h in hook_list:
152
- # Check old format
153
- cmd = str(h.get("command", ""))
154
- if "omni-cortex" in cmd or script_name in cmd:
155
- return True
156
- # Check new format (matcher + hooks array)
157
- if "hooks" in h:
158
- for inner_hook in h.get("hooks", []):
159
- inner_cmd = str(inner_hook.get("command", ""))
160
- if "omni-cortex" in inner_cmd or script_name in inner_cmd:
161
- return True
162
- return False
163
-
164
- # Configure hooks (new format with matcher and hooks array)
165
- hooks_config = {
166
- "PreToolUse": ("pre_tool_use.py", f'"{python_exe}" "{hooks_dir / "pre_tool_use.py"}"'),
167
- "PostToolUse": ("post_tool_use.py", f'"{python_exe}" "{hooks_dir / "post_tool_use.py"}"'),
168
- "Stop": ("stop.py", f'"{python_exe}" "{hooks_dir / "stop.py"}"'),
169
- }
170
-
171
- for hook_name, (script_name, command) in hooks_config.items():
172
- if hook_name not in settings["hooks"]:
173
- settings["hooks"][hook_name] = []
174
-
175
- if not hook_exists(settings["hooks"][hook_name], script_name):
176
- # New format: matcher + hooks array
177
- settings["hooks"][hook_name].append({
178
- "matcher": "",
179
- "hooks": [
180
- {
181
- "type": "command",
182
- "command": command,
183
- }
184
- ]
185
- })
186
-
187
- # Write settings
188
- settings_path.parent.mkdir(parents=True, exist_ok=True)
189
- with open(settings_path, "w") as f:
190
- json.dump(settings, f, indent=2)
191
-
192
- print(f" Configured hooks in {settings_path}")
193
- return True
194
-
195
-
196
- def uninstall() -> bool:
197
- """Remove Omni Cortex from Claude's configuration."""
198
- config_path = get_claude_config_path()
199
- settings_path = get_claude_settings_path()
200
-
201
- # Remove from MCP servers
202
- if config_path.exists():
203
- with open(config_path) as f:
204
- config = json.load(f)
205
-
206
- if "mcpServers" in config and "omni-cortex" in config["mcpServers"]:
207
- del config["mcpServers"]["omni-cortex"]
208
- with open(config_path, "w") as f:
209
- json.dump(config, f, indent=2)
210
- print(f" Removed MCP server from {config_path}")
211
-
212
- # Remove hooks
213
- if settings_path.exists():
214
- with open(settings_path) as f:
215
- settings = json.load(f)
216
-
217
- if "hooks" in settings:
218
- for hook_name in ["PreToolUse", "PostToolUse", "Stop"]:
219
- if hook_name in settings["hooks"]:
220
- settings["hooks"][hook_name] = [
221
- h for h in settings["hooks"][hook_name]
222
- if "omni-cortex" not in str(h.get("command", ""))
223
- and "pre_tool_use" not in str(h.get("command", ""))
224
- and "post_tool_use" not in str(h.get("command", ""))
225
- and "stop.py" not in str(h.get("command", ""))
226
- ]
227
-
228
- with open(settings_path, "w") as f:
229
- json.dump(settings, f, indent=2)
230
- print(f" Removed hooks from {settings_path}")
231
-
232
- return True
233
-
234
-
235
- def main():
236
- """Run the setup process."""
237
- args = sys.argv[1:]
238
-
239
- if "--uninstall" in args or "uninstall" in args:
240
- print("=" * 50)
241
- print("Omni Cortex MCP Uninstall")
242
- print("=" * 50)
243
- print()
244
- uninstall()
245
- print()
246
- print("Uninstall complete. Restart Claude Code.")
247
- return
248
-
249
- print("=" * 50)
250
- print("Omni Cortex MCP Setup")
251
- print("=" * 50)
252
- print()
253
-
254
- # Step 1: Setup MCP server
255
- print("Step 1: Configuring MCP server...")
256
- setup_mcp_server()
257
-
258
- print()
259
-
260
- # Step 2: Setup hooks
261
- print("Step 2: Configuring activity hooks...")
262
- setup_hooks()
263
-
264
- print()
265
- print("=" * 50)
266
- print("Setup complete!")
267
- print()
268
- print("Omni Cortex MCP is now ready to use.")
269
- print("Restart Claude Code for changes to take effect.")
270
- print()
271
- print("The MCP will automatically:")
272
- print(" - Log all tool calls to .omni-cortex/cortex.db")
273
- print(" - Provide cortex_remember/cortex_recall tools")
274
- print(" - Track sessions and activities")
275
- print()
276
- print("For semantic search, install:")
277
- print(" pip install sentence-transformers")
278
- print()
279
- print("To uninstall: omni-cortex-setup --uninstall")
280
- print("=" * 50)
281
-
282
-
283
- if __name__ == "__main__":
284
- main()
@@ -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
- ]