basic-memory 0.14.2__py3-none-any.whl → 0.14.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.
Potentially problematic release.
This version of basic-memory might be problematic. Click here for more details.
- basic_memory/__init__.py +1 -1
- basic_memory/alembic/env.py +3 -1
- basic_memory/api/app.py +4 -1
- basic_memory/api/routers/management_router.py +3 -1
- basic_memory/api/routers/project_router.py +21 -13
- basic_memory/cli/app.py +3 -3
- basic_memory/cli/commands/__init__.py +1 -2
- basic_memory/cli/commands/db.py +5 -5
- basic_memory/cli/commands/import_chatgpt.py +3 -2
- basic_memory/cli/commands/import_claude_conversations.py +3 -1
- basic_memory/cli/commands/import_claude_projects.py +3 -1
- basic_memory/cli/commands/import_memory_json.py +5 -2
- basic_memory/cli/commands/mcp.py +3 -15
- basic_memory/cli/commands/project.py +41 -0
- basic_memory/cli/commands/status.py +4 -1
- basic_memory/cli/commands/sync.py +10 -2
- basic_memory/cli/main.py +0 -1
- basic_memory/config.py +46 -31
- basic_memory/db.py +2 -6
- basic_memory/deps.py +3 -2
- basic_memory/importers/chatgpt_importer.py +19 -9
- basic_memory/importers/memory_json_importer.py +22 -7
- basic_memory/mcp/async_client.py +22 -2
- basic_memory/mcp/project_session.py +6 -4
- basic_memory/mcp/prompts/__init__.py +0 -2
- basic_memory/mcp/server.py +8 -71
- basic_memory/mcp/tools/move_note.py +24 -12
- basic_memory/mcp/tools/read_content.py +16 -0
- basic_memory/mcp/tools/read_note.py +12 -0
- basic_memory/mcp/tools/sync_status.py +3 -2
- basic_memory/mcp/tools/write_note.py +9 -1
- basic_memory/models/project.py +3 -3
- basic_memory/repository/project_repository.py +18 -0
- basic_memory/schemas/importer.py +1 -0
- basic_memory/services/entity_service.py +49 -3
- basic_memory/services/initialization.py +0 -75
- basic_memory/services/project_service.py +85 -28
- basic_memory/sync/background_sync.py +4 -3
- basic_memory/sync/sync_service.py +50 -1
- basic_memory/utils.py +105 -4
- {basic_memory-0.14.2.dist-info → basic_memory-0.14.3.dist-info}/METADATA +2 -2
- {basic_memory-0.14.2.dist-info → basic_memory-0.14.3.dist-info}/RECORD +45 -51
- basic_memory/cli/commands/auth.py +0 -136
- basic_memory/mcp/auth_provider.py +0 -270
- basic_memory/mcp/external_auth_provider.py +0 -321
- basic_memory/mcp/prompts/sync_status.py +0 -112
- basic_memory/mcp/supabase_auth_provider.py +0 -463
- basic_memory/services/migration_service.py +0 -168
- {basic_memory-0.14.2.dist-info → basic_memory-0.14.3.dist-info}/WHEEL +0 -0
- {basic_memory-0.14.2.dist-info → basic_memory-0.14.3.dist-info}/entry_points.txt +0 -0
- {basic_memory-0.14.2.dist-info → basic_memory-0.14.3.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
"""Migration service for handling background migrations and status tracking."""
|
|
2
|
-
|
|
3
|
-
import asyncio
|
|
4
|
-
from dataclasses import dataclass
|
|
5
|
-
from enum import Enum
|
|
6
|
-
from pathlib import Path
|
|
7
|
-
from typing import Optional
|
|
8
|
-
|
|
9
|
-
from loguru import logger
|
|
10
|
-
|
|
11
|
-
from basic_memory.config import BasicMemoryConfig
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
class MigrationStatus(Enum):
|
|
15
|
-
"""Status of migration operations."""
|
|
16
|
-
|
|
17
|
-
NOT_NEEDED = "not_needed"
|
|
18
|
-
PENDING = "pending"
|
|
19
|
-
IN_PROGRESS = "in_progress"
|
|
20
|
-
COMPLETED = "completed"
|
|
21
|
-
FAILED = "failed"
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
@dataclass
|
|
25
|
-
class MigrationState:
|
|
26
|
-
"""Current state of migration operations."""
|
|
27
|
-
|
|
28
|
-
status: MigrationStatus
|
|
29
|
-
message: str
|
|
30
|
-
progress: Optional[str] = None
|
|
31
|
-
error: Optional[str] = None
|
|
32
|
-
projects_migrated: int = 0
|
|
33
|
-
projects_total: int = 0
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
class MigrationManager:
|
|
37
|
-
"""Manages background migration operations and status tracking."""
|
|
38
|
-
|
|
39
|
-
def __init__(self):
|
|
40
|
-
self._state = MigrationState(
|
|
41
|
-
status=MigrationStatus.NOT_NEEDED, message="No migration required"
|
|
42
|
-
)
|
|
43
|
-
self._migration_task: Optional[asyncio.Task] = None
|
|
44
|
-
|
|
45
|
-
@property
|
|
46
|
-
def state(self) -> MigrationState:
|
|
47
|
-
"""Get current migration state."""
|
|
48
|
-
return self._state
|
|
49
|
-
|
|
50
|
-
@property
|
|
51
|
-
def is_ready(self) -> bool:
|
|
52
|
-
"""Check if the system is ready for normal operations."""
|
|
53
|
-
return self._state.status in (MigrationStatus.NOT_NEEDED, MigrationStatus.COMPLETED)
|
|
54
|
-
|
|
55
|
-
@property
|
|
56
|
-
def status_message(self) -> str:
|
|
57
|
-
"""Get a user-friendly status message."""
|
|
58
|
-
if self._state.status == MigrationStatus.IN_PROGRESS:
|
|
59
|
-
progress = (
|
|
60
|
-
f" ({self._state.projects_migrated}/{self._state.projects_total})"
|
|
61
|
-
if self._state.projects_total > 0
|
|
62
|
-
else ""
|
|
63
|
-
)
|
|
64
|
-
return f"🔄 File sync in progress{progress}: {self._state.message}. Use sync_status() tool for details."
|
|
65
|
-
elif self._state.status == MigrationStatus.FAILED:
|
|
66
|
-
return f"❌ File sync failed: {self._state.error or 'Unknown error'}. Use sync_status() tool for details."
|
|
67
|
-
elif self._state.status == MigrationStatus.COMPLETED:
|
|
68
|
-
return "✅ File sync completed successfully"
|
|
69
|
-
else:
|
|
70
|
-
return "✅ System ready"
|
|
71
|
-
|
|
72
|
-
async def check_migration_needed(self, app_config: BasicMemoryConfig) -> bool:
|
|
73
|
-
"""Check if migration is needed without performing it."""
|
|
74
|
-
from basic_memory import db
|
|
75
|
-
from basic_memory.repository import ProjectRepository
|
|
76
|
-
|
|
77
|
-
try:
|
|
78
|
-
# Get database session
|
|
79
|
-
_, session_maker = await db.get_or_create_db(
|
|
80
|
-
db_path=app_config.database_path, db_type=db.DatabaseType.FILESYSTEM
|
|
81
|
-
)
|
|
82
|
-
project_repository = ProjectRepository(session_maker)
|
|
83
|
-
|
|
84
|
-
# Check for legacy projects
|
|
85
|
-
legacy_projects = []
|
|
86
|
-
for project_name, project_path in app_config.projects.items():
|
|
87
|
-
legacy_dir = Path(project_path) / ".basic-memory"
|
|
88
|
-
if legacy_dir.exists():
|
|
89
|
-
project = await project_repository.get_by_name(project_name)
|
|
90
|
-
if project:
|
|
91
|
-
legacy_projects.append(project)
|
|
92
|
-
|
|
93
|
-
if legacy_projects:
|
|
94
|
-
self._state = MigrationState(
|
|
95
|
-
status=MigrationStatus.PENDING,
|
|
96
|
-
message="Legacy projects detected",
|
|
97
|
-
projects_total=len(legacy_projects),
|
|
98
|
-
)
|
|
99
|
-
return True
|
|
100
|
-
else:
|
|
101
|
-
self._state = MigrationState(
|
|
102
|
-
status=MigrationStatus.NOT_NEEDED, message="No migration required"
|
|
103
|
-
)
|
|
104
|
-
return False
|
|
105
|
-
|
|
106
|
-
except Exception as e:
|
|
107
|
-
logger.error(f"Error checking migration status: {e}")
|
|
108
|
-
self._state = MigrationState(
|
|
109
|
-
status=MigrationStatus.FAILED, message="Migration check failed", error=str(e)
|
|
110
|
-
)
|
|
111
|
-
return False
|
|
112
|
-
|
|
113
|
-
async def start_background_migration(self, app_config: BasicMemoryConfig) -> None:
|
|
114
|
-
"""Start migration in background if needed."""
|
|
115
|
-
if not await self.check_migration_needed(app_config):
|
|
116
|
-
return
|
|
117
|
-
|
|
118
|
-
if self._migration_task and not self._migration_task.done():
|
|
119
|
-
logger.info("Migration already in progress")
|
|
120
|
-
return
|
|
121
|
-
|
|
122
|
-
logger.info("Starting background migration")
|
|
123
|
-
self._migration_task = asyncio.create_task(self._run_migration(app_config))
|
|
124
|
-
|
|
125
|
-
async def _run_migration(self, app_config: BasicMemoryConfig) -> None:
|
|
126
|
-
"""Run the actual migration process."""
|
|
127
|
-
try:
|
|
128
|
-
self._state.status = MigrationStatus.IN_PROGRESS
|
|
129
|
-
self._state.message = "Migrating legacy projects"
|
|
130
|
-
|
|
131
|
-
# Import here to avoid circular imports
|
|
132
|
-
from basic_memory.services.initialization import migrate_legacy_projects
|
|
133
|
-
|
|
134
|
-
# Run the migration
|
|
135
|
-
await migrate_legacy_projects(app_config)
|
|
136
|
-
|
|
137
|
-
self._state = MigrationState(
|
|
138
|
-
status=MigrationStatus.COMPLETED, message="Migration completed successfully"
|
|
139
|
-
)
|
|
140
|
-
logger.info("Background migration completed successfully")
|
|
141
|
-
|
|
142
|
-
except Exception as e:
|
|
143
|
-
logger.error(f"Background migration failed: {e}")
|
|
144
|
-
self._state = MigrationState(
|
|
145
|
-
status=MigrationStatus.FAILED, message="Migration failed", error=str(e)
|
|
146
|
-
)
|
|
147
|
-
|
|
148
|
-
async def wait_for_completion(self, timeout: Optional[float] = None) -> bool:
|
|
149
|
-
"""Wait for migration to complete."""
|
|
150
|
-
if self.is_ready:
|
|
151
|
-
return True
|
|
152
|
-
|
|
153
|
-
if not self._migration_task:
|
|
154
|
-
return False
|
|
155
|
-
|
|
156
|
-
try:
|
|
157
|
-
await asyncio.wait_for(self._migration_task, timeout=timeout)
|
|
158
|
-
return self.is_ready
|
|
159
|
-
except asyncio.TimeoutError:
|
|
160
|
-
return False
|
|
161
|
-
|
|
162
|
-
def mark_completed(self, message: str = "Migration completed") -> None:
|
|
163
|
-
"""Mark migration as completed externally."""
|
|
164
|
-
self._state = MigrationState(status=MigrationStatus.COMPLETED, message=message)
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
# Global migration manager instance
|
|
168
|
-
migration_manager = MigrationManager()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|