omni-cortex 1.17.1__py3-none-any.whl → 1.17.3__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 (87) hide show
  1. omni_cortex/__init__.py +3 -0
  2. omni_cortex/_bundled/dashboard/backend/.env.example +12 -0
  3. omni_cortex/_bundled/dashboard/backend/backfill_summaries.py +280 -0
  4. omni_cortex/_bundled/dashboard/backend/chat_service.py +631 -0
  5. omni_cortex/_bundled/dashboard/backend/database.py +1773 -0
  6. omni_cortex/_bundled/dashboard/backend/image_service.py +552 -0
  7. omni_cortex/_bundled/dashboard/backend/logging_config.py +122 -0
  8. omni_cortex/_bundled/dashboard/backend/main.py +1888 -0
  9. omni_cortex/_bundled/dashboard/backend/models.py +472 -0
  10. omni_cortex/_bundled/dashboard/backend/project_config.py +170 -0
  11. omni_cortex/_bundled/dashboard/backend/project_scanner.py +164 -0
  12. omni_cortex/_bundled/dashboard/backend/prompt_security.py +111 -0
  13. omni_cortex/_bundled/dashboard/backend/pyproject.toml +23 -0
  14. omni_cortex/_bundled/dashboard/backend/security.py +104 -0
  15. omni_cortex/_bundled/dashboard/backend/uv.lock +1110 -0
  16. omni_cortex/_bundled/dashboard/backend/websocket_manager.py +104 -0
  17. omni_cortex/_bundled/hooks/post_tool_use.py +497 -0
  18. omni_cortex/_bundled/hooks/pre_tool_use.py +277 -0
  19. omni_cortex/_bundled/hooks/session_utils.py +186 -0
  20. omni_cortex/_bundled/hooks/stop.py +219 -0
  21. omni_cortex/_bundled/hooks/subagent_stop.py +120 -0
  22. omni_cortex/_bundled/hooks/user_prompt.py +220 -0
  23. omni_cortex/categorization/__init__.py +9 -0
  24. omni_cortex/categorization/auto_tags.py +166 -0
  25. omni_cortex/categorization/auto_type.py +165 -0
  26. omni_cortex/config.py +141 -0
  27. omni_cortex/dashboard.py +238 -0
  28. omni_cortex/database/__init__.py +24 -0
  29. omni_cortex/database/connection.py +137 -0
  30. omni_cortex/database/migrations.py +210 -0
  31. omni_cortex/database/schema.py +212 -0
  32. omni_cortex/database/sync.py +421 -0
  33. omni_cortex/decay/__init__.py +7 -0
  34. omni_cortex/decay/importance.py +147 -0
  35. omni_cortex/embeddings/__init__.py +35 -0
  36. omni_cortex/embeddings/local.py +442 -0
  37. omni_cortex/models/__init__.py +20 -0
  38. omni_cortex/models/activity.py +265 -0
  39. omni_cortex/models/agent.py +144 -0
  40. omni_cortex/models/memory.py +395 -0
  41. omni_cortex/models/relationship.py +206 -0
  42. omni_cortex/models/session.py +290 -0
  43. omni_cortex/resources/__init__.py +1 -0
  44. omni_cortex/search/__init__.py +22 -0
  45. omni_cortex/search/hybrid.py +197 -0
  46. omni_cortex/search/keyword.py +204 -0
  47. omni_cortex/search/ranking.py +127 -0
  48. omni_cortex/search/semantic.py +232 -0
  49. omni_cortex/server.py +360 -0
  50. omni_cortex/setup.py +284 -0
  51. omni_cortex/tools/__init__.py +13 -0
  52. omni_cortex/tools/activities.py +453 -0
  53. omni_cortex/tools/memories.py +536 -0
  54. omni_cortex/tools/sessions.py +311 -0
  55. omni_cortex/tools/utilities.py +477 -0
  56. omni_cortex/utils/__init__.py +13 -0
  57. omni_cortex/utils/formatting.py +282 -0
  58. omni_cortex/utils/ids.py +72 -0
  59. omni_cortex/utils/timestamps.py +129 -0
  60. omni_cortex/utils/truncation.py +111 -0
  61. {omni_cortex-1.17.1.dist-info → omni_cortex-1.17.3.dist-info}/METADATA +1 -1
  62. omni_cortex-1.17.3.dist-info/RECORD +86 -0
  63. omni_cortex-1.17.1.dist-info/RECORD +0 -26
  64. {omni_cortex-1.17.1.data → omni_cortex-1.17.3.data}/data/share/omni-cortex/dashboard/backend/.env.example +0 -0
  65. {omni_cortex-1.17.1.data → omni_cortex-1.17.3.data}/data/share/omni-cortex/dashboard/backend/backfill_summaries.py +0 -0
  66. {omni_cortex-1.17.1.data → omni_cortex-1.17.3.data}/data/share/omni-cortex/dashboard/backend/chat_service.py +0 -0
  67. {omni_cortex-1.17.1.data → omni_cortex-1.17.3.data}/data/share/omni-cortex/dashboard/backend/database.py +0 -0
  68. {omni_cortex-1.17.1.data → omni_cortex-1.17.3.data}/data/share/omni-cortex/dashboard/backend/image_service.py +0 -0
  69. {omni_cortex-1.17.1.data → omni_cortex-1.17.3.data}/data/share/omni-cortex/dashboard/backend/logging_config.py +0 -0
  70. {omni_cortex-1.17.1.data → omni_cortex-1.17.3.data}/data/share/omni-cortex/dashboard/backend/main.py +0 -0
  71. {omni_cortex-1.17.1.data → omni_cortex-1.17.3.data}/data/share/omni-cortex/dashboard/backend/models.py +0 -0
  72. {omni_cortex-1.17.1.data → omni_cortex-1.17.3.data}/data/share/omni-cortex/dashboard/backend/project_config.py +0 -0
  73. {omni_cortex-1.17.1.data → omni_cortex-1.17.3.data}/data/share/omni-cortex/dashboard/backend/project_scanner.py +0 -0
  74. {omni_cortex-1.17.1.data → omni_cortex-1.17.3.data}/data/share/omni-cortex/dashboard/backend/prompt_security.py +0 -0
  75. {omni_cortex-1.17.1.data → omni_cortex-1.17.3.data}/data/share/omni-cortex/dashboard/backend/pyproject.toml +0 -0
  76. {omni_cortex-1.17.1.data → omni_cortex-1.17.3.data}/data/share/omni-cortex/dashboard/backend/security.py +0 -0
  77. {omni_cortex-1.17.1.data → omni_cortex-1.17.3.data}/data/share/omni-cortex/dashboard/backend/uv.lock +0 -0
  78. {omni_cortex-1.17.1.data → omni_cortex-1.17.3.data}/data/share/omni-cortex/dashboard/backend/websocket_manager.py +0 -0
  79. {omni_cortex-1.17.1.data → omni_cortex-1.17.3.data}/data/share/omni-cortex/hooks/post_tool_use.py +0 -0
  80. {omni_cortex-1.17.1.data → omni_cortex-1.17.3.data}/data/share/omni-cortex/hooks/pre_tool_use.py +0 -0
  81. {omni_cortex-1.17.1.data → omni_cortex-1.17.3.data}/data/share/omni-cortex/hooks/session_utils.py +0 -0
  82. {omni_cortex-1.17.1.data → omni_cortex-1.17.3.data}/data/share/omni-cortex/hooks/stop.py +0 -0
  83. {omni_cortex-1.17.1.data → omni_cortex-1.17.3.data}/data/share/omni-cortex/hooks/subagent_stop.py +0 -0
  84. {omni_cortex-1.17.1.data → omni_cortex-1.17.3.data}/data/share/omni-cortex/hooks/user_prompt.py +0 -0
  85. {omni_cortex-1.17.1.dist-info → omni_cortex-1.17.3.dist-info}/WHEEL +0 -0
  86. {omni_cortex-1.17.1.dist-info → omni_cortex-1.17.3.dist-info}/entry_points.txt +0 -0
  87. {omni_cortex-1.17.1.dist-info → omni_cortex-1.17.3.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,210 @@
1
+ """Database migration management for Omni Cortex."""
2
+
3
+ import sqlite3
4
+ from typing import Optional
5
+ from pathlib import Path
6
+
7
+ from .schema import SCHEMA_VERSION, get_schema_sql
8
+ from .connection import get_connection
9
+ from ..utils.timestamps import now_iso
10
+
11
+
12
+ # Migration definitions: version -> SQL
13
+ MIGRATIONS: dict[str, str] = {
14
+ # Command analytics columns for slash command/skill tracking
15
+ "1.1": """
16
+ -- Add command analytics columns to activities table
17
+ ALTER TABLE activities ADD COLUMN command_name TEXT;
18
+ ALTER TABLE activities ADD COLUMN command_scope TEXT;
19
+ ALTER TABLE activities ADD COLUMN mcp_server TEXT;
20
+ ALTER TABLE activities ADD COLUMN skill_name TEXT;
21
+
22
+ -- Create indexes for new columns
23
+ CREATE INDEX IF NOT EXISTS idx_activities_command ON activities(command_name);
24
+ CREATE INDEX IF NOT EXISTS idx_activities_mcp ON activities(mcp_server);
25
+ CREATE INDEX IF NOT EXISTS idx_activities_skill ON activities(skill_name);
26
+ """,
27
+ # Natural language summary columns for activity display
28
+ "1.2": """
29
+ -- Add natural language summary columns to activities table
30
+ ALTER TABLE activities ADD COLUMN summary TEXT;
31
+ ALTER TABLE activities ADD COLUMN summary_detail TEXT;
32
+ """,
33
+ # Duration tracking columns for concrete time analysis
34
+ "1.3": """
35
+ -- Add duration tracking to sessions table
36
+ ALTER TABLE sessions ADD COLUMN duration_ms INTEGER;
37
+
38
+ -- Add duration tracking to session_summaries table
39
+ ALTER TABLE session_summaries ADD COLUMN duration_ms INTEGER;
40
+ ALTER TABLE session_summaries ADD COLUMN tool_duration_breakdown TEXT;
41
+
42
+ -- Create index for duration queries
43
+ CREATE INDEX IF NOT EXISTS idx_activities_duration ON activities(duration_ms);
44
+ CREATE INDEX IF NOT EXISTS idx_sessions_duration ON sessions(duration_ms);
45
+ """,
46
+ # User message tracking for style analysis
47
+ "1.4": """
48
+ -- User messages table for tracking all user prompts
49
+ CREATE TABLE IF NOT EXISTS user_messages (
50
+ id TEXT PRIMARY KEY, -- msg_{timestamp}_{random}
51
+ session_id TEXT,
52
+ timestamp TEXT NOT NULL, -- ISO 8601
53
+ content TEXT NOT NULL, -- The full user message
54
+ word_count INTEGER,
55
+ char_count INTEGER,
56
+ line_count INTEGER,
57
+ has_code_blocks INTEGER DEFAULT 0,
58
+ has_questions INTEGER DEFAULT 0,
59
+ has_commands INTEGER DEFAULT 0, -- Starts with /
60
+ tone_indicators TEXT, -- JSON: detected tone markers
61
+ project_path TEXT,
62
+ metadata TEXT, -- JSON for extensibility
63
+ FOREIGN KEY (session_id) REFERENCES sessions(id)
64
+ );
65
+
66
+ -- User style profile for aggregated style analysis
67
+ CREATE TABLE IF NOT EXISTS user_style_profiles (
68
+ id TEXT PRIMARY KEY, -- profile_{timestamp}_{random}
69
+ project_path TEXT, -- NULL for global profile
70
+ total_messages INTEGER DEFAULT 0,
71
+ avg_word_count REAL,
72
+ avg_char_count REAL,
73
+ common_phrases TEXT, -- JSON array of frequent phrases
74
+ vocabulary_richness REAL, -- Type-token ratio
75
+ formality_score REAL, -- 0-100 scale
76
+ question_frequency REAL, -- % of messages with questions
77
+ command_frequency REAL, -- % of messages starting with /
78
+ code_block_frequency REAL, -- % with code blocks
79
+ punctuation_style TEXT, -- JSON: punctuation patterns
80
+ greeting_patterns TEXT, -- JSON: how user starts conversations
81
+ instruction_style TEXT, -- JSON: how user gives instructions
82
+ sample_messages TEXT, -- JSON array of representative samples
83
+ created_at TEXT NOT NULL,
84
+ updated_at TEXT NOT NULL,
85
+ metadata TEXT
86
+ );
87
+
88
+ -- Indexes for user message queries
89
+ CREATE INDEX IF NOT EXISTS idx_user_messages_session ON user_messages(session_id);
90
+ CREATE INDEX IF NOT EXISTS idx_user_messages_timestamp ON user_messages(timestamp DESC);
91
+ CREATE INDEX IF NOT EXISTS idx_user_messages_project ON user_messages(project_path);
92
+ CREATE INDEX IF NOT EXISTS idx_user_style_project ON user_style_profiles(project_path);
93
+ """,
94
+ }
95
+
96
+
97
+ def get_current_version(conn: sqlite3.Connection) -> Optional[str]:
98
+ """Get the current schema version from the database."""
99
+ try:
100
+ cursor = conn.execute(
101
+ "SELECT version FROM schema_migrations ORDER BY applied_at DESC LIMIT 1"
102
+ )
103
+ row = cursor.fetchone()
104
+ return row[0] if row else None
105
+ except sqlite3.OperationalError:
106
+ # Table doesn't exist yet
107
+ return None
108
+
109
+
110
+ def strip_sql_comments(sql: str) -> str:
111
+ """Strip SQL comments from a statement while preserving inline comments in strings."""
112
+ import re
113
+ lines = sql.split('\n')
114
+ cleaned_lines = []
115
+ for line in lines:
116
+ # Remove line comments (-- ...) but only if not inside a string
117
+ # Simple approach: just strip everything after -- if not in CREATE TABLE definition
118
+ # For CREATE TABLE, we need to keep the structure
119
+ stripped = line.strip()
120
+ if stripped.startswith('--'):
121
+ continue # Skip pure comment lines
122
+ # Keep lines that have SQL content (even if they have trailing comments)
123
+ cleaned_lines.append(line)
124
+ return '\n'.join(cleaned_lines)
125
+
126
+
127
+ def apply_migration(conn: sqlite3.Connection, version: str, sql: str) -> None:
128
+ """Apply a single migration.
129
+
130
+ Handles ALTER TABLE ADD COLUMN gracefully - if column exists, skips it.
131
+ """
132
+ # First, strip pure comment lines from the SQL
133
+ sql = strip_sql_comments(sql)
134
+
135
+ # Split into individual statements and apply each
136
+ for statement in sql.strip().split(';'):
137
+ statement = statement.strip()
138
+ if not statement:
139
+ continue
140
+
141
+ # Skip if the remaining statement is just whitespace or pure comments
142
+ non_comment_content = '\n'.join(
143
+ line for line in statement.split('\n')
144
+ if line.strip() and not line.strip().startswith('--')
145
+ ).strip()
146
+ if not non_comment_content:
147
+ continue
148
+
149
+ try:
150
+ conn.execute(statement)
151
+ conn.commit() # Commit each statement so next one sees the change
152
+ except sqlite3.OperationalError as e:
153
+ error_msg = str(e).lower()
154
+ # Ignore "duplicate column" errors - column already exists
155
+ if "duplicate column" in error_msg:
156
+ continue
157
+ # Ignore "index already exists" errors
158
+ if "already exists" in error_msg:
159
+ continue
160
+ # Ignore "no such column" for indexes on columns that may not exist yet
161
+ # (will be created in a later migration)
162
+ if "no such column" in error_msg and "CREATE INDEX" in statement.upper():
163
+ continue
164
+ # Ignore "table already exists" errors
165
+ if "already exists" in error_msg:
166
+ continue
167
+ raise
168
+
169
+ conn.execute(
170
+ "INSERT INTO schema_migrations (version, applied_at) VALUES (?, ?)",
171
+ (version, now_iso())
172
+ )
173
+ conn.commit()
174
+
175
+
176
+ def migrate(db_path: Optional[Path] = None, is_global: bool = False) -> str:
177
+ """Run all pending migrations.
178
+
179
+ Returns:
180
+ The final schema version
181
+ """
182
+ conn = get_connection(db_path, is_global)
183
+ current = get_current_version(conn)
184
+
185
+ if current is None:
186
+ # Fresh database - apply full schema
187
+ conn.executescript(get_schema_sql())
188
+ conn.execute(
189
+ "INSERT INTO schema_migrations (version, applied_at) VALUES (?, ?)",
190
+ (SCHEMA_VERSION, now_iso())
191
+ )
192
+ conn.commit()
193
+ return SCHEMA_VERSION
194
+
195
+ # Apply pending migrations in order
196
+ versions = sorted(MIGRATIONS.keys())
197
+ for version in versions:
198
+ if version > current:
199
+ apply_migration(conn, version, MIGRATIONS[version])
200
+ current = version
201
+
202
+ return current
203
+
204
+
205
+ def needs_migration(conn: sqlite3.Connection) -> bool:
206
+ """Check if database needs migration."""
207
+ current = get_current_version(conn)
208
+ if current is None:
209
+ return True
210
+ return any(v > current for v in MIGRATIONS.keys())
@@ -0,0 +1,212 @@
1
+ """Database schema definitions for Omni Cortex."""
2
+
3
+ SCHEMA_VERSION = "1.0"
4
+
5
+ # Main schema SQL
6
+ SCHEMA_SQL = """
7
+ -- ============================================
8
+ -- OMNI CORTEX MCP DATABASE SCHEMA v1.0
9
+ -- ============================================
10
+
11
+ -- Sessions Table
12
+ CREATE TABLE IF NOT EXISTS sessions (
13
+ id TEXT PRIMARY KEY, -- sess_{timestamp}_{random}
14
+ project_path TEXT NOT NULL,
15
+ started_at TEXT NOT NULL, -- ISO 8601
16
+ ended_at TEXT,
17
+ summary TEXT,
18
+ tags TEXT, -- JSON array
19
+ metadata TEXT -- JSON object
20
+ );
21
+
22
+ -- Agents Table
23
+ CREATE TABLE IF NOT EXISTS agents (
24
+ id TEXT PRIMARY KEY, -- Agent ID from Claude Code
25
+ name TEXT,
26
+ type TEXT NOT NULL DEFAULT 'main', -- main, subagent, tool
27
+ first_seen TEXT NOT NULL,
28
+ last_seen TEXT NOT NULL,
29
+ total_activities INTEGER DEFAULT 0,
30
+ metadata TEXT
31
+ );
32
+
33
+ -- Activities Table (Layer 1)
34
+ CREATE TABLE IF NOT EXISTS activities (
35
+ id TEXT PRIMARY KEY, -- act_{timestamp}_{random}
36
+ session_id TEXT,
37
+ agent_id TEXT,
38
+ timestamp TEXT NOT NULL, -- ISO 8601 with timezone
39
+ event_type TEXT NOT NULL, -- pre_tool_use, post_tool_use, etc.
40
+ tool_name TEXT,
41
+ tool_input TEXT, -- JSON (truncated to 10KB)
42
+ tool_output TEXT, -- JSON (truncated to 10KB)
43
+ duration_ms INTEGER,
44
+ success INTEGER DEFAULT 1,
45
+ error_message TEXT,
46
+ project_path TEXT,
47
+ file_path TEXT,
48
+ metadata TEXT,
49
+ -- Command analytics columns (v1.1)
50
+ command_name TEXT,
51
+ command_scope TEXT,
52
+ mcp_server TEXT,
53
+ skill_name TEXT,
54
+ -- Natural language summaries (v1.2)
55
+ summary TEXT,
56
+ summary_detail TEXT,
57
+ FOREIGN KEY (session_id) REFERENCES sessions(id),
58
+ FOREIGN KEY (agent_id) REFERENCES agents(id)
59
+ );
60
+
61
+ -- Memories Table (Layer 2)
62
+ CREATE TABLE IF NOT EXISTS memories (
63
+ id TEXT PRIMARY KEY, -- mem_{timestamp}_{random}
64
+ content TEXT NOT NULL,
65
+ type TEXT NOT NULL DEFAULT 'general',
66
+ tags TEXT, -- JSON array
67
+ context TEXT,
68
+
69
+ -- Timestamps
70
+ created_at TEXT NOT NULL,
71
+ updated_at TEXT NOT NULL,
72
+ last_accessed TEXT NOT NULL,
73
+ last_verified TEXT,
74
+
75
+ -- Usage
76
+ access_count INTEGER DEFAULT 0,
77
+
78
+ -- Importance/Decay
79
+ importance_score REAL DEFAULT 50.0, -- 0-100
80
+ manual_importance INTEGER, -- User override
81
+
82
+ -- Freshness
83
+ status TEXT DEFAULT 'fresh', -- fresh, needs_review, outdated, archived
84
+
85
+ -- Attribution
86
+ source_session_id TEXT,
87
+ source_agent_id TEXT,
88
+ source_activity_id TEXT,
89
+
90
+ -- Project
91
+ project_path TEXT,
92
+ file_context TEXT, -- JSON array
93
+
94
+ -- Embedding
95
+ has_embedding INTEGER DEFAULT 0,
96
+
97
+ metadata TEXT,
98
+
99
+ FOREIGN KEY (source_session_id) REFERENCES sessions(id),
100
+ FOREIGN KEY (source_agent_id) REFERENCES agents(id),
101
+ FOREIGN KEY (source_activity_id) REFERENCES activities(id)
102
+ );
103
+
104
+ -- FTS5 for Full-Text Search
105
+ CREATE VIRTUAL TABLE IF NOT EXISTS memories_fts USING fts5(
106
+ content, context, tags,
107
+ content=memories,
108
+ content_rowid=rowid,
109
+ tokenize='porter unicode61'
110
+ );
111
+
112
+ -- Triggers to keep FTS in sync with memories table
113
+ CREATE TRIGGER IF NOT EXISTS memories_ai AFTER INSERT ON memories BEGIN
114
+ INSERT INTO memories_fts(rowid, content, context, tags)
115
+ VALUES (NEW.rowid, NEW.content, NEW.context, NEW.tags);
116
+ END;
117
+
118
+ CREATE TRIGGER IF NOT EXISTS memories_ad AFTER DELETE ON memories BEGIN
119
+ INSERT INTO memories_fts(memories_fts, rowid, content, context, tags)
120
+ VALUES ('delete', OLD.rowid, OLD.content, OLD.context, OLD.tags);
121
+ END;
122
+
123
+ CREATE TRIGGER IF NOT EXISTS memories_au AFTER UPDATE ON memories BEGIN
124
+ INSERT INTO memories_fts(memories_fts, rowid, content, context, tags)
125
+ VALUES ('delete', OLD.rowid, OLD.content, OLD.context, OLD.tags);
126
+ INSERT INTO memories_fts(rowid, content, context, tags)
127
+ VALUES (NEW.rowid, NEW.content, NEW.context, NEW.tags);
128
+ END;
129
+
130
+ -- Memory Relationships
131
+ CREATE TABLE IF NOT EXISTS memory_relationships (
132
+ id TEXT PRIMARY KEY,
133
+ source_memory_id TEXT NOT NULL,
134
+ target_memory_id TEXT NOT NULL,
135
+ relationship_type TEXT NOT NULL, -- related_to, supersedes, derived_from, contradicts
136
+ strength REAL DEFAULT 1.0,
137
+ created_at TEXT NOT NULL,
138
+ metadata TEXT,
139
+ FOREIGN KEY (source_memory_id) REFERENCES memories(id) ON DELETE CASCADE,
140
+ FOREIGN KEY (target_memory_id) REFERENCES memories(id) ON DELETE CASCADE,
141
+ UNIQUE(source_memory_id, target_memory_id, relationship_type)
142
+ );
143
+
144
+ -- Activity-Memory Links
145
+ CREATE TABLE IF NOT EXISTS activity_memory_links (
146
+ activity_id TEXT NOT NULL,
147
+ memory_id TEXT NOT NULL,
148
+ link_type TEXT NOT NULL, -- created, accessed, updated, referenced
149
+ created_at TEXT NOT NULL,
150
+ PRIMARY KEY (activity_id, memory_id, link_type),
151
+ FOREIGN KEY (activity_id) REFERENCES activities(id) ON DELETE CASCADE,
152
+ FOREIGN KEY (memory_id) REFERENCES memories(id) ON DELETE CASCADE
153
+ );
154
+
155
+ -- Embeddings
156
+ CREATE TABLE IF NOT EXISTS embeddings (
157
+ id TEXT PRIMARY KEY,
158
+ memory_id TEXT NOT NULL UNIQUE,
159
+ model_name TEXT NOT NULL, -- 'all-MiniLM-L6-v2'
160
+ vector BLOB NOT NULL, -- float32 array
161
+ dimensions INTEGER NOT NULL, -- 384
162
+ created_at TEXT NOT NULL,
163
+ FOREIGN KEY (memory_id) REFERENCES memories(id) ON DELETE CASCADE
164
+ );
165
+
166
+ -- Session Summaries
167
+ CREATE TABLE IF NOT EXISTS session_summaries (
168
+ id TEXT PRIMARY KEY,
169
+ session_id TEXT NOT NULL UNIQUE,
170
+ key_learnings TEXT, -- JSON array
171
+ key_decisions TEXT, -- JSON array
172
+ key_errors TEXT, -- JSON array
173
+ files_modified TEXT, -- JSON array
174
+ tools_used TEXT, -- JSON object
175
+ total_activities INTEGER DEFAULT 0,
176
+ total_memories_created INTEGER DEFAULT 0,
177
+ created_at TEXT NOT NULL,
178
+ FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE
179
+ );
180
+
181
+ -- Configuration
182
+ CREATE TABLE IF NOT EXISTS config (
183
+ key TEXT PRIMARY KEY,
184
+ value TEXT NOT NULL,
185
+ updated_at TEXT NOT NULL
186
+ );
187
+
188
+ -- Schema Migrations
189
+ CREATE TABLE IF NOT EXISTS schema_migrations (
190
+ version TEXT PRIMARY KEY,
191
+ applied_at TEXT NOT NULL
192
+ );
193
+
194
+ -- Indexes
195
+ CREATE INDEX IF NOT EXISTS idx_activities_session ON activities(session_id);
196
+ CREATE INDEX IF NOT EXISTS idx_activities_agent ON activities(agent_id);
197
+ CREATE INDEX IF NOT EXISTS idx_activities_timestamp ON activities(timestamp DESC);
198
+ CREATE INDEX IF NOT EXISTS idx_activities_tool ON activities(tool_name);
199
+ CREATE INDEX IF NOT EXISTS idx_memories_type ON memories(type);
200
+ CREATE INDEX IF NOT EXISTS idx_memories_status ON memories(status);
201
+ CREATE INDEX IF NOT EXISTS idx_memories_project ON memories(project_path);
202
+ CREATE INDEX IF NOT EXISTS idx_memories_importance ON memories(importance_score DESC);
203
+ CREATE INDEX IF NOT EXISTS idx_memories_accessed ON memories(last_accessed DESC);
204
+ CREATE INDEX IF NOT EXISTS idx_memories_created ON memories(created_at DESC);
205
+ CREATE INDEX IF NOT EXISTS idx_relationships_source ON memory_relationships(source_memory_id);
206
+ CREATE INDEX IF NOT EXISTS idx_relationships_target ON memory_relationships(target_memory_id);
207
+ """
208
+
209
+
210
+ def get_schema_sql() -> str:
211
+ """Get the complete schema SQL."""
212
+ return SCHEMA_SQL