feat: add watch to mcp process (#83)

This commit is contained in:
Paul Hernandez
2025-04-06 18:33:10 -05:00
committed by GitHub
parent 617e60bda4
commit 00c8633cfc
6 changed files with 92 additions and 24 deletions
+42 -3
View File
@@ -1,5 +1,6 @@
"""FastAPI application for basic-memory knowledge graph API."""
import asyncio
from contextlib import asynccontextmanager
from fastapi import FastAPI, HTTPException
@@ -7,16 +8,54 @@ from fastapi.exception_handlers import http_exception_handler
from loguru import logger
from basic_memory import db
from basic_memory.config import config as app_config
from basic_memory.api.routers import knowledge, search, memory, resource, project_info
from basic_memory.api.routers import knowledge, memory, project_info, resource, search
from basic_memory.config import config as project_config
from basic_memory.config import config_manager
from basic_memory.sync import SyncService, WatchService
async def run_background_sync(sync_service: SyncService, watch_service: WatchService): # pragma: no cover
logger.info(f"Starting watch service to sync file changes in dir: {project_config.home}")
# full sync
await sync_service.sync(project_config.home, show_progress=False)
# watch changes
await watch_service.run()
@asynccontextmanager
async def lifespan(app: FastAPI): # pragma: no cover
"""Lifecycle manager for the FastAPI app."""
await db.run_migrations(app_config)
await db.run_migrations(project_config)
# app config
basic_memory_config = config_manager.load_config()
logger.info(f"Sync changes enabled: {basic_memory_config.sync_changes}")
logger.info(f"Update permalinks on move enabled: {basic_memory_config.update_permalinks_on_move}")
watch_task = None
if basic_memory_config.sync_changes:
# import after migrations have run
from basic_memory.cli.commands.sync import get_sync_service
sync_service = await get_sync_service()
watch_service = WatchService(
sync_service=sync_service,
file_service=sync_service.entity_service.file_service,
config=project_config,
)
watch_task = asyncio.create_task(run_background_sync(sync_service, watch_service))
else:
logger.info("Sync changes disabled. Skipping watch service.")
# proceed with startup
yield
logger.info("Shutting down Basic Memory API")
if watch_task:
watch_task.cancel()
await db.shutdown_db()
-7
View File
@@ -1,11 +1,7 @@
import asyncio
from typing import Optional
import typer
from basic_memory import db
from basic_memory.config import config
def version_callback(value: bool) -> None:
"""Show version and exit."""
@@ -58,9 +54,6 @@ def app_callback(
config = new_config
# Run database migrations
asyncio.run(db.run_migrations(config))
# Register sub-command groups
import_app = typer.Typer(help="Import data from various sources")
app.add_typer(import_app, name="import")
+8 -1
View File
@@ -4,7 +4,7 @@ from loguru import logger
import basic_memory
from basic_memory.cli.app import app
from basic_memory.config import config
from basic_memory.config import config, config_manager
# Import mcp instance
from basic_memory.mcp.server import mcp as mcp_server # pragma: no cover
@@ -19,8 +19,15 @@ def mcp(): # pragma: no cover
home_dir = config.home
project_name = config.project
# app config
basic_memory_config = config_manager.load_config()
logger.info(f"Starting Basic Memory MCP server {basic_memory.__version__}")
logger.info(f"Project: {project_name}")
logger.info(f"Project directory: {home_dir}")
logger.info(f"Sync changes enabled: {basic_memory_config.sync_changes}")
logger.info(
f"Update permalinks on move enabled: {basic_memory_config.update_permalinks_on_move}"
)
mcp_server.run()
+16 -7
View File
@@ -1,21 +1,26 @@
"""Main CLI entry point for basic-memory.""" # pragma: no cover
from basic_memory.cli.app import app # pragma: no cover
import asyncio
import typer
from basic_memory.cli.app import app # pragma: no cover
# Register commands
from basic_memory.cli.commands import ( # noqa: F401 # pragma: no cover
status,
sync,
db,
import_memory_json,
mcp,
import_chatgpt,
import_claude_conversations,
import_claude_projects,
import_chatgpt,
tool,
import_memory_json,
mcp,
project,
status,
sync,
tool,
)
from basic_memory.config import config
from basic_memory.db import run_migrations as db_run_migrations
# Version command
@@ -55,4 +60,8 @@ def main(
if __name__ == "__main__": # pragma: no cover
# Run database migrations
asyncio.run(db_run_migrations(config))
# start the app
app()
+23 -5
View File
@@ -38,8 +38,7 @@ class ProjectConfig(BaseSettings):
default=500, description="Milliseconds to wait after changes before syncing", gt=0
)
log_level: str = "DEBUG"
# update permalinks on move
update_permalinks_on_move: bool = Field(
default=False,
description="Whether to update permalinks when files are moved or renamed. default (False)",
@@ -82,6 +81,18 @@ class BasicMemoryConfig(BaseSettings):
description="Name of the default project to use",
)
log_level: str = "INFO"
update_permalinks_on_move: bool = Field(
default=False,
description="Whether to update permalinks when files are moved or renamed. default (False)",
)
sync_changes: bool = Field(
default=True,
description="Whether to sync changes in real time. default (True)",
)
model_config = SettingsConfigDict(
env_prefix="BASIC_MEMORY_",
extra="ignore",
@@ -199,9 +210,14 @@ def get_project_config(project_name: Optional[str] = None) -> ProjectConfig:
"BASIC_MEMORY_PROJECT", project_name or config_manager.default_project
)
update_permalinks_on_move = config_manager.load_config().update_permalinks_on_move
try:
project_path = config_manager.get_project_path(actual_project_name)
return ProjectConfig(home=project_path, project=actual_project_name)
return ProjectConfig(
home=project_path,
project=actual_project_name,
update_permalinks_on_move=update_permalinks_on_move,
)
except ValueError: # pragma: no cover
logger.warning(f"Project '{actual_project_name}' not found, using default")
project_path = config_manager.get_project_path(config_manager.default_project)
@@ -230,8 +246,10 @@ def get_process_name(): # pragma: no cover
return "sync"
elif "mcp" in sys.argv:
return "mcp"
else:
elif "cli" in sys.argv:
return "cli"
else:
return "api"
process_name = get_process_name()
@@ -251,7 +269,7 @@ def setup_basic_memory_logging(): # pragma: no cover
setup_logging(
env=config.env,
home_dir=user_home, # Use user home for logs
log_level=config.log_level,
log_level=config_manager.load_config().log_level,
log_file=f"{DATA_DIR_NAME}/basic-memory-{process_name}.log",
console=False,
)
+3 -1
View File
@@ -146,7 +146,9 @@ async def engine_session_factory(
_session_maker = None
async def run_migrations(app_config: ProjectConfig, database_type=DatabaseType.FILESYSTEM):
async def run_migrations(
app_config: ProjectConfig, database_type=DatabaseType.FILESYSTEM
): # pragma: no cover
"""Run any pending alembic migrations."""
logger.info("Running database migrations...")
try: