get-claudia 1.3.0 → 1.3.1

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.
@@ -9,12 +9,13 @@ Starts the memory daemon with:
9
9
 
10
10
  import argparse
11
11
  import asyncio
12
+ import hashlib
12
13
  import logging
13
14
  import signal
14
15
  import sys
15
16
  from pathlib import Path
16
17
 
17
- from .config import get_config
18
+ from .config import get_config, set_project_id
18
19
  from .daemon.health import start_health_server, stop_health_server
19
20
  from .daemon.scheduler import start_scheduler, stop_scheduler
20
21
  from .database import get_db
@@ -26,6 +27,17 @@ logger = logging.getLogger(__name__)
26
27
  _shutdown_requested = False
27
28
 
28
29
 
30
+ def get_project_hash(project_dir: str) -> str:
31
+ """Generate consistent short hash from project directory path.
32
+
33
+ Uses SHA256 truncated to 12 characters for a good balance of:
34
+ - Uniqueness (12 hex chars = 48 bits = ~281 trillion combinations)
35
+ - Readability (short enough to see in file listings)
36
+ - Determinism (same path always produces same hash)
37
+ """
38
+ return hashlib.sha256(project_dir.encode()).hexdigest()[:12]
39
+
40
+
29
41
  def setup_logging(log_path: Path = None, debug: bool = False) -> None:
30
42
  """Configure logging"""
31
43
  config = get_config()
@@ -58,16 +70,23 @@ def signal_handler(signum, frame):
58
70
  _shutdown_requested = True
59
71
 
60
72
 
61
- def run_daemon(mcp_mode: bool = True, debug: bool = False) -> None:
73
+ def run_daemon(mcp_mode: bool = True, debug: bool = False, project_id: str = None) -> None:
62
74
  """
63
75
  Run the Claudia Memory Daemon.
64
76
 
65
77
  Args:
66
78
  mcp_mode: If True, run as MCP server (stdio mode)
67
79
  debug: Enable debug logging
80
+ project_id: Optional project identifier for database isolation
68
81
  """
82
+ # Set project context before any config access
83
+ if project_id:
84
+ set_project_id(project_id)
85
+
69
86
  setup_logging(debug=debug)
70
87
  logger.info("Starting Claudia Memory Daemon")
88
+ if project_id:
89
+ logger.info(f"Project isolation enabled: {project_id}")
71
90
 
72
91
  # Set up signal handlers
73
92
  signal.signal(signal.SIGTERM, signal_handler)
@@ -137,9 +156,21 @@ def main():
137
156
  action="store_true",
138
157
  help="Check system health and exit",
139
158
  )
159
+ parser.add_argument(
160
+ "--project-dir",
161
+ type=str,
162
+ help="Project directory for database isolation (creates project-specific database)",
163
+ )
140
164
 
141
165
  args = parser.parse_args()
142
166
 
167
+ # Compute project ID from directory path if provided
168
+ project_id = None
169
+ if args.project_dir:
170
+ project_id = get_project_hash(args.project_dir)
171
+ # Set project context early for commands that don't call run_daemon
172
+ set_project_id(project_id)
173
+
143
174
  if args.consolidate:
144
175
  # One-shot consolidation
145
176
  setup_logging(debug=args.debug)
@@ -165,7 +196,7 @@ def main():
165
196
  return
166
197
 
167
198
  # Run the daemon
168
- run_daemon(mcp_mode=not args.standalone, debug=args.debug)
199
+ run_daemon(mcp_mode=not args.standalone, debug=args.debug, project_id=project_id)
169
200
 
170
201
 
171
202
  if __name__ == "__main__":
@@ -42,8 +42,14 @@ class MemoryConfig:
42
42
  log_path: Path = field(default_factory=lambda: Path.home() / ".claudia" / "daemon.log")
43
43
 
44
44
  @classmethod
45
- def load(cls) -> "MemoryConfig":
46
- """Load configuration from ~/.claudia/config.json, with defaults"""
45
+ def load(cls, project_id: Optional[str] = None) -> "MemoryConfig":
46
+ """Load configuration from ~/.claudia/config.json, with defaults.
47
+
48
+ Args:
49
+ project_id: Optional project identifier for database isolation.
50
+ When provided, the database path is overridden to
51
+ ~/.claudia/memory/{project_id}.db for per-project isolation.
52
+ """
47
53
  config_path = Path.home() / ".claudia" / "config.json"
48
54
  config = cls()
49
55
 
@@ -80,6 +86,11 @@ class MemoryConfig:
80
86
  # Use defaults on error
81
87
  pass
82
88
 
89
+ # Override database path for project isolation
90
+ # This ensures each project gets its own isolated database
91
+ if project_id:
92
+ config.db_path = Path.home() / ".claudia" / "memory" / f"{project_id}.db"
93
+
83
94
  # Ensure directories exist
84
95
  config.db_path.parent.mkdir(parents=True, exist_ok=True)
85
96
  config.log_path.parent.mkdir(parents=True, exist_ok=True)
@@ -109,13 +120,36 @@ class MemoryConfig:
109
120
  json.dump(data, f, indent=2)
110
121
 
111
122
 
112
- # Global config instance
123
+ # Global config instance and project context
113
124
  _config: Optional[MemoryConfig] = None
125
+ _project_id: Optional[str] = None
126
+
127
+
128
+ def set_project_id(project_id: Optional[str]) -> None:
129
+ """Set the project ID for database isolation.
130
+
131
+ This must be called before any access to get_config() to ensure
132
+ the correct project-specific database path is used.
133
+
134
+ Args:
135
+ project_id: Hash of the project directory path, or None for global database.
136
+ """
137
+ global _config, _project_id
138
+
139
+ # If project_id changes, invalidate cached config so it reloads
140
+ if project_id != _project_id:
141
+ _config = None
142
+ _project_id = project_id
114
143
 
115
144
 
116
145
  def get_config() -> MemoryConfig:
117
- """Get or load the global configuration"""
118
- global _config
146
+ """Get or load the global configuration.
147
+
148
+ The configuration is project-aware. If set_project_id() was called,
149
+ the database path will be project-specific. Otherwise, the global
150
+ claudia.db is used for backward compatibility.
151
+ """
152
+ global _config, _project_id
119
153
  if _config is None:
120
- _config = MemoryConfig.load()
154
+ _config = MemoryConfig.load(project_id=_project_id)
121
155
  return _config
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "get-claudia",
3
- "version": "1.3.0",
3
+ "version": "1.3.1",
4
4
  "description": "An AI assistant who learns how you work.",
5
5
  "keywords": [
6
6
  "claudia",
@@ -7,8 +7,8 @@
7
7
  "claudia-memory": {
8
8
  "_disabled": true,
9
9
  "command": "~/.claudia/daemon/venv/bin/python",
10
- "args": ["-m", "claudia_memory.mcp.server"],
11
- "_description": "Enhanced memory with vector search. Install with: ~/.claudia/memory-daemon/scripts/install.sh"
10
+ "args": ["-m", "claudia_memory", "--project-dir", "${workspaceFolder}"],
11
+ "_description": "Enhanced memory with vector search (per-project isolation). Install with: ~/.claudia/daemon/scripts/install.sh"
12
12
  },
13
13
 
14
14
  "gmail": {