basic-memory 0.1.1__py3-none-any.whl → 0.1.2__py3-none-any.whl

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.

Files changed (77) hide show
  1. basic_memory/__init__.py +1 -1
  2. basic_memory/alembic/README +1 -0
  3. basic_memory/alembic/env.py +75 -0
  4. basic_memory/alembic/migrations.py +29 -0
  5. basic_memory/alembic/script.py.mako +26 -0
  6. basic_memory/alembic/versions/3dae7c7b1564_initial_schema.py +93 -0
  7. basic_memory/api/__init__.py +2 -1
  8. basic_memory/api/app.py +26 -24
  9. basic_memory/api/routers/knowledge_router.py +28 -26
  10. basic_memory/api/routers/memory_router.py +17 -11
  11. basic_memory/api/routers/search_router.py +6 -12
  12. basic_memory/cli/__init__.py +1 -1
  13. basic_memory/cli/app.py +0 -1
  14. basic_memory/cli/commands/__init__.py +3 -3
  15. basic_memory/cli/commands/db.py +25 -0
  16. basic_memory/cli/commands/import_memory_json.py +35 -31
  17. basic_memory/cli/commands/mcp.py +20 -0
  18. basic_memory/cli/commands/status.py +10 -6
  19. basic_memory/cli/commands/sync.py +5 -56
  20. basic_memory/cli/main.py +5 -38
  21. basic_memory/config.py +3 -3
  22. basic_memory/db.py +15 -22
  23. basic_memory/deps.py +3 -4
  24. basic_memory/file_utils.py +36 -35
  25. basic_memory/markdown/entity_parser.py +13 -30
  26. basic_memory/markdown/markdown_processor.py +7 -7
  27. basic_memory/markdown/plugins.py +109 -123
  28. basic_memory/markdown/schemas.py +7 -8
  29. basic_memory/markdown/utils.py +70 -121
  30. basic_memory/mcp/__init__.py +1 -1
  31. basic_memory/mcp/async_client.py +0 -2
  32. basic_memory/mcp/server.py +3 -27
  33. basic_memory/mcp/tools/__init__.py +5 -3
  34. basic_memory/mcp/tools/knowledge.py +2 -2
  35. basic_memory/mcp/tools/memory.py +8 -4
  36. basic_memory/mcp/tools/search.py +2 -1
  37. basic_memory/mcp/tools/utils.py +1 -1
  38. basic_memory/models/__init__.py +1 -2
  39. basic_memory/models/base.py +3 -3
  40. basic_memory/models/knowledge.py +23 -60
  41. basic_memory/models/search.py +1 -1
  42. basic_memory/repository/__init__.py +5 -3
  43. basic_memory/repository/entity_repository.py +34 -98
  44. basic_memory/repository/relation_repository.py +0 -7
  45. basic_memory/repository/repository.py +2 -39
  46. basic_memory/repository/search_repository.py +20 -25
  47. basic_memory/schemas/__init__.py +4 -4
  48. basic_memory/schemas/base.py +21 -62
  49. basic_memory/schemas/delete.py +2 -3
  50. basic_memory/schemas/discovery.py +4 -1
  51. basic_memory/schemas/memory.py +12 -13
  52. basic_memory/schemas/request.py +4 -23
  53. basic_memory/schemas/response.py +10 -9
  54. basic_memory/schemas/search.py +4 -7
  55. basic_memory/services/__init__.py +2 -7
  56. basic_memory/services/context_service.py +116 -110
  57. basic_memory/services/entity_service.py +25 -62
  58. basic_memory/services/exceptions.py +1 -0
  59. basic_memory/services/file_service.py +73 -109
  60. basic_memory/services/link_resolver.py +9 -9
  61. basic_memory/services/search_service.py +22 -15
  62. basic_memory/services/service.py +3 -24
  63. basic_memory/sync/__init__.py +2 -2
  64. basic_memory/sync/file_change_scanner.py +3 -7
  65. basic_memory/sync/sync_service.py +35 -40
  66. basic_memory/sync/utils.py +6 -38
  67. basic_memory/sync/watch_service.py +26 -5
  68. basic_memory/utils.py +42 -33
  69. {basic_memory-0.1.1.dist-info → basic_memory-0.1.2.dist-info}/METADATA +2 -7
  70. basic_memory-0.1.2.dist-info/RECORD +78 -0
  71. basic_memory/mcp/main.py +0 -21
  72. basic_memory/mcp/tools/ai_edit.py +0 -84
  73. basic_memory/services/database_service.py +0 -159
  74. basic_memory-0.1.1.dist-info/RECORD +0 -74
  75. {basic_memory-0.1.1.dist-info → basic_memory-0.1.2.dist-info}/WHEEL +0 -0
  76. {basic_memory-0.1.1.dist-info → basic_memory-0.1.2.dist-info}/entry_points.txt +0 -0
  77. {basic_memory-0.1.1.dist-info → basic_memory-0.1.2.dist-info}/licenses/LICENSE +0 -0
@@ -1,159 +0,0 @@
1
- """Service for managing database lifecycle and schema validation."""
2
-
3
- from datetime import datetime
4
- from pathlib import Path
5
- from typing import Optional, Tuple, List
6
-
7
- from alembic.runtime.migration import MigrationContext
8
- from alembic.autogenerate import compare_metadata
9
- from loguru import logger
10
- from sqlalchemy import MetaData
11
- from sqlalchemy.ext.asyncio import AsyncSession
12
-
13
- from basic_memory import db
14
- from basic_memory.config import ProjectConfig
15
- from basic_memory.models import Base
16
- from basic_memory.repository.search_repository import SearchRepository
17
-
18
-
19
- async def check_schema_matches_models(session: AsyncSession) -> Tuple[bool, List[str]]:
20
- """Check if database schema matches SQLAlchemy models.
21
-
22
- Returns:
23
- tuple[bool, list[str]]: (matches, list of differences)
24
- """
25
- # Get current DB schema via migration context
26
- conn = await session.connection()
27
-
28
- def _compare_schemas(connection):
29
- context = MigrationContext.configure(connection)
30
- return compare_metadata(context, Base.metadata)
31
-
32
- # Run comparison in sync context
33
- differences = await conn.run_sync(_compare_schemas)
34
-
35
- if not differences:
36
- return True, []
37
-
38
- # Format differences into readable messages
39
- diff_messages = []
40
- for diff in differences:
41
- if diff[0] == 'add_table':
42
- diff_messages.append(f"Missing table: {diff[1].name}")
43
- elif diff[0] == 'remove_table':
44
- diff_messages.append(f"Extra table: {diff[1].name}")
45
- elif diff[0] == 'add_column':
46
- diff_messages.append(f"Missing column: {diff[3]} in table {diff[2]}")
47
- elif diff[0] == 'remove_column':
48
- diff_messages.append(f"Extra column: {diff[3]} in table {diff[2]}")
49
- elif diff[0] == 'modify_type':
50
- diff_messages.append(f"Column type mismatch: {diff[3]} in table {diff[2]}")
51
-
52
- return False, diff_messages
53
-
54
-
55
- class DatabaseService:
56
- """Manages database lifecycle including schema validation and backups."""
57
-
58
- def __init__(
59
- self,
60
- config: ProjectConfig,
61
- db_type: db.DatabaseType = db.DatabaseType.FILESYSTEM,
62
- ):
63
- self.config = config
64
- self.db_path = Path(config.database_path)
65
- self.db_type = db_type
66
-
67
- async def create_backup(self) -> Optional[Path]:
68
- """Create backup of existing database file.
69
-
70
- Returns:
71
- Optional[Path]: Path to backup file if created, None if no DB exists
72
- """
73
- if self.db_type == db.DatabaseType.MEMORY:
74
- return None # Skip backups for in-memory DB
75
-
76
- if not self.db_path.exists():
77
- return None
78
-
79
- # Create backup with timestamp
80
- timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
81
- backup_path = self.db_path.with_suffix(f".{timestamp}.backup")
82
-
83
- try:
84
- self.db_path.rename(backup_path)
85
- logger.info(f"Created database backup: {backup_path}")
86
-
87
- # make a new empty file
88
- self.db_path.touch()
89
- return backup_path
90
- except Exception as e:
91
- logger.error(f"Failed to create database backup: {e}")
92
- return None
93
-
94
- async def initialize_db(self):
95
- """Initialize database with current schema."""
96
- logger.info("Initializing database...")
97
-
98
- if self.db_type == db.DatabaseType.FILESYSTEM:
99
- await self.create_backup()
100
-
101
- # Drop existing tables if any
102
- await db.drop_db()
103
-
104
- # Create tables with current schema
105
- await db.get_or_create_db(
106
- db_path=self.db_path,
107
- db_type=self.db_type
108
- )
109
-
110
- logger.info("Database initialized with current schema")
111
-
112
- async def check_db(self) -> bool:
113
- """Check database state and rebuild if schema doesn't match models.
114
-
115
- Returns:
116
- bool: True if DB is ready for use, False if initialization failed
117
- """
118
- try:
119
- _, session_maker = await db.get_or_create_db(
120
- db_path=self.db_path,
121
- db_type=self.db_type
122
- )
123
- async with db.scoped_session(session_maker) as db_session:
124
- # Check actual schema matches
125
- matches, differences = await check_schema_matches_models(db_session)
126
- if not matches:
127
- logger.warning("Database schema does not match models:")
128
- for diff in differences:
129
- logger.warning(f" {diff}")
130
- logger.info("Rebuilding database to match current models...")
131
- await self.initialize_db()
132
- return True
133
-
134
- logger.info("Database schema matches models")
135
- return True
136
-
137
- except Exception as e:
138
- logger.error(f"Database initialization failed: {e}")
139
- return False
140
-
141
- async def cleanup_backups(self, keep_count: int = 5):
142
- """Clean up old database backups, keeping the N most recent."""
143
- if self.db_type == db.DatabaseType.MEMORY:
144
- return # Skip cleanup for in-memory DB
145
-
146
- backup_pattern = "*.backup" # Use relative pattern
147
- backups = sorted(
148
- self.db_path.parent.glob(backup_pattern),
149
- key=lambda p: p.stat().st_mtime,
150
- reverse=True,
151
- )
152
-
153
- # Remove old backups
154
- for backup in backups[keep_count:]:
155
- try:
156
- backup.unlink()
157
- logger.debug(f"Removed old backup: {backup}")
158
- except Exception as e:
159
- logger.error(f"Failed to remove backup {backup}: {e}")
@@ -1,74 +0,0 @@
1
- basic_memory/__init__.py,sha256=5AdJrNglWu8gvlZPWZDKmrYbpOaJJ7KcdBfSQxBl3A8,121
2
- basic_memory/config.py,sha256=bmNBTbbl8YhEsHOI0fnC7EfxIuyKB25LhtNuXzFlXnY,1671
3
- basic_memory/db.py,sha256=rTNI7_rP5sGEpJvIGwk3VXEPbGwqoyKaSXxNgDAxxZQ,4639
4
- basic_memory/deps.py,sha256=YeDwqEmqUTPOc-JdItE1NEj3iunB2j6thYotweHXq98,5316
5
- basic_memory/file_utils.py,sha256=-B-ixIGo4kf27nXE7mlyO5SljK-BhXvSN9rsXfJu0HQ,5814
6
- basic_memory/utils.py,sha256=FCXR_jQxr8qBtHSHkWoESEvSVwPiWjn5xfAPmyqYW0g,2321
7
- basic_memory/api/__init__.py,sha256=2y71HVPvGBIjx2tTd6nsSGeAFuFEyNn2MZ9IcqIs1hY,70
8
- basic_memory/api/app.py,sha256=RcljMzKZIETofuybHDCmQizFcXddDiLSxOPm3ggWF1Q,1755
9
- basic_memory/api/routers/__init__.py,sha256=iviQ1QVYobC8huUuyRhEjcA0BDjrOUm1lXHXhJkxP9A,239
10
- basic_memory/api/routers/knowledge_router.py,sha256=9t-ogIL8HVtGi6_eM-OAM8yY5VZZK-goSKSqbG9GLvI,5756
11
- basic_memory/api/routers/memory_router.py,sha256=YVM_2B1-1N-8ytmW9NcMwR5ee8ykM935s6psO-5uLuo,4231
12
- basic_memory/api/routers/resource_router.py,sha256=_Gp5HSJr-L-GUkQKbEP2bAZvCY8Smd-sBNWpGyqXS4c,1056
13
- basic_memory/api/routers/search_router.py,sha256=eKUibpJGuniLgTxXI_C28CjMrSNoXIrEwrlTBTkf1y4,1168
14
- basic_memory/cli/__init__.py,sha256=Hs6p69LnxlgO41EYFY0zMDCsbB3QxvPH9duNZz0hROs,32
15
- basic_memory/cli/app.py,sha256=gevKtdiAIlsJCbvegd1Pt7NID96Bq7yM1Hv2irHS0tY,35
16
- basic_memory/cli/main.py,sha256=E54Cl4gvHGijiY0UmNSLa-Dlm66EHxfvd2Tr4bB1XIY,1077
17
- basic_memory/cli/commands/__init__.py,sha256=18zCHPanlry0a-5C2bRa-ydwQ8Ki40D2A3M6j7zVmKE,134
18
- basic_memory/cli/commands/import_memory_json.py,sha256=jpGJpEx8QuARi3ZurH4bvDSF-c3c_hTktNLps-0YsSo,5207
19
- basic_memory/cli/commands/status.py,sha256=Dqp8mGR7vFpB-bVkIBRKvWeIkfDN7KyYaAKdtoAEYY4,5691
20
- basic_memory/cli/commands/sync.py,sha256=ycyD9yuZdKrtSd6L6sPQU1N3ang9FDIt5w-BHpqoD-c,8482
21
- basic_memory/markdown/__init__.py,sha256=DdzioCWtDnKaq05BHYLgL_78FawEHLpLXnp-kPSVfIc,501
22
- basic_memory/markdown/entity_parser.py,sha256=EBpBrmspZ7VbWdrro4K2fp5lCxMe-HKCcW5T3MoFB7s,4439
23
- basic_memory/markdown/markdown_processor.py,sha256=7XUagES8n4gRW8xt9KC7XTyO1spFNzal8kKWGiQvyMU,4985
24
- basic_memory/markdown/plugins.py,sha256=lc2C3kFsQdyw83j-T6ovT6489jr8QuUQ9Invqgj0Of0,7601
25
- basic_memory/markdown/schemas.py,sha256=fUNzaf2YNhDJlG_PmHdwmU0H_S_uf332jcuU9raGaXs,1839
26
- basic_memory/markdown/utils.py,sha256=jNSjpeDD2mBccbV3w5WXv6fzuiAKurU2jvT_vFOYbys,5234
27
- basic_memory/mcp/__init__.py,sha256=UioEZETQ-1lEfbqi1XirraBaiHdMHDX6JBpRZbAXTYY,34
28
- basic_memory/mcp/async_client.py,sha256=J4eSKs4VMef1AoWBHOwvzjS6kzfNntjg6cPxPpw56RQ,238
29
- basic_memory/mcp/main.py,sha256=X27Y4DvoLDkhnIy6wixdrtM_Jo0ShPqhMEBpmnTxPmM,503
30
- basic_memory/mcp/server.py,sha256=nSCgu7SCTMviZDi02FOD6PEsZumg1ZtTwvmpwIuxeXg,926
31
- basic_memory/mcp/tools/__init__.py,sha256=j3XpNTu-f0IeOFfo6ZNNtl728fzNwsN4w_kZQiMIE4U,820
32
- basic_memory/mcp/tools/ai_edit.py,sha256=0a6GTqJZdDyYhfecT23pP1VPPvk5bfPRX8bCFN_SKoE,2531
33
- basic_memory/mcp/tools/knowledge.py,sha256=OX-4Sz7Ox1so4USwuhf1iAL-I6bzzPgE5U0hajs-5Cc,2010
34
- basic_memory/mcp/tools/memory.py,sha256=OTKwcOZiGPRDceyNsadvcqqY5Azpb0C1MjvzZatKt3s,5252
35
- basic_memory/mcp/tools/notes.py,sha256=4GKnhDK53UkeZtpZENQ9id9XdemKxLzGwMQJeuX-Kok,3772
36
- basic_memory/mcp/tools/search.py,sha256=ViYLp-yGTxOEJli3PyE_JiBP3JXQ0fs-XLS09Sl7hoc,1103
37
- basic_memory/mcp/tools/utils.py,sha256=9sOE_zW-kr7zbwRRlLAhR5cCmcGfuewNsUtiInXULnk,4857
38
- basic_memory/models/__init__.py,sha256=VA_RP2xVrghTkOtILKvRDkn8EoP6UfjhnP8UgqupSkk,355
39
- basic_memory/models/base.py,sha256=SnOpuFxcw7QoLxXpmZ1NUoj1jEJKCXEWQqTIrXjJ3Z4,286
40
- basic_memory/models/knowledge.py,sha256=F2vfKalqfqumUlASN22QnPzaOym5MahzZ3sAACE3y9Y,6792
41
- basic_memory/models/search.py,sha256=iO1sgBiS1aVCts2EGfjys0i09-1_snxXs2pZNfK6Ojw,1163
42
- basic_memory/repository/__init__.py,sha256=Q1T0Qn1AcyUWLpPrFcfdEa3A1xUkAzt63tgv5U59DpI,241
43
- basic_memory/repository/entity_repository.py,sha256=Nn_ZS4K2cakMD_LVGJfGqQ-0SZ2W-dI_W8wfj-LM-ZQ,6008
44
- basic_memory/repository/observation_repository.py,sha256=BOcy4wARqCXu-thYyt7mPxt2A2C8TW0le3s_X9wrK6I,1701
45
- basic_memory/repository/relation_repository.py,sha256=mHZj3Uhapm9OG7NyTldIspJ7BdNKXKKjJD1lextQKGk,3234
46
- basic_memory/repository/repository.py,sha256=UCMy7VXjtkxkKCI3ZuQm4_RFRKJT0NBDhEvt_ueqjzc,12945
47
- basic_memory/repository/search_repository.py,sha256=Q0v8MIsyQS_M9WD6mHIyRwFlMGanjgkBIAEGEbPR6J8,9426
48
- basic_memory/schemas/__init__.py,sha256=m1Pou5ue1BNmHBm13WPBf3BJKKPsLaIYVnnGmgs2iwo,1618
49
- basic_memory/schemas/base.py,sha256=4O_uxXX_JDpMqPNk7jXduA3Ut3Uz1wjmrf27JlkI-e8,6694
50
- basic_memory/schemas/delete.py,sha256=_tSyTHAujVxkSUy5Cu3s6yHw-n3JmokjeMR6gZqJhG4,1198
51
- basic_memory/schemas/discovery.py,sha256=KtumdsujakYrl2rpX3bgIN-sK3826Cy_58nhq3vnl78,872
52
- basic_memory/schemas/memory.py,sha256=TPT1Lhsxk6Y1tuisx6XidcC2We_DdZxaNrvF2fidvNw,2909
53
- basic_memory/schemas/request.py,sha256=Cpz0cR5P-QdR9PAUapGfAxXhdooeVCH6X2G7MoOWMvw,2006
54
- basic_memory/schemas/response.py,sha256=7oWk3GDS626pdgN2MF__tp9c7WU-_9K7hs1F2quB65Y,6226
55
- basic_memory/schemas/search.py,sha256=7xlUc0HE13-v7iKy3eFs0IKasGbXVxCaq8GZ8qiUBTQ,3395
56
- basic_memory/services/__init__.py,sha256=5yx4U7iCi5gLjHxmkjeQ9JJoftWqy6P2gX2uV3ouMd0,279
57
- basic_memory/services/context_service.py,sha256=9DWryOhHfowelk4JVNIAlOycjblocTw38FSEP2kDkGI,8095
58
- basic_memory/services/database_service.py,sha256=WIyGEC4B8v5Z0_XdzkfVACBhtSmjn-ch0JbFzP8giOo,5665
59
- basic_memory/services/entity_service.py,sha256=Lh63SEt-PCwGgazMx-KIVz-oEsNqX1JC7ktWZtvrVWw,12594
60
- basic_memory/services/exceptions.py,sha256=Z9cizi05f7QBY4HX6c0ywfzKk0_sie3283CP7gzy-dY,287
61
- basic_memory/services/file_service.py,sha256=oiS33BhD5zs7YgF6vMAgAvBBkHiLbUJ6g2cvN2JwymA,7166
62
- basic_memory/services/link_resolver.py,sha256=0OiWN8_m2niVBi5oUNss5nRFqIUTa1Qe1LmH8-oY64Y,4492
63
- basic_memory/services/search_service.py,sha256=yLXYs-PNimELM_5E44O25-fbD4PDzISsAwCm2dNPyQI,7842
64
- basic_memory/services/service.py,sha256=oHsHKMTC2ojRsxeNdnC4nA5YdTL72VYjDzWI_dbmzyA,1134
65
- basic_memory/sync/__init__.py,sha256=5BzfbvY-DKi-gswcjNzVqtNj4I0yXZ82CaupFiPihws,138
66
- basic_memory/sync/file_change_scanner.py,sha256=x2xFaxCzPy5seNLqK-TcN106U2--UKvAR7qoBeq8M84,5919
67
- basic_memory/sync/sync_service.py,sha256=Her8oQxRXuQkxAK1f_EhN9uQXDIq_KRkBNX9PMucXdc,7229
68
- basic_memory/sync/utils.py,sha256=6P5-dvR5X-lA-BE3IZOzoC54uyiq9c_p9figRKaPq5E,2453
69
- basic_memory/sync/watch_service.py,sha256=HIronKujbBTbbosz0HAqLBLkP5IK3zH6gQKoTCrrA9o,6744
70
- basic_memory-0.1.1.dist-info/METADATA,sha256=4ooHFh_c3uKUWIeLJn5JuH5ICrzZ7DOBpHGhyzqxud8,7771
71
- basic_memory-0.1.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
72
- basic_memory-0.1.1.dist-info/entry_points.txt,sha256=IDQa_VmVTzmvMrpnjhEfM0S3F--XsVGEj3MpdJfuo-Q,59
73
- basic_memory-0.1.1.dist-info/licenses/LICENSE,sha256=hIahDEOTzuHCU5J2nd07LWwkLW7Hko4UFO__ffsvB-8,34523
74
- basic_memory-0.1.1.dist-info/RECORD,,