omni-cortex 1.0.4__py3-none-any.whl → 1.3.0__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-1.3.0.data/data/share/omni-cortex/dashboard/backend/chat_service.py +308 -0
- {omni_cortex-1.0.4.data → omni_cortex-1.3.0.data}/data/share/omni-cortex/dashboard/backend/database.py +286 -0
- omni_cortex-1.3.0.data/data/share/omni-cortex/dashboard/backend/image_service.py +543 -0
- omni_cortex-1.3.0.data/data/share/omni-cortex/dashboard/backend/logging_config.py +92 -0
- {omni_cortex-1.0.4.data → omni_cortex-1.3.0.data}/data/share/omni-cortex/dashboard/backend/main.py +385 -42
- {omni_cortex-1.0.4.data → omni_cortex-1.3.0.data}/data/share/omni-cortex/dashboard/backend/models.py +93 -0
- omni_cortex-1.3.0.data/data/share/omni-cortex/dashboard/backend/project_config.py +170 -0
- {omni_cortex-1.0.4.data → omni_cortex-1.3.0.data}/data/share/omni-cortex/dashboard/backend/project_scanner.py +45 -22
- {omni_cortex-1.0.4.data → omni_cortex-1.3.0.data}/data/share/omni-cortex/dashboard/backend/uv.lock +414 -1
- {omni_cortex-1.0.4.dist-info → omni_cortex-1.3.0.dist-info}/METADATA +26 -2
- omni_cortex-1.3.0.dist-info/RECORD +20 -0
- omni_cortex-1.0.4.data/data/share/omni-cortex/dashboard/backend/chat_service.py +0 -140
- omni_cortex-1.0.4.dist-info/RECORD +0 -17
- {omni_cortex-1.0.4.data → omni_cortex-1.3.0.data}/data/share/omni-cortex/dashboard/backend/pyproject.toml +0 -0
- {omni_cortex-1.0.4.data → omni_cortex-1.3.0.data}/data/share/omni-cortex/dashboard/backend/websocket_manager.py +0 -0
- {omni_cortex-1.0.4.data → omni_cortex-1.3.0.data}/data/share/omni-cortex/hooks/post_tool_use.py +0 -0
- {omni_cortex-1.0.4.data → omni_cortex-1.3.0.data}/data/share/omni-cortex/hooks/pre_tool_use.py +0 -0
- {omni_cortex-1.0.4.data → omni_cortex-1.3.0.data}/data/share/omni-cortex/hooks/stop.py +0 -0
- {omni_cortex-1.0.4.data → omni_cortex-1.3.0.data}/data/share/omni-cortex/hooks/subagent_stop.py +0 -0
- {omni_cortex-1.0.4.dist-info → omni_cortex-1.3.0.dist-info}/WHEEL +0 -0
- {omni_cortex-1.0.4.dist-info → omni_cortex-1.3.0.dist-info}/entry_points.txt +0 -0
- {omni_cortex-1.0.4.dist-info → omni_cortex-1.3.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
"""Project configuration manager for user preferences."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import platform
|
|
5
|
+
from datetime import datetime
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Optional
|
|
8
|
+
|
|
9
|
+
from pydantic import BaseModel
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class RegisteredProject(BaseModel):
|
|
13
|
+
"""A manually registered project."""
|
|
14
|
+
|
|
15
|
+
path: str
|
|
16
|
+
display_name: Optional[str] = None
|
|
17
|
+
added_at: datetime
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class RecentProject(BaseModel):
|
|
21
|
+
"""A recently accessed project."""
|
|
22
|
+
|
|
23
|
+
path: str
|
|
24
|
+
last_accessed: datetime
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class ProjectConfig(BaseModel):
|
|
28
|
+
"""User project configuration."""
|
|
29
|
+
|
|
30
|
+
version: int = 1
|
|
31
|
+
scan_directories: list[str] = []
|
|
32
|
+
registered_projects: list[RegisteredProject] = []
|
|
33
|
+
favorites: list[str] = []
|
|
34
|
+
recent: list[RecentProject] = []
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
CONFIG_PATH = Path.home() / ".omni-cortex" / "projects.json"
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def get_default_scan_dirs() -> list[str]:
|
|
41
|
+
"""Return platform-appropriate default scan directories."""
|
|
42
|
+
home = Path.home()
|
|
43
|
+
|
|
44
|
+
dirs = [
|
|
45
|
+
str(home / "projects"),
|
|
46
|
+
str(home / "Projects"),
|
|
47
|
+
str(home / "code"),
|
|
48
|
+
str(home / "Code"),
|
|
49
|
+
str(home / "dev"),
|
|
50
|
+
str(home / "workspace"),
|
|
51
|
+
]
|
|
52
|
+
|
|
53
|
+
if platform.system() == "Windows":
|
|
54
|
+
dirs.insert(0, "D:/Projects")
|
|
55
|
+
|
|
56
|
+
return [d for d in dirs if Path(d).exists()]
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def load_config() -> ProjectConfig:
|
|
60
|
+
"""Load config from disk, creating defaults if missing."""
|
|
61
|
+
if CONFIG_PATH.exists():
|
|
62
|
+
try:
|
|
63
|
+
data = json.loads(CONFIG_PATH.read_text(encoding="utf-8"))
|
|
64
|
+
return ProjectConfig(**data)
|
|
65
|
+
except Exception:
|
|
66
|
+
pass
|
|
67
|
+
|
|
68
|
+
# Create default config
|
|
69
|
+
config = ProjectConfig(scan_directories=get_default_scan_dirs())
|
|
70
|
+
save_config(config)
|
|
71
|
+
return config
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def save_config(config: ProjectConfig) -> None:
|
|
75
|
+
"""Save config to disk."""
|
|
76
|
+
CONFIG_PATH.parent.mkdir(parents=True, exist_ok=True)
|
|
77
|
+
CONFIG_PATH.write_text(config.model_dump_json(indent=2), encoding="utf-8")
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def add_registered_project(path: str, display_name: Optional[str] = None) -> bool:
|
|
81
|
+
"""Register a new project by path."""
|
|
82
|
+
config = load_config()
|
|
83
|
+
|
|
84
|
+
# Validate path has cortex.db
|
|
85
|
+
db_path = Path(path) / ".omni-cortex" / "cortex.db"
|
|
86
|
+
if not db_path.exists():
|
|
87
|
+
return False
|
|
88
|
+
|
|
89
|
+
# Check if already registered
|
|
90
|
+
if any(p.path == path for p in config.registered_projects):
|
|
91
|
+
return False
|
|
92
|
+
|
|
93
|
+
config.registered_projects.append(
|
|
94
|
+
RegisteredProject(path=path, display_name=display_name, added_at=datetime.now())
|
|
95
|
+
)
|
|
96
|
+
save_config(config)
|
|
97
|
+
return True
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def remove_registered_project(path: str) -> bool:
|
|
101
|
+
"""Remove a registered project."""
|
|
102
|
+
config = load_config()
|
|
103
|
+
original_len = len(config.registered_projects)
|
|
104
|
+
config.registered_projects = [
|
|
105
|
+
p for p in config.registered_projects if p.path != path
|
|
106
|
+
]
|
|
107
|
+
|
|
108
|
+
if len(config.registered_projects) < original_len:
|
|
109
|
+
save_config(config)
|
|
110
|
+
return True
|
|
111
|
+
return False
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def toggle_favorite(path: str) -> bool:
|
|
115
|
+
"""Toggle favorite status for a project. Returns new favorite status."""
|
|
116
|
+
config = load_config()
|
|
117
|
+
|
|
118
|
+
if path in config.favorites:
|
|
119
|
+
config.favorites.remove(path)
|
|
120
|
+
is_favorite = False
|
|
121
|
+
else:
|
|
122
|
+
config.favorites.append(path)
|
|
123
|
+
is_favorite = True
|
|
124
|
+
|
|
125
|
+
save_config(config)
|
|
126
|
+
return is_favorite
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def update_recent(path: str) -> None:
|
|
130
|
+
"""Update recent projects list."""
|
|
131
|
+
config = load_config()
|
|
132
|
+
|
|
133
|
+
# Remove if already in list
|
|
134
|
+
config.recent = [r for r in config.recent if r.path != path]
|
|
135
|
+
|
|
136
|
+
# Add to front
|
|
137
|
+
config.recent.insert(0, RecentProject(path=path, last_accessed=datetime.now()))
|
|
138
|
+
|
|
139
|
+
# Keep only last 10
|
|
140
|
+
config.recent = config.recent[:10]
|
|
141
|
+
|
|
142
|
+
save_config(config)
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def add_scan_directory(directory: str) -> bool:
|
|
146
|
+
"""Add a directory to scan list."""
|
|
147
|
+
config = load_config()
|
|
148
|
+
|
|
149
|
+
# Expand user path
|
|
150
|
+
expanded = str(Path(directory).expanduser())
|
|
151
|
+
|
|
152
|
+
if not Path(expanded).is_dir():
|
|
153
|
+
return False
|
|
154
|
+
|
|
155
|
+
if expanded not in config.scan_directories:
|
|
156
|
+
config.scan_directories.append(expanded)
|
|
157
|
+
save_config(config)
|
|
158
|
+
return True
|
|
159
|
+
return False
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def remove_scan_directory(directory: str) -> bool:
|
|
163
|
+
"""Remove a directory from scan list."""
|
|
164
|
+
config = load_config()
|
|
165
|
+
|
|
166
|
+
if directory in config.scan_directories:
|
|
167
|
+
config.scan_directories.remove(directory)
|
|
168
|
+
save_config(config)
|
|
169
|
+
return True
|
|
170
|
+
return False
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
"""Scanner to discover all omni-cortex databases on the system."""
|
|
2
2
|
|
|
3
|
-
import os
|
|
4
3
|
import sqlite3
|
|
5
4
|
from datetime import datetime
|
|
6
5
|
from pathlib import Path
|
|
7
6
|
|
|
8
7
|
from models import ProjectInfo
|
|
8
|
+
from project_config import load_config
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
def get_global_db_path() -> Path:
|
|
@@ -65,54 +65,70 @@ def scan_projects() -> list[ProjectInfo]:
|
|
|
65
65
|
projects: list[ProjectInfo] = []
|
|
66
66
|
seen_paths: set[str] = set()
|
|
67
67
|
|
|
68
|
+
# Load user config
|
|
69
|
+
config = load_config()
|
|
70
|
+
|
|
68
71
|
# 1. Add global index if exists
|
|
69
72
|
global_path = get_global_db_path()
|
|
70
73
|
if global_path.exists():
|
|
71
74
|
stat = global_path.stat()
|
|
75
|
+
global_project_path = str(global_path.parent)
|
|
72
76
|
projects.append(
|
|
73
77
|
ProjectInfo(
|
|
74
78
|
name="Global Index",
|
|
75
|
-
path=
|
|
79
|
+
path=global_project_path,
|
|
76
80
|
db_path=str(global_path),
|
|
77
81
|
last_modified=datetime.fromtimestamp(stat.st_mtime),
|
|
78
82
|
memory_count=get_memory_count(global_path),
|
|
79
83
|
is_global=True,
|
|
84
|
+
is_favorite=global_project_path in config.favorites,
|
|
80
85
|
)
|
|
81
86
|
)
|
|
82
87
|
seen_paths.add(str(global_path))
|
|
83
88
|
|
|
84
|
-
# 2.
|
|
85
|
-
|
|
86
|
-
Path(
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
Path.home() / "code",
|
|
90
|
-
Path.home() / "Code",
|
|
91
|
-
Path.home() / "dev",
|
|
92
|
-
Path.home() / "Dev",
|
|
93
|
-
Path.home() / "src",
|
|
94
|
-
Path.home() / "workspace",
|
|
95
|
-
]
|
|
96
|
-
|
|
97
|
-
for scan_dir in scan_dirs:
|
|
98
|
-
if scan_dir.exists():
|
|
99
|
-
for db_path in scan_directory_for_cortex(scan_dir):
|
|
89
|
+
# 2. Use CONFIGURABLE scan directories
|
|
90
|
+
for scan_dir in config.scan_directories:
|
|
91
|
+
scan_path = Path(scan_dir).expanduser()
|
|
92
|
+
if scan_path.exists():
|
|
93
|
+
for db_path in scan_directory_for_cortex(scan_path):
|
|
100
94
|
if str(db_path) not in seen_paths:
|
|
101
95
|
project_dir = db_path.parent.parent
|
|
102
96
|
stat = db_path.stat()
|
|
97
|
+
project_path = str(project_dir)
|
|
103
98
|
projects.append(
|
|
104
99
|
ProjectInfo(
|
|
105
100
|
name=project_dir.name,
|
|
106
|
-
path=
|
|
101
|
+
path=project_path,
|
|
107
102
|
db_path=str(db_path),
|
|
108
103
|
last_modified=datetime.fromtimestamp(stat.st_mtime),
|
|
109
104
|
memory_count=get_memory_count(db_path),
|
|
110
105
|
is_global=False,
|
|
106
|
+
is_favorite=project_path in config.favorites,
|
|
111
107
|
)
|
|
112
108
|
)
|
|
113
109
|
seen_paths.add(str(db_path))
|
|
114
110
|
|
|
115
|
-
# 3. Add
|
|
111
|
+
# 3. Add REGISTERED projects (manual additions)
|
|
112
|
+
for reg in config.registered_projects:
|
|
113
|
+
db_path = Path(reg.path) / ".omni-cortex" / "cortex.db"
|
|
114
|
+
if db_path.exists() and str(db_path) not in seen_paths:
|
|
115
|
+
stat = db_path.stat()
|
|
116
|
+
projects.append(
|
|
117
|
+
ProjectInfo(
|
|
118
|
+
name=Path(reg.path).name,
|
|
119
|
+
path=reg.path,
|
|
120
|
+
db_path=str(db_path),
|
|
121
|
+
last_modified=datetime.fromtimestamp(stat.st_mtime),
|
|
122
|
+
memory_count=get_memory_count(db_path),
|
|
123
|
+
is_global=False,
|
|
124
|
+
is_favorite=reg.path in config.favorites,
|
|
125
|
+
is_registered=True,
|
|
126
|
+
display_name=reg.display_name,
|
|
127
|
+
)
|
|
128
|
+
)
|
|
129
|
+
seen_paths.add(str(db_path))
|
|
130
|
+
|
|
131
|
+
# 4. Add paths from global db that we haven't seen
|
|
116
132
|
for project_path in get_projects_from_global_db():
|
|
117
133
|
db_path = Path(project_path) / ".omni-cortex" / "cortex.db"
|
|
118
134
|
if db_path.exists() and str(db_path) not in seen_paths:
|
|
@@ -125,12 +141,19 @@ def scan_projects() -> list[ProjectInfo]:
|
|
|
125
141
|
last_modified=datetime.fromtimestamp(stat.st_mtime),
|
|
126
142
|
memory_count=get_memory_count(db_path),
|
|
127
143
|
is_global=False,
|
|
144
|
+
is_favorite=project_path in config.favorites,
|
|
128
145
|
)
|
|
129
146
|
)
|
|
130
147
|
seen_paths.add(str(db_path))
|
|
131
148
|
|
|
132
|
-
# Sort by last_modified (most recent first), with global always first
|
|
133
|
-
projects.sort(
|
|
149
|
+
# Sort: favorites first, then by last_modified (most recent first), with global always first
|
|
150
|
+
projects.sort(
|
|
151
|
+
key=lambda p: (
|
|
152
|
+
not p.is_global,
|
|
153
|
+
not p.is_favorite,
|
|
154
|
+
-(p.last_modified.timestamp() if p.last_modified else 0),
|
|
155
|
+
)
|
|
156
|
+
)
|
|
134
157
|
|
|
135
158
|
return projects
|
|
136
159
|
|