|
4 | 4 |
|
5 | 5 | import typer |
6 | 6 | from loguru import logger |
| 7 | +from rich.console import Console |
| 8 | +from sqlalchemy.exc import OperationalError |
7 | 9 |
|
8 | 10 | from basic_memory import db |
9 | 11 | from basic_memory.cli.app import app |
10 | 12 | from basic_memory.config import ConfigManager, BasicMemoryConfig, save_basic_memory_config |
11 | 13 |
|
| 14 | +console = Console() |
| 15 | + |
12 | 16 |
|
13 | 17 | @app.command() |
14 | 18 | def reset( |
15 | 19 | reindex: bool = typer.Option(False, "--reindex", help="Rebuild db index from filesystem"), |
16 | 20 | ): # pragma: no cover |
17 | 21 | """Reset database (drop all tables and recreate).""" |
18 | | - if typer.confirm("This will delete all data in your db. Are you sure?"): |
| 22 | + console.print( |
| 23 | + "[yellow]Note:[/yellow] This only deletes the index database. " |
| 24 | + "Your markdown note files will not be affected." |
| 25 | + ) |
| 26 | + if typer.confirm("Reset the database index? (You can rebuild it with 'bm sync')"): |
19 | 27 | logger.info("Resetting database...") |
20 | 28 | config_manager = ConfigManager() |
21 | 29 | app_config = config_manager.config |
22 | 30 | # Get database path |
23 | 31 | db_path = app_config.app_database_path |
24 | 32 |
|
25 | | - # Delete the database file if it exists |
26 | | - if db_path.exists(): |
27 | | - db_path.unlink() |
28 | | - logger.info(f"Database file deleted: {db_path}") |
| 33 | + # Delete the database file and WAL files if they exist |
| 34 | + for suffix in ["", "-shm", "-wal"]: |
| 35 | + path = db_path.parent / f"{db_path.name}{suffix}" |
| 36 | + if path.exists(): |
| 37 | + try: |
| 38 | + path.unlink() |
| 39 | + logger.info(f"Deleted: {path}") |
| 40 | + except OSError as e: |
| 41 | + console.print( |
| 42 | + f"[red]Error:[/red] Cannot delete {path.name}: {e}\n" |
| 43 | + "The database may be in use by another process (e.g., MCP server).\n" |
| 44 | + "Please close Claude Desktop or any other Basic Memory clients and try again." |
| 45 | + ) |
| 46 | + raise typer.Exit(1) |
29 | 47 |
|
30 | 48 | # Reset project configuration |
31 | 49 | config = BasicMemoryConfig() |
32 | 50 | save_basic_memory_config(config_manager.config_file, config) |
33 | 51 | logger.info("Project configuration reset to default") |
34 | 52 |
|
35 | 53 | # Create a new empty database |
36 | | - asyncio.run(db.run_migrations(app_config)) |
| 54 | + try: |
| 55 | + asyncio.run(db.run_migrations(app_config)) |
| 56 | + except OperationalError as e: |
| 57 | + if "disk I/O error" in str(e) or "database is locked" in str(e): |
| 58 | + console.print( |
| 59 | + "[red]Error:[/red] Cannot access database. " |
| 60 | + "It may be in use by another process (e.g., MCP server).\n" |
| 61 | + "Please close Claude Desktop or any other Basic Memory clients and try again." |
| 62 | + ) |
| 63 | + raise typer.Exit(1) |
| 64 | + raise |
37 | 65 | logger.info("Database reset complete") |
38 | 66 |
|
39 | 67 | if reindex: |
|
0 commit comments