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

basic_memory/__init__.py CHANGED
@@ -1,4 +1,7 @@
1
1
  """basic-memory - Local-first knowledge management combining Zettelkasten with knowledge graphs"""
2
2
 
3
+ # Package version - updated by release automation
4
+ __version__ = "0.13.2"
5
+
3
6
  # API version for FastAPI - independent of package version
4
- __version__ = "v0"
7
+ __api_version__ = "v0"
@@ -9,7 +9,6 @@ from rich.console import Console
9
9
  from rich.table import Table
10
10
 
11
11
  from basic_memory.cli.app import app
12
- from basic_memory.config import config
13
12
  from basic_memory.mcp.project_session import session
14
13
  from basic_memory.mcp.resources.project_info import project_info
15
14
  import json
@@ -24,6 +23,7 @@ from basic_memory.mcp.tools.utils import call_post
24
23
  from basic_memory.schemas.project_info import ProjectStatusResponse
25
24
  from basic_memory.mcp.tools.utils import call_delete
26
25
  from basic_memory.mcp.tools.utils import call_put
26
+ from basic_memory.utils import generate_permalink
27
27
 
28
28
  console = Console()
29
29
 
@@ -44,11 +44,8 @@ def format_path(path: str) -> str:
44
44
  def list_projects() -> None:
45
45
  """List all configured projects."""
46
46
  # Use API to list projects
47
-
48
- project_url = config.project_url
49
-
50
47
  try:
51
- response = asyncio.run(call_get(client, f"{project_url}/project/projects"))
48
+ response = asyncio.run(call_get(client, "/projects/projects"))
52
49
  result = ProjectList.model_validate(response.json())
53
50
 
54
51
  table = Table(title="Basic Memory Projects")
@@ -65,7 +62,6 @@ def list_projects() -> None:
65
62
  console.print(table)
66
63
  except Exception as e:
67
64
  console.print(f"[red]Error listing projects: {str(e)}[/red]")
68
- console.print("[yellow]Note: Make sure the Basic Memory server is running.[/yellow]")
69
65
  raise typer.Exit(1)
70
66
 
71
67
 
@@ -80,16 +76,14 @@ def add_project(
80
76
  resolved_path = os.path.abspath(os.path.expanduser(path))
81
77
 
82
78
  try:
83
- project_url = config.project_url
84
79
  data = {"name": name, "path": resolved_path, "set_default": set_default}
85
80
 
86
- response = asyncio.run(call_post(client, f"{project_url}/project/projects", json=data))
81
+ response = asyncio.run(call_post(client, "/projects/projects", json=data))
87
82
  result = ProjectStatusResponse.model_validate(response.json())
88
83
 
89
84
  console.print(f"[green]{result.message}[/green]")
90
85
  except Exception as e:
91
86
  console.print(f"[red]Error adding project: {str(e)}[/red]")
92
- console.print("[yellow]Note: Make sure the Basic Memory server is running.[/yellow]")
93
87
  raise typer.Exit(1)
94
88
 
95
89
  # Display usage hint
@@ -105,15 +99,13 @@ def remove_project(
105
99
  ) -> None:
106
100
  """Remove a project from configuration."""
107
101
  try:
108
- project_url = config.project_url
109
-
110
- response = asyncio.run(call_delete(client, f"{project_url}/project/projects/{name}"))
102
+ project_name = generate_permalink(name)
103
+ response = asyncio.run(call_delete(client, f"/projects/{project_name}"))
111
104
  result = ProjectStatusResponse.model_validate(response.json())
112
105
 
113
106
  console.print(f"[green]{result.message}[/green]")
114
107
  except Exception as e:
115
108
  console.print(f"[red]Error removing project: {str(e)}[/red]")
116
- console.print("[yellow]Note: Make sure the Basic Memory server is running.[/yellow]")
117
109
  raise typer.Exit(1)
118
110
 
119
111
  # Show this message regardless of method used
@@ -126,20 +118,16 @@ def set_default_project(
126
118
  ) -> None:
127
119
  """Set the default project and activate it for the current session."""
128
120
  try:
129
- project_url = config.project_url
121
+ project_name = generate_permalink(name)
130
122
 
131
- response = asyncio.run(call_put(client, f"{project_url}/project/projects/{name}/default"))
123
+ response = asyncio.run(call_put(client, f"projects/{project_name}/default"))
132
124
  result = ProjectStatusResponse.model_validate(response.json())
133
125
 
134
126
  console.print(f"[green]{result.message}[/green]")
135
127
  except Exception as e:
136
128
  console.print(f"[red]Error setting default project: {str(e)}[/red]")
137
- console.print("[yellow]Note: Make sure the Basic Memory server is running.[/yellow]")
138
129
  raise typer.Exit(1)
139
130
 
140
- # Always activate it for the current session
141
- os.environ["BASIC_MEMORY_PROJECT"] = name
142
-
143
131
  # Reload configuration to apply the change
144
132
  from importlib import reload
145
133
  from basic_memory import config as config_module
@@ -149,21 +137,18 @@ def set_default_project(
149
137
  console.print("[green]Project activated for current session[/green]")
150
138
 
151
139
 
152
- @project_app.command("sync")
140
+ @project_app.command("sync-config")
153
141
  def synchronize_projects() -> None:
154
- """Synchronize projects between configuration file and database."""
142
+ """Synchronize project config between configuration file and database."""
155
143
  # Call the API to synchronize projects
156
144
 
157
- project_url = config.project_url
158
-
159
145
  try:
160
- response = asyncio.run(call_post(client, f"{project_url}/project/sync"))
146
+ response = asyncio.run(call_post(client, "/projects/sync"))
161
147
  result = ProjectStatusResponse.model_validate(response.json())
162
148
 
163
149
  console.print(f"[green]{result.message}[/green]")
164
150
  except Exception as e: # pragma: no cover
165
151
  console.print(f"[red]Error synchronizing projects: {str(e)}[/red]")
166
- console.print("[yellow]Note: Make sure the Basic Memory server is running.[/yellow]")
167
152
  raise typer.Exit(1)
168
153
 
169
154
 
@@ -16,6 +16,7 @@ from basic_memory.mcp.server import mcp
16
16
  from basic_memory.mcp.tools.utils import call_get, call_put, call_post, call_delete
17
17
  from basic_memory.schemas import ProjectInfoResponse
18
18
  from basic_memory.schemas.project_info import ProjectList, ProjectStatusResponse, ProjectInfoRequest
19
+ from basic_memory.utils import generate_permalink
19
20
 
20
21
 
21
22
  @mcp.tool()
@@ -77,6 +78,7 @@ async def switch_project(project_name: str, ctx: Context | None = None) -> str:
77
78
  if ctx: # pragma: no cover
78
79
  await ctx.info(f"Switching to project: {project_name}")
79
80
 
81
+ project_permalink = generate_permalink(project_name)
80
82
  current_project = session.get_current_project()
81
83
  try:
82
84
  # Validate project exists by getting project list
@@ -84,13 +86,13 @@ async def switch_project(project_name: str, ctx: Context | None = None) -> str:
84
86
  project_list = ProjectList.model_validate(response.json())
85
87
 
86
88
  # Check if project exists
87
- project_exists = any(p.name == project_name for p in project_list.projects)
89
+ project_exists = any(p.permalink == project_permalink for p in project_list.projects)
88
90
  if not project_exists:
89
91
  available_projects = [p.name for p in project_list.projects]
90
92
  return f"Error: Project '{project_name}' not found. Available projects: {', '.join(available_projects)}"
91
93
 
92
94
  # Switch to the project
93
- session.set_current_project(project_name)
95
+ session.set_current_project(project_permalink)
94
96
  current_project = session.get_current_project()
95
97
  project_config = get_project_config(current_project)
96
98
 
@@ -99,11 +101,11 @@ async def switch_project(project_name: str, ctx: Context | None = None) -> str:
99
101
  response = await call_get(
100
102
  client,
101
103
  f"{project_config.project_url}/project/info",
102
- params={"project_name": project_name},
104
+ params={"project_name": project_permalink},
103
105
  )
104
106
  project_info = ProjectInfoResponse.model_validate(response.json())
105
107
 
106
- result = f"✓ Switched to {project_name} project\n\n"
108
+ result = f"✓ Switched to {project_permalink} project\n\n"
107
109
  result += "Project Summary:\n"
108
110
  result += f"• {project_info.statistics.total_entities} entities\n"
109
111
  result += f"• {project_info.statistics.total_observations} observations\n"
@@ -329,4 +331,4 @@ async def delete_project(project_name: str, ctx: Context | None = None) -> str:
329
331
  result += "Files remain on disk but project is no longer tracked by Basic Memory.\n"
330
332
  result += "Re-add the project to access its content again.\n"
331
333
 
332
- return add_project_metadata(result, session.get_current_project())
334
+ return add_project_metadata(result, session.get_current_project())
@@ -6,6 +6,8 @@ from typing import Dict, List, Optional, Any
6
6
 
7
7
  from pydantic import Field, BaseModel
8
8
 
9
+ from basic_memory.utils import generate_permalink
10
+
9
11
 
10
12
  class ProjectStatistics(BaseModel):
11
13
  """Statistics about the current project."""
@@ -183,6 +185,10 @@ class ProjectItem(BaseModel):
183
185
  name: str
184
186
  path: str
185
187
  is_default: bool = False
188
+
189
+ @property
190
+ def permalink(self) -> str: # pragma: no cover
191
+ return generate_permalink(self.name)
186
192
 
187
193
 
188
194
  class ProjectList(BaseModel):
@@ -207,7 +207,7 @@ class ProjectService:
207
207
 
208
208
  # Get all projects from database
209
209
  db_projects = await self.repository.get_active_projects()
210
- db_projects_by_name = {p.name: p for p in db_projects}
210
+ db_projects_by_permalink = {p.permalink: p for p in db_projects}
211
211
 
212
212
  # Get all projects from configuration and normalize names if needed
213
213
  config_projects = config_manager.projects.copy()
@@ -235,7 +235,7 @@ class ProjectService:
235
235
 
236
236
  # Add projects that exist in config but not in DB
237
237
  for name, path in config_projects.items():
238
- if name not in db_projects_by_name:
238
+ if name not in db_projects_by_permalink:
239
239
  logger.info(f"Adding project '{name}' to database")
240
240
  project_data = {
241
241
  "name": name,
@@ -247,7 +247,7 @@ class ProjectService:
247
247
  await self.repository.create(project_data)
248
248
 
249
249
  # Add projects that exist in DB but not in config to config
250
- for name, project in db_projects_by_name.items():
250
+ for name, project in db_projects_by_permalink.items():
251
251
  if name not in config_projects:
252
252
  logger.info(f"Adding project '{name}' to configuration")
253
253
  config_manager.add_project(name, project.path)
@@ -668,4 +668,4 @@ class ProjectService:
668
668
  database_size=db_size_readable,
669
669
  watch_status=watch_status,
670
670
  timestamp=datetime.now(),
671
- )
671
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: basic-memory
3
- Version: 0.13.0b6
3
+ Version: 0.13.2
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,4 +1,4 @@
1
- basic_memory/__init__.py,sha256=kYTgbNYjpTOTrVbmkdvP8eII6KD0j3qf2LgF-q01dQQ,178
1
+ basic_memory/__init__.py,sha256=s4xkAkIj-yvZFc_ImULxCYGhhrih4z5rAGrb5c81sqc,256
2
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
@@ -39,7 +39,7 @@ basic_memory/cli/commands/import_claude_conversations.py,sha256=sXnP0hjfwUapwHQD
39
39
  basic_memory/cli/commands/import_claude_projects.py,sha256=mWYIeA-mu_Pq23R7OEtY2XHXG5CAh1dMGIBhckB4zRk,2811
40
40
  basic_memory/cli/commands/import_memory_json.py,sha256=Vz5rt7KCel5B3Dtv57WPEUJTHCMwFUqQlOCm2djwUi8,2867
41
41
  basic_memory/cli/commands/mcp.py,sha256=jmRUv1U5FT3AQ1cDbvTfAUnjhBw6UsNEmIkpbNr-_qQ,3093
42
- basic_memory/cli/commands/project.py,sha256=YkVYcjxQOVhxIX1M0g_vMaP5dTinYvSnUQIjeOPg8HE,12971
42
+ basic_memory/cli/commands/project.py,sha256=MqRxfIvPJ7BD823gXXeEC0sEMutIdKVsoTMC2XCka94,12258
43
43
  basic_memory/cli/commands/status.py,sha256=708EK8-iPjyc1iE5MPECzAyZraGYoGpvYjLwTm-BlQs,5719
44
44
  basic_memory/cli/commands/sync.py,sha256=gOU_onrMj9_IRiIe8FWU_FLEvfjcOt-qhrvvFJuU-ws,8010
45
45
  basic_memory/cli/commands/tool.py,sha256=my-kALn3khv1W2Avi736NrHsfkpbyP57mDi5LjHwqe0,9540
@@ -79,7 +79,7 @@ basic_memory/mcp/tools/delete_note.py,sha256=tSyRc_VgBmLyVeenClwX1Sk--LKcGahAMzT
79
79
  basic_memory/mcp/tools/edit_note.py,sha256=q4x-f7-j_l-wzm17-AVFT1_WGCo0Cq4lI3seYSe21aY,13570
80
80
  basic_memory/mcp/tools/list_directory.py,sha256=-FxDsCru5YD02M4qkQDAurEJWyRaC7YI4YR6zg0atR8,5236
81
81
  basic_memory/mcp/tools/move_note.py,sha256=esnbddG2OcmIgRNuQwx5OhlwZ1CWcOheg3hUobsEcq0,11320
82
- basic_memory/mcp/tools/project_management.py,sha256=XtZTFWi7--ku6yUR_vwHQx2Ka3vz3pCcWMhVa_y4CQs,12162
82
+ basic_memory/mcp/tools/project_management.py,sha256=aLkfgEL3RlRztzERQur283cIed4mv14eAP7kh6gzHpw,12293
83
83
  basic_memory/mcp/tools/read_content.py,sha256=4FTw13B8UjVVhR78NJB9HKeJb_nA6-BGT1WdGtekN5Q,8596
84
84
  basic_memory/mcp/tools/read_note.py,sha256=GdsJLkcDrCBnmNeM9BZRx9Xs2LUqH5ty_E471T9Kf1Y,7493
85
85
  basic_memory/mcp/tools/recent_activity.py,sha256=XVjNJAJnmxvzx9_Ls1A-QOd2yTR7pJlSTTuRxSivmN4,4833
@@ -107,7 +107,7 @@ basic_memory/schemas/delete.py,sha256=UAR2JK99WMj3gP-yoGWlHD3eZEkvlTSRf8QoYIE-Wf
107
107
  basic_memory/schemas/directory.py,sha256=F9_LrJqRqb_kO08GDKJzXLb2nhbYG2PdVUo5eDD_Kf4,881
108
108
  basic_memory/schemas/importer.py,sha256=FAh-RGxuhFW2rz3HFxwLzENJOiGgbTR2hUeXZZpM3OA,663
109
109
  basic_memory/schemas/memory.py,sha256=6YjEyJ9GJLC4VrFD0EnoRDTfg-Sf6g0D4bhL9rwNBi4,5816
110
- basic_memory/schemas/project_info.py,sha256=cHXgp9k4RbgolIpCIEcrb-RR9m7WL72KFGwknig4H-E,6884
110
+ basic_memory/schemas/project_info.py,sha256=4yM51eGchS75ao2qyyVsk8_JyWRKJ0cJM3UzQF3G2ls,7050
111
111
  basic_memory/schemas/prompt.py,sha256=SpIVfZprQT8E5uP40j3CpBc2nHKflwOo3iZD7BFPIHE,3648
112
112
  basic_memory/schemas/request.py,sha256=Mv5EvrLZlFIiPr8dOjo_4QXvkseYhQI7cd_X2zDsxQM,3760
113
113
  basic_memory/schemas/response.py,sha256=lVYR31DTtSeFRddGWX_wQWnQgyiwX0LEpNJ4f4lKpTM,6440
@@ -121,7 +121,7 @@ basic_memory/services/file_service.py,sha256=jCrmnEkTQ4t9HF7L_M6BL7tdDqjjzty9hpT
121
121
  basic_memory/services/initialization.py,sha256=6ZeuTInPksyre4pjmiK_GXi5o_mJk3mfqGGH6apHxko,9271
122
122
  basic_memory/services/link_resolver.py,sha256=1-_VFsvqdT5rVBHe8Jrq63U59XQ0hxGezxY8c24Tiow,4594
123
123
  basic_memory/services/migration_service.py,sha256=pFJCSD7UgHLx1CHvtN4Df1CzDEp-CZ9Vqx4XYn1m1M0,6096
124
- basic_memory/services/project_service.py,sha256=nWnrlnjISqtGP6ui1BR8rSTNFzwExW8u7mRYPtWJLok,26856
124
+ basic_memory/services/project_service.py,sha256=Nz6N-2rk6DLLKBmtTBcPQATh_nzkLuD8LWWDAwgl6Oc,26875
125
125
  basic_memory/services/search_service.py,sha256=c5Ky0ufz7YPFgHhVzNRQ4OecF_JUrt7nALzpMjobW4M,12782
126
126
  basic_memory/services/service.py,sha256=V-d_8gOV07zGIQDpL-Ksqs3ZN9l3qf3HZOK1f_YNTag,336
127
127
  basic_memory/services/sync_status_service.py,sha256=PRAnYrsNJY8EIlxaxCrDsY0TjySDdhktjta8ReQZyiY,6838
@@ -131,8 +131,8 @@ basic_memory/sync/sync_service.py,sha256=AxC5J1YTcPWTmA0HdzvOZBthi4-_LZ44kNF0KQo
131
131
  basic_memory/sync/watch_service.py,sha256=JAumrHUjV1lF9NtEK32jgg0myWBfLXotNXxONeIV9SM,15316
132
132
  basic_memory/templates/prompts/continue_conversation.hbs,sha256=begMFHOPN3aCm5sHz5PlKMLOfZ8hlpFxFJ-hgy0T9K4,3075
133
133
  basic_memory/templates/prompts/search.hbs,sha256=H1cCIsHKp4VC1GrH2KeUB8pGe5vXFPqb2VPotypmeCA,3098
134
- basic_memory-0.13.0b6.dist-info/METADATA,sha256=WaorkcUqigopjYoHen6E7Ho5QDdBV7o-mKKYxvke4aY,15471
135
- basic_memory-0.13.0b6.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
136
- basic_memory-0.13.0b6.dist-info/entry_points.txt,sha256=wvE2mRF6-Pg4weIYcfQ-86NOLZD4WJg7F7TIsRVFLb8,90
137
- basic_memory-0.13.0b6.dist-info/licenses/LICENSE,sha256=hIahDEOTzuHCU5J2nd07LWwkLW7Hko4UFO__ffsvB-8,34523
138
- basic_memory-0.13.0b6.dist-info/RECORD,,
134
+ basic_memory-0.13.2.dist-info/METADATA,sha256=kTZGjOSHLa84vzIf6BuhEpDxzos3c-MWFGi-VcgLe2o,15469
135
+ basic_memory-0.13.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
136
+ basic_memory-0.13.2.dist-info/entry_points.txt,sha256=wvE2mRF6-Pg4weIYcfQ-86NOLZD4WJg7F7TIsRVFLb8,90
137
+ basic_memory-0.13.2.dist-info/licenses/LICENSE,sha256=hIahDEOTzuHCU5J2nd07LWwkLW7Hko4UFO__ffsvB-8,34523
138
+ basic_memory-0.13.2.dist-info/RECORD,,