basic-memory 0.13.0b2__py3-none-any.whl → 0.13.0b4__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.

@@ -0,0 +1,104 @@
1
+ """project constraint fix
2
+
3
+ Revision ID: 647e7a75e2cd
4
+ Revises: 5fe1ab1ccebe
5
+ Create Date: 2025-06-03 12:48:30.162566
6
+
7
+ """
8
+
9
+ from typing import Sequence, Union
10
+
11
+ from alembic import op
12
+ import sqlalchemy as sa
13
+
14
+
15
+ # revision identifiers, used by Alembic.
16
+ revision: str = "647e7a75e2cd"
17
+ down_revision: Union[str, None] = "5fe1ab1ccebe"
18
+ branch_labels: Union[str, Sequence[str], None] = None
19
+ depends_on: Union[str, Sequence[str], None] = None
20
+
21
+
22
+ def upgrade() -> None:
23
+ """Remove the problematic UNIQUE constraint on is_default column.
24
+
25
+ The UNIQUE constraint prevents multiple projects from having is_default=FALSE,
26
+ which breaks project creation when the service sets is_default=False.
27
+
28
+ Since SQLite doesn't support dropping specific constraints easily, we'll
29
+ recreate the table without the problematic constraint.
30
+ """
31
+ # For SQLite, we need to recreate the table without the UNIQUE constraint
32
+ # Create a new table without the UNIQUE constraint on is_default
33
+ op.create_table(
34
+ "project_new",
35
+ sa.Column("id", sa.Integer(), nullable=False),
36
+ sa.Column("name", sa.String(), nullable=False),
37
+ sa.Column("description", sa.Text(), nullable=True),
38
+ sa.Column("permalink", sa.String(), nullable=False),
39
+ sa.Column("path", sa.String(), nullable=False),
40
+ sa.Column("is_active", sa.Boolean(), nullable=False),
41
+ sa.Column("is_default", sa.Boolean(), nullable=True), # No UNIQUE constraint!
42
+ sa.Column("created_at", sa.DateTime(), nullable=False),
43
+ sa.Column("updated_at", sa.DateTime(), nullable=False),
44
+ sa.PrimaryKeyConstraint("id"),
45
+ sa.UniqueConstraint("name"),
46
+ sa.UniqueConstraint("permalink"),
47
+ )
48
+
49
+ # Copy data from old table to new table
50
+ op.execute("INSERT INTO project_new SELECT * FROM project")
51
+
52
+ # Drop the old table
53
+ op.drop_table("project")
54
+
55
+ # Rename the new table
56
+ op.rename_table("project_new", "project")
57
+
58
+ # Recreate the indexes
59
+ with op.batch_alter_table("project", schema=None) as batch_op:
60
+ batch_op.create_index("ix_project_created_at", ["created_at"], unique=False)
61
+ batch_op.create_index("ix_project_name", ["name"], unique=True)
62
+ batch_op.create_index("ix_project_path", ["path"], unique=False)
63
+ batch_op.create_index("ix_project_permalink", ["permalink"], unique=True)
64
+ batch_op.create_index("ix_project_updated_at", ["updated_at"], unique=False)
65
+
66
+
67
+ def downgrade() -> None:
68
+ """Add back the UNIQUE constraint on is_default column.
69
+
70
+ WARNING: This will break project creation again if multiple projects
71
+ have is_default=FALSE.
72
+ """
73
+ # Recreate the table with the UNIQUE constraint
74
+ op.create_table(
75
+ "project_old",
76
+ sa.Column("id", sa.Integer(), nullable=False),
77
+ sa.Column("name", sa.String(), nullable=False),
78
+ sa.Column("description", sa.Text(), nullable=True),
79
+ sa.Column("permalink", sa.String(), nullable=False),
80
+ sa.Column("path", sa.String(), nullable=False),
81
+ sa.Column("is_active", sa.Boolean(), nullable=False),
82
+ sa.Column("is_default", sa.Boolean(), nullable=True),
83
+ sa.Column("created_at", sa.DateTime(), nullable=False),
84
+ sa.Column("updated_at", sa.DateTime(), nullable=False),
85
+ sa.PrimaryKeyConstraint("id"),
86
+ sa.UniqueConstraint("is_default"), # Add back the problematic constraint
87
+ sa.UniqueConstraint("name"),
88
+ sa.UniqueConstraint("permalink"),
89
+ )
90
+
91
+ # Copy data (this may fail if multiple FALSE values exist)
92
+ op.execute("INSERT INTO project_old SELECT * FROM project")
93
+
94
+ # Drop the current table and rename
95
+ op.drop_table("project")
96
+ op.rename_table("project_old", "project")
97
+
98
+ # Recreate indexes
99
+ with op.batch_alter_table("project", schema=None) as batch_op:
100
+ batch_op.create_index("ix_project_created_at", ["created_at"], unique=False)
101
+ batch_op.create_index("ix_project_name", ["name"], unique=True)
102
+ batch_op.create_index("ix_project_path", ["path"], unique=False)
103
+ batch_op.create_index("ix_project_permalink", ["permalink"], unique=True)
104
+ batch_op.create_index("ix_project_updated_at", ["updated_at"], unique=False)
@@ -57,7 +57,6 @@ def upgrade() -> None:
57
57
  """)
58
58
 
59
59
 
60
-
61
60
  def downgrade() -> None:
62
61
  """Downgrade database schema to use old search index."""
63
62
  # Drop the updated search_index table
@@ -274,4 +274,4 @@ async def delete_entities(
274
274
  background_tasks.add_task(search_service.delete_by_permalink, permalink)
275
275
 
276
276
  result = DeleteEntitiesResponse(deleted=deleted)
277
- return result
277
+ return result
@@ -111,10 +111,9 @@ async def add_project(
111
111
  Response confirming the project was added
112
112
  """
113
113
  try: # pragma: no cover
114
- await project_service.add_project(project_data.name, project_data.path)
115
-
116
- if project_data.set_default: # pragma: no cover
117
- await project_service.set_default_project(project_data.name)
114
+ await project_service.add_project(
115
+ project_data.name, project_data.path, set_default=project_data.set_default
116
+ )
118
117
 
119
118
  return ProjectStatusResponse( # pyright: ignore [reportCallIssue]
120
119
  message=f"Project '{project_data.name}' added successfully",
@@ -145,7 +144,9 @@ async def remove_project(
145
144
  try:
146
145
  old_project = await project_service.get_project(name)
147
146
  if not old_project: # pragma: no cover
148
- raise HTTPException(status_code=404, detail=f"Project: '{name}' does not exist") # pragma: no cover
147
+ raise HTTPException(
148
+ status_code=404, detail=f"Project: '{name}' does not exist"
149
+ ) # pragma: no cover
149
150
 
150
151
  await project_service.remove_project(name)
151
152
 
@@ -186,7 +187,9 @@ async def set_default_project(
186
187
  # get the new project
187
188
  new_default_project = await project_service.get_project(name)
188
189
  if not new_default_project: # pragma: no cover
189
- raise HTTPException(status_code=404, detail=f"Project: '{name}' does not exist") # pragma: no cover
190
+ raise HTTPException(
191
+ status_code=404, detail=f"Project: '{name}' does not exist"
192
+ ) # pragma: no cover
190
193
 
191
194
  await project_service.set_default_project(name)
192
195
 
basic_memory/config.py CHANGED
@@ -179,7 +179,7 @@ class ConfigManager:
179
179
 
180
180
  def save_config(self, config: BasicMemoryConfig) -> None:
181
181
  """Save configuration to file."""
182
- try:
182
+ try:
183
183
  self.config_file.write_text(json.dumps(config.model_dump(), indent=2))
184
184
  except Exception as e: # pragma: no cover
185
185
  logger.error(f"Failed to save config: {e}")
@@ -106,6 +106,5 @@ auth_settings, auth_provider = create_auth_config()
106
106
  mcp = FastMCP(
107
107
  name="Basic Memory",
108
108
  log_level="DEBUG",
109
- auth_server_provider=auth_provider,
110
- auth=auth_settings,
109
+ auth=auth_provider,
111
110
  )
@@ -31,7 +31,7 @@ async def move_note(
31
31
 
32
32
  Examples:
33
33
  - Move to new folder: move_note("My Note", "work/notes/my-note.md")
34
- - Move by permalink: move_note("my-note-permalink", "archive/old-notes/my-note.md")
34
+ - Move by permalink: move_note("my-note-permalink", "archive/old-notes/my-note.md")
35
35
  - Specify project: move_note("My Note", "archive/my-note.md", project="work-project")
36
36
 
37
37
  Note: This operation moves notes within the specified project only. Moving notes
@@ -49,9 +49,7 @@ class Project(Base):
49
49
 
50
50
  # Status flags
51
51
  is_active: Mapped[bool] = mapped_column(Boolean, default=True)
52
- is_default: Mapped[Optional[bool]] = mapped_column(
53
- Boolean, default=None, unique=True, nullable=True
54
- )
52
+ is_default: Mapped[Optional[bool]] = mapped_column(Boolean, default=None, nullable=True)
55
53
 
56
54
  # Timestamps
57
55
  created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
@@ -22,6 +22,7 @@ from basic_memory.config import WATCH_STATUS_JSON
22
22
  from basic_memory.utils import generate_permalink
23
23
  from basic_memory.config import config_manager
24
24
 
25
+
25
26
  class ProjectService:
26
27
  """Service for managing Basic Memory projects."""
27
28
 
@@ -66,12 +67,13 @@ class ProjectService:
66
67
  """Get the file path for a project by name."""
67
68
  return await self.repository.get_by_name(name)
68
69
 
69
- async def add_project(self, name: str, path: str) -> None:
70
+ async def add_project(self, name: str, path: str, set_default: bool = False) -> None:
70
71
  """Add a new project to the configuration and database.
71
72
 
72
73
  Args:
73
74
  name: The name of the project
74
75
  path: The file path to the project directory
76
+ set_default: Whether to set this project as the default
75
77
 
76
78
  Raises:
77
79
  ValueError: If the project already exists
@@ -91,9 +93,16 @@ class ProjectService:
91
93
  "path": resolved_path,
92
94
  "permalink": generate_permalink(project_config.name),
93
95
  "is_active": True,
94
- "is_default": False,
96
+ # Don't set is_default=False to avoid UNIQUE constraint issues
97
+ # Let it default to NULL, only set to True when explicitly making default
95
98
  }
96
- await self.repository.create(project_data)
99
+ created_project = await self.repository.create(project_data)
100
+
101
+ # If this should be the default project, ensure only one default exists
102
+ if set_default:
103
+ await self.repository.set_as_default(created_project.id)
104
+ config_manager.set_default_project(name)
105
+ logger.info(f"Project '{name}' set as default")
97
106
 
98
107
  logger.info(f"Project '{name}' added at {resolved_path}")
99
108
 
@@ -143,6 +152,45 @@ class ProjectService:
143
152
 
144
153
  logger.info(f"Project '{name}' set as default in configuration and database")
145
154
 
155
+ async def _ensure_single_default_project(self) -> None:
156
+ """Ensure only one project has is_default=True.
157
+
158
+ This method validates the database state and fixes any issues where
159
+ multiple projects might have is_default=True or no project is marked as default.
160
+ """
161
+ if not self.repository:
162
+ raise ValueError("Repository is required for _ensure_single_default_project") # pragma: no cover
163
+
164
+ # Get all projects with is_default=True
165
+ db_projects = await self.repository.find_all()
166
+ default_projects = [p for p in db_projects if p.is_default is True]
167
+
168
+ if len(default_projects) > 1: # pragma: no cover
169
+ # Multiple defaults found - fix by keeping the first one and clearing others
170
+ # This is defensive code that should rarely execute due to business logic enforcement
171
+ logger.warning( # pragma: no cover
172
+ f"Found {len(default_projects)} projects with is_default=True, fixing..."
173
+ )
174
+ keep_default = default_projects[0] # pragma: no cover
175
+
176
+ # Clear all defaults first, then set only the first one as default
177
+ await self.repository.set_as_default(keep_default.id) # pragma: no cover
178
+
179
+ logger.info(
180
+ f"Fixed default project conflicts, kept '{keep_default.name}' as default"
181
+ ) # pragma: no cover
182
+
183
+ elif len(default_projects) == 0: # pragma: no cover
184
+ # No default project - set the config default as default
185
+ # This is defensive code for edge cases where no default exists
186
+ config_default = config_manager.default_project # pragma: no cover
187
+ config_project = await self.repository.get_by_name(config_default) # pragma: no cover
188
+ if config_project: # pragma: no cover
189
+ await self.repository.set_as_default(config_project.id) # pragma: no cover
190
+ logger.info(
191
+ f"Set '{config_default}' as default project (was missing)"
192
+ ) # pragma: no cover
193
+
146
194
  async def synchronize_projects(self) -> None: # pragma: no cover
147
195
  """Synchronize projects between database and configuration.
148
196
 
@@ -171,7 +219,7 @@ class ProjectService:
171
219
  "path": path,
172
220
  "permalink": name.lower().replace(" ", "-"),
173
221
  "is_active": True,
174
- "is_default": (name == config_manager.default_project),
222
+ # Don't set is_default here - let the enforcement logic handle it
175
223
  }
176
224
  await self.repository.create(project_data)
177
225
 
@@ -181,19 +229,23 @@ class ProjectService:
181
229
  logger.info(f"Adding project '{name}' to configuration")
182
230
  config_manager.add_project(name, project.path)
183
231
 
184
- # Make sure default project is synchronized
185
- db_default = next((p for p in db_projects if p.is_default), None)
232
+ # Ensure database default project state is consistent
233
+ await self._ensure_single_default_project()
234
+
235
+ # Make sure default project is synchronized between config and database
236
+ db_default = await self.repository.get_default_project()
186
237
  config_default = config_manager.default_project
187
238
 
188
239
  if db_default and db_default.name != config_default:
189
240
  # Update config to match DB default
190
241
  logger.info(f"Updating default project in config to '{db_default.name}'")
191
242
  config_manager.set_default_project(db_default.name)
192
- elif not db_default and config_default in db_projects_by_name:
193
- # Update DB to match config default
194
- logger.info(f"Updating default project in database to '{config_default}'")
195
- project = db_projects_by_name[config_default]
196
- await self.repository.set_as_default(project.id)
243
+ elif not db_default and config_default:
244
+ # Update DB to match config default (if the project exists)
245
+ project = await self.repository.get_by_name(config_default)
246
+ if project:
247
+ logger.info(f"Updating default project in database to '{config_default}'")
248
+ await self.repository.set_as_default(project.id)
197
249
 
198
250
  logger.info("Project synchronization complete")
199
251
 
@@ -148,7 +148,7 @@ class SearchService:
148
148
  # If parsing fails, treat as single tag
149
149
  return [tags] if tags.strip() else []
150
150
 
151
- return [] # pragma: no cover
151
+ return [] # pragma: no cover
152
152
 
153
153
  async def index_entity(
154
154
  self,
@@ -379,7 +379,9 @@ class SyncService:
379
379
  updates = {"file_path": new_path}
380
380
 
381
381
  # If configured, also update permalink to match new path
382
- if self.app_config.update_permalinks_on_move and self.file_service.is_markdown(new_path):
382
+ if self.app_config.update_permalinks_on_move and self.file_service.is_markdown(
383
+ new_path
384
+ ):
383
385
  # generate new permalink value
384
386
  new_permalink = await self.entity_service.resolve_permalink(new_path)
385
387
 
@@ -505,4 +507,4 @@ class SyncService:
505
507
  f"duration_ms={duration_ms}"
506
508
  )
507
509
 
508
- return result
510
+ return result
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: basic-memory
3
- Version: 0.13.0b2
3
+ Version: 0.13.0b4
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
@@ -1,5 +1,5 @@
1
1
  basic_memory/__init__.py,sha256=4JBLRdCwrUwNtv3qPAFmcDiktOIhvAF8hgT-Ku5RL1U,342
2
- basic_memory/config.py,sha256=b9_vlE22BByafE-10h3bpeoEyGCn_9yYHfMoei06haI,11113
2
+ basic_memory/config.py,sha256=lNpbn-b1k9nunQ-htciYQHC8XatRIhc_m6SN2Pbvp-E,11101
3
3
  basic_memory/db.py,sha256=X4-uyEZdJXVLfFDTpcNZxWzawRZXhDdKoEFWAGgE4Lk,6193
4
4
  basic_memory/deps.py,sha256=zXOhqXCoSVIa1iIcO8U6uUiofJn5eT4ycwJkH9I2kX4,12102
5
5
  basic_memory/file_utils.py,sha256=eaxTKLLEbTIy_Mb_Iv_Dmt4IXAJSrZGVi-Knrpyci3E,6700
@@ -11,18 +11,19 @@ basic_memory/alembic/script.py.mako,sha256=MEqL-2qATlST9TAOeYgscMn1uy6HUS9NFvDgl
11
11
  basic_memory/alembic/versions/3dae7c7b1564_initial_schema.py,sha256=lTbWlAnd1es7xU99DoJgfaRe1_Kte8TL98riqeKGV80,4363
12
12
  basic_memory/alembic/versions/502b60eaa905_remove_required_from_entity_permalink.py,sha256=k6xYTmYPM9Ros-7CA7BwZBKYwoK_gmVdC-2n8FAjdoE,1840
13
13
  basic_memory/alembic/versions/5fe1ab1ccebe_add_projects_table.py,sha256=2CCY9ayjzbraYMcinqSsJi9Sc0nu2e-ehkUJus-sz34,4379
14
+ basic_memory/alembic/versions/647e7a75e2cd_project_constraint_fix.py,sha256=YErFkIpZdicvUil4ZtE6uxSpk5BZCTXZ_TfPE-MgSfo,4210
14
15
  basic_memory/alembic/versions/b3c3938bacdb_relation_to_name_unique_index.py,sha256=RsGymQzfRXV1LSNKiyi0lMilTxW1NgwS9jR67ye2apI,1428
15
- basic_memory/alembic/versions/cc7172b46608_update_search_index_schema.py,sha256=QfMZnylSWpagAxK4vTI8eIcjk_FLkX5mpBTjhl_KPgU,3680
16
+ basic_memory/alembic/versions/cc7172b46608_update_search_index_schema.py,sha256=kDavR9Qqx9wSu5P3qd4SZq_waIsDG1UMTg2SmDoktMU,3679
16
17
  basic_memory/api/__init__.py,sha256=wCpj-21j1D0KzKl9Ql6unLBVFY0K1uGp_FeSZRKtqpk,72
17
18
  basic_memory/api/app.py,sha256=ucV1epIVQ210JFdZIs6aZ_UWK8TG78p_NhGf6WOrFk0,2809
18
19
  basic_memory/api/template_loader.py,sha256=exbTeXyJRgyLFmSjNeroxjT7X2DWFm2X5qUVa3drbYM,8607
19
20
  basic_memory/api/routers/__init__.py,sha256=REO5CKQ96o5vtGWACcsIxIpWybIUSeKXc83RWbWc8BQ,398
20
21
  basic_memory/api/routers/directory_router.py,sha256=rBQHvuwffUOk0iKvcEs2QlWclgvr8ur24f_pH3-sVRQ,2054
21
22
  basic_memory/api/routers/importer_router.py,sha256=xFUCorkPWo8AF0ya0UrcLmXNf8CjPZdAqddQIH8PO-o,4513
22
- basic_memory/api/routers/knowledge_router.py,sha256=7Mu7KNK1gVuNwN7GBDSMQj9RjGK1Y60JDwMCHkn_syY,9132
23
+ basic_memory/api/routers/knowledge_router.py,sha256=sdRGWqBmAjELkJ7ZXyZB6qTU1CVH4EXpKOyDDVGV4yU,9133
23
24
  basic_memory/api/routers/management_router.py,sha256=INT5PzUXhfBH2546CTZKqZnRuECYIA4Ypfgdf6JNyu0,2686
24
25
  basic_memory/api/routers/memory_router.py,sha256=M344_tHIFzgi-i5PqltaPHdZaut_bMejqktmzLKto0c,2995
25
- basic_memory/api/routers/project_router.py,sha256=Pe_PdI2fFNxoKyg1wJV6BLxn5U5ql2AcXgCQesls_b0,8186
26
+ basic_memory/api/routers/project_router.py,sha256=ZlKcrA7lThWcm7-IdFMBtxMMd7IoV03GRfSH1zVs5Ug,8175
26
27
  basic_memory/api/routers/prompt_router.py,sha256=LzZAerGtDLPdyTKjThQciVGPUkjbIc3dmdJHX-ievSo,9913
27
28
  basic_memory/api/routers/resource_router.py,sha256=WEJEqEaY_yTKj5-U-rW4kXQKUcJflykgwI6_g_R41ck,8058
28
29
  basic_memory/api/routers/search_router.py,sha256=GD62jlCQTiL_VNsdibi-b1f6H40KCWo9SX2Cl7YH4QU,1226
@@ -60,7 +61,7 @@ basic_memory/mcp/async_client.py,sha256=Eo345wANiBRSM4u3j_Vd6Ax4YtMg7qbWd9PIoFfj
60
61
  basic_memory/mcp/auth_provider.py,sha256=CTydkEBvxh_fg_Z0hxKjTT8nHJoFhxrwp5hTQuToiIU,9977
61
62
  basic_memory/mcp/external_auth_provider.py,sha256=Z1GDbr6P4C-flZVHMWkIqAu30kcfeHv2iSp0EYbFuxo,11483
62
63
  basic_memory/mcp/project_session.py,sha256=OP1X10iG4wIWHgfkwC2q7Inl6b68zrioqkD1-Ju_S6w,3462
63
- basic_memory/mcp/server.py,sha256=xiu7KxJNDzhvninTzSDOicfZtchGcp4CYQ7ReVPJ-08,3705
64
+ basic_memory/mcp/server.py,sha256=2J6uWnpsGFnrlp8G6XlUknhjpD72vFI8nP5OLPw3H28,3665
64
65
  basic_memory/mcp/supabase_auth_provider.py,sha256=MLHfSHjdx2Q5jr_Ljx0qZBaOwp7CkPdk_ybR_LQ7Mvw,16472
65
66
  basic_memory/mcp/prompts/__init__.py,sha256=-Bl9Dgj2TD9PULjzggPqXuvPEjWCRy7S9Yg03h2-U7A,615
66
67
  basic_memory/mcp/prompts/ai_assistant_guide.py,sha256=8TI5xObiRVcwv6w9by1xQHlX0whvyE7-LGsiqDMRTFg,821
@@ -76,7 +77,7 @@ basic_memory/mcp/tools/canvas.py,sha256=KFbwRAWtr31wLjRgeYyvIDLYRGs1Qs_hHhY_WWuD
76
77
  basic_memory/mcp/tools/delete_note.py,sha256=mDX7JxmzMzXyRaY0-fKyLiGf2czM51Kxz2ACX-dyrNU,1270
77
78
  basic_memory/mcp/tools/edit_note.py,sha256=VG1pbB50cm70FTevspAkfDxCj-gs_YbdtPqhHS2i_xA,13025
78
79
  basic_memory/mcp/tools/list_directory.py,sha256=-FxDsCru5YD02M4qkQDAurEJWyRaC7YI4YR6zg0atR8,5236
79
- basic_memory/mcp/tools/move_note.py,sha256=60kF_OSmAr2CyrEt_tIzePWFinzBJaanusn0Jmm6lUc,2886
80
+ basic_memory/mcp/tools/move_note.py,sha256=oZ83EtKmi5bs8usN2ydc-l_PG1hIXmt86QK4-cSZs6M,2885
80
81
  basic_memory/mcp/tools/project_management.py,sha256=wMmiGy_n7VGhwKmRpoBMU-z-2NYJouNdvBmujTGkV3w,10952
81
82
  basic_memory/mcp/tools/read_content.py,sha256=4FTw13B8UjVVhR78NJB9HKeJb_nA6-BGT1WdGtekN5Q,8596
82
83
  basic_memory/mcp/tools/read_note.py,sha256=Q2z_9dEoR3lq4v_NKyMyZAW-SP4LUgi1b6kWrYEanQ4,6944
@@ -87,7 +88,7 @@ basic_memory/mcp/tools/write_note.py,sha256=yGPb9HGB5BFnjBD1lFNsZ7wF4ItY2nOxaE05
87
88
  basic_memory/models/__init__.py,sha256=j0C4dtFi-FOEaQKR8dQWEG-dJtdQ15NBTiJg4nbIXNU,333
88
89
  basic_memory/models/base.py,sha256=4hAXJ8CE1RnjKhb23lPd-QM7G_FXIdTowMJ9bRixspU,225
89
90
  basic_memory/models/knowledge.py,sha256=AFxfKS8fRa43Kq3EjJCAufpte4VNC7fs9YfshDrB4o0,7087
90
- basic_memory/models/project.py,sha256=S3PvS2o8dFLOo8qiSdI12CG29dTvHw2JIpYJLZ0UFmg,2800
91
+ basic_memory/models/project.py,sha256=oUrQaUOu7_muSl-i38Dh0HzmCFrMAtwgxALDUTt9k5c,2773
91
92
  basic_memory/models/search.py,sha256=PhQ8w4taApSvjh1DpPhB4cH9GTt2E2po-DFZzhnoZkY,1300
92
93
  basic_memory/repository/__init__.py,sha256=MWK-o8QikqzOpe5SyPbKQ2ioB5BWA0Upz65tgg-E0DU,327
93
94
  basic_memory/repository/entity_repository.py,sha256=larjP7r6Sc7YyPD1BloC_m96McYsjHTf6doUQy3gSY4,3776
@@ -116,17 +117,17 @@ basic_memory/services/exceptions.py,sha256=oVjQr50XQqnFq1-MNKBilI2ShtHDxypavyDk1
116
117
  basic_memory/services/file_service.py,sha256=jCrmnEkTQ4t9HF7L_M6BL7tdDqjjzty9hpTo9AzwhvM,10059
117
118
  basic_memory/services/initialization.py,sha256=1sPz0dAsFVJOaiWBG6FgxKmwLNrMtBrmX4I4qVTI0aY,7786
118
119
  basic_memory/services/link_resolver.py,sha256=8KgozYS8reQaihzDMS8_0tDKo-BdqHjhECIM39I_wis,4078
119
- basic_memory/services/project_service.py,sha256=9cg2wwDF6QNEi5ZL0HmqgTaYJf5mLb2PCl2fwebpZ74,20518
120
- basic_memory/services/search_service.py,sha256=KoIZ1RYW7-L9wr1Saplh-j6Ds21LZQkgf4wqjtZmfm0,12782
120
+ basic_memory/services/project_service.py,sha256=mntHwPwypgec45vsB5ASzTybA_UGAf4lA9cRKw4sl8E,23310
121
+ basic_memory/services/search_service.py,sha256=c5Ky0ufz7YPFgHhVzNRQ4OecF_JUrt7nALzpMjobW4M,12782
121
122
  basic_memory/services/service.py,sha256=V-d_8gOV07zGIQDpL-Ksqs3ZN9l3qf3HZOK1f_YNTag,336
122
123
  basic_memory/sync/__init__.py,sha256=CVHguYH457h2u2xoM8KvOilJC71XJlZ-qUh8lHcjYj4,156
123
124
  basic_memory/sync/background_sync.py,sha256=4CEx8oP6-qD33uCeowhpzhA8wivmWxaCmSBP37h3Fs8,714
124
- basic_memory/sync/sync_service.py,sha256=1uZRs2ohN7RHsMlA3rA8V-bqsk9xDk53AFtc7NFP92E,19802
125
+ basic_memory/sync/sync_service.py,sha256=7ccn4_YWcmC9VSEgm6diosRAibn4LxBS3lWb8vcTaoQ,19833
125
126
  basic_memory/sync/watch_service.py,sha256=JAumrHUjV1lF9NtEK32jgg0myWBfLXotNXxONeIV9SM,15316
126
127
  basic_memory/templates/prompts/continue_conversation.hbs,sha256=begMFHOPN3aCm5sHz5PlKMLOfZ8hlpFxFJ-hgy0T9K4,3075
127
128
  basic_memory/templates/prompts/search.hbs,sha256=H1cCIsHKp4VC1GrH2KeUB8pGe5vXFPqb2VPotypmeCA,3098
128
- basic_memory-0.13.0b2.dist-info/METADATA,sha256=cnjgVfE8jbAiAPfnsMQ7pZCMkjKg3F2raQU6CZe_IOs,15468
129
- basic_memory-0.13.0b2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
130
- basic_memory-0.13.0b2.dist-info/entry_points.txt,sha256=wvE2mRF6-Pg4weIYcfQ-86NOLZD4WJg7F7TIsRVFLb8,90
131
- basic_memory-0.13.0b2.dist-info/licenses/LICENSE,sha256=hIahDEOTzuHCU5J2nd07LWwkLW7Hko4UFO__ffsvB-8,34523
132
- basic_memory-0.13.0b2.dist-info/RECORD,,
129
+ basic_memory-0.13.0b4.dist-info/METADATA,sha256=Anht8NA7a-vnCuyqZQfv1quuEHqerGWwg26uegkhUZo,15468
130
+ basic_memory-0.13.0b4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
131
+ basic_memory-0.13.0b4.dist-info/entry_points.txt,sha256=wvE2mRF6-Pg4weIYcfQ-86NOLZD4WJg7F7TIsRVFLb8,90
132
+ basic_memory-0.13.0b4.dist-info/licenses/LICENSE,sha256=hIahDEOTzuHCU5J2nd07LWwkLW7Hko4UFO__ffsvB-8,34523
133
+ basic_memory-0.13.0b4.dist-info/RECORD,,