basic-memory 0.14.2__py3-none-any.whl → 0.14.3__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 (51) hide show
  1. basic_memory/__init__.py +1 -1
  2. basic_memory/alembic/env.py +3 -1
  3. basic_memory/api/app.py +4 -1
  4. basic_memory/api/routers/management_router.py +3 -1
  5. basic_memory/api/routers/project_router.py +21 -13
  6. basic_memory/cli/app.py +3 -3
  7. basic_memory/cli/commands/__init__.py +1 -2
  8. basic_memory/cli/commands/db.py +5 -5
  9. basic_memory/cli/commands/import_chatgpt.py +3 -2
  10. basic_memory/cli/commands/import_claude_conversations.py +3 -1
  11. basic_memory/cli/commands/import_claude_projects.py +3 -1
  12. basic_memory/cli/commands/import_memory_json.py +5 -2
  13. basic_memory/cli/commands/mcp.py +3 -15
  14. basic_memory/cli/commands/project.py +41 -0
  15. basic_memory/cli/commands/status.py +4 -1
  16. basic_memory/cli/commands/sync.py +10 -2
  17. basic_memory/cli/main.py +0 -1
  18. basic_memory/config.py +46 -31
  19. basic_memory/db.py +2 -6
  20. basic_memory/deps.py +3 -2
  21. basic_memory/importers/chatgpt_importer.py +19 -9
  22. basic_memory/importers/memory_json_importer.py +22 -7
  23. basic_memory/mcp/async_client.py +22 -2
  24. basic_memory/mcp/project_session.py +6 -4
  25. basic_memory/mcp/prompts/__init__.py +0 -2
  26. basic_memory/mcp/server.py +8 -71
  27. basic_memory/mcp/tools/move_note.py +24 -12
  28. basic_memory/mcp/tools/read_content.py +16 -0
  29. basic_memory/mcp/tools/read_note.py +12 -0
  30. basic_memory/mcp/tools/sync_status.py +3 -2
  31. basic_memory/mcp/tools/write_note.py +9 -1
  32. basic_memory/models/project.py +3 -3
  33. basic_memory/repository/project_repository.py +18 -0
  34. basic_memory/schemas/importer.py +1 -0
  35. basic_memory/services/entity_service.py +49 -3
  36. basic_memory/services/initialization.py +0 -75
  37. basic_memory/services/project_service.py +85 -28
  38. basic_memory/sync/background_sync.py +4 -3
  39. basic_memory/sync/sync_service.py +50 -1
  40. basic_memory/utils.py +105 -4
  41. {basic_memory-0.14.2.dist-info → basic_memory-0.14.3.dist-info}/METADATA +2 -2
  42. {basic_memory-0.14.2.dist-info → basic_memory-0.14.3.dist-info}/RECORD +45 -51
  43. basic_memory/cli/commands/auth.py +0 -136
  44. basic_memory/mcp/auth_provider.py +0 -270
  45. basic_memory/mcp/external_auth_provider.py +0 -321
  46. basic_memory/mcp/prompts/sync_status.py +0 -112
  47. basic_memory/mcp/supabase_auth_provider.py +0 -463
  48. basic_memory/services/migration_service.py +0 -168
  49. {basic_memory-0.14.2.dist-info → basic_memory-0.14.3.dist-info}/WHEEL +0 -0
  50. {basic_memory-0.14.2.dist-info → basic_memory-0.14.3.dist-info}/entry_points.txt +0 -0
  51. {basic_memory-0.14.2.dist-info → basic_memory-0.14.3.dist-info}/licenses/LICENSE +0 -0
basic_memory/utils.py CHANGED
@@ -4,7 +4,6 @@ import os
4
4
 
5
5
  import logging
6
6
  import re
7
- import sys
8
7
  import unicodedata
9
8
  from pathlib import Path
10
9
  from typing import Optional, Protocol, Union, runtime_checkable, List, Any
@@ -144,7 +143,7 @@ def setup_logging(
144
143
  console: Whether to log to the console
145
144
  """
146
145
  # Remove default handler and any existing handlers
147
- logger.remove()
146
+ # logger.remove()
148
147
 
149
148
  # Add file handler if we are not running tests and a log file is specified
150
149
  if log_file and env != "test":
@@ -162,8 +161,8 @@ def setup_logging(
162
161
  )
163
162
 
164
163
  # Add console logger if requested or in test mode
165
- if env == "test" or console:
166
- logger.add(sys.stderr, level=log_level, backtrace=True, diagnose=True, colorize=True)
164
+ # if env == "test" or console:
165
+ # logger.add(sys.stderr, level=log_level, backtrace=True, diagnose=True, colorize=True)
167
166
 
168
167
  logger.info(f"ENV: '{env}' Log level: '{log_level}' Logging to {log_file}")
169
168
 
@@ -182,6 +181,79 @@ def setup_logging(
182
181
  logging.getLogger(logger_name).setLevel(level)
183
182
 
184
183
 
184
+ def normalize_file_path_for_comparison(file_path: str) -> str:
185
+ """Normalize a file path for conflict detection.
186
+
187
+ This function normalizes file paths to help detect potential conflicts:
188
+ - Converts to lowercase for case-insensitive comparison
189
+ - Normalizes Unicode characters
190
+ - Handles path separators consistently
191
+
192
+ Args:
193
+ file_path: The file path to normalize
194
+
195
+ Returns:
196
+ Normalized file path for comparison purposes
197
+ """
198
+ import unicodedata
199
+
200
+ # Convert to lowercase for case-insensitive comparison
201
+ normalized = file_path.lower()
202
+
203
+ # Normalize Unicode characters (NFD normalization)
204
+ normalized = unicodedata.normalize("NFD", normalized)
205
+
206
+ # Replace path separators with forward slashes
207
+ normalized = normalized.replace("\\", "/")
208
+
209
+ # Remove multiple slashes
210
+ normalized = re.sub(r"/+", "/", normalized)
211
+
212
+ return normalized
213
+
214
+
215
+ def detect_potential_file_conflicts(file_path: str, existing_paths: List[str]) -> List[str]:
216
+ """Detect potential conflicts between a file path and existing paths.
217
+
218
+ This function checks for various types of conflicts:
219
+ - Case sensitivity differences
220
+ - Unicode normalization differences
221
+ - Path separator differences
222
+ - Permalink generation conflicts
223
+
224
+ Args:
225
+ file_path: The file path to check
226
+ existing_paths: List of existing file paths to check against
227
+
228
+ Returns:
229
+ List of existing paths that might conflict with the given file path
230
+ """
231
+ conflicts = []
232
+
233
+ # Normalize the input file path
234
+ normalized_input = normalize_file_path_for_comparison(file_path)
235
+ input_permalink = generate_permalink(file_path)
236
+
237
+ for existing_path in existing_paths:
238
+ # Skip identical paths
239
+ if existing_path == file_path:
240
+ continue
241
+
242
+ # Check for case-insensitive path conflicts
243
+ normalized_existing = normalize_file_path_for_comparison(existing_path)
244
+ if normalized_input == normalized_existing:
245
+ conflicts.append(existing_path)
246
+ continue
247
+
248
+ # Check for permalink conflicts
249
+ existing_permalink = generate_permalink(existing_path)
250
+ if input_permalink == existing_permalink:
251
+ conflicts.append(existing_path)
252
+ continue
253
+
254
+ return conflicts
255
+
256
+
185
257
  def parse_tags(tags: Union[List[str], str, None]) -> List[str]:
186
258
  """Parse tags from various input formats into a consistent list.
187
259
 
@@ -214,3 +286,32 @@ def parse_tags(tags: Union[List[str], str, None]) -> List[str]:
214
286
  except (ValueError, TypeError): # pragma: no cover
215
287
  logger.warning(f"Couldn't parse tags from input of type {type(tags)}: {tags}")
216
288
  return []
289
+
290
+
291
+ def validate_project_path(path: str, project_path: Path) -> bool:
292
+ """Ensure path stays within project boundaries."""
293
+ # Allow empty strings as they resolve to the project root
294
+ if not path:
295
+ return True
296
+
297
+ # Check for obvious path traversal patterns first
298
+ if ".." in path or "~" in path:
299
+ return False
300
+
301
+ # Check for Windows-style path traversal (even on Unix systems)
302
+ if "\\.." in path or path.startswith("\\"):
303
+ return False
304
+
305
+ # Block absolute paths (Unix-style starting with / or Windows-style with drive letters)
306
+ if path.startswith("/") or (len(path) >= 2 and path[1] == ":"):
307
+ return False
308
+
309
+ # Block paths with control characters (but allow whitespace that will be stripped)
310
+ if path.strip() and any(ord(c) < 32 and c not in [" ", "\t"] for c in path):
311
+ return False
312
+
313
+ try:
314
+ resolved = (project_path / path).resolve()
315
+ return resolved.is_relative_to(project_path.resolve())
316
+ except (ValueError, OSError):
317
+ return False
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: basic-memory
3
- Version: 0.14.2
3
+ Version: 0.14.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
@@ -13,7 +13,7 @@ Requires-Dist: aiosqlite>=0.20.0
13
13
  Requires-Dist: alembic>=1.14.1
14
14
  Requires-Dist: dateparser>=1.2.0
15
15
  Requires-Dist: fastapi[standard]>=0.115.8
16
- Requires-Dist: fastmcp<2.10.0,>=2.3.4
16
+ Requires-Dist: fastmcp==2.10.2
17
17
  Requires-Dist: greenlet>=3.1.1
18
18
  Requires-Dist: icecream>=2.1.3
19
19
  Requires-Dist: loguru>=0.7.3
@@ -1,11 +1,11 @@
1
- basic_memory/__init__.py,sha256=yUZJCrnWSVfSXfN_chOSAkkW-Kge2Dj3Co6TixwmN9s,256
2
- basic_memory/config.py,sha256=YX6pP8aOMlIx9NoCeKLS0b5cgOnegbWhX2ijJzimLQg,11828
3
- basic_memory/db.py,sha256=bFuJHj_PGEhaj5ZgRItIUSW0ujAFCGgYKO7nZsjbYD0,7582
4
- basic_memory/deps.py,sha256=zXOhqXCoSVIa1iIcO8U6uUiofJn5eT4ycwJkH9I2kX4,12102
1
+ basic_memory/__init__.py,sha256=8waxNnFQNDHI9IsCihBom8GtgzjgHwDI4NDWWe_3Jxo,256
2
+ basic_memory/config.py,sha256=fGhHf0Eouc_97vOZ10E4poVeD2xWwoRGbZUP_7RWVPI,12480
3
+ basic_memory/db.py,sha256=JeBTsLP56PqCOwX8CZAB7-ijpPbg-Aco5QebpFqkBtg,7428
4
+ basic_memory/deps.py,sha256=vOKM2cpUm4r84LxonMH7LcgM1bkp-FEUqmgruK6CQR0,12144
5
5
  basic_memory/file_utils.py,sha256=eaxTKLLEbTIy_Mb_Iv_Dmt4IXAJSrZGVi-Knrpyci3E,6700
6
- basic_memory/utils.py,sha256=yG-HHoSqw6RUD9yU0PkrLdhDAi99r6tmE8fWTvBxrgc,7636
6
+ basic_memory/utils.py,sha256=PZvF_bV-Te6-gvRHk2ZDi3XTaMh6rwO8NNDYWfDNfqg,10946
7
7
  basic_memory/alembic/alembic.ini,sha256=IEZsnF8CbbZnkwBr67LzKKNobHuzTaQNUvM8Psop5xc,3733
8
- basic_memory/alembic/env.py,sha256=gECjMcc--Hhacy3od1WNIAFyHzv6MUi7F_eQG7k3bRQ,2812
8
+ basic_memory/alembic/env.py,sha256=4kHZh-rfzVARy9ndvsuDPTBt6Hk3dZ2BwI030EppBrA,2838
9
9
  basic_memory/alembic/migrations.py,sha256=lriHPXDdBLSNXEW3QTpU0SJKuVd1V-8NrVkpN3qfsUQ,718
10
10
  basic_memory/alembic/script.py.mako,sha256=MEqL-2qATlST9TAOeYgscMn1uy6HUS9NFvDgl93dMj8,635
11
11
  basic_memory/alembic/versions/3dae7c7b1564_initial_schema.py,sha256=lTbWlAnd1es7xU99DoJgfaRe1_Kte8TL98riqeKGV80,4363
@@ -15,40 +15,39 @@ basic_memory/alembic/versions/647e7a75e2cd_project_constraint_fix.py,sha256=YErF
15
15
  basic_memory/alembic/versions/b3c3938bacdb_relation_to_name_unique_index.py,sha256=RsGymQzfRXV1LSNKiyi0lMilTxW1NgwS9jR67ye2apI,1428
16
16
  basic_memory/alembic/versions/cc7172b46608_update_search_index_schema.py,sha256=kDavR9Qqx9wSu5P3qd4SZq_waIsDG1UMTg2SmDoktMU,3679
17
17
  basic_memory/api/__init__.py,sha256=wCpj-21j1D0KzKl9Ql6unLBVFY0K1uGp_FeSZRKtqpk,72
18
- basic_memory/api/app.py,sha256=ucV1epIVQ210JFdZIs6aZ_UWK8TG78p_NhGf6WOrFk0,2809
18
+ basic_memory/api/app.py,sha256=rWc6wsCUEK9YMPav3_qiiwBASA2s1S_wF1C4ssBm6M8,2897
19
19
  basic_memory/api/template_loader.py,sha256=exbTeXyJRgyLFmSjNeroxjT7X2DWFm2X5qUVa3drbYM,8607
20
20
  basic_memory/api/routers/__init__.py,sha256=REO5CKQ96o5vtGWACcsIxIpWybIUSeKXc83RWbWc8BQ,398
21
21
  basic_memory/api/routers/directory_router.py,sha256=rBQHvuwffUOk0iKvcEs2QlWclgvr8ur24f_pH3-sVRQ,2054
22
22
  basic_memory/api/routers/importer_router.py,sha256=xFUCorkPWo8AF0ya0UrcLmXNf8CjPZdAqddQIH8PO-o,4513
23
23
  basic_memory/api/routers/knowledge_router.py,sha256=4dD_tPpcJGWCuoRKEbQXCS3hoXNWe-VbcGC7xV-8VoE,9738
24
- basic_memory/api/routers/management_router.py,sha256=INT5PzUXhfBH2546CTZKqZnRuECYIA4Ypfgdf6JNyu0,2686
24
+ basic_memory/api/routers/management_router.py,sha256=zbzilNzsYUbFbE2uFXRM33cDn9IbI-73y8C1-b-19O4,2730
25
25
  basic_memory/api/routers/memory_router.py,sha256=a9Cnx3XgwSkO-2ABFzI3wM3PoMGxuyfJFFp7NfFZapc,3003
26
- basic_memory/api/routers/project_router.py,sha256=cXGx6VZMg67jdzMi1Xf8SodtueEI04xRwtiv9ygf2Bg,8239
26
+ basic_memory/api/routers/project_router.py,sha256=3qoto8Fm9pWqg6K0ukdd-VmggMENx7kK4JHvJrOhZ_I,8432
27
27
  basic_memory/api/routers/prompt_router.py,sha256=4wxq6-NREgVJM8N9C0YsN1AAUDD8nkTCOzWyzSqTSFw,9948
28
28
  basic_memory/api/routers/resource_router.py,sha256=WEJEqEaY_yTKj5-U-rW4kXQKUcJflykgwI6_g_R41ck,8058
29
29
  basic_memory/api/routers/search_router.py,sha256=GD62jlCQTiL_VNsdibi-b1f6H40KCWo9SX2Cl7YH4QU,1226
30
30
  basic_memory/api/routers/utils.py,sha256=nmD1faJOHcnWQjbCanojUwA9xhinf764U8SUqjNXpXw,5159
31
31
  basic_memory/cli/__init__.py,sha256=arcKLAWRDhPD7x5t80MlviZeYzwHZ0GZigyy3NKVoGk,33
32
- basic_memory/cli/app.py,sha256=BCIaiJBPV0ipk8KwPRLNiG2ACKBQH9wo1ewKZm7CV7o,2269
33
- basic_memory/cli/main.py,sha256=_0eW-TWYxj8WyCHSS9kFcrrntpeIsqJrA2P0n6LfFvY,475
34
- basic_memory/cli/commands/__init__.py,sha256=jtnGMOIgOBNJCXQ8xpKbLWhFUD3qgpOraRi19YRNaTc,411
35
- basic_memory/cli/commands/auth.py,sha256=mnTlb75eeQWocWYs67LaYbuEysaYvHkqP7gQ0FEXKjE,4858
36
- basic_memory/cli/commands/db.py,sha256=vhuXruyNBj9-9cQzYqKL29aEDUJE7IUQCxodu0wHuio,1481
37
- basic_memory/cli/commands/import_chatgpt.py,sha256=VU_Kfr4B0lVh_Z2_bmsTO3e3U40wrAOvTAvtblgjses,2773
38
- basic_memory/cli/commands/import_claude_conversations.py,sha256=sXnP0hjfwUapwHQDzxE2HEkCDe8FTaE4cogKILsD1EA,2866
39
- basic_memory/cli/commands/import_claude_projects.py,sha256=mWYIeA-mu_Pq23R7OEtY2XHXG5CAh1dMGIBhckB4zRk,2811
40
- basic_memory/cli/commands/import_memory_json.py,sha256=Vz5rt7KCel5B3Dtv57WPEUJTHCMwFUqQlOCm2djwUi8,2867
41
- basic_memory/cli/commands/mcp.py,sha256=NCqyY5dFHDtYnMDrWQiquoGbALUh-AqN4iRjJlFngxY,3123
42
- basic_memory/cli/commands/project.py,sha256=9OJWoV9kSkLePETUPxNs0v5YceXLgPWO2fU45ZinP9g,12252
43
- basic_memory/cli/commands/status.py,sha256=708EK8-iPjyc1iE5MPECzAyZraGYoGpvYjLwTm-BlQs,5719
44
- basic_memory/cli/commands/sync.py,sha256=gOU_onrMj9_IRiIe8FWU_FLEvfjcOt-qhrvvFJuU-ws,8010
32
+ basic_memory/cli/app.py,sha256=9xBnA4DXB8RFitiB96Jbs8XNsrz_WfE583QhJk_o8vg,2268
33
+ basic_memory/cli/main.py,sha256=ekBbEr_5jjGZaFJiOK4VhZ3wNiu6WjhXVi_syke1xw0,465
34
+ basic_memory/cli/commands/__init__.py,sha256=3oojcC-Y-4RPqff9vtwWziT_T4uvBVicL0pSHNilVkU,393
35
+ basic_memory/cli/commands/db.py,sha256=cEoQltgKudEuJH0Cn-YiPpNaDQzu5-YVwCD0anIIKOA,1480
36
+ basic_memory/cli/commands/import_chatgpt.py,sha256=iVfMo6yrY1EzViSlGL3BnZVkh-k9ht0bbCMJ6dWFCuU,2856
37
+ basic_memory/cli/commands/import_claude_conversations.py,sha256=e8l4OHMr8A9PtKgOO6T9-86Jca6FzCrJAsOzo-EQrlc,2946
38
+ basic_memory/cli/commands/import_claude_projects.py,sha256=YyFXcHWAHJmtR6DNwTtao8nKECoFyo8GripRElqMQ7w,2891
39
+ basic_memory/cli/commands/import_memory_json.py,sha256=fqGT9nILJnIpCtFseaFDox2IodVng48Suev5EQp8Azg,3013
40
+ basic_memory/cli/commands/mcp.py,sha256=Phvj0nsY70dDIEt8-KN_vCoakfwWNsRo4IzvzYWXusY,2593
41
+ basic_memory/cli/commands/project.py,sha256=JaT_j-zckshHrNls15GSnLHV6_ZTqD7GVG69N44j_C8,13877
42
+ basic_memory/cli/commands/status.py,sha256=ttDqI31xTQVPabJKIFi-unTiJKL6SoClJdYqKqLqLXA,5809
43
+ basic_memory/cli/commands/sync.py,sha256=cDs-c8TDOFDCf29MB6u_XUzl3EP3Br8MQyZLu0X4shM,8213
45
44
  basic_memory/cli/commands/tool.py,sha256=my-kALn3khv1W2Avi736NrHsfkpbyP57mDi5LjHwqe0,9540
46
45
  basic_memory/importers/__init__.py,sha256=BTcBW97P3thcsWa5w9tQsvOu8ynHDgw2-8tPgkCZoh8,795
47
46
  basic_memory/importers/base.py,sha256=awwe_U-CfzSINKoM6iro7ru4QqLlsfXzdHztDvebnxM,2531
48
- basic_memory/importers/chatgpt_importer.py,sha256=36VAsZarI7XE5r_KxNpWeHM1HPfHj6NfTDuH6ExY4hg,7372
47
+ basic_memory/importers/chatgpt_importer.py,sha256=UqhmWNm7YCfyMRCR53zP_xgtx-UzoY_eOR6Cb8gw6m8,7674
49
48
  basic_memory/importers/claude_conversations_importer.py,sha256=p7yehy9Pgc5fef6d0ab9DwCm8CCiyyZkGEqX8U7rHbw,5725
50
49
  basic_memory/importers/claude_projects_importer.py,sha256=pFJnX9m7GOv2TrS9f2nM1-mTtheTEBWjxKtwDWdJOGM,5389
51
- basic_memory/importers/memory_json_importer.py,sha256=u-cNYPuBsiNcyOLKo8YBXKyCp_dOs5PmkTpw5o8SXnw,3936
50
+ basic_memory/importers/memory_json_importer.py,sha256=vH0EUpnxftmtXOv_exQjJQ7CihETDkegrEjTq4K96vw,4631
52
51
  basic_memory/importers/utils.py,sha256=7n4i_UgSNiOU9i7YlEq-gHOMHjq4gTH69jn0qMz9bIk,1792
53
52
  basic_memory/markdown/__init__.py,sha256=DdzioCWtDnKaq05BHYLgL_78FawEHLpLXnp-kPSVfIc,501
54
53
  basic_memory/markdown/entity_parser.py,sha256=Gw0RdzWGRcy63RcLP2J2Dcm9g404x0GXirDaWDYjTWg,4516
@@ -57,18 +56,14 @@ basic_memory/markdown/plugins.py,sha256=gtIzKRjoZsyvBqLpVNnrmzl_cbTZ5ZGn8kcuXxQj
57
56
  basic_memory/markdown/schemas.py,sha256=eyxYCr1hVyWmImcle0asE5It_DD6ARkqaBZYu1KK5n4,1896
58
57
  basic_memory/markdown/utils.py,sha256=G3V_DQbmDj6idsCy6kT-GhVqiV4JPB5gfWKG5wK_SuQ,3410
59
58
  basic_memory/mcp/__init__.py,sha256=dsDOhKqjYeIbCULbHIxfcItTbqudEuEg1Np86eq0GEQ,35
60
- basic_memory/mcp/async_client.py,sha256=Eo345wANiBRSM4u3j_Vd6Ax4YtMg7qbWd9PIoFfj61I,236
61
- basic_memory/mcp/auth_provider.py,sha256=NnnxpOUMI1sZhKkzHh4Hhoufo4FuiKByx34TdfPoBX8,10050
62
- basic_memory/mcp/external_auth_provider.py,sha256=Z1GDbr6P4C-flZVHMWkIqAu30kcfeHv2iSp0EYbFuxo,11483
63
- basic_memory/mcp/project_session.py,sha256=KfObBqUFUKNGlcApCfQcsqMYsmtWs72OdIcQ79ZSWhk,4142
64
- basic_memory/mcp/server.py,sha256=T8utX0fTA12rAC_TjtWgsfB1z-Q6pdTWJH4HISw73vg,3764
65
- basic_memory/mcp/supabase_auth_provider.py,sha256=R_E4jzXSDOyPomoHiIqPVjx-VUhPqJSIUbg84mE2YaQ,16518
66
- basic_memory/mcp/prompts/__init__.py,sha256=UvaIw5KA8PaXj3Wz1Dr-VjlkEq6T5D8AGtYFVwaHqnA,683
59
+ basic_memory/mcp/async_client.py,sha256=ZTH0OH8wowoyIZf_UdbqyuSyWljGSAlZMbPRFF0dowM,925
60
+ basic_memory/mcp/project_session.py,sha256=TaQD7JPeyQY-64sFJG41AXQNFizHegZ9POVLpD1pCBk,4203
61
+ basic_memory/mcp/server.py,sha256=CpEMrifWHqkj6Q--LUtcfKzzsp0-FW8Lf3eHKrlzx2E,1248
62
+ basic_memory/mcp/prompts/__init__.py,sha256=-Bl9Dgj2TD9PULjzggPqXuvPEjWCRy7S9Yg03h2-U7A,615
67
63
  basic_memory/mcp/prompts/ai_assistant_guide.py,sha256=8TI5xObiRVcwv6w9by1xQHlX0whvyE7-LGsiqDMRTFg,821
68
64
  basic_memory/mcp/prompts/continue_conversation.py,sha256=rsmlC2V7e7G6DAK0K825vFsPKgsRQ702HFzn6lkHaDM,1998
69
65
  basic_memory/mcp/prompts/recent_activity.py,sha256=0v1c3b2SdDDxXVuF8eOjNooYy04uRYel0pdJ0rnggw4,3311
70
66
  basic_memory/mcp/prompts/search.py,sha256=nb88MZy9tdW_MmCLUVItiukrLdb3xEHWLv0JVLUlc4o,1692
71
- basic_memory/mcp/prompts/sync_status.py,sha256=0F6YowgqIbAFmGE3vFFJ-D-q1SrTqzGLKYWECgNWaxw,4495
72
67
  basic_memory/mcp/prompts/utils.py,sha256=VacrbqwYtySpIlYIrKHo5s6jtoTMscYJqrFRH3zpC6Q,5431
73
68
  basic_memory/mcp/resources/ai_assistant_guide.md,sha256=qnYWDkYlb-JmKuOoZ5llmRas_t4dWDXB_i8LE277Lgs,14777
74
69
  basic_memory/mcp/resources/project_info.py,sha256=LcUkTx4iXBfU6Lp4TVch78OqLopbOy4ljyKnfr4VXso,1906
@@ -78,26 +73,26 @@ basic_memory/mcp/tools/canvas.py,sha256=22F9G9gfPb-l8i1B5ra4Ja_h9zYY83rPY9mDA5C5
78
73
  basic_memory/mcp/tools/delete_note.py,sha256=tSyRc_VgBmLyVeenClwX1Sk--LKcGahAMzTX2mK2XIs,7346
79
74
  basic_memory/mcp/tools/edit_note.py,sha256=q4x-f7-j_l-wzm17-AVFT1_WGCo0Cq4lI3seYSe21aY,13570
80
75
  basic_memory/mcp/tools/list_directory.py,sha256=-FxDsCru5YD02M4qkQDAurEJWyRaC7YI4YR6zg0atR8,5236
81
- basic_memory/mcp/tools/move_note.py,sha256=jAsCFXrcWXPoBWlWcW8y3Tli5MkKwCQK-n6IwUZoOK8,17357
76
+ basic_memory/mcp/tools/move_note.py,sha256=XvJ9m6rrwsVlb8ScR5ik5OQKcLbNnR52HbyuAhutVYw,17541
82
77
  basic_memory/mcp/tools/project_management.py,sha256=zaxzbWUSn2iahca4L44EO8hKMWV-rXqDMXcRce6qhg8,12944
83
- basic_memory/mcp/tools/read_content.py,sha256=4FTw13B8UjVVhR78NJB9HKeJb_nA6-BGT1WdGtekN5Q,8596
84
- basic_memory/mcp/tools/read_note.py,sha256=V08NdBqWY8Y0Q4zuwK--zN3VK7fmuCH1mOYZKwL1IT4,7614
78
+ basic_memory/mcp/tools/read_content.py,sha256=lqE63axQf9h0OU36Lh5e1xr164nQhywdaMrPnKw_hyQ,9125
79
+ basic_memory/mcp/tools/read_note.py,sha256=3_U84CsW2cX8oxWz8Ju3CGeonWFLDvPwVI3Oh5eASO4,8132
85
80
  basic_memory/mcp/tools/recent_activity.py,sha256=XVjNJAJnmxvzx9_Ls1A-QOd2yTR7pJlSTTuRxSivmN4,4833
86
81
  basic_memory/mcp/tools/search.py,sha256=hRmwBXRoxEUOtUOi9WG80NfLluHOG5XpSOArMJumt8o,15883
87
- basic_memory/mcp/tools/sync_status.py,sha256=mt0DdcaAlyiKW4NK4gy6psajSqcez0bOm_4MzG1NOdg,10486
82
+ basic_memory/mcp/tools/sync_status.py,sha256=c91zsYbq7IuC5rF-OaZ8JwgtJOBlPcTks1cSvYO4CiI,10517
88
83
  basic_memory/mcp/tools/utils.py,sha256=qVAEkR4naCLrqIo_7xXFubqGGxypouz-DB4_svTvARY,20892
89
84
  basic_memory/mcp/tools/view_note.py,sha256=ddNXxyETsdA5SYflIaQVj_Cbd7I7CLVs3atRRDMbGmg,2499
90
- basic_memory/mcp/tools/write_note.py,sha256=GFmX_VLJvcqK29-ADTCDnPgBaweAq_9IBGCs99mwFTw,6178
85
+ basic_memory/mcp/tools/write_note.py,sha256=dxOW-0nTl_619-NjIdTSM8IsTRtTQUkSyEmVfG6W_IM,6612
91
86
  basic_memory/models/__init__.py,sha256=j0C4dtFi-FOEaQKR8dQWEG-dJtdQ15NBTiJg4nbIXNU,333
92
87
  basic_memory/models/base.py,sha256=4hAXJ8CE1RnjKhb23lPd-QM7G_FXIdTowMJ9bRixspU,225
93
88
  basic_memory/models/knowledge.py,sha256=AFxfKS8fRa43Kq3EjJCAufpte4VNC7fs9YfshDrB4o0,7087
94
- basic_memory/models/project.py,sha256=oUrQaUOu7_muSl-i38Dh0HzmCFrMAtwgxALDUTt9k5c,2773
89
+ basic_memory/models/project.py,sha256=wQ0zrG0noh1c1kLwpaL6_apKib2EUoIWmuk4KDgScdM,2808
95
90
  basic_memory/models/search.py,sha256=PhQ8w4taApSvjh1DpPhB4cH9GTt2E2po-DFZzhnoZkY,1300
96
91
  basic_memory/repository/__init__.py,sha256=MWK-o8QikqzOpe5SyPbKQ2ioB5BWA0Upz65tgg-E0DU,327
97
92
  basic_memory/repository/entity_repository.py,sha256=4qjR66bI1kvGHXFo3w_owppnCFi_na6sRkoPRAJz-uA,10405
98
93
  basic_memory/repository/observation_repository.py,sha256=qhMvHLSjaoT3Fa_cQOKsT5jYPj66GXSytEBMwLAgygQ,2943
99
94
  basic_memory/repository/project_info_repository.py,sha256=8XLVAYKkBWQ6GbKj1iqA9OK0FGPHdTlOs7ZtfeUf9t8,338
100
- basic_memory/repository/project_repository.py,sha256=sgdKxKTSiiOZTzABwUNqli7K5mbXiPiQEAc5r0RD_jQ,3159
95
+ basic_memory/repository/project_repository.py,sha256=e-qi9CPBzmCz-fS4AQFDgg4MVZ3Zqec6fxVjnP_fGaI,3783
101
96
  basic_memory/repository/relation_repository.py,sha256=z7Oo5Zz_J-Bj6RvQDpSWR73ZLk2fxG7e7jrMbeFeJvQ,3179
102
97
  basic_memory/repository/repository.py,sha256=MJb-cb8QZQbL-Grq_iqv4Kq75aX2yQohLIqh5T4fFxw,15224
103
98
  basic_memory/repository/search_repository.py,sha256=qXL3PRtx2sV3Do6zeTxsmsROTnkvnatSj4xObGqAvKo,21936
@@ -105,7 +100,7 @@ basic_memory/schemas/__init__.py,sha256=mEgIFcdTeb-v4y0gkOh_pA5zyqGbZk-9XbXqlSi6
105
100
  basic_memory/schemas/base.py,sha256=Fx97DEqzOr7y9zeeseO9qVBYbOft_4OQf9EiVfhOJn4,6738
106
101
  basic_memory/schemas/delete.py,sha256=UAR2JK99WMj3gP-yoGWlHD3eZEkvlTSRf8QoYIE-Wfw,1180
107
102
  basic_memory/schemas/directory.py,sha256=F9_LrJqRqb_kO08GDKJzXLb2nhbYG2PdVUo5eDD_Kf4,881
108
- basic_memory/schemas/importer.py,sha256=FAh-RGxuhFW2rz3HFxwLzENJOiGgbTR2hUeXZZpM3OA,663
103
+ basic_memory/schemas/importer.py,sha256=rDPfQjyjKyjOe26pwp1UH4eDqGwMKfeNs1Fjv5PxOc0,693
109
104
  basic_memory/schemas/memory.py,sha256=rLSpU6VT_spnLEiVeYp9lI7FH5IvdbZt19VXFuO-vtM,5833
110
105
  basic_memory/schemas/project_info.py,sha256=fcNjUpe25_5uMmKy142ib3p5qEakzs1WJPLkgol5zyw,7047
111
106
  basic_memory/schemas/prompt.py,sha256=SpIVfZprQT8E5uP40j3CpBc2nHKflwOo3iZD7BFPIHE,3648
@@ -115,24 +110,23 @@ basic_memory/schemas/search.py,sha256=ywMsDGAQK2sO2TT5lc-da_k67OKW1x1TenXormHHWv
115
110
  basic_memory/services/__init__.py,sha256=XGt8WX3fX_0K9L37Msy8HF8nlMZYIG3uQ6mUX6_iJtg,259
116
111
  basic_memory/services/context_service.py,sha256=4ReLAF5qifA9ayOePGsVKusw1TWj8oBzRECjrsFiKPI,14462
117
112
  basic_memory/services/directory_service.py,sha256=_YOPXseQM4knd7PIFAho9LV_E-FljVE5WVJKQ0uflZs,6017
118
- basic_memory/services/entity_service.py,sha256=fNUWPsprigdy6DjIyGnkeBZnY81qLXRbC5qlwlpluu4,30440
113
+ basic_memory/services/entity_service.py,sha256=b2HnzWqZOG12bVhzb8iOQ1_94T37-3J7-F9w8f5kGvM,32237
119
114
  basic_memory/services/exceptions.py,sha256=oVjQr50XQqnFq1-MNKBilI2ShtHDxypavyDk1UeyHhw,390
120
115
  basic_memory/services/file_service.py,sha256=jCrmnEkTQ4t9HF7L_M6BL7tdDqjjzty9hpTo9AzwhvM,10059
121
- basic_memory/services/initialization.py,sha256=HN1NhFTEPHjpzBwabVkvFbJ_ldXJXuNaww4ugh7MJos,9717
116
+ basic_memory/services/initialization.py,sha256=Td5Yt5nPSskGMeWZSbVbM1WpO9-Z3w2cJAjAzqZ-EMQ,6715
122
117
  basic_memory/services/link_resolver.py,sha256=1-_VFsvqdT5rVBHe8Jrq63U59XQ0hxGezxY8c24Tiow,4594
123
- basic_memory/services/migration_service.py,sha256=pFJCSD7UgHLx1CHvtN4Df1CzDEp-CZ9Vqx4XYn1m1M0,6096
124
- basic_memory/services/project_service.py,sha256=uLIrQB6T1DY3BXrEsLdB2ZlcKnPgjubyn-g6V9vMBzA,27928
118
+ basic_memory/services/project_service.py,sha256=1qsCEMQN5tUxfXxfXQD_NboIRrW3_xac0ztDW60q9kc,30065
125
119
  basic_memory/services/search_service.py,sha256=c5Ky0ufz7YPFgHhVzNRQ4OecF_JUrt7nALzpMjobW4M,12782
126
120
  basic_memory/services/service.py,sha256=V-d_8gOV07zGIQDpL-Ksqs3ZN9l3qf3HZOK1f_YNTag,336
127
121
  basic_memory/services/sync_status_service.py,sha256=CgJdaJ6OFvFjKHIQSVIQX8kEU389Mrz_WS6x8dx2-7c,7504
128
122
  basic_memory/sync/__init__.py,sha256=CVHguYH457h2u2xoM8KvOilJC71XJlZ-qUh8lHcjYj4,156
129
- basic_memory/sync/background_sync.py,sha256=4CEx8oP6-qD33uCeowhpzhA8wivmWxaCmSBP37h3Fs8,714
130
- basic_memory/sync/sync_service.py,sha256=AxC5J1YTcPWTmA0HdzvOZBthi4-_LZ44kNF0KQoDRPw,23387
123
+ basic_memory/sync/background_sync.py,sha256=VJr2SukRKLdsbfB-9Re4LehcpK15a-RLXAFB-sAdRRM,726
124
+ basic_memory/sync/sync_service.py,sha256=GSpefl6M_TV2lQElWwnogmlERZFmhgZaIwIxWjvnc8I,26549
131
125
  basic_memory/sync/watch_service.py,sha256=JAumrHUjV1lF9NtEK32jgg0myWBfLXotNXxONeIV9SM,15316
132
126
  basic_memory/templates/prompts/continue_conversation.hbs,sha256=trrDHSXA5S0JCbInMoUJL04xvCGRB_ku1RHNQHtl6ZI,3076
133
127
  basic_memory/templates/prompts/search.hbs,sha256=H1cCIsHKp4VC1GrH2KeUB8pGe5vXFPqb2VPotypmeCA,3098
134
- basic_memory-0.14.2.dist-info/METADATA,sha256=h7tyu5dCVDkJYGeV4XPL2RbK7hL3CrKM9n5UlrUapWc,17639
135
- basic_memory-0.14.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
136
- basic_memory-0.14.2.dist-info/entry_points.txt,sha256=wvE2mRF6-Pg4weIYcfQ-86NOLZD4WJg7F7TIsRVFLb8,90
137
- basic_memory-0.14.2.dist-info/licenses/LICENSE,sha256=hIahDEOTzuHCU5J2nd07LWwkLW7Hko4UFO__ffsvB-8,34523
138
- basic_memory-0.14.2.dist-info/RECORD,,
128
+ basic_memory-0.14.3.dist-info/METADATA,sha256=_LzguWWrEH3FfrxDesJjCT7__tnmKqk8J4CSfwt5M6c,17632
129
+ basic_memory-0.14.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
130
+ basic_memory-0.14.3.dist-info/entry_points.txt,sha256=wvE2mRF6-Pg4weIYcfQ-86NOLZD4WJg7F7TIsRVFLb8,90
131
+ basic_memory-0.14.3.dist-info/licenses/LICENSE,sha256=hIahDEOTzuHCU5J2nd07LWwkLW7Hko4UFO__ffsvB-8,34523
132
+ basic_memory-0.14.3.dist-info/RECORD,,
@@ -1,136 +0,0 @@
1
- """OAuth management commands."""
2
-
3
- import typer
4
- from typing import Optional
5
- from pydantic import AnyHttpUrl
6
-
7
- from basic_memory.cli.app import app
8
- from basic_memory.mcp.auth_provider import BasicMemoryOAuthProvider
9
- from mcp.shared.auth import OAuthClientInformationFull
10
-
11
-
12
- auth_app = typer.Typer(help="OAuth client management commands")
13
- app.add_typer(auth_app, name="auth")
14
-
15
-
16
- @auth_app.command()
17
- def register_client(
18
- client_id: Optional[str] = typer.Option(
19
- None, help="Client ID (auto-generated if not provided)"
20
- ),
21
- client_secret: Optional[str] = typer.Option(
22
- None, help="Client secret (auto-generated if not provided)"
23
- ),
24
- issuer_url: str = typer.Option("http://localhost:8000", help="OAuth issuer URL"),
25
- ):
26
- """Register a new OAuth client for Basic Memory MCP server."""
27
-
28
- # Create provider instance
29
- provider = BasicMemoryOAuthProvider(issuer_url=issuer_url)
30
-
31
- # Create client info with required redirect_uris
32
- client_info = OAuthClientInformationFull(
33
- client_id=client_id or "", # Provider will generate if empty
34
- client_secret=client_secret or "", # Provider will generate if empty
35
- redirect_uris=[AnyHttpUrl("http://localhost:8000/callback")], # Default redirect URI
36
- client_name="Basic Memory OAuth Client",
37
- grant_types=["authorization_code", "refresh_token"],
38
- )
39
-
40
- # Register the client
41
- import asyncio
42
-
43
- asyncio.run(provider.register_client(client_info))
44
-
45
- typer.echo("Client registered successfully!")
46
- typer.echo(f"Client ID: {client_info.client_id}")
47
- typer.echo(f"Client Secret: {client_info.client_secret}")
48
- typer.echo("\nSave these credentials securely - the client secret cannot be retrieved later.")
49
-
50
-
51
- @auth_app.command()
52
- def test_auth(
53
- issuer_url: str = typer.Option("http://localhost:8000", help="OAuth issuer URL"),
54
- ):
55
- """Test OAuth authentication flow.
56
-
57
- IMPORTANT: Use the same FASTMCP_AUTH_SECRET_KEY environment variable
58
- as your MCP server for tokens to validate correctly.
59
- """
60
-
61
- import asyncio
62
- import secrets
63
- from mcp.server.auth.provider import AuthorizationParams
64
- from pydantic import AnyHttpUrl
65
-
66
- async def test_flow():
67
- # Create provider with same secret key as server
68
- provider = BasicMemoryOAuthProvider(issuer_url=issuer_url)
69
-
70
- # Register a test client
71
- client_info = OAuthClientInformationFull(
72
- client_id=secrets.token_urlsafe(16),
73
- client_secret=secrets.token_urlsafe(32),
74
- redirect_uris=[AnyHttpUrl("http://localhost:8000/callback")],
75
- client_name="Test OAuth Client",
76
- grant_types=["authorization_code", "refresh_token"],
77
- )
78
- await provider.register_client(client_info)
79
- typer.echo(f"Registered test client: {client_info.client_id}")
80
-
81
- # Get the client
82
- client = await provider.get_client(client_info.client_id)
83
- if not client:
84
- typer.echo("Error: Client not found after registration", err=True)
85
- return
86
-
87
- # Create authorization request
88
- auth_params = AuthorizationParams(
89
- state="test-state",
90
- scopes=["read", "write"],
91
- code_challenge="test-challenge",
92
- redirect_uri=AnyHttpUrl("http://localhost:8000/callback"),
93
- redirect_uri_provided_explicitly=True,
94
- )
95
-
96
- # Get authorization URL
97
- auth_url = await provider.authorize(client, auth_params)
98
- typer.echo(f"Authorization URL: {auth_url}")
99
-
100
- # Extract auth code from URL
101
- from urllib.parse import urlparse, parse_qs
102
-
103
- parsed = urlparse(auth_url)
104
- params = parse_qs(parsed.query)
105
- auth_code = params.get("code", [None])[0]
106
-
107
- if not auth_code:
108
- typer.echo("Error: No authorization code in URL", err=True)
109
- return
110
-
111
- # Load the authorization code
112
- code_obj = await provider.load_authorization_code(client, auth_code)
113
- if not code_obj:
114
- typer.echo("Error: Invalid authorization code", err=True)
115
- return
116
-
117
- # Exchange for tokens
118
- token = await provider.exchange_authorization_code(client, code_obj)
119
- typer.echo(f"Access token: {token.access_token}")
120
- typer.echo(f"Refresh token: {token.refresh_token}")
121
- typer.echo(f"Expires in: {token.expires_in} seconds")
122
-
123
- # Validate access token
124
- access_token_obj = await provider.load_access_token(token.access_token)
125
- if access_token_obj:
126
- typer.echo("Access token validated successfully!")
127
- typer.echo(f"Client ID: {access_token_obj.client_id}")
128
- typer.echo(f"Scopes: {access_token_obj.scopes}")
129
- else:
130
- typer.echo("Error: Invalid access token", err=True)
131
-
132
- asyncio.run(test_flow())
133
-
134
-
135
- if __name__ == "__main__":
136
- auth_app()