basic-memory 0.13.0b2__tar.gz → 0.13.0b3__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.13.0b2 → basic_memory-0.13.0b3}/PKG-INFO +1 -1
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/alembic/versions/cc7172b46608_update_search_index_schema.py +0 -1
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/api/routers/knowledge_router.py +1 -1
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/api/routers/project_router.py +6 -2
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/config.py +1 -1
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/mcp/server.py +1 -2
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/mcp/tools/move_note.py +1 -1
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/services/project_service.py +2 -1
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/services/search_service.py +1 -1
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/sync/sync_service.py +4 -2
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/test-int/conftest.py +15 -7
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/api/conftest.py +1 -1
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/api/test_knowledge_router.py +1 -1
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/api/test_project_router.py +9 -9
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/cli/conftest.py +1 -1
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/cli/test_cli_tools.py +1 -1
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/cli/test_project_info.py +0 -2
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/conftest.py +30 -16
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/mcp/test_tool_move_note.py +16 -3
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/services/test_entity_service.py +4 -5
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/services/test_project_service.py +22 -17
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/services/test_search_service.py +10 -10
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/sync/test_sync_service.py +8 -5
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/.env.oauth.example +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/.github/ISSUE_TEMPLATE/documentation.md +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/.github/dependabot.yml +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/.github/workflows/claude.yml +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/.github/workflows/dev-release.yml +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/.github/workflows/pr-title.yml +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/.github/workflows/release.yml +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/.github/workflows/test.yml +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/.gitignore +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/.mcp.json +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/.python-version +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/AUTH.md +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/CHANGELOG.md +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/CITATION.cff +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/CLA.md +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/CLAUDE.md +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/CODE_OF_CONDUCT.md +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/CONTRIBUTING.md +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/Dockerfile +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/LICENSE +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/Makefile +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/README.md +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/RELEASE_NOTES_v0.13.0.md +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/SECURITY.md +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/TESTING.md +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/basic-memory.md +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/docs/AI Assistant Guide.md +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/docs/CLI Reference.md +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/docs/Canvas.md +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/docs/Claude.ai Integration.md +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/docs/Getting Started with Basic Memory.md +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/docs/Knowledge Format.md +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/docs/OAuth Authentication Guide.md +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/docs/Obsidian Integration.md +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/docs/Supabase OAuth Setup.md +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/docs/Technical Information.md +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/docs/User Guide.md +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/docs/Welcome to Basic memory.md +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/docs/attachments/Canvas.png +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/docs/attachments/Claude-Obsidian-Demo.mp4 +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/docs/attachments/Prompt.png +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/docs/attachments/disk-ai-logo-400x400.png +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/docs/attachments/disk-ai-logo.png +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/docs/attachments/prompt 1.png +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/docs/attachments/prompt2.png +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/docs/attachments/prompt3.png +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/docs/attachments/prompt4.png +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/docs/publish.js +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/examples/Coffee Notes/Brewing Equipment.md +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/examples/Coffee Notes/Coffee Bean Origins.md +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/examples/Coffee Notes/Coffee Brewing Methods.md +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/examples/Coffee Notes/Coffee Flavor Map.md +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/examples/Coffee Notes/Coffee Knowledge Base.md +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/examples/Coffee Notes/Flavor Extraction.md +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/examples/Coffee Notes/Perfect Pour Over Coffee Method.canvas +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/examples/Coffee Notes/Tasting Notes.md +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/examples/testing/Test Note Creation - Basic Functionality.md +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/llms-install.md +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/memory.json +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/pyproject.toml +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/scripts/install.sh +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/smithery.yaml +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/__init__.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/alembic/alembic.ini +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/alembic/env.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/alembic/migrations.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/alembic/script.py.mako +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/alembic/versions/3dae7c7b1564_initial_schema.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/alembic/versions/502b60eaa905_remove_required_from_entity_permalink.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/alembic/versions/5fe1ab1ccebe_add_projects_table.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/alembic/versions/b3c3938bacdb_relation_to_name_unique_index.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/api/__init__.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/api/app.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/api/routers/__init__.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/api/routers/directory_router.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/api/routers/importer_router.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/api/routers/management_router.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/api/routers/memory_router.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/api/routers/prompt_router.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/api/routers/resource_router.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/api/routers/search_router.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/api/routers/utils.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/api/template_loader.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/cli/__init__.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/cli/app.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/cli/commands/__init__.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/cli/commands/auth.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/cli/commands/db.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/cli/commands/import_chatgpt.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/cli/commands/import_claude_conversations.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/cli/commands/import_claude_projects.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/cli/commands/import_memory_json.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/cli/commands/mcp.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/cli/commands/project.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/cli/commands/status.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/cli/commands/sync.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/cli/commands/tool.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/cli/main.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/db.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/deps.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/file_utils.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/importers/__init__.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/importers/base.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/importers/chatgpt_importer.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/importers/claude_conversations_importer.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/importers/claude_projects_importer.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/importers/memory_json_importer.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/importers/utils.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/markdown/__init__.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/markdown/entity_parser.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/markdown/markdown_processor.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/markdown/plugins.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/markdown/schemas.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/markdown/utils.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/mcp/__init__.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/mcp/async_client.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/mcp/auth_provider.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/mcp/external_auth_provider.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/mcp/project_session.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/mcp/prompts/__init__.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/mcp/prompts/ai_assistant_guide.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/mcp/prompts/continue_conversation.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/mcp/prompts/recent_activity.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/mcp/prompts/search.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/mcp/prompts/utils.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/mcp/resources/ai_assistant_guide.md +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/mcp/resources/project_info.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/mcp/supabase_auth_provider.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/mcp/tools/__init__.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/mcp/tools/build_context.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/mcp/tools/canvas.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/mcp/tools/delete_note.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/mcp/tools/edit_note.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/mcp/tools/list_directory.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/mcp/tools/project_management.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/mcp/tools/read_content.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/mcp/tools/read_note.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/mcp/tools/recent_activity.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/mcp/tools/search.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/mcp/tools/utils.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/mcp/tools/write_note.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/models/__init__.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/models/base.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/models/knowledge.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/models/project.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/models/search.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/repository/__init__.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/repository/entity_repository.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/repository/observation_repository.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/repository/project_info_repository.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/repository/project_repository.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/repository/relation_repository.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/repository/repository.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/repository/search_repository.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/schemas/__init__.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/schemas/base.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/schemas/delete.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/schemas/directory.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/schemas/importer.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/schemas/memory.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/schemas/project_info.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/schemas/prompt.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/schemas/request.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/schemas/response.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/schemas/search.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/services/__init__.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/services/context_service.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/services/directory_service.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/services/entity_service.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/services/exceptions.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/services/file_service.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/services/initialization.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/services/link_resolver.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/services/service.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/sync/__init__.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/sync/background_sync.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/sync/watch_service.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/templates/prompts/continue_conversation.hbs +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/templates/prompts/search.hbs +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/utils.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/static/ai_assistant_guide.md +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/static/json_canvas_spec_1_0.md +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/test-int/mcp/.coverage.Pauls-MacBook-Pro-2.local.66900.XDhpuELx +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/test-int/mcp/test_delete_note_integration.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/test-int/mcp/test_edit_note_integration.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/test-int/mcp/test_list_directory_integration.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/test-int/mcp/test_move_note_integration.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/test-int/mcp/test_project_management_integration.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/test-int/mcp/test_read_content_integration.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/test-int/mcp/test_read_note_integration.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/test-int/mcp/test_search_integration.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/test-int/mcp/test_write_note_integration.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/.coverage.Pauls-MacBook-Pro-2.local.28077.XqMfGOxx +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/Non-MarkdownFileSupport.pdf +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/Screenshot.png +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/__init__.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/api/.coverage.Pauls-MacBook-Pro-2.local.60974.XPpBfqqx +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/api/test_continue_conversation_template.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/api/test_directory_router.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/api/test_importer_router.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/api/test_management_router.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/api/test_memory_router.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/api/test_project_router_operations.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/api/test_prompt_router.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/api/test_resource_router.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/api/test_search_router.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/api/test_search_template.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/api/test_template_loader.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/api/test_template_loader_helpers.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/cli/.coverage.Pauls-MacBook-Pro-2.local.63666.XDIUQNrx +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/cli/test_auth_commands.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/cli/test_import_chatgpt.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/cli/test_import_claude_conversations.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/cli/test_import_claude_projects.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/cli/test_import_memory_json.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/cli/test_project_commands.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/cli/test_status.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/cli/test_sync.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/cli/test_version.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/importers/test_importer_base.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/importers/test_importer_utils.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/markdown/__init__.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/markdown/test_entity_parser.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/markdown/test_markdown_plugins.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/markdown/test_markdown_processor.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/markdown/test_observation_edge_cases.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/markdown/test_parser_edge_cases.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/markdown/test_relation_edge_cases.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/markdown/test_task_detection.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/mcp/.coverage.Pauls-MacBook-Pro-2.local.63904.XiAZuuhx +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/mcp/conftest.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/mcp/test_auth_provider.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/mcp/test_prompts.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/mcp/test_resource_project_info.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/mcp/test_resources.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/mcp/test_server.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/mcp/test_tool_build_context.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/mcp/test_tool_canvas.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/mcp/test_tool_edit_note.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/mcp/test_tool_list_directory.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/mcp/test_tool_read_note.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/mcp/test_tool_recent_activity.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/mcp/test_tool_resource.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/mcp/test_tool_search.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/mcp/test_tool_utils.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/mcp/test_tool_write_note.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/repository/test_entity_repository.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/repository/test_observation_repository.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/repository/test_project_info_repository.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/repository/test_project_repository.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/repository/test_relation_repository.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/repository/test_repository.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/repository/test_search_repository.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/schemas/test_memory_url.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/schemas/test_schemas.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/schemas/test_search.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/services/test_context_service.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/services/test_directory_service.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/services/test_file_service.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/services/test_initialization.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/services/test_link_resolver.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/services/test_project_service_operations.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/sync/test_sync_wikilink_issue.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/sync/test_tmp_files.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/sync/test_watch_service.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/sync/test_watch_service_edge_cases.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/utils/test_file_utils.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/utils/test_parse_tags.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/utils/test_permalink_formatting.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/tests/utils/test_utf8_handling.py +0 -0
- {basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/uv.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: basic-memory
|
|
3
|
-
Version: 0.13.
|
|
3
|
+
Version: 0.13.0b3
|
|
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
|
{basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/api/routers/project_router.py
RENAMED
|
@@ -145,7 +145,9 @@ async def remove_project(
|
|
|
145
145
|
try:
|
|
146
146
|
old_project = await project_service.get_project(name)
|
|
147
147
|
if not old_project: # pragma: no cover
|
|
148
|
-
raise HTTPException(
|
|
148
|
+
raise HTTPException(
|
|
149
|
+
status_code=404, detail=f"Project: '{name}' does not exist"
|
|
150
|
+
) # pragma: no cover
|
|
149
151
|
|
|
150
152
|
await project_service.remove_project(name)
|
|
151
153
|
|
|
@@ -186,7 +188,9 @@ async def set_default_project(
|
|
|
186
188
|
# get the new project
|
|
187
189
|
new_default_project = await project_service.get_project(name)
|
|
188
190
|
if not new_default_project: # pragma: no cover
|
|
189
|
-
raise HTTPException(
|
|
191
|
+
raise HTTPException(
|
|
192
|
+
status_code=404, detail=f"Project: '{name}' does not exist"
|
|
193
|
+
) # pragma: no cover
|
|
190
194
|
|
|
191
195
|
await project_service.set_default_project(name)
|
|
192
196
|
|
|
@@ -179,7 +179,7 @@ class ConfigManager:
|
|
|
179
179
|
|
|
180
180
|
def save_config(self, config: BasicMemoryConfig) -> None:
|
|
181
181
|
"""Save configuration to file."""
|
|
182
|
-
try:
|
|
182
|
+
try:
|
|
183
183
|
self.config_file.write_text(json.dumps(config.model_dump(), indent=2))
|
|
184
184
|
except Exception as e: # pragma: no cover
|
|
185
185
|
logger.error(f"Failed to save config: {e}")
|
|
@@ -31,7 +31,7 @@ async def move_note(
|
|
|
31
31
|
|
|
32
32
|
Examples:
|
|
33
33
|
- Move to new folder: move_note("My Note", "work/notes/my-note.md")
|
|
34
|
-
- Move by permalink: move_note("my-note-permalink", "archive/old-notes/my-note.md")
|
|
34
|
+
- Move by permalink: move_note("my-note-permalink", "archive/old-notes/my-note.md")
|
|
35
35
|
- Specify project: move_note("My Note", "archive/my-note.md", project="work-project")
|
|
36
36
|
|
|
37
37
|
Note: This operation moves notes within the specified project only. Moving notes
|
{basic_memory-0.13.0b2 → basic_memory-0.13.0b3}/src/basic_memory/services/project_service.py
RENAMED
|
@@ -22,6 +22,7 @@ from basic_memory.config import WATCH_STATUS_JSON
|
|
|
22
22
|
from basic_memory.utils import generate_permalink
|
|
23
23
|
from basic_memory.config import config_manager
|
|
24
24
|
|
|
25
|
+
|
|
25
26
|
class ProjectService:
|
|
26
27
|
"""Service for managing Basic Memory projects."""
|
|
27
28
|
|
|
@@ -545,4 +546,4 @@ class ProjectService:
|
|
|
545
546
|
database_size=db_size_readable,
|
|
546
547
|
watch_status=watch_status,
|
|
547
548
|
timestamp=datetime.now(),
|
|
548
|
-
)
|
|
549
|
+
)
|
|
@@ -379,7 +379,9 @@ class SyncService:
|
|
|
379
379
|
updates = {"file_path": new_path}
|
|
380
380
|
|
|
381
381
|
# If configured, also update permalink to match new path
|
|
382
|
-
if self.app_config.update_permalinks_on_move and self.file_service.is_markdown(
|
|
382
|
+
if self.app_config.update_permalinks_on_move and self.file_service.is_markdown(
|
|
383
|
+
new_path
|
|
384
|
+
):
|
|
383
385
|
# generate new permalink value
|
|
384
386
|
new_permalink = await self.entity_service.resolve_permalink(new_path)
|
|
385
387
|
|
|
@@ -505,4 +507,4 @@ class SyncService:
|
|
|
505
507
|
f"duration_ms={duration_ms}"
|
|
506
508
|
)
|
|
507
509
|
|
|
508
|
-
return result
|
|
510
|
+
return result
|
|
@@ -49,10 +49,8 @@ async def test_my_mcp_tool(mcp_server, app):
|
|
|
49
49
|
The `app` fixture ensures FastAPI dependency overrides are active, and
|
|
50
50
|
`mcp_server` provides the MCP server with proper project session initialization.
|
|
51
51
|
"""
|
|
52
|
-
|
|
52
|
+
|
|
53
53
|
from typing import AsyncGenerator
|
|
54
|
-
from unittest import mock
|
|
55
|
-
from unittest.mock import patch
|
|
56
54
|
|
|
57
55
|
import pytest
|
|
58
56
|
import pytest_asyncio
|
|
@@ -110,21 +108,29 @@ async def test_project(tmp_path, engine_factory) -> Project:
|
|
|
110
108
|
project = await project_repository.create(project_data)
|
|
111
109
|
return project
|
|
112
110
|
|
|
111
|
+
|
|
113
112
|
@pytest.fixture
|
|
114
113
|
def config_home(tmp_path, monkeypatch) -> Path:
|
|
115
114
|
monkeypatch.setenv("HOME", str(tmp_path))
|
|
116
115
|
return tmp_path
|
|
117
116
|
|
|
117
|
+
|
|
118
118
|
@pytest.fixture(scope="function")
|
|
119
119
|
def app_config(config_home, test_project, tmp_path, monkeypatch) -> BasicMemoryConfig:
|
|
120
120
|
"""Create test app configuration."""
|
|
121
121
|
projects = {test_project.name: str(test_project.path)}
|
|
122
|
-
app_config = BasicMemoryConfig(
|
|
122
|
+
app_config = BasicMemoryConfig(
|
|
123
|
+
env="test",
|
|
124
|
+
projects=projects,
|
|
125
|
+
default_project=test_project.name,
|
|
126
|
+
update_permalinks_on_move=True,
|
|
127
|
+
)
|
|
123
128
|
|
|
124
129
|
# Set the module app_config instance project list (like regular tests)
|
|
125
130
|
monkeypatch.setattr("basic_memory.config.app_config", app_config)
|
|
126
131
|
return app_config
|
|
127
132
|
|
|
133
|
+
|
|
128
134
|
@pytest.fixture
|
|
129
135
|
def config_manager(app_config: BasicMemoryConfig, config_home, monkeypatch) -> ConfigManager:
|
|
130
136
|
config_manager = ConfigManager()
|
|
@@ -145,6 +151,7 @@ def config_manager(app_config: BasicMemoryConfig, config_home, monkeypatch) -> C
|
|
|
145
151
|
|
|
146
152
|
return config_manager
|
|
147
153
|
|
|
154
|
+
|
|
148
155
|
@pytest.fixture
|
|
149
156
|
def project_session(test_project: Project):
|
|
150
157
|
# initialize the project session with the test project
|
|
@@ -166,9 +173,10 @@ def project_config(test_project, monkeypatch):
|
|
|
166
173
|
return project_config
|
|
167
174
|
|
|
168
175
|
|
|
169
|
-
|
|
170
176
|
@pytest.fixture(scope="function")
|
|
171
|
-
def app(
|
|
177
|
+
def app(
|
|
178
|
+
app_config, project_config, engine_factory, test_project, project_session, config_manager
|
|
179
|
+
) -> FastAPI:
|
|
172
180
|
"""Create test FastAPI application with single project."""
|
|
173
181
|
|
|
174
182
|
app = fastapi_app
|
|
@@ -228,4 +236,4 @@ def mcp_server(app_config, search_service):
|
|
|
228
236
|
async def client(app: FastAPI) -> AsyncGenerator[AsyncClient, None]:
|
|
229
237
|
"""Create test client that both MCP and tests will use."""
|
|
230
238
|
async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as client:
|
|
231
|
-
yield client
|
|
239
|
+
yield client
|
|
@@ -37,4 +37,4 @@ def project_url(test_project: Project) -> str:
|
|
|
37
37
|
"""
|
|
38
38
|
# Make sure this matches what's in tests/conftest.py for test_project creation
|
|
39
39
|
# The permalink should be generated from "Test Project Context"
|
|
40
|
-
return f"/{test_project.permalink}"
|
|
40
|
+
return f"/{test_project.permalink}"
|
|
@@ -930,7 +930,7 @@ async def test_move_entity_success(client: AsyncClient, project_url):
|
|
|
930
930
|
assert response.status_code == 200
|
|
931
931
|
response_model = EntityResponse.model_validate(response.json())
|
|
932
932
|
assert response_model.file_path == "target/MovedNote.md"
|
|
933
|
-
|
|
933
|
+
|
|
934
934
|
# Verify original entity no longer exists
|
|
935
935
|
response = await client.get(f"{project_url}/knowledge/entities/{original_permalink}")
|
|
936
936
|
assert response.status_code == 404
|
|
@@ -149,25 +149,25 @@ async def test_remove_project_endpoint(test_config, client, project_service):
|
|
|
149
149
|
# First create a test project to remove
|
|
150
150
|
test_project_name = "test-remove-project"
|
|
151
151
|
await project_service.add_project(test_project_name, "/tmp/test-remove-project")
|
|
152
|
-
|
|
152
|
+
|
|
153
153
|
# Verify it exists
|
|
154
154
|
project = await project_service.get_project(test_project_name)
|
|
155
155
|
assert project is not None
|
|
156
|
-
|
|
156
|
+
|
|
157
157
|
# Remove the project
|
|
158
158
|
response = await client.delete(f"/projects/{test_project_name}")
|
|
159
|
-
|
|
159
|
+
|
|
160
160
|
# Verify response
|
|
161
161
|
assert response.status_code == 200
|
|
162
162
|
data = response.json()
|
|
163
|
-
|
|
163
|
+
|
|
164
164
|
# Check response structure
|
|
165
165
|
assert "message" in data
|
|
166
166
|
assert "status" in data
|
|
167
167
|
assert data["status"] == "success"
|
|
168
168
|
assert "old_project" in data
|
|
169
169
|
assert data["old_project"]["name"] == test_project_name
|
|
170
|
-
|
|
170
|
+
|
|
171
171
|
# Verify project is actually removed
|
|
172
172
|
removed_project = await project_service.get_project(test_project_name)
|
|
173
173
|
assert removed_project is None
|
|
@@ -179,20 +179,20 @@ async def test_set_default_project_endpoint(test_config, client, project_service
|
|
|
179
179
|
# Create a test project to set as default
|
|
180
180
|
test_project_name = "test-default-project"
|
|
181
181
|
await project_service.add_project(test_project_name, "/tmp/test-default-project")
|
|
182
|
-
|
|
182
|
+
|
|
183
183
|
# Set it as default
|
|
184
184
|
response = await client.put(f"/projects/{test_project_name}/default")
|
|
185
|
-
|
|
185
|
+
|
|
186
186
|
# Verify response
|
|
187
187
|
assert response.status_code == 200
|
|
188
188
|
data = response.json()
|
|
189
|
-
|
|
189
|
+
|
|
190
190
|
# Check response structure
|
|
191
191
|
assert "message" in data
|
|
192
192
|
assert "status" in data
|
|
193
193
|
assert data["status"] == "success"
|
|
194
194
|
assert "new_project" in data
|
|
195
195
|
assert data["new_project"]["name"] == test_project_name
|
|
196
|
-
|
|
196
|
+
|
|
197
197
|
# Verify it's actually set as default
|
|
198
198
|
assert project_service.default_project == test_project_name
|
|
@@ -29,4 +29,4 @@ async def client(app: FastAPI) -> AsyncGenerator[AsyncClient, None]:
|
|
|
29
29
|
@pytest.fixture
|
|
30
30
|
def cli_env(project_config, client, test_config):
|
|
31
31
|
"""Set up CLI environment with correct project session."""
|
|
32
|
-
return {"project_config": project_config, "client": client}
|
|
32
|
+
return {"project_config": project_config, "client": client}
|
|
@@ -439,4 +439,4 @@ def test_ensure_migrations_handles_errors(mock_initialize_database, project_conf
|
|
|
439
439
|
# Call the function - should not raise exception
|
|
440
440
|
ensure_initialization(project_config)
|
|
441
441
|
|
|
442
|
-
# We're just making sure it doesn't crash by calling it
|
|
442
|
+
# We're just making sure it doesn't crash by calling it
|
|
@@ -5,7 +5,6 @@ import json
|
|
|
5
5
|
from typer.testing import CliRunner
|
|
6
6
|
|
|
7
7
|
from basic_memory.cli.main import app as cli_app
|
|
8
|
-
from basic_memory.config import config
|
|
9
8
|
|
|
10
9
|
|
|
11
10
|
def test_info_stats_command(cli_env, test_graph, project_session):
|
|
@@ -15,7 +14,6 @@ def test_info_stats_command(cli_env, test_graph, project_session):
|
|
|
15
14
|
# Run the command
|
|
16
15
|
result = runner.invoke(cli_app, ["project", "info"])
|
|
17
16
|
|
|
18
|
-
|
|
19
17
|
# Verify exit code
|
|
20
18
|
assert result.exit_code == 0
|
|
21
19
|
|
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
"""Common test fixtures."""
|
|
2
|
-
|
|
2
|
+
|
|
3
3
|
from dataclasses import dataclass
|
|
4
4
|
from datetime import datetime, timezone
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
from textwrap import dedent
|
|
7
7
|
from typing import AsyncGenerator
|
|
8
|
-
from unittest import mock
|
|
9
|
-
from unittest.mock import patch
|
|
10
8
|
|
|
11
9
|
import pytest
|
|
12
10
|
import pytest_asyncio
|
|
13
|
-
from loguru import logger
|
|
14
11
|
from sqlalchemy.ext.asyncio import AsyncEngine, AsyncSession, async_sessionmaker
|
|
15
12
|
|
|
16
13
|
import basic_memory.mcp.project_session
|
|
@@ -49,42 +46,52 @@ def anyio_backend():
|
|
|
49
46
|
def project_root() -> Path:
|
|
50
47
|
return Path(__file__).parent.parent
|
|
51
48
|
|
|
49
|
+
|
|
52
50
|
@pytest.fixture
|
|
53
51
|
def config_home(tmp_path, monkeypatch) -> Path:
|
|
54
52
|
# Patch HOME environment variable for the duration of the test
|
|
55
53
|
monkeypatch.setenv("HOME", str(tmp_path))
|
|
56
54
|
return tmp_path
|
|
57
55
|
|
|
56
|
+
|
|
58
57
|
@pytest.fixture(scope="function", autouse=True)
|
|
59
58
|
def app_config(config_home, tmp_path, monkeypatch) -> BasicMemoryConfig:
|
|
60
59
|
"""Create test app configuration."""
|
|
61
60
|
# Create a basic config without depending on test_project to avoid circular dependency
|
|
62
61
|
projects = {"test-project": str(config_home)}
|
|
63
|
-
app_config = BasicMemoryConfig(
|
|
64
|
-
|
|
62
|
+
app_config = BasicMemoryConfig(
|
|
63
|
+
env="test",
|
|
64
|
+
projects=projects,
|
|
65
|
+
default_project="test-project",
|
|
66
|
+
update_permalinks_on_move=True,
|
|
67
|
+
)
|
|
65
68
|
|
|
66
69
|
# Patch the module app_config instance for the duration of the test
|
|
67
70
|
monkeypatch.setattr("basic_memory.config.app_config", app_config)
|
|
68
71
|
return app_config
|
|
69
72
|
|
|
73
|
+
|
|
70
74
|
@pytest.fixture(autouse=True)
|
|
71
|
-
def config_manager(
|
|
75
|
+
def config_manager(
|
|
76
|
+
app_config: BasicMemoryConfig, project_config: ProjectConfig, config_home: Path, monkeypatch
|
|
77
|
+
) -> ConfigManager:
|
|
72
78
|
# Create a new ConfigManager that uses the test home directory
|
|
73
79
|
config_manager = ConfigManager()
|
|
74
80
|
# Update its paths to use the test directory
|
|
75
81
|
config_manager.config_dir = config_home / ".basic-memory"
|
|
76
82
|
config_manager.config_file = config_manager.config_dir / "config.json"
|
|
77
83
|
config_manager.config_dir.mkdir(parents=True, exist_ok=True)
|
|
78
|
-
|
|
84
|
+
|
|
79
85
|
# Override the config directly instead of relying on disk load
|
|
80
86
|
config_manager.config = app_config
|
|
81
|
-
|
|
87
|
+
|
|
82
88
|
# Ensure the config file is written to disk
|
|
83
89
|
config_manager.save_config(app_config)
|
|
84
|
-
|
|
90
|
+
|
|
85
91
|
# Patch the config_manager in all locations where it's imported
|
|
86
92
|
monkeypatch.setattr("basic_memory.config.config_manager", config_manager)
|
|
87
93
|
monkeypatch.setattr("basic_memory.services.project_service.config_manager", config_manager)
|
|
94
|
+
|
|
88
95
|
# Mock get_project_config to return test project config for test-project, fallback for others
|
|
89
96
|
def mock_get_project_config(project_name=None):
|
|
90
97
|
if project_name == "test-project" or project_name is None:
|
|
@@ -92,18 +99,24 @@ def config_manager(app_config: BasicMemoryConfig, project_config: ProjectConfig,
|
|
|
92
99
|
# For any other project name, return a default config pointing to test location
|
|
93
100
|
fallback_config = ProjectConfig(name=project_name or "main", home=Path(config_home))
|
|
94
101
|
return fallback_config
|
|
95
|
-
|
|
96
|
-
|
|
102
|
+
|
|
103
|
+
monkeypatch.setattr(
|
|
104
|
+
"basic_memory.mcp.project_session.get_project_config", mock_get_project_config
|
|
105
|
+
)
|
|
106
|
+
|
|
97
107
|
# Patch the project config that CLI commands import (only modules that actually import config)
|
|
98
108
|
monkeypatch.setattr("basic_memory.cli.commands.project.config", project_config)
|
|
99
109
|
monkeypatch.setattr("basic_memory.cli.commands.sync.config", project_config)
|
|
100
110
|
monkeypatch.setattr("basic_memory.cli.commands.status.config", project_config)
|
|
101
111
|
monkeypatch.setattr("basic_memory.cli.commands.import_memory_json.config", project_config)
|
|
102
112
|
monkeypatch.setattr("basic_memory.cli.commands.import_claude_projects.config", project_config)
|
|
103
|
-
monkeypatch.setattr(
|
|
113
|
+
monkeypatch.setattr(
|
|
114
|
+
"basic_memory.cli.commands.import_claude_conversations.config", project_config
|
|
115
|
+
)
|
|
104
116
|
monkeypatch.setattr("basic_memory.cli.commands.import_chatgpt.config", project_config)
|
|
105
117
|
return config_manager
|
|
106
118
|
|
|
119
|
+
|
|
107
120
|
@pytest.fixture(autouse=True)
|
|
108
121
|
def project_session(test_project: Project):
|
|
109
122
|
# initialize the project session with the test project
|
|
@@ -134,17 +147,18 @@ class TestConfig:
|
|
|
134
147
|
app_config: BasicMemoryConfig
|
|
135
148
|
config_manager: ConfigManager
|
|
136
149
|
|
|
150
|
+
|
|
137
151
|
@pytest.fixture
|
|
138
152
|
def test_config(config_home, project_config, app_config, config_manager) -> TestConfig:
|
|
139
153
|
"""All test configuration fixtures"""
|
|
140
|
-
|
|
154
|
+
|
|
141
155
|
@dataclass
|
|
142
156
|
class TestConfig:
|
|
143
157
|
config_home: Path
|
|
144
158
|
project_config: ProjectConfig
|
|
145
159
|
app_config: BasicMemoryConfig
|
|
146
160
|
config_manager: ConfigManager
|
|
147
|
-
|
|
161
|
+
|
|
148
162
|
return TestConfig(config_home, project_config, app_config, config_manager)
|
|
149
163
|
|
|
150
164
|
|
|
@@ -501,4 +515,4 @@ def test_files(project_config, project_root) -> dict[str, Path]:
|
|
|
501
515
|
async def synced_files(sync_service, project_config, test_files):
|
|
502
516
|
# Initial sync - should create forward reference
|
|
503
517
|
await sync_service.sync(project_config.home)
|
|
504
|
-
return test_files
|
|
518
|
+
return test_files
|
|
@@ -167,7 +167,11 @@ async def test_move_note_nonexistent_note(client):
|
|
|
167
167
|
|
|
168
168
|
# Should raise an exception from the API with friendly error message
|
|
169
169
|
error_msg = str(exc_info.value)
|
|
170
|
-
assert
|
|
170
|
+
assert (
|
|
171
|
+
"Entity not found" in error_msg
|
|
172
|
+
or "Invalid request" in error_msg
|
|
173
|
+
or "malformed" in error_msg
|
|
174
|
+
)
|
|
171
175
|
|
|
172
176
|
|
|
173
177
|
@pytest.mark.asyncio
|
|
@@ -222,7 +226,11 @@ async def test_move_note_destination_exists(client):
|
|
|
222
226
|
|
|
223
227
|
# Should raise an exception (400 gets wrapped as malformed request)
|
|
224
228
|
error_msg = str(exc_info.value)
|
|
225
|
-
assert
|
|
229
|
+
assert (
|
|
230
|
+
"Destination already exists" in error_msg
|
|
231
|
+
or "Invalid request" in error_msg
|
|
232
|
+
or "malformed" in error_msg
|
|
233
|
+
)
|
|
226
234
|
|
|
227
235
|
|
|
228
236
|
@pytest.mark.asyncio
|
|
@@ -244,7 +252,12 @@ async def test_move_note_same_location(client):
|
|
|
244
252
|
|
|
245
253
|
# Should raise an exception (400 gets wrapped as malformed request)
|
|
246
254
|
error_msg = str(exc_info.value)
|
|
247
|
-
assert
|
|
255
|
+
assert (
|
|
256
|
+
"Destination already exists" in error_msg
|
|
257
|
+
or "same location" in error_msg
|
|
258
|
+
or "Invalid request" in error_msg
|
|
259
|
+
or "malformed" in error_msg
|
|
260
|
+
)
|
|
248
261
|
|
|
249
262
|
|
|
250
263
|
@pytest.mark.asyncio
|
|
@@ -1230,7 +1230,7 @@ async def test_move_entity_success(
|
|
|
1230
1230
|
|
|
1231
1231
|
# Move entity
|
|
1232
1232
|
assert entity.permalink == "original/test-note"
|
|
1233
|
-
|
|
1233
|
+
await entity_service.move_entity(
|
|
1234
1234
|
identifier=entity.permalink,
|
|
1235
1235
|
destination_path="moved/test-note.md",
|
|
1236
1236
|
project_config=project_config,
|
|
@@ -1276,14 +1276,13 @@ async def test_move_entity_with_permalink_update(
|
|
|
1276
1276
|
app_config = BasicMemoryConfig(update_permalinks_on_move=True)
|
|
1277
1277
|
|
|
1278
1278
|
# Move entity
|
|
1279
|
-
|
|
1279
|
+
await entity_service.move_entity(
|
|
1280
1280
|
identifier=entity.permalink,
|
|
1281
1281
|
destination_path="moved/test-note.md",
|
|
1282
1282
|
project_config=project_config,
|
|
1283
1283
|
app_config=app_config,
|
|
1284
1284
|
)
|
|
1285
1285
|
|
|
1286
|
-
|
|
1287
1286
|
# Verify entity was found by new path (since permalink changed)
|
|
1288
1287
|
moved_entity = await entity_service.link_resolver.resolve_link("moved/test-note.md")
|
|
1289
1288
|
assert moved_entity is not None
|
|
@@ -1473,7 +1472,7 @@ async def test_move_entity_by_title(
|
|
|
1473
1472
|
app_config = BasicMemoryConfig(update_permalinks_on_move=False)
|
|
1474
1473
|
|
|
1475
1474
|
# Move by title
|
|
1476
|
-
|
|
1475
|
+
await entity_service.move_entity(
|
|
1477
1476
|
identifier="Test Note", # Use title instead of permalink
|
|
1478
1477
|
destination_path="moved/test-note.md",
|
|
1479
1478
|
project_config=project_config,
|
|
@@ -1657,4 +1656,4 @@ async def test_move_entity_with_complex_observations(
|
|
|
1657
1656
|
relation_targets = {rel.to_name for rel in moved_entity.relations}
|
|
1658
1657
|
assert "Branch Strategy" in relation_targets
|
|
1659
1658
|
assert "Multiple" in relation_targets
|
|
1660
|
-
assert "Links" in relation_targets
|
|
1659
|
+
assert "Links" in relation_targets
|
|
@@ -13,6 +13,7 @@ from basic_memory.schemas import (
|
|
|
13
13
|
from basic_memory.services.project_service import ProjectService
|
|
14
14
|
from basic_memory.config import ConfigManager
|
|
15
15
|
|
|
16
|
+
|
|
16
17
|
def test_projects_property(project_service: ProjectService):
|
|
17
18
|
"""Test the projects property."""
|
|
18
19
|
# Get the projects
|
|
@@ -63,7 +64,9 @@ def test_current_project_property(project_service: ProjectService):
|
|
|
63
64
|
|
|
64
65
|
|
|
65
66
|
@pytest.mark.asyncio
|
|
66
|
-
async def test_project_operations_sync_methods(
|
|
67
|
+
async def test_project_operations_sync_methods(
|
|
68
|
+
app_config, project_service: ProjectService, config_manager: ConfigManager, tmp_path
|
|
69
|
+
):
|
|
67
70
|
"""Test adding, switching, and removing a project using ConfigManager directly.
|
|
68
71
|
|
|
69
72
|
This test uses the ConfigManager directly instead of the async methods.
|
|
@@ -241,24 +244,24 @@ async def test_get_project_method(project_service: ProjectService, tmp_path):
|
|
|
241
244
|
"""Test the get_project method directly."""
|
|
242
245
|
test_project_name = f"test-get-project-{os.urandom(4).hex()}"
|
|
243
246
|
test_project_path = str(tmp_path / "test-get-project")
|
|
244
|
-
|
|
247
|
+
|
|
245
248
|
# Make sure the test directory exists
|
|
246
249
|
os.makedirs(test_project_path, exist_ok=True)
|
|
247
|
-
|
|
250
|
+
|
|
248
251
|
try:
|
|
249
252
|
# Test getting a non-existent project
|
|
250
253
|
result = await project_service.get_project("non-existent-project")
|
|
251
254
|
assert result is None
|
|
252
|
-
|
|
255
|
+
|
|
253
256
|
# Add a project
|
|
254
257
|
await project_service.add_project(test_project_name, test_project_path)
|
|
255
|
-
|
|
258
|
+
|
|
256
259
|
# Test getting an existing project
|
|
257
260
|
result = await project_service.get_project(test_project_name)
|
|
258
261
|
assert result is not None
|
|
259
262
|
assert result.name == test_project_name
|
|
260
263
|
assert result.path == test_project_path
|
|
261
|
-
|
|
264
|
+
|
|
262
265
|
finally:
|
|
263
266
|
# Clean up
|
|
264
267
|
if test_project_name in project_service.projects:
|
|
@@ -266,36 +269,38 @@ async def test_get_project_method(project_service: ProjectService, tmp_path):
|
|
|
266
269
|
|
|
267
270
|
|
|
268
271
|
@pytest.mark.asyncio
|
|
269
|
-
async def test_set_default_project_config_db_mismatch(
|
|
272
|
+
async def test_set_default_project_config_db_mismatch(
|
|
273
|
+
project_service: ProjectService, config_manager: ConfigManager, tmp_path
|
|
274
|
+
):
|
|
270
275
|
"""Test set_default_project when project exists in config but not in database."""
|
|
271
276
|
test_project_name = f"test-mismatch-project-{os.urandom(4).hex()}"
|
|
272
277
|
test_project_path = str(tmp_path / "test-mismatch-project")
|
|
273
|
-
|
|
274
|
-
# Make sure the test directory exists
|
|
278
|
+
|
|
279
|
+
# Make sure the test directory exists
|
|
275
280
|
os.makedirs(test_project_path, exist_ok=True)
|
|
276
|
-
|
|
281
|
+
|
|
277
282
|
original_default = project_service.default_project
|
|
278
|
-
|
|
283
|
+
|
|
279
284
|
try:
|
|
280
285
|
# Add project to config only (not to database)
|
|
281
286
|
config_manager.add_project(test_project_name, test_project_path)
|
|
282
|
-
|
|
287
|
+
|
|
283
288
|
# Verify it's in config but not in database
|
|
284
289
|
assert test_project_name in project_service.projects
|
|
285
290
|
db_project = await project_service.repository.get_by_name(test_project_name)
|
|
286
291
|
assert db_project is None
|
|
287
|
-
|
|
292
|
+
|
|
288
293
|
# Try to set as default - this should trigger the error log on line 142
|
|
289
294
|
await project_service.set_default_project(test_project_name)
|
|
290
|
-
|
|
295
|
+
|
|
291
296
|
# Should still update config despite database mismatch
|
|
292
297
|
assert project_service.default_project == test_project_name
|
|
293
|
-
|
|
298
|
+
|
|
294
299
|
finally:
|
|
295
300
|
# Restore original default
|
|
296
301
|
if original_default:
|
|
297
302
|
config_manager.set_default_project(original_default)
|
|
298
|
-
|
|
303
|
+
|
|
299
304
|
# Clean up
|
|
300
305
|
if test_project_name in project_service.projects:
|
|
301
|
-
config_manager.remove_project(test_project_name)
|
|
306
|
+
config_manager.remove_project(test_project_name)
|
|
@@ -202,7 +202,7 @@ async def test_search_entity_type(search_service, test_graph):
|
|
|
202
202
|
async def test_extract_entity_tags_exception_handling(search_service):
|
|
203
203
|
"""Test the _extract_entity_tags method exception handling (lines 147-151)."""
|
|
204
204
|
from basic_memory.models.knowledge import Entity
|
|
205
|
-
|
|
205
|
+
|
|
206
206
|
# Create entity with string tags that will cause parsing to fail and fall back to single tag
|
|
207
207
|
entity_with_invalid_tags = Entity(
|
|
208
208
|
title="Test Entity",
|
|
@@ -210,23 +210,23 @@ async def test_extract_entity_tags_exception_handling(search_service):
|
|
|
210
210
|
entity_metadata={"tags": "just a string"}, # This will fail ast.literal_eval
|
|
211
211
|
content_type="text/markdown",
|
|
212
212
|
file_path="test/test-entity.md",
|
|
213
|
-
project_id=1
|
|
213
|
+
project_id=1,
|
|
214
214
|
)
|
|
215
|
-
|
|
215
|
+
|
|
216
216
|
# This should trigger the except block on lines 147-149
|
|
217
217
|
result = search_service._extract_entity_tags(entity_with_invalid_tags)
|
|
218
|
-
assert result == [
|
|
219
|
-
|
|
218
|
+
assert result == ["just a string"]
|
|
219
|
+
|
|
220
220
|
# Test with empty string (should return empty list) - covers line 149
|
|
221
221
|
entity_with_empty_tags = Entity(
|
|
222
222
|
title="Test Entity Empty",
|
|
223
|
-
entity_type="test",
|
|
223
|
+
entity_type="test",
|
|
224
224
|
entity_metadata={"tags": ""},
|
|
225
225
|
content_type="text/markdown",
|
|
226
226
|
file_path="test/test-entity-empty.md",
|
|
227
|
-
project_id=1
|
|
227
|
+
project_id=1,
|
|
228
228
|
)
|
|
229
|
-
|
|
229
|
+
|
|
230
230
|
result = search_service._extract_entity_tags(entity_with_empty_tags)
|
|
231
231
|
assert result == []
|
|
232
232
|
|
|
@@ -234,10 +234,10 @@ async def test_extract_entity_tags_exception_handling(search_service):
|
|
|
234
234
|
@pytest.mark.asyncio
|
|
235
235
|
async def test_delete_entity_without_permalink(search_service, sample_entity):
|
|
236
236
|
"""Test deleting an entity that has no permalink (edge case)."""
|
|
237
|
-
|
|
237
|
+
|
|
238
238
|
# Set the entity permalink to None to trigger the else branch on line 355
|
|
239
239
|
sample_entity.permalink = None
|
|
240
|
-
|
|
240
|
+
|
|
241
241
|
# This should trigger the delete_by_entity_id path (line 355) in handle_delete
|
|
242
242
|
await search_service.handle_delete(sample_entity)
|
|
243
243
|
|