basic-memory 0.17.1__tar.gz → 0.17.3__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.
Files changed (410) hide show
  1. {basic_memory-0.17.1 → basic_memory-0.17.3}/.github/workflows/test.yml +55 -1
  2. {basic_memory-0.17.1 → basic_memory-0.17.3}/CHANGELOG.md +55 -0
  3. {basic_memory-0.17.1 → basic_memory-0.17.3}/PKG-INFO +2 -2
  4. basic_memory-0.17.3/docs/testing-coverage.md +30 -0
  5. {basic_memory-0.17.1 → basic_memory-0.17.3}/justfile +30 -14
  6. {basic_memory-0.17.1 → basic_memory-0.17.3}/pyproject.toml +8 -4
  7. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/__init__.py +1 -1
  8. basic_memory-0.17.3/src/basic_memory/alembic/versions/6830751f5fb6_merge_multiple_heads.py +24 -0
  9. basic_memory-0.17.3/src/basic_memory/alembic/versions/g9a0b3c4d5e6_add_external_id_to_project_and_entity.py +173 -0
  10. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/api/app.py +11 -11
  11. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/api/routers/knowledge_router.py +4 -3
  12. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/api/routers/project_router.py +17 -5
  13. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/api/routers/resource_router.py +4 -4
  14. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/api/v2/routers/directory_router.py +13 -13
  15. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/api/v2/routers/importer_router.py +18 -19
  16. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/api/v2/routers/knowledge_router.py +118 -104
  17. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/api/v2/routers/memory_router.py +11 -11
  18. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/api/v2/routers/project_router.py +87 -70
  19. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/api/v2/routers/prompt_router.py +16 -17
  20. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/api/v2/routers/resource_router.py +59 -59
  21. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/api/v2/routers/search_router.py +11 -11
  22. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/cli/auth.py +27 -4
  23. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/cli/commands/cloud/api_client.py +20 -5
  24. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/cli/commands/cloud/cloud_utils.py +13 -6
  25. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/cli/commands/cloud/rclone_commands.py +47 -21
  26. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/cli/commands/cloud/upload.py +10 -3
  27. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/cli/commands/import_chatgpt.py +10 -7
  28. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/cli/commands/import_claude_conversations.py +10 -7
  29. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/cli/commands/import_claude_projects.py +10 -7
  30. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/cli/commands/import_memory_json.py +10 -7
  31. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/cli/commands/project.py +2 -2
  32. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/config.py +4 -4
  33. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/deps.py +329 -20
  34. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/file_utils.py +4 -4
  35. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/ignore_utils.py +5 -5
  36. basic_memory-0.17.3/src/basic_memory/importers/base.py +100 -0
  37. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/importers/chatgpt_importer.py +17 -4
  38. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/importers/claude_conversations_importer.py +23 -11
  39. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/importers/claude_projects_importer.py +50 -14
  40. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/importers/memory_json_importer.py +36 -16
  41. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/markdown/markdown_processor.py +48 -4
  42. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/mcp/project_context.py +16 -4
  43. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/mcp/prompts/ai_assistant_guide.py +2 -2
  44. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/mcp/prompts/recent_activity.py +2 -2
  45. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/mcp/prompts/utils.py +3 -3
  46. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/mcp/server.py +5 -5
  47. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/mcp/tools/build_context.py +1 -1
  48. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/mcp/tools/canvas.py +6 -6
  49. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/mcp/tools/chatgpt_tools.py +1 -1
  50. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/mcp/tools/delete_note.py +12 -6
  51. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/mcp/tools/edit_note.py +2 -2
  52. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/mcp/tools/list_directory.py +1 -1
  53. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/mcp/tools/move_note.py +16 -12
  54. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/mcp/tools/project_management.py +5 -7
  55. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/mcp/tools/read_content.py +2 -2
  56. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/mcp/tools/read_note.py +4 -4
  57. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/mcp/tools/recent_activity.py +30 -36
  58. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/mcp/tools/search.py +7 -3
  59. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/mcp/tools/utils.py +10 -10
  60. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/mcp/tools/write_note.py +7 -7
  61. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/models/knowledge.py +7 -1
  62. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/models/project.py +7 -1
  63. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/models/search.py +9 -0
  64. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/repository/entity_repository.py +33 -15
  65. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/repository/postgres_search_repository.py +92 -20
  66. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/repository/project_repository.py +12 -0
  67. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/repository/relation_repository.py +4 -4
  68. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/repository/search_repository.py +2 -2
  69. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/repository/search_repository_base.py +2 -2
  70. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/repository/sqlite_search_repository.py +1 -1
  71. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/schemas/base.py +2 -2
  72. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/schemas/directory.py +2 -1
  73. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/schemas/memory.py +2 -2
  74. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/schemas/project_info.py +1 -0
  75. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/schemas/response.py +84 -27
  76. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/schemas/sync_report.py +1 -1
  77. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/schemas/v2/entity.py +13 -9
  78. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/schemas/v2/resource.py +2 -1
  79. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/services/context_service.py +5 -5
  80. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/services/directory_service.py +13 -11
  81. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/services/file_service.py +12 -8
  82. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/services/project_service.py +33 -25
  83. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/services/search_service.py +29 -11
  84. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/sync/sync_service.py +9 -3
  85. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/sync/watch_service.py +12 -7
  86. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/utils.py +5 -5
  87. {basic_memory-0.17.1 → basic_memory-0.17.3}/test-int/conftest.py +2 -0
  88. {basic_memory-0.17.1 → basic_memory-0.17.3}/test-int/mcp/test_write_note_integration.py +1 -0
  89. basic_memory-0.17.3/tests/api/test_async_client.py +53 -0
  90. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/api/test_directory_router.py +0 -199
  91. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/api/test_knowledge_router.py +0 -36
  92. basic_memory-0.17.3/tests/api/test_management_router.py +123 -0
  93. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/api/test_relation_background_resolution.py +19 -9
  94. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/api/v2/conftest.py +3 -3
  95. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/api/v2/test_knowledge_router.py +64 -62
  96. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/api/v2/test_project_router.py +55 -51
  97. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/api/v2/test_resource_router.py +28 -22
  98. basic_memory-0.17.3/tests/cli/cloud/test_cloud_api_client_and_utils.py +161 -0
  99. basic_memory-0.17.3/tests/cli/cloud/test_rclone_config_and_bmignore_filters.py +80 -0
  100. basic_memory-0.17.3/tests/cli/cloud/test_upload_path.py +73 -0
  101. basic_memory-0.17.3/tests/cli/test_auth_cli_auth.py +147 -0
  102. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/cli/test_cli_tool_exit.py +20 -3
  103. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/cli/test_cli_tools.py +44 -41
  104. basic_memory-0.17.3/tests/cli/test_cloud_authentication.py +225 -0
  105. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/cli/test_import_memory_json.py +5 -3
  106. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/cli/test_project_add_with_local_path.py +35 -23
  107. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/cli/test_upload.py +84 -182
  108. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/conftest.py +30 -0
  109. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/importers/test_conversation_indexing.py +4 -2
  110. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/importers/test_importer_base.py +28 -43
  111. basic_memory-0.17.3/tests/mcp/test_async_client_modes.py +82 -0
  112. basic_memory-0.17.3/tests/mcp/test_project_context.py +105 -0
  113. basic_memory-0.17.3/tests/mcp/test_recent_activity_prompt_modes.py +101 -0
  114. basic_memory-0.17.3/tests/mcp/test_server_lifespan_branches.py +36 -0
  115. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/mcp/test_tool_move_note.py +21 -66
  116. basic_memory-0.17.3/tests/mcp/test_tool_project_management.py +51 -0
  117. basic_memory-0.17.3/tests/mcp/test_tool_read_content.py +170 -0
  118. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/mcp/test_tool_read_note.py +79 -25
  119. basic_memory-0.17.3/tests/mcp/test_tool_recent_activity.py +412 -0
  120. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/mcp/test_tool_search.py +42 -20
  121. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/mcp/test_tool_utils.py +54 -31
  122. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/mcp/test_tool_view_note.py +12 -57
  123. basic_memory-0.17.3/tests/mcp/tools/test_chatgpt_tools.py +215 -0
  124. basic_memory-0.17.3/tests/repository/test_postgres_search_repository.py +195 -0
  125. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/repository/test_search_repository.py +121 -12
  126. basic_memory-0.17.3/tests/schemas/test_relation_response_reference_resolution.py +42 -0
  127. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/schemas/test_schemas.py +43 -0
  128. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/services/test_entity_service.py +6 -6
  129. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/services/test_file_service.py +37 -19
  130. basic_memory-0.17.3/tests/services/test_initialization.py +120 -0
  131. basic_memory-0.17.3/tests/services/test_initialization_cloud_mode_branches.py +23 -0
  132. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/services/test_project_service.py +4 -12
  133. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/services/test_project_service_operations.py +0 -38
  134. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/services/test_search_service.py +8 -40
  135. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/sync/test_sync_service.py +74 -503
  136. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/sync/test_watch_service.py +10 -8
  137. basic_memory-0.17.3/tests/sync/test_watch_service_atomic_adds.py +53 -0
  138. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/sync/test_watch_service_edge_cases.py +5 -15
  139. basic_memory-0.17.3/tests/sync/test_watch_service_reload.py +259 -0
  140. basic_memory-0.17.3/tests/test_rclone_commands.py +460 -0
  141. basic_memory-0.17.3/tests/test_telemetry.py +268 -0
  142. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/utils/test_timezone_utils.py +6 -10
  143. {basic_memory-0.17.1 → basic_memory-0.17.3}/uv.lock +993 -985
  144. basic_memory-0.17.1/src/basic_memory/importers/base.py +0 -79
  145. basic_memory-0.17.1/tests/api/test_async_client.py +0 -56
  146. basic_memory-0.17.1/tests/api/test_management_router.py +0 -211
  147. basic_memory-0.17.1/tests/cli/test_cloud_authentication.py +0 -239
  148. basic_memory-0.17.1/tests/mcp/test_tool_read_content.py +0 -495
  149. basic_memory-0.17.1/tests/mcp/test_tool_recent_activity.py +0 -135
  150. basic_memory-0.17.1/tests/mcp/tools/test_chatgpt_tools.py +0 -228
  151. basic_memory-0.17.1/tests/services/test_initialization.py +0 -122
  152. basic_memory-0.17.1/tests/sync/test_watch_service_reload.py +0 -252
  153. basic_memory-0.17.1/tests/test_rclone_commands.py +0 -647
  154. basic_memory-0.17.1/tests/test_telemetry.py +0 -276
  155. {basic_memory-0.17.1 → basic_memory-0.17.3}/.claude/commands/release/beta.md +0 -0
  156. {basic_memory-0.17.1 → basic_memory-0.17.3}/.claude/commands/release/changelog.md +0 -0
  157. {basic_memory-0.17.1 → basic_memory-0.17.3}/.claude/commands/release/release-check.md +0 -0
  158. {basic_memory-0.17.1 → basic_memory-0.17.3}/.claude/commands/release/release.md +0 -0
  159. {basic_memory-0.17.1 → basic_memory-0.17.3}/.claude/commands/spec.md +0 -0
  160. {basic_memory-0.17.1 → basic_memory-0.17.3}/.claude/commands/test-live.md +0 -0
  161. {basic_memory-0.17.1 → basic_memory-0.17.3}/.claude/settings.json +0 -0
  162. {basic_memory-0.17.1 → basic_memory-0.17.3}/.dockerignore +0 -0
  163. {basic_memory-0.17.1 → basic_memory-0.17.3}/.env.example +0 -0
  164. {basic_memory-0.17.1 → basic_memory-0.17.3}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  165. {basic_memory-0.17.1 → basic_memory-0.17.3}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  166. {basic_memory-0.17.1 → basic_memory-0.17.3}/.github/ISSUE_TEMPLATE/documentation.md +0 -0
  167. {basic_memory-0.17.1 → basic_memory-0.17.3}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  168. {basic_memory-0.17.1 → basic_memory-0.17.3}/.github/dependabot.yml +0 -0
  169. {basic_memory-0.17.1 → basic_memory-0.17.3}/.github/workflows/claude-code-review.yml +0 -0
  170. {basic_memory-0.17.1 → basic_memory-0.17.3}/.github/workflows/claude-issue-triage.yml +0 -0
  171. {basic_memory-0.17.1 → basic_memory-0.17.3}/.github/workflows/claude.yml +0 -0
  172. {basic_memory-0.17.1 → basic_memory-0.17.3}/.github/workflows/dev-release.yml +0 -0
  173. {basic_memory-0.17.1 → basic_memory-0.17.3}/.github/workflows/docker.yml +0 -0
  174. {basic_memory-0.17.1 → basic_memory-0.17.3}/.github/workflows/pr-title.yml +0 -0
  175. {basic_memory-0.17.1 → basic_memory-0.17.3}/.github/workflows/release.yml +0 -0
  176. {basic_memory-0.17.1 → basic_memory-0.17.3}/.gitignore +0 -0
  177. {basic_memory-0.17.1 → basic_memory-0.17.3}/.python-version +0 -0
  178. {basic_memory-0.17.1 → basic_memory-0.17.3}/CITATION.cff +0 -0
  179. {basic_memory-0.17.1 → basic_memory-0.17.3}/CLA.md +0 -0
  180. {basic_memory-0.17.1 → basic_memory-0.17.3}/CLAUDE.md +0 -0
  181. {basic_memory-0.17.1 → basic_memory-0.17.3}/CODE_OF_CONDUCT.md +0 -0
  182. {basic_memory-0.17.1 → basic_memory-0.17.3}/CONTRIBUTING.md +0 -0
  183. {basic_memory-0.17.1 → basic_memory-0.17.3}/Dockerfile +0 -0
  184. {basic_memory-0.17.1 → basic_memory-0.17.3}/LICENSE +0 -0
  185. {basic_memory-0.17.1 → basic_memory-0.17.3}/README.md +0 -0
  186. {basic_memory-0.17.1 → basic_memory-0.17.3}/SECURITY.md +0 -0
  187. {basic_memory-0.17.1 → basic_memory-0.17.3}/docker-compose-postgres.yml +0 -0
  188. {basic_memory-0.17.1 → basic_memory-0.17.3}/docker-compose.yml +0 -0
  189. {basic_memory-0.17.1 → basic_memory-0.17.3}/docs/Docker.md +0 -0
  190. {basic_memory-0.17.1 → basic_memory-0.17.3}/docs/ai-assistant-guide-extended.md +0 -0
  191. {basic_memory-0.17.1 → basic_memory-0.17.3}/docs/character-handling.md +0 -0
  192. {basic_memory-0.17.1 → basic_memory-0.17.3}/docs/cloud-cli.md +0 -0
  193. {basic_memory-0.17.1 → basic_memory-0.17.3}/llms-install.md +0 -0
  194. {basic_memory-0.17.1 → basic_memory-0.17.3}/smithery.yaml +0 -0
  195. {basic_memory-0.17.1 → basic_memory-0.17.3}/specs/SPEC-1 Specification-Driven Development Process.md +0 -0
  196. {basic_memory-0.17.1 → basic_memory-0.17.3}/specs/SPEC-10 Unified Deployment Workflow and Event Tracking.md +0 -0
  197. {basic_memory-0.17.1 → basic_memory-0.17.3}/specs/SPEC-11 Basic Memory API Performance Optimization.md +0 -0
  198. {basic_memory-0.17.1 → basic_memory-0.17.3}/specs/SPEC-12 OpenTelemetry Observability.md +0 -0
  199. {basic_memory-0.17.1 → basic_memory-0.17.3}/specs/SPEC-13 CLI Authentication with Subscription Validation.md +0 -0
  200. {basic_memory-0.17.1 → basic_memory-0.17.3}/specs/SPEC-14 Cloud Git Versioning & GitHub Backup.md +0 -0
  201. {basic_memory-0.17.1 → basic_memory-0.17.3}/specs/SPEC-14- Cloud Git Versioning & GitHub Backup.md +0 -0
  202. {basic_memory-0.17.1 → basic_memory-0.17.3}/specs/SPEC-15 Configuration Persistence via Tigris for Cloud Tenants.md +0 -0
  203. {basic_memory-0.17.1 → basic_memory-0.17.3}/specs/SPEC-16 MCP Cloud Service Consolidation.md +0 -0
  204. {basic_memory-0.17.1 → basic_memory-0.17.3}/specs/SPEC-17 Semantic Search with ChromaDB.md +0 -0
  205. {basic_memory-0.17.1 → basic_memory-0.17.3}/specs/SPEC-18 AI Memory Management Tool.md +0 -0
  206. {basic_memory-0.17.1 → basic_memory-0.17.3}/specs/SPEC-19 Sync Performance and Memory Optimization.md +0 -0
  207. {basic_memory-0.17.1 → basic_memory-0.17.3}/specs/SPEC-2 Slash Commands Reference.md +0 -0
  208. {basic_memory-0.17.1 → basic_memory-0.17.3}/specs/SPEC-20 Simplified Project-Scoped Rclone Sync.md +0 -0
  209. {basic_memory-0.17.1 → basic_memory-0.17.3}/specs/SPEC-3 Agent Definitions.md +0 -0
  210. {basic_memory-0.17.1 → basic_memory-0.17.3}/specs/SPEC-4 Notes Web UI Component Architecture.md +0 -0
  211. {basic_memory-0.17.1 → basic_memory-0.17.3}/specs/SPEC-5 CLI Cloud Upload via WebDAV.md +0 -0
  212. {basic_memory-0.17.1 → basic_memory-0.17.3}/specs/SPEC-6 Explicit Project Parameter Architecture.md +0 -0
  213. {basic_memory-0.17.1 → basic_memory-0.17.3}/specs/SPEC-7 POC to spike Tigris Turso for local access to cloud data.md +0 -0
  214. {basic_memory-0.17.1 → basic_memory-0.17.3}/specs/SPEC-8 TigrisFS Integration.md +0 -0
  215. {basic_memory-0.17.1 → basic_memory-0.17.3}/specs/SPEC-9 Multi-Project Bidirectional Sync Architecture.md +0 -0
  216. {basic_memory-0.17.1 → basic_memory-0.17.3}/specs/SPEC-9 Signed Header Tenant Information.md +0 -0
  217. {basic_memory-0.17.1 → basic_memory-0.17.3}/specs/SPEC-9-1 Follow-Ups- Conflict, Sync, and Observability.md +0 -0
  218. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/alembic/alembic.ini +0 -0
  219. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/alembic/env.py +0 -0
  220. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/alembic/migrations.py +0 -0
  221. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/alembic/script.py.mako +0 -0
  222. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/alembic/versions/314f1ea54dc4_add_postgres_full_text_search_support_.py +0 -0
  223. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/alembic/versions/3dae7c7b1564_initial_schema.py +0 -0
  224. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/alembic/versions/502b60eaa905_remove_required_from_entity_permalink.py +0 -0
  225. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/alembic/versions/5fe1ab1ccebe_add_projects_table.py +0 -0
  226. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/alembic/versions/647e7a75e2cd_project_constraint_fix.py +0 -0
  227. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/alembic/versions/9d9c1cb7d8f5_add_mtime_and_size_columns_to_entity_.py +0 -0
  228. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/alembic/versions/a1b2c3d4e5f6_fix_project_foreign_keys.py +0 -0
  229. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/alembic/versions/a2b3c4d5e6f7_add_search_index_entity_cascade.py +0 -0
  230. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/alembic/versions/b3c3938bacdb_relation_to_name_unique_index.py +0 -0
  231. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/alembic/versions/cc7172b46608_update_search_index_schema.py +0 -0
  232. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/alembic/versions/e7e1f4367280_add_scan_watermark_tracking_to_project.py +0 -0
  233. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/alembic/versions/f8a9b2c3d4e5_add_pg_trgm_for_fuzzy_link_resolution.py +0 -0
  234. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/api/__init__.py +0 -0
  235. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/api/routers/__init__.py +0 -0
  236. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/api/routers/directory_router.py +0 -0
  237. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/api/routers/importer_router.py +0 -0
  238. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/api/routers/management_router.py +0 -0
  239. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/api/routers/memory_router.py +0 -0
  240. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/api/routers/prompt_router.py +0 -0
  241. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/api/routers/search_router.py +0 -0
  242. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/api/routers/utils.py +0 -0
  243. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/api/template_loader.py +0 -0
  244. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/api/v2/__init__.py +0 -0
  245. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/api/v2/routers/__init__.py +0 -0
  246. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/cli/__init__.py +0 -0
  247. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/cli/app.py +0 -0
  248. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/cli/commands/__init__.py +0 -0
  249. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/cli/commands/cloud/__init__.py +0 -0
  250. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/cli/commands/cloud/bisync_commands.py +0 -0
  251. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/cli/commands/cloud/core_commands.py +0 -0
  252. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/cli/commands/cloud/rclone_config.py +0 -0
  253. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/cli/commands/cloud/rclone_installer.py +0 -0
  254. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/cli/commands/cloud/upload_command.py +0 -0
  255. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/cli/commands/command_utils.py +0 -0
  256. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/cli/commands/db.py +0 -0
  257. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/cli/commands/format.py +0 -0
  258. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/cli/commands/mcp.py +0 -0
  259. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/cli/commands/status.py +0 -0
  260. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/cli/commands/telemetry.py +0 -0
  261. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/cli/commands/tool.py +0 -0
  262. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/cli/main.py +0 -0
  263. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/db.py +0 -0
  264. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/importers/__init__.py +0 -0
  265. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/importers/utils.py +0 -0
  266. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/markdown/__init__.py +0 -0
  267. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/markdown/entity_parser.py +0 -0
  268. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/markdown/plugins.py +0 -0
  269. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/markdown/schemas.py +0 -0
  270. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/markdown/utils.py +0 -0
  271. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/mcp/__init__.py +0 -0
  272. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/mcp/async_client.py +0 -0
  273. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/mcp/prompts/__init__.py +0 -0
  274. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/mcp/prompts/continue_conversation.py +0 -0
  275. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/mcp/prompts/search.py +0 -0
  276. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/mcp/resources/ai_assistant_guide.md +0 -0
  277. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/mcp/resources/project_info.py +0 -0
  278. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/mcp/tools/__init__.py +0 -0
  279. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/mcp/tools/view_note.py +0 -0
  280. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/models/__init__.py +0 -0
  281. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/models/base.py +0 -0
  282. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/repository/__init__.py +0 -0
  283. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/repository/observation_repository.py +0 -0
  284. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/repository/project_info_repository.py +0 -0
  285. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/repository/repository.py +0 -0
  286. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/repository/search_index_row.py +0 -0
  287. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/schemas/__init__.py +0 -0
  288. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/schemas/cloud.py +0 -0
  289. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/schemas/delete.py +0 -0
  290. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/schemas/importer.py +0 -0
  291. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/schemas/prompt.py +0 -0
  292. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/schemas/request.py +0 -0
  293. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/schemas/search.py +0 -0
  294. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/schemas/v2/__init__.py +0 -0
  295. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/services/__init__.py +0 -0
  296. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/services/entity_service.py +0 -0
  297. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/services/exceptions.py +0 -0
  298. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/services/initialization.py +0 -0
  299. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/services/link_resolver.py +0 -0
  300. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/services/service.py +0 -0
  301. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/sync/__init__.py +0 -0
  302. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/sync/background_sync.py +0 -0
  303. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/telemetry.py +0 -0
  304. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/templates/prompts/continue_conversation.hbs +0 -0
  305. {basic_memory-0.17.1 → basic_memory-0.17.3}/src/basic_memory/templates/prompts/search.hbs +0 -0
  306. {basic_memory-0.17.1 → basic_memory-0.17.3}/test-int/BENCHMARKS.md +0 -0
  307. {basic_memory-0.17.1 → basic_memory-0.17.3}/test-int/cli/test_project_commands_integration.py +0 -0
  308. {basic_memory-0.17.1 → basic_memory-0.17.3}/test-int/cli/test_version_integration.py +0 -0
  309. {basic_memory-0.17.1 → basic_memory-0.17.3}/test-int/mcp/test_build_context_underscore.py +0 -0
  310. {basic_memory-0.17.1 → basic_memory-0.17.3}/test-int/mcp/test_build_context_validation.py +0 -0
  311. {basic_memory-0.17.1 → basic_memory-0.17.3}/test-int/mcp/test_chatgpt_tools_integration.py +0 -0
  312. {basic_memory-0.17.1 → basic_memory-0.17.3}/test-int/mcp/test_default_project_mode_integration.py +0 -0
  313. {basic_memory-0.17.1 → basic_memory-0.17.3}/test-int/mcp/test_delete_note_integration.py +0 -0
  314. {basic_memory-0.17.1 → basic_memory-0.17.3}/test-int/mcp/test_edit_note_integration.py +0 -0
  315. {basic_memory-0.17.1 → basic_memory-0.17.3}/test-int/mcp/test_lifespan_shutdown_sync_task_cancellation_integration.py +0 -0
  316. {basic_memory-0.17.1 → basic_memory-0.17.3}/test-int/mcp/test_list_directory_integration.py +0 -0
  317. {basic_memory-0.17.1 → basic_memory-0.17.3}/test-int/mcp/test_move_note_integration.py +0 -0
  318. {basic_memory-0.17.1 → basic_memory-0.17.3}/test-int/mcp/test_project_management_integration.py +0 -0
  319. {basic_memory-0.17.1 → basic_memory-0.17.3}/test-int/mcp/test_project_state_sync_integration.py +0 -0
  320. {basic_memory-0.17.1 → basic_memory-0.17.3}/test-int/mcp/test_read_content_integration.py +0 -0
  321. {basic_memory-0.17.1 → basic_memory-0.17.3}/test-int/mcp/test_read_note_integration.py +0 -0
  322. {basic_memory-0.17.1 → basic_memory-0.17.3}/test-int/mcp/test_search_integration.py +0 -0
  323. {basic_memory-0.17.1 → basic_memory-0.17.3}/test-int/mcp/test_single_project_mcp_integration.py +0 -0
  324. {basic_memory-0.17.1 → basic_memory-0.17.3}/test-int/test_db_wal_mode.py +0 -0
  325. {basic_memory-0.17.1 → basic_memory-0.17.3}/test-int/test_disable_permalinks_integration.py +0 -0
  326. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/Non-MarkdownFileSupport.pdf +0 -0
  327. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/README.md +0 -0
  328. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/Screenshot.png +0 -0
  329. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/__init__.py +0 -0
  330. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/api/conftest.py +0 -0
  331. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/api/test_continue_conversation_template.py +0 -0
  332. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/api/test_importer_router.py +0 -0
  333. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/api/test_memory_router.py +0 -0
  334. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/api/test_project_router.py +0 -0
  335. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/api/test_project_router_operations.py +0 -0
  336. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/api/test_prompt_router.py +0 -0
  337. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/api/test_resource_router.py +0 -0
  338. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/api/test_search_router.py +0 -0
  339. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/api/test_search_template.py +0 -0
  340. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/api/test_template_loader.py +0 -0
  341. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/api/test_template_loader_helpers.py +0 -0
  342. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/api/v2/__init__.py +0 -0
  343. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/api/v2/test_directory_router.py +0 -0
  344. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/api/v2/test_importer_router.py +0 -0
  345. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/api/v2/test_memory_router.py +0 -0
  346. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/api/v2/test_prompt_router.py +0 -0
  347. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/api/v2/test_search_router.py +0 -0
  348. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/cli/conftest.py +0 -0
  349. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/cli/test_cli_exit.py +0 -0
  350. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/cli/test_ignore_utils.py +0 -0
  351. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/cli/test_import_chatgpt.py +0 -0
  352. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/cli/test_import_claude_conversations.py +0 -0
  353. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/cli/test_import_claude_projects.py +0 -0
  354. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/db/test_issue_254_foreign_key_constraints.py +0 -0
  355. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/importers/test_importer_utils.py +0 -0
  356. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/markdown/__init__.py +0 -0
  357. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/markdown/test_date_frontmatter_parsing.py +0 -0
  358. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/markdown/test_entity_parser.py +0 -0
  359. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/markdown/test_entity_parser_error_handling.py +0 -0
  360. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/markdown/test_markdown_plugins.py +0 -0
  361. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/markdown/test_markdown_processor.py +0 -0
  362. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/markdown/test_observation_edge_cases.py +0 -0
  363. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/markdown/test_parser_edge_cases.py +0 -0
  364. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/markdown/test_relation_edge_cases.py +0 -0
  365. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/markdown/test_task_detection.py +0 -0
  366. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/mcp/conftest.py +0 -0
  367. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/mcp/test_obsidian_yaml_formatting.py +0 -0
  368. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/mcp/test_permalink_collision_file_overwrite.py +0 -0
  369. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/mcp/test_prompts.py +0 -0
  370. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/mcp/test_resources.py +0 -0
  371. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/mcp/test_tool_build_context.py +0 -0
  372. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/mcp/test_tool_canvas.py +0 -0
  373. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/mcp/test_tool_delete_note.py +0 -0
  374. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/mcp/test_tool_edit_note.py +0 -0
  375. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/mcp/test_tool_list_directory.py +0 -0
  376. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/mcp/test_tool_resource.py +0 -0
  377. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/mcp/test_tool_write_note.py +0 -0
  378. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/mcp/test_tool_write_note_kebab_filenames.py +0 -0
  379. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/repository/test_entity_repository.py +0 -0
  380. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/repository/test_entity_repository_upsert.py +0 -0
  381. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/repository/test_entity_upsert_issue_187.py +0 -0
  382. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/repository/test_observation_repository.py +0 -0
  383. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/repository/test_project_info_repository.py +0 -0
  384. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/repository/test_project_repository.py +0 -0
  385. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/repository/test_relation_repository.py +0 -0
  386. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/repository/test_repository.py +0 -0
  387. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/repository/test_search_repository_edit_bug_fix.py +0 -0
  388. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/schemas/test_base_timeframe_minimum.py +0 -0
  389. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/schemas/test_memory_serialization.py +0 -0
  390. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/schemas/test_memory_url.py +0 -0
  391. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/schemas/test_memory_url_validation.py +0 -0
  392. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/schemas/test_search.py +0 -0
  393. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/services/test_context_service.py +0 -0
  394. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/services/test_directory_service.py +0 -0
  395. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/services/test_entity_service_disable_permalinks.py +0 -0
  396. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/services/test_link_resolver.py +0 -0
  397. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/services/test_project_removal_bug.py +0 -0
  398. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/sync/test_character_conflicts.py +0 -0
  399. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/sync/test_sync_service_incremental.py +0 -0
  400. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/sync/test_sync_wikilink_issue.py +0 -0
  401. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/sync/test_tmp_files.py +0 -0
  402. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/test_config.py +0 -0
  403. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/test_deps.py +0 -0
  404. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/test_production_cascade_delete.py +0 -0
  405. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/utils/test_file_utils.py +0 -0
  406. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/utils/test_frontmatter_obsidian_compatible.py +0 -0
  407. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/utils/test_parse_tags.py +0 -0
  408. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/utils/test_permalink_formatting.py +0 -0
  409. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/utils/test_utf8_handling.py +0 -0
  410. {basic_memory-0.17.1 → basic_memory-0.17.3}/tests/utils/test_validate_project_path.py +0 -0
@@ -110,4 +110,58 @@ jobs:
110
110
  - name: Run tests (Postgres via testcontainers)
111
111
  run: |
112
112
  uv pip install pytest pytest-cov
113
- just test-postgres
113
+ just test-postgres
114
+
115
+ coverage:
116
+ name: Coverage Summary (combined, Python 3.12)
117
+ runs-on: ubuntu-latest
118
+
119
+ steps:
120
+ - uses: actions/checkout@v4
121
+ with:
122
+ submodules: true
123
+
124
+ - name: Set up Python 3.12
125
+ uses: actions/setup-python@v4
126
+ with:
127
+ python-version: "3.12"
128
+ cache: "pip"
129
+
130
+ - name: Install uv
131
+ run: |
132
+ pip install uv
133
+
134
+ - name: Install just
135
+ run: |
136
+ curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- --to /usr/local/bin
137
+
138
+ - name: Create virtual env
139
+ run: |
140
+ uv venv
141
+
142
+ - name: Install dependencies
143
+ run: |
144
+ uv pip install -e .[dev]
145
+
146
+ - name: Run combined coverage (SQLite + Postgres)
147
+ run: |
148
+ uv pip install pytest pytest-cov
149
+ just coverage
150
+
151
+ - name: Add coverage report to job summary
152
+ if: always()
153
+ run: |
154
+ {
155
+ echo "## Coverage"
156
+ echo ""
157
+ echo '```'
158
+ uv run coverage report -m
159
+ echo '```'
160
+ } >> "$GITHUB_STEP_SUMMARY"
161
+
162
+ - name: Upload HTML coverage report
163
+ if: always()
164
+ uses: actions/upload-artifact@v4
165
+ with:
166
+ name: htmlcov
167
+ path: htmlcov/
@@ -1,5 +1,60 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## v0.17.3 (2026-01-03)
4
+
5
+ ### Features
6
+
7
+ - **#485**: Add stable external_id (UUID) to Project and Entity models
8
+ ([`a4000f6`](https://github.com/basicmachines-co/basic-memory/commit/a4000f6))
9
+ - Projects and entities now have immutable UUID identifiers
10
+ - API v2 endpoints use external_id for stable references
11
+ - Directory responses include external_id for entities
12
+
13
+ ### Bug Fixes
14
+
15
+ - **#501**: Update mcp dependency to support protocol version 2025-11-25
16
+ ([`c6baf58`](https://github.com/basicmachines-co/basic-memory/commit/c6baf58))
17
+ - Fixes "Unsupported protocol version" error when using Claude Code
18
+ - Bump mcp from >=1.2.0 to >=1.23.1
19
+
20
+ - **#499**: Fix route ordering for cloud deployments
21
+ ([`53c4c20`](https://github.com/basicmachines-co/basic-memory/commit/53c4c20))
22
+
23
+ - **#486**: Skip config file update for set_default_project in cloud mode
24
+ ([`fd732aa`](https://github.com/basicmachines-co/basic-memory/commit/fd732aa))
25
+
26
+ - **#484**: Make RelationResponse.from_id optional to handle null permalinks
27
+ ([`537e58a`](https://github.com/basicmachines-co/basic-memory/commit/537e58a))
28
+
29
+ - Use upsert to prevent IntegrityError during parallel search indexing
30
+ ([`4ce2198`](https://github.com/basicmachines-co/basic-memory/commit/4ce2198))
31
+
32
+ - Use relative file paths in importers for cloud storage compatibility
33
+ ([`8adf1f4`](https://github.com/basicmachines-co/basic-memory/commit/8adf1f4))
34
+
35
+ ### Internal
36
+
37
+ - Refactor importers to use FileService for cloud compatibility
38
+ ([`45ce181`](https://github.com/basicmachines-co/basic-memory/commit/45ce181))
39
+
40
+ - Strengthen integration test coverage, remove stdlib mocks
41
+ ([`b4486d2`](https://github.com/basicmachines-co/basic-memory/commit/b4486d2))
42
+
43
+ ## v0.17.2 (2025-12-29)
44
+
45
+ ### Bug Fixes
46
+
47
+ - Allow recent_activity discovery mode in cloud mode
48
+ ([`0bcda4a`](https://github.com/basicmachines-co/basic-memory/commit/0bcda4a))
49
+ - Add `allow_discovery` parameter to `resolve_project_parameter()`
50
+ - Tools like `recent_activity` can now work across all projects in cloud mode
51
+ - Fix circular import in project_context module
52
+
53
+ ### Internal
54
+
55
+ - Optimize release workflow by running lint/typecheck only (skip full tests)
56
+ ([`0b5425f`](https://github.com/basicmachines-co/basic-memory/commit/0b5425f))
57
+
3
58
  ## v0.17.1 (2025-12-29)
4
59
 
5
60
  ### Bug Fixes
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: basic-memory
3
- Version: 0.17.1
3
+ Version: 0.17.3
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
@@ -19,7 +19,7 @@ Requires-Dist: fastmcp==2.12.3
19
19
  Requires-Dist: greenlet>=3.1.1
20
20
  Requires-Dist: loguru>=0.7.3
21
21
  Requires-Dist: markdown-it-py>=3.0.0
22
- Requires-Dist: mcp>=1.2.0
22
+ Requires-Dist: mcp>=1.23.1
23
23
  Requires-Dist: mdformat-frontmatter>=2.0.8
24
24
  Requires-Dist: mdformat-gfm>=0.3.7
25
25
  Requires-Dist: mdformat>=0.7.22
@@ -0,0 +1,30 @@
1
+ ## Coverage policy (practical 100%)
2
+
3
+ Basic Memory’s test suite intentionally mixes:
4
+ - unit tests (fast, deterministic)
5
+ - integration tests (real filesystem + real DB via `test-int/`)
6
+
7
+ To keep the default CI signal **stable and meaningful**, the default `pytest` coverage report targets **core library logic** and **excludes** a small set of modules that are either:
8
+ - highly environment-dependent (OS/DB tuning)
9
+ - inherently interactive (CLI)
10
+ - background-task orchestration (watchers/sync runners)
11
+ - external analytics
12
+
13
+ ### What’s excluded (and why)
14
+
15
+ Coverage excludes are configured in `pyproject.toml` under `[tool.coverage.report].omit`.
16
+
17
+ Current exclusions include:
18
+ - `src/basic_memory/cli/**`: interactive wrappers; behavior is validated via higher-level tests and smoke tests.
19
+ - `src/basic_memory/db.py`: platform/backend tuning paths (SQLite/Postgres/Windows), covered by integration tests and targeted runs.
20
+ - `src/basic_memory/services/initialization.py`: startup orchestration/background tasks; covered indirectly by app/MCP entrypoints.
21
+ - `src/basic_memory/sync/sync_service.py`: heavy filesystem↔DB integration; validated in integration suite (not enforced in unit coverage).
22
+ - `src/basic_memory/telemetry.py`: external analytics; exercised lightly but excluded from strict coverage gate.
23
+
24
+ ### Recommended additional runs
25
+
26
+ If you want extra confidence locally/CI:
27
+ - **Postgres backend**: run tests with `BASIC_MEMORY_TEST_POSTGRES=1`.
28
+ - **Strict backend-complete coverage**: run coverage on SQLite + Postgres and combine the results (recommended).
29
+
30
+
@@ -98,8 +98,30 @@ test-all:
98
98
 
99
99
  # Generate HTML coverage report
100
100
  coverage:
101
- uv run pytest -p pytest_mock -v -n auto tests test-int --cov-report=html
102
- @echo "Coverage report generated in htmlcov/index.html"
101
+ #!/usr/bin/env bash
102
+ set -euo pipefail
103
+
104
+ uv run coverage erase
105
+
106
+ echo "🔎 Coverage (SQLite)..."
107
+ BASIC_MEMORY_ENV=test uv run coverage run --source=basic_memory -m pytest -p pytest_mock -v --no-cov tests test-int
108
+
109
+ echo "🔎 Coverage (Postgres via testcontainers)..."
110
+ # Note: Uses timeout due to FastMCP Client + asyncpg cleanup hang (tests pass, process hangs on exit)
111
+ # See: https://github.com/jlowin/fastmcp/issues/1311
112
+ TIMEOUT_CMD=$(command -v gtimeout || command -v timeout || echo "")
113
+ if [[ -n "$TIMEOUT_CMD" ]]; then
114
+ $TIMEOUT_CMD --signal=KILL 600 bash -c 'BASIC_MEMORY_ENV=test BASIC_MEMORY_TEST_POSTGRES=1 uv run coverage run --source=basic_memory -m pytest -p pytest_mock -v --no-cov -m postgres tests test-int' || test $? -eq 137
115
+ else
116
+ echo "⚠️ No timeout command found, running without timeout..."
117
+ BASIC_MEMORY_ENV=test BASIC_MEMORY_TEST_POSTGRES=1 uv run coverage run --source=basic_memory -m pytest -p pytest_mock -v --no-cov -m postgres tests test-int
118
+ fi
119
+
120
+ echo "🧩 Combining coverage data..."
121
+ uv run coverage combine
122
+ uv run coverage report -m
123
+ uv run coverage html
124
+ echo "Coverage report generated in htmlcov/index.html"
103
125
 
104
126
  # Lint and fix code (calls fix)
105
127
  lint: fix
@@ -127,14 +149,6 @@ format:
127
149
  run-inspector:
128
150
  npx @modelcontextprotocol/inspector
129
151
 
130
- # Build macOS installer
131
- installer-mac:
132
- cd installer && chmod +x make_icons.sh && ./make_icons.sh
133
- cd installer && uv run python setup.py bdist_mac
134
-
135
- # Build Windows installer
136
- installer-win:
137
- cd installer && uv run python setup.py bdist_win32
138
152
 
139
153
  # Update all dependencies to latest versions
140
154
  update-deps:
@@ -182,8 +196,9 @@ release version:
182
196
  fi
183
197
 
184
198
  # Run quality checks
185
- echo "🔍 Running quality checks..."
186
- just check
199
+ echo "🔍 Running lint checks..."
200
+ just lint
201
+ just typecheck
187
202
 
188
203
  # Update version in __init__.py
189
204
  echo "📝 Updating version in __init__.py..."
@@ -241,8 +256,9 @@ beta version:
241
256
  fi
242
257
 
243
258
  # Run quality checks
244
- echo "🔍 Running quality checks..."
245
- just check
259
+ echo "🔍 Running lint checks..."
260
+ just lint
261
+ just typecheck
246
262
 
247
263
  # Update version in __init__.py
248
264
  echo "📝 Updating version in __init__.py..."
@@ -15,7 +15,7 @@ dependencies = [
15
15
  "aiosqlite>=0.20.0",
16
16
  "greenlet>=3.1.1",
17
17
  "pydantic[email,timezone]>=2.10.3",
18
- "mcp>=1.2.0",
18
+ "mcp>=1.23.1",
19
19
  "pydantic-settings>=2.6.1",
20
20
  "loguru>=0.7.3",
21
21
  "pyright>=1.1.390",
@@ -112,6 +112,8 @@ pythonVersion = "3.12"
112
112
 
113
113
  [tool.coverage.run]
114
114
  concurrency = ["thread", "gevent"]
115
+ parallel = true
116
+ source = ["basic_memory"]
115
117
 
116
118
  [tool.coverage.report]
117
119
  exclude_lines = [
@@ -133,9 +135,11 @@ omit = [
133
135
  "*/supabase_auth_provider.py", # External HTTP calls to Supabase APIs
134
136
  "*/watch_service.py", # File system watching - complex integration testing
135
137
  "*/background_sync.py", # Background processes
136
- "*/cli/main.py", # CLI entry point
137
- "*/mcp/tools/project_management.py", # Covered by integration tests
138
- "*/mcp/tools/sync_status.py", # Covered by integration tests
138
+ "*/cli/**", # CLI is an interactive wrapper; core logic is covered via API/MCP/service tests
139
+ "*/db.py", # Backend/runtime-dependent (sqlite/postgres/windows tuning); validated via integration tests
140
+ "*/services/initialization.py", # Startup orchestration + background tasks (watchers); exercised indirectly in entrypoints
141
+ "*/sync/sync_service.py", # Heavy filesystem/db integration; covered by integration suite, not enforced in unit coverage
142
+ "*/telemetry.py", # External analytics; tested lightly, excluded from strict coverage target
139
143
  "*/services/migration_service.py", # Complex migration scenarios
140
144
  ]
141
145
 
@@ -1,7 +1,7 @@
1
1
  """basic-memory - Local-first knowledge management combining Zettelkasten with knowledge graphs"""
2
2
 
3
3
  # Package version - updated by release automation
4
- __version__ = "0.17.1"
4
+ __version__ = "0.17.3"
5
5
 
6
6
  # API version for FastAPI - independent of package version
7
7
  __api_version__ = "v0"
@@ -0,0 +1,24 @@
1
+ """Merge multiple heads
2
+
3
+ Revision ID: 6830751f5fb6
4
+ Revises: a2b3c4d5e6f7, g9a0b3c4d5e6
5
+ Create Date: 2025-12-29 12:46:46.476268
6
+
7
+ """
8
+ from typing import Sequence, Union
9
+
10
+
11
+
12
+ # revision identifiers, used by Alembic.
13
+ revision: str = '6830751f5fb6'
14
+ down_revision: Union[str, Sequence[str], None] = ('a2b3c4d5e6f7', 'g9a0b3c4d5e6')
15
+ branch_labels: Union[str, Sequence[str], None] = None
16
+ depends_on: Union[str, Sequence[str], None] = None
17
+
18
+
19
+ def upgrade() -> None:
20
+ pass
21
+
22
+
23
+ def downgrade() -> None:
24
+ pass
@@ -0,0 +1,173 @@
1
+ """Add external_id UUID column to project and entity tables
2
+
3
+ Revision ID: g9a0b3c4d5e6
4
+ Revises: f8a9b2c3d4e5
5
+ Create Date: 2025-12-29 10:00:00.000000
6
+
7
+ """
8
+
9
+ import uuid
10
+ from typing import Sequence, Union
11
+
12
+ import sqlalchemy as sa
13
+ from alembic import op
14
+ from sqlalchemy import text
15
+
16
+
17
+ def column_exists(connection, table: str, column: str) -> bool:
18
+ """Check if a column exists in a table (idempotent migration support)."""
19
+ if connection.dialect.name == "postgresql":
20
+ result = connection.execute(
21
+ text(
22
+ "SELECT 1 FROM information_schema.columns "
23
+ "WHERE table_name = :table AND column_name = :column"
24
+ ),
25
+ {"table": table, "column": column},
26
+ )
27
+ return result.fetchone() is not None
28
+ else:
29
+ # SQLite
30
+ result = connection.execute(text(f"PRAGMA table_info({table})"))
31
+ columns = [row[1] for row in result]
32
+ return column in columns
33
+
34
+
35
+ def index_exists(connection, index_name: str) -> bool:
36
+ """Check if an index exists (idempotent migration support)."""
37
+ if connection.dialect.name == "postgresql":
38
+ result = connection.execute(
39
+ text("SELECT 1 FROM pg_indexes WHERE indexname = :index_name"),
40
+ {"index_name": index_name},
41
+ )
42
+ return result.fetchone() is not None
43
+ else:
44
+ # SQLite
45
+ result = connection.execute(
46
+ text("SELECT 1 FROM sqlite_master WHERE type='index' AND name = :index_name"),
47
+ {"index_name": index_name},
48
+ )
49
+ return result.fetchone() is not None
50
+
51
+
52
+ # revision identifiers, used by Alembic.
53
+ revision: str = "g9a0b3c4d5e6"
54
+ down_revision: Union[str, None] = "f8a9b2c3d4e5"
55
+ branch_labels: Union[str, Sequence[str], None] = None
56
+ depends_on: Union[str, Sequence[str], None] = None
57
+
58
+
59
+ def upgrade() -> None:
60
+ """Add external_id UUID column to project and entity tables.
61
+
62
+ This migration:
63
+ 1. Adds external_id column to project table
64
+ 2. Adds external_id column to entity table
65
+ 3. Generates UUIDs for existing rows
66
+ 4. Creates unique indexes on both columns
67
+ """
68
+ connection = op.get_bind()
69
+ dialect = connection.dialect.name
70
+
71
+ # -------------------------------------------------------------------------
72
+ # Add external_id to project table
73
+ # -------------------------------------------------------------------------
74
+
75
+ if not column_exists(connection, "project", "external_id"):
76
+ # Step 1: Add external_id column as nullable first
77
+ op.add_column("project", sa.Column("external_id", sa.String(), nullable=True))
78
+
79
+ # Step 2: Generate UUIDs for existing rows
80
+ if dialect == "postgresql":
81
+ # Postgres has gen_random_uuid() function
82
+ op.execute("""
83
+ UPDATE project
84
+ SET external_id = gen_random_uuid()::text
85
+ WHERE external_id IS NULL
86
+ """)
87
+ else:
88
+ # SQLite: need to generate UUIDs in Python
89
+ result = connection.execute(text("SELECT id FROM project WHERE external_id IS NULL"))
90
+ for row in result:
91
+ new_uuid = str(uuid.uuid4())
92
+ connection.execute(
93
+ text("UPDATE project SET external_id = :uuid WHERE id = :id"),
94
+ {"uuid": new_uuid, "id": row[0]},
95
+ )
96
+
97
+ # Step 3: Make external_id NOT NULL
98
+ if dialect == "postgresql":
99
+ op.alter_column("project", "external_id", nullable=False)
100
+ else:
101
+ # SQLite requires batch operations for ALTER COLUMN
102
+ with op.batch_alter_table("project") as batch_op:
103
+ batch_op.alter_column("external_id", nullable=False)
104
+
105
+ # Step 4: Create unique index on project.external_id (idempotent)
106
+ if not index_exists(connection, "ix_project_external_id"):
107
+ op.create_index("ix_project_external_id", "project", ["external_id"], unique=True)
108
+
109
+ # -------------------------------------------------------------------------
110
+ # Add external_id to entity table
111
+ # -------------------------------------------------------------------------
112
+
113
+ if not column_exists(connection, "entity", "external_id"):
114
+ # Step 1: Add external_id column as nullable first
115
+ op.add_column("entity", sa.Column("external_id", sa.String(), nullable=True))
116
+
117
+ # Step 2: Generate UUIDs for existing rows
118
+ if dialect == "postgresql":
119
+ # Postgres has gen_random_uuid() function
120
+ op.execute("""
121
+ UPDATE entity
122
+ SET external_id = gen_random_uuid()::text
123
+ WHERE external_id IS NULL
124
+ """)
125
+ else:
126
+ # SQLite: need to generate UUIDs in Python
127
+ result = connection.execute(text("SELECT id FROM entity WHERE external_id IS NULL"))
128
+ for row in result:
129
+ new_uuid = str(uuid.uuid4())
130
+ connection.execute(
131
+ text("UPDATE entity SET external_id = :uuid WHERE id = :id"),
132
+ {"uuid": new_uuid, "id": row[0]},
133
+ )
134
+
135
+ # Step 3: Make external_id NOT NULL
136
+ if dialect == "postgresql":
137
+ op.alter_column("entity", "external_id", nullable=False)
138
+ else:
139
+ # SQLite requires batch operations for ALTER COLUMN
140
+ with op.batch_alter_table("entity") as batch_op:
141
+ batch_op.alter_column("external_id", nullable=False)
142
+
143
+ # Step 4: Create unique index on entity.external_id (idempotent)
144
+ if not index_exists(connection, "ix_entity_external_id"):
145
+ op.create_index("ix_entity_external_id", "entity", ["external_id"], unique=True)
146
+
147
+
148
+ def downgrade() -> None:
149
+ """Remove external_id columns from project and entity tables."""
150
+ connection = op.get_bind()
151
+ dialect = connection.dialect.name
152
+
153
+ # Drop from entity table
154
+ if index_exists(connection, "ix_entity_external_id"):
155
+ op.drop_index("ix_entity_external_id", table_name="entity")
156
+
157
+ if column_exists(connection, "entity", "external_id"):
158
+ if dialect == "postgresql":
159
+ op.drop_column("entity", "external_id")
160
+ else:
161
+ with op.batch_alter_table("entity") as batch_op:
162
+ batch_op.drop_column("external_id")
163
+
164
+ # Drop from project table
165
+ if index_exists(connection, "ix_project_external_id"):
166
+ op.drop_index("ix_project_external_id", table_name="project")
167
+
168
+ if column_exists(connection, "project", "external_id"):
169
+ if dialect == "postgresql":
170
+ op.drop_column("project", "external_id")
171
+ else:
172
+ with op.batch_alter_table("project") as batch_op:
173
+ batch_op.drop_column("external_id")
@@ -92,17 +92,7 @@ app = FastAPI(
92
92
  lifespan=lifespan,
93
93
  )
94
94
 
95
- # Include v1 routers
96
- app.include_router(knowledge.router, prefix="/{project}")
97
- app.include_router(memory.router, prefix="/{project}")
98
- app.include_router(resource.router, prefix="/{project}")
99
- app.include_router(search.router, prefix="/{project}")
100
- app.include_router(project.project_router, prefix="/{project}")
101
- app.include_router(directory_router.router, prefix="/{project}")
102
- app.include_router(prompt_router.router, prefix="/{project}")
103
- app.include_router(importer_router.router, prefix="/{project}")
104
-
105
- # Include v2 routers (ID-based paths)
95
+ # Include v2 routers FIRST (more specific paths must match before /{project} catch-all)
106
96
  app.include_router(v2_knowledge, prefix="/v2/projects/{project_id}")
107
97
  app.include_router(v2_memory, prefix="/v2/projects/{project_id}")
108
98
  app.include_router(v2_search, prefix="/v2/projects/{project_id}")
@@ -112,6 +102,16 @@ app.include_router(v2_prompt, prefix="/v2/projects/{project_id}")
112
102
  app.include_router(v2_importer, prefix="/v2/projects/{project_id}")
113
103
  app.include_router(v2_project, prefix="/v2")
114
104
 
105
+ # Include v1 routers (/{project} is a catch-all, must come after specific prefixes)
106
+ app.include_router(knowledge.router, prefix="/{project}")
107
+ app.include_router(memory.router, prefix="/{project}")
108
+ app.include_router(resource.router, prefix="/{project}")
109
+ app.include_router(search.router, prefix="/{project}")
110
+ app.include_router(project.project_router, prefix="/{project}")
111
+ app.include_router(directory_router.router, prefix="/{project}")
112
+ app.include_router(prompt_router.router, prefix="/{project}")
113
+ app.include_router(importer_router.router, prefix="/{project}")
114
+
115
115
  # Project resource router works across projects
116
116
  app.include_router(project.project_resource_router)
117
117
  app.include_router(management.router)
@@ -51,9 +51,10 @@ async def resolve_relations_background(sync_service, entity_id: int, entity_perm
51
51
  logger.debug(
52
52
  f"Background: Resolved relations for entity {entity_permalink} (id={entity_id})"
53
53
  )
54
- except Exception as e:
55
- # Log but don't fail - this is a background task
56
- logger.warning(
54
+ except Exception as e: # pragma: no cover
55
+ # Log but don't fail - this is a background task.
56
+ # Avoid forcing synthetic failures just for coverage.
57
+ logger.warning( # pragma: no cover
57
58
  f"Background: Failed to resolve relations for entity {entity_permalink}: {e}"
58
59
  )
59
60
 
@@ -51,6 +51,7 @@ async def get_project(
51
51
 
52
52
  return ProjectItem(
53
53
  id=found_project.id,
54
+ external_id=found_project.external_id,
54
55
  name=found_project.name,
55
56
  path=normalize_project_path(found_project.path),
56
57
  is_default=found_project.is_default or False,
@@ -89,6 +90,7 @@ async def update_project(
89
90
 
90
91
  old_project_info = ProjectItem(
91
92
  id=old_project.id,
93
+ external_id=old_project.external_id,
92
94
  name=old_project.name,
93
95
  path=old_project.path,
94
96
  is_default=old_project.is_default or False,
@@ -102,7 +104,9 @@ async def update_project(
102
104
  # Get updated project info
103
105
  updated_project = await project_service.get_project(name)
104
106
  if not updated_project:
105
- raise HTTPException(status_code=404, detail=f"Project '{name}' not found after update")
107
+ raise HTTPException( # pragma: no cover
108
+ status_code=404, detail=f"Project '{name}' not found after update"
109
+ )
106
110
 
107
111
  return ProjectStatusResponse(
108
112
  message=f"Project '{name}' updated successfully",
@@ -111,13 +115,14 @@ async def update_project(
111
115
  old_project=old_project_info,
112
116
  new_project=ProjectItem(
113
117
  id=updated_project.id,
118
+ external_id=updated_project.external_id,
114
119
  name=updated_project.name,
115
120
  path=updated_project.path,
116
121
  is_default=updated_project.is_default or False,
117
122
  ),
118
123
  )
119
124
  except ValueError as e:
120
- raise HTTPException(status_code=400, detail=str(e))
125
+ raise HTTPException(status_code=400, detail=str(e)) # pragma: no cover
121
126
 
122
127
 
123
128
  # Sync project filesystem
@@ -181,10 +186,10 @@ async def project_sync_status(
181
186
  Returns:
182
187
  Scan report with details on files that need syncing
183
188
  """
184
- logger.info(f"Scanning filesystem for project: {project_config.name}")
185
- sync_report = await sync_service.scan(project_config.home)
189
+ logger.info(f"Scanning filesystem for project: {project_config.name}") # pragma: no cover
190
+ sync_report = await sync_service.scan(project_config.home) # pragma: no cover
186
191
 
187
- return SyncReportResponse.from_sync_report(sync_report)
192
+ return SyncReportResponse.from_sync_report(sync_report) # pragma: no cover
188
193
 
189
194
 
190
195
  # List all available projects
@@ -203,6 +208,7 @@ async def list_projects(
203
208
  project_items = [
204
209
  ProjectItem(
205
210
  id=project.id,
211
+ external_id=project.external_id,
206
212
  name=project.name,
207
213
  path=normalize_project_path(project.path),
208
214
  is_default=project.is_default or False,
@@ -250,6 +256,7 @@ async def add_project(
250
256
  default=existing_project.is_default or False,
251
257
  new_project=ProjectItem(
252
258
  id=existing_project.id,
259
+ external_id=existing_project.external_id,
253
260
  name=existing_project.name,
254
261
  path=existing_project.path,
255
262
  is_default=existing_project.is_default or False,
@@ -279,6 +286,7 @@ async def add_project(
279
286
  default=project_data.set_default,
280
287
  new_project=ProjectItem(
281
288
  id=new_project.id,
289
+ external_id=new_project.external_id,
282
290
  name=new_project.name,
283
291
  path=new_project.path,
284
292
  is_default=new_project.is_default or False,
@@ -334,6 +342,7 @@ async def remove_project(
334
342
  default=False,
335
343
  old_project=ProjectItem(
336
344
  id=old_project.id,
345
+ external_id=old_project.external_id,
337
346
  name=old_project.name,
338
347
  path=old_project.path,
339
348
  is_default=old_project.is_default or False,
@@ -382,12 +391,14 @@ async def set_default_project(
382
391
  default=True,
383
392
  old_project=ProjectItem(
384
393
  id=default_project.id,
394
+ external_id=default_project.external_id,
385
395
  name=default_name,
386
396
  path=default_project.path,
387
397
  is_default=False,
388
398
  ),
389
399
  new_project=ProjectItem(
390
400
  id=new_default_project.id,
401
+ external_id=new_default_project.external_id,
391
402
  name=name,
392
403
  path=new_default_project.path,
393
404
  is_default=True,
@@ -417,6 +428,7 @@ async def get_default_project(
417
428
 
418
429
  return ProjectItem(
419
430
  id=default_project.id,
431
+ external_id=default_project.external_id,
420
432
  name=default_project.name,
421
433
  path=default_project.path,
422
434
  is_default=True,
@@ -31,8 +31,8 @@ def _mtime_to_datetime(entity: EntityModel) -> datetime:
31
31
  Returns the file's actual modification time, falling back to updated_at
32
32
  if mtime is not available.
33
33
  """
34
- if entity.mtime:
35
- return datetime.fromtimestamp(entity.mtime).astimezone()
34
+ if entity.mtime: # pragma: no cover
35
+ return datetime.fromtimestamp(entity.mtime).astimezone() # pragma: no cover
36
36
  return entity.updated_at
37
37
 
38
38
 
@@ -169,11 +169,11 @@ async def write_resource(
169
169
  # FastAPI should validate this, but if a dict somehow gets through
170
170
  # (e.g., via JSON body parsing), we need to catch it here
171
171
  if isinstance(content, dict):
172
- logger.error(
172
+ logger.error( # pragma: no cover
173
173
  f"Error writing resource {file_path}: "
174
174
  f"content is a dict, expected string. Keys: {list(content.keys())}"
175
175
  )
176
- raise HTTPException(
176
+ raise HTTPException( # pragma: no cover
177
177
  status_code=400,
178
178
  detail="content must be a string, not a dict. "
179
179
  "Ensure request body is sent as raw string content, not JSON object.",