basic-memory 0.13.0b5__tar.gz → 0.13.0b6__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.0b5 → basic_memory-0.13.0b6}/.github/workflows/release.yml +4 -10
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/PKG-INFO +1 -1
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/RELEASE_NOTES_v0.13.0.md +1 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/docs/AI Assistant Guide.md +7 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/__init__.py +2 -1
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/cli/commands/project.py +1 -1
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/cli/commands/tool.py +6 -6
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/mcp/prompts/recent_activity.py +1 -1
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/mcp/tools/read_note.py +2 -2
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/mcp/tools/view_note.py +1 -1
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/repository/search_repository.py +17 -12
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/services/entity_service.py +14 -1
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/services/project_service.py +24 -3
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/sync/sync_service.py +36 -11
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/static/ai_assistant_guide.md +7 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/cli/test_project_info.py +2 -2
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/mcp/test_prompts.py +9 -9
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/mcp/test_resource_project_info.py +2 -2
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/mcp/test_resources.py +1 -1
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/mcp/test_tool_build_context.py +7 -7
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/mcp/test_tool_canvas.py +6 -6
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/mcp/test_tool_edit_note.py +33 -31
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/mcp/test_tool_list_directory.py +17 -17
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/mcp/test_tool_move_note.py +46 -46
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/mcp/test_tool_read_note.py +17 -17
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/mcp/test_tool_recent_activity.py +10 -10
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/mcp/test_tool_resource.py +10 -10
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/mcp/test_tool_search.py +18 -18
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/mcp/test_tool_sync_status.py +7 -7
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/mcp/test_tool_view_note.py +30 -26
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/mcp/test_tool_write_note.py +21 -21
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/repository/test_search_repository.py +34 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/services/test_entity_service.py +113 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/services/test_project_service.py +132 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/sync/test_sync_service.py +222 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/uv.lock +3 -3
- basic_memory-0.13.0b5/TESTING.md +0 -337
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/.claude/commands/check-health.md +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/.claude/commands/commands.md +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/.claude/commands/lint-fix.md +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/.claude/commands/release/beta.md +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/.claude/commands/release/changelog.md +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/.claude/commands/release/release-check.md +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/.claude/commands/release/release.md +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/.claude/commands/test-coverage.md +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/.claude/commands/test-live.md +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/.env.oauth.example +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/.github/ISSUE_TEMPLATE/documentation.md +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/.github/dependabot.yml +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/.github/workflows/claude.yml +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/.github/workflows/dev-release.yml +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/.github/workflows/pr-title.yml +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/.github/workflows/test.yml +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/.gitignore +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/.mcp.json +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/.python-version +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/AUTH.md +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/CHANGELOG.md +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/CITATION.cff +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/CLA.md +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/CLAUDE.md +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/CODE_OF_CONDUCT.md +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/CONTRIBUTING.md +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/Dockerfile +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/LICENSE +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/README.md +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/SECURITY.md +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/basic-memory.md +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/docs/CLI Reference.md +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/docs/Canvas.md +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/docs/Claude.ai Integration.md +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/docs/Getting Started with Basic Memory.md +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/docs/Knowledge Format.md +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/docs/OAuth Authentication Guide.md +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/docs/Obsidian Integration.md +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/docs/Supabase OAuth Setup.md +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/docs/Technical Information.md +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/docs/User Guide.md +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/docs/Welcome to Basic memory.md +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/docs/attachments/Canvas.png +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/docs/attachments/Claude-Obsidian-Demo.mp4 +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/docs/attachments/Prompt.png +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/docs/attachments/disk-ai-logo-400x400.png +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/docs/attachments/disk-ai-logo.png +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/docs/attachments/prompt 1.png +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/docs/attachments/prompt2.png +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/docs/attachments/prompt3.png +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/docs/attachments/prompt4.png +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/docs/publish.js +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/examples/Coffee Notes/Brewing Equipment.md +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/examples/Coffee Notes/Coffee Bean Origins.md +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/examples/Coffee Notes/Coffee Brewing Methods.md +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/examples/Coffee Notes/Coffee Flavor Map.md +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/examples/Coffee Notes/Coffee Knowledge Base.md +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/examples/Coffee Notes/Flavor Extraction.md +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/examples/Coffee Notes/Perfect Pour Over Coffee Method.canvas +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/examples/Coffee Notes/Tasting Notes.md +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/examples/testing/Test Note Creation - Basic Functionality.md +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/justfile +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/llms-install.md +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/memory.json +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/pyproject.toml +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/scripts/install.sh +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/smithery.yaml +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/alembic/alembic.ini +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/alembic/env.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/alembic/migrations.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/alembic/script.py.mako +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/alembic/versions/3dae7c7b1564_initial_schema.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/alembic/versions/502b60eaa905_remove_required_from_entity_permalink.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/alembic/versions/5fe1ab1ccebe_add_projects_table.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/alembic/versions/647e7a75e2cd_project_constraint_fix.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/alembic/versions/b3c3938bacdb_relation_to_name_unique_index.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/alembic/versions/cc7172b46608_update_search_index_schema.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/api/__init__.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/api/app.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/api/routers/__init__.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/api/routers/directory_router.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/api/routers/importer_router.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/api/routers/knowledge_router.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/api/routers/management_router.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/api/routers/memory_router.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/api/routers/project_router.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/api/routers/prompt_router.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/api/routers/resource_router.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/api/routers/search_router.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/api/routers/utils.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/api/template_loader.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/cli/__init__.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/cli/app.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/cli/commands/__init__.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/cli/commands/auth.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/cli/commands/db.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/cli/commands/import_chatgpt.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/cli/commands/import_claude_conversations.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/cli/commands/import_claude_projects.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/cli/commands/import_memory_json.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/cli/commands/mcp.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/cli/commands/status.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/cli/commands/sync.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/cli/main.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/config.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/db.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/deps.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/file_utils.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/importers/__init__.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/importers/base.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/importers/chatgpt_importer.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/importers/claude_conversations_importer.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/importers/claude_projects_importer.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/importers/memory_json_importer.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/importers/utils.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/markdown/__init__.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/markdown/entity_parser.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/markdown/markdown_processor.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/markdown/plugins.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/markdown/schemas.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/markdown/utils.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/mcp/__init__.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/mcp/async_client.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/mcp/auth_provider.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/mcp/external_auth_provider.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/mcp/project_session.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/mcp/prompts/__init__.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/mcp/prompts/ai_assistant_guide.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/mcp/prompts/continue_conversation.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/mcp/prompts/search.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/mcp/prompts/sync_status.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/mcp/prompts/utils.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/mcp/resources/ai_assistant_guide.md +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/mcp/resources/project_info.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/mcp/server.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/mcp/supabase_auth_provider.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/mcp/tools/__init__.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/mcp/tools/build_context.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/mcp/tools/canvas.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/mcp/tools/delete_note.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/mcp/tools/edit_note.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/mcp/tools/list_directory.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/mcp/tools/move_note.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/mcp/tools/project_management.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/mcp/tools/read_content.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/mcp/tools/recent_activity.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/mcp/tools/search.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/mcp/tools/sync_status.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/mcp/tools/utils.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/mcp/tools/write_note.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/models/__init__.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/models/base.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/models/knowledge.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/models/project.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/models/search.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/repository/__init__.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/repository/entity_repository.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/repository/observation_repository.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/repository/project_info_repository.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/repository/project_repository.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/repository/relation_repository.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/repository/repository.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/schemas/__init__.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/schemas/base.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/schemas/delete.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/schemas/directory.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/schemas/importer.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/schemas/memory.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/schemas/project_info.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/schemas/prompt.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/schemas/request.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/schemas/response.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/schemas/search.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/services/__init__.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/services/context_service.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/services/directory_service.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/services/exceptions.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/services/file_service.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/services/initialization.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/services/link_resolver.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/services/migration_service.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/services/search_service.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/services/service.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/services/sync_status_service.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/sync/__init__.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/sync/background_sync.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/sync/watch_service.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/templates/prompts/continue_conversation.hbs +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/templates/prompts/search.hbs +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/utils.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/static/json_canvas_spec_1_0.md +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/test-int/conftest.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/test-int/mcp/test_build_context_validation.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/test-int/mcp/test_delete_note_integration.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/test-int/mcp/test_edit_note_integration.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/test-int/mcp/test_list_directory_integration.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/test-int/mcp/test_move_note_integration.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/test-int/mcp/test_project_management_integration.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/test-int/mcp/test_read_content_integration.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/test-int/mcp/test_read_note_integration.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/test-int/mcp/test_search_integration.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/test-int/mcp/test_write_note_integration.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/Non-MarkdownFileSupport.pdf +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/Screenshot.png +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/__init__.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/api/conftest.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/api/test_continue_conversation_template.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/api/test_directory_router.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/api/test_importer_router.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/api/test_knowledge_router.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/api/test_management_router.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/api/test_memory_router.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/api/test_project_router.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/api/test_project_router_operations.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/api/test_prompt_router.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/api/test_resource_router.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/api/test_search_router.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/api/test_search_template.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/api/test_template_loader.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/api/test_template_loader_helpers.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/cli/conftest.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/cli/test_auth_commands.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/cli/test_cli_tools.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/cli/test_import_chatgpt.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/cli/test_import_claude_conversations.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/cli/test_import_claude_projects.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/cli/test_import_memory_json.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/cli/test_project_commands.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/cli/test_status.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/cli/test_sync.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/cli/test_version.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/conftest.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/importers/test_importer_base.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/importers/test_importer_utils.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/markdown/__init__.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/markdown/test_entity_parser.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/markdown/test_markdown_plugins.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/markdown/test_markdown_processor.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/markdown/test_observation_edge_cases.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/markdown/test_parser_edge_cases.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/markdown/test_relation_edge_cases.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/markdown/test_task_detection.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/mcp/conftest.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/mcp/test_auth_provider.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/mcp/test_server.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/mcp/test_tool_delete_note.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/mcp/test_tool_utils.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/repository/test_entity_repository.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/repository/test_observation_repository.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/repository/test_project_info_repository.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/repository/test_project_repository.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/repository/test_relation_repository.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/repository/test_repository.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/schemas/test_memory_url.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/schemas/test_memory_url_validation.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/schemas/test_schemas.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/schemas/test_search.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/services/test_context_service.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/services/test_directory_service.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/services/test_file_service.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/services/test_initialization.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/services/test_link_resolver.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/services/test_project_service_operations.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/services/test_search_service.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/services/test_sync_status_service.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/sync/test_sync_wikilink_issue.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/sync/test_tmp_files.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/sync/test_watch_service.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/sync/test_watch_service_edge_cases.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/utils/test_file_utils.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/utils/test_parse_tags.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/utils/test_permalink_formatting.py +0 -0
- {basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/tests/utils/test_utf8_handling.py +0 -0
|
@@ -32,17 +32,11 @@ jobs:
|
|
|
32
32
|
uv sync
|
|
33
33
|
uv build
|
|
34
34
|
|
|
35
|
-
- name: Verify
|
|
35
|
+
- name: Verify build succeeded
|
|
36
36
|
run: |
|
|
37
|
-
#
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
echo "Package version: $PACKAGE_VERSION"
|
|
41
|
-
echo "Tag version: $TAG_VERSION"
|
|
42
|
-
if [ "$PACKAGE_VERSION" != "$TAG_VERSION" ]; then
|
|
43
|
-
echo "Version mismatch! Package: $PACKAGE_VERSION, Tag: $TAG_VERSION"
|
|
44
|
-
exit 1
|
|
45
|
-
fi
|
|
37
|
+
# Verify that build artifacts exist
|
|
38
|
+
ls -la dist/
|
|
39
|
+
echo "Build completed successfully"
|
|
46
40
|
|
|
47
41
|
- name: Create GitHub Release
|
|
48
42
|
uses: softprops/action-gh-release@v2
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: basic-memory
|
|
3
|
-
Version: 0.13.
|
|
3
|
+
Version: 0.13.0b6
|
|
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
|
|
@@ -16,6 +16,7 @@ Basic Memory v0.13.0 is a **major release** that transforms Basic Memory into a
|
|
|
16
16
|
**Key v0.13.0 Accomplishments:**
|
|
17
17
|
- ✅ **Complete Project Management System** - Project switching and project-specific operations
|
|
18
18
|
- ✅ **Advanced Note Editing** - Incremental editing with append, prepend, find/replace, and section operations
|
|
19
|
+
- ✅ **View Notes as Artifacts in Claude Desktop/Web** - Use the view_note tool to view a note as an artifact
|
|
19
20
|
- ✅ **File Management System** - Full move operations with database consistency and rollback protection
|
|
20
21
|
- ✅ **Enhanced Search Capabilities** - Frontmatter tags now searchable, improved content discoverability
|
|
21
22
|
- ✅ **Unified Database Architecture** - Single app-level database for better performance and project management
|
|
@@ -77,6 +77,13 @@ read_note("specs/search-design") # By path
|
|
|
77
77
|
read_note("memory://specs/search") # By memory URL
|
|
78
78
|
```
|
|
79
79
|
|
|
80
|
+
**Viewing notes as formatted artifacts (Claude Desktop):**
|
|
81
|
+
```
|
|
82
|
+
view_note("Search Design") # Creates readable artifact
|
|
83
|
+
view_note("specs/search-design") # By permalink
|
|
84
|
+
view_note("memory://specs/search") # By memory URL
|
|
85
|
+
```
|
|
86
|
+
|
|
80
87
|
**Incremental editing** (v0.13.0):
|
|
81
88
|
```
|
|
82
89
|
edit_note(
|
|
@@ -174,7 +174,7 @@ def display_project_info(
|
|
|
174
174
|
"""Display detailed information and statistics about the current project."""
|
|
175
175
|
try:
|
|
176
176
|
# Get project info
|
|
177
|
-
info = asyncio.run(project_info())
|
|
177
|
+
info = asyncio.run(project_info.fn()) # type: ignore # pyright: ignore [reportAttributeAccessIssue]
|
|
178
178
|
|
|
179
179
|
if json_output:
|
|
180
180
|
# Convert to JSON and print
|
|
@@ -90,7 +90,7 @@ def write_note(
|
|
|
90
90
|
typer.echo("Empty content provided. Please provide non-empty content.", err=True)
|
|
91
91
|
raise typer.Exit(1)
|
|
92
92
|
|
|
93
|
-
note = asyncio.run(mcp_write_note(title, content, folder, tags))
|
|
93
|
+
note = asyncio.run(mcp_write_note.fn(title, content, folder, tags))
|
|
94
94
|
rprint(note)
|
|
95
95
|
except Exception as e: # pragma: no cover
|
|
96
96
|
if not isinstance(e, typer.Exit):
|
|
@@ -103,7 +103,7 @@ def write_note(
|
|
|
103
103
|
def read_note(identifier: str, page: int = 1, page_size: int = 10):
|
|
104
104
|
"""Read a markdown note from the knowledge base."""
|
|
105
105
|
try:
|
|
106
|
-
note = asyncio.run(mcp_read_note(identifier, page, page_size))
|
|
106
|
+
note = asyncio.run(mcp_read_note.fn(identifier, page, page_size))
|
|
107
107
|
rprint(note)
|
|
108
108
|
except Exception as e: # pragma: no cover
|
|
109
109
|
if not isinstance(e, typer.Exit):
|
|
@@ -124,7 +124,7 @@ def build_context(
|
|
|
124
124
|
"""Get context needed to continue a discussion."""
|
|
125
125
|
try:
|
|
126
126
|
context = asyncio.run(
|
|
127
|
-
mcp_build_context(
|
|
127
|
+
mcp_build_context.fn(
|
|
128
128
|
url=url,
|
|
129
129
|
depth=depth,
|
|
130
130
|
timeframe=timeframe,
|
|
@@ -157,7 +157,7 @@ def recent_activity(
|
|
|
157
157
|
"""Get recent activity across the knowledge base."""
|
|
158
158
|
try:
|
|
159
159
|
context = asyncio.run(
|
|
160
|
-
mcp_recent_activity(
|
|
160
|
+
mcp_recent_activity.fn(
|
|
161
161
|
type=type, # pyright: ignore [reportArgumentType]
|
|
162
162
|
depth=depth,
|
|
163
163
|
timeframe=timeframe,
|
|
@@ -210,7 +210,7 @@ def search_notes(
|
|
|
210
210
|
search_type = "text" if search_type is None else search_type
|
|
211
211
|
|
|
212
212
|
results = asyncio.run(
|
|
213
|
-
mcp_search(
|
|
213
|
+
mcp_search.fn(
|
|
214
214
|
query,
|
|
215
215
|
search_type=search_type,
|
|
216
216
|
page=page,
|
|
@@ -241,7 +241,7 @@ def continue_conversation(
|
|
|
241
241
|
"""Prompt to continue a previous conversation or work session."""
|
|
242
242
|
try:
|
|
243
243
|
# Prompt functions return formatted strings directly
|
|
244
|
-
session = asyncio.run(mcp_continue_conversation(topic=topic, timeframe=timeframe))
|
|
244
|
+
session = asyncio.run(mcp_continue_conversation.fn(topic=topic, timeframe=timeframe)) # type: ignore
|
|
245
245
|
rprint(session)
|
|
246
246
|
except Exception as e: # pragma: no cover
|
|
247
247
|
if not isinstance(e, typer.Exit):
|
{basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/mcp/prompts/recent_activity.py
RENAMED
|
@@ -38,7 +38,7 @@ async def recent_activity_prompt(
|
|
|
38
38
|
"""
|
|
39
39
|
logger.info(f"Getting recent activity, timeframe: {timeframe}")
|
|
40
40
|
|
|
41
|
-
recent = await recent_activity(timeframe=timeframe, type=[SearchItemType.ENTITY])
|
|
41
|
+
recent = await recent_activity.fn(timeframe=timeframe, type=[SearchItemType.ENTITY])
|
|
42
42
|
|
|
43
43
|
# Extract primary results from the hierarchical structure
|
|
44
44
|
primary_results = []
|
|
@@ -81,7 +81,7 @@ async def read_note(
|
|
|
81
81
|
|
|
82
82
|
# Fallback 1: Try title search via API
|
|
83
83
|
logger.info(f"Search title for: {identifier}")
|
|
84
|
-
title_results = await search_notes(query=identifier, search_type="title", project=project)
|
|
84
|
+
title_results = await search_notes.fn(query=identifier, search_type="title", project=project)
|
|
85
85
|
|
|
86
86
|
if title_results and title_results.results:
|
|
87
87
|
result = title_results.results[0] # Get the first/best match
|
|
@@ -105,7 +105,7 @@ async def read_note(
|
|
|
105
105
|
|
|
106
106
|
# Fallback 2: Text search as a last resort
|
|
107
107
|
logger.info(f"Title search failed, trying text search for: {identifier}")
|
|
108
|
-
text_results = await search_notes(query=identifier, search_type="text", project=project)
|
|
108
|
+
text_results = await search_notes.fn(query=identifier, search_type="text", project=project)
|
|
109
109
|
|
|
110
110
|
# We didn't find a direct match, construct a helpful error message
|
|
111
111
|
if not text_results or not text_results.results:
|
|
@@ -37,7 +37,7 @@ async def view_note(
|
|
|
37
37
|
logger.info(f"Viewing note: {identifier}")
|
|
38
38
|
|
|
39
39
|
# Call the existing read_note logic
|
|
40
|
-
content = await read_note(identifier, page, page_size, project)
|
|
40
|
+
content = await read_note.fn(identifier, page, page_size, project)
|
|
41
41
|
|
|
42
42
|
# Check if this is an error message (note not found)
|
|
43
43
|
if "# Note Not Found:" in content:
|
{basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/repository/search_repository.py
RENAMED
|
@@ -237,19 +237,24 @@ class SearchRepository:
|
|
|
237
237
|
|
|
238
238
|
# Handle text search for title and content
|
|
239
239
|
if search_text:
|
|
240
|
-
#
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
# If boolean operators are present, use the raw query
|
|
245
|
-
# No need to prepare it, FTS5 will understand the operators
|
|
246
|
-
params["text"] = search_text
|
|
247
|
-
conditions.append("(title MATCH :text OR content_stems MATCH :text)")
|
|
240
|
+
# Skip FTS for wildcard-only queries that would cause "unknown special query" errors
|
|
241
|
+
if search_text.strip() == "*" or search_text.strip() == "":
|
|
242
|
+
# For wildcard searches, don't add any text conditions - return all results
|
|
243
|
+
pass
|
|
248
244
|
else:
|
|
249
|
-
#
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
245
|
+
# Check for explicit boolean operators - only detect them in proper boolean contexts
|
|
246
|
+
has_boolean = any(op in f" {search_text} " for op in [" AND ", " OR ", " NOT "])
|
|
247
|
+
|
|
248
|
+
if has_boolean:
|
|
249
|
+
# If boolean operators are present, use the raw query
|
|
250
|
+
# No need to prepare it, FTS5 will understand the operators
|
|
251
|
+
params["text"] = search_text
|
|
252
|
+
conditions.append("(title MATCH :text OR content_stems MATCH :text)")
|
|
253
|
+
else:
|
|
254
|
+
# Standard search with term preparation
|
|
255
|
+
processed_text = self._prepare_search_term(search_text.strip())
|
|
256
|
+
params["text"] = processed_text
|
|
257
|
+
conditions.append("(title MATCH :text OR content_stems MATCH :text)")
|
|
253
258
|
|
|
254
259
|
# Handle title match search
|
|
255
260
|
if title:
|
|
@@ -299,7 +299,20 @@ class EntityService(BaseService[EntityModel]):
|
|
|
299
299
|
# Mark as incomplete because we still need to add relations
|
|
300
300
|
model.checksum = None
|
|
301
301
|
# Repository will set project_id automatically
|
|
302
|
-
|
|
302
|
+
try:
|
|
303
|
+
return await self.repository.add(model)
|
|
304
|
+
except IntegrityError as e:
|
|
305
|
+
# Handle race condition where entity was created by another process
|
|
306
|
+
if "UNIQUE constraint failed: entity.file_path" in str(
|
|
307
|
+
e
|
|
308
|
+
) or "UNIQUE constraint failed: entity.permalink" in str(e):
|
|
309
|
+
logger.info(
|
|
310
|
+
f"Entity already exists for file_path={file_path} (file_path or permalink conflict), updating instead of creating"
|
|
311
|
+
)
|
|
312
|
+
return await self.update_entity_and_observations(file_path, markdown)
|
|
313
|
+
else:
|
|
314
|
+
# Re-raise if it's a different integrity error
|
|
315
|
+
raise
|
|
303
316
|
|
|
304
317
|
async def update_entity_and_observations(
|
|
305
318
|
self, file_path: Path, markdown: EntityMarkdown
|
{basic_memory-0.13.0b5 → basic_memory-0.13.0b6}/src/basic_memory/services/project_service.py
RENAMED
|
@@ -209,8 +209,29 @@ class ProjectService:
|
|
|
209
209
|
db_projects = await self.repository.get_active_projects()
|
|
210
210
|
db_projects_by_name = {p.name: p for p in db_projects}
|
|
211
211
|
|
|
212
|
-
# Get all projects from configuration
|
|
213
|
-
config_projects = config_manager.projects
|
|
212
|
+
# Get all projects from configuration and normalize names if needed
|
|
213
|
+
config_projects = config_manager.projects.copy()
|
|
214
|
+
updated_config = {}
|
|
215
|
+
config_updated = False
|
|
216
|
+
|
|
217
|
+
for name, path in config_projects.items():
|
|
218
|
+
# Generate normalized name (what the database expects)
|
|
219
|
+
normalized_name = generate_permalink(name)
|
|
220
|
+
|
|
221
|
+
if normalized_name != name:
|
|
222
|
+
logger.info(f"Normalizing project name in config: '{name}' -> '{normalized_name}'")
|
|
223
|
+
config_updated = True
|
|
224
|
+
|
|
225
|
+
updated_config[normalized_name] = path
|
|
226
|
+
|
|
227
|
+
# Update the configuration if any changes were made
|
|
228
|
+
if config_updated:
|
|
229
|
+
config_manager.config.projects = updated_config
|
|
230
|
+
config_manager.save_config(config_manager.config)
|
|
231
|
+
logger.info("Config updated with normalized project names")
|
|
232
|
+
|
|
233
|
+
# Use the normalized config for further processing
|
|
234
|
+
config_projects = updated_config
|
|
214
235
|
|
|
215
236
|
# Add projects that exist in config but not in DB
|
|
216
237
|
for name, path in config_projects.items():
|
|
@@ -219,7 +240,7 @@ class ProjectService:
|
|
|
219
240
|
project_data = {
|
|
220
241
|
"name": name,
|
|
221
242
|
"path": path,
|
|
222
|
-
"permalink": name
|
|
243
|
+
"permalink": generate_permalink(name),
|
|
223
244
|
"is_active": True,
|
|
224
245
|
# Don't set is_default here - let the enforcement logic handle it
|
|
225
246
|
}
|
|
@@ -364,18 +364,43 @@ class SyncService:
|
|
|
364
364
|
content_type = self.file_service.content_type(path)
|
|
365
365
|
|
|
366
366
|
file_path = Path(path)
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
367
|
+
try:
|
|
368
|
+
entity = await self.entity_repository.add(
|
|
369
|
+
Entity(
|
|
370
|
+
entity_type="file",
|
|
371
|
+
file_path=path,
|
|
372
|
+
checksum=checksum,
|
|
373
|
+
title=file_path.name,
|
|
374
|
+
created_at=created,
|
|
375
|
+
updated_at=modified,
|
|
376
|
+
content_type=content_type,
|
|
377
|
+
)
|
|
376
378
|
)
|
|
377
|
-
|
|
378
|
-
|
|
379
|
+
return entity, checksum
|
|
380
|
+
except IntegrityError as e:
|
|
381
|
+
# Handle race condition where entity was created by another process
|
|
382
|
+
if "UNIQUE constraint failed: entity.file_path" in str(e):
|
|
383
|
+
logger.info(
|
|
384
|
+
f"Entity already exists for file_path={path}, updating instead of creating"
|
|
385
|
+
)
|
|
386
|
+
# Treat as update instead of create
|
|
387
|
+
entity = await self.entity_repository.get_by_file_path(path)
|
|
388
|
+
if entity is None: # pragma: no cover
|
|
389
|
+
logger.error(f"Entity not found after constraint violation, path={path}")
|
|
390
|
+
raise ValueError(f"Entity not found after constraint violation: {path}")
|
|
391
|
+
|
|
392
|
+
updated = await self.entity_repository.update(
|
|
393
|
+
entity.id, {"file_path": path, "checksum": checksum}
|
|
394
|
+
)
|
|
395
|
+
|
|
396
|
+
if updated is None: # pragma: no cover
|
|
397
|
+
logger.error(f"Failed to update entity, entity_id={entity.id}, path={path}")
|
|
398
|
+
raise ValueError(f"Failed to update entity with ID {entity.id}")
|
|
399
|
+
|
|
400
|
+
return updated, checksum
|
|
401
|
+
else:
|
|
402
|
+
# Re-raise if it's a different integrity error
|
|
403
|
+
raise
|
|
379
404
|
else:
|
|
380
405
|
entity = await self.entity_repository.get_by_file_path(path)
|
|
381
406
|
if entity is None: # pragma: no cover
|
|
@@ -50,6 +50,13 @@ read_note("specs/search-design") # By permalink
|
|
|
50
50
|
read_note("memory://specs/search") # By memory URL
|
|
51
51
|
```
|
|
52
52
|
|
|
53
|
+
**Viewing notes as formatted artifacts (Claude Desktop):**
|
|
54
|
+
```
|
|
55
|
+
view_note("Search Design") # Creates readable artifact
|
|
56
|
+
view_note("specs/search-design") # By permalink
|
|
57
|
+
view_note("memory://specs/search") # By memory URL
|
|
58
|
+
```
|
|
59
|
+
|
|
53
60
|
**Incremental editing (v0.13.0) - REQUIRES EXACT IDENTIFIERS:**
|
|
54
61
|
```
|
|
55
62
|
edit_note(
|
|
@@ -48,7 +48,7 @@ def test_info_stats():
|
|
|
48
48
|
|
|
49
49
|
# Mock the async project_info function
|
|
50
50
|
with patch(
|
|
51
|
-
"basic_memory.cli.commands.project.project_info", new_callable=AsyncMock
|
|
51
|
+
"basic_memory.cli.commands.project.project_info.fn", new_callable=AsyncMock
|
|
52
52
|
) as mock_func:
|
|
53
53
|
mock_func.return_value = mock_info
|
|
54
54
|
|
|
@@ -97,7 +97,7 @@ def test_info_stats_json():
|
|
|
97
97
|
|
|
98
98
|
# Mock the async project_info function
|
|
99
99
|
with patch(
|
|
100
|
-
"basic_memory.cli.commands.project.project_info", new_callable=AsyncMock
|
|
100
|
+
"basic_memory.cli.commands.project.project_info.fn", new_callable=AsyncMock
|
|
101
101
|
) as mock_func:
|
|
102
102
|
mock_func.return_value = mock_info
|
|
103
103
|
|
|
@@ -15,7 +15,7 @@ async def test_continue_conversation_with_topic(client, test_graph):
|
|
|
15
15
|
# We can use the test_graph fixture which already has relevant content
|
|
16
16
|
|
|
17
17
|
# Call the function with a topic that should match existing content
|
|
18
|
-
result = await continue_conversation(topic="Root", timeframe="1w")
|
|
18
|
+
result = await continue_conversation.fn(topic="Root", timeframe="1w")
|
|
19
19
|
|
|
20
20
|
# Check that the result contains expected content
|
|
21
21
|
assert "Continuing conversation on: Root" in result
|
|
@@ -27,7 +27,7 @@ async def test_continue_conversation_with_topic(client, test_graph):
|
|
|
27
27
|
async def test_continue_conversation_with_recent_activity(client, test_graph):
|
|
28
28
|
"""Test continue_conversation with no topic, using recent activity."""
|
|
29
29
|
# Call the function without a topic
|
|
30
|
-
result = await continue_conversation(timeframe="1w")
|
|
30
|
+
result = await continue_conversation.fn(timeframe="1w")
|
|
31
31
|
|
|
32
32
|
# Check that the result contains expected content for recent activity
|
|
33
33
|
assert "Continuing conversation on: Recent Activity" in result
|
|
@@ -40,7 +40,7 @@ async def test_continue_conversation_with_recent_activity(client, test_graph):
|
|
|
40
40
|
async def test_continue_conversation_no_results(client):
|
|
41
41
|
"""Test continue_conversation when no results are found."""
|
|
42
42
|
# Call with a non-existent topic
|
|
43
|
-
result = await continue_conversation(topic="NonExistentTopic", timeframe="1w")
|
|
43
|
+
result = await continue_conversation.fn(topic="NonExistentTopic", timeframe="1w")
|
|
44
44
|
|
|
45
45
|
# Check the response indicates no results found
|
|
46
46
|
assert "Continuing conversation on: NonExistentTopic" in result
|
|
@@ -51,7 +51,7 @@ async def test_continue_conversation_no_results(client):
|
|
|
51
51
|
async def test_continue_conversation_creates_structured_suggestions(client, test_graph):
|
|
52
52
|
"""Test that continue_conversation generates structured tool usage suggestions."""
|
|
53
53
|
# Call the function with a topic that should match existing content
|
|
54
|
-
result = await continue_conversation(topic="Root", timeframe="1w")
|
|
54
|
+
result = await continue_conversation.fn(topic="Root", timeframe="1w")
|
|
55
55
|
|
|
56
56
|
# Verify the response includes clear tool usage instructions
|
|
57
57
|
assert "start by executing one of the suggested commands" in result.lower()
|
|
@@ -69,7 +69,7 @@ async def test_continue_conversation_creates_structured_suggestions(client, test
|
|
|
69
69
|
async def test_search_prompt_with_results(client, test_graph):
|
|
70
70
|
"""Test search_prompt with a query that returns results."""
|
|
71
71
|
# Call the function with a query that should match existing content
|
|
72
|
-
result = await search_prompt("Root")
|
|
72
|
+
result = await search_prompt.fn("Root")
|
|
73
73
|
|
|
74
74
|
# Check the response contains expected content
|
|
75
75
|
assert 'Search Results for: "Root"' in result
|
|
@@ -82,7 +82,7 @@ async def test_search_prompt_with_results(client, test_graph):
|
|
|
82
82
|
async def test_search_prompt_with_timeframe(client, test_graph):
|
|
83
83
|
"""Test search_prompt with a timeframe."""
|
|
84
84
|
# Call the function with a query and timeframe
|
|
85
|
-
result = await search_prompt("Root", timeframe="1w")
|
|
85
|
+
result = await search_prompt.fn("Root", timeframe="1w")
|
|
86
86
|
|
|
87
87
|
# Check the response includes timeframe information
|
|
88
88
|
assert 'Search Results for: "Root" (after 7d)' in result
|
|
@@ -93,7 +93,7 @@ async def test_search_prompt_with_timeframe(client, test_graph):
|
|
|
93
93
|
async def test_search_prompt_no_results(client):
|
|
94
94
|
"""Test search_prompt when no results are found."""
|
|
95
95
|
# Call with a query that won't match anything
|
|
96
|
-
result = await search_prompt("XYZ123NonExistentQuery")
|
|
96
|
+
result = await search_prompt.fn("XYZ123NonExistentQuery")
|
|
97
97
|
|
|
98
98
|
# Check the response indicates no results found
|
|
99
99
|
assert 'Search Results for: "XYZ123NonExistentQuery"' in result
|
|
@@ -149,7 +149,7 @@ def test_prompt_context_with_file_path_no_permalink():
|
|
|
149
149
|
async def test_recent_activity_prompt(client, test_graph):
|
|
150
150
|
"""Test recent_activity_prompt."""
|
|
151
151
|
# Call the function
|
|
152
|
-
result = await recent_activity_prompt(timeframe="1w")
|
|
152
|
+
result = await recent_activity_prompt.fn(timeframe="1w")
|
|
153
153
|
|
|
154
154
|
# Check the response contains expected content
|
|
155
155
|
assert "Recent Activity" in result
|
|
@@ -161,7 +161,7 @@ async def test_recent_activity_prompt(client, test_graph):
|
|
|
161
161
|
async def test_recent_activity_prompt_with_custom_timeframe(client, test_graph):
|
|
162
162
|
"""Test recent_activity_prompt with custom timeframe."""
|
|
163
163
|
# Call the function with a custom timeframe
|
|
164
|
-
result = await recent_activity_prompt(timeframe="1d")
|
|
164
|
+
result = await recent_activity_prompt.fn(timeframe="1d")
|
|
165
165
|
|
|
166
166
|
# Check the response includes the custom timeframe
|
|
167
167
|
assert "Recent Activity from (1d)" in result
|
|
@@ -97,7 +97,7 @@ async def test_project_info_tool():
|
|
|
97
97
|
"basic_memory.mcp.resources.project_info.call_get", return_value=mock_response
|
|
98
98
|
) as mock_call_get:
|
|
99
99
|
# Call the function
|
|
100
|
-
result = await project_info()
|
|
100
|
+
result = await project_info.fn()
|
|
101
101
|
|
|
102
102
|
# Verify that call_get was called with the correct URL
|
|
103
103
|
mock_call_get.assert_called_once()
|
|
@@ -138,7 +138,7 @@ async def test_project_info_error_handling():
|
|
|
138
138
|
):
|
|
139
139
|
# Verify that the exception propagates
|
|
140
140
|
with pytest.raises(Exception) as excinfo:
|
|
141
|
-
await project_info()
|
|
141
|
+
await project_info.fn()
|
|
142
142
|
|
|
143
143
|
# Verify error message
|
|
144
144
|
assert "Test error" in str(excinfo.value)
|
|
@@ -8,7 +8,7 @@ import pytest
|
|
|
8
8
|
async def test_ai_assistant_guide_exists(app):
|
|
9
9
|
"""Test that the canvas spec resource exists and returns content."""
|
|
10
10
|
# Call the resource function
|
|
11
|
-
guide = ai_assistant_guide()
|
|
11
|
+
guide = ai_assistant_guide.fn()
|
|
12
12
|
|
|
13
13
|
# Verify basic characteristics of the content
|
|
14
14
|
assert guide is not None
|
|
@@ -14,7 +14,7 @@ from basic_memory.schemas.memory import (
|
|
|
14
14
|
@pytest.mark.asyncio
|
|
15
15
|
async def test_get_basic_discussion_context(client, test_graph):
|
|
16
16
|
"""Test getting basic discussion context."""
|
|
17
|
-
context = await build_context(url="memory://test/root")
|
|
17
|
+
context = await build_context.fn(url="memory://test/root")
|
|
18
18
|
|
|
19
19
|
assert isinstance(context, GraphContext)
|
|
20
20
|
assert len(context.results) == 1
|
|
@@ -33,7 +33,7 @@ async def test_get_basic_discussion_context(client, test_graph):
|
|
|
33
33
|
@pytest.mark.asyncio
|
|
34
34
|
async def test_get_discussion_context_pattern(client, test_graph):
|
|
35
35
|
"""Test getting context with pattern matching."""
|
|
36
|
-
context = await build_context(url="memory://test/*", depth=1)
|
|
36
|
+
context = await build_context.fn(url="memory://test/*", depth=1)
|
|
37
37
|
|
|
38
38
|
assert isinstance(context, GraphContext)
|
|
39
39
|
assert len(context.results) > 1 # Should match multiple test/* paths
|
|
@@ -45,13 +45,13 @@ async def test_get_discussion_context_pattern(client, test_graph):
|
|
|
45
45
|
async def test_get_discussion_context_timeframe(client, test_graph):
|
|
46
46
|
"""Test timeframe parameter filtering."""
|
|
47
47
|
# Get recent context
|
|
48
|
-
recent_context = await build_context(
|
|
48
|
+
recent_context = await build_context.fn(
|
|
49
49
|
url="memory://test/root",
|
|
50
50
|
timeframe="1d", # Last 24 hours
|
|
51
51
|
)
|
|
52
52
|
|
|
53
53
|
# Get older context
|
|
54
|
-
older_context = await build_context(
|
|
54
|
+
older_context = await build_context.fn(
|
|
55
55
|
url="memory://test/root",
|
|
56
56
|
timeframe="30d", # Last 30 days
|
|
57
57
|
)
|
|
@@ -74,7 +74,7 @@ async def test_get_discussion_context_timeframe(client, test_graph):
|
|
|
74
74
|
@pytest.mark.asyncio
|
|
75
75
|
async def test_get_discussion_context_not_found(client):
|
|
76
76
|
"""Test handling of non-existent URIs."""
|
|
77
|
-
context = await build_context(url="memory://test/does-not-exist")
|
|
77
|
+
context = await build_context.fn(url="memory://test/does-not-exist")
|
|
78
78
|
|
|
79
79
|
assert isinstance(context, GraphContext)
|
|
80
80
|
assert len(context.results) == 0
|
|
@@ -103,7 +103,7 @@ async def test_build_context_timeframe_formats(client, test_graph):
|
|
|
103
103
|
# Test each valid timeframe
|
|
104
104
|
for timeframe in valid_timeframes:
|
|
105
105
|
try:
|
|
106
|
-
result = await build_context(
|
|
106
|
+
result = await build_context.fn(
|
|
107
107
|
url=test_url, timeframe=timeframe, page=1, page_size=10, max_related=10
|
|
108
108
|
)
|
|
109
109
|
assert result is not None
|
|
@@ -113,4 +113,4 @@ async def test_build_context_timeframe_formats(client, test_graph):
|
|
|
113
113
|
# Test invalid timeframes should raise ValidationError
|
|
114
114
|
for timeframe in invalid_timeframes:
|
|
115
115
|
with pytest.raises(ToolError):
|
|
116
|
-
await build_context(url=test_url, timeframe=timeframe)
|
|
116
|
+
await build_context.fn(url=test_url, timeframe=timeframe)
|
|
@@ -34,7 +34,7 @@ async def test_create_canvas(app, project_config):
|
|
|
34
34
|
folder = "visualizations"
|
|
35
35
|
|
|
36
36
|
# Execute
|
|
37
|
-
result = await canvas(nodes=nodes, edges=edges, title=title, folder=folder)
|
|
37
|
+
result = await canvas.fn(nodes=nodes, edges=edges, title=title, folder=folder)
|
|
38
38
|
|
|
39
39
|
# Verify result message
|
|
40
40
|
assert result
|
|
@@ -71,7 +71,7 @@ async def test_create_canvas_with_extension(app, project_config):
|
|
|
71
71
|
folder = "visualizations"
|
|
72
72
|
|
|
73
73
|
# Execute
|
|
74
|
-
result = await canvas(nodes=nodes, edges=edges, title=title, folder=folder)
|
|
74
|
+
result = await canvas.fn(nodes=nodes, edges=edges, title=title, folder=folder)
|
|
75
75
|
|
|
76
76
|
# Verify
|
|
77
77
|
assert "Created: visualizations/extension-test.canvas" in result
|
|
@@ -105,7 +105,7 @@ async def test_update_existing_canvas(app, project_config):
|
|
|
105
105
|
folder = "visualizations"
|
|
106
106
|
|
|
107
107
|
# Create initial canvas
|
|
108
|
-
await canvas(nodes=nodes, edges=edges, title=title, folder=folder)
|
|
108
|
+
await canvas.fn(nodes=nodes, edges=edges, title=title, folder=folder)
|
|
109
109
|
|
|
110
110
|
# Verify file exists
|
|
111
111
|
file_path = Path(project_config.home) / folder / f"{title}.canvas"
|
|
@@ -128,7 +128,7 @@ async def test_update_existing_canvas(app, project_config):
|
|
|
128
128
|
]
|
|
129
129
|
|
|
130
130
|
# Execute update
|
|
131
|
-
result = await canvas(nodes=updated_nodes, edges=updated_edges, title=title, folder=folder)
|
|
131
|
+
result = await canvas.fn(nodes=updated_nodes, edges=updated_edges, title=title, folder=folder)
|
|
132
132
|
|
|
133
133
|
# Verify result indicates update
|
|
134
134
|
assert "Updated: visualizations/update-test.canvas" in result
|
|
@@ -159,7 +159,7 @@ async def test_create_canvas_with_nested_folders(app, project_config):
|
|
|
159
159
|
folder = "visualizations/nested/folders" # Deep path
|
|
160
160
|
|
|
161
161
|
# Execute
|
|
162
|
-
result = await canvas(nodes=nodes, edges=edges, title=title, folder=folder)
|
|
162
|
+
result = await canvas.fn(nodes=nodes, edges=edges, title=title, folder=folder)
|
|
163
163
|
|
|
164
164
|
# Verify
|
|
165
165
|
assert "Created: visualizations/nested/folders/nested-test.canvas" in result
|
|
@@ -242,7 +242,7 @@ async def test_create_canvas_complex_content(app, project_config):
|
|
|
242
242
|
test_file_path.write_text("# Test File\nThis is referenced by the canvas")
|
|
243
243
|
|
|
244
244
|
# Execute
|
|
245
|
-
result = await canvas(nodes=nodes, edges=edges, title=title, folder=folder)
|
|
245
|
+
result = await canvas.fn(nodes=nodes, edges=edges, title=title, folder=folder)
|
|
246
246
|
|
|
247
247
|
# Verify
|
|
248
248
|
assert "Created: visualizations/complex-test.canvas" in result
|