basic-memory 0.12.0__tar.gz → 0.12.2__tar.gz
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-0.12.0 → basic_memory-0.12.2}/CHANGELOG.md +20 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/PKG-INFO +3 -9
- {basic_memory-0.12.0 → basic_memory-0.12.2}/README.md +2 -8
- {basic_memory-0.12.0 → basic_memory-0.12.2}/docs/CLI Reference.md +16 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/docs/Getting Started with Basic Memory.md +9 -20
- {basic_memory-0.12.0 → basic_memory-0.12.2}/docs/Knowledge Format.md +13 -1
- {basic_memory-0.12.0 → basic_memory-0.12.2}/installer/installer.py +1 -1
- {basic_memory-0.12.0 → basic_memory-0.12.2}/pyproject.toml +1 -1
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/__init__.py +1 -1
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/api/app.py +3 -34
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/cli/app.py +13 -1
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/cli/commands/import_memory_json.py +1 -1
- basic_memory-0.12.2/src/basic_memory/cli/commands/mcp.py +35 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/cli/commands/sync.py +8 -8
- basic_memory-0.12.2/src/basic_memory/cli/main.py +26 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/config.py +2 -2
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/markdown/entity_parser.py +1 -1
- basic_memory-0.12.2/src/basic_memory/mcp/server.py +37 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/repository/repository.py +0 -4
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/services/file_service.py +1 -1
- basic_memory-0.12.2/src/basic_memory/services/initialization.py +143 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/sync/sync_service.py +75 -185
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/sync/watch_service.py +49 -30
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/api/test_resource_router.py +3 -3
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/cli/test_cli_tools.py +28 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/cli/test_import_chatgpt.py +8 -7
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/cli/test_import_claude_conversations.py +5 -4
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/cli/test_import_claude_projects.py +5 -4
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/cli/test_import_memory_json.py +4 -3
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/conftest.py +1 -1
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/markdown/test_markdown_processor.py +5 -5
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/mcp/test_tool_canvas.py +4 -4
- basic_memory-0.12.2/tests/services/test_initialization.py +49 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/sync/test_sync_service.py +36 -36
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/sync/test_sync_wikilink_issue.py +6 -5
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/sync/test_tmp_files.py +2 -2
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/sync/test_watch_service.py +6 -6
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/utils/test_file_utils.py +10 -10
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/utils/test_permalink_formatting.py +3 -2
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/utils/test_utf8_handling.py +2 -2
- {basic_memory-0.12.0 → basic_memory-0.12.2}/uv.lock +1 -1
- basic_memory-0.12.0/src/basic_memory/cli/commands/mcp.py +0 -33
- basic_memory-0.12.0/src/basic_memory/cli/main.py +0 -67
- basic_memory-0.12.0/src/basic_memory/mcp/server.py +0 -11
- {basic_memory-0.12.0 → basic_memory-0.12.2}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/.github/ISSUE_TEMPLATE/documentation.md +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/.github/dependabot.yml +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/.github/workflows/claude-code-actions.yml +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/.github/workflows/pr-title.yml +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/.github/workflows/release.yml +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/.github/workflows/test.yml +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/.gitignore +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/.python-version +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/CITATION.cff +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/CLA.md +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/CLAUDE.md +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/CODE_OF_CONDUCT.md +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/CONTRIBUTING.md +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/Dockerfile +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/LICENSE +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/Makefile +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/SECURITY.md +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/basic-memory.md +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/docs/AI Assistant Guide.md +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/docs/Canvas.md +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/docs/Obsidian Integration.md +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/docs/Technical Information.md +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/docs/User Guide.md +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/docs/Welcome to Basic memory.md +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/docs/attachments/Canvas.png +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/docs/attachments/Claude-Obsidian-Demo.mp4 +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/docs/attachments/Prompt.png +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/docs/attachments/disk-ai-logo-400x400.png +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/docs/attachments/disk-ai-logo.png +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/docs/attachments/prompt 1.png +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/docs/attachments/prompt2.png +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/docs/attachments/prompt3.png +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/docs/attachments/prompt4.png +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/docs/publish.js +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/examples/Coffee Notes/Brewing Equipment.md +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/examples/Coffee Notes/Coffee Bean Origins.md +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/examples/Coffee Notes/Coffee Brewing Methods.md +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/examples/Coffee Notes/Coffee Flavor Map.md +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/examples/Coffee Notes/Coffee Knowledge Base.md +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/examples/Coffee Notes/Flavor Extraction.md +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/examples/Coffee Notes/Perfect Pour Over Coffee Method.canvas +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/examples/Coffee Notes/Tasting Notes.md +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/installer/Basic.icns +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/installer/README.md +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/installer/icon.svg +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/installer/make_icons.sh +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/installer/setup.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/llms-install.md +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/memory.json +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/scripts/install.sh +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/smithery.yaml +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/alembic/alembic.ini +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/alembic/env.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/alembic/migrations.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/alembic/script.py.mako +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/alembic/versions/3dae7c7b1564_initial_schema.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/alembic/versions/502b60eaa905_remove_required_from_entity_permalink.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/alembic/versions/b3c3938bacdb_relation_to_name_unique_index.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/alembic/versions/cc7172b46608_update_search_index_schema.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/api/__init__.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/api/routers/__init__.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/api/routers/knowledge_router.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/api/routers/memory_router.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/api/routers/project_info_router.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/api/routers/resource_router.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/api/routers/search_router.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/cli/__init__.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/cli/commands/__init__.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/cli/commands/db.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/cli/commands/import_chatgpt.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/cli/commands/import_claude_conversations.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/cli/commands/import_claude_projects.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/cli/commands/project.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/cli/commands/status.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/cli/commands/tool.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/db.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/deps.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/file_utils.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/markdown/__init__.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/markdown/markdown_processor.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/markdown/plugins.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/markdown/schemas.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/markdown/utils.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/mcp/__init__.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/mcp/async_client.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/mcp/main.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/mcp/prompts/__init__.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/mcp/prompts/ai_assistant_guide.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/mcp/prompts/continue_conversation.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/mcp/prompts/recent_activity.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/mcp/prompts/search.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/mcp/prompts/utils.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/mcp/resources/ai_assistant_guide.md +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/mcp/tools/__init__.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/mcp/tools/build_context.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/mcp/tools/canvas.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/mcp/tools/delete_note.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/mcp/tools/project_info.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/mcp/tools/read_content.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/mcp/tools/read_note.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/mcp/tools/recent_activity.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/mcp/tools/search.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/mcp/tools/utils.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/mcp/tools/write_note.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/models/__init__.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/models/base.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/models/knowledge.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/models/search.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/repository/__init__.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/repository/entity_repository.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/repository/observation_repository.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/repository/project_info_repository.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/repository/relation_repository.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/repository/search_repository.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/schemas/__init__.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/schemas/base.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/schemas/delete.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/schemas/memory.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/schemas/project_info.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/schemas/request.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/schemas/response.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/schemas/search.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/services/__init__.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/services/context_service.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/services/entity_service.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/services/exceptions.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/services/link_resolver.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/services/search_service.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/services/service.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/sync/__init__.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/utils.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/static/ai_assistant_guide.md +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/static/json_canvas_spec_1_0.md +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/Non-MarkdownFileSupport.pdf +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/Screenshot.png +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/__init__.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/api/conftest.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/api/test_knowledge_router.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/api/test_memory_router.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/api/test_project_info_router.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/api/test_search_router.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/cli/conftest.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/cli/test_project_commands.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/cli/test_project_info.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/cli/test_status.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/cli/test_sync.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/cli/test_version.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/edit_file_test.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/markdown/__init__.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/markdown/test_entity_parser.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/markdown/test_markdown_plugins.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/markdown/test_observation_edge_cases.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/markdown/test_parser_edge_cases.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/markdown/test_relation_edge_cases.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/markdown/test_task_detection.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/mcp/conftest.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/mcp/test_prompts.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/mcp/test_resources.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/mcp/test_tool_memory.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/mcp/test_tool_project_info.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/mcp/test_tool_read_note.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/mcp/test_tool_resource.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/mcp/test_tool_search.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/mcp/test_tool_utils.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/mcp/test_tool_write_note.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/repository/test_entity_repository.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/repository/test_observation_repository.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/repository/test_relation_repository.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/repository/test_repository.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/schemas/test_memory_url.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/schemas/test_schemas.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/schemas/test_search.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/services/test_context_service.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/services/test_entity_service.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/services/test_file_service.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/services/test_link_resolver.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/services/test_search_service.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/sync/test_watch_service_edge_cases.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/test_basic_memory.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/test_config.py +0 -0
- {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/utils/test_parse_tags.py +0 -0
|
@@ -1,6 +1,26 @@
|
|
|
1
1
|
# CHANGELOG
|
|
2
2
|
|
|
3
3
|
|
|
4
|
+
## v0.12.2 (2025-04-08)
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
- Utf8 for all file reads/write/open instead of default platform encoding
|
|
9
|
+
([#91](https://github.com/basicmachines-co/basic-memory/pull/91),
|
|
10
|
+
[`2934176`](https://github.com/basicmachines-co/basic-memory/commit/29341763318408ea8f1e954a41046c4185f836c6))
|
|
11
|
+
|
|
12
|
+
Signed-off-by: phernandez <paul@basicmachines.co>
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
## v0.12.1 (2025-04-07)
|
|
16
|
+
|
|
17
|
+
### Bug Fixes
|
|
18
|
+
|
|
19
|
+
- Run migrations and sync when starting mcp
|
|
20
|
+
([#88](https://github.com/basicmachines-co/basic-memory/pull/88),
|
|
21
|
+
[`78a3412`](https://github.com/basicmachines-co/basic-memory/commit/78a3412bcff83b46e78e26f8b9fce42ed9e05991))
|
|
22
|
+
|
|
23
|
+
|
|
4
24
|
## v0.12.0 (2025-04-06)
|
|
5
25
|
|
|
6
26
|
### Bug Fixes
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: basic-memory
|
|
3
|
-
Version: 0.12.
|
|
3
|
+
Version: 0.12.2
|
|
4
4
|
Summary: Local-first knowledge management combining Zettelkasten with knowledge graphs
|
|
5
5
|
Project-URL: Homepage, https://github.com/basicmachines-co/basic-memory
|
|
6
6
|
Project-URL: Repository, https://github.com/basicmachines-co/basic-memory
|
|
@@ -187,7 +187,7 @@ The note embeds semantic content and links to other topics via simple Markdown f
|
|
|
187
187
|
|
|
188
188
|
3. You see this file on your computer in real time in the current project directory (default `~/$HOME/basic-memory`).
|
|
189
189
|
|
|
190
|
-
- Realtime sync
|
|
190
|
+
- Realtime sync is enabled by default with the v0.12.0 version
|
|
191
191
|
|
|
192
192
|
4. In a chat with the LLM, you can reference a topic:
|
|
193
193
|
|
|
@@ -378,13 +378,7 @@ config:
|
|
|
378
378
|
|
|
379
379
|
2. Sync your knowledge:
|
|
380
380
|
|
|
381
|
-
|
|
382
|
-
# One-time sync of local knowledge updates
|
|
383
|
-
basic-memory sync
|
|
384
|
-
|
|
385
|
-
# Run realtime sync process (recommended)
|
|
386
|
-
basic-memory sync --watch
|
|
387
|
-
```
|
|
381
|
+
Basic Memory will sync the files in your project in real time if you make manual edits.
|
|
388
382
|
|
|
389
383
|
3. In Claude Desktop, the LLM can now use these tools:
|
|
390
384
|
|
|
@@ -153,7 +153,7 @@ The note embeds semantic content and links to other topics via simple Markdown f
|
|
|
153
153
|
|
|
154
154
|
3. You see this file on your computer in real time in the current project directory (default `~/$HOME/basic-memory`).
|
|
155
155
|
|
|
156
|
-
- Realtime sync
|
|
156
|
+
- Realtime sync is enabled by default with the v0.12.0 version
|
|
157
157
|
|
|
158
158
|
4. In a chat with the LLM, you can reference a topic:
|
|
159
159
|
|
|
@@ -344,13 +344,7 @@ config:
|
|
|
344
344
|
|
|
345
345
|
2. Sync your knowledge:
|
|
346
346
|
|
|
347
|
-
|
|
348
|
-
# One-time sync of local knowledge updates
|
|
349
|
-
basic-memory sync
|
|
350
|
-
|
|
351
|
-
# Run realtime sync process (recommended)
|
|
352
|
-
basic-memory sync --watch
|
|
353
|
-
```
|
|
347
|
+
Basic Memory will sync the files in your project in real time if you make manual edits.
|
|
354
348
|
|
|
355
349
|
3. In Claude Desktop, the LLM can now use these tools:
|
|
356
350
|
|
|
@@ -29,6 +29,22 @@ Options:
|
|
|
29
29
|
- `--watch`: Continuously monitor for changes
|
|
30
30
|
- `--verbose`: Show detailed output
|
|
31
31
|
|
|
32
|
+
**Note**:
|
|
33
|
+
|
|
34
|
+
As of the v0.12.0 release syncing will occur in real time when the mcp process starts.
|
|
35
|
+
- The real time sync means that it is no longer necessary to run the `basic-memory sync --watch` process in a a terminal to sync changes to the db (so the AI can see them). This will be done automatically.
|
|
36
|
+
|
|
37
|
+
This behavior can be changed via the config. The config file for Basic Memory is in the home directory under `.basic-memory/config.json`.
|
|
38
|
+
|
|
39
|
+
To change the properties, set the following values:
|
|
40
|
+
```
|
|
41
|
+
~/.basic-memory/config.json
|
|
42
|
+
{
|
|
43
|
+
"sync_changes": false,
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Thanks for using Basic Memory!
|
|
32
48
|
### import
|
|
33
49
|
|
|
34
50
|
Imports external knowledge sources:
|
|
@@ -89,22 +89,11 @@ Replace `/absolute/path/to/uvx` with the actual path you found in Step 1.
|
|
|
89
89
|
|
|
90
90
|
Close and reopen Claude Desktop for the changes to take effect.
|
|
91
91
|
|
|
92
|
-
### 3.
|
|
92
|
+
### 3. Sync changes in real time
|
|
93
93
|
|
|
94
|
-
> Note
|
|
95
|
-
|
|
96
|
-
Start the sync service to monitor your files for changes:
|
|
97
|
-
|
|
98
|
-
```bash
|
|
99
|
-
# One-time sync
|
|
100
|
-
basic-memory sync
|
|
101
|
-
|
|
102
|
-
# For continuous monitoring (recommended)
|
|
103
|
-
basic-memory sync --watch
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
The `--watch` flag enables automatic detection of file changes, updating your knowledge in real time.
|
|
94
|
+
> **Note**: The service will sync changes from your project directory in real time so they available for the AI assistant.
|
|
107
95
|
|
|
96
|
+
To disable realtime sync, you can update the config. See [[CLI Reference#sync]].
|
|
108
97
|
### 4. Staying Updated
|
|
109
98
|
|
|
110
99
|
To update Basic Memory when new versions are released:
|
|
@@ -145,8 +134,8 @@ If Claude cannot find Basic Memory tools:
|
|
|
145
134
|
1. **Check absolute paths**: Ensure you're using complete absolute paths to uvx in the Claude Desktop configuration
|
|
146
135
|
2. **Verify installation**: Run `basic-memory --version` in Terminal to confirm Basic Memory is installed
|
|
147
136
|
3. **Restart applications**: Restart both Terminal and Claude Desktop after making configuration changes
|
|
148
|
-
4. **Check sync status**:
|
|
149
|
-
|
|
137
|
+
4. **Check sync status**: You can view the sync status by running `basic-memory status
|
|
138
|
+
.
|
|
150
139
|
#### Permission Issues
|
|
151
140
|
|
|
152
141
|
If you encounter permission errors:
|
|
@@ -282,15 +271,15 @@ basic-memory import claude conversations
|
|
|
282
271
|
basic-memory import chatgpt
|
|
283
272
|
```
|
|
284
273
|
|
|
285
|
-
After importing,
|
|
274
|
+
After importing, the changes will be synced. Initial syncs may take a few moments. You can see info about your project by running `basic-memrory project info`.
|
|
286
275
|
|
|
287
276
|
## Quick Tips
|
|
288
277
|
|
|
289
|
-
-
|
|
278
|
+
- Basic Memory will sync changes from your project in real time.
|
|
290
279
|
- Use special prompts (Continue Conversation, Recent Activity, Search) to start contextual discussions
|
|
291
280
|
- Build connections between notes for a richer knowledge graph
|
|
292
|
-
- Use direct memory
|
|
293
|
-
- Use git to version control your knowledge base
|
|
281
|
+
- Use direct `memory://` URLs with a permalink when you need precise context. See [[User Guide#Using memory // URLs]]
|
|
282
|
+
- Use git to version control your knowledge base (git integration is on the roadmap)
|
|
294
283
|
- Review and edit AI-generated notes for accuracy
|
|
295
284
|
|
|
296
285
|
## Next Steps
|
|
@@ -144,7 +144,19 @@ permalink: auth-approaches-2024
|
|
|
144
144
|
---
|
|
145
145
|
```
|
|
146
146
|
|
|
147
|
-
If not specified, one will be generated automatically from the title.
|
|
147
|
+
If not specified, one will be generated automatically from the title, if the note has has a frontmatter section.
|
|
148
|
+
|
|
149
|
+
By default a notes' permalink value will not change if the file is moved. It's a **stable** identifier :). But if you'd rather permalinks are always updated when a file moves, you can set the config setting in the global config.
|
|
150
|
+
|
|
151
|
+
The config file for Basic Memory is in the home directory under `.basic-memory/config.json`.
|
|
152
|
+
|
|
153
|
+
To change the behavior, set the following value:
|
|
154
|
+
```
|
|
155
|
+
~/.basic-memory/config.json
|
|
156
|
+
{
|
|
157
|
+
"update_permalinks_on_move": true
|
|
158
|
+
}
|
|
159
|
+
```
|
|
148
160
|
|
|
149
161
|
### Using memory:// URLs
|
|
150
162
|
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
"""FastAPI application for basic-memory knowledge graph API."""
|
|
2
2
|
|
|
3
|
-
import asyncio
|
|
4
3
|
from contextlib import asynccontextmanager
|
|
5
4
|
|
|
6
5
|
from fastapi import FastAPI, HTTPException
|
|
@@ -10,44 +9,14 @@ from loguru import logger
|
|
|
10
9
|
from basic_memory import db
|
|
11
10
|
from basic_memory.api.routers import knowledge, memory, project_info, resource, search
|
|
12
11
|
from basic_memory.config import config as project_config
|
|
13
|
-
from basic_memory.
|
|
14
|
-
from basic_memory.sync import SyncService, WatchService
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
async def run_background_sync(sync_service: SyncService, watch_service: WatchService): # pragma: no cover
|
|
18
|
-
logger.info(f"Starting watch service to sync file changes in dir: {project_config.home}")
|
|
19
|
-
# full sync
|
|
20
|
-
await sync_service.sync(project_config.home, show_progress=False)
|
|
21
|
-
|
|
22
|
-
# watch changes
|
|
23
|
-
await watch_service.run()
|
|
12
|
+
from basic_memory.services.initialization import initialize_app
|
|
24
13
|
|
|
25
14
|
|
|
26
15
|
@asynccontextmanager
|
|
27
16
|
async def lifespan(app: FastAPI): # pragma: no cover
|
|
28
17
|
"""Lifecycle manager for the FastAPI app."""
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
# app config
|
|
32
|
-
basic_memory_config = config_manager.load_config()
|
|
33
|
-
logger.info(f"Sync changes enabled: {basic_memory_config.sync_changes}")
|
|
34
|
-
logger.info(f"Update permalinks on move enabled: {basic_memory_config.update_permalinks_on_move}")
|
|
35
|
-
|
|
36
|
-
watch_task = None
|
|
37
|
-
if basic_memory_config.sync_changes:
|
|
38
|
-
# import after migrations have run
|
|
39
|
-
from basic_memory.cli.commands.sync import get_sync_service
|
|
40
|
-
|
|
41
|
-
sync_service = await get_sync_service()
|
|
42
|
-
watch_service = WatchService(
|
|
43
|
-
sync_service=sync_service,
|
|
44
|
-
file_service=sync_service.entity_service.file_service,
|
|
45
|
-
config=project_config,
|
|
46
|
-
)
|
|
47
|
-
watch_task = asyncio.create_task(run_background_sync(sync_service, watch_service))
|
|
48
|
-
else:
|
|
49
|
-
logger.info("Sync changes disabled. Skipping watch service.")
|
|
50
|
-
|
|
18
|
+
# Initialize database and file sync services
|
|
19
|
+
watch_task = await initialize_app(project_config)
|
|
51
20
|
|
|
52
21
|
# proceed with startup
|
|
53
22
|
yield
|
|
@@ -7,8 +7,11 @@ def version_callback(value: bool) -> None:
|
|
|
7
7
|
"""Show version and exit."""
|
|
8
8
|
if value: # pragma: no cover
|
|
9
9
|
import basic_memory
|
|
10
|
+
from basic_memory.config import config
|
|
10
11
|
|
|
11
12
|
typer.echo(f"Basic Memory version: {basic_memory.__version__}")
|
|
13
|
+
typer.echo(f"Current project: {config.project}")
|
|
14
|
+
typer.echo(f"Project path: {config.home}")
|
|
12
15
|
raise typer.Exit()
|
|
13
16
|
|
|
14
17
|
|
|
@@ -17,11 +20,12 @@ app = typer.Typer(name="basic-memory")
|
|
|
17
20
|
|
|
18
21
|
@app.callback()
|
|
19
22
|
def app_callback(
|
|
23
|
+
ctx: typer.Context,
|
|
20
24
|
project: Optional[str] = typer.Option(
|
|
21
25
|
None,
|
|
22
26
|
"--project",
|
|
23
27
|
"-p",
|
|
24
|
-
help="Specify which project to use",
|
|
28
|
+
help="Specify which project to use 1",
|
|
25
29
|
envvar="BASIC_MEMORY_PROJECT",
|
|
26
30
|
),
|
|
27
31
|
version: Optional[bool] = typer.Option(
|
|
@@ -34,6 +38,7 @@ def app_callback(
|
|
|
34
38
|
),
|
|
35
39
|
) -> None:
|
|
36
40
|
"""Basic Memory - Local-first personal knowledge management."""
|
|
41
|
+
|
|
37
42
|
# We use the project option to set the BASIC_MEMORY_PROJECT environment variable
|
|
38
43
|
# The config module will pick this up when loading
|
|
39
44
|
if project: # pragma: no cover
|
|
@@ -53,6 +58,13 @@ def app_callback(
|
|
|
53
58
|
|
|
54
59
|
config = new_config
|
|
55
60
|
|
|
61
|
+
# Run migrations for every command unless --version was specified
|
|
62
|
+
if not version and ctx.invoked_subcommand is not None:
|
|
63
|
+
from basic_memory.config import config
|
|
64
|
+
from basic_memory.services.initialization import ensure_initialize_database
|
|
65
|
+
|
|
66
|
+
ensure_initialize_database(config)
|
|
67
|
+
|
|
56
68
|
|
|
57
69
|
# Register sub-command groups
|
|
58
70
|
import_app = typer.Typer(help="Import data from various sources")
|
{basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/cli/commands/import_memory_json.py
RENAMED
|
@@ -38,7 +38,7 @@ async def process_memory_json(
|
|
|
38
38
|
read_task = progress.add_task("Reading memory.json...", total=None)
|
|
39
39
|
|
|
40
40
|
# First pass - collect entities and relations
|
|
41
|
-
with open(json_path) as f:
|
|
41
|
+
with open(json_path, encoding="utf-8") as f:
|
|
42
42
|
lines = f.readlines()
|
|
43
43
|
progress.update(read_task, total=len(lines))
|
|
44
44
|
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""MCP server command."""
|
|
2
|
+
|
|
3
|
+
import basic_memory
|
|
4
|
+
from basic_memory.cli.app import app
|
|
5
|
+
|
|
6
|
+
# Import mcp instance
|
|
7
|
+
from basic_memory.mcp.server import mcp as mcp_server # pragma: no cover
|
|
8
|
+
|
|
9
|
+
# Import mcp tools to register them
|
|
10
|
+
import basic_memory.mcp.tools # noqa: F401 # pragma: no cover
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@app.command()
|
|
14
|
+
def mcp(): # pragma: no cover
|
|
15
|
+
"""Run the MCP server"""
|
|
16
|
+
from basic_memory.config import config
|
|
17
|
+
import asyncio
|
|
18
|
+
from basic_memory.services.initialization import initialize_database
|
|
19
|
+
|
|
20
|
+
# First, run just the database migrations synchronously
|
|
21
|
+
asyncio.run(initialize_database(config))
|
|
22
|
+
|
|
23
|
+
# Load config to check if sync is enabled
|
|
24
|
+
from basic_memory.config import config_manager
|
|
25
|
+
|
|
26
|
+
basic_memory_config = config_manager.load_config()
|
|
27
|
+
|
|
28
|
+
if basic_memory_config.sync_changes:
|
|
29
|
+
# For now, we'll just log that sync will be handled by the MCP server
|
|
30
|
+
from loguru import logger
|
|
31
|
+
|
|
32
|
+
logger.info("File sync will be handled by the MCP server")
|
|
33
|
+
|
|
34
|
+
# Start the MCP server
|
|
35
|
+
mcp_server.run()
|
|
@@ -179,14 +179,14 @@ async def run_sync(verbose: bool = False, watch: bool = False, console_status: b
|
|
|
179
179
|
)
|
|
180
180
|
|
|
181
181
|
# full sync - no progress bars in watch mode
|
|
182
|
-
await sync_service.sync(config.home
|
|
182
|
+
await sync_service.sync(config.home)
|
|
183
183
|
|
|
184
184
|
# watch changes
|
|
185
185
|
await watch_service.run() # pragma: no cover
|
|
186
186
|
else:
|
|
187
|
-
# one time sync
|
|
187
|
+
# one time sync
|
|
188
188
|
logger.info("Running one-time sync")
|
|
189
|
-
knowledge_changes = await sync_service.sync(config.home
|
|
189
|
+
knowledge_changes = await sync_service.sync(config.home)
|
|
190
190
|
|
|
191
191
|
# Log results
|
|
192
192
|
duration_ms = int((time.time() - start_time) * 1000)
|
|
@@ -237,11 +237,11 @@ def sync(
|
|
|
237
237
|
if not isinstance(e, typer.Exit):
|
|
238
238
|
logger.exception(
|
|
239
239
|
"Sync command failed",
|
|
240
|
-
project=config.project,
|
|
241
|
-
error=str(e),
|
|
242
|
-
error_type=type(e).__name__,
|
|
243
|
-
watch_mode=watch,
|
|
244
|
-
directory=str(config.home),
|
|
240
|
+
f"project={config.project},"
|
|
241
|
+
f"error={str(e)},"
|
|
242
|
+
f"error_type={type(e).__name__},"
|
|
243
|
+
f"watch_mode={watch},"
|
|
244
|
+
f"directory={str(config.home)}",
|
|
245
245
|
)
|
|
246
246
|
typer.echo(f"Error during sync: {e}", err=True)
|
|
247
247
|
raise typer.Exit(1)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""Main CLI entry point for basic-memory.""" # pragma: no cover
|
|
2
|
+
|
|
3
|
+
from basic_memory.cli.app import app # pragma: no cover
|
|
4
|
+
|
|
5
|
+
# Register commands
|
|
6
|
+
from basic_memory.cli.commands import ( # noqa: F401 # pragma: no cover
|
|
7
|
+
db,
|
|
8
|
+
import_chatgpt,
|
|
9
|
+
import_claude_conversations,
|
|
10
|
+
import_claude_projects,
|
|
11
|
+
import_memory_json,
|
|
12
|
+
mcp,
|
|
13
|
+
project,
|
|
14
|
+
status,
|
|
15
|
+
sync,
|
|
16
|
+
tool,
|
|
17
|
+
)
|
|
18
|
+
from basic_memory.config import config
|
|
19
|
+
from basic_memory.services.initialization import ensure_initialization
|
|
20
|
+
|
|
21
|
+
if __name__ == "__main__": # pragma: no cover
|
|
22
|
+
# Run initialization if we are starting as a module
|
|
23
|
+
ensure_initialization(config)
|
|
24
|
+
|
|
25
|
+
# start the app
|
|
26
|
+
app()
|
|
@@ -35,7 +35,7 @@ class ProjectConfig(BaseSettings):
|
|
|
35
35
|
|
|
36
36
|
# Watch service configuration
|
|
37
37
|
sync_delay: int = Field(
|
|
38
|
-
default=
|
|
38
|
+
default=1000, description="Milliseconds to wait after changes before syncing", gt=0
|
|
39
39
|
)
|
|
40
40
|
|
|
41
41
|
# update permalinks on move
|
|
@@ -274,7 +274,7 @@ def setup_basic_memory_logging(): # pragma: no cover
|
|
|
274
274
|
console=False,
|
|
275
275
|
)
|
|
276
276
|
|
|
277
|
-
logger.info(f"
|
|
277
|
+
logger.info(f"Basic Memory {basic_memory.__version__} (Project: {config.project})")
|
|
278
278
|
_LOGGING_SETUP = True
|
|
279
279
|
|
|
280
280
|
|
|
@@ -104,7 +104,7 @@ class EntityParser:
|
|
|
104
104
|
absolute_path = self.base_path / path
|
|
105
105
|
|
|
106
106
|
# Parse frontmatter and content using python-frontmatter
|
|
107
|
-
file_content = absolute_path.read_text()
|
|
107
|
+
file_content = absolute_path.read_text(encoding="utf-8")
|
|
108
108
|
return await self.parse_file_content(absolute_path, file_content)
|
|
109
109
|
|
|
110
110
|
async def parse_file_content(self, absolute_path, file_content):
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""Enhanced FastMCP server instance for Basic Memory."""
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
from contextlib import asynccontextmanager
|
|
5
|
+
from typing import AsyncIterator, Optional
|
|
6
|
+
|
|
7
|
+
from mcp.server.fastmcp import FastMCP
|
|
8
|
+
from mcp.server.fastmcp.utilities.logging import configure_logging as mcp_configure_logging
|
|
9
|
+
from dataclasses import dataclass
|
|
10
|
+
|
|
11
|
+
from basic_memory.config import config as project_config
|
|
12
|
+
from basic_memory.services.initialization import initialize_app
|
|
13
|
+
|
|
14
|
+
# mcp console logging
|
|
15
|
+
mcp_configure_logging(level="ERROR")
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@dataclass
|
|
19
|
+
class AppContext:
|
|
20
|
+
watch_task: Optional[asyncio.Task]
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@asynccontextmanager
|
|
24
|
+
async def app_lifespan(server: FastMCP) -> AsyncIterator[AppContext]: # pragma: no cover
|
|
25
|
+
"""Manage application lifecycle with type-safe context"""
|
|
26
|
+
# Initialize on startup
|
|
27
|
+
watch_task = await initialize_app(project_config)
|
|
28
|
+
try:
|
|
29
|
+
yield AppContext(watch_task=watch_task)
|
|
30
|
+
finally:
|
|
31
|
+
# Cleanup on shutdown
|
|
32
|
+
if watch_task:
|
|
33
|
+
watch_task.cancel()
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
# Create the shared server instance
|
|
37
|
+
mcp = FastMCP("Basic Memory", log_level="ERROR", lifespan=app_lifespan)
|
|
@@ -137,8 +137,6 @@ class Repository[T: Base]:
|
|
|
137
137
|
|
|
138
138
|
async def find_one(self, query: Select[tuple[T]]) -> Optional[T]:
|
|
139
139
|
"""Execute a query and retrieve a single record."""
|
|
140
|
-
logger.debug(f"Finding one {self.Model.__name__} with query: {query}")
|
|
141
|
-
|
|
142
140
|
# add in load options
|
|
143
141
|
query = query.options(*self.get_load_options())
|
|
144
142
|
result = await self.execute_query(query)
|
|
@@ -270,11 +268,9 @@ class Repository[T: Base]:
|
|
|
270
268
|
"""Execute a query asynchronously."""
|
|
271
269
|
|
|
272
270
|
query = query.options(*self.get_load_options()) if use_query_options else query
|
|
273
|
-
|
|
274
271
|
logger.debug(f"Executing query: {query}")
|
|
275
272
|
async with db.scoped_session(self.session_maker) as session:
|
|
276
273
|
result = await session.execute(query)
|
|
277
|
-
logger.debug("Query executed successfully")
|
|
278
274
|
return result
|
|
279
275
|
|
|
280
276
|
def get_load_options(self) -> List[LoaderOption]:
|
|
@@ -60,7 +60,7 @@ class FileService:
|
|
|
60
60
|
Returns:
|
|
61
61
|
Raw content string without metadata sections
|
|
62
62
|
"""
|
|
63
|
-
logger.debug("Reading entity content
|
|
63
|
+
logger.debug(f"Reading entity content, entity_id={entity.id}, permalink={entity.permalink}")
|
|
64
64
|
|
|
65
65
|
file_path = self.get_entity_path(entity)
|
|
66
66
|
markdown = await self.markdown_processor.read_file(file_path)
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
"""Shared initialization service for Basic Memory.
|
|
2
|
+
|
|
3
|
+
This module provides shared initialization functions used by both CLI and API
|
|
4
|
+
to ensure consistent application startup across all entry points.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import asyncio
|
|
8
|
+
from typing import Optional
|
|
9
|
+
|
|
10
|
+
from loguru import logger
|
|
11
|
+
|
|
12
|
+
from basic_memory import db
|
|
13
|
+
from basic_memory.config import ProjectConfig, config_manager
|
|
14
|
+
from basic_memory.sync import WatchService
|
|
15
|
+
|
|
16
|
+
# Import this inside functions to avoid circular imports
|
|
17
|
+
# from basic_memory.cli.commands.sync import get_sync_service
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
async def initialize_database(app_config: ProjectConfig) -> None:
|
|
21
|
+
"""Run database migrations to ensure schema is up to date.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
app_config: The Basic Memory project configuration
|
|
25
|
+
"""
|
|
26
|
+
try:
|
|
27
|
+
logger.info("Running database migrations...")
|
|
28
|
+
await db.run_migrations(app_config)
|
|
29
|
+
logger.info("Migrations completed successfully")
|
|
30
|
+
except Exception as e:
|
|
31
|
+
logger.error(f"Error running migrations: {e}")
|
|
32
|
+
# Allow application to continue - it might still work
|
|
33
|
+
# depending on what the error was, and will fail with a
|
|
34
|
+
# more specific error if the database is actually unusable
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
async def initialize_file_sync(
|
|
38
|
+
app_config: ProjectConfig,
|
|
39
|
+
) -> asyncio.Task:
|
|
40
|
+
"""Initialize file synchronization services.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
app_config: The Basic Memory project configuration
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
Tuple of (sync_service, watch_service, watch_task) if sync is enabled,
|
|
47
|
+
or (None, None, None) if sync is disabled
|
|
48
|
+
"""
|
|
49
|
+
# Load app configuration
|
|
50
|
+
# Import here to avoid circular imports
|
|
51
|
+
from basic_memory.cli.commands.sync import get_sync_service
|
|
52
|
+
|
|
53
|
+
# Initialize sync service
|
|
54
|
+
sync_service = await get_sync_service()
|
|
55
|
+
|
|
56
|
+
# Initialize watch service
|
|
57
|
+
watch_service = WatchService(
|
|
58
|
+
sync_service=sync_service,
|
|
59
|
+
file_service=sync_service.entity_service.file_service,
|
|
60
|
+
config=app_config,
|
|
61
|
+
quiet=True,
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
# Create the background task for running sync
|
|
65
|
+
async def run_background_sync(): # pragma: no cover
|
|
66
|
+
# Run initial full sync
|
|
67
|
+
await sync_service.sync(app_config.home)
|
|
68
|
+
logger.info("Sync completed successfully")
|
|
69
|
+
|
|
70
|
+
# Start background sync task
|
|
71
|
+
logger.info(f"Starting watch service to sync file changes in dir: {app_config.home}")
|
|
72
|
+
|
|
73
|
+
# Start watching for changes
|
|
74
|
+
await watch_service.run()
|
|
75
|
+
|
|
76
|
+
watch_task = asyncio.create_task(run_background_sync())
|
|
77
|
+
logger.info("Watch service started")
|
|
78
|
+
return watch_task
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
async def initialize_app(
|
|
82
|
+
app_config: ProjectConfig,
|
|
83
|
+
) -> Optional[asyncio.Task]:
|
|
84
|
+
"""Initialize the Basic Memory application.
|
|
85
|
+
|
|
86
|
+
This function handles all initialization steps needed for both API and shor lived CLI commands.
|
|
87
|
+
For long running commands like mcp, a
|
|
88
|
+
- Running database migrations
|
|
89
|
+
- Setting up file synchronization
|
|
90
|
+
|
|
91
|
+
Args:
|
|
92
|
+
app_config: The Basic Memory project configuration
|
|
93
|
+
"""
|
|
94
|
+
# Initialize database first
|
|
95
|
+
await initialize_database(app_config)
|
|
96
|
+
|
|
97
|
+
basic_memory_config = config_manager.load_config()
|
|
98
|
+
logger.info(f"Sync changes enabled: {basic_memory_config.sync_changes}")
|
|
99
|
+
logger.info(
|
|
100
|
+
f"Update permalinks on move enabled: {basic_memory_config.update_permalinks_on_move}"
|
|
101
|
+
)
|
|
102
|
+
if not basic_memory_config.sync_changes: # pragma: no cover
|
|
103
|
+
logger.info("Sync changes disabled. Skipping watch service.")
|
|
104
|
+
return
|
|
105
|
+
|
|
106
|
+
# Initialize file sync services
|
|
107
|
+
return await initialize_file_sync(app_config)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def ensure_initialization(app_config: ProjectConfig) -> None:
|
|
111
|
+
"""Ensure initialization runs in a synchronous context.
|
|
112
|
+
|
|
113
|
+
This is a wrapper for the async initialize_app function that can be
|
|
114
|
+
called from synchronous code like CLI entry points.
|
|
115
|
+
|
|
116
|
+
Args:
|
|
117
|
+
app_config: The Basic Memory project configuration
|
|
118
|
+
"""
|
|
119
|
+
try:
|
|
120
|
+
asyncio.run(initialize_app(app_config))
|
|
121
|
+
except Exception as e:
|
|
122
|
+
logger.error(f"Error during initialization: {e}")
|
|
123
|
+
# Continue execution even if initialization fails
|
|
124
|
+
# The command might still work, or will fail with a
|
|
125
|
+
# more specific error message
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def ensure_initialize_database(app_config: ProjectConfig) -> None:
|
|
129
|
+
"""Ensure initialization runs in a synchronous context.
|
|
130
|
+
|
|
131
|
+
This is a wrapper for the async initialize_database function that can be
|
|
132
|
+
called from synchronous code like CLI entry points.
|
|
133
|
+
|
|
134
|
+
Args:
|
|
135
|
+
app_config: The Basic Memory project configuration
|
|
136
|
+
"""
|
|
137
|
+
try:
|
|
138
|
+
asyncio.run(initialize_database(app_config))
|
|
139
|
+
except Exception as e:
|
|
140
|
+
logger.error(f"Error during initialization: {e}")
|
|
141
|
+
# Continue execution even if initialization fails
|
|
142
|
+
# The command might still work, or will fail with a
|
|
143
|
+
# more specific error message
|